authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-24 22:40:01-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-02-26 13:20:36-08:00
log9ef1c0c9a3c056fd0ed309b5b0ba0cda72848dd0
treeb4de4739ccb8a5988ff5196eb912b59928032a13
parentad9bc6c1df40ac41ee9f50405bb17bbea6b08674

wordmakr


1 files changed, 32 insertions(+), 9 deletions(-)

apps/web/src/components/Sidebar.tsx+32-9
...@@ -7,7 +7,13 @@ import { useAppSettings } from "../appSettings";...@@ -7,7 +7,13 @@ import { useAppSettings } from "../appSettings";
7import { isElectron } from "../env";7import { isElectron } from "../env";
8import { APP_STAGE_LABEL } from "../branding";8import { APP_STAGE_LABEL } from "../branding";
9import { DEFAULT_MODEL } from "../model-logic";9import { DEFAULT_MODEL } from "../model-logic";
10import { asProjectId, asThreadId, newCommandId, newProjectId, newThreadId } from "../lib/orchestrationIds";10import {
11 asProjectId,
12 asThreadId,
13 newCommandId,
14 newProjectId,
15 newThreadId,
16} from "../lib/orchestrationIds";
11import { useStore } from "../store";17import { useStore } from "../store";
12import { isChatNewLocalShortcut, isChatNewShortcut } from "../keybindings";18import { isChatNewLocalShortcut, isChatNewShortcut } from "../keybindings";
13import { type Thread } from "../types";19import { type Thread } from "../types";
...@@ -120,6 +126,22 @@ function terminalStatusIndicator(thread: Thread): TerminalStatusIndicator | null...@@ -120,6 +126,22 @@ function terminalStatusIndicator(thread: Thread): TerminalStatusIndicator | null
120 };126 };
121}127}
122128
129function T3Wordmark() {
130 return (
131 <svg
132 aria-label="T3"
133 className="h-3 w-auto shrink-0 text-foreground"
134 viewBox="15.5309 37 94.3941 56.96"
135 xmlns="http://www.w3.org/2000/svg"
136 >
137 <path
138 d="M33.4509 93V47.56H15.5309V37H64.3309V47.56H46.4109V93H33.4509ZM86.7253 93.96C82.832 93.96 78.9653 93.4533 75.1253 92.44C71.2853 91.3733 68.032 89.88 65.3653 87.96L70.4053 78.04C72.5386 79.5867 75.0186 80.8133 77.8453 81.72C80.672 82.6267 83.5253 83.08 86.4053 83.08C89.6586 83.08 92.2186 82.44 94.0853 81.16C95.952 79.88 96.8853 78.12 96.8853 75.88C96.8853 73.7467 96.0586 72.0667 94.4053 70.84C92.752 69.6133 90.0853 69 86.4053 69H80.4853V60.44L96.0853 42.76L97.5253 47.4H68.1653V37H107.365V45.4L91.8453 63.08L85.2853 59.32H89.0453C95.9253 59.32 101.125 60.8667 104.645 63.96C108.165 67.0533 109.925 71.0267 109.925 75.88C109.925 79.0267 109.099 81.9867 107.445 84.76C105.792 87.48 103.259 89.6933 99.8453 91.4C96.432 93.1067 92.0586 93.96 86.7253 93.96Z"
139 fill="currentColor"
140 />
141 </svg>
142 );
143}
144
123export default function Sidebar() {145export default function Sidebar() {
124 const { state, dispatch } = useStore();146 const { state, dispatch } = useStore();
125 const api = useNativeApi();147 const api = useNativeApi();
...@@ -152,7 +174,8 @@ export default function Sidebar() {...@@ -152,7 +174,8 @@ export default function Sidebar() {
152 if (!api) return Promise.resolve();174 if (!api) return Promise.resolve();
153 const threadId = newThreadId();175 const threadId = newThreadId();
154 const createdAt = new Date().toISOString();176 const createdAt = new Date().toISOString();
155 const model = state.projects.find((project) => project.id === projectId)?.model ?? DEFAULT_MODEL;177 const model =
178 state.projects.find((project) => project.id === projectId)?.model ?? DEFAULT_MODEL;
156 return (async () => {179 return (async () => {
157 await api.orchestration.dispatchCommand({180 await api.orchestration.dispatchCommand({
158 type: "thread.create",181 type: "thread.create",
...@@ -272,7 +295,7 @@ export default function Sidebar() {...@@ -272,7 +295,7 @@ export default function Sidebar() {
272 if (appSettings.confirmThreadDelete) {295 if (appSettings.confirmThreadDelete) {
273 const confirmed = await api.dialogs.confirm(296 const confirmed = await api.dialogs.confirm(
274 [297 [
275 `Delete thread \"${thread.title}\"?`,298 `Delete thread "${thread.title}"?`,
276 "This permanently clears conversation history for this thread.",299 "This permanently clears conversation history for this thread.",
277 ].join("\n"),300 ].join("\n"),
278 );301 );
...@@ -404,8 +427,7 @@ export default function Sidebar() {...@@ -404,8 +427,7 @@ export default function Sidebar() {
404 projectId: asProjectId(projectId),427 projectId: asProjectId(projectId),
405 });428 });
406 } catch (error) {429 } catch (error) {
407 const message =430 const message = error instanceof Error ? error.message : "Unknown error deleting project.";
408 error instanceof Error ? error.message : "Unknown error deleting project.";
409 console.error("Failed to remove project", { projectId, error });431 console.error("Failed to remove project", { projectId, error });
410 toastManager.add({432 toastManager.add({
411 type: "error",433 type: "error",
...@@ -449,13 +471,14 @@ export default function Sidebar() {...@@ -449,13 +471,14 @@ export default function Sidebar() {
449 return (471 return (
450 <>472 <>
451 <SidebarHeader473 <SidebarHeader
452 className={`gap-3 ${isElectron ? "drag-region h-[52px] px-4 pl-[76px]" : "px-3 py-2 sm:gap-2.5 sm:px-4 sm:py-3"}`}474 className={`gap-3 ${isElectron ? "drag-region h-[52px] px-4 pl-[88px]" : "px-3 py-2 sm:gap-2.5 sm:px-4 sm:py-3"}`}
453 >475 >
454 <div className="flex items-center gap-2">476 <div className="flex items-center gap-2">
455 <SidebarTrigger className="shrink-0 md:hidden" />477 <SidebarTrigger className="shrink-0 md:hidden" />
456 <div className="flex min-w-0 flex-1 items-center gap-2">478 <div className="flex min-w-0 flex-1 items-center gap-1">
457 <span className="truncate text-sm font-semibold tracking-tight text-foreground">479 <T3Wordmark />
458 T3 <span className="font-normal text-muted-foreground">Code</span>480 <span className="truncate text-base font-medium tracking-tight text-muted-foreground">
481 Code
459 </span>482 </span>
460 <span className="rounded-full bg-muted/50 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-widest text-muted-foreground/60">483 <span className="rounded-full bg-muted/50 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-widest text-muted-foreground/60">
461 {APP_STAGE_LABEL}484 {APP_STAGE_LABEL}