From 53682f5cc6fd76ec325aff771459a5d42a1cd559 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:31:04 +0900 Subject: [PATCH] :art: --- locales/index.d.ts | 12 +- locales/ja-JP.yml | 4 +- packages/frontend/src/components/MkMenu.vue | 113 ++++++++++-------- packages/frontend/src/components/MkModal.vue | 2 +- .../frontend/src/pages/settings/general.vue | 26 ++-- .../pages/settings/preferences-backups.vue | 4 +- packages/frontend/src/store.ts | 10 +- 7 files changed, 102 insertions(+), 69 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 2a27eb3e15..f379fe7c40 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2053,9 +2053,17 @@ export interface Locale extends ILocale { */ "native": string; /** - * メニューをドロワーで表示しない + * メニューのスタイル */ - "disableDrawer": string; + "menuStyle": string; + /** + * ドロワー + */ + "drawer": string; + /** + * ポップアップ + */ + "popup": string; /** * ノートのアクションをホバー時のみ表示する */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 80cd8dc7cc..25af266c0b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -509,7 +509,9 @@ uiLanguage: "UIの表示言語" aboutX: "{x}について" emojiStyle: "絵文字のスタイル" native: "ネイティブ" -disableDrawer: "メニューをドロワーで表示しない" +menuStyle: "メニューのスタイル" +drawer: "ドロワー" +popup: "ポップアップ" showNoteActionsOnlyHover: "ノートのアクションをホバー時のみ表示する" showReactionsCount: "ノートのリアクション数を表示する" noHistory: "履歴はありません" diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 0d794d84d5..890b99fcc2 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -4,18 +4,22 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div role="menu" @focusin.passive.stop="() => {}"> +<div + role="menu" + :class="{ + [$style.root]: true, + [$style.center]: align === 'center', + [$style.big]: big, + [$style.asDrawer]: asDrawer, + }" + @focusin.passive.stop="() => {}" +> <div ref="itemsEl" v-hotkey="keymap" tabindex="0" class="_popup _shadow" - :class="{ - [$style.root]: true, - [$style.center]: align === 'center', - [$style.big]: big, - [$style.asDrawer]: asDrawer, - }" + :class="$style.menu" :style="{ width: (width && !asDrawer) ? `${width}px` : '', maxHeight: maxHeight ? `min(${maxHeight}px, calc(100dvh - 32px))` : 'calc(100dvh - 32px)', @@ -300,6 +304,8 @@ async function showRadioOptions(item: MenuRadio, ev: Event) { } async function showChildren(item: MenuParent, ev: Event) { + ev.stopPropagation(); + const children: MenuItem[] = await (async () => { if (childrenCache.has(item)) { return childrenCache.get(item)!; @@ -421,6 +427,58 @@ onBeforeUnmount(() => { <style lang="scss" module> .root { + &.center { + > .menu { + > .item { + text-align: center; + } + } + } + + &.big:not(.asDrawer) { + > .menu { + > .item { + padding: 6px 20px; + font-size: 1em; + line-height: 24px; + } + } + } + + &.asDrawer { + max-width: 600px; + margin: auto; + + > .menu { + padding: 12px 0 max(env(safe-area-inset-bottom, 0px), 12px) 0; + width: 100%; + border-radius: 24px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + + > .item { + font-size: 1em; + padding: 12px 24px; + + &::before { + width: calc(100% - 24px); + border-radius: 12px; + } + + > .icon { + margin-right: 14px; + width: 24px; + } + } + + > .divider { + margin: 12px 0; + } + } + } +} + +.menu { padding: 8px 0; box-sizing: border-box; max-width: 100vw; @@ -431,47 +489,6 @@ onBeforeUnmount(() => { &:focus-visible { outline: none; } - - &.center { - > .item { - text-align: center; - } - } - - &.big:not(.asDrawer) { - > .item { - padding: 6px 20px; - font-size: 1em; - line-height: 24px; - } - } - - &.asDrawer { - padding: 12px 0 max(env(safe-area-inset-bottom, 0px), 12px) 0; - width: 100%; - border-radius: 24px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - - > .item { - font-size: 1em; - padding: 12px 24px; - - &::before { - width: calc(100% - 24px); - border-radius: 12px; - } - - > .icon { - margin-right: 14px; - width: 24px; - } - } - - > .divider { - margin: 12px 0; - } - } } .item { diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index f8032f9b43..c766a33823 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -106,7 +106,7 @@ const zIndex = os.claimZIndex(props.zPriority); const useSendAnime = ref(false); const type = computed<ModalTypes>(() => { if (props.preferType === 'auto') { - if (!defaultStore.state.disableDrawer && isTouchUsing && deviceKind === 'smartphone') { + if ((defaultStore.state.menuStyle === 'drawer') || (defaultStore.state.menuStyle === 'auto' && isTouchUsing && deviceKind === 'smartphone')) { return 'drawer'; } else { return props.src != null ? 'popup' : 'dialog'; diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 69238b0436..1bfdfd0e76 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -17,13 +17,6 @@ SPDX-License-Identifier: AGPL-3.0-only </template> </MkSelect> - <MkRadios v-model="hemisphere"> - <template #label>{{ i18n.ts.hemisphere }}</template> - <option value="N">{{ i18n.ts._hemisphere.N }}</option> - <option value="S">{{ i18n.ts._hemisphere.S }}</option> - <template #caption>{{ i18n.ts._hemisphere.caption }}</template> - </MkRadios> - <MkRadios v-model="overridedDeviceKind"> <template #label>{{ i18n.ts.overridedDeviceKind }}</template> <option :value="null">{{ i18n.ts.auto }}</option> @@ -132,11 +125,18 @@ SPDX-License-Identifier: AGPL-3.0-only <MkSwitch v-model="squareAvatars">{{ i18n.ts.squareAvatars }}</MkSwitch> <MkSwitch v-model="showAvatarDecorations">{{ i18n.ts.showAvatarDecorations }}</MkSwitch> <MkSwitch v-model="useSystemFont">{{ i18n.ts.useSystemFont }}</MkSwitch> - <MkSwitch v-model="disableDrawer">{{ i18n.ts.disableDrawer }}</MkSwitch> <MkSwitch v-model="forceShowAds">{{ i18n.ts.forceShowAds }}</MkSwitch> <MkSwitch v-model="enableSeasonalScreenEffect">{{ i18n.ts.seasonalScreenEffect }}</MkSwitch> <MkSwitch v-model="useNativeUIForVideoAudioPlayer">{{ i18n.ts.useNativeUIForVideoAudioPlayer }}</MkSwitch> </div> + + <MkSelect v-model="menuStyle"> + <template #label>{{ i18n.ts.menuStyle }}</template> + <option value="auto">{{ i18n.ts.auto }}</option> + <option value="popup">{{ i18n.ts.popup }}</option> + <option value="drawer">{{ i18n.ts.drawer }}</option> + </MkSelect> + <div> <MkRadios v-model="emojiStyle"> <template #label>{{ i18n.ts.emojiStyle }}</template> @@ -225,6 +225,12 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts.other }}</template> <div class="_gaps"> + <MkRadios v-model="hemisphere"> + <template #label>{{ i18n.ts.hemisphere }}</template> + <option value="N">{{ i18n.ts._hemisphere.N }}</option> + <option value="S">{{ i18n.ts._hemisphere.S }}</option> + <template #caption>{{ i18n.ts._hemisphere.caption }}</template> + </MkRadios> <MkFolder> <template #label>{{ i18n.ts.additionalEmojiDictionary }}</template> <div class="_buttons"> @@ -244,6 +250,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, ref, watch } from 'vue'; import * as Misskey from 'misskey-js'; +import { langs } from '@@/js/config.js'; import MkSwitch from '@/components/MkSwitch.vue'; import MkSelect from '@/components/MkSelect.vue'; import MkRadios from '@/components/MkRadios.vue'; @@ -254,7 +261,6 @@ import FormSection from '@/components/form/section.vue'; import FormLink from '@/components/form/link.vue'; import MkLink from '@/components/MkLink.vue'; import MkInfo from '@/components/MkInfo.vue'; -import { langs } from '@@/js/config.js'; import { defaultStore } from '@/store.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; @@ -287,7 +293,7 @@ const advancedMfm = computed(defaultStore.makeGetterSetter('advancedMfm')); const showReactionsCount = computed(defaultStore.makeGetterSetter('showReactionsCount')); const enableQuickAddMfmFunction = computed(defaultStore.makeGetterSetter('enableQuickAddMfmFunction')); const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle')); -const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer')); +const menuStyle = computed(defaultStore.makeGetterSetter('menuStyle')); const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages')); const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds')); const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages')); diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 1552a7afee..f6f3b933c6 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -39,6 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, onUnmounted, ref } from 'vue'; import { v4 as uuid } from 'uuid'; +import { version, host } from '@@/js/config.js'; import FormSection from '@/components/form/section.vue'; import MkButton from '@/components/MkButton.vue'; import MkInfo from '@/components/MkInfo.vue'; @@ -49,7 +50,6 @@ import { unisonReload } from '@/scripts/unison-reload.js'; import { useStream } from '@/stream.js'; import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; -import { version, host } from '@@/js/config.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { miLocalStorage } from '@/local-storage.js'; @@ -75,7 +75,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'dataSaver', 'disableShowingAnimatedImages', 'emojiStyle', - 'disableDrawer', + 'menuStyle', 'useBlurEffectForModal', 'useBlurEffect', 'showFixedPostForm', diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 40615cfc7d..5b10a9a387 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -5,10 +5,12 @@ import { markRaw, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import { hemisphere } from '@@/js/intl-const.js'; +import lightTheme from '@@/themes/l-light.json5'; +import darkTheme from '@@/themes/d-green-lime.json5'; import { miLocalStorage } from './local-storage.js'; import type { SoundType } from '@/scripts/sound.js'; import { Storage } from '@/pizzax.js'; -import { hemisphere } from '@@/js/intl-const.js'; interface PostFormAction { title: string, @@ -250,9 +252,9 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: 'twemoji', // twemoji / fluentEmoji / native }, - disableDrawer: { + menuStyle: { where: 'device', - default: false, + default: 'auto' as 'auto' | 'popup' | 'drawer', }, useBlurEffectForModal: { where: 'device', @@ -520,8 +522,6 @@ interface Watcher { /** * 常にメモリにロードしておく必要がないような設定情報を保管するストレージ(非リアクティブ) */ -import lightTheme from '@@/themes/l-light.json5'; -import darkTheme from '@@/themes/d-green-lime.json5'; export class ColdDeviceStorage { public static default = {