diff --git a/static/css/xess.css b/static/css/xess.css new file mode 100644 index 0000000..618eb3b --- /dev/null +++ b/static/css/xess.css @@ -0,0 +1,74 @@ +main { + font-family: monospace, monospace; + max-width: 38rem; + padding: 2rem; + margin: auto; +} + +@media only screen and (max-device-width: 736px) { + main { + padding: 0rem; + } +} + +::selection { + background: #d3869b; +} + +body { + background: #282828; + color: #ebdbb2; +} + +pre { + background-color: #3c3836; + padding: 1em; + border: 0; +} + +a, a:active, a:visited { + color: #b16286; + background-color: #1d2021; +} + +h1, h2, h3, h4, h5 { + margin-bottom: .1rem; +} + +blockquote { + border-left: 1px solid #bdae93; + margin: 0.5em 10px; + padding: 0.5em 10px; +} + +footer { + align: center; +} + +@media (prefers-color-scheme: light) { + body { + background: #fbf1c7; + color: #3c3836; + } + + pre { + background-color: #ebdbb2; + padding: 1em; + border: 0; + } + + a, a:active, a:visited { + color: #b16286; + background-color: #f9f5d7; + } + + h1, h2, h3, h4, h5 { + margin-bottom: .1rem; + } + + blockquote { + border-left: 1px solid #655c54; + margin: 0.5em 10px; + padding: 0.5em 10px; + } +} diff --git a/static/js/xeact-html.js b/static/js/xeact-html.js new file mode 100644 index 0000000..5da2a85 --- /dev/null +++ b/static/js/xeact-html.js @@ -0,0 +1,34 @@ +import { h, t } from "./xeact.js"; +const $tl = (kind) => (text, attrs = {}, children = []) => { + children.unshift(t(text)); + return h(kind, attrs, children); +}; +export const h1 = $tl("h1"); +export const h2 = $tl("h2"); +export const h3 = $tl("h3"); +export const h4 = $tl("h4"); +export const h5 = $tl("h5"); +export const h6 = $tl("h6"); +export const p = $tl("p"); +export const b = $tl("b"); +export const i = $tl("i"); +export const u = $tl("u"); +export const dd = $tl("dd"); +export const dt = $tl("dt"); +export const del = $tl("del"); +export const sub = $tl("sub"); +export const sup = $tl("sup"); +export const strong = $tl("strong"); +export const small = $tl("small"); +export const hl = () => h("hl"); +export const br = () => h("br"); +export const img = (src, alt="") => h("img", {src, alt}); +export const ahref = (href, text) => h("a", {href}, t(text)); +const $dl = (kind) => (attrs = {}, children = []) => h(kind, attrs, children); +export const span = $dl("span"); +export const div = $dl("div"); +export const ul = $dl("ul"); +export const iframe = (src, attrs = {}) => { + attrs["src"] = src; + return h("iframe", attrs); +}; diff --git a/static/js/xeact.js b/static/js/xeact.js new file mode 100644 index 0000000..4f2f615 --- /dev/null +++ b/static/js/xeact.js @@ -0,0 +1,88 @@ +/** + * Creates a DOM element, assigns the properties of `data` to it, and appends all `children`. + * + * @type{function(string, Object=, Node|Array.=)} + */ +const h = (name, data = {}, children = []) => { + let result = Object.assign(document.createElement(name), data); + if (!Array.isArray(children)) { + children = [children]; + } + result.append(...children); + return result; +}; + +/** + * Create a text node. + * + * Equivalent to `document.createTextNode(text)` + * + * @type{function(string): Text} + */ +const t = (text) => document.createTextNode(text); + +/** + * Remove all child nodes from a DOM element. + * + * @type{function(Node)} + */ +const x = (elem) => { + while (elem.lastChild) { + elem.removeChild(elem.lastChild); + } +}; + +/** + * Get all elements with the given ID. + * + * Equivalent to `document.getElementById(name)` + * + * @type{function(string): HTMLElement} + */ +const g = (name) => document.getElementById(name); + +/** + * Get all elements with the given class name. + * + * Equivalent to `document.getElementsByClassName(name)` + * + * @type{function(string): HTMLCollectionOf.} + */ +const c = (name) => document.getElementsByClassName(name); + +/** @type{function(string): HTMLCollectionOf.} */ +const n = (name) => document.getElementsByName(name); + +/** + * Get all elements matching the given HTML selector. + * + * Matches selectors with `document.querySelectorAll(selector)` + * + * @type{function(string): Array.} + */ +const s = (selector) => Array.from(document.querySelectorAll(selector)); + +/** + * Generate a relative URL from `url`, appending all key-value pairs from `params` as URL-encoded parameters. + * + * @type{function(string=, Object=): string} + */ +const u = (url = "", params = {}) => { + let result = new URL(url, window.location.href); + Object.entries(params).forEach((kv) => { + let [k, v] = kv; + result.searchParams.set(k, v); + }); + return result.toString(); +}; + +/** + * Takes a callback to run when all DOM content is loaded. + * + * Equivalent to `window.addEventListener('DOMContentLoaded', callback)` + * + * @type{function(function())} + */ +const r = (callback) => window.addEventListener('DOMContentLoaded', callback); + +export { h, t, x, g, c, n, u, s, r };