diff --git a/src/css/icons.css b/src/css/icons.css new file mode 100644 index 0000000..58ee1b8 --- /dev/null +++ b/src/css/icons.css @@ -0,0 +1,23 @@ +@font-face { + font-family: 'Material Symbols Rounded'; + font-style: normal; + font-weight: 100 700; + src: url(./icons.woff2) format('woff2'); +} + +.material-symbols-rounded { + font-family: 'Material Symbols Rounded'; + font-weight: normal; + font-style: normal; + font-size: 24px; + overflow: hidden; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; +} \ No newline at end of file diff --git a/src/css/icons.woff2 b/src/css/icons.woff2 new file mode 100644 index 0000000..16a9d96 Binary files /dev/null and b/src/css/icons.woff2 differ diff --git a/src/index.html b/src/index.html index edf25b1..d171099 100644 --- a/src/index.html +++ b/src/index.html @@ -5,6 +5,7 @@ Home + @@ -29,7 +30,8 @@ --> - + + diff --git a/src/js/abstract.js b/src/js/abstract.js deleted file mode 100644 index 1665493..0000000 --- a/src/js/abstract.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @typedef {Object} $ - * @property {function(object=, ...HTMLElement): HTMLElement} DOCS - creates element with this tagname -*/ - -/** - * ### Create element - * - * @type {$} - */ -const $ = new Proxy( - class { - /** - * ### Creates `$` element - * @param {string} type element type - * @param {object} props element properties (onclick, class, ...) - * @param {...HTMLElement} children - * @returns {HTMLElement} - */ - static createElement(type, props, ...children) { - const element = document.createElement(type) - - if (props) { - try { - if ( - props instanceof Node - || typeof props === 'string' - || typeof props === 'number' - ) children = [props, ...children] - else {throw Error()} - } catch { - for (const [key, value] of Object.entries(props)) { - if (key.startsWith('on') && typeof value === 'function') { - element.addEventListener(key.slice(2).toLowerCase(), value) - } else if (key === 'className') { - element.className = value - } else { - element.setAttribute(key, value) - } - } - } - } - children.flat().forEach(child => { - if (typeof child === 'string' || typeof child === 'number') { - element.innerHTML += child - } else if (child instanceof Node) { - element.appendChild(child) - } - }); - - element[Symbol.toPrimitive] = function(hint) { - if (hint === 'string') return this.outerHTML - return this - }; - - return element - } - }, - { - get(target, element) { - return function(props, ...children) { - return target.createElement(element, props, ...children) - } - } - } -); - diff --git a/src/lib/gicons.lib.js b/src/lib/gicons.lib.js new file mode 100644 index 0000000..d22d835 --- /dev/null +++ b/src/lib/gicons.lib.js @@ -0,0 +1,56 @@ +/** + * @typedef {Object} IconOptions + * @prop {100|200|300|400|500|600|700} weight Symbol weight + * @prop {bool} fill + * @prop {'low' | 'default' | 'high'} grade Symbol thickness + * @prop {20|48} optical_size (from 20 to 48) For the image to look the same at different sizes in dp + * @prop {number} size Icon size in px + * @prop {string} color Any css-supported color variant (names, rgb, hex) + */ + +var DEFAULT_ICON_COLOR = '#000' +var DEFAULT_ICON_SIZE = 24 +/** @type {IconOptions} */ +var DEFAULT_ICON_OPTIONS = {} + +/** @type {Record HTMLSpanElement} */ +const Icons = new Proxy( + class { + /** + * @param {string} name + * @param {IconOptions} options + * @returns {HTMLSpanElement} + */ + static getIcon(name, {fill, weight, grade, optical_size, size, color}) { + const gr = ({ + 'low': -25, + 'default': 0, + 'high': 200 + })[grade] + const data = ` + 'FILL' ${fill !== undefined ? fill?1:0 : 1}, + 'wdth' ${weight || 400}, + 'GRAD' ${gr || 0}, + 'opsz' ${optical_size || 20}` + const fz = size ? typeof size != Number ? `${size}px`:size : (DEFAULT_ICON_SIZE+'px') + return $.span( + {class: 'material-symbols-rounded icon', style: `font-size: ${fz}; width: ${fz}; height: ${fz}; ${color ? `color: ${color};` : ''}font-variation-settings: ${data}`}, + name + ) + } + }, + { + get(target, name) { + /** + * @argument {IconOptions} options + */ + return function(options) { + return target.getIcon(name, options || DEFAULT_ICON_OPTIONS) + } + } + } +) + +const gIconsInit = () => document.head.innerHTML += ` + +` \ No newline at end of file diff --git a/src/lib/sinya.lib.js b/src/lib/sinya.lib.js new file mode 100644 index 0000000..aa357ae --- /dev/null +++ b/src/lib/sinya.lib.js @@ -0,0 +1,226 @@ +/** + * @typedef {Object} $ + * @property {function(object=, ...HTMLElement): HTMLElement} div - creates div element + * @property {function(object=, ...HTMLElement): HTMLElement} p - creates p element + * @property {function(object=, ...HTMLElement): HTMLElement} span - creates span element + * @property {function(object=, ...HTMLElement): HTMLElement} button - creates button element + * @property {function(object=, ...HTMLElement): HTMLElement} input - creates input element + * @property {function(object=, ...HTMLElement): HTMLElement} a - creates a element + * @property {function(object=, ...HTMLElement): HTMLElement} img - creates img element + * @property {function(object=, ...HTMLElement): HTMLElement} h1 - creates h1 element + * @property {function(object=, ...HTMLElement): HTMLElement} h2 - creates h2 element + * @property {function(object=, ...HTMLElement): HTMLElement} h3 - creates h3 element + * @property {function(object=, ...HTMLElement): HTMLElement} h4 - creates h4 element + * @property {function(object=, ...HTMLElement): HTMLElement} h5 - creates h5 element + * @property {function(object=, ...HTMLElement): HTMLElement} h6 - creates h6 element + * @property {function(object=, ...HTMLElement): HTMLElement} ul - creates ul element + * @property {function(object=, ...HTMLElement): HTMLElement} li - creates li element + * @property {function(object=, ...HTMLElement): HTMLElement} form - creates form element + * @property {function(object=, ...HTMLElement): HTMLElement} table - creates table element + * @property {function(object=, ...HTMLElement): HTMLElement} tr - creates tr element + * @property {function(object=, ...HTMLElement): HTMLElement} td - creates td element +*/ + +/** + * ### Create element + * + * @type {$} + */ +const $ = new Proxy( + class { + /** + * ### Creates `$` element + * @param {string} type element type + * @param {object} props element properties (onclick, class, ...) + * @param {...HTMLElement} children + * @returns {HTMLElement} + */ + static createElement(type, props, ...children) { + const element = document.createElement(type) + + if (props) { + try { + if ( + props instanceof Node + || typeof props === 'string' + || typeof props === 'number' + ) children = [props, ...children] + else {throw Error()} + } catch { + for (const [key, value] of Object.entries(props)) { + if (key.startsWith('on') && typeof value === 'function') { + element.addEventListener(key.slice(2).toLowerCase(), value) + } else if (key === 'className') { + element.className = value + } else { + element.setAttribute(key, value) + } + } + } + } + children.flat().forEach(child => { + if (typeof child === 'string' || typeof child === 'number') { + element.innerHTML += child + } else if (child instanceof Node) { + element.appendChild(child) + } + }); + + element[Symbol.toPrimitive] = function(hint) { + if (hint === 'string') return this.outerHTML + return this + }; + + return element + } + }, + { + get(target, element) { + return function(props, ...children) { + return target.createElement(element, props, ...children) + } + } + } +); + + +/** + * Select single DOM element and wrap them + * @param {string} selector + * @returns {WrappedElement} + */ +const select = (selector, _target = document) => wrap(_target.querySelector(selector)) + +/** + * Select multiple DOM element and wrap them + * @param {string} selector + * @returns {Array.} + */ +const selectAll = (selector, _target = document) => [..._target.querySelectorAll(selector)].map(_ => wrap(_)) + +/** + * Wrap existing DOM element + * @param {HTMLElement} element + * @returns {WrappedElement} + */ +const wrap = element => new WrappedElement(element) + +const sleep = s => new Promise(r => setTimeout(r, s*1000)) + + +class WrappedElement { + /** + * @type {HTMLElement} + */ + element + + /** + * Create element wrapper + * @param {HTMLElement} element + */ + constructor(element) { + this.element = element + } + + /** + * Override element classes + * @param {...string} list + * @returns {WrappedElement} this element for chaining + */ + classes(...list) { + this.element.classList = list.join(' ') + return this + } + + /** + * Get elements styles to edit them + * @returns {CSSStyleDeclaration} + */ + styles () { + return this.element.style + } + + /** + * Get element nodes + * @returns {Array.} + */ + nodes () { + return [...this.element.childNodes].map(e => wrap(e)) + } + + /** + * Apply animation to element (async) + * @param {string} animation_name + * @param {number} animation_duration + * @param {string} animation_function_name + * @returns {WrappedElement} this element for chaining + */ + async animate (animation_name, animation_duration, animation_function_name = '') { + this.styles().animation = `${animation_name} ${animation_duration}s ${animation_function_name}` + await sleep(animation_duration - (animation_duration / 20)) + this.styles().animation = `` + return this + } + + /** + * Clear element content (async) + * @returns {WrappedElement} this element for chaining + */ + async clear () { + this.element.innerHTML = '' + return this + } + + /** + * Overwrite element content (async) + * @param {...HTMLElement} children + * @returns {WrappedElement} this element for chaining + */ + async overwrite (...children) { + this.clear() + this.append(...children) + return this + } + /** + * Add content to element (async) + * @param {...HTMLElement} children + * @returns {WrappedElement} this element for chaining + */ + async append (...children) { + children.forEach(child => { + if (typeof child === 'string' || typeof child === 'number') { + this.element.innerHTML += child + } else if (child instanceof Node) { + this.element.appendChild(child) + } else if (child instanceof WrappedElement) { + this.element.appendChild(child.element) + } + }) + return this + } + /** + * Removes element (async) + */ + async remove() { + this.element.remove() + } + + /** + * Return element node by selector + * @param {string} selector + * @returns {WrappedElement} + */ + select (selector) { + return select(selector, this.element) + } + /** + * Return element nodes by selector + * @param {string} selector + * @returns {Array.} + */ + selectAll (selector) { + return selectAll(selector, this.element) + } +} + +const Body = select('body') \ No newline at end of file