deep-proxy #1
							
								
								
									
										12
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @ -1,12 +0,0 @@ | ||||
| { | ||||
|     "configurations": [ | ||||
|         { | ||||
|             "name": "deno launch", | ||||
|             "request": "launch", | ||||
|             "type": "node", | ||||
|             "cwd": "${workspaceFolder}", | ||||
|             "runtimeExecutable": "deno", | ||||
|             "runtimeArgs": ["styler.tsx"], | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										97
									
								
								bundle.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								bundle.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | ||||
| export {} | ||||
| declare global | ||||
| { | ||||
|   namespace Van { | ||||
| 
 | ||||
|     interface State<T> { | ||||
|       val: T | ||||
|       readonly oldVal: T | ||||
|       readonly rawVal: T | ||||
|     } | ||||
|      | ||||
|     // Defining readonly view of State<T> for covariance.
 | ||||
|     // Basically we want StateView<string> to implement StateView<string | number>
 | ||||
|     type StateView<T> = Readonly<State<T>> | ||||
|      | ||||
|     type Val<T> = State<T> | T | ||||
|      | ||||
|     type Primitive = string | number | boolean | bigint | ||||
|      | ||||
|     // deno-lint-ignore no-explicit-any
 | ||||
|     type PropValue = Primitive | ((e: any) => void) | null | ||||
|      | ||||
|     type PropValueOrDerived = PropValue | StateView<PropValue> | (() => PropValue) | ||||
|      | ||||
|     type Props = Record<string, PropValueOrDerived> & { class?: PropValueOrDerived; is?: string } | ||||
|      | ||||
|     type PropsWithKnownKeys<ElementType> = Partial<{[K in keyof ElementType]: PropValueOrDerived}> | ||||
|      | ||||
|     type ValidChildDomValue = Primitive | Node | null | undefined | ||||
|      | ||||
|     type BindingFunc = ((dom?: Node) => ValidChildDomValue) | ((dom?: Element) => Element) | ||||
|      | ||||
|     type ChildDom = ValidChildDomValue | StateView<Primitive | null | undefined> | BindingFunc | readonly ChildDom[] | ||||
|      | ||||
|     type TagFunc<Result> = (first?: Props & PropsWithKnownKeys<Result> | ChildDom, ...rest: readonly ChildDom[]) => Result | ||||
|      | ||||
|     type Tags = Readonly<Record<string, TagFunc<Element>>> & { | ||||
|       [K in keyof HTMLElementTagNameMap]: TagFunc<HTMLElementTagNameMap[K]> | ||||
|     } | ||||
|   } | ||||
|   const van:{ | ||||
|     readonly state: <T>(initVal: T, HMRKey?:string)=> Van.State<T> | ||||
|     readonly derive: <T>(f: () => T) => Van.State<T> | ||||
|     readonly add: (dom: Element, ...children: readonly Van.ChildDom[]) => Element | ||||
|     readonly tags: Van.Tags & ((namespaceURI: string) => Readonly<Record<string, Van.TagFunc<Element>>>) | ||||
|     readonly hydrate: <T extends Node>(dom: T, f: (dom: T) => T | null | undefined) => T | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
|   namespace VanX | ||||
|   { | ||||
|     type StateOf<T> = { readonly [K in keyof T]: Van.State<T[K]> } | ||||
|     type ValueType<T> = T extends (infer V)[] ? V : T[keyof T] | ||||
|     type KeyType<T> = T extends unknown[] ? number : string | ||||
|     type ReplacementFunc<T> = | ||||
|         T extends (infer V)[] ? (items: V[]) => readonly V[] : | ||||
|         (items: [string, T[keyof T]][]) => readonly [string, T[keyof T]][] | ||||
|   } | ||||
|   const vanX:{ | ||||
|     readonly calc: <R>(f: () => R) => R | ||||
|     readonly reactive: <T extends object>(obj: T, HMRKey?:string) => T | ||||
|     readonly noreactive: <T extends object>(obj: T) => T | ||||
|     readonly stateFields: <T extends object>(obj: T) => VanX.StateOf<T> | ||||
|     readonly raw: <T extends object>(obj: T) => T | ||||
|     readonly list: <T extends object, ElementType extends Element>( | ||||
|       container: (() => ElementType) | ElementType, | ||||
|       items: T,itemFunc: (v: Van.State<VanX.ValueType<T>>, deleter: () => void, k: VanX.KeyType<T>) => Node | ||||
|     ) => ElementType | ||||
|     readonly replace: <T extends object>(obj: T, replacement: VanX.ReplacementFunc<T> | T) => T | ||||
|     readonly compact: <T extends object>(obj: T) => T | ||||
|     // my addition
 | ||||
|     readonly Store: <T extends object>(obj:T, key:string)=>T | ||||
|   }; | ||||
| 
 | ||||
|   namespace Gale {  | ||||
|     type KeyQuery = "@"; | ||||
|     type KeyPseudo = ":"; | ||||
|     type KeyChild = "."; | ||||
|     type KeyGroup = "^"; | ||||
|     type UserStyles = Partial<CSSStyleDeclaration> & {[key: `${KeyQuery|KeyPseudo|KeyChild|KeyGroup}${string}`]: UserStyles } | ||||
|     type UserSheet = Record<string, UserStyles> | ||||
|     type CollectKeys<Obj> = {[Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys<Obj[Key]> : Key }[keyof Obj] | ||||
|     type FilterKeys<Keys> = Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never | ||||
|     type CrossMultiply<A, B> = A extends string ? B extends string ? `${A}${B}` : never : never  | ||||
|     type CrossMultiplyRecord<Rec> = keyof Rec | { [K in keyof Rec]: K extends string ? CrossMultiply<K, FilterKeys<CollectKeys<Rec[K]>>> : never }[keyof Rec] | ||||
|     type Tier = (selector:string, obj:UserStyles)=>string; | ||||
|     type CreateSheet = <T extends UserSheet>(sheet:UserSheet&T)=> ((...args:CrossMultiplyRecord<T>[])=>string)&{CSS:string, DOM:Elemental<CrossMultiplyRecord<T>>} | ||||
|      | ||||
| 
 | ||||
|     type Elemental<T extends string> = {[K in keyof HTMLElementTagNameMap]: Circular<T, K>} | ||||
|     type Circular<Keys extends string, ElementName extends keyof HTMLElementTagNameMap> = { | ||||
|         [K in Keys]: Circular<Keys, ElementName>&Van.TagFunc<HTMLElementTagNameMap[ElementName]>; | ||||
|     }; | ||||
|      | ||||
|   } | ||||
|   const Gale:Gale.CreateSheet | ||||
| } | ||||
							
								
								
									
										17
									
								
								bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								bundle.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| //van
 | ||||
| {let e,t,r,o,n,l,s,i,f,h,w,a,d,u,_,c,S,g,y,b,m,v,j,x,O;s=Object.getPrototypeOf,f={},h=s(i={isConnected:1}),w=s(s),a=(e,t,r,o)=>(e??(setTimeout(r,o),new Set)).add(t),d=(e,t,o)=>{let n=r;r=t;try{return e(o)}catch(e){return console.error(e),o}finally{r=n}},u=e=>e.filter(e=>e.t?.isConnected),_=e=>n=a(n,e,()=>{for(let e of n)e.o=u(e.o),e.l=u(e.l);n=l},1e3),c={get val(){return r?.i?.add(this),this.rawVal},get oldVal(){return r?.i?.add(this),this.h},set val(o){r?.u?.add(this),o!==this.rawVal&&(this.rawVal=o,this.o.length+this.l.length?(t?.add(this),e=a(e,this,x)):this.h=o)}},S=e=>({__proto__:c,rawVal:e,h:e,o:[],l:[]}),g=(e,t)=>{let r={i:new Set,u:new Set},n={f:e},l=o;o=[];let s=d(e,r,t);s=(s??document).nodeType?s:new Text(s);for(let e of r.i)r.u.has(e)||(_(e),e.o.push(n));for(let e of o)e.t=s;return o=l,n.t=s},y=(e,t=S(),r)=>{let n={i:new Set,u:new Set},l={f:e,s:t};l.t=r??o?.push(l)??i,t.val=d(e,n,t.rawVal);for(let e of n.i)n.u.has(e)||(_(e),e.l.push(l));return t},b=(e,...t)=>{for(let r of t.flat(1/0)){let t=s(r??0),o=t===c?g(()=>r.val):t===w?g(r):r;o!=l&&e.append(o)}return e},m=(e,t,...r)=>{let[{is:o,...n},...i]=s(r[0]??0)===h?r:[{},...r],a=e?document.createElementNS(e,t,{is:o}):document.createElement(t,{is:o});for(let[e,r]of Object.entries(n)){let o=t=>t?Object.getOwnPropertyDescriptor(t,e)??o(s(t)):l,n=t+","+e,i=f[n]??=o(s(a))?.set??0,h=e.startsWith("on")?(t,r)=>{let o=e.slice(2);a.removeEventListener(o,r),a.addEventListener(o,t)}:i?i.bind(a):a.setAttribute.bind(a,e),d=s(r??0);e.startsWith("on")||d===w&&(r=y(r),d=c),d===c?g(()=>(h(r.val,r.h),a)):h(r)}return b(a,i)},v=e=>({get:(t,r)=>m.bind(l,e,r)}),j=(e,t)=>t?t!==e&&e.replaceWith(t):e.remove(),x=()=>{let r=0,o=[...e].filter(e=>e.rawVal!==e.h);do{t=new Set;for(let e of new Set(o.flatMap(e=>e.l=u(e.l))))y(e.f,e.s,e.t),e.t=l}while(++r<100&&(o=[...t]).length);let n=[...e].filter(e=>e.rawVal!==e.h);e=l;for(let e of new Set(n.flatMap(e=>e.o=u(e.o))))j(e.t,g(e.f,e.t)),e.t=l;for(let e of n)e.h=e.rawVal},O={tags:new Proxy(e=>new Proxy(m,v(e)),v()),hydrate:(e,t)=>j(e,g(t,e)),add:b,state:S,derive:y},window.van=O;} | ||||
| //vanx
 | ||||
| {let e,t,r,{fromEntries:o,entries:l,keys:n,hasOwn:f,getPrototypeOf:a}=Object,{get:i,set:y,deleteProperty:c,ownKeys:s}=Reflect,{state:m,derive:d,add:u}=van,b=1e3,w=Symbol(),A=Symbol(),S=Symbol(),_=Symbol(),g=Symbol(),p=Symbol(),P=e=>(e[A]=1,e),v=e=>e instanceof Object&&!(e instanceof Function)&&!e[p],h=e=>{if(e?.[A]){let t=m();return d(()=>{let r=e();v(t.rawVal)&&v(r)?B(t.rawVal,r):t.val=x(r)}),t}return m(x(e))},F=e=>{let t=Array.isArray(e)?[]:{__proto__:a(e)};for(let[r,o]of l(e))t[r]=h(o);return t[S]=[],t[_]=m(1),t},O={get:(e,t,r)=>t===w?e:f(e,t)?Array.isArray(e)&&"length"===t?(e[_].val,e.length):e[t].val:i(e,t,r),set:(e,o,l,n)=>f(e,o)?Array.isArray(e)&&"length"===o?(l!==e.length&&++e[_].val,e.length=l,1):(e[o].val=x(l),1):o in e?y(e,o,l,n):y(e,o,h(l))&&(++e[_].val,C(e).forEach(E.bind(t,n,o,e[o],r)),1),deleteProperty:(e,t)=>(c(e,t)&&R(e,t),++e[_].val),ownKeys:e=>(e[_].val,s(e))},x=e=>!v(e)||e[w]?e:new Proxy(F(e),O),D=e=>(e[p]=1,e),j=e=>e[w],K=a(m()),N=e=>new Proxy(e,{get:(e,t,r)=>a(e[t]??0)===K?{val:k(e[t].rawVal)}:i(e,t,r)}),k=e=>e?.[w]?new Proxy(N(e[w]),O):e,C=e=>e[S]=e[S].filter(e=>e.t.isConnected),E=(e,t,r,o,{t:l,f:f})=>{let a=Array.isArray(e),i=a?Number(t):t;u(l,()=>l[g][t]=f(r,()=>delete e[t],i)),a&&!o&&i!==e.length-1&&l.insertBefore(l.lastChild,l[g][n(e).find(e=>Number(e)>i)])},R=(e,t)=>{for(let r of C(e)){let e=r.t[g];e[t]?.remove(),delete e[t]}},T=r=>(e??(setTimeout(()=>(e.forEach(C),e=t),b),e=new Set)).add(r),q=(e,t,r)=>{let o={t:e instanceof Function?e():e,f:r},n=t[w];o.t[g]={},n[S].push(o),T(n);for(let[e,r]of l(n))E(t,e,r,1,o);return o.t},z=(e,t)=>{for(let[r,o]of l(t)){let t=e[r];v(t)&&v(o)?z(t,o):e[r]=o}for(let r in e)f(t,r)||delete e[r];let r=n(t),o=Array.isArray(e);if(o||n(e).some((e,t)=>e!==r[t])){let l=e[w];if(o)e.length=t.length;else{++l[_].val;let e={...l};for(let e of r)delete l[e];for(let t of r)l[t]=e[t]}for(let{t:e}of C(l)){let{firstChild:t,[g]:o}=e;for(let l of r)t===o[l]?t=t.nextSibling:e.insertBefore(o[l],t)}}return e},B=(e,n)=>{r=1;try{return z(e,n instanceof Function?Array.isArray(e)?n(e.filter(e=>1)):o(n(l(e))):n)}finally{r=t}},G=e=>Array.isArray(e)?e.filter(e=>1).map(G):v(e)?o(l(e).map(([e,t])=>[e,G(t)])):e;window.vanX={calc:P,reactive:x,noreactive:D,stateFields:j,raw:k,list:q,replace:B,compact:G}} | ||||
| 
 | ||||
| //Store
 | ||||
| vanX.Store =(obj, key)=> { | ||||
|     const recall = localStorage.getItem(key); | ||||
|     const store = vanX.reactive(recall ? JSON.parse(recall) : obj); | ||||
|     van.derive(() => localStorage.setItem(key, JSON.stringify(vanX.compact(store)))); | ||||
|     return store; | ||||
| } | ||||
| 
 | ||||
| //gale
 | ||||
| const KeyQuery="@",KeyPseudo=":",KeyChild=".",KeyGroup="^",Tier=(e,t)=>`${e}{${Object.keys(t).map((e=>{const n=t[e];switch(e[0]){case"@":return Tier(`@media(max-width:${e.substring(1)})`,n);case":":return Tier(`&${e}`,n);case".":return Tier(`${e}`,n);case"^":return Tier(`&:hover .${e.substring(1)}`,n)}return`${e.replace(/([a-z])([A-Z])/g,"$1-$2")}: ${n};`})).join("\n")}}`;let i=0;globalThis.Gale=e=>{const t=i?"_"+i:"";i++;const n=Object.keys(e).map((t=>Tier("."+t,e[t]))).join("\n");globalThis.document?.head.insertAdjacentHTML("beforeend",`<style data-sheet="${i}">${n}</style>`);const r=(...e)=>{const n=(e,t)=>{const n=t.lastIndexOf(e)+e.length;return n?t.substring(n):t};return e.map((e=>n("^",n(".",e)))).join(t+" ")+t};return r.CSS=n,r.DOM=new Proxy({},{get(e,t){const n=t,r=[],s=new Proxy(((...e)=>{const t=van.tags[n](...e);return t.className=r.join(" "),t}),{get:(e,t)=>(r.push(t.substring(t.lastIndexOf(".")+1)),s)});return s}}),r}; | ||||
| //boot
 | ||||
| ((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"; ')}))})(); | ||||
							
								
								
									
										18
									
								
								deno.json
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								deno.json
									
									
									
									
									
								
							| @ -1,11 +1,13 @@ | ||||
| { | ||||
|     "imports": { | ||||
|         "react": "https://esm.sh/preact@10.18.1/compat", | ||||
|         "react/": "https://esm.sh/preact@10.18.1/compat/" | ||||
|     "compilerOptions": { | ||||
|         "checkJs": true, | ||||
|         "lib": [ | ||||
|             "deno.window", | ||||
|             "DOM" | ||||
|         ], | ||||
|         "types": ["./bundle.d.ts"] | ||||
|     }, | ||||
| 	"tasks": {"go": "deno run -A styler.tsx"}, | ||||
| 	"compilerOptions": { | ||||
| 		"jsx": "react-jsx", | ||||
| 		"lib": ["deno.window","dom","dom.asynciterable"] | ||||
| 	} | ||||
|     "imports": { | ||||
|         "entry":"./app.js" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										94
									
								
								dev_server.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								dev_server.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| import { contentType } from "jsr:@std/media-types"; | ||||
| 
 | ||||
| // Parse the port from the command-line arguments, defaulting to 8000
 | ||||
| const port = parseInt(Deno.args[0] || "8000", 10); | ||||
| const sockets: WebSocket[] = []; | ||||
| const connect = `<script>
 | ||||
| const ws = new WebSocket('ws://localhost:${port}/ws'); | ||||
| ws.addEventListener('message', (event) => { | ||||
|   if (event.data === 'reload') { | ||||
|     window.location.reload(); | ||||
|   } | ||||
| }); | ||||
| ws.addEventListener('error', console.error); | ||||
| ws.addEventListener('close', console.warn); | ||||
| </script>`;
 | ||||
| 
 | ||||
| const bundle = await fetch(import.meta.resolve("./bundle.js")).then(r=>r.text()); | ||||
| 
 | ||||
| let html: string; | ||||
| try { | ||||
|   html = Deno.readTextFileSync("./index.html").replace("<head>", "<head>"+connect); | ||||
| } catch (_) { | ||||
|   html = ` | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|     <head> | ||||
|       ${connect} | ||||
|         <meta charset="UTF-8"> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|         <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>${bundle}</script> | ||||
|     </head> | ||||
|     <body></body> | ||||
| </html>`;
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| function extension(path: string): string { | ||||
|   // Remove trailing slash if it exists
 | ||||
|   const normalizedPath = path.endsWith("/") ? path.slice(0, -1) : path; | ||||
|   // Get the last part of the path
 | ||||
|   const lastPart = normalizedPath.split("/").pop() || ""; | ||||
|   // Check if the last part contains a "."
 | ||||
|   return lastPart.split(".")[1] || ""; | ||||
| } | ||||
| 
 | ||||
| // Start the HTTP server using Deno.serve
 | ||||
| Deno.serve({ port }, async (req: Request) => { | ||||
|   const url = new URL(req.url); | ||||
| 
 | ||||
|   // Handle WebSocket connections
 | ||||
|   if (url.pathname === "/ws") { | ||||
|     const { socket, response } = Deno.upgradeWebSocket(req); | ||||
|     sockets.push(socket); | ||||
|     return response; | ||||
|   } | ||||
| 
 | ||||
|   // Serve static files or the predefined HTML for non-file routes
 | ||||
|   const path = new URL(req.url).pathname; | ||||
|   const ext = extension(path); | ||||
| 
 | ||||
|   // Serve the predefined HTML for non-file routes
 | ||||
|   if (!ext) { | ||||
|     return new Response(html, { | ||||
|       headers: { "Content-Type": "text/html" }, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   try { | ||||
|     const file = await Deno.open("." + path, { read: true }); | ||||
|     return new Response(file.readable, { | ||||
|       headers: { "Content-Type": contentType(ext) || "application/javascript" }, | ||||
|     }); | ||||
|   } catch (err) { | ||||
|     if (err instanceof Deno.errors.NotFound) { | ||||
|       return new Response("File not found", { status: 404 }); | ||||
|     } else { | ||||
|       return new Response("Internal server error", { status: 500 }); | ||||
|     } | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| // Start watching for file changes
 | ||||
| const watcher = Deno.watchFs("."); | ||||
| for await (const event of watcher) { | ||||
|   if (event.kind === "modify") { | ||||
|     for (const ws of sockets) { | ||||
|         if (ws.readyState === WebSocket.OPEN) { | ||||
|           ws.send("reload"); | ||||
|           continue; | ||||
|         } | ||||
|       } | ||||
|   } | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| import {config, Complex} from "./gale.tsx"; | ||||
| 
 | ||||
| export default config({other:"lol"}); | ||||
							
								
								
									
										92
									
								
								gale.tsx
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								gale.tsx
									
									
									
									
									
								
							| @ -1,92 +0,0 @@ | ||||
| 
 | ||||
| const typeface = { | ||||
|     sans: "sans serif", | ||||
|     serif: "Times New Roman" | ||||
| }; | ||||
| const sizes = { | ||||
|     small: "1rem", | ||||
|     large: "3rem" | ||||
| }; | ||||
| const colors = { | ||||
|     red: "#ff2200", | ||||
|     blue: "#0022ff" | ||||
| }; | ||||
| const responsive = { | ||||
|     md: "min-width:767px", | ||||
|     lg: "min-width:1024px", | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| const styles = new Map<string, string>(); | ||||
| function Mapper<T extends Record<string, string>>(className:string, propertyName:string, lut:T) | ||||
| { | ||||
|     const build =(propertyValue:string, customPropertyName?:string):string=> | ||||
|     { | ||||
|         const selector = `${className}-${(customPropertyName||propertyValue as string).replace(/[^a-zA-Z0-9]/g, "")}${activeQuery.val?"_"+activeQuery.key:""}`; | ||||
|         const check = styles.get(selector); | ||||
|         if(!check) | ||||
|         { | ||||
|             const body = `{ ${propertyName}:${propertyValue}; }`; | ||||
|             styles.set(selector, activeQuery.val ? `{ @media(${activeQuery.val})${body}}` : body);     | ||||
|         } | ||||
|         return selector; | ||||
|     } | ||||
|     type UseCustom = (custom:string)=>string; | ||||
|     return new Proxy(((override:string)=>build(override)) as UseCustom, | ||||
|         { | ||||
|             get(_, prop){ | ||||
| 
 | ||||
|                 return build(lut[prop as string], prop as string); | ||||
|             } | ||||
|         } | ||||
|     ) as T & UseCustom; | ||||
| } | ||||
| function MapperQuery<T extends Record<string, string>>(lut:T) | ||||
| { | ||||
|     type UseCustom = (custom:string)=>QueryInvoker; | ||||
|     return new Proxy(((override:string)=>Query(override, override)) as UseCustom, | ||||
|         { | ||||
|             get(_, prop:string){ | ||||
|                 return Query(lut[prop], prop) | ||||
|             } | ||||
|         } | ||||
|     ) as Record<keyof T, QueryInvoker> & UseCustom; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| let activeQuery:ActiveQuery; | ||||
| type ActiveQuery = {key:string|false, val:string|false}; | ||||
| const activeQueryStack:ActiveQuery[] = []; | ||||
| type QueryInvoker = (...args:string[])=>string | ||||
| function Query(amount:string, key?:string):QueryInvoker | ||||
| { | ||||
|     activeQuery = {key:key||amount, val:amount}; | ||||
|     activeQueryStack.push(activeQuery); | ||||
|     return (...args)=> { | ||||
| 
 | ||||
|         activeQueryStack.pop() | ||||
|         activeQuery = activeQueryStack.at(-1) || {key:false, val:false}; | ||||
|         return args.join(" "); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export function config<T>(obj:T) | ||||
| { | ||||
|     const CSS = { | ||||
|         Sheet() | ||||
|         { | ||||
|             const rules = []; | ||||
|             for(const [key, value] of styles.entries()) | ||||
|             { | ||||
|                 rules.push(key+value); | ||||
|             } | ||||
|             return rules.join("\n"); | ||||
|         }, | ||||
|         Face: Mapper("Face", "font-family", {...typeface, ...obj}), | ||||
|         Pad: Mapper("Pad", "padding", sizes), | ||||
|         Q: MapperQuery(responsive) | ||||
|     }; | ||||
|     return CSS; | ||||
| } | ||||
| 
 | ||||
| export default config({}); | ||||
| @ -1,5 +0,0 @@ | ||||
| <style> | ||||
|     .py-01{padding:30px 0 30px 0;} | ||||
|     .px-01{padding:0 20px 0 20px;} | ||||
| </style> | ||||
| <p class="px-01 py-01">test</p> | ||||
							
								
								
									
										33
									
								
								refresh_types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								refresh_types.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| import { resolve, toFileUrl } from "https://deno.land/std/path/mod.ts"; | ||||
| 
 | ||||
| async function main() | ||||
| { | ||||
|   // Look for the deno.json file in the current directory
 | ||||
|   const denoJsonPath = resolve("./deno.json"); | ||||
| 
 | ||||
|   // Read and parse the deno.json file
 | ||||
|   const denoJson = JSON.parse(await Deno.readTextFile("./deno.json")); | ||||
| 
 | ||||
|   // Check if compilerOptions and types are defined
 | ||||
|   if (denoJson.compilerOptions?.types) { | ||||
|     const types:string[] = denoJson.compilerOptions.types; | ||||
| 
 | ||||
|     // Iterate over each type file and cache it
 | ||||
|     for (const typeFile of types) { | ||||
|         let lookup:string = typeFile; | ||||
|         if(!typeFile.startsWith("http")) | ||||
|         { | ||||
|             lookup = toFileUrl(resolve(Deno.cwd(), typeFile)).href; | ||||
|         } | ||||
|       console.log(`Caching ${lookup}`); | ||||
|       await import(lookup); // This will cache the file
 | ||||
|     } | ||||
|   } else { | ||||
|     console.log("No types found in compilerOptions."); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| main().catch((error) => { | ||||
|   console.error("Error:", error); | ||||
|   Deno.exit(1); | ||||
| }); | ||||
							
								
								
									
										19
									
								
								scaffold.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								scaffold.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| const hostedRoot = import.meta.resolve("../").slice(0, -1); | ||||
| async function Download(file:string, processor = (text:string)=>text) | ||||
| { | ||||
|     const pathHosted = hostedRoot + "/scaffold/" + file; | ||||
|     try | ||||
|     { | ||||
|         const fileContents = await fetch(pathHosted).then(resp=>resp.text()); | ||||
|         await Deno.writeTextFile(file, processor(fileContents)); | ||||
|         console.log(`Successfully downloaded ${file}`); | ||||
|     } | ||||
|     catch (error) | ||||
|     { | ||||
|         console.error(`Error downloading ${file}:`, error); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Download("deno.json", t=>t.replaceAll(`{HOSTED}`, hostedRoot)); | ||||
| Download("index.html", t=>t.replaceAll(`{HOSTED}`, hostedRoot)); | ||||
| Download("app.js"); | ||||
							
								
								
									
										47
									
								
								scaffold/app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								scaffold/app.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| const {DOM} = Gale({ | ||||
|     Button: { | ||||
|         padding: "20px", | ||||
|         background: "orange", | ||||
|         ".Inner": { | ||||
|             fontSize: "10rem" | ||||
|         } | ||||
|     }, | ||||
|     Outline: { | ||||
|         border: "2px solid orange" | ||||
|     }, | ||||
|     Window:{ | ||||
|       height: "100vh", | ||||
|       border: "2px solid black", | ||||
|       display: "flex", | ||||
|       flexDirection: "row", | ||||
|       alignItems: "end", | ||||
|       justifyContent: "center", | ||||
|       gap: "10px" | ||||
|     }, | ||||
|     Ability:{ | ||||
|       width: "50px", | ||||
|       height: "50px", | ||||
|       background: "red", | ||||
|       transition: "all 0.4s", | ||||
|       ":hover":{ | ||||
|         transform:"scale(1.1)" | ||||
|       } | ||||
|     }, | ||||
|     Orange:{ | ||||
|         background:"orange" | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| const UI =()=> | ||||
| { | ||||
|   return DOM.div.Window( | ||||
|     DOM.div.Ability(), | ||||
|     DOM.div.Ability(), | ||||
|     DOM.div.Ability(), | ||||
|     DOM.div.Ability.Orange(), | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| van.add(document.body, UI()); | ||||
							
								
								
									
										14
									
								
								scaffold/deno.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								scaffold/deno.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| { | ||||
|     "compilerOptions": { | ||||
|         "checkJs": true, | ||||
|         "lib": [ "deno.window", "DOM"], | ||||
|         "types": ["{HOSTED}/bundle.d.ts"] | ||||
|     }, | ||||
|     "tasks": { | ||||
|         "dev": "deno run -Ar {HOSTED}/dev_server.ts", | ||||
|         "types": "deno run -Ar {HOSTED}/refresh_types.ts" | ||||
|     }, | ||||
|     "imports": { | ||||
|         "entry":"./app.js" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								scaffold/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								scaffold/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| <html lang="en"> | ||||
|     <head> | ||||
|         <meta charset="UTF-8"> | ||||
|         <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> | ||||
|         <!-- bundled source --> | ||||
|         <script src="{HOSTED}/bundle.js"></script> | ||||
|     </head> | ||||
|     <body></body> | ||||
| </html> | ||||
							
								
								
									
										15
									
								
								src/boot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/boot.js
									
									
									
									
									
										Normal 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"; ') | ||||
|     }) | ||||
| )(); | ||||
							
								
								
									
										73
									
								
								src/gale.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/gale.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | ||||
| const KeyQuery = "@"; | ||||
| const KeyPseudo = ":"; | ||||
| const KeyChild = "."; | ||||
| const KeyGroup = "^"; | ||||
| 
 | ||||
| /** @type {Gale.Tier} */ | ||||
| const Tier=(selector, obj)=> | ||||
| { | ||||
|     const styles = Object.keys(obj).map((key)=> | ||||
|     { | ||||
|         const value = obj[key]; | ||||
|         switch(key[0]) | ||||
|         { | ||||
|             case KeyQuery : | ||||
|                 return Tier(`@media(max-width:${key.substring(KeyQuery.length)})`, value); | ||||
|             case KeyPseudo : | ||||
|                 return Tier(`&${key}`, value); | ||||
|             case KeyChild : | ||||
|                 return Tier(`${key}`, value); | ||||
|             case KeyGroup : | ||||
|                 return Tier(`&:hover .${key.substring(KeyGroup.length)}`, value); | ||||
|         } | ||||
|         return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2') }: ${value};` | ||||
|     }); | ||||
|     return `${selector}{${styles.join("\n")}}`; | ||||
| } | ||||
| 
 | ||||
| let i = 0; | ||||
| /** @type {Gale.CreateSheet} */ | ||||
| globalThis.Gale =sheet=> | ||||
| { | ||||
|     const id = i ? "_"+i : ""; | ||||
|     i++; | ||||
|     const css = Object.keys(sheet).map(key=>Tier("."+key, sheet[key])).join(`\n`); | ||||
|     globalThis.document?.head.insertAdjacentHTML("beforeend", `<style data-sheet="${i}">${css}</style>`); | ||||
|     const classes =(...args)=>{ | ||||
|         /** @type {(needle:string, str:string)=>string} */ | ||||
|         const extractLast =(needle, str)=>{ | ||||
|             const ind = str.lastIndexOf(needle)+needle.length; | ||||
|             return ind ? str.substring(ind) : str; | ||||
|         } | ||||
|         return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id; | ||||
|     } | ||||
| 
 | ||||
|     classes.CSS = css; | ||||
|     classes.DOM = new Proxy( | ||||
|         {}, | ||||
|         {get(_, prop) | ||||
|             { | ||||
|                 const pending = prop; | ||||
|                 const mentioned = []; | ||||
|                 const collector = new Proxy( | ||||
|                     (...args)=> | ||||
|                     { | ||||
|                         const element = van.tags[pending](...args); | ||||
|                         element.className = mentioned.join(" "); | ||||
|                         return element; | ||||
|                     }, | ||||
|                     { | ||||
|                         get(_, prop) | ||||
|                         { | ||||
|                             mentioned.push(prop.substring(prop.lastIndexOf(".")+1)); | ||||
|                             return collector; | ||||
|                         } | ||||
|                     } | ||||
|                 ); | ||||
|                 return collector; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
|     return classes; | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| import Gale from "./gale-custom.tsx"; | ||||
| 
 | ||||
| const classes = Gale.Q.lg( Gale.Face.sans, Gale.Q.md(Gale.Pad.large), Gale.Pad.small ); | ||||
| 
 | ||||
| console.log(classes); | ||||
| 
 | ||||
| console.log(Gale.Sheet()) | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user