@sudajs/cli 0.18.9 → 0.18.10
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.d.ts +4 -2
- package/dist/index.js +100 -62
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/theme/AGENTS.md +183 -1182
- package/templates/theme/docs/agent-guides/component-authoring.md +270 -0
- package/templates/theme/docs/agent-guides/design-and-runtime.md +170 -0
- package/templates/theme/docs/agent-guides/editor-compatibility.md +231 -0
- package/templates/theme/docs/agent-guides/templates-and-locales.md +206 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { ThemeModule, ThemeStarterPage } from '@sudajs/theme-engine';
|
|
3
|
-
import { ThemeRender, extractLayoutChrome, resolveAssetPath } from '@sudajs/theme-engine/server';
|
|
3
|
+
import { ThemeRender, extractLayoutChrome, resolveAssetPath, ThemePreviewLocaleMessages } from '@sudajs/theme-engine/server';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { createElement } from 'react';
|
|
6
6
|
import { renderToString } from 'react-dom/server';
|
|
@@ -1816,6 +1816,7 @@ declare const __testUtils: {
|
|
|
1816
1816
|
performUpdateThemeSettings: typeof performUpdateThemeSettings;
|
|
1817
1817
|
getRemoteThemeSettings: typeof getRemoteThemeSettings;
|
|
1818
1818
|
renderDevStarterPageHtml: typeof renderDevStarterPageHtml;
|
|
1819
|
+
writeVitePreviewEntries: typeof writeVitePreviewEntries;
|
|
1819
1820
|
resolveDevStarterSlug: typeof resolveDevStarterSlug;
|
|
1820
1821
|
resolveScreenshotOptions: typeof resolveScreenshotOptions;
|
|
1821
1822
|
slugifyThemeName: typeof slugifyThemeName;
|
|
@@ -1831,6 +1832,7 @@ declare const __testUtils: {
|
|
|
1831
1832
|
updateRemotePageDraft: typeof updateRemotePageDraft;
|
|
1832
1833
|
};
|
|
1833
1834
|
declare function watchTheme(root: string, port: number): Promise<void>;
|
|
1835
|
+
declare function writeVitePreviewEntries(root: string): Promise<void>;
|
|
1834
1836
|
declare function withSerializedVitePreviewLocaleLoad<Result>(server: object, load: () => Promise<Result>): Promise<Result>;
|
|
1835
1837
|
declare function resolveDevStarterSlug(pathname: string): string | null | undefined;
|
|
1836
1838
|
declare function resolveThemePreviewLocale(params: {
|
|
@@ -1856,7 +1858,7 @@ interface ThemeRenderer {
|
|
|
1856
1858
|
renderToString: typeof renderToString;
|
|
1857
1859
|
}
|
|
1858
1860
|
declare function loadThemeScopedRenderer(themeRoot: string): Promise<ThemeRenderer>;
|
|
1859
|
-
declare function renderDevStarterPageHtml(theme: ValidatedTheme, page: ThemeStarterPage, renderer: ThemeRenderer, locale?: string, preserveLang?: boolean): string;
|
|
1861
|
+
declare function renderDevStarterPageHtml(theme: ValidatedTheme, page: ThemeStarterPage, renderer: ThemeRenderer, locale?: string, preserveLang?: boolean, previewLocaleMessages?: ThemePreviewLocaleMessages): string;
|
|
1860
1862
|
interface ScreenshotOptions extends ThemeRootOptions {
|
|
1861
1863
|
device?: string[] | string;
|
|
1862
1864
|
output?: string;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
|
-
import fs, { readFile, writeFile, stat, readdir,
|
|
4
|
+
import fs, { readFile, mkdir, writeFile, stat, readdir, copyFile, rm } from 'fs/promises';
|
|
5
5
|
import { createRequire } from 'module';
|
|
6
6
|
import path2 from 'path';
|
|
7
7
|
import { createInterface } from 'readline/promises';
|
|
@@ -12,6 +12,9 @@ import { themeDesignSystemSchema, createThemeDesignCssVariables, createThemeAgen
|
|
|
12
12
|
import { themeManifestSchema, runWithThemePreviewLocale } from '@sudajs/theme-engine/server';
|
|
13
13
|
import { Command } from 'commander';
|
|
14
14
|
import { build } from 'esbuild';
|
|
15
|
+
import { CircleCheck } from 'lucide-react';
|
|
16
|
+
import { createElement } from 'react';
|
|
17
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
15
18
|
import { z } from 'zod';
|
|
16
19
|
import os from 'os';
|
|
17
20
|
import pc from 'picocolors';
|
|
@@ -1520,26 +1523,7 @@ async function buildClientRuntime(root, minify) {
|
|
|
1520
1523
|
await mkdir(path2.dirname(generatedEntry), { recursive: true });
|
|
1521
1524
|
await writeFile(
|
|
1522
1525
|
generatedEntry,
|
|
1523
|
-
|
|
1524
|
-
'"use client";',
|
|
1525
|
-
'import type { ThemeClientHooks, ThemeClientRuntime, ThemeRenderModule } from "@sudajs/theme-engine/runtime";',
|
|
1526
|
-
'import * as themeConfig from "../src/config.js";',
|
|
1527
|
-
clientHooksImport,
|
|
1528
|
-
"const theme: ThemeRenderModule = {",
|
|
1529
|
-
" pageConfig: themeConfig.pageConfig,",
|
|
1530
|
-
" layoutConfig: themeConfig.layoutConfig,",
|
|
1531
|
-
"};",
|
|
1532
|
-
'if ("rendering" in themeConfig && themeConfig.rendering !== undefined) {',
|
|
1533
|
-
" theme.rendering = themeConfig.rendering;",
|
|
1534
|
-
"}",
|
|
1535
|
-
"const hooks: ThemeClientHooks = clientHooks;",
|
|
1536
|
-
"const runtime: ThemeClientRuntime = { theme };",
|
|
1537
|
-
"if (hooks.initialize !== undefined) {",
|
|
1538
|
-
" runtime.initialize = hooks.initialize;",
|
|
1539
|
-
"}",
|
|
1540
|
-
"export default runtime;",
|
|
1541
|
-
""
|
|
1542
|
-
].join("\n"),
|
|
1526
|
+
createClientRuntimeSource(clientHooksImport, true),
|
|
1543
1527
|
"utf8"
|
|
1544
1528
|
);
|
|
1545
1529
|
await mkdir(path2.join(root, "dist"), { recursive: true });
|
|
@@ -1754,6 +1738,7 @@ var __testUtils = {
|
|
|
1754
1738
|
performUpdateThemeSettings,
|
|
1755
1739
|
getRemoteThemeSettings,
|
|
1756
1740
|
renderDevStarterPageHtml,
|
|
1741
|
+
writeVitePreviewEntries,
|
|
1757
1742
|
resolveDevStarterSlug,
|
|
1758
1743
|
resolveScreenshotOptions,
|
|
1759
1744
|
slugifyThemeName,
|
|
@@ -1825,13 +1810,17 @@ async function watchTheme(root, port) {
|
|
|
1825
1810
|
async function startViteDevPreviewServer(root, port) {
|
|
1826
1811
|
const viteConfig = await findViteConfig(root);
|
|
1827
1812
|
const vite = await loadThemeVite(root);
|
|
1813
|
+
await writeVitePreviewEntries(root);
|
|
1828
1814
|
const host = "127.0.0.1";
|
|
1829
1815
|
const server = await vite.createServer({
|
|
1830
1816
|
root,
|
|
1831
1817
|
configFile: viteConfig,
|
|
1832
1818
|
configLoader: "runner",
|
|
1833
|
-
cacheDir: path2.join(root, ".suda-build", "vite
|
|
1819
|
+
cacheDir: path2.join(root, ".suda-build", "node_modules", ".vite"),
|
|
1834
1820
|
appType: "custom",
|
|
1821
|
+
optimizeDeps: {
|
|
1822
|
+
entries: [".suda-build/preview-client.ts"]
|
|
1823
|
+
},
|
|
1835
1824
|
server: { host, port },
|
|
1836
1825
|
plugins: [createSudaPreviewVitePlugin(root)]
|
|
1837
1826
|
});
|
|
@@ -1843,6 +1832,55 @@ async function startViteDevPreviewServer(root, port) {
|
|
|
1843
1832
|
close: () => server.close()
|
|
1844
1833
|
};
|
|
1845
1834
|
}
|
|
1835
|
+
async function writeVitePreviewEntries(root) {
|
|
1836
|
+
const clientHooksPath = path2.join(root, "src", "client.ts");
|
|
1837
|
+
const clientHooksImport = existsSync(clientHooksPath) ? 'import { clientHooks } from "../src/client.js";' : "const clientHooks = {};";
|
|
1838
|
+
const buildDir = path2.join(root, ".suda-build");
|
|
1839
|
+
await mkdir(buildDir, { recursive: true });
|
|
1840
|
+
await writeFile(
|
|
1841
|
+
path2.join(buildDir, "runtime.dev.ts"),
|
|
1842
|
+
createClientRuntimeSource(clientHooksImport, false),
|
|
1843
|
+
"utf8"
|
|
1844
|
+
);
|
|
1845
|
+
await writeFile(
|
|
1846
|
+
path2.join(buildDir, "preview-client.ts"),
|
|
1847
|
+
[
|
|
1848
|
+
'import { hydrateThemePage, loadThemeRuntime } from "@sudajs/theme-engine/client";',
|
|
1849
|
+
'import { installThemePreviewLocale, resolveAssetPath } from "@sudajs/theme-engine/site-runtime";',
|
|
1850
|
+
'const payloadElement=document.querySelector("#suda-theme-hydration-data");',
|
|
1851
|
+
'if(!payloadElement){throw new Error("Missing Suda theme hydration payload.")}',
|
|
1852
|
+
"const payload=JSON.parse(payloadElement.textContent ?? '{}');",
|
|
1853
|
+
"if(payload.previewLocaleMessages){installThemePreviewLocale(payload.previewLocaleMessages)}",
|
|
1854
|
+
'const runtime=(await loadThemeRuntime("/.suda-build/runtime.dev.ts")).default;',
|
|
1855
|
+
'const metadata={contactForm:payload.contactForm,resolveAssetUrl:(value: string | undefined)=>resolveAssetPath(value,{legacyResolve:(key)=>key.startsWith("themes/")?`/api/themes/${key.slice("themes/".length)}`:undefined})};',
|
|
1856
|
+
'await hydrateThemePage({container:document.querySelector("[data-theme-hydration-root]")!,runtime,pageData:payload.pageData,layoutData:payload.layoutData,metadata,onRecoverableError:(error)=>console.error("[theme-dev] theme hydration recovered from an error",error)});',
|
|
1857
|
+
""
|
|
1858
|
+
].join("\n"),
|
|
1859
|
+
"utf8"
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
function createClientRuntimeSource(clientHooksImport, useClientDirective) {
|
|
1863
|
+
return [
|
|
1864
|
+
...useClientDirective ? ['"use client";'] : [],
|
|
1865
|
+
'import type { ThemeClientHooks, ThemeClientRuntime, ThemeRenderModule } from "@sudajs/theme-engine/runtime";',
|
|
1866
|
+
'import * as themeConfig from "../src/config.js";',
|
|
1867
|
+
clientHooksImport,
|
|
1868
|
+
"const theme: ThemeRenderModule = {",
|
|
1869
|
+
" pageConfig: themeConfig.pageConfig,",
|
|
1870
|
+
" layoutConfig: themeConfig.layoutConfig,",
|
|
1871
|
+
"};",
|
|
1872
|
+
'if ("rendering" in themeConfig && themeConfig.rendering !== undefined) {',
|
|
1873
|
+
" theme.rendering = themeConfig.rendering;",
|
|
1874
|
+
"}",
|
|
1875
|
+
"const hooks: ThemeClientHooks = clientHooks;",
|
|
1876
|
+
"const runtime: ThemeClientRuntime = { theme };",
|
|
1877
|
+
"if (hooks.initialize !== undefined) {",
|
|
1878
|
+
" runtime.initialize = hooks.initialize;",
|
|
1879
|
+
"}",
|
|
1880
|
+
"export default runtime;",
|
|
1881
|
+
""
|
|
1882
|
+
].join("\n");
|
|
1883
|
+
}
|
|
1846
1884
|
function createSudaPreviewVitePlugin(root) {
|
|
1847
1885
|
return {
|
|
1848
1886
|
name: "suda-theme-preview",
|
|
@@ -1865,54 +1903,31 @@ function createSudaPreviewVitePlugin(root) {
|
|
|
1865
1903
|
const acceptLanguageHeader = request.headers["accept-language"];
|
|
1866
1904
|
const acceptLanguage = Array.isArray(acceptLanguageHeader) ? acceptLanguageHeader.join(",") : acceptLanguageHeader;
|
|
1867
1905
|
const explicitLang = url.searchParams.get("lang");
|
|
1868
|
-
const
|
|
1906
|
+
const localized = await loadLocalizedViteDevTheme(
|
|
1869
1907
|
root,
|
|
1870
1908
|
server,
|
|
1871
1909
|
explicitLang,
|
|
1872
1910
|
acceptLanguage
|
|
1873
1911
|
);
|
|
1874
1912
|
const renderer = await loadThemeScopedRenderer(root);
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
if (!homeSlug) {
|
|
1878
|
-
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
1879
|
-
response.end("No starter pages declared by this theme.");
|
|
1880
|
-
return;
|
|
1881
|
-
}
|
|
1882
|
-
const starter2 = findStarterPage(theme, homeSlug);
|
|
1883
|
-
if (!starter2) {
|
|
1884
|
-
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
1885
|
-
response.end(`Unknown starter page: ${homeSlug}`);
|
|
1886
|
-
return;
|
|
1887
|
-
}
|
|
1888
|
-
const html2 = await server.transformIndexHtml(
|
|
1889
|
-
url.pathname,
|
|
1890
|
-
renderDevStarterPageHtml(
|
|
1891
|
-
theme,
|
|
1892
|
-
starter2,
|
|
1893
|
-
renderer,
|
|
1894
|
-
locale,
|
|
1895
|
-
canonicalLocale(explicitLang) !== null
|
|
1896
|
-
)
|
|
1897
|
-
);
|
|
1898
|
-
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1899
|
-
response.end(html2);
|
|
1900
|
-
return;
|
|
1901
|
-
}
|
|
1902
|
-
const starter = findStarterPage(theme, slug);
|
|
1913
|
+
const starterSlug = slug ?? pickStarterSlug(localized.theme);
|
|
1914
|
+
const starter = starterSlug ? findStarterPage(localized.theme, starterSlug) : null;
|
|
1903
1915
|
if (!starter) {
|
|
1904
1916
|
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
1905
|
-
response.end(
|
|
1917
|
+
response.end(
|
|
1918
|
+
starterSlug ? `Unknown starter page: ${starterSlug}` : "No starter pages declared by this theme."
|
|
1919
|
+
);
|
|
1906
1920
|
return;
|
|
1907
1921
|
}
|
|
1908
1922
|
const html = await server.transformIndexHtml(
|
|
1909
1923
|
url.pathname,
|
|
1910
1924
|
renderDevStarterPageHtml(
|
|
1911
|
-
theme,
|
|
1925
|
+
localized.theme,
|
|
1912
1926
|
starter,
|
|
1913
1927
|
renderer,
|
|
1914
|
-
locale,
|
|
1915
|
-
canonicalLocale(explicitLang) !== null
|
|
1928
|
+
localized.locale,
|
|
1929
|
+
canonicalLocale(explicitLang) !== null,
|
|
1930
|
+
localized.previewLocaleMessages
|
|
1916
1931
|
)
|
|
1917
1932
|
);
|
|
1918
1933
|
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -1940,13 +1955,13 @@ async function loadLocalizedViteDevTheme(root, server, explicitLang, acceptLangu
|
|
|
1940
1955
|
if (!baseTheme.module.manifest.previewLocales) {
|
|
1941
1956
|
return { theme: baseTheme, locale };
|
|
1942
1957
|
}
|
|
1943
|
-
const
|
|
1958
|
+
const previewLocaleMessages = await readDevPreviewLocaleMessages(root, locale);
|
|
1944
1959
|
server.moduleGraph.invalidateAll();
|
|
1945
1960
|
const theme = await runWithThemePreviewLocale(
|
|
1946
|
-
|
|
1961
|
+
previewLocaleMessages,
|
|
1947
1962
|
() => loadViteDevTheme(root, server)
|
|
1948
1963
|
);
|
|
1949
|
-
return { theme, locale };
|
|
1964
|
+
return { theme, locale, previewLocaleMessages };
|
|
1950
1965
|
});
|
|
1951
1966
|
}
|
|
1952
1967
|
var vitePreviewLocaleLoadTails = /* @__PURE__ */ new WeakMap();
|
|
@@ -1998,6 +2013,9 @@ function resolveDevStarterSlug(pathname) {
|
|
|
1998
2013
|
if (pathname === "/") {
|
|
1999
2014
|
return null;
|
|
2000
2015
|
}
|
|
2016
|
+
if (pathname.startsWith("/@")) {
|
|
2017
|
+
return void 0;
|
|
2018
|
+
}
|
|
2001
2019
|
const normalized = pathname.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
2002
2020
|
if (!normalized || normalized.includes("/")) {
|
|
2003
2021
|
return void 0;
|
|
@@ -2104,7 +2122,7 @@ async function loadThemeScopedRenderer(themeRoot) {
|
|
|
2104
2122
|
renderToString: reactDomServerModule.renderToString
|
|
2105
2123
|
};
|
|
2106
2124
|
}
|
|
2107
|
-
function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserveLang = false) {
|
|
2125
|
+
function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserveLang = false, previewLocaleMessages) {
|
|
2108
2126
|
const chrome = renderer.extractLayoutChrome(theme.module.defaultLayout);
|
|
2109
2127
|
const metadata = {
|
|
2110
2128
|
resolveAssetUrl: createPreviewAssetResolver(renderer.resolveAssetPath),
|
|
@@ -2122,6 +2140,16 @@ function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserve
|
|
|
2122
2140
|
const customHead = chrome.customHeadCode ?? "";
|
|
2123
2141
|
const customBody = chrome.customBodyCode ?? "";
|
|
2124
2142
|
const designPalette = renderDevDesignPalette(theme.module.manifest.designSystem);
|
|
2143
|
+
const hydrationPayload = serializeInlineScriptValue({
|
|
2144
|
+
pageData: page.data,
|
|
2145
|
+
layoutData: theme.module.defaultLayout,
|
|
2146
|
+
contactForm: PREVIEW_CONTACT_FORM,
|
|
2147
|
+
previewLocaleMessages
|
|
2148
|
+
});
|
|
2149
|
+
const hydrationScript = [
|
|
2150
|
+
`<script id="suda-theme-hydration-data" type="application/json">${hydrationPayload}</script>`,
|
|
2151
|
+
'<script type="module">void import("/.suda-build/preview-client.ts").catch((error)=>console.error("[theme-dev] theme client failed to load",error))</script>'
|
|
2152
|
+
].join("");
|
|
2125
2153
|
return [
|
|
2126
2154
|
"<!doctype html>",
|
|
2127
2155
|
`<html lang="${escapeHtml(locale)}">`,
|
|
@@ -2134,9 +2162,10 @@ function renderDevStarterPageHtml(theme, page, renderer, locale = "en", preserve
|
|
|
2134
2162
|
customHead,
|
|
2135
2163
|
"</head>",
|
|
2136
2164
|
`<body${cssVarStyle ? ` style="${cssVarStyle}"` : ""}>`,
|
|
2137
|
-
body
|
|
2165
|
+
`<div data-theme-hydration-root="" style="display:contents">${body}</div>`,
|
|
2138
2166
|
designPalette.html,
|
|
2139
2167
|
customBody,
|
|
2168
|
+
hydrationScript,
|
|
2140
2169
|
...preserveLang ? [
|
|
2141
2170
|
'<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>'
|
|
2142
2171
|
] : [],
|
|
@@ -2155,19 +2184,28 @@ function renderDevDesignPalette(designSystem) {
|
|
|
2155
2184
|
id: preset.id,
|
|
2156
2185
|
variables: createThemeDesignCssVariables(preset.tokens)
|
|
2157
2186
|
}));
|
|
2187
|
+
const selectedIcon = renderToStaticMarkup(
|
|
2188
|
+
createElement(CircleCheck, {
|
|
2189
|
+
className: "suda-dev-preset-selected-icon",
|
|
2190
|
+
width: 32,
|
|
2191
|
+
height: 32,
|
|
2192
|
+
"aria-hidden": true,
|
|
2193
|
+
focusable: false
|
|
2194
|
+
})
|
|
2195
|
+
);
|
|
2158
2196
|
const buttons = designSystem.presets.map(
|
|
2159
2197
|
(preset) => `<button type="button" data-suda-dev-preset="${escapeHtml(preset.id)}" title="${escapeHtml(
|
|
2160
2198
|
preset.description ? `${preset.label} \u2014 ${preset.description}` : preset.label
|
|
2161
2199
|
)}" aria-label="${escapeHtml(preset.label)}"><span style="background:${escapeHtml(
|
|
2162
2200
|
preset.tokens.colors.primary
|
|
2163
|
-
)}"></span
|
|
2201
|
+
)}"></span>${selectedIcon}</button>`
|
|
2164
2202
|
).join("");
|
|
2165
2203
|
const config = serializeInlineScriptValue({
|
|
2166
2204
|
defaultPresetId: designSystem.defaultPresetId,
|
|
2167
2205
|
presets
|
|
2168
2206
|
});
|
|
2169
2207
|
return {
|
|
2170
|
-
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
|
|
2208
|
+
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 .suda-dev-preset-selected-icon{position:absolute;display:block;width:32px;height:32px;color:var(--suda-dev-preset-primary);visibility:hidden;opacity:0;transform:scale(.85);transition:opacity 120ms ease,transform 120ms ease}\n#suda-dev-palette button[aria-pressed="true"] .suda-dev-preset-selected-icon{visibility:visible;opacity:1;transform:scale(1)}\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,#suda-dev-palette .suda-dev-preset-selected-icon{transition:none}}\n</style>',
|
|
2171
2209
|
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>`
|
|
2172
2210
|
};
|
|
2173
2211
|
}
|