Bundles in-flight ECHODO work with the Coolify deployment configuration: App - New routes: ai, forms, planner, settings (templates/types), teams, doc detail, whiteboard detail - New components: app shell rework (icon-rail, top-header), forms builder/renderer/responses, types manager, objects creation dialog, card primitive, form + overview views - New tRPC routers: favorites, forms, types, workspaces; updates to health and objects routers - Markdown backlog sync (packages/database) + cursor-sync schema/migrations - Schema additions: forms, types, favorites, markdown_backlog, cursor_sync - Initial Drizzle migrations checked in Deployment - docker/docker-compose.coolify.yml: drops bundled Postgres/Redis (uses CT 102 shared services), removes host port mappings, adds Coolify SERVICE_FQDN_* magic vars for web + collab - .env.example rewritten as the full ECHODO/Coolify variable manifest - NextAuth gains an Authentik OIDC provider (gated on env presence) - Root layout injects Umami tracking script when configured; metadata title flipped to ECHODO Security - .gitignore expanded to exclude AGENT-DEPLOY.md, .env.*, secrets/, credentials.*, *.key, *.crt, *.pem, ssh keys Made-with: Cursor
174 lines
5.2 KiB
TypeScript
174 lines
5.2 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
ChevronsLeft,
|
|
ChevronsRight,
|
|
ChevronDown,
|
|
ClipboardList,
|
|
FileText,
|
|
List,
|
|
Presentation,
|
|
LayoutGrid,
|
|
Plus,
|
|
Search,
|
|
SlidersHorizontal,
|
|
} from "lucide-react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
import { useSidebarStore } from "@/lib/stores/sidebar-store";
|
|
|
|
export interface SidebarHeaderProps {
|
|
collapsed: boolean;
|
|
onOpenSearch?: () => void;
|
|
onQuickAction?: (type: string) => void;
|
|
}
|
|
|
|
export function SidebarHeader({
|
|
collapsed,
|
|
onOpenSearch,
|
|
onQuickAction,
|
|
}: SidebarHeaderProps) {
|
|
const toggle = useSidebarStore((s) => s.toggle);
|
|
|
|
if (collapsed) {
|
|
return (
|
|
<div className="flex shrink-0 justify-center border-b border-sidebar-border px-1 py-2">
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="size-7 shrink-0 text-muted-foreground hover:text-sidebar-foreground"
|
|
onClick={toggle}
|
|
aria-label="Expand sidebar"
|
|
>
|
|
<ChevronsRight className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="right">Expand</TooltipContent>
|
|
</Tooltip>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex shrink-0 items-center gap-1 border-b border-sidebar-border px-2 py-2">
|
|
<span className="min-w-0 flex-1 truncate text-base font-semibold text-sidebar-foreground">
|
|
Home
|
|
</span>
|
|
<div className="flex shrink-0 items-center gap-0.5">
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="size-7 text-muted-foreground hover:text-sidebar-foreground"
|
|
aria-label="Search"
|
|
onClick={() => onOpenSearch?.()}
|
|
>
|
|
<Search className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom">Search</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="size-7 text-muted-foreground hover:text-sidebar-foreground"
|
|
aria-label="Filter"
|
|
>
|
|
<SlidersHorizontal className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom">Filter</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="size-7 text-muted-foreground hover:text-sidebar-foreground"
|
|
onClick={toggle}
|
|
aria-label="Collapse sidebar"
|
|
>
|
|
<ChevronsLeft className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom">Collapse</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<DropdownMenu>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="sm"
|
|
className="h-7 gap-0.5 px-1.5 text-muted-foreground hover:text-sidebar-foreground"
|
|
aria-label="Create"
|
|
>
|
|
<Plus className="size-4" />
|
|
<ChevronDown className="size-3 opacity-70" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom">Create</TooltipContent>
|
|
</Tooltip>
|
|
<DropdownMenuContent align="end" className="w-52">
|
|
<DropdownMenuItem
|
|
className="gap-2"
|
|
onClick={() => onQuickAction?.("list")}
|
|
>
|
|
<List className="size-4" />
|
|
List
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="gap-2"
|
|
onClick={() => onQuickAction?.("doc")}
|
|
>
|
|
<FileText className="size-4" />
|
|
Doc
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="gap-2"
|
|
onClick={() => onQuickAction?.("whiteboard")}
|
|
>
|
|
<Presentation className="size-4" />
|
|
Whiteboard
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="gap-2"
|
|
onClick={() => onQuickAction?.("form")}
|
|
>
|
|
<ClipboardList className="size-4" />
|
|
Form
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="gap-2"
|
|
onClick={() => onQuickAction?.("space")}
|
|
>
|
|
<LayoutGrid className="size-4" />
|
|
Space
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|