style: fresh look on header

This commit is contained in:
Maze Winther
2025-07-31 23:01:02 +02:00
parent c60ec04f8d
commit 5475cea0de
+73 -57
View File
@@ -1,23 +1,31 @@
"use client"; "use client";
import Link from "next/link";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { ChevronLeft, Download } from "lucide-react"; import { ChevronDown, ArrowLeft, Download, SquarePen, Trash } from "lucide-react";
import { useTimelineStore } from "@/stores/timeline-store"; import { useTimelineStore } from "@/stores/timeline-store";
import { HeaderBase } from "./header-base"; import { HeaderBase } from "./header-base";
import { formatTimeCode } from "@/lib/time"; import { formatTimeCode } from "@/lib/time";
import { useProjectStore } from "@/stores/project-store"; import { useProjectStore } from "@/stores/project-store";
import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help"; import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help";
import { useState, useRef } from "react"; import { useState } from "react";
import { Input } from "@/components/ui/input"; import {
import { toast } from "sonner"; DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "./ui/dropdown-menu";
import Link from "next/link";
import { RenameProjectDialog } from "./rename-project-dialog";
import { DeleteProjectDialog } from "./delete-project-dialog";
import { useRouter } from "next/navigation";
export function EditorHeader() { export function EditorHeader() {
const { getTotalDuration } = useTimelineStore(); const { getTotalDuration } = useTimelineStore();
const { activeProject, renameProject } = useProjectStore(); const { activeProject, renameProject, deleteProject } = useProjectStore();
const [isEditing, setIsEditing] = useState(false); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [newName, setNewName] = useState(activeProject?.name || ""); const [isRenameDialogOpen, setIsRenameDialogOpen] = useState(false);
const inputRef = useRef<HTMLInputElement>(null); const router = useRouter();
const handleExport = () => { const handleExport = () => {
// TODO: Implement export functionality // TODO: Implement export functionality
@@ -26,66 +34,75 @@ export function EditorHeader() {
window.open("https://youtube.com/watch?v=dQw4w9WgXcQ", "_blank"); window.open("https://youtube.com/watch?v=dQw4w9WgXcQ", "_blank");
}; };
const handleNameClick = () => { const handleNameSave = async (newName: string) => {
if (!activeProject) return; console.log("handleNameSave", newName);
setNewName(activeProject.name);
setIsEditing(true);
};
const handleNameSave = async () => {
if (activeProject && newName.trim() && newName !== activeProject.name) { if (activeProject && newName.trim() && newName !== activeProject.name) {
try { try {
await renameProject(activeProject.id, newName.trim()); await renameProject(activeProject.id, newName.trim());
setIsRenameDialogOpen(false);
} catch (error) { } catch (error) {
console.error("Failed to rename project:", error); console.error("Failed to rename project:", error);
setNewName(activeProject.name);
} }
} }
setIsEditing(false);
}; };
const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { const handleDelete = () => {
if (e.key === "Enter") handleNameSave(); if (activeProject) {
else if (e.key === "Escape") setIsEditing(false); deleteProject(activeProject.id);
setIsDeleteDialogOpen(false);
router.push("/projects");
}
}; };
const leftContent = ( const leftContent = (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Link <DropdownMenu>
href="/projects" <DropdownMenuTrigger asChild>
className="font-medium tracking-tight flex items-center gap-2 hover:opacity-80 transition-opacity" <Button
> variant="secondary"
<ChevronLeft className="h-4 w-4" /> className="h-auto py-1.5 px-2.5 flex items-center justify-center"
</Link>
<div className="w-40 xl:w-60 h-9 flex items-center">
{isEditing ? (
<Input
ref={inputRef}
className="text-sm font-medium w-full px-2 py-1 h-9 truncate"
value={newName}
onChange={(e) => setNewName(e.target.value)}
onBlur={handleNameSave}
onKeyDown={handleInputKeyDown}
onFocus={(e) => e.target.select()}
maxLength={64}
aria-label="Project name"
autoFocus
/>
) : (
<span
className="text-sm font-medium cursor-pointer hover:underline"
title="Click to rename"
role="button"
tabIndex={0}
onClick={handleNameClick}
onKeyDown={(e) => e.key === "Enter" && handleNameClick()}
> >
<div className="truncate text-ellipsis overflow-clip max-w-40 xl:max-w-60"> <ChevronDown className="text-muted-foreground" />
{activeProject?.name} <span className="text-[0.85rem] mr-2">{activeProject?.name}</span>
</div> </Button>
</span> </DropdownMenuTrigger>
)} <DropdownMenuContent align="start" className="w-40">
</div> <Link href="/projects">
<DropdownMenuItem className="flex items-center gap-1.5">
<ArrowLeft className="h-4 w-4" />
Projects
</DropdownMenuItem>
</Link>
<DropdownMenuSeparator />
<DropdownMenuItem
className="flex items-center gap-1.5"
onClick={() => setIsRenameDialogOpen(true)}
>
<SquarePen className="h-4 w-4" />
Rename project
</DropdownMenuItem>
<DropdownMenuItem
variant="destructive"
className="flex items-center gap-1.5"
onClick={() => setIsDeleteDialogOpen(true)}
>
<Trash className="h-4 w-4" />
Delete Project
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<RenameProjectDialog
isOpen={isRenameDialogOpen}
onOpenChange={setIsRenameDialogOpen}
onConfirm={handleNameSave}
projectName={activeProject?.name || ""}
/>
<DeleteProjectDialog
isOpen={isDeleteDialogOpen}
onOpenChange={setIsDeleteDialogOpen}
onConfirm={handleDelete}
projectName={activeProject?.name || ""}
/>
</div> </div>
); );
@@ -106,8 +123,7 @@ export function EditorHeader() {
<KeyboardShortcutsHelp /> <KeyboardShortcutsHelp />
<Button <Button
size="sm" size="sm"
variant="primary" className="h-7 text-xs !bg-linear-to-r from-cyan-400 to-blue-500 text-white hover:opacity-85 transition-opacity"
className="h-7 text-xs"
onClick={handleExport} onClick={handleExport}
> >
<Download className="h-4 w-4" /> <Download className="h-4 w-4" />