feat(ui): Add templates sidebar, tooltips styling, and canvas menu improvements

- Add Templates tab to both v1 sidebar and v2 bottom bar
- Add template categories (Official, SDXL, ControlNet, Video, Community)
- Style tooltips with JetBrains Mono, smaller size, uppercase
- Convert native title attributes to v-tooltip directive
- Add workspace/account sections to canvas logo dropdown menu
- Move Settings to icon in sidebar footer near Sign out
- Add sort/filter features across workspace pages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
orkhanart
2025-11-28 19:33:46 -08:00
parent 508815bc6c
commit 67f8e0aba9
10 changed files with 755 additions and 187 deletions

View File

@@ -1,6 +1,9 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import Tooltip from 'primevue/tooltip'
const vTooltip = Tooltip
interface MenuItem {
label: string
@@ -23,28 +26,6 @@ const router = useRouter()
const isTeam = computed(() => props.workspaceId === 'team')
// Workspace dropdown
const showWorkspaceMenu = ref(false)
// Mock workspaces for switching
const workspaces = [
{ id: 'personal', name: 'Personal', type: 'personal' as const },
{ id: 'team', name: 'Team Workspace', type: 'team' as const }
]
function toggleWorkspaceMenu(): void {
showWorkspaceMenu.value = !showWorkspaceMenu.value
}
function closeWorkspaceMenu(): void {
showWorkspaceMenu.value = false
}
function switchWorkspace(workspaceId: string): void {
router.push(`/${workspaceId}`)
closeWorkspaceMenu()
}
const userMenuGroups = computed<MenuGroup[]>(() => [
{
label: 'Overview',
@@ -109,132 +90,24 @@ function signOut(): void {
<aside
class="flex h-full w-60 flex-col border-r border-zinc-200 bg-zinc-50/50 dark:border-zinc-800 dark:bg-zinc-950"
>
<!-- Header with Dropdown -->
<div class="relative border-b border-zinc-200 dark:border-zinc-800">
<button
class="flex h-14 w-full items-center gap-3 px-4 transition-colors hover:bg-zinc-100 dark:hover:bg-zinc-800/50"
@click="toggleWorkspaceMenu"
>
<div
:class="[
'flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md text-sm font-semibold',
isTeam ? 'bg-blue-600 text-white' : 'bg-zinc-900 text-white dark:bg-zinc-100 dark:text-zinc-900'
]"
>
{{ workspaceId.charAt(0).toUpperCase() }}
</div>
<div class="flex-1 overflow-hidden text-left">
<p class="truncate text-sm font-medium text-zinc-900 dark:text-zinc-100">
{{ workspaceId }}
</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">
{{ isTeam ? 'Team' : 'Personal' }}
</p>
</div>
<i
:class="[
'pi text-xs text-zinc-400 transition-transform',
showWorkspaceMenu ? 'pi-chevron-up' : 'pi-chevron-down'
]"
/>
</button>
<!-- Dropdown Menu -->
<!-- Header -->
<div class="flex h-14 items-center gap-3 border-b border-zinc-200 px-4 dark:border-zinc-800">
<div
v-if="showWorkspaceMenu"
class="absolute left-2 right-2 top-full z-50 mt-1 rounded-lg border border-zinc-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-900"
:class="[
'flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md text-sm font-semibold',
isTeam ? 'bg-blue-600 text-white' : 'bg-zinc-900 text-white dark:bg-zinc-100 dark:text-zinc-900'
]"
>
<!-- Account Section -->
<div class="border-b border-zinc-100 p-2 dark:border-zinc-800">
<p class="px-2 py-1 text-xs font-medium text-zinc-500 dark:text-zinc-400">Account</p>
<RouterLink
to="/account/profile"
class="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-zinc-700 transition-colors hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
@click="closeWorkspaceMenu"
>
<i class="pi pi-user text-zinc-400" />
<span>Profile</span>
</RouterLink>
<RouterLink
to="/account/billing"
class="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-zinc-700 transition-colors hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
@click="closeWorkspaceMenu"
>
<i class="pi pi-credit-card text-zinc-400" />
<span>Billing</span>
</RouterLink>
</div>
<!-- Workspaces Section -->
<div class="border-b border-zinc-100 p-2 dark:border-zinc-800">
<p class="px-2 py-1 text-xs font-medium text-zinc-500 dark:text-zinc-400">Workspaces</p>
<button
v-for="ws in workspaces"
:key="ws.id"
class="flex w-full items-center gap-3 rounded-md px-2 py-2 text-left text-sm text-zinc-700 transition-colors hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
@click="switchWorkspace(ws.id)"
>
<div
:class="[
'flex h-6 w-6 items-center justify-center rounded text-xs font-semibold',
ws.type === 'team' ? 'bg-blue-600 text-white' : 'bg-zinc-200 text-zinc-700 dark:bg-zinc-700 dark:text-zinc-300'
]"
>
{{ ws.name.charAt(0) }}
</div>
<span class="flex-1">{{ ws.name }}</span>
<i v-if="ws.id === workspaceId" class="pi pi-check text-xs text-blue-600 dark:text-blue-400" />
</button>
<button
class="flex w-full items-center gap-3 rounded-md px-2 py-2 text-left text-sm text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-300"
@click="closeWorkspaceMenu"
>
<div class="flex h-6 w-6 items-center justify-center rounded border border-dashed border-zinc-300 dark:border-zinc-600">
<i class="pi pi-plus text-xs" />
</div>
<span>Create workspace</span>
</button>
</div>
<!-- About Section -->
<div class="p-2">
<RouterLink
to="/about"
class="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-zinc-700 transition-colors hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
@click="closeWorkspaceMenu"
>
<i class="pi pi-info-circle text-zinc-400" />
<span>About</span>
</RouterLink>
<a
href="https://docs.comfy.org"
target="_blank"
class="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-zinc-700 transition-colors hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
@click="closeWorkspaceMenu"
>
<i class="pi pi-book text-zinc-400" />
<span>Documentation</span>
<i class="pi pi-external-link ml-auto text-xs text-zinc-400" />
</a>
<a
href="https://github.com/comfyanonymous/ComfyUI"
target="_blank"
class="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-zinc-700 transition-colors hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"
@click="closeWorkspaceMenu"
>
<i class="pi pi-github text-zinc-400" />
<span>GitHub</span>
<i class="pi pi-external-link ml-auto text-xs text-zinc-400" />
</a>
</div>
{{ workspaceId.charAt(0).toUpperCase() }}
</div>
<div class="flex-1 overflow-hidden">
<p class="truncate text-sm font-medium text-zinc-900 dark:text-zinc-100">
{{ workspaceId }}
</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">
{{ isTeam ? 'Team' : 'Personal' }}
</p>
</div>
<!-- Backdrop to close menu -->
<div
v-if="showWorkspaceMenu"
class="fixed inset-0 z-40"
@click="closeWorkspaceMenu"
/>
</div>
<!-- Menu Groups -->
@@ -279,6 +152,7 @@ function signOut(): void {
<!-- Footer -->
<div class="flex items-center justify-end gap-1 border-t border-zinc-200 px-3 py-2 dark:border-zinc-800">
<RouterLink
v-tooltip.top="'Settings'"
:to="`/${workspaceId}/settings`"
:class="[
'flex h-8 w-8 items-center justify-center rounded-md transition-colors',
@@ -286,13 +160,12 @@ function signOut(): void {
? 'bg-zinc-900 text-white dark:bg-zinc-100 dark:text-zinc-900'
: 'text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-200'
]"
title="Settings"
>
<i class="pi pi-cog text-base" />
</RouterLink>
<button
v-tooltip.top="'Sign out'"
class="flex h-8 w-8 items-center justify-center rounded-md text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-200"
title="Sign out"
@click="signOut"
>
<i class="pi pi-sign-out text-base" />