diff --git a/extension/helpers.js b/extension/helpers.js index 50ae2c4..81ad92b 100644 --- a/extension/helpers.js +++ b/extension/helpers.js @@ -53,6 +53,13 @@ web.createElement = (html) => { .join(''); return template.content.firstElementChild; }; +web.htmlEscape = (str) => + str + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/'/g, ''') + .replace(/"/g, '"'); /** * @param {string} sheet diff --git a/extension/icons/blackwhite.svg b/extension/icons/blackwhite.svg index 12da3b0..0176e24 100644 --- a/extension/icons/blackwhite.svg +++ b/extension/icons/blackwhite.svg @@ -1,4 +1,4 @@ -<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<svg viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <path d="M250 0H0V250H250V0Z" fill="url(#pattern0)"/> <rect x="77" y="86" width="119" height="120" fill="white"/> <g filter="url(#filter0_d)"> diff --git a/extension/icons/colour.svg b/extension/icons/colour.svg index 958c24b..a56e457 100644 --- a/extension/icons/colour.svg +++ b/extension/icons/colour.svg @@ -1,4 +1,4 @@ -<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<svg viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <path d="M250 0H0V250H250V0Z" fill="url(#pattern0)"/> <rect x="77" y="86" width="119" height="120" fill="white"/> <path d="M161 131L145 118L138 126.5L154 139.5L161 131Z" fill="white"/> diff --git a/extension/icons/fontawesome/caret-down.svg b/extension/icons/fontawesome/caret-down.svg new file mode 100644 index 0000000..b8b0772 --- /dev/null +++ b/extension/icons/fontawesome/caret-down.svg @@ -0,0 +1,2 @@ +<!-- https://fontawesome.com/icons/caret-down?style=solid --> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path></svg> \ No newline at end of file diff --git a/extension/icons/fontawesome/code.svg b/extension/icons/fontawesome/code.svg new file mode 100644 index 0000000..62763ca --- /dev/null +++ b/extension/icons/fontawesome/code.svg @@ -0,0 +1,2 @@ +<!-- https://fontawesome.com/icons/code?style=solid --> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M278.9 511.5l-61-17.7c-6.4-1.8-10-8.5-8.2-14.9L346.2 8.7c1.8-6.4 8.5-10 14.9-8.2l61 17.7c6.4 1.8 10 8.5 8.2 14.9L293.8 503.3c-1.9 6.4-8.5 10.1-14.9 8.2zm-114-112.2l43.5-46.4c4.6-4.9 4.3-12.7-.8-17.2L117 256l90.6-79.7c5.1-4.5 5.5-12.3.8-17.2l-43.5-46.4c-4.5-4.8-12.1-5.1-17-.5L3.8 247.2c-5.1 4.7-5.1 12.8 0 17.5l144.1 135.1c4.9 4.6 12.5 4.4 17-.5zm327.2.6l144.1-135.1c5.1-4.7 5.1-12.8 0-17.5L492.1 112.1c-4.8-4.5-12.4-4.3-17 .5L431.6 159c-4.6 4.9-4.3 12.7.8 17.2L523 256l-90.6 79.7c-5.1 4.5-5.5 12.3-.8 17.2l43.5 46.4c4.5 4.9 12.1 5.1 17 .6z"></path></svg> \ No newline at end of file diff --git a/extension/icons/fontawesome/file.svg b/extension/icons/fontawesome/file.svg new file mode 100644 index 0000000..89a009e --- /dev/null +++ b/extension/icons/fontawesome/file.svg @@ -0,0 +1,2 @@ +<!-- https://fontawesome.com/icons/file?style=solid --> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm160-14.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"/></svg> \ No newline at end of file diff --git a/extension/icons/fontawesome/long-arrow-alt-left.svg b/extension/icons/fontawesome/long-arrow-alt-left.svg new file mode 100644 index 0000000..e680e12 --- /dev/null +++ b/extension/icons/fontawesome/long-arrow-alt-left.svg @@ -0,0 +1,2 @@ +<!-- https://fontawesome.com/icons/long-arrow-alt-left?style=solid --> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M134.059 296H436c6.627 0 12-5.373 12-12v-56c0-6.627-5.373-12-12-12H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.569 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296z"></path></svg> \ No newline at end of file diff --git a/extension/icons/fontawesome/long-arrow-alt-right.svg b/extension/icons/fontawesome/long-arrow-alt-right.svg new file mode 100644 index 0000000..13a4808 --- /dev/null +++ b/extension/icons/fontawesome/long-arrow-alt-right.svg @@ -0,0 +1,2 @@ +<!-- https://fontawesome.com/icons/long-arrow-alt-right?style=solid --> +<span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z"></path></svg> \ No newline at end of file diff --git a/extension/manifest.json b/extension/manifest.json index d8c8acb..5b8ba40 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -17,7 +17,7 @@ }, "web_accessible_resources": [ { - "resources": ["icons/*", "repo/*", "helpers.js"], + "resources": ["helpers.js", "repo/*", "icons/*", "dep/*"], "matches": ["https://*.notion.so/*"] } ], diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css index da95868..7b2e43f 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css @@ -88,9 +88,6 @@ main section[data-container] article { main section[data-container] article img { max-width: 100%; } -main section[data-container] article > img { - border-bottom: 1px solid var(--theme--divider); -} main section[data-container] article > div { padding: 1rem; } @@ -132,6 +129,9 @@ main section[data-container] article > div { fill: var(--theme--text_property); } +.library--preview { + border-bottom: 1px solid var(--theme--divider); +} .library--version { font-weight: normal; font-size: 0.8rem; diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js index 470faaa..e555aa8 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js @@ -14,65 +14,79 @@ for (let mod of await registry.get()) { } } -const components = { - preview({ preview }) { - if (!preview) return ''; - const element = web.createElement( - `<img alt="" class="library--preview" src="${preview}" />` - ); - return element; - }, - name({ name, id, version }) { - const element = web.createElement(`<label for="enable--${id}" class="library--title library--toggle_label"> - <input type="checkbox" id="enable--${id}" /> - <h2><span>${name} <span class="library--version">v${version}</span></span> - <span class="library--toggle"></span></h2></label>`); - return element; - }, - tags({ tags }) { - if (!tags || !tags.length) return ''; - const element = web.createElement( - `<ul class="library--tags">${tags.map((tag) => `<li>#${tag}</li>`).join('')}</ul>` - ); - return element; - }, - description({ description }) { - const element = web.createElement( - `<p class="library--description">${markdown.renderInline(description)}</p>` - ); - return element; - }, - authors({ authors }) { - const element = web.createElement( - `<ul class="library--authors">${authors +// why a tagged template? because it syntax highlights +const html = (html, ...templates) => + html.map((str) => str + (templates.shift() || '')).join(''); + +const views = {}; +views.components = { + card: { + preview: ({ preview = '' }) => + web.createElement( + html`<img + alt="" + class="library--preview" + src="${web.htmlEscape(preview)}" + onerror="this.remove()" + />` + ), + name: ({ name, id, version }) => + web.createElement( + html`<label + for="enable--${web.htmlEscape(id)}" + class="library--title library--toggle_label" + > + <input type="checkbox" id="enable--${web.htmlEscape(id)}" /> + <h2> + <span> + ${web.htmlEscape(name)} + <span class="library--version">v${web.htmlEscape(version)}</span> + </span> + <span class="library--toggle"></span> + </h2> + </label>` + ), + tags: ({ tags = [] }) => + web.createElement( + html`<ul class="library--tags"> + ${tags.map((tag) => html`<li>#${tag}</li>`).join('')} + </ul>` + ), + description: ({ description }) => + html`<p class="library--description">${markdown.renderInline(description)}</p>`, + authors: ({ authors }) => + html`<ul class="library--authors"> + ${authors .map( (author) => - `<li><a href="${author.url}"><img src="${author.icon}"/> <span>${author.name}</span></a></li>` + html`<li> + <a href="${author.url}" + ><img src="${author.icon}" /> <span>${author.name}</span></a + > + </li>` ) - .join('')}</ul>` + .join('')} + </ul>`, + async expand({ id }) { + const element = web.createElement( + `<p class="library--expand"><a href="?mod=${id}">${await fs.getText( + 'icons/fontawesome/long-arrow-alt-right.svg' + )}</span> <span>settings & documentation</span></a></p>` ); return element; }, - expand({ id }) { - const element = web.createElement(`<p class="library--expand"><a href="?mod=${id}"> - <!-- https://fontawesome.com/icons/long-arrow-alt-right?style=solid --> - <span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" - d="M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z"> - </path></svg></span> <span>settings & documentation</span></a></p>`); - return element; - }, + }, + options: { toggle(id, { key, label, value }) { const element = web.createElement(`<label for="toggle--${id}.${key}" class="library--toggle_label"> <input type="checkbox" id="toggle--${id}.${key}" /> <p><span>${label}</span><span class="library--toggle"></span></p></label>`); return element; }, - select(id, { key, label, values }) { + async select(id, { key, label, values }) { const element = web.createElement(`<label for="select--${id}.${key}" class="library--select_label"> <p>${label}</p><p class="library--select"><span> - <!-- https://fontawesome.com/icons/caret-down?style=solid --> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"> - <path fill="currentColor" d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path></svg></span> + ${await fs.getText('icons/fontawesome/caret-down.svg')}</span> <select id="select--${id}.${key}">${values.map( (value) => `<option value="${value}">${value}</option>` )}</select></p></label>`); @@ -92,61 +106,139 @@ const components = { <p>${label}</p><input id="number--${id}.${key}" type="number"></inpu></label>`); return element; }, - file(id, { key, label, extensions }) { + }, +}; + +const components = { + preview: ({ preview = '' }) => + web.createElement( + html`<img alt="" class="library--preview" src="${preview}" onerror="this.remove()" />` + ), + name: ({ name, id, version }) => + web.createElement(`<label for="enable--${id}" class="library--title library--toggle_label"> + <input type="checkbox" id="enable--${id}" /><h2><span>${name} <span class="library--version">v${version}</span></span> + <span class="library--toggle"></span></h2></label>`), + tags({ tags }) { + if (!tags || !tags.length) return ''; + const element = web.createElement( + `<ul class="library--tags">${tags.map((tag) => `<li>#${tag}</li>`).join('')}</ul>` + ); + return element; + }, + description({ description }) { + const element = web.createElement( + `<p class="library--description">${markdown.renderInline(description)}</p>` + ); + return element; + }, + authors: ({ authors }) => + html`<ul class="library--authors"> + ${authors + .map( + (author) => + html`<li> + <a href="${author.url}" + ><img src="${author.icon}" /> <span>${author.name}</span></a + > + </li>` + ) + .join('')} + </ul>`, + async expand({ id }) { + const element = web.createElement( + `<p class="library--expand"><a href="?mod=${id}">${await fs.getText( + 'icons/fontawesome/long-arrow-alt-right.svg' + )}</span> <span>settings & documentation</span></a></p>` + ); + return element; + }, + toggle(id, { key, label, value }) { + const element = web.createElement(`<label for="toggle--${id}.${key}" class="library--toggle_label"> + <input type="checkbox" id="toggle--${id}.${key}" /> + <p><span>${label}</span><span class="library--toggle"></span></p></label>`); + return element; + }, + async select(id, { key, label, values }) { + const element = web.createElement(`<label for="select--${id}.${key}" class="library--select_label"> + <p>${label}</p><p class="library--select"><span> + ${await fs.getText('icons/fontawesome/caret-down.svg')}</span> + <select id="select--${id}.${key}">${values.map( + (value) => `<option value="${value}">${value}</option>` + )}</select></p></label>`); + return element; + }, + text(id, { key, label, value }) { + const element = web.createElement(`<label for="text--${id}.${key}" class="library--text_label"> + <p>${label}</p><textarea id="text--${id}.${key}" rows="1"></textarea></label>`); + element.querySelector('textarea').addEventListener('input', (ev) => { + ev.target.style.removeProperty('--txt--scroll-height'); + ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px'); + }); + return element; + }, + number(id, { key, label, value }) { + const element = web.createElement(`<label for="number--${id}.${key}" class="library--number_label"> + <p>${label}</p><input id="number--${id}.${key}" type="number"></inpu></label>`); + return element; + }, + async file(id, { key, label, extensions }) { const accept = extensions && extensions.length ? ` accept="${extensions.join(',')}"` : ''; const element = web.createElement(`<label for="file--${id}.${key}" class="library--file_label"> <input type="file" id="file--${id}.${key}"${accept}/><p>${label}</p> - <p class="library--file"><span><!-- https://fontawesome.com/icons/file?style=solid --> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" - d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm160-14.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z" - /></svg></span><span class="library--file_path">choose file...</span></p></label>`); + <p class="library--file"><span>${await fs.getText( + 'icons/fontawesome/file.svg' + )}</span><span class="library--file_path">choose file...</span></p></label>`); element.querySelector('input[type="file"]').addEventListener('change', (ev) => { element.querySelector('.library--file_path').innerText = ev.target.files[0].name; }); return element; }, - documentation_buttons({ _dir }) { + async documentation_buttons({ _dir }) { const element = web.createElement(`<p class="documentation--buttons"> - <a href="?"><!-- https://fontawesome.com/icons/long-arrow-alt-left?style=solid --> - <span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" - d="M134.059 296H436c6.627 0 12-5.373 12-12v-56c0-6.627-5.373-12-12-12H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.569 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296z"> - </path></svg></span> <span>back to library</span></a> + <a href="?"> + <span> + ${await fs.getText( + 'icons/fontawesome/long-arrow-alt-left.svg' + )}</span> <span>back to library</span></a> <a href="https://github.com/notion-enhancer/extension/tree/main/repo/${encodeURIComponent( _dir - )}"><!-- https://fontawesome.com/icons/code?style=solid --> - <span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" - d="M278.9 511.5l-61-17.7c-6.4-1.8-10-8.5-8.2-14.9L346.2 8.7c1.8-6.4 8.5-10 14.9-8.2l61 17.7c6.4 1.8 10 8.5 8.2 14.9L293.8 503.3c-1.9 6.4-8.5 10.1-14.9 8.2zm-114-112.2l43.5-46.4c4.6-4.9 4.3-12.7-.8-17.2L117 256l90.6-79.7c5.1-4.5 5.5-12.3.8-17.2l-43.5-46.4c-4.5-4.8-12.1-5.1-17-.5L3.8 247.2c-5.1 4.7-5.1 12.8 0 17.5l144.1 135.1c4.9 4.6 12.5 4.4 17-.5zm327.2.6l144.1-135.1c5.1-4.7 5.1-12.8 0-17.5L492.1 112.1c-4.8-4.5-12.4-4.3-17 .5L431.6 159c-4.6 4.9-4.3 12.7.8 17.2L523 256l-90.6 79.7c-5.1 4.5-5.5 12.3-.8 17.2l43.5 46.4c4.5 4.9 12.1 5.1 17 .6z"> - </path></svg></span> <span>view source code</span></a> + )}"> + <span> + ${await fs.getText( + 'icons/fontawesome/code.svg' + )}</span> <span>view source code</span></a> </p>`); return element; }, }, generators = { - summary_card(mod) { + async summary_card(mod) { const article = web.createElement('<article class="library--summary_card"></article>'), body = web.createElement('<div></div>'); - article.append(components.preview(mod)); - body.append(components.name(mod)); - body.append(components.tags(mod)); - body.append(components.description(mod)); - body.append(components.authors(mod)); - body.append(components.expand(mod)); + article.append(await components.preview(mod)); + body.append(await components.name(mod)); + body.append(await components.tags(mod)); + body.append(await components.description(mod)); + body.append(await components.authors(mod)); + body.append(await components.expand(mod)); article.append(body); return article; }, - full_card(mod) { + async full_card(mod) { const article = web.createElement('<article class="library--full_card"></article>'), body = web.createElement('<div></div>'); - article.append(components.preview(mod)); - body.append(components.name(mod)); - body.append(components.tags(mod)); - body.append(components.description(mod)); - body.append(components.authors(mod)); + article.append(await components.preview(mod)); + body.append(await components.name(mod)); + body.append(await components.tags(mod)); + body.append(await components.description(mod)); + body.append(await components.authors(mod)); article.append(body); if (mod.options && mod.options.length) { const options = web.createElement(`<div class="library--options"></div>`); - mod.options.forEach((opt) => options.append(components[opt.type](mod.id, opt))); + ( + await Promise.all(mod.options.map((opt) => components[opt.type](mod.id, opt))) + ).map((opt) => options.append(opt)); article.append(options); } return article; @@ -170,7 +262,8 @@ const components = { const $container = document.querySelector('[data-container]'); $container.dataset.container = 'library'; $container.innerHTML = ''; - for (let mod of await registry.get()) $container.append(generators.summary_card(mod)); + for (let mod of await registry.get()) + $container.append(await generators.summary_card(mod)); }, }, mod: { @@ -181,8 +274,8 @@ const components = { const $container = document.querySelector('[data-container]'); $container.dataset.container = 'page'; $container.innerHTML = ''; - $container.append(components.documentation_buttons(mod)); - $container.append(generators.full_card(mod)); + $container.append(await components.documentation_buttons(mod)); + $container.append(await generators.full_card(mod)); $container.append(await generators.documentation(mod)); }, },