2021-04-10 03:40:50 +00:00
< template >
2021-12-03 13:09:40 +00:00
< div class = "dkgtipfy" : class = "{ wallpaper }" >
< XSidebar v-if = "!isMobile" class = "sidebar" / >
2021-04-10 03:40:50 +00:00
2022-07-03 05:40:02 +00:00
< MkStickyContainer class = "contents" >
< template # header > < XStatusBars :class = "$style.statusbars" / > < / template >
< main style = "min-width: 0;" : style = "{ background: pageMetadata?.value?.bg }" @contextmenu.stop ="onContextmenu" >
2022-12-28 09:02:11 +00:00
< div :class = "$style.content" style = "container-type: inline-size;" >
2022-06-20 08:38:49 +00:00
< RouterView / >
2021-04-10 03:40:50 +00:00
< / div >
2022-07-03 05:40:02 +00:00
< div :class = "$style.spacer" > < / div >
2021-04-10 03:40:50 +00:00
< / main >
2022-07-03 05:40:02 +00:00
< / MkStickyContainer >
2021-04-10 03:40:50 +00:00
2021-12-03 13:09:40 +00:00
< div v-if = "isDesktop" ref="widgetsEl" class="widgets" >
2021-04-10 03:40:50 +00:00
< XWidgets @mounted ="attachSticky" / >
< / div >
2022-12-20 23:39:28 +00:00
< button v-if = "!isDesktop && !isMobile" class="widgetButton _button" @click="widgetsShowing = true"><i class="ti ti-apps" > < / i > < / button >
2021-12-03 13:09:40 +00:00
< div v-if = "isMobile" class="buttons" >
2023-01-02 00:41:43 +00:00
< button class = "button nav _button" @ click = "drawerMenuShowing = true" > < i class = "icon ti ti-menu-2" > < / i > < span v-if = "menuIndicated" class="indicator"><i class="_indicatorCircle" > < / i > < / span > < / button >
< button class = "button home _button" @ click = "mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')" > < i class = "icon ti ti-home" > < / i > < / button >
< button class = "button notifications _button" @click ="mainRouter.push('/my/notifications')" > < i class = "icon ti ti-bell" > < / i > < span v-if = "$i?.hasUnreadNotification" class="indicator"><i class="_indicatorCircle" > < / i > < / span > < / button >
< button class = "button widget _button" @ click = "widgetsShowing = true" > < i class = "icon ti ti-apps" > < / i > < / button >
< button class = "button post _button" @click ="os.post()" > < i class = "icon ti ti-pencil" > < / i > < / button >
2021-04-10 03:40:50 +00:00
< / div >
2022-12-30 04:37:14 +00:00
< Transition : name = "$store.state.animation ? 'menuDrawer-back' : ''" >
2022-06-20 08:38:49 +00:00
< div
v - if = "drawerMenuShowing"
2021-12-03 13:09:40 +00:00
class = "menuDrawer-back _modalBg"
@ click = "drawerMenuShowing = false"
@ touchstart . passive = "drawerMenuShowing = false"
> < / div >
2022-12-30 04:37:14 +00:00
< / Transition >
2021-12-03 13:09:40 +00:00
2022-12-30 04:37:14 +00:00
< Transition : name = "$store.state.animation ? 'menuDrawer' : ''" >
2021-12-03 13:09:40 +00:00
< XDrawerMenu v-if = "drawerMenuShowing" class = "menuDrawer" / >
2022-12-30 04:37:14 +00:00
< / Transition >
2021-04-10 03:40:50 +00:00
2022-12-30 04:37:14 +00:00
< Transition : name = "$store.state.animation ? 'widgetsDrawer-back' : ''" >
2022-06-20 08:38:49 +00:00
< div
v - if = "widgetsShowing"
2021-12-03 13:09:40 +00:00
class = "widgetsDrawer-back _modalBg"
2021-04-10 03:40:50 +00:00
@ click = "widgetsShowing = false"
@ touchstart . passive = "widgetsShowing = false"
> < / div >
2022-12-30 04:37:14 +00:00
< / Transition >
2021-04-10 03:40:50 +00:00
2022-12-30 04:37:14 +00:00
< Transition : name = "$store.state.animation ? 'widgetsDrawer' : ''" >
2021-12-03 13:09:40 +00:00
< XWidgets v-if = "widgetsShowing" class = "widgetsDrawer" / >
2022-12-30 04:37:14 +00:00
< / Transition >
2021-04-10 03:40:50 +00:00
< XCommon / >
< / div >
< / template >
2022-02-01 14:48:19 +00:00
< script lang = "ts" setup >
2022-06-20 08:38:49 +00:00
import { defineAsyncComponent , provide , onMounted , computed , ref , watch , ComputedRef } from 'vue' ;
import XCommon from './_common_/common.vue' ;
2021-11-11 17:02:25 +00:00
import { instanceName } from '@/config' ;
import { StickySidebar } from '@/scripts/sticky-sidebar' ;
2022-07-14 08:42:12 +00:00
import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue' ;
2021-11-11 17:02:25 +00:00
import * as os from '@/os' ;
2021-12-03 13:09:40 +00:00
import { defaultStore } from '@/store' ;
2022-07-14 08:42:12 +00:00
import { navbarItemDef } from '@/navbar' ;
2021-12-03 13:09:40 +00:00
import { i18n } from '@/i18n' ;
2022-02-01 14:48:19 +00:00
import { $i } from '@/account' ;
2022-06-20 08:38:49 +00:00
import { Router } from '@/nirax' ;
import { mainRouter } from '@/router' ;
import { PageMetadata , provideMetadataReceiver , setPageMetadata } from '@/scripts/page-metadata' ;
2022-07-24 09:44:50 +00:00
import { deviceKind } from '@/scripts/device-kind' ;
2023-01-07 01:13:02 +00:00
import { miLocalStorage } from '@/local-storage' ;
2022-02-01 14:48:19 +00:00
const XWidgets = defineAsyncComponent ( ( ) => import ( './universal.widgets.vue' ) ) ;
2022-07-14 08:42:12 +00:00
const XSidebar = defineAsyncComponent ( ( ) => import ( '@/ui/_common_/navbar.vue' ) ) ;
2022-07-03 05:40:02 +00:00
const XStatusBars = defineAsyncComponent ( ( ) => import ( '@/ui/_common_/statusbars.vue' ) ) ;
2021-04-10 03:40:50 +00:00
const DESKTOP _THRESHOLD = 1100 ;
2021-12-03 13:09:40 +00:00
const MOBILE _THRESHOLD = 500 ;
2021-04-10 03:40:50 +00:00
2022-07-24 09:44:50 +00:00
// デスクトップでウィンドウを狭くしたときモバイルUIが表示されて欲しいことはあるので deviceKind === 'desktop' の判定は行わない
2022-02-01 14:48:19 +00:00
const isDesktop = ref ( window . innerWidth >= DESKTOP _THRESHOLD ) ;
2022-07-24 09:44:50 +00:00
const isMobile = ref ( deviceKind === 'smartphone' || window . innerWidth <= MOBILE _THRESHOLD ) ;
2022-02-01 14:48:19 +00:00
window . addEventListener ( 'resize' , ( ) => {
2022-07-24 09:44:50 +00:00
isMobile . value = deviceKind === 'smartphone' || window . innerWidth <= MOBILE _THRESHOLD ;
2022-02-01 14:48:19 +00:00
} ) ;
2022-06-20 08:38:49 +00:00
let pageMetadata = $ref < null | ComputedRef < PageMetadata > > ( ) ;
2023-01-03 01:12:37 +00:00
const widgetsEl = $shallowRef < HTMLElement > ( ) ;
2022-06-20 08:38:49 +00:00
const widgetsShowing = $ref ( false ) ;
provide ( 'router' , mainRouter ) ;
provideMetadataReceiver ( ( info ) => {
pageMetadata = info ;
if ( pageMetadata . value ) {
document . title = ` ${ pageMetadata . value . title } | ${ instanceName } ` ;
}
} ) ;
2022-02-01 14:48:19 +00:00
const menuIndicated = computed ( ( ) => {
2022-07-14 08:42:12 +00:00
for ( const def in navbarItemDef ) {
2022-02-01 14:48:19 +00:00
if ( def === 'notifications' ) continue ; // 通知は下にボタンとして表示されてるから
2022-07-14 08:42:12 +00:00
if ( navbarItemDef [ def ] . indicated ) return true ;
2022-02-01 14:48:19 +00:00
}
return false ;
} ) ;
const drawerMenuShowing = ref ( false ) ;
2022-06-20 08:38:49 +00:00
mainRouter . on ( 'change' , ( ) => {
2022-02-01 14:48:19 +00:00
drawerMenuShowing . value = false ;
} ) ;
document . documentElement . style . overflowY = 'scroll' ;
2023-01-02 07:02:42 +00:00
defaultStore . ready . then ( ( ) => {
if ( defaultStore . state . widgets . length === 0 ) {
defaultStore . set ( 'widgets' , [ {
name : 'calendar' ,
id : 'a' , place : 'right' , data : { } ,
} , {
name : 'notifications' ,
id : 'b' , place : 'right' , data : { } ,
} , {
name : 'trends' ,
id : 'c' , place : 'right' , data : { } ,
} ] ) ;
}
} ) ;
2022-02-01 14:48:19 +00:00
onMounted ( ( ) => {
if ( ! isDesktop . value ) {
2021-12-03 13:09:40 +00:00
window . addEventListener ( 'resize' , ( ) => {
2022-02-01 14:48:19 +00:00
if ( window . innerWidth >= DESKTOP _THRESHOLD ) isDesktop . value = true ;
} , { passive : true } ) ;
}
} ) ;
const onContextmenu = ( ev ) => {
const isLink = ( el : HTMLElement ) => {
if ( el . tagName === 'A' ) return true ;
if ( el . parentElement ) {
return isLink ( el . parentElement ) ;
}
} ;
if ( isLink ( ev . target ) ) return ;
if ( [ 'INPUT' , 'TEXTAREA' , 'IMG' , 'VIDEO' , 'CANVAS' ] . includes ( ev . target . tagName ) || ev . target . attributes [ 'contenteditable' ] ) return ;
if ( window . getSelection ( ) ? . toString ( ) !== '' ) return ;
2022-06-20 08:38:49 +00:00
const path = mainRouter . getCurrentPath ( ) ;
2022-02-01 14:48:19 +00:00
os . contextMenu ( [ {
type : 'label' ,
text : path ,
} , {
2022-12-19 10:01:30 +00:00
icon : 'ti ti-window-maximize' ,
2022-02-01 14:48:19 +00:00
text : i18n . ts . openInWindow ,
action : ( ) => {
os . pageWindow ( path ) ;
2022-06-20 08:38:49 +00:00
} ,
2022-02-01 14:48:19 +00:00
} ] , ev ) ;
} ;
const attachSticky = ( el ) => {
const sticky = new StickySidebar ( widgetsEl ) ;
window . addEventListener ( 'scroll' , ( ) => {
sticky . calc ( window . scrollY ) ;
} , { passive : true } ) ;
} ;
function top ( ) {
window . scroll ( { top : 0 , behavior : 'smooth' } ) ;
}
2021-04-10 03:40:50 +00:00
2023-01-07 01:13:02 +00:00
const wallpaper = miLocalStorage . getItem ( 'wallpaper' ) != null ;
2021-04-10 03:40:50 +00:00
< / script >
< style lang = "scss" scoped >
2021-12-03 13:09:40 +00:00
. widgetsDrawer - enter - active ,
. widgetsDrawer - leave - active {
2021-04-10 03:40:50 +00:00
opacity : 1 ;
transform : translateX ( 0 ) ;
transition : transform 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) , opacity 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) ;
}
2021-12-03 13:09:40 +00:00
. widgetsDrawer - enter - from ,
. widgetsDrawer - leave - active {
2021-04-10 03:40:50 +00:00
opacity : 0 ;
transform : translateX ( 240 px ) ;
}
2021-12-03 13:09:40 +00:00
. widgetsDrawer - back - enter - active ,
. widgetsDrawer - back - leave - active {
2021-04-10 03:40:50 +00:00
opacity : 1 ;
transition : opacity 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) ;
}
2021-12-03 13:09:40 +00:00
. widgetsDrawer - back - enter - from ,
. widgetsDrawer - back - leave - active {
2021-04-10 03:40:50 +00:00
opacity : 0 ;
}
2021-12-03 13:09:40 +00:00
. menuDrawer - enter - active ,
. menuDrawer - leave - active {
opacity : 1 ;
transform : translateX ( 0 ) ;
transition : transform 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) , opacity 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) ;
}
. menuDrawer - enter - from ,
. menuDrawer - leave - active {
opacity : 0 ;
transform : translateX ( - 240 px ) ;
}
. menuDrawer - back - enter - active ,
. menuDrawer - back - leave - active {
opacity : 1 ;
transition : opacity 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) ;
}
. menuDrawer - back - enter - from ,
. menuDrawer - back - leave - active {
opacity : 0 ;
}
. dkgtipfy {
2021-04-10 03:40:50 +00:00
$ui - font - size : 1 em ; // TODO: どこかに集約したい
$widgets - hide - threshold : 1090 px ;
2022-11-13 02:43:23 +00:00
min - height : 100 dvh ;
2021-04-10 03:40:50 +00:00
box - sizing : border - box ;
display : flex ;
& . wallpaper {
background : var ( -- wallpaperOverlay ) ;
2021-08-11 13:34:45 +00:00
//backdrop-filter: var(--blur, blur(4px));
2021-04-10 03:40:50 +00:00
}
2021-08-16 06:21:58 +00:00
> . sidebar {
2021-11-30 14:08:34 +00:00
border - right : solid 0.5 px var ( -- divider ) ;
2021-08-16 06:21:58 +00:00
}
2021-04-10 03:40:50 +00:00
> . contents {
width : 100 % ;
min - width : 0 ;
2022-07-02 05:00:37 +00:00
background : var ( -- bg ) ;
2021-04-10 03:40:50 +00:00
}
> . widgets {
padding : 0 var ( -- margin ) ;
2021-09-20 19:09:28 +00:00
border - left : solid 0.5 px var ( -- divider ) ;
background : var ( -- bg ) ;
2021-04-10 03:40:50 +00:00
@ media ( max - width : $widgets - hide - threshold ) {
display : none ;
}
}
> . widgetButton {
display : block ;
position : fixed ;
z - index : 1000 ;
bottom : 32 px ;
right : 32 px ;
width : 64 px ;
height : 64 px ;
border - radius : 100 % ;
box - shadow : 0 3 px 5 px - 1 px rgba ( 0 , 0 , 0 , 0.2 ) , 0 6 px 10 px 0 rgba ( 0 , 0 , 0 , 0.14 ) , 0 1 px 18 px 0 rgba ( 0 , 0 , 0 , 0.12 ) ;
font - size : 22 px ;
background : var ( -- panel ) ;
2021-12-03 13:09:40 +00:00
}
> . widgetsDrawer - back {
z - index : 1001 ;
}
> . widgetsDrawer {
position : fixed ;
top : 0 ;
right : 0 ;
z - index : 1001 ;
2022-11-13 02:43:23 +00:00
height : 100 dvh ;
2022-12-27 05:55:11 +00:00
padding : var ( -- margin ) ! important ;
2021-12-03 13:09:40 +00:00
box - sizing : border - box ;
overflow : auto ;
2021-12-03 13:22:08 +00:00
overscroll - behavior : contain ;
2021-12-03 13:09:40 +00:00
background : var ( -- bg ) ;
2021-04-10 03:40:50 +00:00
}
> . buttons {
position : fixed ;
z - index : 1000 ;
bottom : 0 ;
2021-12-03 13:09:40 +00:00
left : 0 ;
2023-01-02 23:26:39 +00:00
padding : 12 px 12 px max ( 12 px , env ( safe - area - inset - bottom , 0 px ) ) 12 px ;
2023-01-02 00:33:37 +00:00
display : grid ;
grid - template - columns : 1 fr 1 fr 1 fr 1 fr 1 fr ;
grid - gap : 8 px ;
2021-04-10 03:40:50 +00:00
width : 100 % ;
box - sizing : border - box ;
2021-08-11 13:34:45 +00:00
- webkit - backdrop - filter : var ( -- blur , blur ( 32 px ) ) ;
backdrop - filter : var ( -- blur , blur ( 32 px ) ) ;
2021-04-10 03:40:50 +00:00
background - color : var ( -- header ) ;
2022-02-12 07:52:01 +00:00
border - top : solid 0.5 px var ( -- divider ) ;
2021-04-10 03:40:50 +00:00
> . button {
position : relative ;
padding : 0 ;
2023-01-02 00:33:37 +00:00
aspect - ratio : 1 ;
width : 100 % ;
max - width : 60 px ;
2021-04-10 03:40:50 +00:00
margin : auto ;
2023-01-02 00:33:37 +00:00
border - radius : 100 % ;
2021-04-10 03:40:50 +00:00
background : var ( -- panel ) ;
color : var ( -- fg ) ;
& : hover {
background : var ( -- X2 ) ;
}
2021-04-20 14:22:59 +00:00
> . indicator {
2021-04-10 03:40:50 +00:00
position : absolute ;
top : 0 ;
left : 0 ;
color : var ( -- indicator ) ;
font - size : 16 px ;
animation : blink 1 s infinite ;
}
2023-01-02 00:41:43 +00:00
> . icon {
font - size : 18 px ;
2021-04-10 03:40:50 +00:00
}
& : disabled {
cursor : default ;
2023-01-02 00:41:43 +00:00
> . icon {
2021-04-10 03:40:50 +00:00
opacity : 0.5 ;
}
}
2023-01-02 23:26:39 +00:00
& . post {
background : linear - gradient ( 90 deg , var ( -- buttonGradateA ) , var ( -- buttonGradateB ) ) ;
color : var ( -- fgOnAccent ) ;
}
2021-04-10 03:40:50 +00:00
}
}
2021-12-03 13:09:40 +00:00
> . menuDrawer - back {
2021-04-10 03:40:50 +00:00
z - index : 1001 ;
}
2021-12-03 13:09:40 +00:00
> . menuDrawer {
2021-04-10 03:40:50 +00:00
position : fixed ;
top : 0 ;
2021-12-03 13:09:40 +00:00
left : 0 ;
2021-04-10 03:40:50 +00:00
z - index : 1001 ;
2022-11-13 02:43:23 +00:00
height : 100 dvh ;
2021-12-03 13:09:40 +00:00
width : 240 px ;
2021-04-10 03:40:50 +00:00
box - sizing : border - box ;
2022-07-15 13:09:05 +00:00
contain : strict ;
2021-04-10 03:40:50 +00:00
overflow : auto ;
2021-12-03 13:22:08 +00:00
overscroll - behavior : contain ;
2022-07-15 13:09:05 +00:00
background : var ( -- navBg ) ;
2021-04-10 03:40:50 +00:00
}
}
< / style >
2022-07-03 05:40:02 +00:00
< style lang = "scss" module >
. statusbars {
position : sticky ;
top : 0 ;
left : 0 ;
}
. spacer {
$widgets - hide - threshold : 1090 px ;
height : calc ( env ( safe - area - inset - bottom , 0 px ) + 96 px ) ;
@ media ( min - width : ( $widgets - hide - threshold + 1 px ) ) {
display : none ;
}
}
2021-04-10 03:40:50 +00:00
< / style >