diff --git a/CHANGELOG.md b/CHANGELOG.md index 738a09279..96fc1cb30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,34 @@ ChangeLog ========= +12.27.1 (2020/03/28) +------------------- + +### ✨Improvements +* MiAuthのバグを修正 + +12.27.0 (2020/03/28) +------------------- + +### ✨Improvements +* サードパーティーアプリケーションの認証方法にMiAuthを追加 ([Misskey API ドキュメント](https://github.com/syuilo/misskey/blob/b8088dc01a0c53b264c0697082ff5b16b06c4cda/src/docs/api.ja-JP.md#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%97%E3%81%A6%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)) + 従来の、API `app/create` => `auth/session/generate` => `auth/session/userkey` を使用する方法は依然として使用可能です。 +UIからアプリを作成する画面 (`/dev/apps`) は廃止されました、同等の操作を行いたい場合は API `app/create` で可能です。 +* テーマをインポートする前にプレビューできるように +* アプリから通知を作成できるように +* インストールしたアプリを見たり削除したりできるように + +12.26.0 (2020/03/25) +------------------- + +### ✨Improvements +* ロゴが新しく +* インスタンス設定の「ユーザー」が登録の逆順で表示されるように + +### 🐛Fixes +* 新規登録フォームの「利用規約」のリンク色が通常の文字と同じだった問題を修正 +* ダークモードの同期の問題を修正 + 12.25.0 (2020/03/24) ------------------- @@ -25,7 +53,6 @@ ChangeLog ### 🐛Fixes * iOSで起動できない問題を修正 -* 画面が小さいとメニューがすべて見えない問題を修正 * Pages画面にタイトルがない問題を修正 12.24.0 (2020/03/22) diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 3813a6522..203fee63a 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -442,15 +442,10 @@ _charts: _instanceCharts: requests: "Anfragen" users: "Unterschied in der Anzahl von Benutzern" - usersTotal: "Anzahl aller Benutzer" notes: "Unterschied in der Anzahl von Notizen" - notesTotal: "Anzahl aller Notizen" ff: "Unterschied in der Anzahl von Followern" - ffTotal: "Gesamtanzahl der Follower" cacheSize: "Unterschied in der Größe des Caches" - cacheSizeTotal: "Gesamtgröße des Caches" files: "Unterschied in der Anzahl der Dateien" - filesTotal: "Gesamtanzahl der Dateien" _timelines: home: "Startseite" local: "Lokal" diff --git a/locales/en-US.yml b/locales/en-US.yml index 4c2ea21be..d0a250fe5 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -468,6 +468,14 @@ unableToProcess: "The operation could not be completed." recentUsed: "Recently used" install: "Install" uninstall: "Uninstall" +installedApps: "Authorized Applications" +nothing: "There's nothing to see here" +installedDate: "Authorized" +lastUsedDate: "Last used" +state: "State" +sort: "Sort" +ascendingOrder: "Ascending" +descendingOrder: "Descending" _theme: explore: "Explore Themes" install: "Install theme" @@ -560,7 +568,11 @@ _permissions: "write:user-groups": "Edit or delete user groups" _auth: shareAccess: "Would you like to authorize \"{name}\" to access this account?" + shareAccessAsk: "Are you sure you want to authorize this application to access your account?" permissionAsk: "This application requires following permissions:" + pleaseGoBack: "Please go back to the application" + callback: "Returning back to the application" + denied: "Access Denied" _antennaSources: all: "All notes" homeTimeline: "Notes from following users" @@ -670,7 +682,7 @@ _instanceCharts: ff: "Difference in # of followers" ffTotal: "Total # of followers" cacheSize: "Difference in cache size" - cacheSizeTotal: "Total accumulated cache" + cacheSizeTotal: "Total cache size" files: "Difference in # of files" filesTotal: "Total # of files" _timelines: diff --git a/locales/es-ES.yml b/locales/es-ES.yml index d9d52e7f1..d1ee32f78 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -468,6 +468,10 @@ unableToProcess: "La operación no se puede llevar a cabo" recentUsed: "Usado recientemente" install: "Instalación" uninstall: "Desinstalar" +installedApps: "Aplicaciones Autorizadas" +nothing: "No hay nada que ver aqui" +installedDate: "Autorizado" +lastUsedDate: "Utilizado el" _theme: explore: "Explorar temas" install: "Instalar tema" @@ -560,7 +564,11 @@ _permissions: "write:user-groups": "Administrar grupos de usuarios" _auth: shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?" + shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder a su cuenta?" permissionAsk: "Esta aplicación requiere los siguientes permisos" + pleaseGoBack: "Por favor, vuelve a la aplicación" + callback: "Volviendo a la aplicación" + denied: "Acceso denegado" _antennaSources: all: "Todas las notas" homeTimeline: "Notas de los usuarios que sigues" @@ -664,15 +672,10 @@ _charts: _instanceCharts: requests: "Pedidos" users: "Variación de usuarios" - usersTotal: "Total de usuarios" notes: "Variación de la cantidad de notas" - notesTotal: "Estimación de notas" ff: "Variación de cantidad de seguidos/seguidores" - ffTotal: "Total de seguidos/seguidores" cacheSize: "Variación del tamaño de la caché" - cacheSizeTotal: "Total del tamaño de la caché" files: "Variación de cantidad de archivos" - filesTotal: "Total de archivos" _timelines: home: "Inicio" local: "Local" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 6fa81d865..0138b7221 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -42,8 +42,8 @@ sendMessage: "Envoyer un message" copyUsername: "Copier le nom d'utilisateur" reply: "Répondre" loadMore: "Voir plus" -youGotNewFollower: "Vous a abonnés" -receiveFollowRequest: "Demande de abonnés reçue" +youGotNewFollower: "Vous suit" +receiveFollowRequest: "Demande de suivi reçue" followRequestAccepted: "L'abonne la demande acceptée" mentions: "Mentions" directNotes: "Messages directs" @@ -53,7 +53,7 @@ export: "Exporter" files: "Fichier·s" download: "Télécharger" driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{name}\" ? Les notes avec ce fichier joint seront aussi supprimées." -unfollowConfirm: "Êtes-vous sûr·de ne plus vouloir abonne {name} ?" +unfollowConfirm: "Se désabonner de {name} ?" exportRequested: "Vous avez demandé une exportation. Cela pourrait prendre un peu de temps. Une fois l'exportation terminée, le fichier résultant sera ajouté dans le Drive." importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps." lists: "Listes" @@ -62,17 +62,17 @@ note: "Note" notes: "Notes" following: "Abonnements" followers: "Abonné·e·s" -followsYou: "Votre abonné" +followsYou: "Vous suit" createList: "Créer une liste" manageLists: "Gérer les listes" error: "Une erreur est survenue" retry: "Réessayer" enterListName: "Nom de la liste" privacy: "Vie privée" -makeFollowManuallyApprove: "Demandes d’abonnements requiert l’approbation" +makeFollowManuallyApprove: "Demandes d’suivi requiert l'approbation" defaultNoteVisibility: "Visibilité par défaut" -follow: "Abonnement" -followRequest: "Demande d’abonnement" +follow: "Suivre" +followRequest: "Demande d’suivre" followRequests: "Demandes d’abonnement" unfollow: "Se désabonner" followRequestPending: "En attente d’approbation" @@ -121,7 +121,7 @@ setWallpaper: "Définir le fond d'écran" removeWallpaper: "Supprimer l'arrière plan" searchWith: "Recherche : {q}" youHaveNoLists: "Vous n'avez aucune liste" -followConfirm: "Désirez-vous abonne {name} ?" +followConfirm: "Désirez-vous suivre {name} ?" proxyAccount: "Compte proxy" proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions, comme un·e abonné·e distant pour les utilisateurs d'autres instances.\nExemple : quand un·e utilisateur·rice distant·e est ajouté·e à une liste, ses notes ne serait pas visibles sur l'instance si personne ne le·la abonné. Le compte proxy va donc le·la abonne pour que ses notes soient acheminées." host: "Hôte" @@ -468,6 +468,10 @@ unableToProcess: "L'opération n'a pas pu être complétée" recentUsed: "Récemment utilisé" install: "Installation" uninstall: "Désinstaller" +installedApps: "Applications Autorisées" +nothing: "Il n'y a rien à voir ici" +installedDate: "Autorisé" +lastUsedDate: "Dernière utilisation" _theme: explore: "Explorer les thèmes" install: "Installer un thème" @@ -560,7 +564,11 @@ _permissions: "write:user-groups": "Éditer les groupes des utilisateur·rice·s" _auth: shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?" + shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?" permissionAsk: "Cette application nécessite les autorisations suivantes " + pleaseGoBack: "Veillez retourner à l'application" + callback: "Retour vers l’application" + denied: "Accès refusé" _antennaSources: all: "Toutes les notes" homeTimeline: "Notes de l'utilisateur auquel je m'abonne" @@ -664,15 +672,10 @@ _charts: _instanceCharts: requests: "Requêtes" users: "Variation du nombre d'utilisateur·rice·s" - usersTotal: "Somme du nombre d'utilisateur·rice·s accumulés" notes: "Variation du nombre d'notes" - notesTotal: "Somme du nombre d’notes accumulés" ff: "Variation des abonné·e·s" - ffTotal: "Somme du nombre d'abonnements accumulés" cacheSize: "Variation de la taille du cache" - cacheSizeTotal: "Somme de la taille du cache accumulé" files: "Variation du nombre de fichiers" - filesTotal: "Somme du nombre de fichiers accumulés" _timelines: home: "Principal" local: "Local" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index a77991ccc..4e764bc63 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -472,6 +472,10 @@ installedApps: "インストールされたアプリ" nothing: "ありません" installedDate: "インストール日時" lastUsedDate: "最終使用日時" +state: "状態" +sort: "ソート" +ascendingOrder: "昇順" +descendingOrder: "降順" _theme: explore: "テーマを探す" @@ -691,15 +695,15 @@ _charts: _instanceCharts: requests: "リクエスト" users: "ユーザーの増減" - usersTotal: "ユーザーの積算" + usersTotal: "ユーザーの累積" notes: "ノートの増減" - notesTotal: "ノートの積算" + notesTotal: "ノートの累積" ff: "フォロー/フォロワーの増減" - ffTotal: "フォロー/フォロワーの積算" + ffTotal: "フォロー/フォロワーの累積" cacheSize: "キャッシュサイズの増減" - cacheSizeTotal: "キャッシュサイズの積算" + cacheSizeTotal: "キャッシュサイズの累積" files: "ファイル数の増減" - filesTotal: "ファイル数の積算" + filesTotal: "ファイル数の累積" _timelines: home: "ホーム" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 6a9a6d2f6..b66061ad7 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -468,6 +468,14 @@ unableToProcess: "작업을 완료할 수 없습니다" recentUsed: "최근 사용" install: "설치" uninstall: "삭제" +installedApps: "인증된 애플리케이션" +nothing: "아무것도 없습니다" +installedDate: "승인한 날짜" +lastUsedDate: "마지막 사용" +state: "상태" +sort: "정렬" +ascendingOrder: "오름차순" +descendingOrder: "내림차순" _theme: explore: "테마 찾아보기" install: "테마 설치" @@ -560,7 +568,11 @@ _permissions: "write:user-groups": "유저 그룹을 만들거나, 초대하거나, 이름을 변경하거나, 양도하거나, 삭제합니다" _auth: shareAccess: "\"{name}\" 이 계정에 접근하는 것을 허용하시겠습니까?" + shareAccessAsk: "이 애플리케이션이 계정에 접근하는 것을 허용하시겠습니까?" permissionAsk: "이 앱은 다음의 권한을 요청합니다" + pleaseGoBack: "앱으로 돌아가서 시도해 주세요" + callback: "앱으로 돌아갑니다" + denied: "접근이 거부되었습니다" _antennaSources: all: "모든 노트" homeTimeline: "팔로우중인 유저의 노트" @@ -664,15 +676,10 @@ _charts: _instanceCharts: requests: "요청" users: "유저 수 증감" - usersTotal: "누적 유저 수" notes: "노트 수 증감" - notesTotal: "총 노트 수" ff: "팔로잉/팔로워 증감" - ffTotal: "팔로잉/팔로워 누적" cacheSize: "캐시 용량 증감" - cacheSizeTotal: "누적 캐시 용량" files: "파일 수 증감" - filesTotal: "누적 파일 수" _timelines: home: "홈" local: "로컬" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index cd42bd7c8..8003f1f89 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -468,6 +468,14 @@ unableToProcess: "操作无法完成" recentUsed: "最近使用" install: "安装" uninstall: "卸载" +installedApps: "已授权的应用" +nothing: "没什么" +installedDate: "授权日期" +lastUsedDate: "最近使用" +state: "状态" +sort: "排序" +ascendingOrder: "升序" +descendingOrder: "降序" _theme: explore: "寻找主题" install: "安装主题" @@ -560,7 +568,11 @@ _permissions: "write:user-groups": "操作用户组" _auth: shareAccess: "您要授权允许“{name}”访问您的帐户吗?" + shareAccessAsk: "您确定要授权此应用程序访问您的帐户吗?" permissionAsk: "这个应用程序需要以下权限" + pleaseGoBack: "请返回到应用程序" + callback: "回到应用程序" + denied: "拒绝访问" _antennaSources: all: "所有帖子" homeTimeline: "已关注用户的帖子" @@ -664,15 +676,15 @@ _charts: _instanceCharts: requests: "请求" users: "用户数量:增加/减少" - usersTotal: "用户总数" + usersTotal: "用户总计" notes: "帖子:增加/减少" - notesTotal: "帖子:总数" + notesTotal: "帖子总计" ff: "关注/被关注:数量变化" - ffTotal: "关注/被关注:总数" + ffTotal: "关注/被关注者总计" cacheSize: "缓存大小:增加/减少" - cacheSizeTotal: "合计缓存大小" + cacheSizeTotal: "缓存大小总计" files: "文件总数增减" - filesTotal: "合计文件总数" + filesTotal: "文件数总计" _timelines: home: "首页" local: "本地" diff --git a/package.json b/package.json index df63693e9..8ef4c0a71 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "misskey", "author": "syuilo <syuilotan@yahoo.co.jp>", - "version": "12.27.1", + "version": "12.28.0", "codename": "indigo", "repository": { "type": "git", diff --git a/src/client/app.vue b/src/client/app.vue index 99268e42b..fc40b6973 100644 --- a/src/client/app.vue +++ b/src/client/app.vue @@ -975,6 +975,10 @@ export default Vue.extend({ &:not(.naked) { background: var(--pageBg); } + + &.naked { + background: var(--bg); + } } } diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue index d41dd9d52..b80c6494e 100644 --- a/src/client/components/date-separated-list.vue +++ b/src/client/components/date-separated-list.vue @@ -1,8 +1,8 @@ <template> <component :is="$store.state.device.animation ? 'transition-group' : 'div'" class="sqadhkmv" name="list" tag="div" :data-direction="direction" :data-reversed="reversed ? 'true' : 'false'"> <template v-for="(item, i) in items"> - <slot :item="item" :i="i"></slot> - <div class="separator" :key="item.id + '_date'" v-if="showDate(i, item)"> + <slot :item="item"></slot> + <div class="separator" v-if="showDate(i, item)" :key="item.id + '_date'"> <p class="date"> <span><fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span> <span>{{ getDateText(items[i + 1].createdAt) }}<fa class="icon" :icon="faAngleDown"/></span> diff --git a/src/client/pages/apps.vue b/src/client/pages/apps.vue index 03c6707f9..445bba34c 100644 --- a/src/client/pages/apps.vue +++ b/src/client/pages/apps.vue @@ -27,6 +27,12 @@ <div class="actions"> <button class="_button" @click="revoke(token)"><fa :icon="faTrashAlt"/></button> </div> + <details> + <summary>{{ $t('details') }}</summary> + <ul> + <li v-for="p in token.permission" :key="p">{{ $t(`_permissions.${p}`) }}</li> + </ul> + </details> </div> </div> </template> diff --git a/src/client/pages/instance/federation.vue b/src/client/pages/instance/federation.vue index fa7c37772..5babc6045 100644 --- a/src/client/pages/instance/federation.vue +++ b/src/client/pages/instance/federation.vue @@ -1,11 +1,14 @@ <template> <div class="mk-federation"> + <portal to="icon"><fa :icon="faGlobe"/></portal> + <portal to="title">{{ $t('federation') }}</portal> + <section class="_card instances"> - <div class="_title"><fa :icon="faGlobe"/> {{ $t('instances') }}</div> <div class="_content"> + <mk-input v-model="host" :debounce="true"><span>{{ $t('host') }}</span></mk-input> <div class="inputs" style="display: flex;"> - <mk-input v-model="host" :debounce="true" style="margin: 0; flex: 1;"><span>{{ $t('host') }}</span></mk-input> - <mk-select v-model="state" style="margin: 0;"> + <mk-select v-model="state" style="margin: 0; flex: 1;"> + <template #label>{{ $t('state') }}</template> <option value="all">{{ $t('all') }}</option> <option value="federating">{{ $t('federating') }}</option> <option value="subscribing">{{ $t('subscribing') }}</option> @@ -14,11 +17,32 @@ <option value="blocked">{{ $t('blocked') }}</option> <option value="notResponding">{{ $t('notResponding') }}</option> </mk-select> + <mk-select v-model="sort" style="margin: 0; flex: 1;"> + <template #label>{{ $t('sort') }}</template> + <option value="+pubSub">{{ $t('pubSub') }} ({{ $t('descendingOrder') }})</option> + <option value="-pubSub">{{ $t('pubSub') }} ({{ $t('ascendingOrder') }})</option> + <option value="+notes">{{ $t('notes') }} ({{ $t('descendingOrder') }})</option> + <option value="-notes">{{ $t('notes') }} ({{ $t('ascendingOrder') }})</option> + <option value="+users">{{ $t('users') }} ({{ $t('descendingOrder') }})</option> + <option value="-users">{{ $t('users') }} ({{ $t('ascendingOrder') }})</option> + <option value="+following">{{ $t('following') }} ({{ $t('descendingOrder') }})</option> + <option value="-following">{{ $t('following') }} ({{ $t('ascendingOrder') }})</option> + <option value="+followers">{{ $t('followers') }} ({{ $t('descendingOrder') }})</option> + <option value="-followers">{{ $t('followers') }} ({{ $t('ascendingOrder') }})</option> + <option value="+caughtAt">{{ $t('caughtAt') }} ({{ $t('descendingOrder') }})</option> + <option value="-caughtAt">{{ $t('caughtAt') }} ({{ $t('ascendingOrder') }})</option> + <option value="+lastCommunicatedAt">{{ $t('lastCommunicatedAt') }} ({{ $t('descendingOrder') }})</option> + <option value="-lastCommunicatedAt">{{ $t('lastCommunicatedAt') }} ({{ $t('ascendingOrder') }})</option> + <option value="+driveUsage">{{ $t('driveUsage') }} ({{ $t('descendingOrder') }})</option> + <option value="-driveUsage">{{ $t('driveUsage') }} ({{ $t('ascendingOrder') }})</option> + <option value="+driveFiles">{{ $t('driveFiles') }} ({{ $t('descendingOrder') }})</option> + <option value="-driveFiles">{{ $t('driveFiles') }} ({{ $t('ascendingOrder') }})</option> + </mk-select> </div> </div> <div class="_content"> <mk-pagination :pagination="pagination" #default="{items}" class="instances" ref="instances" :key="host + state"> - <div class="instance" v-for="(instance, i) in items" :key="instance.id" @click="info(instance)"> + <div class="instance" v-for="instance in items" :key="instance.id" @click="info(instance)"> <div class="host"><fa :icon="faCircle" class="indicator" :class="getStatus(instance)"/><b>{{ instance.host }}</b></div> <div class="status"> <span class="sub" v-if="instance.followersCount > 0"><fa :icon="faCaretDown" class="icon"/>Sub</span> diff --git a/src/client/pages/instance/queue.vue b/src/client/pages/instance/queue.vue index 8590f9ae2..c4892e88d 100644 --- a/src/client/pages/instance/queue.vue +++ b/src/client/pages/instance/queue.vue @@ -1,5 +1,8 @@ <template> <div> + <portal to="icon"><fa :icon="faExchangeAlt"/></portal> + <portal to="title">{{ $t('jobQueue') }}</portal> + <x-queue :connection="connection" domain="inbox"> <template #title><fa :icon="faExchangeAlt"/> In</template> </x-queue> diff --git a/src/client/pages/messaging/messaging-room.vue b/src/client/pages/messaging/messaging-room.vue index 0a20c56c2..317ad087f 100644 --- a/src/client/pages/messaging/messaging-room.vue +++ b/src/client/pages/messaging/messaging-room.vue @@ -19,7 +19,7 @@ <button class="more _button" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages"> <template v-if="fetchingMoreMessages"><fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $t('loading') : $t('loadMore') }} </button> - <x-list class="messages" :items="messages" v-slot="{ item: message, i }" direction="up" reversed> + <x-list class="messages" :items="messages" v-slot="{ item: message }" direction="up" reversed> <x-message :message="message" :is-group="group != null" :key="message.id"/> </x-list> </div> diff --git a/src/client/pages/miauth.vue b/src/client/pages/miauth.vue index 2ee0f2347..0e170af11 100644 --- a/src/client/pages/miauth.vue +++ b/src/client/pages/miauth.vue @@ -68,8 +68,8 @@ export default Vue.extend({ icon(): string { return this.$route.query.icon; }, - permission(): string { - return this.$route.query.permission; + permission(): string[] { + return this.$route.query.permission ? this.$route.query.permission.split(',') : []; }, }, methods: { @@ -79,7 +79,7 @@ export default Vue.extend({ session: this.session, name: this.name, iconUrl: this.icon, - permission: this.permission || [], + permission: this.permission, }); this.state = 'accepted'; diff --git a/src/client/theme.ts b/src/client/theme.ts index cc69ee406..2f4920e3a 100644 --- a/src/client/theme.ts +++ b/src/client/theme.ts @@ -27,7 +27,7 @@ export const builtinThemes = [ require('./themes/danboard.json5'), require('./themes/olive.json5'), require('./themes/tweetdeck.json5'), -]; +] as Theme[]; let timeout = null; @@ -66,16 +66,21 @@ export function applyTheme(theme: Theme, persist = true) { } } -function compile(theme: Theme): { [key: string]: string } { - function getColor(code: string): tinycolor.Instance { - // ref - if (code[0] == '@') { - return getColor(theme.props[code.substr(1)]); +function compile(theme: Theme): Record<string, string> { + function getColor(val: string): tinycolor.Instance { + // ref (prop) + if (val[0] === '@') { + return getColor(theme.props[val.substr(1)]); + } + + // ref (const) + else if (val[0] === '$') { + return getColor(theme.props[val]); } // func - if (code[0] == ':') { - const parts = code.split('<'); + else if (val[0] === ':') { + const parts = val.split('<'); const func = parts.shift().substr(1); const arg = parseFloat(parts.shift()); const color = getColor(parts.join('<')); @@ -87,12 +92,15 @@ function compile(theme: Theme): { [key: string]: string } { } } - return tinycolor(code); + // other case + return tinycolor(val); } const props = {}; for (const [k, v] of Object.entries(theme.props)) { + if (k.startsWith('$')) continue; // ignore const + props[k] = genValue(getColor(v)); } diff --git a/src/client/widgets/memo.vue b/src/client/widgets/memo.vue index 974c13eb0..3c170adc4 100644 --- a/src/client/widgets/memo.vue +++ b/src/client/widgets/memo.vue @@ -5,7 +5,7 @@ <div class="otgbylcu"> <textarea v-model="text" :placeholder="$t('placeholder')" @input="onChange"></textarea> - <button @click="saveMemo" :disabled="!changed">{{ $t('save') }}</button> + <button @click="saveMemo" :disabled="!changed" class="_buttonPrimary">{{ $t('save') }}</button> </div> </mk-container> </div> @@ -84,6 +84,7 @@ export default define({ border: none; border-bottom: solid var(--lineWidth) var(--faceDivider); border-radius: 0; + box-sizing: border-box; } > button { @@ -94,22 +95,8 @@ export default define({ margin: 0; padding: 0 10px; height: 28px; - color: #fff; - background: var(--accent) !important; outline: none; - border: none; border-radius: 4px; - transition: background 0.1s ease; - cursor: pointer; - - &:hover { - background: var(--accentLighten10) !important; - } - - &:active { - background: var(--accentDarken) !important; - transition: background 0s ease; - } &:disabled { opacity: 0.7; diff --git a/src/db/postgre.ts b/src/db/postgre.ts index 57703fb09..9e3eb3f7d 100644 --- a/src/db/postgre.ts +++ b/src/db/postgre.ts @@ -69,7 +69,9 @@ class MyCustomLogger implements Logger { } public logQuery(query: string, parameters?: any[]) { - sqlLogger.info(this.highlight(query)); + if (program.verbose) { + sqlLogger.info(this.highlight(query)); + } } public logQueryError(error: string, query: string, parameters?: any[]) { @@ -158,7 +160,7 @@ export function initDb(justBorrow = false, sync = false, forceRecreate = false) } catch (e) {} } - const log = program.verbose; + const log = process.env.NODE_ENV != 'production'; return createConnection({ type: 'postgres', diff --git a/src/docs/theme.ja-JP.md b/src/docs/theme.ja-JP.md new file mode 100644 index 000000000..c9604da41 --- /dev/null +++ b/src/docs/theme.ja-JP.md @@ -0,0 +1,74 @@ +# テーマ + +テーマを設定して、Misskeyクライアントの見た目を変更できます。 + +## テーマの設定 +設定 > テーマ + +## テーマを作成する +テーマコードはJSON5で記述されたテーマオブジェクトです。 +テーマは以下のようなオブジェクトです。 +``` js +{ + id: '17587283-dd92-4a2c-a22c-be0637c9e22a', + + name: 'Danboard', + author: 'syuilo', + + base: 'light', + + props: { + accent: 'rgb(218, 141, 49)', + bg: 'rgb(218, 212, 190)', + fg: 'rgb(115, 108, 92)', + panel: 'rgb(236, 232, 220)', + renote: 'rgb(100, 152, 106)', + link: 'rgb(100, 152, 106)', + mention: '@accent', + hashtag: 'rgb(100, 152, 106)', + header: 'rgba(239, 227, 213, 0.75)', + navBg: 'rgb(216, 206, 182)', + inputBorder: 'rgba(0, 0, 0, 0.1)', + }, +} + +``` + +* `id` ... テーマの一意なID。UUIDをおすすめします。 +* `name` ... テーマ名 +* `author` ... テーマの作者 +* `desc` ... テーマの説明(オプション) +* `base` ... 明るいテーマか、暗いテーマか + * `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。 + * テーマはここで設定されたベーステーマを継承します。 +* `props` ... テーマのスタイル定義。これから説明します。 + +### テーマのスタイル定義 +`props`下にはテーマのスタイルを定義します。 +キーがCSSの変数名になり、バリューで中身を指定します。 +なお、この`props`オブジェクトはベーステーマから継承されます。 +ベーステーマは、このテーマの`base`が`light`なら[_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5)で、`dark`なら[_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5)です。 +つまり、このテーマ内の`props`に`panel`というキーが無くても、そこにはベーステーマの`panel`があると見なされます。 + +#### バリューで使える構文 +* 16進数で表された色 + * 例: `#00ff00` +* `rgb(r, g, b)`形式で表された色 + * 例: `rgb(0, 255, 0)` +* `rgb(r, g, b, a)`形式で表された透明度を含む色 + * 例: `rgba(0, 255, 0, 0.5)` +* 他のキーの値の参照 + * `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。 + * 例: `@panel` +* 定数(後述)の参照 + * `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。 + * 例: `$main` +* 関数(後述) + * `:{関数名}<{引数}<{色}` + +#### 定数 +「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 +キー名を`$`で始めると、そのキーはCSS変数として出力されません。 + +#### 関数 +wip diff --git a/src/models/repositories/notification.ts b/src/models/repositories/notification.ts index a8978cc01..b484c43c5 100644 --- a/src/models/repositories/notification.ts +++ b/src/models/repositories/notification.ts @@ -46,8 +46,8 @@ export class NotificationRepository extends Repository<Notification> { } : {}), ...(notification.type === 'app' ? { body: notification.customBody, - header: notification.customHeader || token!.name, - icon: notification.customIcon || token!.iconUrl, + header: notification.customHeader || token?.name, + icon: notification.customIcon || token?.iconUrl, } : {}), }); } diff --git a/src/server/api/define.ts b/src/server/api/define.ts index 2ee0ba486..1c7ee2647 100644 --- a/src/server/api/define.ts +++ b/src/server/api/define.ts @@ -15,12 +15,12 @@ type Params<T extends IEndpointMeta> = { export type Response = Record<string, any> | void; type executor<T extends IEndpointMeta> = - (params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any, cleanup?: Function) => + (params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any, cleanup?: Function) => Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>; export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>) - : (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any) => Promise<any> { - return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any) => { + : (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => Promise<any> { + return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => { function cleanup() { fs.unlink(file.path, () => {}); } diff --git a/src/server/api/endpoints/i/apps.ts b/src/server/api/endpoints/i/apps.ts index dc74123ce..3b5cd21a7 100644 --- a/src/server/api/endpoints/i/apps.ts +++ b/src/server/api/endpoints/i/apps.ts @@ -38,5 +38,6 @@ export default define(meta, async (ps, user) => { name: token.name, createdAt: token.createdAt, lastUsedAt: token.lastUsedAt, + permission: token.permission, }))); }); diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts index 8eaa65a2c..41adc855d 100644 --- a/src/server/api/endpoints/meta.ts +++ b/src/server/api/endpoints/meta.ts @@ -159,6 +159,7 @@ export default define(meta, async (ps, me) => { github: instance.enableGithubIntegration, discord: instance.enableDiscordIntegration, serviceWorker: instance.enableServiceWorker, + miauth: true, }; } diff --git a/src/server/api/endpoints/notifications/create.ts b/src/server/api/endpoints/notifications/create.ts index fed422b64..6267699e9 100644 --- a/src/server/api/endpoints/notifications/create.ts +++ b/src/server/api/endpoints/notifications/create.ts @@ -29,7 +29,7 @@ export const meta = { export default define(meta, async (ps, user, token) => { createNotification(user.id, 'app', { - appAccessTokenId: token.id, + appAccessTokenId: token ? token.id : null, customBody: ps.body, customHeader: ps.header, customIcon: ps.icon, diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts index 05594ac72..2781d14bd 100644 --- a/src/server/api/stream/index.ts +++ b/src/server/api/stream/index.ts @@ -18,7 +18,7 @@ export default class Connection { public user?: User; public following: User['id'][] = []; public muting: User['id'][] = []; - public token: AccessToken; + public token?: AccessToken; private wsConnection: websocket.connection; public subscriber: EventEmitter; private channels: Channel[] = []; @@ -117,7 +117,7 @@ export default class Connection { this.subscribingNotes[payload.id]++; - if (this.subscribingNotes[payload.id] == 1) { + if (this.subscribingNotes[payload.id] === 1) { this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage); }