feat: ナビゲーションメニューにバナー表示オプションを追加

This commit is contained in:
NoriDev 2023-06-11 23:57:11 +09:00
parent 6aaffa798f
commit ed948bf91a
12 changed files with 110 additions and 21 deletions

View file

@ -35,6 +35,7 @@
- 노트 검색을 전체/로컬/리모트로 나누도록 변경 ([misskey.design 4adad07](https://github.com/kiyo4act/misskey.design/commit/4adad0768ce02bd49207a94678cf3c9130ed9e10))
- 노트/유저 검색 페이지에서 Enter 키를 누르면 검색하도록
- 프로필 번역 기능 추가
- 네비게이션 메뉴에 배너 표시 옵션 추가
### Client
- 모바일에서 UI 흐림 효과를 껐을 때 가독성 향상

View file

@ -1,5 +1,6 @@
---
_lang_: "English"
displayBanner: "Display Banner Image"
requireRefresh: "When the page needs to refresh"
performanceWarning: "High resource usage can result in higher device temperatures and faster battery consumption"
photosensitiveSeizuresWarning: "Can cause photosensitive seizures"
@ -1102,6 +1103,11 @@ additionalEmojiDictionary: "Additional emoji dictionaries"
installed: "Installed"
branding: "Branding"
translateProfile: "Translate a profile"
_bannerDisplay:
all: "All"
top: "Top (Server banner)"
bottom: "Bottom (Profile banner)"
hide: "Hide"
_requireRefreshBehavior:
dialog: "Show warning dialog"
quiet: "Show unobtrusive alert"

7
locales/index.d.ts vendored
View file

@ -3,6 +3,7 @@
// Do not edit this file directly.
export interface Locale {
"_lang_": string;
"displayBanner": string;
"requireRefresh": string;
"performanceWarning": string;
"photosensitiveSeizuresWarning": string;
@ -1105,6 +1106,12 @@ export interface Locale {
"installed": string;
"branding": string;
"translateProfile": string;
"_bannerDisplay": {
"all": string;
"top": string;
"bottom": string;
"hide": string;
};
"_requireRefreshBehavior": {
"dialog": string;
"quiet": string;

View file

@ -1,5 +1,6 @@
_lang_: "日本語"
displayBanner: "バナー画像の表示"
requireRefresh: "ページの更新が必要なとき"
performanceWarning: "リソースを多く使用するため、デバイスの温度が高くなり、バッテリーの消耗が速くなる可能性があります"
photosensitiveSeizuresWarning: "光敏感性発作を起こす可能性があります"
@ -1103,6 +1104,12 @@ installed: "インストール済み"
branding: "ブランディング"
translateProfile: "プロフィールを翻訳する"
_bannerDisplay:
all: "全て"
top: "上部(サーバーバナー)"
bottom: "下部(プロフィールバナー)"
hide: "隠す"
_requireRefreshBehavior:
dialog: "ダイアログで通知"
quiet: "控えめに通知"

View file

@ -1,5 +1,6 @@
---
_lang_: "한국어"
displayBanner: "배너 이미지 표시"
requireRefresh: "페이지 새로 고침이 필요할 때"
performanceWarning: "리소스를 많이 사용하므로, 디바이스의 온도가 높아지고 배터리의 소모가 빨라질 수 있어요"
photosensitiveSeizuresWarning: "광과민성 발작을 일으킬 수 있어요"
@ -1102,6 +1103,11 @@ goToMisskey: "CherryPick으로"
additionalEmojiDictionary: "이모지 추가 사전"
installed: "설치됨"
translateProfile: "프로필 번역하기"
_bannerDisplay:
all: "전부"
top: "상단 (서버 배너)"
bottom: "하단 (프로필 배너)"
hide: "숨기기"
_requireRefreshBehavior:
dialog: "알림창 표시"
quiet: "조용히 알림"

View file

@ -37,6 +37,14 @@
<option value="top">{{ i18n.ts._menuDisplay.top }}</option>
<!-- <MkRadio v-model="menuDisplay" value="hide" disabled>{{ i18n.ts._menuDisplay.hide }}</MkRadio>--> <!-- TODO: サイドバーを完全に隠せるようにすると別途ハンバーガーボタンのようなものをUIに表示する必要があり面倒 -->
</MkRadios>
<MkRadios v-model="bannerDisplay">
<template #label>{{ i18n.ts.displayBanner }}</template>
<option value="all">{{ i18n.ts._bannerDisplay.all }}</option>
<option value="top">{{ i18n.ts._bannerDisplay.top }}</option>
<option value="bottom">{{ i18n.ts._bannerDisplay.bottom }}</option>
<option value="hide">{{ i18n.ts._bannerDisplay.hide }}</option>
</MkRadios>
</div>
</template>
@ -63,6 +71,7 @@ const items = ref(defaultStore.state.menu.map(x => ({
})));
const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay'));
const bannerDisplay = computed(defaultStore.makeGetterSetter('bannerDisplay'));
async function reloadAsk() {
if (defaultStore.state.requireRefreshBehavior === 'dialog') {
@ -109,7 +118,7 @@ function reset() {
}));
}
watch(menuDisplay, async () => {
watch([menuDisplay, bannerDisplay], async () => {
await reloadAsk();
});

View file

@ -82,6 +82,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'reactionPickerUseDrawerForMobile',
'defaultSideView',
'menuDisplay',
'bannerDisplay',
'reportError',
'squareAvatars',
'numberOfPageCache',

View file

@ -366,6 +366,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: 'dialog' as 'quiet' | 'dialog',
},
bannerDisplay: {
where: 'device',
default: 'all' as 'all' | 'top' | 'bottom' | 'hide',
},
}));
// TODO: 他のタブと永続化されたstateを同期

View file

@ -1,7 +1,7 @@
<template>
<div :class="$style.root">
<div :class="$style.top">
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'top'" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button>
@ -30,6 +30,7 @@
</MkA>
</div>
<div :class="$style.bottom">
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'bottom'" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button class="_button" :class="$style.post" data-cy-open-post-form @click="os.post">
<i :class="$style.postIcon" class="ti ti-pencil ti-fw"></i><span style="position: relative;">{{ i18n.ts.note }}</span>
</button>
@ -89,14 +90,25 @@ function more() {
.banner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
&.topBanner {
top: 0;
height: 100%;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
}
&.bottomBanner {
bottom: 0;
height: 80%;
background-position-y: -10px;
-webkit-mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
}
}
.instance {

View file

@ -2,7 +2,7 @@
<div :class="[$style.root, { [$style.iconOnly]: iconOnly }]">
<div :class="$style.body">
<div :class="$style.top">
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'top'" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button>
@ -40,6 +40,7 @@
</MkA>
</div>
<div :class="$style.bottom">
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'bottom'" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button v-tooltip.noDelay.right="i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post">
<i class="ti ti-pencil ti-fw" :class="$style.postIcon"></i><span :class="$style.postText">{{ i18n.ts.note }}</span>
</button>
@ -142,14 +143,25 @@ function more(ev: MouseEvent) {
.banner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
&.topBanner {
top: 0;
height: 100%;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
}
&.bottomBanner {
bottom: 0;
height: 80%;
background-position-y: -10px;
-webkit-mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
}
}
.instance {

View file

@ -1,7 +1,7 @@
<template>
<div :class="$style.root">
<div :class="$style.top">
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'top'" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button>
@ -30,6 +30,7 @@
</MkA>
</div>
<div :class="$style.bottom">
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'bottom'" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button class="_button" :class="$style.post" data-cy-open-post-form @click="os.post">
<i :class="$style.postIcon" class="ti ti-pencil ti-fw"></i><span style="position: relative;">{{ i18n.ts.note }}</span>
</button>
@ -98,14 +99,25 @@ function openProfile() {
.banner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
&.topBanner {
top: 0;
height: 100%;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
}
&.bottomBanner {
bottom: 0;
height: 80%;
background-position-y: -10px;
-webkit-mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
}
}
.instance {

View file

@ -2,7 +2,7 @@
<div :class="[$style.root, { [$style.iconOnly]: iconOnly }]">
<div :class="$style.body">
<div :class="$style.top">
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'top'" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button>
@ -40,6 +40,7 @@
</MkA>
</div>
<div :class="$style.bottom">
<div v-if="defaultStore.state.bannerDisplay === 'all' || defaultStore.state.bannerDisplay === 'bottom'" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button v-tooltip.noDelay.right="i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post">
<i class="ti ti-pencil ti-fw" :class="$style.postIcon"></i><span :class="$style.postText">{{ i18n.ts.note }}</span>
</button>
@ -153,14 +154,25 @@ function openProfile() {
.banner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
&.topBanner {
top: 0;
height: 100%;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
}
&.bottomBanner {
bottom: 0;
height: 80%;
background-position-y: -10px;
-webkit-mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
mask-image: linear-gradient(0deg,rgba(0,0,0,.75) 15%,rgba(0,0,0,0) 80%);
}
}
.instance {