2020-07-11 01:13:11 +00:00
< template >
2022-06-20 08:38:49 +00:00
< div
2022-07-03 11:30:58 +00:00
class = "mk-deck" : class = "[{ isMobile }]"
2020-12-26 13:41:00 +00:00
>
2021-12-03 13:09:40 +00:00
< XSidebar v -if = " ! isMobile " / >
2020-07-11 01:13:11 +00:00
2022-07-03 05:40:02 +00:00
< div class = "main" >
< XStatusBars class = "statusbars" / >
2022-07-03 14:13:41 +00:00
< div ref = "columnsEl" class = "columns" :class ="deckStore.reactiveState.columnAlign.value" @contextmenu.self.prevent ="onContextmenu" >
< template v-for ="ids in layout" >
<!-- sectionを利用しているのは 、 deck . vue側でcolumnに対してfirst - of - typeを効かせるため -- >
< section
v - if = "ids.length > 1"
class = "folder column"
: style = "columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }"
>
< DeckColumnCore v -for = " id in ids " :ref ="id" :key ="id" : column = "columns.find(c => c.id === id)" :is-stacked ="true" @ parent -focus = " moveFocus ( id , $ event ) " / >
< / section >
< DeckColumnCore
v - else
: ref = "ids[0]"
: key = "ids[0]"
class = "column"
: column = "columns.find(c => c.id === ids[0])"
: is - stacked = "false"
: style = "columns.find(c => c.id === ids[0])!.flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0])!.width + 'px' }"
@ parent - focus = "moveFocus(ids[0], $event)"
/ >
< / template >
< div v-if ="layout.length === 0" class="intro _panel" >
< div > { { i18n . ts . _deck . introduction } } < / div >
< MkButton primary class = "add" @click ="addColumn" > {{ i18n.ts._deck.addColumn }} < / MkButton >
< div > { { i18n . ts . _deck . introduction2 } } < / div >
2022-07-03 11:30:58 +00:00
< / div >
< div class = "sideMenu" >
2022-07-16 06:19:44 +00:00
< div class = "top" >
2022-12-19 10:01:30 +00:00
< button v -tooltip .noDelay.left = " ` $ { i18n.ts._deck.profile } : $ { deckStore.state.profile } ` " class = "_button button" @click ="changeProfile" > < i class = "ti ti-caret-down" > < / i > < / button >
< button v -tooltip .noDelay.left = " i18n.ts._deck.deleteProfile " class = "_button button" @click ="deleteProfile" > < i class = "ti ti-trash" > < / i > < / button >
2022-07-16 06:19:44 +00:00
< / div >
< div class = "middle" >
2022-12-19 10:01:30 +00:00
< button v -tooltip .noDelay.left = " i18n.ts._deck.addColumn " class = "_button button" @click ="addColumn" > < i class = "ti ti-plus" > < / i > < / button >
2022-07-16 06:19:44 +00:00
< / div >
< div class = "bottom" >
2022-12-19 10:01:30 +00:00
< button v -tooltip .noDelay.left = " i18n.ts.settings " class = "_button button settings" @click ="showSettings" > < i class = "ti ti-settings" > < / i > < / button >
2022-07-16 06:19:44 +00:00
< / div >
2022-07-03 11:30:58 +00:00
< / div >
2022-07-03 05:40:02 +00:00
< / div >
< / div >
2020-07-11 01:13:11 +00:00
2021-12-03 13:09:40 +00:00
< div v-if ="isMobile" class="buttons" >
2023-01-10 00:57:41 +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.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 post _button" @click ="os.post()" > < i class = "icon ti ti-pencil" > < / i > < / button >
2021-12-03 13:09:40 +00:00
< / div >
2022-12-30 04:37:14 +00:00
< Transition : name = "$store.state.animation ? 'menu-back' : ''" >
2022-06-20 08:38:49 +00:00
< div
v - if = "drawerMenuShowing"
2021-12-03 13:09:40 +00:00
class = "menu-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 ? 'menu' : ''" >
2021-12-03 13:09:40 +00:00
< XDrawerMenu v -if = " drawerMenuShowing " class = "menu" / >
2022-12-30 04:37:14 +00:00
< / Transition >
2020-07-11 01:13:11 +00:00
2020-10-24 16:21:41 +00:00
< XCommon / >
2020-07-11 01:13:11 +00:00
< / div >
< / template >
2022-03-20 18:11:14 +00:00
< script lang = "ts" setup >
2022-07-03 05:40:02 +00:00
import { computed , defineAsyncComponent , onMounted , provide , ref , watch } from 'vue' ;
2020-07-11 01:13:11 +00:00
import { v4 as uuid } from 'uuid' ;
2022-06-20 08:38:49 +00:00
import XCommon from './_common_/common.vue' ;
2022-07-16 06:19:44 +00:00
import { deckStore , addColumn as addColumnToStore , loadDeck , getProfiles , deleteProfile as deleteProfile _ } from './deck/deck-store' ;
2021-11-11 17:02:25 +00:00
import DeckColumnCore from '@/ui/deck/column-core.vue' ;
2022-07-14 08:42:12 +00:00
import XSidebar from '@/ui/_common_/navbar.vue' ;
import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue' ;
2022-09-06 09:21:49 +00:00
import MkButton from '@/components/MkButton.vue' ;
2021-11-11 17:02:25 +00:00
import { getScrollContainer } from '@/scripts/scroll' ;
import * as os from '@/os' ;
2022-07-14 08:42:12 +00:00
import { navbarItemDef } from '@/navbar' ;
2021-12-03 13:09:40 +00:00
import { $i } from '@/account' ;
import { i18n } from '@/i18n' ;
2022-06-20 08:38:49 +00:00
import { mainRouter } from '@/router' ;
2022-07-16 06:19:44 +00:00
import { unisonReload } from '@/scripts/unison-reload' ;
2022-07-03 05:40:02 +00:00
const XStatusBars = defineAsyncComponent ( ( ) => import ( '@/ui/_common_/statusbars.vue' ) ) ;
2020-10-17 11:12:00 +00:00
2022-07-16 20:12:22 +00:00
mainRouter . navHook = ( path , flag ) : boolean => {
if ( flag === 'forcePage' ) return false ;
2022-07-05 06:55:55 +00:00
const noMainColumn = ! deckStore . state . columns . some ( x => x . type === 'main' ) ;
if ( deckStore . state . navWindow || noMainColumn ) {
2022-06-28 08:59:23 +00:00
os . pageWindow ( path ) ;
return true ;
2022-07-05 06:55:55 +00:00
}
return false ;
} ;
2022-06-28 08:59:23 +00:00
2022-03-20 18:11:14 +00:00
const isMobile = ref ( window . innerWidth <= 500 ) ;
window . addEventListener ( 'resize' , ( ) => {
isMobile . value = window . innerWidth <= 500 ;
2020-07-11 01:13:11 +00:00
} ) ;
2022-03-20 18:11:14 +00:00
const drawerMenuShowing = ref ( false ) ;
2022-06-20 08:38:49 +00:00
const route = 'TODO' ;
2022-03-20 18:11:14 +00:00
watch ( route , ( ) => {
drawerMenuShowing . value = false ;
} ) ;
const columns = deckStore . reactiveState . columns ;
const layout = deckStore . reactiveState . layout ;
const menuIndicated = computed ( ( ) => {
if ( $i == null ) return false ;
2022-07-14 08:42:12 +00:00
for ( const def in navbarItemDef ) {
if ( navbarItemDef [ def ] . indicated ) return true ;
2022-03-20 18:11:14 +00:00
}
return false ;
} ) ;
2022-07-05 07:07:53 +00:00
function showSettings ( ) {
os . pageWindow ( '/settings/deck' ) ;
}
2023-01-03 01:12:37 +00:00
let columnsEl = $shallowRef < HTMLElement > ( ) ;
2022-07-03 05:40:02 +00:00
2022-03-20 18:11:14 +00:00
const addColumn = async ( ev ) => {
const columns = [
'main' ,
'widgets' ,
'notifications' ,
'tl' ,
'antenna' ,
'list' ,
'mentions' ,
'direct' ,
] ;
const { canceled , result : column } = await os . select ( {
title : i18n . ts . _deck . addColumn ,
items : columns . map ( column => ( {
2022-06-20 08:38:49 +00:00
value : column , text : i18n . t ( '_deck._columns.' + column ) ,
} ) ) ,
2022-03-20 18:11:14 +00:00
} ) ;
if ( canceled ) return ;
addColumnToStore ( {
type : column ,
id : uuid ( ) ,
name : i18n . t ( '_deck._columns.' + column ) ,
width : 330 ,
} ) ;
} ;
const onContextmenu = ( ev ) => {
os . contextMenu ( [ {
text : i18n . ts . _deck . addColumn ,
action : addColumn ,
} ] , ev ) ;
} ;
document . documentElement . style . overflowY = 'hidden' ;
document . documentElement . style . scrollBehavior = 'auto' ;
window . addEventListener ( 'wheel' , ( ev ) => {
2022-07-03 05:40:02 +00:00
if ( ev . target === columnsEl && ev . deltaX === 0 ) {
columnsEl . scrollLeft += ev . deltaY ;
} else if ( getScrollContainer ( ev . target as HTMLElement ) == null && ev . deltaX === 0 ) {
columnsEl . scrollLeft += ev . deltaY ;
2022-03-20 18:11:14 +00:00
}
} ) ;
loadDeck ( ) ;
function moveFocus ( id : string , direction : 'up' | 'down' | 'left' | 'right' ) {
// TODO??
}
2022-07-16 06:19:44 +00:00
function changeProfile ( ev : MouseEvent ) {
const items = ref ( [ {
text : deckStore . state . profile ,
active : true . valueOf ,
} ] ) ;
getProfiles ( ) . then ( profiles => {
items . value = [ {
text : deckStore . state . profile ,
active : true . valueOf ,
} , ... ( profiles . filter ( k => k !== deckStore . state . profile ) . map ( k => ( {
text : k ,
action : ( ) => {
deckStore . set ( 'profile' , k ) ;
unisonReload ( ) ;
} ,
} ) ) ) , null , {
text : i18n . ts . _deck . newProfile ,
2022-12-19 10:01:30 +00:00
icon : 'ti ti-plus' ,
2022-07-16 06:19:44 +00:00
action : async ( ) => {
const { canceled , result : name } = await os . inputText ( {
title : i18n . ts . _deck . profile ,
allowEmpty : false ,
} ) ;
if ( canceled ) return ;
deckStore . set ( 'profile' , name ) ;
unisonReload ( ) ;
} ,
} ] ;
} ) ;
os . popupMenu ( items , ev . currentTarget ? ? ev . target ) ;
}
async function deleteProfile ( ) {
const { canceled } = await os . confirm ( {
type : 'warning' ,
text : i18n . t ( 'deleteAreYouSure' , { x : deckStore . state . profile } ) ,
} ) ;
if ( canceled ) return ;
deleteProfile _ ( deckStore . state . profile ) ;
deckStore . set ( 'profile' , 'default' ) ;
unisonReload ( ) ;
}
2020-07-11 01:13:11 +00:00
< / script >
< style lang = "scss" scoped >
2021-12-03 13:09:40 +00:00
. menu - enter - active ,
. menu - 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 ) ;
}
. menu - enter - from ,
. menu - leave - active {
opacity : 0 ;
transform : translateX ( - 240 px ) ;
}
. menu - back - enter - active ,
. menu - back - leave - active {
opacity : 1 ;
transition : opacity 300 ms cubic - bezier ( 0.23 , 1 , 0.32 , 1 ) ;
}
. menu - back - enter - from ,
. menu - back - leave - active {
opacity : 0 ;
}
2020-07-11 01:13:11 +00:00
. mk - deck {
$nav - hide - threshold : 650 px ; // TODO: どこかに集約したい
-- margin : var ( -- marginHalf ) ;
2022-07-03 11:30:58 +00:00
-- deckDividerThickness : 5 px ;
2020-07-11 01:13:11 +00:00
display : flex ;
2022-11-13 02:43:23 +00:00
height : 100 dvh ;
2020-07-11 01:13:11 +00:00
box - sizing : border - box ;
flex : 1 ;
2021-12-03 13:09:40 +00:00
& . isMobile {
padding - bottom : 100 px ;
}
2022-07-03 05:40:02 +00:00
> . main {
flex : 1 ;
min - width : 0 ;
display : flex ;
flex - direction : column ;
2020-07-11 01:13:11 +00:00
2022-07-03 14:13:41 +00:00
> . columns {
2022-07-03 05:40:02 +00:00
flex : 1 ;
2022-07-03 11:30:58 +00:00
display : flex ;
2022-07-03 14:13:41 +00:00
overflow - x : auto ;
overflow - y : clip ;
2022-07-03 11:30:58 +00:00
2022-07-03 14:13:41 +00:00
& . center {
> . column : first - of - type {
margin - left : auto ;
}
2022-07-03 11:30:58 +00:00
2022-07-03 14:13:41 +00:00
> . column : last - of - type {
margin - right : auto ;
}
}
2022-07-03 11:30:58 +00:00
2022-07-03 14:13:41 +00:00
> . column {
flex - shrink : 0 ;
border - right : solid var ( -- deckDividerThickness ) var ( -- deckDivider ) ;
& : first - of - type {
border - left : solid var ( -- deckDividerThickness ) var ( -- deckDivider ) ;
2022-07-03 11:30:58 +00:00
}
2022-07-03 14:13:41 +00:00
& . folder {
display : flex ;
flex - direction : column ;
2022-07-03 05:40:02 +00:00
2022-07-03 14:13:41 +00:00
> * : not ( : last - of - type ) {
border - bottom : solid var ( -- deckDividerThickness ) var ( -- deckDivider ) ;
2022-07-03 11:30:58 +00:00
}
2022-07-03 14:13:41 +00:00
}
}
2022-07-03 05:40:02 +00:00
2022-07-03 14:13:41 +00:00
> . intro {
padding : 32 px ;
height : min - content ;
text - align : center ;
margin : auto ;
2022-07-03 05:40:02 +00:00
2022-07-03 14:13:41 +00:00
> . add {
margin : 1 em auto ;
2022-07-03 05:40:02 +00:00
}
2020-07-11 01:13:11 +00:00
}
2022-07-03 11:30:58 +00:00
> . sideMenu {
2022-07-03 14:13:41 +00:00
flex - shrink : 0 ;
margin - right : 0 ;
margin - left : auto ;
2022-07-03 11:30:58 +00:00
display : flex ;
flex - direction : column ;
justify - content : center ;
width : 32 px ;
2022-07-16 06:19:44 +00:00
> . top , > . middle , > . bottom {
> . button {
display : block ;
width : 100 % ;
aspect - ratio : 1 ;
}
}
> . top {
margin - bottom : auto ;
}
> . middle {
margin - top : auto ;
margin - bottom : auto ;
}
> . bottom {
margin - top : auto ;
2022-07-03 11:30:58 +00:00
}
}
2020-07-11 01:13:11 +00:00
}
}
2021-12-03 13:09:40 +00:00
> . buttons {
2020-07-11 01:13:11 +00:00
position : fixed ;
z - index : 1000 ;
2021-12-03 13:09:40 +00:00
bottom : 0 ;
left : 0 ;
2023-01-10 00:57:41 +00:00
padding : 12 px 12 px max ( 12 px , env ( safe - area - inset - bottom , 0 px ) ) 12 px ;
display : grid ;
grid - template - columns : 1 fr 1 fr 1 fr 1 fr ;
grid - gap : 8 px ;
2021-12-03 13:09:40 +00:00
width : 100 % ;
box - sizing : border - box ;
2023-01-10 00:57:41 +00:00
- webkit - backdrop - filter : var ( -- blur , blur ( 32 px ) ) ;
backdrop - filter : var ( -- blur , blur ( 32 px ) ) ;
background - color : var ( -- header ) ;
border - top : solid 0.5 px var ( -- divider ) ;
2020-07-11 01:13:11 +00:00
2021-12-03 13:09:40 +00:00
> . button {
position : relative ;
padding : 0 ;
2023-01-10 00:57:41 +00:00
aspect - ratio : 1 ;
width : 100 % ;
max - width : 60 px ;
2021-12-03 13:09:40 +00:00
margin : auto ;
2023-01-10 00:57:41 +00:00
border - radius : 100 % ;
2021-12-03 13:09:40 +00:00
background : var ( -- panel ) ;
color : var ( -- fg ) ;
2020-07-11 01:13:11 +00:00
2021-12-03 13:09:40 +00:00
& : hover {
background : var ( -- X2 ) ;
}
> . indicator {
position : absolute ;
top : 0 ;
left : 0 ;
color : var ( -- indicator ) ;
font - size : 16 px ;
animation : blink 1 s infinite ;
}
2023-01-10 00:57:41 +00:00
> . icon {
font - size : 18 px ;
2021-12-03 13:09:40 +00:00
}
& : disabled {
cursor : default ;
2023-01-10 00:57:41 +00:00
> . icon {
2021-12-03 13:09:40 +00:00
opacity : 0.5 ;
}
}
2023-01-10 00:57:41 +00:00
& . post {
background : linear - gradient ( 90 deg , var ( -- buttonGradateA ) , var ( -- buttonGradateB ) ) ;
color : var ( -- fgOnAccent ) ;
}
2020-07-11 01:13:11 +00:00
}
}
2021-12-03 13:09:40 +00:00
> . menu - back {
z - index : 1001 ;
}
> . menu {
position : fixed ;
top : 0 ;
left : 0 ;
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 ;
box - sizing : border - box ;
2022-07-15 13:09:05 +00:00
contain : strict ;
2021-12-03 13:09:40 +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-12-03 13:09:40 +00:00
}
2020-07-11 01:13:11 +00:00
}
< / style >