Compare commits

..

No commits in common. "restructure" and "master" have entirely different histories.

11 changed files with 109 additions and 143 deletions

View File

@ -1,3 +0,0 @@
{
"liveServer.settings.port": 5501
}

132
app.js
View File

@ -1,113 +1,45 @@
const {DOM, Tag, H, App} = Gale({ const {DOM, Tag, H} = Gale({
Form:{ Button: {
padding: "20px" padding: "20px",
}, background: "orange",
Input:{ ".Inner": {
display:"inlnine-block", fontSize: "10rem"
padding:"0.5rem 1rem",
borderRadius:"0.5rem",
outline:"1px solid #ddd",
":focus":{
outline: "2px solid green"
} }
}, },
Button:{ Outline: {
display:"inline-block", border: "2px solid orange"
padding:"1rem",
background:"green",
color:"white",
borderRadius:"0.5rem",
cursor:"pointer",
textTransform:"uppercase",
fontWeight:"bolder",
":hover":{background:"black"}
}, },
Complete:{ Window:{
fontSize:"0.6rem", height: "100vh",
padding:"0.5rem", border: "2px solid black",
background:"limegreen" display: "flex",
flexDirection: "row",
alignItems: "end",
justifyContent: "center",
gap: "10px"
}, },
Incomplete:{ Ability:{
fontSize:"0.6rem", width: "50px",
padding:"0.5rem", height: "50px",
background:"yellow", background: "red",
color:"black", transition: "all 0.4s",
":hover":{ ":hover":{
color:"white" transform:"scale(1.1)"
} }
}, },
Delete:{ Orange:{
fontSize:"0.6rem", background:"orange"
padding:"0.5rem",
background:"tomato"
},
Title:{
fontSize: "2rem"
},
List:{
padding:"1rem",
background:"#ddd"
},
Item:{
display:"flex",
gap:"1rem",
alignItems:"center"
},
Done:{
textDecoration:"line-through"
} }
}); }, "abilities");
/** @typedef {{name:string, done:boolean}} Todo */ const UI =()=>
/** @type {{pending:string, list:Todo[]}} */
const InitialState = {pending:"todo name", list:[]};
const Store = vanX.Store(InitialState, "todos_v1");
const PendingCreate=()=>{
const newTodo = /** @type {Todo} */({name:Store.pending, done:false});
Store.list.unshift(newTodo);
Store.pending = "";
console.log(Store);
}
const PendingChange =(/** @type {InputEvent}*/e)=>{
console.log(e);
Store.pending = /** @type {HTMLInputElement}*/(e.target).value;
}
function Form()
{ {
const input = DOM.input.Input({value:Store.pending, oninput:PendingChange}) return H.Window(
return DOM.form.Form( H.Ability({class:Tag("Ability", "Orange")}),
{onsubmit(e){e.preventDefault(); PendingCreate();}}, H.Ability(),
()=> H.Ability(),
{ H.Ability.Orange(),
input.value = Store.pending;
input.setAttribute("data-value", Store.pending);
return input;
},
()=>DOM.button.Button({disabled:Store.pending == ""}, "Create")
) )
} }
function List() van.add(document.body, UI());
{
return ()=>Store.list.length && vanX.list(DOM.ul.List, Store.list, (v, d)=>DOM.li.Item(
v.val.done ? DOM.button.Button.Complete({onclick(){v.val.done = false}}, "Complete") : DOM.button.Button.Incomplete({onclick(){v.val.done = true}}, "Incomplete"),
DOM.span({class: v.val.done ? Tag("Done") : ""}, v.val.name),
DOM.button.Button.Delete({onclick:d}, "Delete")
));
}
App("body",
H.Form
(
H.Title("todos"),
Form(),
List(),
()=>H.Item(Store.pending)
)
);

1
dist/core.d.ts vendored
View File

@ -87,7 +87,6 @@ declare global
type CreateSheet = <T extends UserSheet>(sheet:UserSheet&T, hash?:string)=>{ type CreateSheet = <T extends UserSheet>(sheet:UserSheet&T, hash?:string)=>{
Tag:(...args:CrossMultiplyRecord<T>[])=>string, Tag:(...args:CrossMultiplyRecord<T>[])=>string,
CSS:string, CSS:string,
App:(selector:string, ...elements:Van.ChildDom[])=>ShadowRoot,
DOM:Elemental<CrossMultiplyRecord<T>>, DOM:Elemental<CrossMultiplyRecord<T>>,
H:Circular<CrossMultiplyRecord<T>, Van.TagFunc<HTMLDivElement>> H:Circular<CrossMultiplyRecord<T>, Van.TagFunc<HTMLDivElement>>
} }

18
dist/core.js vendored
View File

@ -8,21 +8,7 @@
vanX.Store=(e,t)=>{const a=localStorage.getItem(t),r=vanX.reactive(a?JSON.parse(a):e);return van.derive((()=>localStorage.setItem(t,JSON.stringify(vanX.compact(r))))),r}; vanX.Store=(e,t)=>{const a=localStorage.getItem(t),r=vanX.reactive(a?JSON.parse(a):e);return van.derive((()=>localStorage.setItem(t,JSON.stringify(vanX.compact(r))))),r};
//gale //gale
globalThis.Gale=(e,t="")=>{const n=(e,t,o)=>`${e}{${Object.keys(t).map((e=>{const a=t[e];switch(e[0]){case"@":return n(`@media(max-width:${e.substring(1)})`,a,o);case":":return n(`&${e}`,a,o);case".":return n(`${e}${o}`,a,o);case"^":return n(`&:hover .${e.substring(1)}${o}`,a,o)}return`${e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}: ${a};`})).join("\n")}}`,o=(e,t)=>{const n=t.lastIndexOf(e)+e.length;return n?t.substring(n):t},a=e=>{const t=van.tags[e];let n=[];const o=new Proxy(((...e)=>{const o=t(...e);return o.className=n.join(i+" ")+i+" "+o.className,n=[],o}),{get:(e,t)=>(n.push(t.substring(t.lastIndexOf(".")+1)),o)});return o},i=t?"_"+t:"",r=Object.keys(e).map((t=>n("."+t+i,e[t],i))).join("\n"),s=document.createElement("style");return s.setAttribute("data-sheet",i),s.textContent=r+"*{margin:0;padding:0;box-sizing:border-box;}html, :host{height:100%;width:100%;font-family:Arial, sans-serif;line-height:1.6;}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}img, video{max-width:100%;height:auto;}a{text-decoration:none;color:inherit;}ul, ol{list-style:none;}button, input, textarea{font-family:inherit;font-size:inherit;line-height:inherit;border:none;background:none;padding:0;margin:0;outline:none;}table{border-collapse:collapse;width:100%;}",globalThis.document?.head.appendChild(s),{Tag:(...e)=>e.map((e=>o("^",o(".",e)))).join(i+" ")+i,CSS:r,App(e,...t){const n=document.querySelector(e).attachShadow({mode:"open"});return n.appendChild(s),van.add(n,...t),n},DOM:new Proxy({},{get:(e,t)=>a(t)}),H:new Proxy({},{get:(e,t)=>a("div")[t]})}}; globalThis.Gale=(e,t="")=>{const n=(e,t,s)=>`${e}{${Object.keys(t).map((e=>{const r=t[e];switch(e[0]){case"@":return n(`@media(max-width:${e.substring(1)})`,r,s);case":":return n(`&${e}`,r,s);case".":return n(`${e}${s}`,r,s);case"^":return n(`&:hover .${e.substring(1)}${s}`,r,s)}return`${e.replace(/([a-z])([A-Z])/g,"$1-$2")}: ${r};`})).join("\n")}}`,s=(e,t)=>{const n=t.lastIndexOf(e)+e.length;return n?t.substring(n):t},r=e=>{const t=van.tags[e];let n=[];const s=new Proxy(((...e)=>{const s=t(...e);return s.className=n.join(a+" ")+a+" "+s.className,n=[],s}),{get:(e,t)=>(n.push(t.substring(t.lastIndexOf(".")+1)),s)});return s},a=t?"_"+t:"",c=Object.keys(e).map((t=>n("."+t+a,e[t],a))).join("\n");return globalThis.document?.head.insertAdjacentHTML("beforeend",`<style data-sheet="${a}">${c}</style>`),{Tag:(...e)=>e.map((e=>s("^",s(".",e)))).join(a+" ")+a,CSS:c,DOM:new Proxy({},{get:(e,t)=>r(t)}),H:new Proxy({},{get:(e,t)=>r("div")[t]})}};
//boot //boot
const configFile = import.meta.url.split("?")[1] || window.location+"deno.json"; ((t="/")=>{fetch(t+"deno.json").then((t=>t.json())).then((e=>{const n=(t,e)=>{let n=document.createElement("script");n.type=t,n.textContent=e,document.head.appendChild(n)},o=e.imports;for(let e in o){const n=o[e];n.startsWith("./")&&(o[e]=t+n.substring(2))}n("importmap",JSON.stringify({imports:o})),n("module",'import "entry"; ')}))})();
const configFolder = configFile.substring(0, configFile.lastIndexOf("/")+1);
fetch(configFile)
.then(text=>text.json())
.then(json=>{
const n=(t,e)=>{let n=document.createElement("script");n.type=t,n.textContent=e,document.head.appendChild(n)};
const imports = json.imports;
for(let n in imports)
{
const path=imports[n];
path.startsWith("./")&&(imports[n]=configFolder+path.substring(2))
}
n("importmap",JSON.stringify({imports}));
n("module",'import "entry"; ');
})

1
dist/index.html vendored
View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- css reset --><style>*{margin:0;padding:0;box-sizing:border-box;}html, body{height:100%;width:100%;font-family:Arial, sans-serif;line-height:1.6;}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}img, video{max-width:100%;height:auto;}a{text-decoration:none;color:inherit;}ul, ol{list-style:none;}button, input, textarea{font-family:inherit;font-size:inherit;line-height:inherit;border:none;background:none;padding:0;margin:0;outline:none;}table{border-collapse:collapse;width:100%;}</style>
</head> </head>
<body></body> <body></body>
</html> </html>

View File

@ -3,7 +3,8 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./dist/core.js?/deno.json" type="module"></script> <!-- css reset --><style>*{margin:0;padding:0;box-sizing:border-box;}html, body{height:100%;width:100%;font-family:Arial, sans-serif;line-height:1.6;}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}img, video{max-width:100%;height:auto;}a{text-decoration:none;color:inherit;}ul, ol{list-style:none;}button, input, textarea{font-family:inherit;font-size:inherit;line-height:inherit;border:none;background:none;padding:0;margin:0;outline:none;}table{border-collapse:collapse;width:100%;}</style>
<script src="./dist/core.js"></script>
<script src="./src/gale.js"></script> <script src="./src/gale.js"></script>
</head> </head>
<body></body> <body></body>

View File

@ -1,5 +1,6 @@
const bundle = await fetch(import.meta.resolve("../dist/core.js")).then(r=>r.text());
const index = await fetch(import.meta.resolve("../dist/index.html")).then(r=>r.text());
export const HTML = index.replace(`</head>`, `<script>${bundle}</script></head>`);
export const Root = import.meta.resolve("../"); export const Root = import.meta.resolve("../");
const index = await fetch(Root + "dist/index.html").then(r=>r.text());
export const HTML = index.replace(`</head>`, `<script type="module" src="${Root + "dist/core.js?/deno.json"}"></script></head>`);
export const Load =async(file:string)=> await fetch(Root + file).then(resp=>resp.text()); export const Load =async(file:string)=> await fetch(Root + file).then(resp=>resp.text());
export const Save =async(text:string, name:string)=> await Deno.writeTextFile(name, text); export const Save =async(text:string, name:string)=> await Deno.writeTextFile(name, text);

View File

@ -12,7 +12,7 @@ try {
} catch (_) { } catch (_) {
html = HTML; html = HTML;
} }
html = html.replace("</head>", `<script type="module">${devinc}</script></head>`); html = html.replace("</head>", `<script>${devinc}</script></head>`);
function extension(path: string): string { function extension(path: string): string {
// Remove trailing slash if it exists // Remove trailing slash if it exists

43
shadow.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shadow DOM Example</title>
</head>
<body>
<script>
// Define the custom web component
class APP extends HTMLElement {
constructor() {
super();
// Attach a shadow root to the custom element
const shadowRoot = this.attachShadow({ mode: 'open' });
// Add custom markup and styles to the shadow root
shadowRoot.innerHTML = `
<style>
.shadow-content {
color: white;
background-color: black;
padding: 10px;
border-radius: 5px;
}
</style>
<div class="shadow-content">
This is content inside the shadow root of a web component.
</div>
`;
}
}
// Register the custom element
customElements.define('gale-app', APP);
</script>
<gale-app></gale-app>
</body>
</html>

15
src/boot.js Normal file
View File

@ -0,0 +1,15 @@
(
(root="/")=>fetch(root+"deno.json")
.then(text=>text.json())
.then(json=>{
const n=(t,e)=>{let n=document.createElement("script");n.type=t,n.textContent=e,document.head.appendChild(n)};
const imports = json.imports;
for(let n in imports)
{
const path=imports[n];
path.startsWith("./")&&(imports[n]=root+path.substring(2))
}
n("importmap",JSON.stringify({imports})),
n("module",'import "entry"; ')
})
)();

View File

@ -23,7 +23,7 @@ globalThis.Gale = (sheet, hash="")=>
case KeyGroup : case KeyGroup :
return Tier(`&:hover .${key.substring(KeyGroup.length)}${suffix}`, value, suffix); return Tier(`&:hover .${key.substring(KeyGroup.length)}${suffix}`, value, suffix);
} }
return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() }: ${value};` return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2') }: ${value};`
}); });
return `${selector}{${styles.join("\n")}}`; return `${selector}{${styles.join("\n")}}`;
@ -60,22 +60,13 @@ globalThis.Gale = (sheet, hash="")=>
const id = hash ? "_"+hash : ""; const id = hash ? "_"+hash : "";
const css = Object.keys(sheet).map(key=>Tier("."+key+id, sheet[key], id)).join(`\n`); const css = Object.keys(sheet).map(key=>Tier("."+key+id, sheet[key], id)).join(`\n`);
const style = document.createElement('style'); globalThis.document?.head.insertAdjacentHTML("beforeend", `<style data-sheet="${id}">${css}</style>`);
style.setAttribute("data-sheet", id);
style.textContent = css + `*{margin:0;padding:0;box-sizing:border-box;}html, :host{height:100%;width:100%;font-family:Arial, sans-serif;line-height:1.6;}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}img, video{max-width:100%;height:auto;}a{text-decoration:none;color:inherit;}ul, ol{list-style:none;}button, input, textarea{font-family:inherit;font-size:inherit;line-height:inherit;border:none;background:none;padding:0;margin:0;outline:none;}table{border-collapse:collapse;width:100%;}`;
globalThis.document?.head.appendChild(style);
return { return {
Tag(...args){ Tag(...args){
return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id; return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id;
}, },
CSS: css, CSS: css,
App(selector, ...elements){
const sr = document.querySelector(selector).attachShadow({ mode: 'open' });
sr.appendChild(style);
van.add(sr, ...elements);
return sr;
},
DOM: new Proxy( DOM: new Proxy(
{}, {},
{ {