feat(frontend): タイトルバーを表示できるように
This commit is contained in:
parent
2e91cd6d45
commit
d6ae4c980b
|
@ -13,6 +13,7 @@
|
||||||
### Client
|
### Client
|
||||||
- Feat: チャットウィジェットを追加
|
- Feat: チャットウィジェットを追加
|
||||||
- Feat: デッキにチャットカラムを追加
|
- Feat: デッキにチャットカラムを追加
|
||||||
|
- Feat: タイトルバーを表示できるように
|
||||||
- Enhance: Unicode絵文字をslugから入力する際に`:ok:`のように最後の`:`を入力したあとにUnicode絵文字に変換できるように
|
- Enhance: Unicode絵文字をslugから入力する際に`:ok:`のように最後の`:`を入力したあとにUnicode絵文字に変換できるように
|
||||||
- Enhance: コントロールパネルでジョブキューをクリアできるように
|
- Enhance: コントロールパネルでジョブキューをクリアできるように
|
||||||
- Enhance: テーマでページヘッダーの色を変更できるように
|
- Enhance: テーマでページヘッダーの色を変更できるように
|
||||||
|
|
|
@ -31,6 +31,7 @@ html {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
|
border-radius: 10px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ html.embed.noborder #splash {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
|
border-radius: 10px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
<SearchMarker :keywords="['titlebar', 'show']">
|
||||||
|
<MkPreferenceContainer k="showTitlebar">
|
||||||
|
<MkSwitch v-model="showTitlebar">
|
||||||
|
<template #label><SearchLabel>{{ i18n.ts.showTitlebar }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['avatar', 'icon', 'decoration', 'show']">
|
<SearchMarker :keywords="['avatar', 'icon', 'decoration', 'show']">
|
||||||
<MkPreferenceContainer k="showAvatarDecorations">
|
<MkPreferenceContainer k="showAvatarDecorations">
|
||||||
<MkSwitch v-model="showAvatarDecorations">
|
<MkSwitch v-model="showAvatarDecorations">
|
||||||
|
@ -742,6 +750,7 @@ const lang = ref(miLocalStorage.getItem('lang'));
|
||||||
const dataSaver = ref(prefer.s.dataSaver);
|
const dataSaver = ref(prefer.s.dataSaver);
|
||||||
|
|
||||||
const overridedDeviceKind = prefer.model('overridedDeviceKind');
|
const overridedDeviceKind = prefer.model('overridedDeviceKind');
|
||||||
|
const showTitlebar = prefer.model('showTitlebar');
|
||||||
const keepCw = prefer.model('keepCw');
|
const keepCw = prefer.model('keepCw');
|
||||||
const serverDisconnectedBehavior = prefer.model('serverDisconnectedBehavior');
|
const serverDisconnectedBehavior = prefer.model('serverDisconnectedBehavior');
|
||||||
const hemisphere = prefer.model('hemisphere');
|
const hemisphere = prefer.model('hemisphere');
|
||||||
|
|
|
@ -333,6 +333,9 @@ export const PREF_DEF = {
|
||||||
showNavbarSubButtons: {
|
showNavbarSubButtons: {
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
showTitlebar: {
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
default: [] as Plugin[],
|
default: [] as Plugin[],
|
||||||
},
|
},
|
||||||
|
|
|
@ -413,7 +413,7 @@ if ($i) {
|
||||||
|
|
||||||
#devTicker {
|
#devTicker {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2147483647;
|
z-index: 2147483647;
|
||||||
color: #ff0;
|
color: #ff0;
|
||||||
|
|
|
@ -121,6 +121,7 @@ function more() {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 38px;
|
width: 38px;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom {
|
.bottom {
|
||||||
|
|
|
@ -7,7 +7,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="[$style.root, { [$style.iconOnly]: iconOnly }]">
|
<div :class="[$style.root, { [$style.iconOnly]: iconOnly }]">
|
||||||
<div :class="$style.body">
|
<div :class="$style.body">
|
||||||
<div :class="$style.top">
|
<div :class="$style.top">
|
||||||
<div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
|
|
||||||
<button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
|
<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" style="viewTransitionName: navbar-serverIcon;"/>
|
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon" style="viewTransitionName: navbar-serverIcon;"/>
|
||||||
</button>
|
</button>
|
||||||
|
@ -183,12 +182,9 @@ function menuEdit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
position: fixed;
|
position: relative;
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
width: var(--nav-icon-only-width);
|
width: var(--nav-icon-only-width);
|
||||||
height: 100dvh;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
overflow-x: clip;
|
overflow-x: clip;
|
||||||
|
@ -303,18 +299,6 @@ function menuEdit() {
|
||||||
backdrop-filter: var(--MI-blur, blur(8px));
|
backdrop-filter: var(--MI-blur, blur(8px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.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%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.instance {
|
.instance {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -335,6 +319,7 @@ function menuEdit() {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 38px;
|
width: 38px;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom {
|
.bottom {
|
||||||
|
@ -559,6 +544,7 @@ function menuEdit() {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom {
|
.bottom {
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="$style.root">
|
||||||
|
<div :class="$style.title">
|
||||||
|
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
|
||||||
|
<span :class="$style.instanceTitle">{{ instance.name ?? host }}</span>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.controls">
|
||||||
|
<span :class="$style.left">
|
||||||
|
<button v-if="canBack" class="_button" :class="$style.button" @click="goBack"><i class="ti ti-arrow-left"></i></button>
|
||||||
|
</span>
|
||||||
|
<span :class="$style.right">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { host } from '@@/js/config.js';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { instance } from '@/instance.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
|
const canBack = ref(true);
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
--height: 36px;
|
||||||
|
|
||||||
|
background: var(--MI_THEME-navBg);
|
||||||
|
height: var(--height);
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
height: var(--height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: var(--height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.instanceIcon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instanceTitle {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
height: var(--height);
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,10 +4,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.root, { [$style.withWallpaper]: withWallpaper }]">
|
<div :class="[$style.root]">
|
||||||
|
<XTitlebar v-if="prefer.r.showTitlebar.value" style="flex-shrink: 0;"/>
|
||||||
|
|
||||||
|
<div :class="$style.nonTitlebarArea">
|
||||||
<XSidebar v-if="!isMobile && prefer.r['deck.navbarPosition'].value === 'left'"/>
|
<XSidebar v-if="!isMobile && prefer.r['deck.navbarPosition'].value === 'left'"/>
|
||||||
|
|
||||||
<div :class="$style.main">
|
<div :class="[$style.main, { [$style.withWallpaper]: withWallpaper, [$style.withSidebarAndTitlebar]: !isMobile && prefer.r['deck.navbarPosition'].value === 'left' && prefer.r.showTitlebar.value }]" :style="{ backgroundImage: prefer.s['deck.wallpaper'] != null ? `url(${ prefer.s['deck.wallpaper'] })` : null }">
|
||||||
<XNavbarH v-if="!isMobile && prefer.r['deck.navbarPosition'].value === 'top'"/>
|
<XNavbarH v-if="!isMobile && prefer.r['deck.navbarPosition'].value === 'top'"/>
|
||||||
|
|
||||||
<XAnnouncements v-if="$i"/>
|
<XAnnouncements v-if="$i"/>
|
||||||
|
@ -70,6 +73,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<XMobileFooterMenu v-if="isMobile" v-model:drawerMenuShowing="drawerMenuShowing" v-model:widgetsShowing="widgetsShowing"/>
|
<XMobileFooterMenu v-if="isMobile" v-model:drawerMenuShowing="drawerMenuShowing" v-model:widgetsShowing="widgetsShowing"/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<XCommon v-model:drawerMenuShowing="drawerMenuShowing" v-model:widgetsShowing="widgetsShowing"/>
|
<XCommon v-model:drawerMenuShowing="drawerMenuShowing" v-model:widgetsShowing="widgetsShowing"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,6 +86,7 @@ import XCommon from './_common_/common.vue';
|
||||||
import XSidebar from '@/ui/_common_/navbar.vue';
|
import XSidebar from '@/ui/_common_/navbar.vue';
|
||||||
import XNavbarH from '@/ui/_common_/navbar-h.vue';
|
import XNavbarH from '@/ui/_common_/navbar-h.vue';
|
||||||
import XMobileFooterMenu from '@/ui/_common_/mobile-footer-menu.vue';
|
import XMobileFooterMenu from '@/ui/_common_/mobile-footer-menu.vue';
|
||||||
|
import XTitlebar from '@/ui/_common_/titlebar.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
@ -209,30 +214,25 @@ async function deleteProfile() {
|
||||||
|
|
||||||
window.document.documentElement.style.overflowY = 'hidden';
|
window.document.documentElement.style.overflowY = 'hidden';
|
||||||
window.document.documentElement.style.scrollBehavior = 'auto';
|
window.document.documentElement.style.scrollBehavior = 'auto';
|
||||||
|
|
||||||
if (prefer.s['deck.wallpaper'] != null) {
|
|
||||||
window.document.documentElement.style.backgroundImage = `url(${prefer.s['deck.wallpaper']})`;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.root {
|
.root {
|
||||||
$nav-hide-threshold: 650px; // TODO: どこかに集約したい
|
|
||||||
|
|
||||||
--MI-margin: var(--MI-marginHalf);
|
--MI-margin: var(--MI-marginHalf);
|
||||||
|
|
||||||
--columnGap: v-bind("gap + 'px'");
|
--columnGap: v-bind("gap + 'px'");
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
background: var(--MI_THEME-navBg);
|
||||||
|
}
|
||||||
|
|
||||||
&.withWallpaper {
|
.nonTitlebarArea {
|
||||||
.main {
|
display: flex;
|
||||||
background: transparent;
|
flex: 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
|
@ -240,7 +240,15 @@ if (prefer.s['deck.wallpaper'] != null) {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
&:not(.withWallpaper) {
|
||||||
background: var(--MI_THEME-deckBg);
|
background: var(--MI_THEME-deckBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.withSidebarAndTitlebar {
|
||||||
|
border-radius: 12px 0 0 0;
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.columnsWrapper {
|
.columnsWrapper {
|
||||||
|
|
|
@ -5,9 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.root, { '_forceShrinkSpacer': deviceKind === 'smartphone' }]">
|
<div :class="[$style.root, { '_forceShrinkSpacer': deviceKind === 'smartphone' }]">
|
||||||
|
<XTitlebar v-if="prefer.r.showTitlebar.value" style="flex-shrink: 0;"/>
|
||||||
|
|
||||||
|
<div :class="$style.nonTitlebarArea">
|
||||||
<XSidebar v-if="!isMobile" :class="$style.sidebar" :showWidgetButton="!isDesktop" @widgetButtonClick="widgetsShowing = true"/>
|
<XSidebar v-if="!isMobile" :class="$style.sidebar" :showWidgetButton="!isDesktop" @widgetButtonClick="widgetsShowing = true"/>
|
||||||
|
|
||||||
<div :class="$style.contents" @contextmenu.stop="onContextmenu">
|
<div :class="[$style.contents, !isMobile && prefer.r.showTitlebar.value ? $style.withSidebarAndTitlebar : null]" @contextmenu.stop="onContextmenu">
|
||||||
<div>
|
<div>
|
||||||
<XPreferenceRestore v-if="shouldSuggestRestoreBackup"/>
|
<XPreferenceRestore v-if="shouldSuggestRestoreBackup"/>
|
||||||
<XAnnouncements v-if="$i"/>
|
<XAnnouncements v-if="$i"/>
|
||||||
|
@ -21,6 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-if="isDesktop && !pageMetadata?.needWideArea" :class="$style.widgets">
|
<div v-if="isDesktop && !pageMetadata?.needWideArea" :class="$style.widgets">
|
||||||
<XWidgets/>
|
<XWidgets/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<XCommon v-model:drawerMenuShowing="drawerMenuShowing" v-model:widgetsShowing="widgetsShowing"/>
|
<XCommon v-model:drawerMenuShowing="drawerMenuShowing" v-model:widgetsShowing="widgetsShowing"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +38,7 @@ import XCommon from './_common_/common.vue';
|
||||||
import type { PageMetadata } from '@/page.js';
|
import type { PageMetadata } from '@/page.js';
|
||||||
import XMobileFooterMenu from '@/ui/_common_/mobile-footer-menu.vue';
|
import XMobileFooterMenu from '@/ui/_common_/mobile-footer-menu.vue';
|
||||||
import XPreferenceRestore from '@/ui/_common_/PreferenceRestore.vue';
|
import XPreferenceRestore from '@/ui/_common_/PreferenceRestore.vue';
|
||||||
|
import XTitlebar from '@/ui/_common_/titlebar.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
@ -128,8 +133,14 @@ $widgets-hide-threshold: 1090px;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--MI_THEME-navBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nonTitlebarArea {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
|
@ -142,7 +153,12 @@ $widgets-hide-threshold: 1090px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background: var(--MI_THEME-bg);
|
|
||||||
|
&.withSidebarAndTitlebar {
|
||||||
|
background: var(--MI_THEME-navBg);
|
||||||
|
border-radius: 12px 0 0 0;
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|
Loading…
Reference in New Issue