@@ -272,44 +272,135 @@ function validateStudioFormState(formState: any): {
272272 } ;
273273}
274274
275+ type SharedThemeTokens = {
276+ colors : {
277+ bg : string ;
278+ bgAlt : string ;
279+ panel : string ;
280+ panelStrong : string ;
281+ border : string ;
282+ text : string ;
283+ muted : string ;
284+ primary : string ;
285+ primaryStrong : string ;
286+ accent : string ;
287+ success : string ;
288+ danger : string ;
289+ } ;
290+ radius : { sm : string ; md : string ; lg : string } ;
291+ spacing : { xs : string ; sm : string ; md : string ; lg : string ; xl : string } ;
292+ typography : { display : string ; body : string ; mono : string } ;
293+ motion : { fast : string ; base : string } ;
294+ } ;
295+
296+ function defaultSharedThemeTokens ( ) : SharedThemeTokens {
297+ return {
298+ colors : {
299+ bg : '#06122b' ,
300+ bgAlt : '#0a1f45' ,
301+ panel : '#0f2958cc' ,
302+ panelStrong : '#103062' ,
303+ border : '#7eb8ff55' ,
304+ text : '#f3f8ff' ,
305+ muted : '#b6caea' ,
306+ primary : '#4cb1f7' ,
307+ primaryStrong : '#1e8fe0' ,
308+ accent : '#ffc700' ,
309+ success : '#12c26d' ,
310+ danger : '#ff5f63'
311+ } ,
312+ radius : { sm : '10px' , md : '14px' , lg : '20px' } ,
313+ spacing : { xs : '6px' , sm : '10px' , md : '16px' , lg : '24px' , xl : '36px' } ,
314+ typography : {
315+ display : '"Montserrat", "Avenir Next", "Segoe UI", sans-serif' ,
316+ body : '"Inter", "Segoe UI", sans-serif' ,
317+ mono : 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
318+ } ,
319+ motion : { fast : '120ms' , base : '180ms' }
320+ } ;
321+ }
322+
323+ function loadSharedThemeTokens ( ) : SharedThemeTokens {
324+ try {
325+ const templateDir = resolveNextExportUiTemplateDir ( ) ;
326+ const tokenPath = path . join ( templateDir , 'src' , 'theme' , 'tokens.json' ) ;
327+ if ( ! fs . existsSync ( tokenPath ) ) return defaultSharedThemeTokens ( ) ;
328+ return JSON . parse ( fs . readFileSync ( tokenPath , 'utf-8' ) ) as SharedThemeTokens ;
329+ } catch {
330+ return defaultSharedThemeTokens ( ) ;
331+ }
332+ }
333+
334+ function renderStudioThemeCssVars ( tokens : SharedThemeTokens ) : string {
335+ return [
336+ `--th-bg:${ tokens . colors . bg } ` ,
337+ `--th-bg-alt:${ tokens . colors . bgAlt } ` ,
338+ `--th-panel:${ tokens . colors . panel } ` ,
339+ `--th-panel-strong:${ tokens . colors . panelStrong } ` ,
340+ `--th-border:${ tokens . colors . border } ` ,
341+ `--th-text:${ tokens . colors . text } ` ,
342+ `--th-muted:${ tokens . colors . muted } ` ,
343+ `--th-primary:${ tokens . colors . primary } ` ,
344+ `--th-primary-strong:${ tokens . colors . primaryStrong } ` ,
345+ `--th-accent:${ tokens . colors . accent } ` ,
346+ `--th-success:${ tokens . colors . success } ` ,
347+ `--th-danger:${ tokens . colors . danger } ` ,
348+ `--th-radius-sm:${ tokens . radius . sm } ` ,
349+ `--th-radius-md:${ tokens . radius . md } ` ,
350+ `--th-radius-lg:${ tokens . radius . lg } ` ,
351+ `--th-space-xs:${ tokens . spacing . xs } ` ,
352+ `--th-space-sm:${ tokens . spacing . sm } ` ,
353+ `--th-space-md:${ tokens . spacing . md } ` ,
354+ `--th-space-lg:${ tokens . spacing . lg } ` ,
355+ `--th-space-xl:${ tokens . spacing . xl } ` ,
356+ `--th-font-display:${ tokens . typography . display } ` ,
357+ `--th-font-body:${ tokens . typography . body } ` ,
358+ `--th-font-mono:${ tokens . typography . mono } ` ,
359+ `--th-motion-fast:${ tokens . motion . fast } ` ,
360+ `--th-motion-base:${ tokens . motion . base } `
361+ ] . join ( ';' ) ;
362+ }
363+
275364function renderStudioHtml ( ) : string {
276365 // Keep this local-first and dependency-free for fast startup in any repo clone.
366+ const themeTokens = loadSharedThemeTokens ( ) ;
367+ const cssVars = renderStudioThemeCssVars ( themeTokens ) ;
277368 return `<!doctype html>
278369<html lang="en">
279370<head>
280371 <meta charset="utf-8" />
281372 <meta name="viewport" content="width=device-width, initial-scale=1" />
282373 <title>Token Host Studio (Local)</title>
283374 <style>
284- :root { color-scheme: light; --bg:#0b1220 ; --panel:#111a2b; --muted:#9db0cc; --text:#edf3ff ; --ok:#2bb673; --err:#f25f5c ; --warn:#f2c14e ; }
375+ :root { color-scheme: light; ${ cssVars } ; --ok:var(--th-success) ; --err:var(--th-danger) ; --warn:var(--th-accent) ; }
285376 * { box-sizing: border-box; }
286- body { margin:0; font-family: ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif ; background: radial-gradient(circle at 10% 10 %, #1f3559, #0b1220 55%) ; color: var(--text); }
377+ body { margin:0; font-family: var(--th-font-body) ; background: radial-gradient(circle at 8% 0 %, #255bb688, transparent 42%), radial-gradient(circle at 88% 0%, #50b9fa66, transparent 36%), linear-gradient(155deg, var(--th-bg) 20%, var(--th-bg-alt) 100%) ; color: var(--th -text); }
287378 .wrap { max-width: 1400px; margin: 0 auto; padding: 20px; }
288379 .row { display:grid; grid-template-columns: 1.6fr 1fr; gap: 14px; }
289- .panel { background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(0,0,0,0.12)) ; border:1px solid rgba(255,255,255,0.12 ); border-radius: 14px ; padding: 14px ; }
290- .title { margin:0 0 10px 0; font-size: 18px ; font-weight: 700; }
291- .muted { color: var(--muted); font-size: 13px; }
292- textarea { width:100%; min-height: 120px; border-radius: 10px ; border:1px solid rgba(255,255,255,0.18 ); background: #0a1426 ; color: #eaf2ff ; padding: 10px; font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace ; font-size: 13px; line-height: 1.35; }
293- input[type=text], input[type=number], select { width: 100%; border-radius: 8px ; border:1px solid rgba(255,255,255,0.18 ); background:#0a1426 ; color:#eaf2ff ; padding: 8px; }
294- label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; }
380+ .panel { background: linear-gradient(180deg, #0f2958cf, #0d234bd4) ; border:1px solid var(--th-border ); border-radius: var(--th-radius-lg) ; padding: var(--th-space-md); box-shadow: 0 8px 32px #02122f4d ; }
381+ .title { margin:0 0 10px 0; font-size: 22px; font-family: var(--th-font-display) ; font-weight: 700; }
382+ .muted { color: var(--th- muted); font-size: 13px; }
383+ textarea { width:100%; min-height: 120px; border-radius: var(--th-radius-sm) ; border:1px solid var(--th-border ); background: #071b3f ; color: var(--th-text) ; padding: 10px; font-family: var(--th-font-mono) ; font-size: 13px; line-height: 1.35; }
384+ input[type=text], input[type=number], select { width: 100%; border-radius: var(--th-radius-sm) ; border:1px solid var(--th-border ); background:#071b3f ; color:var(--th-text) ; padding: 8px; }
385+ label { display: block; font-size: 12px; color: var(--th- muted); margin-bottom: 4px; }
295386 .grid2 { display:grid; grid-template-columns: 1fr 1fr; gap:8px; }
296387 .grid3 { display:grid; grid-template-columns: 1fr 1fr 1fr; gap:8px; }
297- .card { border:1px solid rgba(255,255,255,0.12 ); border-radius: 10px ; padding: 8px; margin-top: 8px; background: rgba(0,0,0,0.2) ; }
388+ .card { border:1px solid var(--th-border ); border-radius: var(--th-radius-sm) ; padding: 8px; margin-top: 8px; background: #0a2a5888 ; }
298389 .sectionTitle { font-size: 14px; font-weight: 700; margin-top: 10px; }
299390 .stack { display:flex; flex-direction:column; gap:8px; }
300391 .toolbar { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px; }
301392 .configList { display:flex; flex-direction:column; gap:8px; max-height:260px; overflow:auto; }
302- .configRow { display:grid; grid-template-columns: 1fr auto; gap:8px; align-items:center; border:1px solid rgba(255,255,255,0.12 ); border-radius:8px ; padding:8px; background: rgba(0,0,0,0.2) ; }
303- .configPath { font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace ; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
304- button { border:1px solid rgba(255,255,255,0.2 ); color:#fff ; background:#1e3357 ; border-radius:8px ; padding:8px 10px; cursor:pointer; }
305- button:hover { filter: brightness(1.08) ; }
393+ .configRow { display:grid; grid-template-columns: 1fr auto; gap:8px; align-items:center; border:1px solid var(--th-border ); border-radius: var(--th-radius-sm) ; padding:8px; background: #0a2a5888 ; }
394+ .configPath { font-family: var(--th-font-mono) ; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
395+ button { border:1px solid var(--th-border ); color:var(--th-text) ; background:#15407f ; border-radius: var(--th-radius-sm) ; padding:8px 10px; cursor:pointer; transition: transform var(--th-motion-fast) ease, background var(--th-motion-base) ease; font-weight: 600 ; }
396+ button:hover { background:#1a4f9d ; }
306397 .pill { display:inline-block; padding: 2px 8px; border-radius:999px; font-size: 12px; border:1px solid transparent; }
307- .ok { color:#d8ffe9; background: rgba(43,182,115,.2 ); border-color: rgba(43,182,115,.45 );}
308- .err { color:#ffd6d6; background: rgba(242,95,92,.2 ); border-color: rgba(242,95,92,.45 );}
309- .warn { color:#fff6d5; background: rgba(242,193,78,.2 ); border-color: rgba(242,193,78,.45 );}
398+ .ok { color:#d8ffe9; background: color-mix(in srgb, var(--th-success) 24%, transparent ); border-color: color-mix(in srgb, var(--th-success) 45%, transparent );}
399+ .err { color:#ffd6d6; background: color-mix(in srgb, var(--th-danger) 24%, transparent ); border-color: color-mix(in srgb, var(--th-danger) 45%, transparent );}
400+ .warn { color:#fff6d5; background: color-mix(in srgb, var(--th-accent) 24%, transparent ); border-color: color-mix(in srgb, var(--th-accent) 45%, transparent );}
310401 ul { margin: 8px 0 0 18px; padding:0; }
311402 li { margin: 2px 0; }
312- pre { white-space: pre-wrap; word-break: break-word; background:#0a1426 ; border:1px solid rgba(255,255,255,0.1 ); border-radius: 8px ; padding: 10px; max-height: 280px; overflow:auto; }
403+ pre { white-space: pre-wrap; word-break: break-word; background:#071b3f ; border:1px solid var(--th-border ); border-radius: var(--th-radius-sm) ; padding: 10px; max-height: 280px; overflow:auto; }
313404 </style>
314405</head>
315406<body>
0 commit comments