initial commit
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
<script setup lang="ts">
|
||||
const { close: closeSidebar, open, sidebarWidth, resize, saveWidth } = useSidebar()
|
||||
const route = useRoute()
|
||||
|
||||
const isResizing = ref(false)
|
||||
const startX = ref(0)
|
||||
const initialWidth = ref(0)
|
||||
|
||||
const closeSidenavRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const onResizeStart = (event: MouseEvent) => {
|
||||
isResizing.value = true
|
||||
startX.value = event.clientX
|
||||
initialWidth.value = sidebarWidth.value
|
||||
document.body.style.cursor = 'col-resize'
|
||||
document.body.style.userSelect = 'none'
|
||||
}
|
||||
|
||||
const onResizeMove = (event: MouseEvent) => {
|
||||
if (!isResizing.value) return
|
||||
if (resizeAnimationFrame) return;
|
||||
|
||||
resizeAnimationFrame = requestAnimationFrame(() => {
|
||||
const deltaX = event.clientX - startX.value
|
||||
const newWidth = initialWidth.value + deltaX
|
||||
resize(newWidth)
|
||||
resizeAnimationFrame = null
|
||||
})
|
||||
}
|
||||
|
||||
const onResizeEnd = () => {
|
||||
if (!isResizing.value) return
|
||||
|
||||
isResizing.value = false
|
||||
document.body.style.cursor = ''
|
||||
document.body.style.userSelect = ''
|
||||
saveWidth()
|
||||
}
|
||||
|
||||
let resizeAnimationFrame: number | null = null
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('mousemove', onResizeMove)
|
||||
document.addEventListener('mouseup', onResizeEnd)
|
||||
|
||||
watch(hovering, (value) => {
|
||||
if (value) {
|
||||
const width = closeSidenavRef.value!.scrollWidth
|
||||
closeSidenavRef.value!.style.width = `${width}px`
|
||||
} else {
|
||||
closeSidenavRef.value!.style.width = '0'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('mousemove', onResizeMove)
|
||||
document.removeEventListener('mouseup', onResizeEnd)
|
||||
})
|
||||
|
||||
const hovering = ref(false)
|
||||
|
||||
const navKind = computed(() => {
|
||||
if (route.path === '/') return 'home'
|
||||
if (route.path.startsWith('/agent/')) return 'agent'
|
||||
return null
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<aside :class="[
|
||||
'h-full max-w-fit bg-[var(--color-base)] overflow-hidden will-change-width text-[var(--color-subtle)] select-none',
|
||||
open ? 'w-full mr-2' : 'w-0 mr-0',
|
||||
isResizing ? '' : 'transition-[width,margin] duration-250 ease-[cubic-bezier(0,0.55,0.45,1)]'
|
||||
]" :style="open ? { width: `${sidebarWidth}px` } : {}" @mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false">
|
||||
<div :style="{ minWidth: `${sidebarWidth}px` }" class="flex flex-col h-full justify-between">
|
||||
<div class="flex flex-col">
|
||||
<!-- Header -->
|
||||
<div class="relative flex flex-row gap-2 justify-between items-center pb-1.5">
|
||||
<SidenavHeader v-if="navKind === 'home'" v-model="hovering" />
|
||||
<SidenavHeaderAgent v-else-if="navKind === 'agent'" v-model="hovering" />
|
||||
|
||||
<div class="flex items-center justify-end text-[var(--color-subtle)] gap-0.5">
|
||||
<div ref="closeSidenavRef" style="width: 0;"
|
||||
:class="['flex-shrink-0 overflow-hidden rounded-lg transition-all duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)] transform-origin-center-right']">
|
||||
<button aria-label="close sidebar" @click="closeSidebar" :class="[
|
||||
'text-5 p-1.5 hover:bg-[var(--color-highlight)] bg-transparent transition-inherit',
|
||||
]">
|
||||
<Icon name="mynaui:panel-left-close"
|
||||
:class="['transition-inherit', hovering ? 'opacity-100 scale-100' : 'opacity-0 scale-95']" />
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="navKind === 'agent'" class="flex-shrink-0 overflow-hidden rounded-lg">
|
||||
<NuxtLink aria-label="Start a new topic" :to="`/agent/${route.params.id}`" :class="[
|
||||
'flex text-5 p-1.5 hover:bg-[var(--color-highlight)] bg-transparent text-inherit',
|
||||
]">
|
||||
<Icon name="mynaui:book-plus" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Menu -->
|
||||
<div class="max-h-full overflow-auto">
|
||||
<SidenavNavHome v-if="navKind === 'home'" />
|
||||
<SidenavNavAgent v-else-if="navKind === 'agent'" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Theme Switcher -->
|
||||
<div class="flex justify-end">
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
<!-- resize handle -->
|
||||
<div @mousedown="onResizeStart" class="absolute top-0 right-0 bottom-0 p-1 cursor-ew-resize">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user