aboutsummaryrefslogtreecommitdiffstats
path: root/renderer/src/components
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-28 19:34:02 -0800
committerbndw <ben@bdw.to>2026-02-28 19:34:02 -0800
commit283013c09d4855529e846951a1e090f0f16030a8 (patch)
treee78c84c85b07806770faee99af7280d0a83eadc8 /renderer/src/components
parent9a636af9090b122db2e55737fca3e78550aab9df (diff)
feat: auto session naming
Diffstat (limited to 'renderer/src/components')
-rw-r--r--renderer/src/components/Header.tsx81
1 files changed, 66 insertions, 15 deletions
diff --git a/renderer/src/components/Header.tsx b/renderer/src/components/Header.tsx
index b4faa6e..a435519 100644
--- a/renderer/src/components/Header.tsx
+++ b/renderer/src/components/Header.tsx
@@ -1,4 +1,4 @@
1import React from "react"; 1import React, { useState } from "react";
2import type { Project, Session, Phase } from "../types"; 2import type { Project, Session, Phase } from "../types";
3 3
4type Theme = "dark" | "light"; 4type Theme = "dark" | "light";
@@ -14,6 +14,7 @@ interface HeaderProps {
14 onCreateSession: () => void; 14 onCreateSession: () => void;
15 onDeleteProject?: (id: string) => void; 15 onDeleteProject?: (id: string) => void;
16 onDeleteSession?: (id: string) => void; 16 onDeleteSession?: (id: string) => void;
17 onRenameSession?: (id: string, name: string) => void;
17 theme: Theme; 18 theme: Theme;
18 onToggleTheme: () => void; 19 onToggleTheme: () => void;
19} 20}
@@ -37,6 +38,7 @@ export function Header({
37 onCreateSession, 38 onCreateSession,
38 onDeleteProject, 39 onDeleteProject,
39 onDeleteSession, 40 onDeleteSession,
41 onRenameSession,
40 theme, 42 theme,
41 onToggleTheme, 43 onToggleTheme,
42}: HeaderProps) { 44}: HeaderProps) {
@@ -54,6 +56,32 @@ export function Header({
54 } 56 }
55 }; 57 };
56 58
59 const [isRenamingSession, setIsRenamingSession] = useState(false);
60 const [renameValue, setRenameValue] = useState("");
61 // Guard against double-commit (onKeyDown Enter → unmount → onBlur)
62 const renameCommitted = React.useRef(false);
63
64 const startRename = () => {
65 if (!selectedSession) return;
66 renameCommitted.current = false;
67 setRenameValue(selectedSession.name);
68 setIsRenamingSession(true);
69 };
70
71 const commitRename = () => {
72 if (renameCommitted.current) return;
73 renameCommitted.current = true;
74 if (selectedSession && onRenameSession && renameValue.trim()) {
75 onRenameSession(selectedSession.id, renameValue.trim());
76 }
77 setIsRenamingSession(false);
78 };
79
80 const cancelRename = () => {
81 renameCommitted.current = true; // prevent blur from committing after cancel
82 setIsRenamingSession(false);
83 };
84
57 return ( 85 return (
58 <header className="header"> 86 <header className="header">
59 <div className="header-left"> 87 <div className="header-left">
@@ -88,21 +116,44 @@ export function Header({
88 116
89 {selectedProject && ( 117 {selectedProject && (
90 <> 118 <>
91 <select 119 {isRenamingSession ? (
92 value={selectedSession?.id || ""} 120 <input
93 onChange={(e) => { 121 autoFocus
94 const session = sessions.find((s) => s.id === e.target.value); 122 value={renameValue}
95 onSelectSession(session || null); 123 onChange={(e) => setRenameValue(e.target.value)}
96 }} 124 onKeyDown={(e) => {
97 > 125 if (e.key === "Enter") commitRename();
98 <option value="">Select Session...</option> 126 if (e.key === "Escape") cancelRename();
99 {sessions.map((s) => ( 127 }}
100 <option key={s.id} value={s.id}> 128 onBlur={commitRename}
101 {s.name} 129 className="session-rename-input"
102 </option> 130 />
103 ))} 131 ) : (
104 </select> 132 <select
133 value={selectedSession?.id || ""}
134 onChange={(e) => {
135 const session = sessions.find((s) => s.id === e.target.value);
136 onSelectSession(session || null);
137 }}
138 >
139 <option value="">Select Session...</option>
140 {sessions.map((s) => (
141 <option key={s.id} value={s.id}>
142 {s.name}
143 </option>
144 ))}
145 </select>
146 )}
105 <button onClick={onCreateSession}>+ Session</button> 147 <button onClick={onCreateSession}>+ Session</button>
148 {selectedSession && onRenameSession && !isRenamingSession && (
149 <button
150 onClick={startRename}
151 className="btn-rename"
152 title="Rename session"
153 >
154 ✏️
155 </button>
156 )}
106 {selectedSession && onDeleteSession && ( 157 {selectedSession && onDeleteSession && (
107 <button 158 <button
108 onClick={handleDeleteSession} 159 onClick={handleDeleteSession}