@@ -125,7 +125,7 @@ export function CommitDialog({ repo, onClose, onCommitted }: CommitDialogProps)
onClick={() => handleSubmit(false)}
disabled={!isValid || loading}
className="rounded border px-3 py-1.5 text-sm font-medium transition-opacity disabled:opacity-50"
- style={{ backgroundColor: "var(--forge-accent)", borderColor: "var(--forge-accent)", color: "#fff" }}
+ style={{ backgroundColor: "var(--forge-accent)", borderColor: "var(--forge-accent)", color: "var(--forge-accent-text)" }}
>
Commit
@@ -133,7 +133,7 @@ export function CommitDialog({ repo, onClose, onCommitted }: CommitDialogProps)
onClick={() => handleSubmit(true)}
disabled={!isValid || loading}
className="rounded border px-3 py-1.5 text-sm font-medium transition-opacity disabled:opacity-50"
- style={{ backgroundColor: "#854d0e", borderColor: "#a16207", color: "#fef08a" }}
+ style={{ backgroundColor: "var(--forge-warning-bg)", borderColor: "var(--forge-warning-border)", color: "var(--forge-warning)" }}
>
Commit & Push
diff --git a/packages/frontend/src/components/ErrorDisplay.tsx b/packages/frontend/src/components/ErrorDisplay.tsx
index 1b3ac2b..4a866df 100644
--- a/packages/frontend/src/components/ErrorDisplay.tsx
+++ b/packages/frontend/src/components/ErrorDisplay.tsx
@@ -25,10 +25,10 @@ export function ErrorDisplay({
className="rounded-lg p-6"
style={{
backgroundColor: "var(--forge-surface)",
- border: "1px solid #7f1d1d",
+ border: "1px solid var(--forge-danger-border)",
}}
>
-
+
{title}
@@ -50,7 +50,7 @@ export function ErrorDisplay({
style={{
backgroundColor: "var(--forge-bg)",
color: "var(--forge-text-secondary)",
- fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
+ fontFamily: "var(--font-mono)",
}}
>
{fullLog}
@@ -64,7 +64,7 @@ export function ErrorDisplay({
diff --git a/packages/frontend/src/components/Toast.tsx b/packages/frontend/src/components/Toast.tsx
index 68cf7d4..90cb43c 100644
--- a/packages/frontend/src/components/Toast.tsx
+++ b/packages/frontend/src/components/Toast.tsx
@@ -29,9 +29,9 @@ export function useToast() {
}
const COLORS: Record = {
- success: { bg: "#052e16", border: "#166534", text: "#4ade80" },
- error: { bg: "#3b1111", border: "#7f1d1d", text: "#fca5a5" },
- info: { bg: "#1c1403", border: "#946200", text: "#fbbf24" },
+ success: { bg: "var(--forge-success-bg)", border: "var(--forge-success-border)", text: "var(--forge-success)" },
+ error: { bg: "var(--forge-danger-bg)", border: "var(--forge-danger-border)", text: "var(--forge-danger)" },
+ info: { bg: "var(--forge-warning-bg)", border: "var(--forge-warning-border)", text: "var(--forge-warning)" },
};
const AUTO_DISMISS: Record = {
@@ -49,7 +49,7 @@ function ToastItem({
}) {
const { bg, border, text } = COLORS[toast.type];
const timeout = AUTO_DISMISS[toast.type];
- const timerRef = useRef>();
+ const timerRef = useRef>(undefined);
useEffect(() => {
if (timeout) {
@@ -92,7 +92,7 @@ export function ToastProvider({ children }: { children: ReactNode }) {
return (
{children}
-
+
{toasts.map((t) => (
))}
diff --git a/packages/frontend/src/components/editor/EditorTabs.tsx b/packages/frontend/src/components/editor/EditorTabs.tsx
index 437ba4b..91f76aa 100644
--- a/packages/frontend/src/components/editor/EditorTabs.tsx
+++ b/packages/frontend/src/components/editor/EditorTabs.tsx
@@ -56,16 +56,18 @@ export function EditorTabs({
/>
)}
-
{
e.stopPropagation();
onClose(tab.path);
}}
className="ml-1 rounded p-0.5 opacity-0 transition-opacity hover:bg-white/10 group-hover:opacity-100"
- style={{ color: "var(--forge-text-secondary)" }}
+ style={{ appearance: "none", border: "none", background: "transparent", cursor: "pointer", color: "var(--forge-text-secondary)" }}
>
×
-
+
);
})}
diff --git a/packages/frontend/src/components/editor/FileExplorer.tsx b/packages/frontend/src/components/editor/FileExplorer.tsx
index 5c372e5..f78ea07 100644
--- a/packages/frontend/src/components/editor/FileExplorer.tsx
+++ b/packages/frontend/src/components/editor/FileExplorer.tsx
@@ -87,7 +87,7 @@ function FileTreeNode({
paddingLeft: `${depth * 16 + 8}px`,
backgroundColor: isSelected ? "var(--forge-surface)" : undefined,
color: isSelected ? "var(--forge-text)" : "var(--forge-text-secondary)",
- fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
+ fontFamily: "var(--font-mono)",
fontSize: "13px",
}}
>
@@ -186,8 +186,17 @@ export function FileExplorer({
)}
{error && (
-
- {error}
+
+ {error.includes("ENOENT") ? (
+
+
Repository not cloned
+
+ Clone repositories from the Repos page or run the setup wizard.
+
+
+ ) : (
+
{error}
+ )}
)}
diff --git a/packages/frontend/src/components/editor/MonacoEditor.tsx b/packages/frontend/src/components/editor/MonacoEditor.tsx
index 9e03914..ac424b8 100644
--- a/packages/frontend/src/components/editor/MonacoEditor.tsx
+++ b/packages/frontend/src/components/editor/MonacoEditor.tsx
@@ -167,13 +167,14 @@ function registerNWScript(monaco: Parameters
[1]) {
function defineForgeTheme(monaco: Parameters[1]) {
const style = getComputedStyle(document.documentElement);
- const bg = style.getPropertyValue("--forge-bg").trim() || "#121212";
- const surface = style.getPropertyValue("--forge-surface").trim() || "#1e1e2e";
- const accent = style.getPropertyValue("--forge-accent").trim() || "#946200";
- const text = style.getPropertyValue("--forge-text").trim() || "#f2f2f2";
+ const bg = style.getPropertyValue("--forge-bg").trim() || "#1f1a14";
+ const surface = style.getPropertyValue("--forge-surface").trim() || "#2a2419";
+ const accent = style.getPropertyValue("--forge-accent").trim() || "#b07a1a";
+ const text = style.getPropertyValue("--forge-text").trim() || "#ede8e0";
const textSecondary =
- style.getPropertyValue("--forge-text-secondary").trim() || "#888888";
- const border = style.getPropertyValue("--forge-border").trim() || "#2e2e3e";
+ style.getPropertyValue("--forge-text-secondary").trim() || "#9a9080";
+ const border = style.getPropertyValue("--forge-border").trim() || "#3d3528";
+ const accentSubtle = style.getPropertyValue("--forge-accent-subtle").trim() || "#2e2818";
monaco.editor.defineTheme("forge-dark", {
base: "vs-dark",
@@ -196,7 +197,7 @@ function defineForgeTheme(monaco: Parameters[1]) {
"editor.lineHighlightBackground": surface,
"editorLineNumber.foreground": textSecondary,
"editorLineNumber.activeForeground": text,
- "editor.selectionBackground": "#264f7840",
+ "editor.selectionBackground": accentSubtle,
"editorWidget.background": surface,
"editorWidget.border": border,
"editorSuggestWidget.background": surface,
diff --git a/packages/frontend/src/components/editor/SearchPanel.tsx b/packages/frontend/src/components/editor/SearchPanel.tsx
index 481bad7..bc4589c 100644
--- a/packages/frontend/src/components/editor/SearchPanel.tsx
+++ b/packages/frontend/src/components/editor/SearchPanel.tsx
@@ -82,9 +82,9 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
const toggleBtnStyle = (active: boolean): React.CSSProperties => ({
backgroundColor: active ? "var(--forge-accent)" : "transparent",
- color: active ? "#121212" : "var(--forge-text-secondary)",
+ color: active ? "var(--forge-accent-text)" : "var(--forge-text-secondary)",
border: `1px solid ${active ? "var(--forge-accent)" : "var(--forge-border)"}`,
- fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
+ fontFamily: "var(--font-mono)",
fontSize: "12px",
lineHeight: "1",
});
@@ -119,7 +119,7 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
backgroundColor: "var(--forge-surface)",
color: "var(--forge-text)",
border: "1px solid var(--forge-border)",
- fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
+ fontFamily: "var(--font-mono)",
fontSize: "13px",
}}
/>
@@ -172,7 +172,7 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
className="w-full rounded px-3 py-1 text-sm font-medium transition-colors disabled:opacity-50"
style={{
backgroundColor: "var(--forge-accent)",
- color: "#121212",
+ color: "var(--forge-accent-text)",
}}
>
{loading ? "Searching..." : "Search"}
@@ -181,7 +181,7 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
{error && (
-
{error}
+
{error}
)}
{searched && !loading && !error && (
@@ -213,7 +213,7 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
{group.file}
@@ -240,7 +240,7 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
className="shrink-0 text-xs"
style={{
color: "var(--forge-text-secondary)",
- fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
+ fontFamily: "var(--font-mono)",
fontSize: "11px",
minWidth: "32px",
textAlign: "right",
@@ -251,7 +251,7 @@ export function SearchPanel({ repo, onResultClick }: SearchPanelProps) {
{type === "entry" ? "E" : "R"}{index}
@@ -287,7 +287,7 @@ export function DialogEditor({ repo, filePath, content, onSave, onSwitchToRaw }:
onClick={handleSave}
disabled={!dirty || saving}
className="rounded px-3 py-1 text-sm font-medium transition-colors disabled:opacity-40"
- style={{ backgroundColor: "var(--forge-accent)", color: "#fff" }}
+ style={{ backgroundColor: "var(--forge-accent)", color: "var(--forge-accent-text)" }}
>
{saving ? "Saving..." : "Save"}
@@ -317,7 +317,7 @@ export function DialogEditor({ repo, filePath, content, onSave, onSwitchToRaw }:
{/* Content */}
{error && (
-
{error}
+
{error}
)}
{activeTab === "tree" && (
diff --git a/packages/frontend/src/components/gff/GffEditor.tsx b/packages/frontend/src/components/gff/GffEditor.tsx
index b00cbff..1cad62d 100644
--- a/packages/frontend/src/components/gff/GffEditor.tsx
+++ b/packages/frontend/src/components/gff/GffEditor.tsx
@@ -215,13 +215,13 @@ function FieldRenderer({ field, value, onChange, onLocStringChange }: FieldRende
className="flex-1 rounded border px-2 py-1.5 font-mono text-sm"
style={{
backgroundColor: "var(--forge-bg)",
- borderColor: valid ? "var(--forge-border)" : "#ef4444",
+ borderColor: valid ? "var(--forge-border)" : "var(--forge-danger)",
color: "var(--forge-text)",
}}
/>
{str.length}/16
@@ -421,7 +421,7 @@ export function GffEditor({
return (
-
{error}
+
{error}
{onSwitchToRaw && (
@@ -480,7 +480,7 @@ export function GffEditor({
className="rounded px-3 py-1 text-sm font-medium transition-colors disabled:opacity-40"
style={{
backgroundColor: "var(--forge-accent)",
- color: "#fff",
+ color: "var(--forge-accent-text)",
}}
>
{saving ? "Saving..." : "Save"}
diff --git a/packages/frontend/src/components/gff/ItemEditor.tsx b/packages/frontend/src/components/gff/ItemEditor.tsx
index 665da74..9ed1c81 100644
--- a/packages/frontend/src/components/gff/ItemEditor.tsx
+++ b/packages/frontend/src/components/gff/ItemEditor.tsx
@@ -141,7 +141,7 @@ function PropertiesListOverride({ value }: FieldOverrideProps) {
diff --git a/packages/frontend/src/components/terminal/Terminal.tsx b/packages/frontend/src/components/terminal/Terminal.tsx
index 740046b..fa03dc0 100644
--- a/packages/frontend/src/components/terminal/Terminal.tsx
+++ b/packages/frontend/src/components/terminal/Terminal.tsx
@@ -15,21 +15,28 @@ export function Terminal({ sessionId }: TerminalProps) {
useEffect(() => {
if (!containerRef.current) return;
+ const style = getComputedStyle(document.documentElement);
+ const bg = style.getPropertyValue("--forge-bg").trim();
+ const fg = style.getPropertyValue("--forge-text").trim();
+ const accent = style.getPropertyValue("--forge-accent").trim();
+ const secondary = style.getPropertyValue("--forge-text-secondary").trim();
+ const accentHover = style.getPropertyValue("--forge-accent-hover").trim();
+
const term = new XTerm({
theme: {
- background: "#121212",
- foreground: "#f2f2f2",
- cursor: "#946200",
- selectionBackground: "#946200",
- selectionForeground: "#f2f2f2",
- black: "#121212",
- brightBlack: "#666666",
- white: "#f2f2f2",
- brightWhite: "#ffffff",
- yellow: "#946200",
- brightYellow: "#c48800",
+ background: bg,
+ foreground: fg,
+ cursor: accent,
+ selectionBackground: accent,
+ selectionForeground: fg,
+ black: bg,
+ brightBlack: secondary,
+ white: fg,
+ brightWhite: fg,
+ yellow: accent,
+ brightYellow: accentHover,
},
- fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
+ fontFamily: "var(--font-mono)",
fontSize: 13,
cursorBlink: true,
});
@@ -80,7 +87,7 @@ export function Terminal({ sessionId }: TerminalProps) {
);
}
diff --git a/packages/frontend/src/layouts/IDELayout.tsx b/packages/frontend/src/layouts/IDELayout.tsx
index 536639d..5bf7799 100644
--- a/packages/frontend/src/layouts/IDELayout.tsx
+++ b/packages/frontend/src/layouts/IDELayout.tsx
@@ -3,14 +3,28 @@ import { Outlet, Link, useLocation, useNavigate } from "react-router-dom";
import { Terminal } from "../components/terminal/Terminal";
import { useWebSocket } from "../hooks/useWebSocket";
import { useTheme } from "../hooks/useTheme";
+import {
+ Code2,
+ Wrench,
+ Hammer,
+ Play,
+ GitBranch,
+ Settings,
+ Sun,
+ Moon,
+ Terminal as TerminalIcon,
+ ChevronDown,
+ ChevronUp,
+} from "lucide-react";
+import type { LucideIcon } from "lucide-react";
-const NAV_ITEMS = [
- { path: "/editor", label: "Editor", icon: "\u270E" },
- { path: "/toolset", label: "Toolset", icon: "\u2699" },
- { path: "/build", label: "Build", icon: "\u2692" },
- { path: "/server", label: "Server", icon: "\u25B6" },
- { path: "/repos", label: "Repos", icon: "\u2387" },
- { path: "/settings", label: "Settings", icon: "\u2318" },
+const NAV_ITEMS: { path: string; label: string; Icon: LucideIcon }[] = [
+ { path: "/editor", label: "Editor", Icon: Code2 },
+ { path: "/toolset", label: "Toolset", Icon: Wrench },
+ { path: "/build", label: "Build", Icon: Hammer },
+ { path: "/server", label: "Server", Icon: Play },
+ { path: "/repos", label: "Repos", Icon: GitBranch },
+ { path: "/settings", label: "Settings", Icon: Settings },
];
export function IDELayout({ sidebar }: { sidebar?: React.ReactNode }) {
@@ -21,6 +35,7 @@ export function IDELayout({ sidebar }: { sidebar?: React.ReactNode }) {
const navigate = useNavigate();
const { subscribe } = useWebSocket();
const { theme, toggleTheme } = useTheme();
+ const showSidebar = location.pathname === "/editor" || location.pathname.startsWith("/editor/");
useEffect(() => {
return subscribe("git:upstream-update", (event) => {
@@ -85,25 +100,28 @@ export function IDELayout({ sidebar }: { sidebar?: React.ReactNode }) {
};
return (
-
+
{/* Left sidebar nav */}