@beforesemicolon/builder 1.8.0 → 1.8.11

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.
Files changed (51) hide show
  1. package/dist/cjs/docs/markdown-layout/index.js +1 -0
  2. package/dist/cjs/docs/markdown-layout/marked-extension.js +1 -0
  3. package/dist/cjs/docs/markdown-layout/parser.js +7 -0
  4. package/dist/cjs/docs/markdown-layout/renderer.js +1 -0
  5. package/dist/cjs/docs/markdown-layout/types.js +1 -0
  6. package/dist/cjs/docs/run.js +76 -1
  7. package/dist/cjs/docs/templates/fading-citrus/layouts/_code-snippet.js +53 -0
  8. package/dist/cjs/docs/templates/fading-citrus/layouts/_layout-utils.js +89 -0
  9. package/dist/cjs/docs/templates/fading-citrus/layouts/document.js +6 -3
  10. package/dist/cjs/docs/templates/fading-citrus/layouts/landing-cta.js +30 -0
  11. package/dist/cjs/docs/templates/fading-citrus/layouts/landing-ecosystem.js +43 -0
  12. package/dist/cjs/docs/templates/fading-citrus/layouts/landing-features.js +25 -0
  13. package/dist/cjs/docs/templates/fading-citrus/layouts/landing-hero.js +81 -0
  14. package/dist/cjs/docs/templates/fading-citrus/layouts/landing-install.js +116 -0
  15. package/dist/cjs/docs/templates/fading-citrus/layouts/landing-showcase.js +125 -0
  16. package/dist/cjs/docs/templates/fading-citrus/layouts/landing.js +7 -617
  17. package/dist/cjs/docs/templates/fading-citrus/stylesheets/common.css +5 -4
  18. package/dist/cjs/docs/templates/fading-citrus/stylesheets/documentation.css +5 -71
  19. package/dist/cjs/docs/templates/fading-citrus/stylesheets/landing.css +4 -1
  20. package/dist/cjs/docs/templates/fading-citrus/template.config.js +101 -2
  21. package/dist/cjs/docs/types.js +1 -1
  22. package/dist/esm/docs/markdown-layout/index.js +1 -0
  23. package/dist/esm/docs/markdown-layout/marked-extension.js +1 -0
  24. package/dist/esm/docs/markdown-layout/parser.js +7 -0
  25. package/dist/esm/docs/markdown-layout/renderer.js +1 -0
  26. package/dist/esm/docs/markdown-layout/types.js +0 -0
  27. package/dist/esm/docs/run.js +76 -1
  28. package/dist/esm/docs/templates/fading-citrus/layouts/_code-snippet.js +53 -0
  29. package/dist/esm/docs/templates/fading-citrus/layouts/_layout-utils.js +89 -0
  30. package/dist/esm/docs/templates/fading-citrus/layouts/document.js +6 -3
  31. package/dist/esm/docs/templates/fading-citrus/layouts/landing-cta.js +30 -0
  32. package/dist/esm/docs/templates/fading-citrus/layouts/landing-ecosystem.js +43 -0
  33. package/dist/esm/docs/templates/fading-citrus/layouts/landing-features.js +25 -0
  34. package/dist/esm/docs/templates/fading-citrus/layouts/landing-hero.js +81 -0
  35. package/dist/esm/docs/templates/fading-citrus/layouts/landing-install.js +116 -0
  36. package/dist/esm/docs/templates/fading-citrus/layouts/landing-showcase.js +125 -0
  37. package/dist/esm/docs/templates/fading-citrus/layouts/landing.js +7 -617
  38. package/dist/esm/docs/templates/fading-citrus/stylesheets/common.css +5 -4
  39. package/dist/esm/docs/templates/fading-citrus/stylesheets/documentation.css +5 -71
  40. package/dist/esm/docs/templates/fading-citrus/stylesheets/landing.css +4 -1
  41. package/dist/esm/docs/templates/fading-citrus/template.config.js +101 -2
  42. package/dist/types/docs/markdown-layout/index.d.ts +4 -0
  43. package/dist/types/docs/markdown-layout/marked-extension.d.ts +8 -0
  44. package/dist/types/docs/markdown-layout/parser.d.ts +12 -0
  45. package/dist/types/docs/markdown-layout/renderer.d.ts +3 -0
  46. package/dist/types/docs/markdown-layout/types.d.ts +35 -0
  47. package/dist/types/docs/run.d.ts +12 -1
  48. package/dist/types/docs/types.d.ts +22 -0
  49. package/package.json +3 -2
  50. package/dist/cjs/docs/templates/fading-citrus/layouts/_copy-code.js +0 -50
  51. package/dist/esm/docs/templates/fading-citrus/layouts/_copy-code.js +0 -50
@@ -0,0 +1 @@
1
+ "use strict";var a=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var t=(f,e,p,x)=>{if(e&&typeof e=="object"||typeof e=="function")for(let m of c(e))!d.call(f,m)&&m!==p&&a(f,m,{get:()=>e[m],enumerable:!(x=b(e,m))||x.enumerable});return f},r=(f,e,p)=>(t(f,e,"default"),p&&t(p,e,"default"));var g=f=>t(a({},"__esModule",{value:!0}),f);var o={};module.exports=g(o);r(o,require("./marked-extension.js"),module.exports);r(o,require("./parser.js"),module.exports);r(o,require("./renderer.js"),module.exports);r(o,require("./types.js"),module.exports);0&&(module.exports={...require("./marked-extension.js"),...require("./parser.js"),...require("./renderer.js"),...require("./types.js")});
@@ -0,0 +1 @@
1
+ "use strict";var d=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var y=(o,r)=>d(o,"name",{value:r,configurable:!0});var m=(o,r)=>{for(var e in r)d(o,e,{get:r[e],enumerable:!0})},l=(o,r,e,t)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of w(r))!L.call(o,n)&&n!==e&&d(o,n,{get:()=>r[n],enumerable:!(t=M(r,n))||t.enumerable});return o};var c=o=>l(d({},"__esModule",{value:!0}),o);var x={};m(x,{createMarkdownLayoutExtension:()=>p});module.exports=c(x);var k=require("./parser.js"),u=require("./renderer.js");const p=y(({marked:o,handlers:r={},renderMarkdown:e})=>({extensions:[{name:"markdownLayout",level:"block",start(t){return t.match(/^::: layout /m)?.index},tokenizer(t){const n=(0,k.readLayoutBlock)(t);if(n)return{...(0,k.parseLayoutBlock)(n),type:"markdownLayout",raw:n}},renderer(t){const n=t,s={marked:o,renderMarkdown(a){return e?e(a):o.parse(a)},renderDefault(a){return(0,u.renderDefaultMarkdownLayout)(a,s)},renderParts(a){return a.items.map(i=>({...i,html:s.renderMarkdown(i.body)}))}};return(0,u.renderMarkdownLayout)(n,s,r)}}]}),"createMarkdownLayoutExtension");0&&(module.exports={createMarkdownLayoutExtension});
@@ -0,0 +1,7 @@
1
+ "use strict";var a=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var i=(e,t)=>a(e,"name",{value:t,configurable:!0});var g=(e,t)=>{for(var n in t)a(e,n,{get:t[n],enumerable:!0})},k=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of w(t))!L.call(e,o)&&o!==n&&a(e,o,{get:()=>t[o],enumerable:!(r=h(t,o))||r.enumerable});return e};var x=e=>k(a({},"__esModule",{value:!0}),e);var j={};g(j,{parseItemHeader:()=>f,parseLayoutBlock:()=>$,parseLayoutHeader:()=>y,parseOptions:()=>d,readLayoutBlock:()=>N});module.exports=x(j);const l=/^::: layout(?:\s+.*)?$/,c=/^:::\s*$/,M=/^===(?:\s+.*)?$/,O=i(e=>{const t=e.replace(/^(['"])(.*)\1$/,"$2");return/^-?\d+(\.\d+)?$/.test(t)?Number(t):t==="true"?!0:t==="false"?!1:t},"coerceOptionValue"),p=i((e="")=>{const t=[],n=/\S+=("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S*)|"[^"]*"|'[^']*'|\S+/g;let r;for(;r=n.exec(e);)t.push(r[0]);return t},"tokenizeOptions"),d=i((e="")=>p(e).reduce((t,n)=>{const r=n.indexOf("=");if(r===-1)return t[n]=!0,t;const o=n.slice(0,r).trim(),s=n.slice(r+1).trim();return o&&(t[o]=O(s)),t},{}),"parseOptions"),y=i(e=>{const t=e.replace(/^:::\s*layout\s*/,"").trim(),[n="",...r]=p(t);if(!n)throw new Error(`Invalid layout header: ${e}`);return{layoutType:n,options:d(r.join(" "))}},"parseLayoutHeader"),f=i(e=>{const t=e.replace(/^===\s*/,"").trim();if(!t)return{name:null,options:{}};const[n=null,...r]=p(t);return{name:n,options:d(r.join(" "))}},"parseItemHeader"),I=i(e=>{const t=e.split(`
2
+ `),n=[];let r=0,o=null,s=[];const m=i(()=>{o&&(n.push({...o,body:s.join(`
3
+ `).trim()}),s=[])},"pushCurrent");for(const u of t){if(l.test(u.trim())){o&&s.push(u),r+=1;continue}if(c.test(u.trim())&&r>0){r-=1,o&&s.push(u);continue}if(r===0&&M.test(u.trim())){m(),o=f(u.trim());continue}o&&s.push(u)}return m(),n.length?n:[{name:null,options:{},body:e.trim()}]},"splitLayoutItems"),$=i(e=>{const t=e.replace(/\s+$/,"").split(`
4
+ `),n=t.shift();if(!n||!l.test(n.trim()))throw new Error("Layout block must start with `::: layout`.");return t.length&&c.test(t[t.length-1].trim())&&t.pop(),{...y(n.trim()),items:I(t.join(`
5
+ `)),raw:e}},"parseLayoutBlock"),N=i(e=>{if(!e.startsWith("::: layout"))return null;const t=e.split(`
6
+ `);let n=0;const r=[];for(const o of t){const s=o.trim();if(r.push(o),l.test(s))n+=1;else if(c.test(s)&&(n-=1,n===0))return r.join(`
7
+ `)}return null},"readLayoutBlock");0&&(module.exports={parseItemHeader,parseLayoutBlock,parseLayoutHeader,parseOptions,readLayoutBlock});
@@ -0,0 +1 @@
1
+ "use strict";var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var n=(t,o)=>s(t,"name",{value:o,configurable:!0});var i=(t,o)=>{for(var a in o)s(t,a,{get:o[a],enumerable:!0})},c=(t,o,a,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of p(o))!d.call(t,e)&&e!==a&&s(t,e,{get:()=>o[e],enumerable:!(r=l(o,e))||r.enumerable});return t};var w=t=>c(s({},"__esModule",{value:!0}),t);var $={};i($,{renderDefaultMarkdownLayout:()=>L,renderMarkdownLayout:()=>M});module.exports=w($);const y=n(t=>String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;"),"escapeAttribute"),k=n(t=>`--${t.replace(/[A-Z]/g,o=>`-${o.toLowerCase()}`)}`,"optionToStyleName"),u=n(t=>{const o=Object.entries(t).filter(([,a])=>typeof a!="boolean").map(([a,r])=>`${k(a)}: ${r};`);return o.length?` style="${y(o.join(" "))}"`:""},"optionsToStyle"),L=n((t,o)=>{const a=y(t.layoutType),r=t.items.map(e=>`<section class="bfs-layout-item"${e.name?` data-name="${y(e.name)}"`:""}${u(e.options)}>${o.renderMarkdown(e.body)}</section>`).join("");return`<div class="bfs-layout bfs-layout-${a}" data-layout="${a}"${u(t.options)}>${r}</div>`},"renderDefaultMarkdownLayout"),M=n((t,o,a={})=>{const r=a[t.layoutType];return r?r({type:t.layoutType,options:t.options,parts:o.renderParts(t),raw:t.raw},o):o.renderDefault(t)},"renderMarkdownLayout");0&&(module.exports={renderDefaultMarkdownLayout,renderMarkdownLayout});
@@ -0,0 +1 @@
1
+ "use strict";var n=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var i=(t,o,a,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of u(o))!y.call(t,e)&&e!==a&&n(t,e,{get:()=>o[e],enumerable:!(r=d(o,e))||r.enumerable});return t};var k=t=>i(n({},"__esModule",{value:!0}),t);var p={};module.exports=k(p);
@@ -1 +1,76 @@
1
- "use strict";var V=Object.create;var S=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,tt=Object.prototype.hasOwnProperty;var D=(s,a)=>S(s,"name",{value:a,configurable:!0});var et=(s,a)=>{for(var o in a)S(s,o,{get:a[o],enumerable:!0})},R=(s,a,o,c)=>{if(a&&typeof a=="object"||typeof a=="function")for(let l of Y(a))!tt.call(s,l)&&l!==o&&S(s,l,{get:()=>a[l],enumerable:!(c=X(a,l))||c.enumerable});return s};var f=(s,a,o)=>(o=s!=null?V(Z(s)):{},R(a||!s||!s.__esModule?S(o,"default",{value:s,enumerable:!0}):o,s)),st=s=>R(S({},"__esModule",{value:!0}),s);var it={};et(it,{buildDocs:()=>ot});module.exports=st(it);const nt={};var B=require("marked"),i=require("fs/promises"),r=f(require("path"),1),z=f(require("front-matter"),1),J=f(require("isomorphic-dompurify"),1),U=require("marked-highlight"),L=f(require("highlight.js"),1),G=f(require("./templates/default.template.js"),1),H=f(require("./renderer/index.js"),1),Q=f(require("clean-css"),1),q=f(require("html-minifier"),1),rt=f(require("@putout/minify"),1),b=require("url"),m=f(require("fs"),1);let _;const at=new Q.default({inline:["none"]}),E=new Map;E.set("default",G.default);let A;const v=new B.Marked((0,U.markedHighlight)({langPrefix:"hljs language-",highlight(s,a){const o=L.default.getLanguage(a)?a:"plaintext";return L.default.highlight(s,{language:o}).value}}));v.use({renderer:H.default});const g=D(async s=>{const a=await(0,i.readdir)(s),o=[];for(const c of a){const l=r.default.extname(c);/^[._]/.test(c)||(l?o.push(r.default.join(s,c)):/(stylesheets|assets|scripts)/.test(c)||o.push(...await g(r.default.join(s,c))))}return o},"traverseDirectory");v.use({hooks:{postprocess(s){const{layout:a="default",...o}=A.attributes;s=J.default.sanitize(s);const c=[...s.matchAll(/<h([0-6])\sid="[^"]+".*?>.*?<a\s+href="([^"]+)".*?>([^<]+)<\/a>/gm)].map(l=>({path:l[2],label:l[3],level:l[1]}));return E.get(a)?.({...o,content:s,siteMap:A.siteMap,tableOfContent:c,projectMeta:_})||s}}});const ot=D(async({srcDir:s,publicDir:a,markedOptions:o,template:c}={})=>{try{const t=r.default.resolve(process.cwd(),"package.json");m.default.existsSync(t)&&(_=JSON.parse(await(0,i.readFile)(t,"utf-8")))}catch(t){console.warn("Failed to load project package.json metadata",t)}const l=D(()=>{try{return __dirname}catch{return r.default.dirname((0,b.fileURLToPath)(nt.url))}},"getDirname"),d=c?r.default.resolve(l(),"templates",c):null,j=d?r.default.resolve(d,"assets"):null,x=d?r.default.resolve(d,"stylesheets"):null,P=d?r.default.resolve(d,"layouts"):null;if(d)try{let t=r.default.resolve(d,"template.config.js");if(m.default.existsSync(t)||(t=t.replace(/\.js$/,".ts")),m.default.existsSync(t)){const e=await import((0,b.pathToFileURL)(t).href),n=e.default||e;n.markedOptions&&v.use(n.markedOptions)}}catch(t){console.error(`Failed to load template config for ${c}`,t)}o&&v.use(o);const p=s??r.default.resolve(process.cwd(),"docs"),h=a??r.default.resolve(process.cwd(),"website"),T=r.default.resolve(p,"_layouts"),M=r.default.resolve(p,"assets"),$=r.default.resolve(p,"stylesheets"),k=r.default.resolve(p,"scripts");if(await(0,i.mkdir)(h,{recursive:!0}),j&&m.default.existsSync(j))try{await(0,i.cp)(j,M.replace(p,h),{recursive:!0})}catch(t){console.warn(t)}if(m.default.existsSync(M))try{await(0,i.cp)(M,M.replace(p,h),{recursive:!0})}catch(t){console.warn(t)}try{const t=new Set;if(x&&m.default.existsSync(x)&&(await g(x)).forEach(e=>t.add(e)),m.default.existsSync($)&&(await g($)).forEach(e=>t.add(e)),t.size){await(0,i.mkdir)(r.default.join(h,"stylesheets"),{recursive:!0});for(const e of t){const n=await(0,i.readFile)(e,"utf-8"),u=at.minify(n);u.errors.length&&u.errors.forEach(console.error);const y=e.startsWith(p)?e.replace(p,h):r.default.join(h,"stylesheets",r.default.basename(e));await(0,i.writeFile)(y,u.styles??n)}}}catch(t){console.error(t)}if(m.default.existsSync(k))try{const t=await g(k);t.length&&await(0,i.mkdir)(k.replace(p,h),{recursive:!0});for(const e of t)try{const n=await(0,i.readFile)(e,"utf-8");await(0,i.writeFile)(e.replace(p,h),rt.minify(n))}catch(n){console.error(n)}}catch(t){console.warn(t)}try{const t=new Map;P&&m.default.existsSync(P)&&(await g(P)).forEach(e=>{/\.(j|t)s$/.test(e)&&t.set(r.default.basename(e).replace(/\.(j|t)s$/,""),e)}),m.default.existsSync(T)&&(await g(T)).forEach(e=>{/\.(j|t)s$/.test(e)&&t.set(r.default.basename(e).replace(/\.(j|t)s$/,""),e)});for(const[e,n]of t.entries()){const u=await import((0,b.pathToFileURL)(n).href);E.set(e,u.default)}}catch(t){console.error("Template import failed",t)}const I=await g(p),W=new Map;(await Promise.all(I.filter(t=>t.endsWith(".md")).map(async t=>{const e=await(0,i.readFile)(t,"utf-8");return{filePath:t,...(0,z.default)(e)}}))).sort((t,e)=>(t.attributes.order??0)-(e.attributes.order??0)).map(({attributes:t,body:e,filePath:n})=>{const u=n.replace(p,"").replace(/\.md/,".html"),y=n.replace(p,h).replace(".md",".html"),O=y.replace(r.default.basename(y),""),C=r.default.basename(u)||"/",K=u.replace(C,"").replace(/\/$/,"");let w=W;K.split("/").filter(Boolean).forEach(F=>{w.has(F)||w.set(F,new Map),w=w.get(F)});const N={...t,path:u};return w.has(C)||w.set(C,N),{attributes:N,fileWebsitePath:y,fileDirWebsitePath:O,body:e,siteMap:W}}).forEach(async({attributes:t,body:e,fileDirWebsitePath:n,fileWebsitePath:u,siteMap:y})=>{A={attributes:t,siteMap:y};const O=await v.parse(e);await(0,i.mkdir)(n,{recursive:!0}),await(0,i.writeFile)(u,q.default.minify(O,{includeAutoGeneratedTags:!0,removeAttributeQuotes:!0,removeComments:!0,removeRedundantAttributes:!0,removeScriptTypeAttributes:!0,removeStyleLinkTypeAttributes:!0,sortClassName:!0,useShortDoctype:!0,collapseWhitespace:!0,minifyJS:!0,minifyCSS:!0}))})},"buildDocs");0&&(module.exports={buildDocs});
1
+ "use strict";var fe=Object.create;var C=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var he=Object.getOwnPropertyNames;var ge=Object.getPrototypeOf,ye=Object.prototype.hasOwnProperty;var m=(e,t)=>C(e,"name",{value:t,configurable:!0});var we=(e,t)=>{for(var r in t)C(e,r,{get:t[r],enumerable:!0})},Q=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of he(t))!ye.call(e,i)&&i!==r&&C(e,i,{get:()=>t[i],enumerable:!(n=de(t,i))||n.enumerable});return e};var w=(e,t,r)=>(r=e!=null?fe(ge(e)):{},Q(t||!e||!e.__esModule?C(r,"default",{value:e,enumerable:!0}):r,e)),ve=e=>Q(C({},"__esModule",{value:!0}),e);var _e={};we(_e,{buildDocs:()=>We});module.exports=ve(_e);const Be={};var ee=require("marked"),c=require("fs/promises"),o=w(require("path"),1),te=w(require("front-matter"),1),se=w(require("isomorphic-dompurify"),1),re=require("marked-highlight"),W=w(require("highlight.js"),1),oe=w(require("./templates/default.template.js"),1),ae=w(require("./renderer/index.js"),1),ne=require("./markdown-layout/index.js"),ie=w(require("clean-css"),1),le=w(require("html-minifier"),1),X=w(require("@putout/minify"),1),$=require("url"),p=w(require("fs"),1);let K;const V=new ie.default({inline:["none"]}),A=new Map;A.set("default",oe.default);let R;const xe=m((e,t)=>{if(!(!e&&!t))return{light:{...e?.light,...t?.light},dark:{...e?.dark,...t?.dark}}},"mergeTheme"),Se=m((e,t)=>({...e,...t,markdownLayouts:{...e.markdownLayouts,...t.markdownLayouts},scripts:{...e.scripts,...t.scripts},theme:xe(e.theme,t.theme)}),"mergeTemplateConfig"),be=m((e,t)=>{if(typeof e=="function")return!0;const{match:r}=e;return r?typeof r=="string"?t.includes(r):Array.isArray(r)?r.some(n=>t.includes(n)):r instanceof RegExp?r.test(t):r(t):!0},"scriptMatches"),De=m((e,t)=>e?Object.values(e).filter(r=>r!==!1).filter(r=>be(r,t)).map(r=>typeof r=="function"?r():r.render()):[],"renderPageScripts"),G=m((e,t)=>{const r=Object.entries(t).filter(([n])=>n.startsWith("--")).map(([n,i])=>` ${n}: ${i};`).join(`
2
+ `);return r?`${e} {
3
+ ${r}
4
+ }`:""},"renderThemeBlock"),$e=m(e=>{if(!e)return"";const t=e.light??e.dark,r=e.dark??e.light;return!t&&!r?"":[t?G(":root",t):"",r?`@media (prefers-color-scheme: dark) {
5
+ ${G(" :root",r)}
6
+ }`:"",t?G('[data-theme="light"]',t):"",r?G('[data-theme="dark"]',r):""].filter(Boolean).join(`
7
+
8
+ `)},"renderThemeStylesheet"),Pe=m((e="")=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;"),"escapeXML"),ke=m((e="")=>e.replace(/```[\s\S]*?```/g," ").replace(/`([^`]+)`/g,"$1").replace(/!\[[^\]]*]\([^)]*\)/g," ").replace(/\[([^\]]+)]\([^)]*\)/g,"$1").replace(/^#{1,6}\s+/gm,"").replace(/^---+$/gm," ").replace(/[>*_~]/g,"").replace(/\s+/g," ").trim(),"stripMarkdown"),je=m(e=>e==="/index.html"?"/":e.replace(/\/index\.html$/,"/").replace(/\.html$/,"").replace(/\/+/g,"/"),"pagePathToUrlPath"),Y=m((e,t)=>e?`${e.replace(/\/$/,"")}${t==="/"?"/":t}`:t,"canonicalUrl"),Te=m(async(e,t)=>p.default.existsSync(e)?(await(0,c.mkdir)(o.default.dirname(t),{recursive:!0}),await(0,c.cp)(e,t),!0):!1,"copyIfExists"),Me=m(e=>{const t={sitemap:!0,robots:!0,llms:!0,llmsFull:!0,netlify:!1};return e===!1?{sitemap:!1,robots:!1,llms:!1,llmsFull:!1,netlify:!1}:e===!0||e===void 0?t:{...t,...e}},"normalizeGeneratedFilesConfig"),Ce=m((e,t)=>{if(!t)return"";const r=new Date().toISOString().slice(0,10);return`<?xml version="1.0" encoding="UTF-8"?>
9
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
10
+ ${e.map(i=>{const u=i.urlPath==="/"?"1.0":"0.8";return` <url>
11
+ <loc>${Pe(Y(t,i.urlPath))}</loc>
12
+ <lastmod>${r}</lastmod>
13
+ <changefreq>weekly</changefreq>
14
+ <priority>${u}</priority>
15
+ </url>`}).join(`
16
+ `)}
17
+ </urlset>
18
+ `},"generateSitemap"),Fe=m(e=>`User-agent: *
19
+ Allow: /
20
+ ${e?`
21
+ Sitemap: ${e.replace(/\/$/,"")}/sitemap.xml
22
+ Host: ${e.replace(/\/$/,"")}
23
+ `:""}
24
+ `,"generateRobots"),Ge=m(e=>`# Documentation
25
+
26
+ ## Page index
27
+
28
+ ${e.map(t=>`- ${t.name}: ${t.urlPath} - ${t.description}`).join(`
29
+ `)}
30
+ `,"generateLlms"),Ee=m((e,t)=>`# Documentation for AI agents
31
+
32
+ This file is generated at build time from the Markdown documentation. Use it to choose the most relevant page before reading the canonical HTML documentation.
33
+
34
+ ${e.map(r=>`## ${r.title}
35
+
36
+ URL: ${Y(t,r.urlPath)}
37
+ Source: docs/${r.sourcePath}
38
+ Description: ${r.description}
39
+
40
+ ${r.summary||r.description}
41
+ `).join(`
42
+ `)}
43
+ `,"generateLlmsFull"),Le=m((e,t)=>{const r=["# Generated by @beforesemicolon/builder"];return[t.llms?"llms.txt":"",t.llmsFull?"llms-full.txt":"",t.sitemap?"sitemap.xml":"",t.robots?"robots.txt":""].filter(Boolean).forEach(i=>r.push(`/${i} /${i} 200`)),e.forEach(i=>{if(i.urlPath==="/")return;const u=i.urlPath.endsWith("/")?`${i.urlPath}index.html`:`${i.urlPath}.html`;r.push(`${i.urlPath} ${u} 200`),i.urlPath.endsWith("/")&&r.push(`${i.urlPath.replace(/\/$/,"")} ${u} 200`)}),`${[...new Set(r)].join(`
44
+ `)}
45
+ `},"generateNetlifyRedirects"),Oe=m(e=>`[build]
46
+ command = "node build-docs.js"
47
+ publish = "${e||"website"}"
48
+
49
+ [[headers]]
50
+ for = "/llms.txt"
51
+
52
+ [headers.values]
53
+ Content-Type = "text/plain; charset=utf-8"
54
+ Cache-Control = "public, max-age=0, must-revalidate"
55
+
56
+ [[headers]]
57
+ for = "/llms-full.txt"
58
+
59
+ [headers.values]
60
+ Content-Type = "text/plain; charset=utf-8"
61
+ Cache-Control = "public, max-age=0, must-revalidate"
62
+
63
+ [[headers]]
64
+ for = "/sitemap.xml"
65
+
66
+ [headers.values]
67
+ Content-Type = "application/xml; charset=utf-8"
68
+ Cache-Control = "public, max-age=0, must-revalidate"
69
+
70
+ [[headers]]
71
+ for = "/robots.txt"
72
+
73
+ [headers.values]
74
+ Content-Type = "text/plain; charset=utf-8"
75
+ Cache-Control = "public, max-age=0, must-revalidate"
76
+ `,"generateNetlifyToml"),D=m(async(e,t,r,n)=>{if(await Te(e,t))return;const i=r();if(!i){n&&console.warn(n);return}await(0,c.mkdir)(o.default.dirname(t),{recursive:!0}),await(0,c.writeFile)(t,i)},"writeGeneratedFile"),Ae=m(async({docsDir:e,docsSiteDir:t,pages:r,siteUrl:n,publicDir:i,generatedFiles:u})=>{u.sitemap&&await D(o.default.resolve(e,"sitemap.xml"),o.default.resolve(t,"sitemap.xml"),()=>Ce(r,n),"Skipping generated sitemap.xml because buildDocs({ siteUrl }) is not set."),u.robots&&await D(o.default.resolve(e,"robots.txt"),o.default.resolve(t,"robots.txt"),()=>Fe(n)),u.llms&&await D(o.default.resolve(e,"llms.txt"),o.default.resolve(t,"llms.txt"),()=>Ge(r)),u.llmsFull&&await D(o.default.resolve(e,"llms-full.txt"),o.default.resolve(t,"llms-full.txt"),()=>Ee(r,n)),u.netlify&&(await D(o.default.resolve(e,"_redirects"),o.default.resolve(t,"_redirects"),()=>Le(r,u)),await D(o.default.resolve(e,"netlify.toml"),o.default.resolve(t,"netlify.toml"),()=>Oe(i&&o.default.basename(i))))},"writeGeneratedDocsFiles"),Z=m((e={},t,r)=>{const n=new ee.Marked((0,re.markedHighlight)({langPrefix:"hljs language-",highlight(i,u){const P=W.default.getLanguage(u)?u:"plaintext";return W.default.highlight(i,{language:P}).value}}));return n.use({renderer:ae.default}),n.use((0,ne.createMarkdownLayoutExtension)({marked:n,handlers:e.markdownLayouts,renderMarkdown:r})),e.markedOptions&&n.use(e.markedOptions),t&&n.use(t),n},"createBaseMarked"),Re=m((e={},t)=>{const r=Z(e,t),n=m(u=>r.parse(u),"renderMarkdown"),i=Z(e,t,n);return i.use({hooks:{postprocess(u){const{layout:P="default",...y}=R.attributes,k=De(e.scripts,u);u=se.default.sanitize(u);const j=[...u.matchAll(/<h([0-6])\sid="[^"]+".*?>.*?<a\s+href="([^"]+)".*?>([^<]+)<\/a>/gm)].map(S=>({path:S[2],label:S[3],level:S[1]}));return A.get(P)?.({...y,content:u,siteMap:R.siteMap,tableOfContent:j,projectMeta:K,renderMarkdown:n,scripts:k,themeStylesheet:e.theme?"/stylesheets/theme.css":void 0})||u}}}),i},"createMarked"),v=m(async e=>{const t=await(0,c.readdir)(e),r=[];for(const n of t){const i=o.default.extname(n);/^[._]/.test(n)||(i?r.push(o.default.join(e,n)):/(stylesheets|assets|scripts)/.test(n)||r.push(...await v(o.default.join(e,n))))}return r},"traverseDirectory"),We=m(async({srcDir:e,publicDir:t,markedOptions:r,template:n,siteUrl:i,generatedFiles:u}={})=>{try{const s=o.default.resolve(process.cwd(),"package.json");p.default.existsSync(s)&&(K=JSON.parse(await(0,c.readFile)(s,"utf-8")))}catch(s){console.warn("Failed to load project package.json metadata",s)}const P=m(()=>{try{return __dirname}catch{return o.default.dirname((0,$.fileURLToPath)(Be.url))}},"getDirname"),y=n?o.default.resolve(P(),"templates",n):null,k=y?o.default.resolve(y,"assets"):null,j=y?o.default.resolve(y,"stylesheets"):null,S=y?o.default.resolve(y,"layouts"):null;let T={};if(y)try{let s=o.default.resolve(y,"template.config.js");if(p.default.existsSync(s)||(s=s.replace(/\.js$/,".ts")),p.default.existsSync(s)){const a=await import((0,$.pathToFileURL)(s).href);T=a.default||a}}catch(s){console.error(`Failed to load template config for ${n}`,s)}const d=e??o.default.resolve(process.cwd(),"docs"),f=t??o.default.resolve(process.cwd(),"website"),ce=Me(u),x=o.default.resolve(d,"_template"),_=o.default.resolve(x,"assets"),B=o.default.resolve(x,"stylesheets"),N=o.default.resolve(x,"scripts"),U=o.default.resolve(x,"layouts"),z=o.default.resolve(d,"_layouts"),F=o.default.resolve(d,"assets"),q=o.default.resolve(d,"stylesheets"),E=o.default.resolve(d,"scripts");try{let s=o.default.resolve(x,"template.config.js");if(p.default.existsSync(s)||(s=s.replace(/\.js$/,".ts")),p.default.existsSync(s)){const a=await import((0,$.pathToFileURL)(s).href),l=a.default||a;T=Se(T,l)}}catch(s){console.error("Failed to load docs _template config",s)}const me=Re(T,r);if(await(0,c.mkdir)(f,{recursive:!0}),k&&p.default.existsSync(k))try{await(0,c.cp)(k,F.replace(d,f),{recursive:!0})}catch(s){console.warn(s)}if(p.default.existsSync(F))try{await(0,c.cp)(F,F.replace(d,f),{recursive:!0})}catch(s){console.warn(s)}if(p.default.existsSync(_))try{await(0,c.cp)(_,o.default.resolve(f,"assets"),{recursive:!0})}catch(s){console.warn(s)}try{const s=new Set;if(j&&p.default.existsSync(j)&&(await v(j)).forEach(l=>s.add(l)),p.default.existsSync(q)&&(await v(q)).forEach(l=>s.add(l)),p.default.existsSync(B)&&(await v(B)).forEach(l=>s.add(l)),s.size){await(0,c.mkdir)(o.default.join(f,"stylesheets"),{recursive:!0});for(const l of s){const h=await(0,c.readFile)(l,"utf-8"),g=V.minify(h);g.errors.length&&g.errors.forEach(console.error);const M=l.startsWith(x)?l.replace(x,f):l.startsWith(d)?l.replace(d,f):o.default.join(f,"stylesheets",o.default.basename(l));await(0,c.writeFile)(M,g.styles??h)}}const a=$e(T.theme);if(a){const l=V.minify(a);l.errors.length&&l.errors.forEach(console.error),await(0,c.mkdir)(o.default.join(f,"stylesheets"),{recursive:!0}),await(0,c.writeFile)(o.default.join(f,"stylesheets","theme.css"),l.styles??a)}}catch(s){console.error(s)}if(p.default.existsSync(E))try{const s=await v(E);s.length&&await(0,c.mkdir)(E.replace(d,f),{recursive:!0});for(const a of s)try{const l=await(0,c.readFile)(a,"utf-8");await(0,c.writeFile)(a.replace(d,f),X.minify(l))}catch(l){console.error(l)}}catch(s){console.warn(s)}if(p.default.existsSync(N))try{const s=await v(N);s.length&&await(0,c.mkdir)(o.default.join(f,"scripts"),{recursive:!0});for(const a of s)try{const l=await(0,c.readFile)(a,"utf-8");await(0,c.writeFile)(a.replace(x,f),X.minify(l))}catch(l){console.error(l)}}catch(s){console.warn(s)}try{const s=new Map;S&&p.default.existsSync(S)&&(await v(S)).forEach(a=>{/\.(j|t)s$/.test(a)&&s.set(o.default.basename(a).replace(/\.(j|t)s$/,""),a)}),p.default.existsSync(z)&&(await v(z)).forEach(a=>{/\.(j|t)s$/.test(a)&&s.set(o.default.basename(a).replace(/\.(j|t)s$/,""),a)}),p.default.existsSync(U)&&(await v(U)).forEach(a=>{/\.(j|t)s$/.test(a)&&s.set(o.default.basename(a).replace(/\.(j|t)s$/,""),a)});for(const[a,l]of s.entries()){const h=await import((0,$.pathToFileURL)(l).href);A.set(a,h.default)}}catch(s){console.error("Template import failed",s)}const ue=await v(d),H=new Map,I=(await Promise.all(ue.filter(s=>s.endsWith(".md")).map(async s=>{const a=await(0,c.readFile)(s,"utf-8");return{filePath:s,...(0,te.default)(a)}}))).sort((s,a)=>(s.attributes.order??0)-(a.attributes.order??0)).map(({attributes:s,body:a,filePath:l})=>{const h=l.replace(d,"").replace(/\.md/,".html"),g=l.replace(d,f).replace(".md",".html"),M=g.replace(o.default.basename(g),""),L=o.default.basename(h)||"/",pe=h.replace(L,"").replace(/\/$/,"");let b=H;pe.split("/").filter(Boolean).forEach(O=>{b.has(O)||b.set(O,new Map),b=b.get(O)});const J={...s,path:h};return b.has(L)||b.set(L,J),{attributes:J,fileWebsitePath:g,fileDirWebsitePath:M,body:a,sourcePath:o.default.relative(d,l),siteMap:H}});for(const{attributes:s,body:a,fileDirWebsitePath:l,fileWebsitePath:h,siteMap:g}of I){R={attributes:s,siteMap:g};const M=await me.parse(a);await(0,c.mkdir)(l,{recursive:!0}),await(0,c.writeFile)(h,le.default.minify(M,{includeAutoGeneratedTags:!0,removeAttributeQuotes:!0,removeComments:!0,removeRedundantAttributes:!0,removeScriptTypeAttributes:!0,removeStyleLinkTypeAttributes:!0,sortClassName:!0,useShortDoctype:!0,collapseWhitespace:!0,minifyJS:!0,minifyCSS:!0}))}await Ae({docsDir:d,docsSiteDir:f,pages:I.map(({attributes:s,body:a,sourcePath:l})=>{const h=je(String(s.path)),g=ke(a);return{sourcePath:l,urlPath:h,title:String(s.title||s.name||"").trim()||"Documentation",name:String(s.name||s.title||"").trim()||"Documentation",description:String(s.description||"").trim()||g.slice(0,156)||"Documentation page.",order:Number(s.order??999),summary:g.slice(0,320)}}),siteUrl:i,publicDir:f,generatedFiles:ce})},"buildDocs");0&&(module.exports={buildDocs});
@@ -44,6 +44,59 @@ export const highlightLine = (line) => {
44
44
  return tokens.join('')
45
45
  }
46
46
 
47
+ export const renderCodeCopyScript = () => `
48
+ <script type="application/javascript">
49
+ (() => {
50
+ if (window.__fadingCitrusCodeCopyReady) return
51
+ window.__fadingCitrusCodeCopyReady = true
52
+
53
+ const showCopyButton = (snippet) => {
54
+ const copyBtn = snippet.querySelector('.code-copy-btn')
55
+ const hasCode = snippet.dataset.code || snippet.querySelector('code') || snippet.querySelector('.content')
56
+ if (copyBtn && hasCode) copyBtn.style.visibility = 'visible'
57
+ }
58
+
59
+ document.querySelectorAll('.code-snippet').forEach(showCopyButton)
60
+
61
+ document.addEventListener('click', (event) => {
62
+ const copyBtn = event.target.closest('.code-copy-btn')
63
+ if (!copyBtn) return
64
+
65
+ const snippet = copyBtn.closest('.code-snippet')
66
+ if (!snippet) return
67
+
68
+ let code = snippet.dataset.code ?? ''
69
+
70
+ if (!code) {
71
+ const codeEl = snippet.querySelector('code')
72
+ if (codeEl) {
73
+ const clone = codeEl.cloneNode(true)
74
+ clone.querySelectorAll('.line-number').forEach((el) => el.remove())
75
+ code = clone.textContent ?? ''
76
+ }
77
+ }
78
+
79
+ if (!code) {
80
+ code = snippet.querySelector('.content')?.textContent ?? ''
81
+ }
82
+
83
+ if (!code.trim().length) return
84
+
85
+ clearTimeout(copyBtn._timer)
86
+ navigator.clipboard.writeText(code.trim())
87
+ copyBtn.textContent = 'copied'
88
+ copyBtn.setAttribute('aria-label', 'Code copied')
89
+ copyBtn.classList.add('copied')
90
+ copyBtn._timer = setTimeout(() => {
91
+ copyBtn.textContent = 'copy'
92
+ copyBtn.setAttribute('aria-label', 'Copy code')
93
+ copyBtn.classList.remove('copied')
94
+ }, 1000)
95
+ })
96
+ })()
97
+ </script>
98
+ `
99
+
47
100
  export const renderCodeBlock = (filename, code, lang = 'javascript') => {
48
101
  const lines = code
49
102
  .replace(/\n$/, '')
@@ -0,0 +1,89 @@
1
+ export const escapeHTML = (value = '') =>
2
+ String(value)
3
+ .replace(/&/g, '&amp;')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&#39;')
8
+
9
+ export const partByName = (parts, name) =>
10
+ parts.find((part) => part.name === name)
11
+
12
+ export const option = (value, fallback = '') =>
13
+ value === undefined || value === true ? fallback : String(value)
14
+
15
+ export const optionText = (value, fallback = '') =>
16
+ option(value, fallback).replace(/&quot;/g, '"')
17
+
18
+ export const codeFromPart = (part = {}) => {
19
+ const match = String(part.body || '').match(
20
+ /(?:```|~~~)([^\n]*)\n([\s\S]*?)\n(?:```|~~~)/
21
+ )
22
+
23
+ if (!match) return ''
24
+
25
+ return match[2]
26
+ }
27
+
28
+ export const withFirstParagraphClass = (html = '', className = '') =>
29
+ html.replace(/<p>/, `<p class="${className}">`)
30
+
31
+ export const statContent = (html = '') => {
32
+ const value = html.match(/<h2[^>]*>([\s\S]*?)<\/h2>/)?.[1] || ''
33
+ const label = html.match(/<p[^>]*>([\s\S]*?)<\/p>/)?.[1] || ''
34
+
35
+ return `
36
+ <span class="stat-value text-gradient-primary">${value}</span>
37
+ <span class="stat-label">${label}</span>
38
+ `
39
+ }
40
+
41
+ export const stripHeadingLinks = (html = '') =>
42
+ html.replace(
43
+ /<h([1-6])([^>]*)><a href="[^"]*">([\s\S]*?)<\/a><\/h\1>/g,
44
+ '<h$1$2>$3</h$1>'
45
+ )
46
+
47
+ export const sectionHeader = (html = '') =>
48
+ stripHeadingLinks(html).replace(
49
+ /<p><code>([\s\S]*?)<\/code><\/p>/,
50
+ '<span class="section-tag font-mono">$1</span>'
51
+ )
52
+
53
+ export const groupedSectionHeader = (html = '') => {
54
+ const normalized = sectionHeader(html)
55
+ const match = normalized.match(
56
+ /^(\s*<span class="section-tag font-mono">[\s\S]*?<\/span>)(\s*<h2[^>]*>[\s\S]*?<\/h2>)([\s\S]*)$/
57
+ )
58
+
59
+ if (!match) return normalized
60
+
61
+ return `<div>${match[1]}${match[2]}</div>${match[3]}`
62
+ }
63
+
64
+ export const icon = (name) => {
65
+ const icons = {
66
+ arrowRight:
67
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>',
68
+ arrowUpRight:
69
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7"/><path d="M7 7h10v10"/></svg>',
70
+ book: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>',
71
+ terminal:
72
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>',
73
+ sparkles:
74
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sparkles-icon"><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275Z"/><path d="m5 3 1 2.5L8.5 6 6 7 5 9.5 4 7 1.5 6 4 5Z"/><path d="m19 17 1 2.5 2.5.5-2.5 1-1 2.5-1-2.5-2.5-1 2.5-1Z"/></svg>',
75
+ webComponents:
76
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5.5 8.5 9 12l-3.5 3.5L2 12l3.5-3.5Z"/><path d="m12 2 3.5 3.5L12 9 8.5 5.5 12 2Z"/><path d="M18.5 8.5 22 12l-3.5 3.5L15 12l3.5-3.5Z"/><path d="m12 15 3.5 3.5-3.5 3.5-3.5-3.5 3.5-3.5Z"/></svg>',
77
+ router: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="19" r="3"/><circle cx="18" cy="5" r="3"/><path d="M9 19h8.5a3.5 3.5 0 0 0 3.5-3.5V8.5a3.5 3.5 0 0 0-3.5-3.5H9"/></svg>',
78
+ reactive:
79
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>',
80
+ tiny: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"/><line x1="16" y1="8" x2="2" y2="22"/><line x1="17.5" y1="15" x2="9" y2="15"/></svg>',
81
+ standards:
82
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8.3 10a3.5 3.5 0 0 1 0-7h7.4a3.5 3.5 0 0 1 0 7H8.3Z"/><path d="M12 14a3 3 0 0 1 3-3h3.5a3 3 0 0 1 3 3v3.5a3 3 0 0 1-3 3H15a3 3 0 0 1-3-3V14Z"/><path d="M2 14.5a3.5 3.5 0 0 1 7 0v2.8a3.5 3.5 0 0 1-7 0v-2.8Z"/></svg>',
83
+ plug: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22v-5"/><path d="M9 8V2"/><path d="M15 8V2"/><path d="M18 8H6v5a4 4 0 0 0 4 4h4a4 4 0 0 0 4-4Z"/></svg>',
84
+ surgical:
85
+ '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m12 14 4-4"/><path d="M3.34 19a10 10 0 1 1 17.32 0"/></svg>',
86
+ }
87
+
88
+ return icons[name] || icons.reactive
89
+ }
@@ -1,7 +1,6 @@
1
1
  import meta from './_head-meta.js'
2
2
  import header from './_header.js'
3
3
  import footer from './_footer.js'
4
- import copyCode from './_copy-code.js'
5
4
 
6
5
  const githubDocsPath =
7
6
  'https://github.com/beforesemicolon/markup/tree/main/docs'
@@ -47,6 +46,11 @@ export default (props) => {
47
46
  <head>
48
47
  ${meta(props)}
49
48
  <link rel="stylesheet" href="/stylesheets/documentation.css?v=20260621exact">
49
+ ${
50
+ props.themeStylesheet
51
+ ? `<link rel="stylesheet" href="${props.themeStylesheet}">`
52
+ : ''
53
+ }
50
54
  </head>
51
55
  <body>
52
56
  ${header(props)}
@@ -83,8 +87,7 @@ export default (props) => {
83
87
  </main>
84
88
 
85
89
  ${footer()}
86
-
87
- ${copyCode()}
90
+ ${props.scripts?.join('') || ''}
88
91
 
89
92
  </body>
90
93
  </html>
@@ -0,0 +1,30 @@
1
+ import { icon, partByName } from './_layout-utils.js'
2
+
3
+ export default ({ parts, options }) => {
4
+ const copy = partByName(parts, 'copy') || parts[0]
5
+ const title = options.title || ''
6
+ const title2 = options.title2 || ''
7
+
8
+ return `
9
+ <section class="cta-section wrapper">
10
+ <div class="cta-card">
11
+ <div class="cta-glow"></div>
12
+ <h2>
13
+ <span class="text-gradient">${title}</span>
14
+ <span class="text-gradient-primary">${title2}</span>
15
+ </h2>
16
+ ${copy?.html || ''}
17
+ <div class="cta-buttons">
18
+ <a href="/documentation/get-started" class="btn-primary">
19
+ <span>Get Started</span>
20
+ ${icon('arrowRight')}
21
+ </a>
22
+ <a href="/documentation/index.html?v=20260621exact" class="btn-outline">
23
+ ${icon('book')}
24
+ <span>Read the Docs</span>
25
+ </a>
26
+ </div>
27
+ </div>
28
+ </section>
29
+ `
30
+ }
@@ -0,0 +1,43 @@
1
+ import {
2
+ groupedSectionHeader,
3
+ icon,
4
+ option,
5
+ partByName,
6
+ } from './_layout-utils.js'
7
+
8
+ export default ({ parts }) => {
9
+ const header = partByName(parts, 'header') || parts[0]
10
+ const cards = parts.filter((part) => part.name === 'product')
11
+
12
+ return `
13
+ <section class="products-section wrapper">
14
+ <div class="section-header">${groupedSectionHeader(header?.html || '')}</div>
15
+ <div class="products-grid">
16
+ ${cards
17
+ .map(
18
+ (card) => `
19
+ <div class="product-card card-${option(card.options.color, 'orange')}">
20
+ <div class="product-glow"></div>
21
+ <a href="${option(card.options.href, '#')}" target="_blank" rel="noreferrer" class="product-head">
22
+ <div class="product-title-row">
23
+ <div class="icon-container">${icon(option(card.options.icon, 'webComponents'))}</div>
24
+ <div>
25
+ <h3>${option(card.options.title, card.name || '')}</h3>
26
+ <span class="package-name font-mono">${option(card.options.package, '')}</span>
27
+ </div>
28
+ </div>
29
+ <span class="product-arrow">${icon('arrowUpRight')}</span>
30
+ </a>
31
+ ${card.html}
32
+ <a href="${option(card.options.href, '#')}" target="_blank" rel="noreferrer" class="product-link">
33
+ <span>Read the docs</span>
34
+ ${icon('arrowUpRight')}
35
+ </a>
36
+ </div>
37
+ `
38
+ )
39
+ .join('')}
40
+ </div>
41
+ </section>
42
+ `
43
+ }
@@ -0,0 +1,25 @@
1
+ import { icon, option, partByName, sectionHeader } from './_layout-utils.js'
2
+
3
+ export default ({ parts }) => {
4
+ const header = partByName(parts, 'header') || parts[0]
5
+ const features = parts.filter((part) => part.name === 'feature')
6
+
7
+ return `
8
+ <section id="features" class="features-section wrapper">
9
+ <div class="section-header">${sectionHeader(header?.html || '')}</div>
10
+ <div class="features-grid">
11
+ ${features
12
+ .map(
13
+ (feature) => `
14
+ <div class="feature-card">
15
+ <div class="feature-border"></div>
16
+ <div class="icon-box">${icon(option(feature.options.icon, 'reactive'))}</div>
17
+ ${feature.html}
18
+ </div>
19
+ `
20
+ )
21
+ .join('')}
22
+ </div>
23
+ </section>
24
+ `
25
+ }
@@ -0,0 +1,81 @@
1
+ import { renderCodeBlock } from './_code-snippet.js'
2
+ import {
3
+ codeFromPart,
4
+ icon,
5
+ option,
6
+ partByName,
7
+ statContent,
8
+ withFirstParagraphClass,
9
+ } from './_layout-utils.js'
10
+
11
+ export default ({ parts, options }) => {
12
+ const copy = partByName(parts, 'copy') || parts[0]
13
+ const code = partByName(parts, 'code') || parts[1]
14
+ const stats = parts.filter((part) => part.name === 'stat')
15
+ const version = option(options.version)
16
+ const title = option(options.title, '')
17
+ const title2 = option(options.title2, '')
18
+ const primaryHref = option(
19
+ options.primaryHref,
20
+ '/documentation/get-started'
21
+ )
22
+ const primaryLabel = option(options.primaryLabel, 'Get Started')
23
+ const secondaryLabel = option(
24
+ options.secondaryLabel,
25
+ 'npm i @beforesemicolon/markup'
26
+ )
27
+
28
+ return `
29
+ <section class="hero-section relative overflow-hidden">
30
+ <div class="absolute inset-0 bg-grid pointer-events-none"></div>
31
+ <div class="absolute inset-0 hero-glow pointer-events-none animate-pulse-glow"></div>
32
+ <div class="wrapper hero-container animate-float-up">
33
+ <div class="hero-content">
34
+ ${
35
+ version
36
+ ? `<a href="https://github.com/beforesemicolon/markup" target="_blank" rel="noopener" class="version-badge">
37
+ ${icon('sparkles')}
38
+ <span>${version}</span>
39
+ ${icon('arrowRight')}
40
+ </a>`
41
+ : ''
42
+ }
43
+ <h1 class="hero-title">
44
+ <span class="text-gradient">${title}</span><br/>
45
+ <span class="text-gradient-primary">${title2}</span>
46
+ </h1>
47
+ ${withFirstParagraphClass(copy?.html || '', 'hero-subtitle')}
48
+ <div class="hero-actions">
49
+ <a href="${primaryHref}" class="btn-primary">
50
+ <span>${primaryLabel}</span>
51
+ ${icon('arrowRight')}
52
+ </a>
53
+ <a href="#install" class="btn-secondary font-mono">${secondaryLabel}</a>
54
+ </div>
55
+ ${
56
+ stats.length
57
+ ? `<div class="hero-stats">${stats
58
+ .map(
59
+ (stat, index) => `
60
+ ${index ? '<div class="stat-divider"></div>' : ''}
61
+ <div class="stat-item">${statContent(stat.html)}</div>
62
+ `
63
+ )
64
+ .join('')}</div>`
65
+ : ''
66
+ }
67
+ </div>
68
+ ${
69
+ code
70
+ ? `<div class="hero-code-panel">
71
+ <div class="glow-container">
72
+ <div class="absolute inset-0 bg-gradient-to-br from-primary/20 to-accent/20 blur-3xl rounded-full"></div>
73
+ </div>
74
+ ${renderCodeBlock(option(code.options.filename, ''), codeFromPart(code), option(code.options.lang, 'javascript'))}
75
+ </div>`
76
+ : ''
77
+ }
78
+ </div>
79
+ </section>
80
+ `
81
+ }