mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-07-01 12:22:15 +02:00
⚡ irelands
This commit is contained in:
@ -236,12 +236,11 @@ function registerClientPart(page_id){
|
||||
`),
|
||||
);
|
||||
|
||||
// Register our highlighting script to run after Shiki loads
|
||||
const scriptElement = el("script", { type: "module" });
|
||||
|
||||
registerClientFile(
|
||||
new URL("./code.js.js", import.meta.url),
|
||||
scriptElement
|
||||
{
|
||||
head: el("script", { type: "module" }),
|
||||
}
|
||||
);
|
||||
|
||||
is_registered[page_id]= true;
|
||||
|
37
docs/components/examples/ireland-test/counter.js
Normal file
37
docs/components/examples/ireland-test/counter.js
Normal file
@ -0,0 +1,37 @@
|
||||
import { el } from "deka-dom-el";
|
||||
import { S } from "deka-dom-el/signals";
|
||||
|
||||
const className = "client-side-counter";
|
||||
document.body.append(
|
||||
el("style").append(`
|
||||
.${className} {
|
||||
border: 1px dashed #ccc;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
}
|
||||
`.trim())
|
||||
);
|
||||
|
||||
export function CounterStandard() {
|
||||
// Create reactive state with a signal
|
||||
const count = S(0);
|
||||
|
||||
// Create UI components that react to state changes
|
||||
return el("div", { className }).append(
|
||||
el("h4", "Client-Side Counter"),
|
||||
el("div", {
|
||||
// The textContent updates automatically when count changes
|
||||
textContent: S(() => `Count: ${count.get()}`),
|
||||
}),
|
||||
el("div", { className: "controls" }).append(
|
||||
el("button", {
|
||||
onclick: () => count.set(count.get() - 1),
|
||||
textContent: "-",
|
||||
}),
|
||||
el("button", {
|
||||
onclick: () => count.set(count.get() + 1),
|
||||
textContent: "+",
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
88
docs/components/ireland.html.js
Normal file
88
docs/components/ireland.html.js
Normal file
@ -0,0 +1,88 @@
|
||||
import { el, queue } from "deka-dom-el";
|
||||
import { addEventListener, registerClientFile } from "../ssr.js";
|
||||
import { relative } from "node:path";
|
||||
|
||||
const dir= new URL("./", import.meta.url).pathname;
|
||||
const dirFE= "irelands";
|
||||
// Track all component instances for client-side rehydration
|
||||
const componentsRegistry = new Map();
|
||||
/**
|
||||
* Creates a component that shows code and its runtime output
|
||||
* with server-side pre-rendering and client-side rehydration
|
||||
*
|
||||
* @param {object} attrs
|
||||
* @param {URL} attrs.src - Path to the file containing the component
|
||||
* @param {string} [attrs.exportName="default"] - Name of the export to use
|
||||
* @param {string} attrs.page_id - ID of the current page
|
||||
* @param {object} [attrs.props={}] - Props to pass to the component
|
||||
*/
|
||||
export function ireland({ src, exportName = "default", props = {} }) {
|
||||
// relative src against the current directory
|
||||
const path= "./"+relative(dir, src.pathname);
|
||||
const id = "ireland-" + generateComponentId(src);
|
||||
const element = el.mark({ type: "ireland", name: ireland.name });
|
||||
queue(import(path).then(module => {
|
||||
const component = module[exportName];
|
||||
element.replaceWith(el(component, props, mark(id)));
|
||||
}));
|
||||
|
||||
if(!componentsRegistry.size)
|
||||
addEventListener("oneachrender", registerClientPart);
|
||||
componentsRegistry.set(id, {
|
||||
src,
|
||||
path: dirFE+"/"+path.split("/").pop(),
|
||||
exportName,
|
||||
props,
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function registerClientPart(){
|
||||
const todo= Array.from(componentsRegistry.entries())
|
||||
.map(([ id, d ]) => {
|
||||
registerClientFile(d.src, {
|
||||
folder: dirFE,
|
||||
// not all browsers support importmap
|
||||
replacer(file){
|
||||
return file
|
||||
.replaceAll(/ from "deka-dom-el(\/signals)?";/g, ` from "./esm-with-signals.js";`);
|
||||
}
|
||||
});
|
||||
return [ id, d ];
|
||||
});
|
||||
const store = JSON.stringify(JSON.stringify(todo));
|
||||
registerClientFile(new URL("./ireland.js.js", import.meta.url));
|
||||
registerClientFile(new URL("../../dist/esm-with-signals.js", import.meta.url), { folder: dirFE });
|
||||
document.head.append(
|
||||
// not all browsers support importmap
|
||||
el("script", { type: "importmap" }).append(`
|
||||
{
|
||||
"imports": {
|
||||
"deka-dom-el": "./${dirFE}/esm-with-signals.js",
|
||||
"deka-dom-el/signals": "./${dirFE}/esm-with-signals.js"
|
||||
}
|
||||
}
|
||||
`.trim())
|
||||
);
|
||||
document.body.append(
|
||||
el("script", { type: "module" }).append(`
|
||||
import { loadIrelands } from "./ireland.js.js";
|
||||
loadIrelands(new Map(JSON.parse(${store})));
|
||||
`.trim())
|
||||
)
|
||||
}
|
||||
function mark(id) { return el=> el.dataset.ddeMark= id; }
|
||||
const store_prev= new Map();
|
||||
/** @param {URL} src */
|
||||
function generateComponentId(src){
|
||||
const candidate= parseInt(relative((new URL("..", import.meta.url)).pathname, src.pathname)
|
||||
.split("")
|
||||
.map(ch=> ch.charCodeAt(0))
|
||||
.join(""), 10)
|
||||
.toString(36)
|
||||
.replace(/000+/g, "");
|
||||
const count= 1 + ( store_prev.get(candidate) || 0 );
|
||||
store_prev.set(candidate, count);
|
||||
return count.toString()+"-"+candidate;
|
||||
}
|
13
docs/components/ireland.js.js
Normal file
13
docs/components/ireland.js.js
Normal file
@ -0,0 +1,13 @@
|
||||
// not all browsers support importmaps
|
||||
// import { el } from "deka-dom-el";
|
||||
import { el } from "./irelands/esm-with-signals.js";
|
||||
export function loadIrelands(store) {
|
||||
document.body.querySelectorAll("[data-dde-mark]").forEach(ireland => {
|
||||
const { ddeMark }= ireland.dataset;
|
||||
if(!store.has(ddeMark)) return;
|
||||
const { path, exportName, props }= store.get(ddeMark);
|
||||
import("./"+path).then(module => {
|
||||
ireland.replaceWith(el(module[exportName], props));
|
||||
})
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user