diff --git a/dist/styles/main.css b/dist/styles/main.css index 9043356..0cfbf9b 100644 --- a/dist/styles/main.css +++ b/dist/styles/main.css @@ -8838,14 +8838,36 @@ details.collapse summary::-webkit-details-marker { .bg-gradient-to-r { background-image: linear-gradient(to right, var(--tw-gradient-stops)); } +.from-blue-200 { + --tw-gradient-from: #bfdbfe var(--tw-gradient-from-position); + --tw-gradient-to: rgb(191 219 254 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} .from-blue-400 { --tw-gradient-from: #60a5fa var(--tw-gradient-from-position); --tw-gradient-to: rgb(96 165 250 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } +.from-blue-600 { + --tw-gradient-from: #2563eb var(--tw-gradient-from-position); + --tw-gradient-to: rgb(37 99 235 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} .to-blue-500 { --tw-gradient-to: #3b82f6 var(--tw-gradient-to-position); } +.to-blue-600 { + --tw-gradient-to: #2563eb var(--tw-gradient-to-position); +} +.to-blue-300 { + --tw-gradient-to: #93c5fd var(--tw-gradient-to-position); +} +.to-blue-400 { + --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); +} +.to-blue-200 { + --tw-gradient-to: #bfdbfe var(--tw-gradient-to-position); +} .decoration-slice { -webkit-box-decoration-break: slice; box-decoration-break: slice; diff --git a/dist/vader/component.d.ts b/dist/vader/component.d.ts new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/dist/vader/component.d.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dist/vader/vader.js b/dist/vader/vader.js index c0209b5..fa906b9 100644 --- a/dist/vader/vader.js +++ b/dist/vader/vader.js @@ -1,74 +1,8 @@ -let dom = [] +// @ts-nocheck +let dom = []; let states = {}; -let worker = new Worker(new URL('./worker.js', import.meta.url)); -/** - * @function markdown - * @param {String} content - * @description Allows you to convert markdown to html - */ -function markdown(content) { - - let headers = content.match(/(#+)(.*)/g); - if (headers) { - headers.forEach((header) => { - if(header.includes('/') || header.includes('<') || header.includes('>')){ - return - - } - let level = header.split('#').length; - content = content.replace(header, `${header.replace(/#/g, '')}`); - }); - } - - content = content.replace(/\*\*(.*?)\*\*/g, (match, text) => { - return `${text}`; - }); - content = content.replace(/\*(.*?)\*/g, (match, text) => { - return `${text}`; - }) - content = content.replace(/`(.*?)`/g, (match, text) => { - return `${text}`; - }); - content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => { - return `${text}`; - }); - content = content.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, (match, alt, src) => { - return `${alt}`; - }); - content = content.split('\n').map((line, index, arr) => { - if (line.match(/^\s*-\s+(.*?)$/gm)) { - if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) { - return ``; - } else { - return `
  • ${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}
  • `; - } - } else { - return line; - } - }).join('\n'); - - content = content.split('\n').map((line, index, arr) => { - if (line.match(/^\s*\d+\.\s+(.*?)$/gm)) { - if (index === 0 || !arr[index - 1].match(/^\s*\d+\.\s+(.*?)$/gm)) { - return `
    1. ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}
    2. `; - } else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*\d+\.\s+(.*?)$/gm)) { - return `
    3. ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}
    `; - } else { - return `
  • ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}
  • `; - } - } else { - return line; - } - }).join('\n'); - - - return content - -} - +let worker = new Worker(new URL("./worker.js", import.meta.url)); /** * @function useRef @@ -76,7 +10,7 @@ function markdown(content) { * @param {String} ref * @returns {void | Object} {current, update} */ - + export const useRef = (ref) => { const element = document.querySelector(`[ref="${ref}"]`); const getElement = () => element; @@ -97,7 +31,7 @@ export const useRef = (ref) => { return { current: getElement(), - update, + update }; }; @@ -141,47 +75,63 @@ export class Component { this.$_useStore_subscribers = []; this.init(); this.Componentcontent = null; - this.$_signal_dispatch_event = new CustomEvent("signalDispatch", { + this.$_signal_dispatch_event = new CustomEvent("SignalDispatch", { detail: { hasUpdated: false, - state: null, - }, + state: null + } }); + /** + * @property {Object} $_signal_dispatch_cleanup_event + * @description Allows you to dispatch a signal cleanup event + * @private + */ + this.$_signal_dispatch_cleanup_event = new CustomEvent( + "Signal_Cleanup_Dispatch", + { + detail: { + state: null, + lastState: null + } + } + ); + /** + * @property {Array} snapshots + * @private + */ this.snapshots = []; /** * @property {Object} dom * @description Allows you to get reference to DOM element * @returns {void | HTMLElement} - * + * */ - this.dom = [] - + this.dom = []; + /** * @property {Boolean} cfr - * @description Allows you to compile html code on the fly - client fly rendering - * + * @description Allows you to compile html code on the fly - client fly rendering + * */ - this.cfr = false + this.cfr = false; /** * @property {Boolean} worker * @description Allows you to use a web worker to compile html code on the fly - client fly rendering */ - } /** * @method adapter * @description Allows you to create an adapter - this is used to create custom logic - * - * + * + * */ - adapter() { - return + adapter(options) { + // allow you to override the compoent logic } init() { this.registerComponent(); - } registerComponent() { @@ -303,13 +253,20 @@ export class Component { this.$_signal_subscribe = (fn, runonce) => { this.$_signal_subscribers.push({ function: fn, - runonce: runonce, + runonce: runonce }); + return fn; }; this.$_signal_cleanup = (fn) => { + this.lastState = state; this.$_signal_subscribers = this.$_signal_subscribers.filter( (subscriber) => subscriber.function !== fn ); + // @ts-ignore + this.$_signal_dispatch_cleanup_event.detail.state = this.states; + // @ts-ignore + this.$_signal_dispatch_cleanup_event.detail.lastState = this.lastState; + window.dispatchEvent(this.$_signal_dispatch_event); }; this.$_signal_dispatch = () => { for (var i = 0; i < this.$_signal_subscribers.length; i++) { @@ -382,7 +339,7 @@ export class Component { * @description Allows you to get the value of a signal * @returns {any} */ - get: this.$_signal_get, + get: this.$_signal_get }; }; /** @@ -466,7 +423,7 @@ export class Component { return logicalOperator === "any" ? auth.canAnyOf(actions) : auth.canAllOf(actions); - }, + } }; return auth; } @@ -506,11 +463,10 @@ export class Component { (action) => { this.states[key] = reducer(this.states[key], action); this.updateComponent(); - }, + } ]; } - runEffects() { Object.keys(this.effects).forEach((component) => { this.effects[component].forEach((effect) => { @@ -521,7 +477,7 @@ export class Component { }); }); } - + /** * @method useSyncStore * @description Allows you to create a store @@ -545,8 +501,7 @@ export class Component { subscriber(s); }); }) || - {}, - + {} ); const getField = (fieldName) => { @@ -569,7 +524,7 @@ export class Component { getField, setField, subscribe, - clear, + clear }; } /** @@ -588,12 +543,10 @@ export class Component { * setCount(count + 1) */ useState(key, initialValue, callback = null) { - - if(!this.states[key]){ - this.states[key] = initialValue; - } - - + if (!this.states[key]) { + this.states[key] = initialValue; + } + return [ this.states[key], /** @@ -607,7 +560,7 @@ export class Component { this.updateComponent(); // @ts-ignore typeof callback === "function" ? callback() : null; - }, + } ]; } /** @@ -624,9 +577,8 @@ export class Component { useRef(ref) { // get ref from array - console.log(this.dom) - const element = this.dom[ref] - + const element = this.dom[ref]; + const getElement = () => element; const update = (data) => { @@ -648,12 +600,12 @@ export class Component { // @ts-ignore current: getElement, /**@type {Function} */ - update, + update }; } /** - * + * * @function useEffect * @param {*} effectFn * @param {*} dependencies @@ -682,10 +634,12 @@ export class Component { return { cleanup: () => { + // @ts-ignore this.effects[this.name] = this.effects[this.name].filter( + // @ts-ignore (effect) => effect !== effectFn ); - }, + } }; } /** @@ -718,8 +672,7 @@ export class Component { const fragment = document.createDocumentFragment(); Object.keys(components).forEach(async (component) => { const { name } = components[component]; - - + let componentContainer = document.querySelector( `[data-component="${name}"]` ); @@ -736,7 +689,7 @@ export class Component { prev_state: this.states, prev_props: this.storedProps, // @ts-ignore - content: componentContainer.innerHTML, + content: componentContainer.innerHTML }; if (!componentContainer) return; @@ -796,141 +749,6 @@ export class Component { return /^[a-zA-Z0-9-_]+$/.test(className); } - - parseHTML(result) { - - const dom = new DOMParser().parseFromString(result, "text/html"); - console.log(dom) - const elements = dom.documentElement.querySelectorAll("*"); - - elements.forEach((element) => { - switch (element.nodeName) { - case "IMG": - if ( - !element.hasAttribute("alt") && - !document.documentElement.outerHTML - .trim() - .includes("") - ) { - throw new SyntaxError( - `Image: ${element.outerHTML} missing alt attribute` - ); - } else if ( - element.hasAttribute("alt") && - // @ts-ignore - element.getAttribute("alt").length < 1 && - !document.documentElement.outerHTML - .trim() - .includes("") - ) { - throw new SyntaxError( - `Image: ${element.outerHTML} alt attribute cannot be empty` - ); - - } else if ( - element.hasAttribute("src") && - !element.getAttribute("src")?.includes("http") || !element.getAttribute("src")?.includes("https") && - !document.documentElement.outerHTML - .trim() - .includes("") - ) { - let prevurl = element.getAttribute("src"); - element.setAttribute("aria-hidden", "true"); - element.setAttribute("hidden", "true"); - // if window.lcoation.pathname includes a html file remove it and only use the path - let url = window.location.origin + window.location.pathname.replace(/\/[^\/]*$/, '') + '/public/' + element.getAttribute("src"); - let image = new Image(); - image.src = url; - image.onerror = () => { - // @ts-ignore - element.setAttribute("src", prevurl); - throw new Error(`Image: ${element.outerHTML} not found`); - }; - element.setAttribute("src", url); - - image.onload = () => { - document.querySelectorAll(`img[src="${url}"]`).forEach((img) => { - img.setAttribute("src", url); - img.removeAttribute("aria-hidden"); - img.removeAttribute("hidden"); - }); - }; - } - break; - - default: - if (element.hasAttribute("ref")) { - // @ts-ignore - dom[element.getAttribute("ref")] = element; - } - if(element.nodeName === "MARKDOWN"){ - element.innerHTML = markdown(element.innerHTML.replace(/\\n/g, '\n').trim()) - } - - if (element.hasAttribute("class")) { - const allowClassComments = - document.documentElement.outerHTML.includes( - "" - ); - if (!allowClassComments) { - console.warn( - "you can disable class errors using, " - ); - throw new Error( - "class attribute is not allowed, please use className instead" - ); - } - } else if (element.hasAttribute("className")) { - // @ts-ignore - element.setAttribute("class", element.getAttribute("className")); - element.removeAttribute("className"); - } - - if ( - element.hasAttribute("href") && - // @ts-ignore - element.getAttribute("href").startsWith("/") && - !document.documentElement.outerHTML - .trim() - .includes("") - ) { - element.setAttribute( - "href", - // @ts-ignore - `#/${element.getAttribute("href").replace("/", "")}` - ); - } - - if ( - element.hasAttribute("src") && - // @ts-ignore - !element.getAttribute("src").includes("http") && - // @ts-ignore - !element.getAttribute("src").includes("https") && - !document.documentElement.outerHTML.includes(``) - ) { - element.setAttribute( - "src", - // @ts-ignore - `./public/${element.getAttribute("src")}` - ); - } - break; - } - - }); - - result = dom.body.innerHTML; - - this.Componentcontent = result; - - if (!result.includes("
    ${result}
    `; - } - return markdown(result.replace(/\\n/g, '\n').trim()) - - } - /** * The `html` method generates and processes HTML content for a component, performing various validations and tasks. * @@ -977,104 +795,116 @@ export class Component { * @see {@link Component} * @see {@link Component#componentDidMount} */ - - - + html(strings, ...args) { // @ts-ignore - let tiemr = setInterval(()=>{ - if(document.querySelector(`[data-component="${this.name}"]`)){ - clearInterval(tiemr) + let timer = setInterval(() => { + if (document.querySelector(`[data-component="${this.name}"]`)) { + clearInterval(timer); this.componentMounted = true; - - document.querySelector(`[data-component="${this.name}"]`)?.querySelectorAll("*").forEach((element)=>{ - if(element.hasAttribute("ref")){ - // @ts-ignore - this.dom[element.getAttribute("ref")] = element - } - }) + + document + .querySelector(`[data-component="${this.name}"]`) + ?.querySelectorAll("*") + .forEach((element) => { + if (element.hasAttribute("ref")) { + // @ts-ignore + this.dom[element.getAttribute("ref")] = element; + } + }); this.componentDidMount(); } - }, 100) + }, 100); let script = document.createElement("script"); script.setAttribute("type", "text/javascript"); script.setAttribute(`data-component-script`, this.name); - - - let dom = this.dom - - if(this.cfr){ - - worker.postMessage({strings, args, location: window.location.origin + window.location.pathname.replace(/\/[^\/]*$/, '') + '/public/', name: this.name}) - let promise = new Promise((resolve, reject)=>{ - worker.onmessage = (e)=>{ - if(e.data.error){ - throw new Error(e.data.error) - } - const dom = this.dom; // Assuming this.dom is an object - console.log(this.dom) - let js = e.data.js - let template = e.data.template - // Bind the component's context - - const useState = this.useState.bind(this); // Bind the component's context - const useEffect = this.useEffect.bind(this); // Bind the component's context - const useReducer = this.useReducer.bind(this); // Bind the component's context - const useAuth = this.useAuth.bind(this); // Bind the component's context - const useSyncStore = this.useSyncStore.bind(this); // Bind the component's context - const signal = this.signal.bind(this); // Bind the component's context - const rf = this.$Function.bind(this); // Bind the component's context - let states = this.states - const useRef = this.useRef.bind(this); // Bind the component's context - new Function("useState", "useEffect", "useAuth", "useReducer", "useSyncStore", "signal", "rf", "dom", "render", "states", "useRef", js)( + worker.postMessage({ + strings, + args, + location: + window.location.origin + + window.location.pathname.replace(/\/[^\/]*$/, "") + + "/public/", + name: this.name + }); + let promise = new Promise((resolve, reject) => { + worker.onmessage = (e) => { + if (e.data.error) { + throw new Error(e.data.error); + } + const dom = this.dom; // Assuming this.dom is an object + let js = e.data.js; + let template = e.data.template; + // Bind the component's context + + const useState = this.useState.bind(this); // Bind the component's context + const useEffect = this.useEffect.bind(this); // Bind the component's context + const useReducer = this.useReducer.bind(this); // Bind the component's context + const useAuth = this.useAuth.bind(this); // Bind the component's context + const useSyncStore = this.useSyncStore.bind(this); // Bind the component's context + const signal = this.signal.bind(this); // Bind the component's context + const $Function = this.$Function.bind(this); // Bind the component's context + let states = this.states; + const useRef = this.useRef.bind(this); // Bind the component's context + new Function( + "useState", + "useEffect", + "useAuth", + "useReducer", + "useSyncStore", + "signal", + "$Function", + "dom", + "render", + "states", + "useRef", + js + )( + useState, + useEffect, + useAuth, + useReducer, + useSyncStore, + signal, + $Function, + this.dom, + this.render, + this.states, + useRef + ); + + resolve( + new Function( + "useRef", + "states", + "signal", + "useState", + "useReducer", + "useAuth", + "useSyncStore", + "useRef", + "$Function", + "return" + "`" + template + "`" + )( + useRef, + states, + signal, useState, - useEffect, - useAuth, useReducer, + useAuth, useSyncStore, - signal, - rf, - this.dom, - this.render, - this.states, - useRef + useRef, + $Function ) - - resolve(new Function("useRef", "states", "return" + "`" + template + "`")(useRef, states)) - - - - - } - worker.onerror = (e)=>{ - reject(e) - } - }) - // @ts-ignore - return promise; - }else{ - let result = ""; - for (let i = 0; i < strings.length; i++) { - result += strings[i]; - if (i < args.length) { - result += args[i]; - } - } - result = new Function("useRef", `return \`${result}\``)(useRef) - - if (!result.trim().startsWith("")) { - console.warn( - "You should wrap your html in a body tag, vader may not grab all html!" ); - } - - - - return this.parseHTML(result); - } - - + }; + worker.onerror = (e) => { + reject(e); + }; + }); + // @ts-ignore + return promise; } // write types to ensure it returns a string /** @@ -1133,9 +963,14 @@ const Vader = { * } */ Component: Component, - useRef: useRef, + useRef: useRef }; -export const component = (name) => { +/** + * @function component + * @description Allows you to create a component + * @returns {Component} + */ +export const component = () => { return new Component(); }; @@ -1151,81 +986,91 @@ export const rf = (name, fn) => { window[name] = fn; }; let cache = {}; -async function handletemplate(data){ +async function handletemplate(data) { let dom = new DOMParser().parseFromString(data, "text/html"); let elements = dom.documentElement.querySelectorAll("*"); - + if (elements.length > 0) { for (var i = 0; i < elements.length; i++) { - if (elements[i].nodeName === "INCLUDE") { - if(!elements[i].getAttribute("src") || elements[i].getAttribute("src") === ""){ - throw new Error("Include tag must have src attribute") + if ( + !elements[i].getAttribute("src") || + elements[i].getAttribute("src") === "" + ) { + throw new Error("Include tag must have src attribute"); } - - let componentName = elements[i].getAttribute("src")?.split("/").pop()?.split(".")[0] - // @ts-ignore - let filedata = await include(elements[i].getAttribute("src")) - // replace ` with \`\` to allow for template literals - filedata = filedata.replace(/`/g, "\\`") - cache[elements[i].getAttribute("src")] = filedata - filedata = new Function(`return \`${filedata}\`;`)(); - let newdom = new DOMParser().parseFromString(filedata, "text/html"); - newdom.querySelectorAll("include").forEach((el)=>{ - el.remove() - }) - // @ts-ignore - - let els = dom.querySelectorAll(componentName) - - els.forEach((el)=>{ - - if(el.attributes.length > 0){ - for(var i = 0; i < el.attributes.length; i++){ - newdom.body.outerHTML = newdom.body.outerHTML.replace(`{{${el.attributes[i].name}}}`, el.attributes[i].value) - } - - } - if(el.children.length > 0 && newdom.body.querySelector('slot')){ - for(var i = 0; i < el.children.length; i++){ - let slots = newdom.body.querySelectorAll("slot") - slots.forEach((slot)=>{ - let id = slot.getAttribute("id") - if(id === el.nodeName.toLowerCase()){ - slot.outerHTML = `
    ${el.innerHTML}
    ` - } - }) - - - } - - } + let componentName = elements[i] + .getAttribute("src") + ?.split("/") + .pop() + ?.split(".")[0]; + // @ts-ignore + let filedata = await include(elements[i].getAttribute("src")); + // replace ` with \`\` to allow for template literals + filedata = filedata.replace(/`/g, "\\`"); + cache[elements[i].getAttribute("src")] = filedata; + filedata = new Function(`return \`${filedata}\`;`)(); + let newdom = new DOMParser().parseFromString(filedata, "text/html"); - dom.body.querySelectorAll('include').forEach((el)=>{ - el.remove() - }) - // replace ` with \`\` to allow for template literals - dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`") - dom.body.outerHTML = dom.body.outerHTML.replace(el.outerHTML, new Function(`return \`${newdom.body.outerHTML}\`;`)()) - - - }) - - - + newdom.querySelectorAll("include").forEach((el) => { + el.remove(); + }); + // @ts-ignore + + let els = dom.querySelectorAll(componentName); + + els.forEach((el) => { + if (el.attributes.length > 0) { + for (var i = 0; i < el.attributes.length; i++) { + // @ts-ignore + let t = "{{" + el.attributes[i].name + "}}"; + if (newdom.body.innerHTML.includes(t)) { + // @ts-ignore + newdom.body.innerHTML = newdom.body.innerHTML.replaceAll( + t, + el.attributes[i].value + ); + } + } + } + if (el.children.length > 0 && newdom.body.querySelector("slot")) { + for (var i = 0; i < el.children.length; i++) { + let slots = newdom.body.querySelectorAll("slot"); + slots.forEach((slot) => { + let id = slot.getAttribute("id"); + + if ( + (el.hasAttribute("key") && el.getAttribute("key") === id) || + (!el.hasAttribute("key") && el.nodeName === id) + ) { + if (el.children[i].innerHTML.length > 0) { + slot.outerHTML = el.children[i].innerHTML; + } + } + }); + } + } + dom.body.querySelectorAll("include").forEach((el) => { + el.remove(); + }); + // replace ` with \`\` to allow for template literals + dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`"); + dom.body.outerHTML = dom.body.outerHTML.replace( + el.outerHTML, + new Function(`return \`${newdom.body.outerHTML}\`;`)() + ); + }); } } - - } - + // replace ` with \`\` to allow for template literals - dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`") + dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`"); data = new Function(`return \`${dom.body.outerHTML}\`;`)(); - - return data; + + return data; } /** * @function include @@ -1234,10 +1079,7 @@ async function handletemplate(data){ * @param {string} path */ - - export const include = async (path) => { - if ( path.startsWith("/") && !path.includes("/src/") && @@ -1247,26 +1089,27 @@ export const include = async (path) => { ) { path = "/src/" + path; } + // @ts-ignore if (cache[path]) { - return await handletemplate(new Function(`return \`${cache[path]}\`;`)()) - - }else{ + // @ts-ignore + return await handletemplate(new Function(`return \`${cache[path]}\`;`)()); + } else { return fetch(`./${path}`) - .then((res) => { - if (res.status === 404) { - throw new Error(`No file found at ${path}`); - } - return res.text(); - }) - .then(async (data) => { - cache[path] = data - - data = await handletemplate(new Function(`return \`${data}\`;`)()) - - return data - }); + .then((res) => { + if (res.status === 404) { + throw new Error(`No file found at ${path}`); + } + return res.text(); + }) + .then(async (data) => { + // @ts-ignore + cache[path] = data; + + data = await handletemplate(new Function(`return \`${data}\`;`)()); + + return data; + }); } - }; -export default Vader; +export default Vader \ No newline at end of file diff --git a/dist/vader/vaderDeveloperKit.js b/dist/vader/vaderDeveloperKit.js new file mode 100644 index 0000000..e69de29 diff --git a/dist/vader/worker.js b/dist/vader/worker.js index 4f3a687..ff46086 100644 --- a/dist/vader/worker.js +++ b/dist/vader/worker.js @@ -1,223 +1,303 @@ - -onmessage = (e)=>{ - let time_started = Date.now() - let strings = e.data.strings - let args = e.data.args - let js = '' - let l = e.data.location.split('/').slice(0,-1).join('/') - let result = ""; - for (let i = 0; i < strings.length; i++) { - result += strings[i]; - if (i < args.length) { - result += args[i]; +onmessage = (e) => { + let time_started = Date.now(); + let strings = e.data.strings; + let args = e.data.args; + let js = ""; + let l = e.data.location.split("/").slice(0, -1).join("/"); + let result = ""; + for (let i = 0; i < strings.length; i++) { + result += strings[i]; + if (i < args.length) { + result += args[i]; + } + } + + let comments = result.match(/--([^>]*)--/gs); + if (comments) { + while (comments.length) { + let comment = comments.pop(); + // @ts-ignore + result = result.replace(comment, ""); + } + } + + // Convert headings (e.g., #1-6 Heading => Heading) + // @ts-ignore + result = result.replace(/(#+)(.*)/g, (match, hashes, text) => { + if (!match.includes("<") || !match.includes(">")) { + let level = hashes.length; + return `${text}`; + } else { + return match; + } + }); + + // Convert bold (e.g., **Bold** => Bold) + result = result.replace(/\*\*(.*?)\*\*/g, (match, text) => { + return `${text}`; + }); + + // Convert italic (e.g., *Italic* => Italic) + result = result.replace(/\*(.*?)\*/g, (match, text) => { + return `${text}`; + }); + + // Convert code (e.g., `code` => code) + result = result.replace(/`(.*?)`/g, (match, text) => { + return `${text}`; + }); + + // Convert links (e.g., [Text](URL) => Text) + result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => { + return `${text}`; + }); + + // Convert images (e.g., ![Alt](URL) => Alt) + result = result.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, (match, alt, src) => { + return `${alt}`; + }); + + // Convert unordered lists (e.g., * Item => ) + result.split("\n").forEach((line, index, arr) => { + if (line.match(/^\s*-\s+(.*?)$/gm)) { + if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) { + result = result.replace( + line, + `` + ); + } else { + result = result.replace( + line, + `
  • ${line.replace(/^\s*-\s+(.*?)$/gm, "$1")}
  • ` + ); } } + }); - let comments = result.match(/--([^>]*)--/gs) - if(comments){ - while(comments.length){ - let comment = comments.pop() - console.log(comment) - // @ts-ignore - result = result.replace(comment,'') - } + // Convert ordered lists (e.g., 1. Item =>
    1. Item
    ) in order + + result.split("\n").forEach((line, index, arr) => { + if (line.match(/^\s*\d+\.\s+(.*?)$/gm)) { + if (index === 0 || !arr[index - 1].match(/^\s*\d+\.\s+(.*?)$/gm)) { + result = result.replace( + line, + `
    1. ${line.replace( + /^\s*\d+\.\s+(.*?)$/gm, + "$1" + )}
    2. ` + ); + } else if ( + index === arr.length - 1 || + !arr[index + 1].match(/^\s*\d+\.\s+(.*?)$/gm) + ) { + result = result.replace( + line, + `
    3. ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, "$1")}
    ` + ); + } else { + result = result.replace( + line, + `
  • ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, "$1")}
  • ` + ); + } } + }); - - // Convert headings (e.g., #1-6 Heading => Heading) - // @ts-ignore - result = result.replace(/(#+)(.*)/g, (match, hashes, text) => { - console.log(match) - if(!match.includes('<') || !match.includes('>')){ - let level = hashes.length; - return `${text}`; - }else{ - return match - } - }); - - - // Convert bold (e.g., **Bold** => Bold) - result = result.replace(/\*\*(.*?)\*\*/g, (match, text) => { - return `${text}`; - }); - - // Convert italic (e.g., *Italic* => Italic) - result = result.replace(/\*(.*?)\*/g, (match, text) => { - return `${text}`; - }); - - // Convert code (e.g., `code` => code) - result = result.replace(/`(.*?)`/g, (match, text) => { - return `${text}`; - }); - - // Convert links (e.g., [Text](URL) => Text) - result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => { - return `${text}`; - }); - - // Convert images (e.g., ![Alt](URL) => Alt) - result = result.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, (match, alt, src) => { - return `${alt}`; - }); - - // Convert unordered lists (e.g., * Item => ) - result.split('\n').forEach((line, index, arr) => { - if (line.match(/^\s*-\s+(.*?)$/gm)) { - if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) { - result = result.replace(line, ``); - } else { - result = result.replace(line, `
  • ${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}
  • `); - } - } - }); - - // Convert ordered lists (e.g., 1. Item =>
    1. Item
    ) in order - - result.split('\n').forEach((line, index, arr) => { - if (line.match(/^\s*\d+\.\s+(.*?)$/gm)) { - if (index === 0 || !arr[index - 1].match(/^\s*\d+\.\s+(.*?)$/gm)) { - result = result.replace(line, `
    1. ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}
    2. `); - } else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*\d+\.\s+(.*?)$/gm)) { - result = result.replace(line, `
    3. ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}
    `); - } else { - result = result.replace(line, `
  • ${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}
  • `); - } - } - }); + result = result.replace(/^\s*-\s+(.*?)$/gm, (match, text) => { + return `
  • ${text}
  • `; + }); + result = result.replace( + /^\s*---\s*$/gm, + '
    ' + ); - - result = result.replace(/^\s*-\s+(.*?)$/gm, (match, text) => { - return `
  • ${text}
  • `; + // Convert blockquotes (e.g., > Quote =>
    Quote
    ) + result = result.replace(/^\s*> (.*)$/gm, (match, text) => { + return `
    ${text}
    `; + }); + + // Convert tables (e.g., | Header | Cell | =>
    HeaderCell
    ) + result = result.replace( + /((?: *\|.*?)+)\n((?: *\|.*?)+)/gm, + (match, header, cell) => { + const headerCells = header.split("|").slice(1, -1); + const cells = cell.split("|").slice(1, -1); + let table = ''; + table += + ''; + headerCells.forEach((headerCell) => { + table += ``; }); - result = result.replace(/^\s*---\s*$/gm, '
    '); - - // Convert blockquotes (e.g., > Quote =>
    Quote
    ) - result = result.replace(/^\s*> (.*)$/gm, (match, text) => { - return `
    ${text}
    `; + table += + ''; + cells.forEach((cell) => { + table += ``; }); + table += "
    ${headerCell}
    ${cell}
    "; + return table; + } + ); - // Convert tables (e.g., | Header | Cell | =>
    HeaderCell
    ) - result = result.replace(/((?: *\|.*?)+)\n((?: *\|.*?)+)/gm, (match, header, cell) => { - const headerCells = header.split('|').slice(1, -1); - const cells = cell.split('|').slice(1, -1); - let table = ''; - table += ''; - headerCells.forEach((headerCell) => { - table += ``; - }); - table += ''; - cells.forEach((cell) => { - table += ``; + if (!result.includes("")) { + throw new Error( + `Vader Error: You must enclose your html in a body tag for all components. \n\n${result}` + ); + } + /** + * @type {string[]} + * @description - grabbing all className attributes and replace them with class + */ + // @ts-ignore + result = result.replace(/classname/g, "class"); + /** + * @type {string[]} + * @description - grabbing all image tags and replace the src attribute with the absolute path + */ + // @ts-ignore + let images = result.match(/]*)>/g); + if (images) { + for (let i = 0; i < images.length; i++) { + let image = images[i]; + let src = image.match(/src="([^"]*)"/); + let alt = image.match(/alt="([^"]*)"/); + + if (!alt && !result.includes("")) { + throw new Error( + `Vader Error: You must include an alt attribute in the image tag \n\n${image} of class ${e.data.name}. ` + ); + } + if (src) { + src.forEach((s) => { + if ( + !s.includes("http") && + !result.includes("") + ) { + result = result.replace(`src="${s}"`, `src="${l}/${s}"`); + } else if ( + !s.includes("http") && + s.startsWith(".") && + !result.includes("") + ) { + throw new Error( + `Vader Error: You cannot use absolute paths since relative paths are not disabled in ${e.data.file}. Use relative paths instead. \n\n${s}` + ); + } }); - table += '
    ${headerCell}
    ${cell}
    '; - return table; - }); - - - - if(!result.includes('')){ - throw new Error(`Vader Error: You must enclose your html in a body tag for all components. \n\n${result}`) + } + } + } + + let href = result.match(/href="([^"]*)"/g); + if (href) { + while (href.length) { + let h = href.pop(); + // @ts-ignore + h = h.replace('href="', "").replace('"', ""); + if ( + !h.includes("http") && + !result.includes("") + ) { + result = result.replace(`href="${h}"`, `href="#${h}"`); + } else if ( + !h.includes("http") && + h.startsWith(".") && + !result.includes("") + ) { + throw new Error( + `Vader Error: You cannot use absolute paths since relative paths are not disabled in ${e.data.file}. Use relative paths instead. \n\n${h}` + ); + } } - /** - * @type {string[]} - * @description - grabbing all className attributes and replace them with class - */ - // @ts-ignore - result = result.replace(/classname/g,'class') - /** - * @type {string[]} - * @description - grabbing all image tags and replace the src attribute with the absolute path - */ - // @ts-ignore - let images = result.match(/]*)>/g) - if(images){ - for(let i = 0; i < images.length; i++){ - let image = images[i] - let src = image.match(/src="([^"]*)"/) - let alt = image.match(/alt="([^"]*)"/) - if(src){ - if(!src[1].includes('http') || !result.includes('')){ - // @ts-ignore - result = result.replace(src[1],`${l}/${src[1]}`) - }else{ - throw new Error(`Vader Error: You cannot use relative paths in the src attribute of ${src[0]}. Use absolute paths instead. \n\n${src[0]}`) + } + + let time_ended = Date.now(); + let time_taken = time_ended - time_started; + let hasran = false; + if (l.includes("localhost") || (l.includes("127.0.0.1") && !hasran)) { + hasran = true; + result += `\$\{console.log('%c${e.data.name} component rendered in ${time_taken}ms')\}`; + } + + const d = result.split("")[0]; + js += script; } - if(!alt && !result.includes('')){ - throw new Error(`Vader Error: You must include an alt attribute in the image tag \n\n${image} of class ${e.data.name}. `) + }); + } + + let jstemplates = result.match(/(\$\(.*?\))/gs); + if (jstemplates) { + while (jstemplates.length) { + let jstemplate = jstemplates.pop(); + // @ts-ignore + result = result.replace( + // @ts-ignore + jstemplate, + // @ts-ignore + `$\{${jstemplate.replace("$(", "").replace(")", "")}\}` + ); + } + } + + let title = result.match(/@title '([^>]*)'/); + if (title) { + let t = title[1]; + let ti = `{document.title = "${t}", ""}`; + result = result.replace(title[0], "$" + ti); + } + // @ts-ignore + + let styles = result.match(/@style{([^>]*)};/gs); + if (styles) { + for (let i = 0; i < styles.length; i++) { + // make sure its in a tag + + if (!styles[i].includes("style")) { + continue; } + let style = styles[i]; + + + let s = style.match(/@style{([^>]*)};/); + // @ts-ignore - if(!caches.match(`${l}/${src[1]}`)){ - caches.open('vader').then((cache)=>{ - // @ts-ignore - cache.add(`${l}/${src[1]}`) - // @ts-ignore - console.log('cached', `${l}/${src[1]}`) - }).catch((err)=>{ - console.log(err) - }) - }else{ + s.forEach((style) => { + + let st = style.replace("@style{", "").replace("};", ""); + // @ts-ignore - console.log('already cached', caches.match(`${l}/${src[1]}`)) - } - } - } - - let href = result.match(/href="([^"]*)"/g) - if(href){ - while(href.length){ - let h = href.pop() - // @ts-ignore - h = h.replace('href="','').replace('"','') - if(!h.includes('http') || !result.includes('')){ - result = result.replace(`href="${h}"`,`href="#${h}"`) - }else{ - throw new Error(`Vader Error: You cannot use relative paths in ${e.data.file}. Use absolute paths instead. \n\n${h}`) - } - } - } - - let time_ended = Date.now() - let time_taken = time_ended - time_started - let hasran = false - if(l.includes('localhost') || l.includes('127.0.0.1') && !hasran){ - hasran = true - result+= `\$\{console.log('%c${e.data.name} component rendered in ${time_taken}ms','color:#fff;background:#000;padding:5px;border-radius:5px;font-size:12px;font-weight:bold'),""\}` - } - - - const d = result.split('')[0]; - js += script; - } + st = st.replaceAll(',', ';') + // @ts-ignore + st = st.replaceAll(/'/g, ' ') + + result = result.replace(style, `style="${st}"`); }); } - - let jstemplates = result.match(/(\$\(.*?\))/gs) - if(jstemplates){ - while(jstemplates.length){ - let jstemplate = jstemplates.pop() - // @ts-ignore - result = result.replace(jstemplate,`$\{${jstemplate.replace('$(','').replace(')','')}\}`) - } - } - postMessage({ - template: `
    ${result}
    `, - js: js ? js : '' - }) - - } \ No newline at end of file + } + + postMessage({ + template: `
    ${result}
    `, + js: js ? js : "" + }); +}; diff --git a/public/images/components.png b/public/images/components.png new file mode 100644 index 0000000..62c111a Binary files /dev/null and b/public/images/components.png differ diff --git a/src/components/nav.vjs b/src/components/nav.vjs index 0d383b2..9a8fb0b 100644 --- a/src/components/nav.vjs +++ b/src/components/nav.vjs @@ -12,7 +12,7 @@ border border-base-200 text-black bg-base-100 "> ${ $FULL_URL.includes("docs") ? "Docs" - : "Vader.js v1.3.0 " + : `Vader.js v1.3.2` } @@ -38,8 +38,11 @@ border border-base-200 text-black bg-base-100 ">
  • Profile - New + + + +
  • Settings
  • Logout
  • diff --git a/src/components/sidedrawer.vjs b/src/components/sidedrawer.vjs index 2e246b9..bfb0661 100644 --- a/src/components/sidedrawer.vjs +++ b/src/components/sidedrawer.vjs @@ -83,7 +83,9 @@ Tutorials
    - +
      + +
    @@ -127,6 +129,40 @@ + diff --git a/src/pages/Docs.js b/src/pages/Docs.js index 5704f9e..8c81f71 100644 --- a/src/pages/Docs.js +++ b/src/pages/Docs.js @@ -3,7 +3,7 @@ import Vader,{ include } from "../../dist/vader/vader.js"; export class Docs extends Vader.Component{ constructor(){ super() - this.cfr = true + } async render(p, asterisk){ diff --git a/src/pages/Home.js b/src/pages/Home.js index 3d73a8d..7e34b7d 100644 --- a/src/pages/Home.js +++ b/src/pages/Home.js @@ -4,28 +4,20 @@ export class Home extends Vader.Component { constructor() { super(); - this.cfr = true + this.cfr = true; } async render() { - let counter = this.signal('count', 0) - - - - let e = this.$Function((e)=>{ - counter.set(counter.get() + 1); - - }) - let test = await include('/views/home.html') return await this.html(test) } + // @ts-ignore componentUpdated(prev_state, prev_props, content){ console.log(prev_state); } diff --git a/src/pages/test.js b/src/pages/test.js new file mode 100644 index 0000000..8b2b4ec --- /dev/null +++ b/src/pages/test.js @@ -0,0 +1,6 @@ +import { component } from "../../dist/vader/vader"; + +export default function test(children) { + + return c.html(``); +} \ No newline at end of file diff --git a/src/views/doc.html b/src/views/doc.html new file mode 100644 index 0000000..e69de29 diff --git a/src/views/docs/base/getting-started.html b/src/views/docs/base/getting-started.html index 92c96a2..14cb023 100644 --- a/src/views/docs/base/getting-started.html +++ b/src/views/docs/base/getting-started.html @@ -3,9 +3,8 @@ - ${ - document.title = "Getting Started | Vader Docs", "" - } + @title 'Getting Started | Vader Docs' + @@ -66,12 +65,9 @@ ## Try In Your Browser - + - + \ No newline at end of file diff --git a/src/views/docs/basics/project-structure.html b/src/views/docs/basics/project-structure.html index 3f6a310..c78be26 100644 --- a/src/views/docs/basics/project-structure.html +++ b/src/views/docs/basics/project-structure.html @@ -1,6 +1,5 @@ -${ - document.title = "Project Structure | Vader Docs", "" -} +@title 'Project Structure | Vader Docs' + @@ -95,5 +94,6 @@

    Directories

    + - + \ No newline at end of file diff --git a/src/views/docs/basics/views.html b/src/views/docs/basics/views.html index bd8993e..e414d95 100644 --- a/src/views/docs/basics/views.html +++ b/src/views/docs/basics/views.html @@ -1,38 +1,54 @@ -${ - document.title = "Views | Vader Docs", "" -} +@title 'Views | Vader Docs' + - + -
    - -

    Views

    -

    - Views are vader components which are used to display content to the user. They help you organize your webapp into different page files, while also allowing you to embed them in one another. - Views use the src/ directory and can be included in other views using the <include/> tag. - Alternatively their is a include() function to include views inside of your top level js files! -

    -

    - There are no limitation to what you write inside of view files most the documentation you have read about vader is written in both html and markdown! - vader transpiles markdown code inside of your html/vjs files. - They also are returned as functions which means you can write js inside using $ { } . -

    -

    Link Between Views

    - -

    - After defining routes to your pages - vader looks for relative links for example /about and /contact are valid links to your pages. - These will be changed to #/about.html and #/contact.html respectively. -

    - -
    - - **Note** -

    - You can disable relative paths - using #vader_disable_relative-paths comment at the top of your file. -

    -
    - + +

    Views

    +

    + Views are vader components which are used to display content to the user. They help you organize your webapp + into different page files, while also allowing you to embed them in one another. + Views use the src/ directory and can be included in + other views using the <include/> tag. + Alternatively their is a include() function to include views inside of + your top level js files! +

    +

    + They offer remarkable flexibility, treating your content consistently whether it's written in Markdown or HTML. Your at no limitation to what you can write or do inside of then! + +

    +

    Creating Views

    +

    + After defining routes to your pages - vader looks for relative links for example /about and /contact are valid links to your pages. + These will be changed to #/about.html and #/contact.html respectively. +

    + +

    + Vader uses relative paths because often times it can be hard indexing folders. in a webapp - so vader uses relative paths to both the root public folder and the root src folder. + These two folders are required to be in the root of your project. +

    +
    + + **Note** +

    + You can disable relative paths - using #vader_disable_relative-paths + comment at the top of your file. +

    +
    + +

    Javascript

    +

    + Views have two ways of using js in your project views - we have the inline version ${'`'}