@sudajs/cli 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { createInterface } from 'readline/promises';
8
8
  import { fileURLToPath, pathToFileURL } from 'url';
9
9
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
10
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
- import { themeDesignSystemSchema, createThemeAgentManifest, createSudaPageAgentRuntime, checkThemeModule, formatThemeCheckResult, agentValidationResultSchema, agentPageSchemaOutputSchema, agentComponentOutputSchema } from '@sudajs/theme-engine';
11
+ import { themeDesignSystemSchema, createThemeDesignCssVariables, createThemeAgentManifest, createSudaPageAgentRuntime, checkThemeModule, formatThemeCheckResult, agentValidationResultSchema, agentPageSchemaOutputSchema, agentComponentOutputSchema } from '@sudajs/theme-engine';
12
12
  import { themeManifestSchema, runWithThemePreviewLocale } from '@sudajs/theme-engine/server';
13
13
  import { Command } from 'commander';
14
14
  import { build } from 'esbuild';
@@ -2018,6 +2018,7 @@ function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserve
2018
2018
  const cssVarStyle = Object.entries(chrome.cssVariables).map(([key, value]) => `${key}: ${value};`).join(" ");
2019
2019
  const customHead = chrome.customHeadCode ?? "";
2020
2020
  const customBody = chrome.customBodyCode ?? "";
2021
+ const designPalette = renderDevDesignPalette(theme.module.manifest.designSystem);
2021
2022
  return [
2022
2023
  "<!doctype html>",
2023
2024
  `<html lang="${escapeHtml(locale)}">`,
@@ -2026,10 +2027,12 @@ function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserve
2026
2027
  '<meta name="viewport" content="width=device-width, initial-scale=1" />',
2027
2028
  `<title>${escapeHtml(`${theme.module.manifest.name} \u2014 ${page.title}`)}</title>`,
2028
2029
  '<link rel="stylesheet" href="/src/styles.css" />',
2030
+ designPalette.style,
2029
2031
  customHead,
2030
2032
  "</head>",
2031
2033
  `<body${cssVarStyle ? ` style="${cssVarStyle}"` : ""}>`,
2032
2034
  body,
2035
+ designPalette.html,
2033
2036
  customBody,
2034
2037
  ...preserveLang ? [
2035
2038
  '<script>for(const a of document.querySelectorAll("a[href]")){try{const u=new URL(a.href,location.href);if(u.origin===location.origin){u.searchParams.set("lang",new URL(location.href).searchParams.get("lang"));a.href=u.pathname+u.search+u.hash}}catch{}}</script>'
@@ -2038,6 +2041,33 @@ function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserve
2038
2041
  "</html>"
2039
2042
  ].join("");
2040
2043
  }
2044
+ function serializeInlineScriptValue(value) {
2045
+ return JSON.stringify(value).replaceAll("<", "\\u003c").replaceAll("\u2028", "\\u2028").replaceAll("\u2029", "\\u2029");
2046
+ }
2047
+ function renderDevDesignPalette(designSystem) {
2048
+ if (designSystem.presets.length < 2) {
2049
+ return { style: "", html: "" };
2050
+ }
2051
+ const presets = designSystem.presets.map((preset) => ({
2052
+ id: preset.id,
2053
+ variables: createThemeDesignCssVariables(preset.tokens)
2054
+ }));
2055
+ const buttons = designSystem.presets.map(
2056
+ (preset) => `<button type="button" data-suda-dev-preset="${escapeHtml(preset.id)}" title="${escapeHtml(
2057
+ preset.description ? `${preset.label} \u2014 ${preset.description}` : preset.label
2058
+ )}" aria-label="${escapeHtml(preset.label)}"><span style="background:${escapeHtml(
2059
+ preset.tokens.colors.primary
2060
+ )}"></span></button>`
2061
+ ).join("");
2062
+ const config = serializeInlineScriptValue({
2063
+ defaultPresetId: designSystem.defaultPresetId,
2064
+ presets
2065
+ });
2066
+ return {
2067
+ style: '<style data-suda-dev-palette-style>\n#suda-dev-palette{all:initial;position:fixed;z-index:2147483000;top:50%;right:16px;width:64px;max-height:calc(100svh - 32px);padding:8px 9px;overflow-x:hidden;overflow-y:auto;box-sizing:border-box;background:#fff;border:1px solid #d1d5db;border-radius:999px;box-shadow:0 8px 24px rgb(15 23 42 / 12%);transform:translateY(-50%);color-scheme:light;scrollbar-width:none;-ms-overflow-style:none}\n#suda-dev-palette::-webkit-scrollbar{display:none}\n#suda-dev-palette button{all:initial;position:relative;display:grid;width:44px;height:44px;box-sizing:border-box;cursor:pointer;border-radius:999px;place-items:center}\n#suda-dev-palette button span{display:block;width:32px;height:32px;border-radius:999px;transition:transform 120ms ease}\n#suda-dev-palette button:hover span{transform:scale(1.08)}\n#suda-dev-palette button[aria-pressed="true"] span{visibility:hidden}\n#suda-dev-palette button[aria-pressed="true"]::after{position:absolute;display:grid;width:32px;height:32px;color:var(--suda-dev-preset-primary);font:700 22px/1 ui-sans-serif,system-ui,sans-serif;content:"\u2713";place-items:center}\n#suda-dev-palette button:focus-visible{outline:2px solid #94a3b8;outline-offset:2px}\n@media(max-width:640px){#suda-dev-palette{right:8px;max-height:calc(100svh - 16px)}}\n@media(prefers-reduced-motion:reduce){#suda-dev-palette button span{transition:none}}\n</style>',
2068
+ html: `<aside id="suda-dev-palette" aria-label="Design presets">${buttons}</aside><script data-suda-dev-palette-script>(function(){const config=${config};const palette=document.getElementById("suda-dev-palette");if(!palette)return;const byId=new Map(config.presets.map((preset)=>[preset.id,preset]));const params=new URL(location.href).searchParams;const requested=params.get("designPreset");const selected=byId.has(requested)?requested:config.defaultPresetId;function apply(id,updateUrl){const preset=byId.get(id);if(!preset)return;const properties=Object.keys(preset.variables);const targets=[document.documentElement,document.body,...document.querySelectorAll("[style]")].filter((element,index,items)=>items.indexOf(element)===index&&(element===document.documentElement||element===document.body||properties.some((property)=>element.style.getPropertyValue(property)!=="")));for(const target of targets){for(const [property,value] of Object.entries(preset.variables))target.style.setProperty(property,value)}for(const button of palette.querySelectorAll("[data-suda-dev-preset]")){const active=button.dataset.sudaDevPreset===id;button.setAttribute("aria-pressed",String(active));button.style.setProperty("--suda-dev-preset-primary",byId.get(button.dataset.sudaDevPreset).variables["--suda-color-primary"])}if(updateUrl){const url=new URL(location.href);url.searchParams.set("designPreset",id);history.replaceState(history.state,"",url)}}if(requested&&byId.has(requested))apply(selected,false);else for(const button of palette.querySelectorAll("[data-suda-dev-preset]")){button.setAttribute("aria-pressed",String(button.dataset.sudaDevPreset===selected));button.style.setProperty("--suda-dev-preset-primary",byId.get(button.dataset.sudaDevPreset).variables["--suda-color-primary"])}palette.addEventListener("click",(event)=>{const button=event.target.closest("[data-suda-dev-preset]");if(button)apply(button.dataset.sudaDevPreset,true)})})();</script>`
2069
+ };
2070
+ }
2041
2071
  var SCREENSHOT_DEVICES = ["desktop", "tablet", "mobile"];
2042
2072
  var SCREENSHOT_DEVICE_CONFIG = {
2043
2073
  desktop: {