From b12bf78c6dfe024df329d1f5258d9d7d2cb10e75 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 23 Mar 2020 13:17:29 +0900 Subject: [PATCH 1/6] Update CHANGELOG.md --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc48dd37e..2e7e2d2b95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ ChangeLog ========= +12.24.2 (2020/03/22) +------------------- + +### 🐛Fixes +* ダークモードの同期を修正 + +12.24.1 (2020/03/22) +------------------- + +### ✨Improvements +* SVG形式のアイコンファイルを追加 + +### 🐛Fixes +* iOSで起動できない問題を修正 +* 画面が小さいとメニューがすべて見えない問題を修正 +* Pages画面にタイトルがない問題を修正 + +12.24.0 (2020/03/22) +------------------- + +### ✨Improvements +* クライアント設定にアカウント設定へのリンクを追加 +* ダークモードの同期を強化 + +### 🐛Fixes +* 画面が小さいとメニューがすべて見えない問題を修正 + 12.23.0 (2020/03/22) ------------------- From dac962580b40c5828e70bc4745ce33e049720c6b Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Mon, 23 Mar 2020 19:06:46 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E3=83=86=E3=83=BC=E3=83=9E=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=88=E6=A9=9F=E8=83=BD=E3=82=92?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E3=81=99=E3=82=8B=E3=81=AA=E3=81=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 11 +++ src/client/components/error.vue | 2 +- src/client/components/notes.vue | 2 +- src/client/init.ts | 1 + src/client/pages/follow-requests.vue | 2 +- src/client/pages/messaging/index.vue | 2 +- src/client/pages/not-found.vue | 2 +- src/client/pages/preferences/theme.vue | 95 ++++++++++++++++++++++++-- src/client/theme.ts | 7 ++ src/server/web/views/base.pug | 6 +- 10 files changed, 118 insertions(+), 12 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 6eb90c9d02..40772f9b1f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -466,6 +466,17 @@ details: "詳細" chooseEmoji: "絵文字を選択" unableToProcess: "操作を完了できません" recentUsed: "最近使用" +install: "インストール" +uninstall: "アンインストール" + +_theme: + explore: "テーマを探す" + install: "テーマのインストール" + manage: "テーマの管理" + code: "テーマコード" + installed: "{name}をインストールしました" + alreadyInstalled: "そのテーマは既にインストールされています" + invalid: "テーマの形式が間違っています" _sfx: note: "ノート" diff --git a/src/client/components/error.vue b/src/client/components/error.vue index 7446a7cb5d..dd9de43c16 100644 --- a/src/client/components/error.vue +++ b/src/client/components/error.vue @@ -1,6 +1,6 @@ <template> <div class="mjndxjcg _panel"> - <img src="https://xn--931a.moe/assets/error.png" class="_ghost"/> + <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> <p><fa :icon="faExclamationTriangle"/> {{ $t('error') }}</p> <mk-button @click="() => $emit('retry')" class="button">{{ $t('retry') }}</mk-button> </div> diff --git a/src/client/components/notes.vue b/src/client/components/notes.vue index bc2ae8472c..65dda17575 100644 --- a/src/client/components/notes.vue +++ b/src/client/components/notes.vue @@ -1,7 +1,7 @@ <template> <div class="mk-notes" v-size="[{ max: 500 }]"> <div class="empty" v-if="empty"> - <img src="https://xn--931a.moe/assets/info.png" class="_ghost"/> + <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> <div>{{ $t('noNotes') }}</div> </div> diff --git a/src/client/init.ts b/src/client/init.ts index c7587afb8c..b9c6aedae4 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -178,6 +178,7 @@ os.init(async () => { }, watch: { '$store.state.device.darkMode'() { + // TODO: このファイルでbuiltinThemesを参照するとcode splittingが効かず、初回読み込み時に全てのテーマコードを読み込むことになってしまい無駄なので何とかする const themes = builtinThemes.concat(this.$store.state.device.themes); applyTheme(themes.find(x => x.id === (this.$store.state.device.darkMode ? this.$store.state.device.darkTheme : this.$store.state.device.lightTheme))); } diff --git a/src/client/pages/follow-requests.vue b/src/client/pages/follow-requests.vue index 14d60a12ec..a900bf735c 100644 --- a/src/client/pages/follow-requests.vue +++ b/src/client/pages/follow-requests.vue @@ -6,7 +6,7 @@ <mk-pagination :pagination="pagination" class="mk-follow-requests" ref="list"> <template #empty> <div class="tkdrhpxr"> - <img src="https://xn--931a.moe/assets/info.png" class="_ghost"/> + <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> <div>{{ $t('noFollowRequests') }}</div> </div> </template> diff --git a/src/client/pages/messaging/index.vue b/src/client/pages/messaging/index.vue index 702979a098..ed24f8ef54 100644 --- a/src/client/pages/messaging/index.vue +++ b/src/client/pages/messaging/index.vue @@ -32,7 +32,7 @@ </router-link> </div> <div class="no-history" v-if="!fetching && messages.length == 0"> - <img src="https://xn--931a.moe/assets/info.png" class="_ghost"/> + <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> <div>{{ $t('noHistory') }}</div> </div> <mk-loading v-if="fetching"/> diff --git a/src/client/pages/not-found.vue b/src/client/pages/not-found.vue index 6ddbd1932b..9608e07786 100644 --- a/src/client/pages/not-found.vue +++ b/src/client/pages/not-found.vue @@ -5,7 +5,7 @@ <section class="_card"> <div class="_content"> - <img src="https://xn--931a.moe/assets/not-found.png" class="_ghost"/> + <img src="https://xn--931a.moe/assets/not-found.jpg" class="_ghost"/> <div>{{ $t('notFoundDescription') }}</div> </div> </section> diff --git a/src/client/pages/preferences/theme.vue b/src/client/pages/preferences/theme.vue index 488935a0cd..fcea457396 100644 --- a/src/client/pages/preferences/theme.vue +++ b/src/client/pages/preferences/theme.vue @@ -42,6 +42,7 @@ <option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option> </optgroup> </mk-select> + <a href="https://assets.msky.cafe/theme/list" rel="noopener" target="_blank" class="_link">{{ $t('_theme.explore') }}</a> </div> <div class="_content"> <mk-switch v-model="syncDeviceDarkMode">{{ $t('syncDeviceDarkMode') }}</mk-switch> @@ -50,18 +51,43 @@ <mk-button primary v-if="wallpaper == null" @click="setWallpaper">{{ $t('setWallpaper') }}</mk-button> <mk-button primary v-else @click="wallpaper = null">{{ $t('removeWallpaper') }}</mk-button> </div> + <div class="_content"> + <details> + <summary><fa :icon="faDownload"/> {{ $t('_theme.install') }}</summary> + <mk-textarea v-model="installThemeCode"> + <span>{{ $t('_theme.code') }}</span> + </mk-textarea> + <mk-button @click="() => install(this.installThemeCode)" :disabled="installThemeCode == null"><fa :icon="faCheck"/> {{ $t('install') }}</mk-button> + </details> + </div> + <div class="_content"> + <details> + <summary><fa :icon="faFolderOpen"/> {{ $t('_theme.manage') }}</summary> + <mk-select v-model="selectedThemeId"> + <option v-for="x in installedThemes" :value="x.id" :key="x.id">{{ x.name }}</option> + </mk-select> + <template v-if="selectedTheme"> + <mk-textarea readonly tall :value="selectedThemeCode"> + <span>{{ $t('_theme.code') }}</span> + </mk-textarea> + <mk-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="faTrashAlt"/> {{ $t('uninstall') }}</mk-button> + </template> + </details> + </div> </section> </template> <script lang="ts"> import Vue from 'vue'; -import { faPalette } from '@fortawesome/free-solid-svg-icons'; +import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import * as JSON5 from 'json5'; import MkInput from '../../components/ui/input.vue'; import MkButton from '../../components/ui/button.vue'; import MkSelect from '../../components/ui/select.vue'; import MkSwitch from '../../components/ui/switch.vue'; +import MkTextarea from '../../components/ui/textarea.vue'; import i18n from '../../i18n'; -import { Theme, builtinThemes, applyTheme } from '../../theme'; +import { Theme, builtinThemes, applyTheme, validateTheme } from '../../theme'; import { selectFile } from '../../scripts/select-file'; import { isDeviceDarkmode } from '../../scripts/is-device-darkmode'; @@ -73,12 +99,16 @@ export default Vue.extend({ MkButton, MkSelect, MkSwitch, + MkTextarea, }, data() { return { + builtinThemes, + installThemeCode: null, + selectedThemeId: null, wallpaper: localStorage.getItem('wallpaper'), - faPalette + faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt } }, @@ -118,6 +148,16 @@ export default Vue.extend({ get() { return this.$store.state.device.syncDeviceDarkMode; }, set(value) { this.$store.commit('device/set', { key: 'syncDeviceDarkMode', value }); } }, + + selectedTheme() { + if (this.selectedThemeId == null) return null; + return this.themes.find(x => x.id === this.selectedThemeId); + }, + + selectedThemeCode() { + if (this.selectedTheme == null) return null; + return JSON5.stringify(this.selectedTheme, null, '\t'); + }, }, watch: { @@ -155,6 +195,53 @@ export default Vue.extend({ this.wallpaper = file.url; }); }, + + install(code) { + let theme; + try { + theme = JSON5.parse(code); + } catch (e) { + this.$root.dialog({ + type: 'error', + text: this.$t('_theme.invalid') + }); + return; + } + if (!validateTheme(theme)) { + this.$root.dialog({ + type: 'error', + text: this.$t('_theme.invalid') + }); + return; + } + if (this.$store.state.device.themes.some(t => t.id === theme.id)) { + this.$root.dialog({ + type: 'info', + text: this.$t('_theme.alreadyInstalled') + }); + return; + } + const themes = this.$store.state.device.themes.concat(theme); + this.$store.commit('device/set', { + key: 'themes', value: themes + }); + this.$root.dialog({ + type: 'success', + text: this.$t('_theme.installed', { name: theme.name }) + }); + }, + + uninstall() { + const theme = this.selectedTheme; + const themes = this.$store.state.device.themes.filter(t => t.id != theme.id); + this.$store.commit('device/set', { + key: 'themes', value: themes + }); + this.$root.dialog({ + type: 'info', + iconOnly: true, autoClose: true + }); + }, } }); </script> @@ -179,7 +266,7 @@ export default Vue.extend({ top: 50%; left: 50%; overflow: hidden; - padding: 0 200px; + padding: 0 100px; transform: translate3d(-50%, -50%, 0); input { diff --git a/src/client/theme.ts b/src/client/theme.ts index 2a6adbffcc..e90c1f3a3b 100644 --- a/src/client/theme.ts +++ b/src/client/theme.ts @@ -102,3 +102,10 @@ function compile(theme: Theme): { [key: string]: string } { function genValue(c: tinycolor.Instance): string { return c.toRgbString(); } + +export function validateTheme(theme: Record<string, any>): boolean { + if (theme.id == null) return false; + if (theme.name == null) return false; + if (theme.base == null || !['light', 'dark'].includes(theme.base)) return false; + return true; +} diff --git a/src/server/web/views/base.pug b/src/server/web/views/base.pug index e6751ecca2..76114e6f5a 100644 --- a/src/server/web/views/base.pug +++ b/src/server/web/views/base.pug @@ -16,9 +16,9 @@ html link(rel='icon' href= icon || '/favicon.ico') link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png') link(rel='manifest' href='/manifest.json') - link(rel='prefetch' href='https://xn--931a.moe/assets/info.png') - link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.png') - link(rel='prefetch' href='https://xn--931a.moe/assets/error.png') + link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg') + link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') + link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') title block title From e25dea27e71581c2318431516ebf5aea205dc574 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Mon, 23 Mar 2020 19:09:20 +0900 Subject: [PATCH 3/6] Better theme validation --- src/client/theme.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/client/theme.ts b/src/client/theme.ts index e90c1f3a3b..cc69ee4060 100644 --- a/src/client/theme.ts +++ b/src/client/theme.ts @@ -104,8 +104,9 @@ function genValue(c: tinycolor.Instance): string { } export function validateTheme(theme: Record<string, any>): boolean { - if (theme.id == null) return false; - if (theme.name == null) return false; + if (theme.id == null || typeof theme.id !== 'string') return false; + if (theme.name == null || typeof theme.name !== 'string') return false; if (theme.base == null || !['light', 'dark'].includes(theme.base)) return false; + if (theme.props == null || typeof theme.props !== 'object') return false; return true; } From 833c39969b89c0d5de0b6616a253afea03e5fbb7 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Mon, 23 Mar 2020 19:42:26 +0900 Subject: [PATCH 4/6] Refactor --- src/server/api/endpoints/notes/state.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/api/endpoints/notes/state.ts b/src/server/api/endpoints/notes/state.ts index 2ec4a93d5b..b41b56162c 100644 --- a/src/server/api/endpoints/notes/state.ts +++ b/src/server/api/endpoints/notes/state.ts @@ -28,15 +28,15 @@ export default define(meta, async (ps, user) => { const [favorite, watching] = await Promise.all([ NoteFavorites.count({ where: { - userId: user.id, - noteId: ps.noteId + userId: user.id, + noteId: ps.noteId }, take: 1 }), NoteWatchings.count({ where: { - userId: user.id, - noteId: ps.noteId + userId: user.id, + noteId: ps.noteId }, take: 1 }) From a43a225740a8c27455435022fec31a3599234a86 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Mon, 23 Mar 2020 19:47:02 +0900 Subject: [PATCH 5/6] Fix #6180 --- src/server/api/endpoints/notes/timeline.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index 3eed9f0ca8..d60136a9ca 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -102,6 +102,13 @@ export const meta = { }; export default define(meta, async (ps, user) => { + const hasFollowing = (await Followings.count({ + where: { + followerId: user.id, + }, + take: 1 + })) !== 0; + //#region Construct query const followingQuery = Followings.createQueryBuilder('following') .select('following.followeeId') @@ -110,8 +117,8 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere(new Brackets(qb => { qb - .where(`note.userId IN (${ followingQuery.getQuery() })`) - .orWhere('note.userId = :meId', { meId: user.id }); + .where('note.userId = :meId', { meId: user.id }); + if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) .leftJoinAndSelect('note.user', 'user') .setParameters(followingQuery.getParameters()); From 2f898aa037705883744dbd5cdbc62e4fc4228bea Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Mon, 23 Mar 2020 19:48:19 +0900 Subject: [PATCH 6/6] 12.25.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 096ab58eda..86d5ab202a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "misskey", "author": "syuilo <syuilotan@yahoo.co.jp>", - "version": "12.24.2", + "version": "12.25.0", "codename": "indigo", "repository": { "type": "git",