mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat(web): add sidebar collapse
This commit is contained in:
@@ -2,18 +2,23 @@
|
|||||||
<aside>
|
<aside>
|
||||||
<Sidebar collapsible="icon">
|
<Sidebar collapsible="icon">
|
||||||
<SidebarHeader class="p-0 border-0">
|
<SidebarHeader class="p-0 border-0">
|
||||||
<div class="h-1.5 group-data-[collapsible=icon]:hidden" />
|
<div class="h-10 flex items-center pl-2 group-data-[collapsible=icon]:pl-3 transition-[padding] duration-200 ease-linear">
|
||||||
<div class="h-9.5 flex items-center group-data-[collapsible=icon]:justify-center">
|
<Button
|
||||||
<div class="flex items-center gap-1 ml-3 group-data-[collapsible=icon]:hidden">
|
variant="ghost"
|
||||||
<span class="text-[10px] font-medium text-muted-foreground uppercase tracking-[0.7px]">
|
size="icon"
|
||||||
{{ t('sidebar.bots') }}
|
class="size-6 text-muted-foreground hover:text-foreground shrink-0"
|
||||||
</span>
|
aria-label="Toggle Sidebar"
|
||||||
</div>
|
@click="toggleSidebar"
|
||||||
<div class="flex items-center gap-1 ml-auto mr-1.5 group-data-[collapsible=icon]:ml-0 group-data-[collapsible=icon]:mr-0">
|
>
|
||||||
|
<PanelLeftClose class="size-3.5 group-data-[collapsible=icon]:hidden" />
|
||||||
|
<PanelLeftOpen class="size-3.5 hidden group-data-[collapsible=icon]:block" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<div class="ml-auto mr-1.5 group-data-[collapsible=icon]:hidden">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
class="size-6 text-muted-foreground hover:text-foreground"
|
class="size-6 text-muted-foreground hover:text-foreground shrink-0"
|
||||||
:aria-label="t('bots.createBot')"
|
:aria-label="t('bots.createBot')"
|
||||||
@click="router.push({ name: 'bots' })"
|
@click="router.push({ name: 'bots' })"
|
||||||
>
|
>
|
||||||
@@ -120,14 +125,16 @@ import {
|
|||||||
SidebarMenuButton,
|
SidebarMenuButton,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
SidebarRail,
|
SidebarRail,
|
||||||
|
useSidebar,
|
||||||
} from '@memohai/ui'
|
} from '@memohai/ui'
|
||||||
import { Plus, LoaderCircle, Settings } from 'lucide-vue-next'
|
import { Plus, LoaderCircle, Settings, PanelLeftClose, PanelLeftOpen } from 'lucide-vue-next'
|
||||||
import BotItem from './bot-item.vue'
|
import BotItem from './bot-item.vue'
|
||||||
import { usePinnedBots } from '@/composables/usePinnedBots'
|
import { usePinnedBots } from '@/composables/usePinnedBots'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const { toggleSidebar } = useSidebar()
|
||||||
// const { userInfo } = useUserStore()
|
// const { userInfo } = useUserStore()
|
||||||
const { sortBots } = usePinnedBots()
|
const { sortBots } = usePinnedBots()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="flex h-dvh overflow-hidden">
|
<section class="flex h-dvh overflow-hidden">
|
||||||
<sidebar-provider
|
<sidebar-provider
|
||||||
|
v-model:open="isOpen"
|
||||||
class="min-h-0 h-full"
|
class="min-h-0 h-full"
|
||||||
:default-open="sidebarDefaultOpen"
|
:default-open="sidebarDefaultOpen"
|
||||||
>
|
>
|
||||||
@@ -15,7 +16,20 @@
|
|||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
import { SidebarProvider } from '@memohai/ui'
|
import { SidebarProvider } from '@memohai/ui'
|
||||||
|
import { useMediaQuery } from '@vueuse/core'
|
||||||
|
|
||||||
const sidebarDefaultOpen = !document.cookie.includes('sidebar_state=false')
|
const sidebarDefaultOpen = !document.cookie.includes('sidebar_state=false')
|
||||||
|
const isOpen = ref(sidebarDefaultOpen)
|
||||||
|
|
||||||
|
const isSmallScreen = useMediaQuery('(max-width: 1024px)')
|
||||||
|
|
||||||
|
watch(isSmallScreen, (isSmall) => {
|
||||||
|
if (isSmall) {
|
||||||
|
isOpen.value = false
|
||||||
|
} else {
|
||||||
|
isOpen.value = true
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SidebarProps } from '.'
|
import type { SidebarProps } from '.'
|
||||||
import { cn } from '#/lib/utils'
|
import { cn } from '#/lib/utils'
|
||||||
import { Sheet, SheetContent } from '#/components/sheet'
|
import { SIDEBAR_WIDTH, useSidebar } from './utils'
|
||||||
import SheetDescription from '#/components/sheet/SheetDescription.vue'
|
|
||||||
import SheetHeader from '#/components/sheet/SheetHeader.vue'
|
|
||||||
import SheetTitle from '#/components/sheet/SheetTitle.vue'
|
|
||||||
import { SIDEBAR_WIDTH, SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
@@ -17,7 +13,7 @@ const props = withDefaults(defineProps<SidebarProps>(), {
|
|||||||
collapsible: 'offcanvas',
|
collapsible: 'offcanvas',
|
||||||
})
|
})
|
||||||
|
|
||||||
const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
const { state } = useSidebar()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -30,35 +26,9 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
|||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Sheet
|
|
||||||
v-else-if="isMobile"
|
|
||||||
:open="openMobile"
|
|
||||||
v-bind="$attrs"
|
|
||||||
@update:open="setOpenMobile"
|
|
||||||
>
|
|
||||||
<SheetContent
|
|
||||||
data-sidebar="sidebar"
|
|
||||||
data-slot="sidebar"
|
|
||||||
data-mobile="true"
|
|
||||||
:side="side"
|
|
||||||
class="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
|
|
||||||
:style="{
|
|
||||||
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<SheetHeader class="sr-only">
|
|
||||||
<SheetTitle>Sidebar</SheetTitle>
|
|
||||||
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
|
|
||||||
</SheetHeader>
|
|
||||||
<div class="flex h-full w-full flex-col">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</SheetContent>
|
|
||||||
</Sheet>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="group peer text-sidebar-foreground hidden md:block"
|
class="group peer text-sidebar-foreground block"
|
||||||
data-slot="sidebar"
|
data-slot="sidebar"
|
||||||
:data-state="state"
|
:data-state="state"
|
||||||
:data-collapsible="state === 'collapsed' ? collapsible : ''"
|
:data-collapsible="state === 'collapsed' ? collapsible : ''"
|
||||||
@@ -79,7 +49,7 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
:class="cn(
|
:class="cn(
|
||||||
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
|
'fixed inset-y-0 z-10 flex h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear',
|
||||||
side === 'left'
|
side === 'left'
|
||||||
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
||||||
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function setOpenMobile(value: boolean) {
|
|||||||
|
|
||||||
// Helper to toggle the sidebar.
|
// Helper to toggle the sidebar.
|
||||||
function toggleSidebar() {
|
function toggleSidebar() {
|
||||||
return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)
|
return setOpen(!open.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEventListener('keydown', (event: KeyboardEvent) => {
|
useEventListener('keydown', (event: KeyboardEvent) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user