diff --git a/apps/web/src/components/editor-header.tsx b/apps/web/src/components/editor-header.tsx
index c6cecbe..6f9f0b2 100644
--- a/apps/web/src/components/editor-header.tsx
+++ b/apps/web/src/components/editor-header.tsx
@@ -6,6 +6,7 @@ import { ChevronLeft, Download } from "lucide-react";
import { useProjectStore } from "@/stores/project-store";
import { useTimelineStore } from "@/stores/timeline-store";
import { HeaderBase } from "./header-base";
+import { ProjectNameEditor } from "./editor/project-name-editor";
export function EditorHeader() {
const { activeProject } = useProjectStore();
@@ -24,13 +25,15 @@ export function EditorHeader() {
};
const leftContent = (
-
-
- {activeProject?.name || "Loading..."}
-
+
);
const centerContent = (
diff --git a/apps/web/src/components/editor/project-name-editor.tsx b/apps/web/src/components/editor/project-name-editor.tsx
new file mode 100644
index 0000000..aa0141a
--- /dev/null
+++ b/apps/web/src/components/editor/project-name-editor.tsx
@@ -0,0 +1,110 @@
+"use client";
+
+import { useState, useRef, useEffect } from "react";
+import { Input } from "../ui/input";
+import { useProjectStore } from "@/stores/project-store";
+import { Edit2, Check, X } from "lucide-react";
+import { Button } from "../ui/button";
+
+interface ProjectNameEditorProps {
+ className?: string;
+}
+
+export function ProjectNameEditor({ className }: ProjectNameEditorProps) {
+ const { activeProject, updateProjectName } = useProjectStore();
+ const [isEditing, setIsEditing] = useState(false);
+ const [editValue, setEditValue] = useState("");
+ const inputRef = useRef(null);
+
+ useEffect(() => {
+ if (activeProject) {
+ setEditValue(activeProject.name);
+ }
+ }, [activeProject]);
+
+ useEffect(() => {
+ if (isEditing && inputRef.current) {
+ inputRef.current.focus();
+ inputRef.current.select();
+ }
+ }, [isEditing]);
+
+ const handleStartEdit = () => {
+ if (activeProject) {
+ setEditValue(activeProject.name);
+ setIsEditing(true);
+ }
+ };
+
+ const handleSave = () => {
+ if (editValue.trim()) {
+ updateProjectName(editValue.trim());
+ setIsEditing(false);
+ }
+ };
+
+ const handleCancel = () => {
+ if (activeProject) {
+ setEditValue(activeProject.name);
+ }
+ setIsEditing(false);
+ };
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === "Enter") {
+ handleSave();
+ } else if (e.key === "Escape") {
+ handleCancel();
+ }
+ };
+
+ if (!activeProject) {
+ return Loading...;
+ }
+
+ if (isEditing) {
+ return (
+
+ setEditValue(e.target.value)}
+ onKeyDown={handleKeyDown}
+ className="h-7 text-sm px-3 py-1 min-w-[200px]"
+ size={1}
+ />
+
+
+
+ );
+ }
+
+ return (
+
+ {activeProject.name}
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/web/src/stores/project-store.ts b/apps/web/src/stores/project-store.ts
index 734c07e..0d0812c 100644
--- a/apps/web/src/stores/project-store.ts
+++ b/apps/web/src/stores/project-store.ts
@@ -7,6 +7,7 @@ interface ProjectStore {
// Actions
createNewProject: (name: string) => void;
closeProject: () => void;
+ updateProjectName: (name: string) => void;
}
export const useProjectStore = create((set) => ({
@@ -25,4 +26,16 @@ export const useProjectStore = create((set) => ({
closeProject: () => {
set({ activeProject: null });
},
+
+ updateProjectName: (name: string) => {
+ set((state) => ({
+ activeProject: state.activeProject
+ ? {
+ ...state.activeProject,
+ name,
+ updatedAt: new Date(),
+ }
+ : null,
+ }));
+ },
}));