feat(frontend): add Front/ — Vite/React frontend with backend pipeline integration

Mirror of design_agent_front/design-agent/ for shipping alongside backend.

Vite plugin (vitePluginPhaseZApi) endpoints :
  - POST /api/run   — spawn `python -m src.phase_z2_pipeline` with overrides
  - GET  /api/sample-mdx?mdx=03/04/05 — fixed sample MDX
  - GET  /frame-preview/{n} — figma preview thumbnails
  - GET  /data/runs/{run_id}/{path} — pipeline artifacts (final.html, step*.json, ...)

Env toggle forward (보고용) :
  PHASE_Z_ALLOW_RESTRUCTURE / PHASE_Z_ALLOW_REJECT / PHASE_Z_MAX_RANK=32

Components :
  - LeftMdxPanel (03/04/05 fix list + section tree)
  - SlideCanvas (iframe + slideOverrideCss prop for inline CSS inject)
  - FramePanel (label priority + confidence sort)
  - LayoutPanel

README with mermaid diagrams covering the 5-step demo flow.
node_modules / dist / .manus-logs / .env excluded via .gitignore.
This commit is contained in:
2026-05-14 14:45:30 +09:00
parent 52ccb7fc8b
commit 0f0d3fa91f
99 changed files with 20280 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
import React, { createContext, useContext, useEffect, useState } from "react";
type Theme = "light" | "dark";
interface ThemeContextType {
theme: Theme;
toggleTheme?: () => void;
switchable: boolean;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
interface ThemeProviderProps {
children: React.ReactNode;
defaultTheme?: Theme;
switchable?: boolean;
}
export function ThemeProvider({
children,
defaultTheme = "light",
switchable = false,
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(() => {
if (switchable) {
const stored = localStorage.getItem("theme");
return (stored as Theme) || defaultTheme;
}
return defaultTheme;
});
useEffect(() => {
const root = document.documentElement;
if (theme === "dark") {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
if (switchable) {
localStorage.setItem("theme", theme);
}
}, [theme, switchable]);
const toggleTheme = switchable
? () => {
setTheme(prev => (prev === "light" ? "dark" : "light"));
}
: undefined;
return (
<ThemeContext.Provider value={{ theme, toggleTheme, switchable }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within ThemeProvider");
}
return context;
}