syntax higlighting ✔ (needs proper theming)

This commit is contained in:
dragonwocky 2021-04-21 11:51:21 +10:00
parent 93e764fb0a
commit d58d5b1850
8 changed files with 910 additions and 102 deletions

507
extension/dep/prism.css Normal file
View File

@ -0,0 +1,507 @@
/* PrismJS 1.23.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+asciidoc+aspnet+asm6502+autohotkey+autoit+bash+basic+batch+bbcode+birb+bison+bnf+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+clojure+cmake+cobol+coffeescript+concurnas+csp+coq+crystal+css-extras+csv+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gcode+gdscript+gedcom+gherkin+git+glsl+go+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keyman+kotlin+kumir+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+makefile+markdown+markup-templating+matlab+mel+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+jsx+tsx+reason+regex+rego+renpy+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+iecst+stylus+swift+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+turtle+twig+typescript+typoscript+unrealscript+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+wiki+xeora+xml-doc+xojo+xquery+yaml+yang+zig&plugins=autolinker+show-language+inline-color+previewers+normalize-whitespace+data-uri-highlight+toolbar+copy-to-clipboard */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*='language-'],
pre[class*='language-'] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*='language-']::-moz-selection,
pre[class*='language-'] ::-moz-selection,
code[class*='language-']::-moz-selection,
code[class*='language-'] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*='language-']::selection,
pre[class*='language-'] ::selection,
code[class*='language-']::selection,
code[class*='language-'] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*='language-'],
pre[class*='language-'] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*='language-'] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*='language-'],
pre[class*='language-'] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*='language-'] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.token.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
/* This background color was intended by the author of this theme. */
background: hsla(0, 0%, 100%, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #dd4a68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token a {
color: inherit;
}
div.code-toolbar {
position: relative;
}
div.code-toolbar > .toolbar {
position: absolute;
top: 0.3em;
right: 0.2em;
transition: opacity 0.3s ease-in-out;
opacity: 0;
}
div.code-toolbar:hover > .toolbar {
opacity: 1;
}
/* Separate line b/c rules are thrown out if selector is invalid.
IE11 and old Edge versions don't support :focus-within. */
div.code-toolbar:focus-within > .toolbar {
opacity: 1;
}
div.code-toolbar > .toolbar .toolbar-item {
display: inline-block;
}
div.code-toolbar > .toolbar a {
cursor: pointer;
}
div.code-toolbar > .toolbar button {
background: none;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none; /* for button */
-moz-user-select: none;
-ms-user-select: none;
}
div.code-toolbar > .toolbar a,
div.code-toolbar > .toolbar button,
div.code-toolbar > .toolbar span {
color: #bbb;
font-size: 0.8em;
padding: 0 0.5em;
background: #f5f2f0;
background: rgba(224, 224, 224, 0.2);
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2);
border-radius: 0.5em;
}
div.code-toolbar > .toolbar a:hover,
div.code-toolbar > .toolbar a:focus,
div.code-toolbar > .toolbar button:hover,
div.code-toolbar > .toolbar button:focus,
div.code-toolbar > .toolbar span:hover,
div.code-toolbar > .toolbar span:focus {
color: inherit;
text-decoration: none;
}
span.inline-color-wrapper {
/*
* The background image is the following SVG inline in base 64:
*
* <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2">
* <path fill="gray" d="M0 0h2v2H0z"/>
* <path fill="white" d="M0 0h1v1H0zM1 1h1v1H1z"/>
* </svg>
*
* SVG-inlining explained:
* https://stackoverflow.com/a/21626701/7595472
*/
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyIDIiPjxwYXRoIGZpbGw9ImdyYXkiIGQ9Ik0wIDBoMnYySDB6Ii8+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0wIDBoMXYxSDB6TTEgMWgxdjFIMXoiLz48L3N2Zz4=');
/* This is to prevent visual glitches where one pixel from the repeating pattern could be seen. */
background-position: center;
background-size: 110%;
display: inline-block;
height: 1.333ch;
width: 1.333ch;
margin: 0 0.333ch;
box-sizing: border-box;
border: 1px solid white;
outline: 1px solid rgba(0, 0, 0, 0.5);
overflow: hidden;
}
span.inline-color {
display: block;
/* To prevent visual glitches again */
height: 120%;
width: 120%;
}
.prism-previewer,
.prism-previewer:before,
.prism-previewer:after {
position: absolute;
pointer-events: none;
}
.prism-previewer,
.prism-previewer:after {
left: 50%;
}
.prism-previewer {
margin-top: -48px;
width: 32px;
height: 32px;
margin-left: -16px;
opacity: 0;
-webkit-transition: opacity 0.25s;
-o-transition: opacity 0.25s;
transition: opacity 0.25s;
}
.prism-previewer.flipped {
margin-top: 0;
margin-bottom: -48px;
}
.prism-previewer:before,
.prism-previewer:after {
content: '';
position: absolute;
pointer-events: none;
}
.prism-previewer:before {
top: -5px;
right: -5px;
left: -5px;
bottom: -5px;
border-radius: 10px;
border: 5px solid #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75);
}
.prism-previewer:after {
top: 100%;
width: 0;
height: 0;
margin: 5px 0 0 -7px;
border: 7px solid transparent;
border-color: rgba(255, 0, 0, 0);
border-top-color: #fff;
}
.prism-previewer.flipped:after {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: 5px;
border-top-color: rgba(255, 0, 0, 0);
border-bottom-color: #fff;
}
.prism-previewer.active {
opacity: 1;
}
.prism-previewer-angle:before {
border-radius: 50%;
background: #fff;
}
.prism-previewer-angle:after {
margin-top: 4px;
}
.prism-previewer-angle svg {
width: 32px;
height: 32px;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.prism-previewer-angle[data-negative] svg {
-webkit-transform: scaleX(-1) rotate(-90deg);
-moz-transform: scaleX(-1) rotate(-90deg);
-ms-transform: scaleX(-1) rotate(-90deg);
-o-transform: scaleX(-1) rotate(-90deg);
transform: scaleX(-1) rotate(-90deg);
}
.prism-previewer-angle circle {
fill: transparent;
stroke: hsl(200, 10%, 20%);
stroke-opacity: 0.9;
stroke-width: 32;
stroke-dasharray: 0, 500;
}
.prism-previewer-gradient {
background-image: linear-gradient(
45deg,
#bbb 25%,
transparent 25%,
transparent 75%,
#bbb 75%,
#bbb
),
linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
width: 64px;
margin-left: -32px;
}
.prism-previewer-gradient:before {
content: none;
}
.prism-previewer-gradient div {
position: absolute;
top: -5px;
left: -5px;
right: -5px;
bottom: -5px;
border-radius: 10px;
border: 5px solid #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75);
}
.prism-previewer-color {
background-image: linear-gradient(
45deg,
#bbb 25%,
transparent 25%,
transparent 75%,
#bbb 75%,
#bbb
),
linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
}
.prism-previewer-color:before {
background-color: inherit;
background-clip: padding-box;
}
.prism-previewer-easing {
margin-top: -76px;
margin-left: -30px;
width: 60px;
height: 60px;
background: #333;
}
.prism-previewer-easing.flipped {
margin-bottom: -116px;
}
.prism-previewer-easing svg {
width: 60px;
height: 60px;
}
.prism-previewer-easing circle {
fill: hsl(200, 10%, 20%);
stroke: white;
}
.prism-previewer-easing path {
fill: none;
stroke: white;
stroke-linecap: round;
stroke-width: 4;
}
.prism-previewer-easing line {
stroke: white;
stroke-opacity: 0.5;
stroke-width: 2;
}
@-webkit-keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
@-o-keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
@-moz-keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
@keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
.prism-previewer-time:before {
border-radius: 50%;
background: #fff;
}
.prism-previewer-time:after {
margin-top: 4px;
}
.prism-previewer-time svg {
width: 32px;
height: 32px;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.prism-previewer-time circle {
fill: transparent;
stroke: hsl(200, 10%, 20%);
stroke-opacity: 0.9;
stroke-width: 32;
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
-webkit-animation: prism-previewer-time linear infinite 3s;
-moz-animation: prism-previewer-time linear infinite 3s;
-o-animation: prism-previewer-time linear infinite 3s;
animation: prism-previewer-time linear infinite 3s;
}

268
extension/dep/prism.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -54,14 +54,29 @@ web.createElement = (html) => {
.join(' '); .join(' ');
return template.content.firstElementChild; return template.content.firstElementChild;
}; };
web.htmlEscape = (str) => web.escapeHtml = (str) =>
str str
.replace(/&/g, '&amp;') .replace(/&(?![^\s]+;)/g, '&amp;')
.replace(/</g, '&lt;') .replace(/</g, '&lt;')
.replace(/>/g, '&gt;') .replace(/>/g, '&gt;')
.replace(/'/g, '&#39;') .replace(/'/g, '&#39;')
.replace(/"/g, '&quot;'); .replace(/"/g, '&quot;');
// why a tagged template? because it syntax highlights
// https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
web.html = (html, ...templates) => html.map((str) => str + (templates.shift() || '')).join('');
web.Prism = async () => {
try {
return Prism;
} catch {
await import('./dep/prism.js');
Prism.manual = true;
web.loadStyleset('./dep/prism.css');
}
return Prism;
};
/** /**
* @param {string} sheet * @param {string} sheet
*/ */
@ -379,8 +394,12 @@ registry.errors = async (callback = () => {}) => {
export const markdown = new markdownit({ export const markdown = new markdownit({
linkify: true, linkify: true,
highlight(...args) { highlight: (str, lang) =>
console.log(args); web.html`<pre${lang ? ` class="language-${lang}"` : ''}><code>${web.escapeHtml(
return ''; str
}, )}</code></pre>`,
}); });
markdown.renderer.rules.code_block = (tokens, idx, options, env, slf) =>
web.html`<pre${slf.renderAttrs(tokens[idx])}><code>${web.escapeHtml(
tokens[idx].content
)}</code></pre>\n`;

View File

@ -1,3 +1,10 @@
```js
const check = (prop, value, condition) =>
Promise.resolve(condition ? value : err(`invalid ${prop} ${JSON.stringify(value)}`)),
validation = await registry.validate(mod, err, check);
if (validation.every((condition) => condition !== ERROR)) registry._list.push(mod);
```
# markdown tester # markdown tester
## table ## table
@ -14,25 +21,21 @@
# Markdown: Syntax # Markdown: Syntax
- [Overview](#overview) - [markdown tester](#markdown-tester)
- [Philosophy](#philosophy) - [table](#table)
- [Inline HTML](#html) - [Markdown: Syntax](#markdown-syntax)
- [Automatic Escaping for Special Characters](#autoescape) - [Overview](#overview)
- [Block Elements](#block) - [Philosophy](#philosophy)
- [Paragraphs and Line Breaks](#p) - [Block Elements](#block-elements)
- [Headers](#header) - [Paragraphs and Line Breaks](#paragraphs-and-line-breaks)
- [Blockquotes](#blockquote) - [Headers](#headers)
- [Lists](#list) - [Blockquotes](#blockquotes)
- [Code Blocks](#precode) - [Lists](#lists)
- [Horizontal Rules](#hr) - [Code Blocks](#code-blocks)
- [Span Elements](#span) - [Span Elements](#span-elements)
- [Links](#link) - [Links](#links)
- [Emphasis](#em) - [Emphasis](#emphasis)
- [Code](#code) - [Code](#code)
- [Images](#img)
- [Miscellaneous](#misc)
- [Backslash Escapes](#backslash)
- [Automatic Links](#autolink)
**Note:** This document is itself written using Markdown; you **Note:** This document is itself written using Markdown; you
can [see the source for it by adding '.text' to the URL](/projects/markdown/syntax.text). can [see the source for it by adding '.text' to the URL](/projects/markdown/syntax.text).
@ -267,9 +270,9 @@ easy to include example HTML source code using Markdown -- just paste
it and indent it, and Markdown will handle the hassle of encoding the it and indent it, and Markdown will handle the hassle of encoding the
ampersands and angle brackets. For example, this: ampersands and angle brackets. For example, this:
<div class="footer"> ```html
&copy; 2004 Foo Corporation <div class="footer">&copy; 2004 Foo Corporation</div>
</div> ```
Regular Markdown syntax is not processed within code blocks. E.g., Regular Markdown syntax is not processed within code blocks. E.g.,
asterisks are just literal asterisks within a code block. This means asterisks are just literal asterisks within a code block. This means

View File

@ -6,6 +6,7 @@
.enhancer--sidebarMenuTrigger { .enhancer--sidebarMenuTrigger {
user-select: none; user-select: none;
-webkit-user-select: none;
transition: background 20ms ease-in 0s; transition: background 20ms ease-in 0s;
cursor: pointer; cursor: pointer;
} }

View File

@ -8,6 +8,7 @@
box-sizing: border-box; box-sizing: border-box;
word-break: break-word; word-break: break-word;
text-size-adjust: 100%; text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
font-family: var(--theme--font_sans); font-family: var(--theme--font_sans);
color: var(--theme--text); color: var(--theme--text);
} }
@ -40,7 +41,7 @@ header h1 a:not([data-active]) {
text-decoration: none; text-decoration: none;
} }
main section[data-container] { [data-container] {
display: grid; display: grid;
grid-gap: 1.25em; grid-gap: 1.25em;
grid-template-columns: 1fr; grid-template-columns: 1fr;
@ -48,58 +49,55 @@ main section[data-container] {
transition: opacity 200ms ease-out; transition: opacity 200ms ease-out;
} }
@media (min-width: 550px) { @media (min-width: 550px) {
main section[data-container] { [data-container] {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }
main section[data-container='mod'] > .documentation--buttons { [data-container='mod'] > .documentation--buttons {
grid-column: span 2; grid-column: span 2;
} }
} }
@media (min-width: 850px) { @media (min-width: 850px) {
main section[data-container] { [data-container] {
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} }
main section[data-container='mod'] > .documentation--buttons { [data-container='mod'] > .documentation--buttons {
grid-column: span 3; grid-column: span 3;
} }
main section[data-container='mod'] > .documentation--body { [data-container='mod'] > .documentation--body {
grid-column: span 2; grid-column: span 2;
} }
} }
@media (min-width: 1350px) { @media (min-width: 1350px) {
main section[data-container] { [data-container] {
grid-template-columns: 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr;
} }
main section[data-container='mod'] > .documentation--buttons { [data-container='mod'] > .documentation--buttons {
grid-column: span 4; grid-column: span 4;
} }
main section[data-container='mod'] > .documentation--body { [data-container='mod'] > .documentation--body {
grid-column: span 3; grid-column: span 3;
} }
} }
@media (min-width: 2050px) { @media (min-width: 2050px) {
main section[data-container] { [data-container] {
grid-template-columns: 1fr 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
} }
main section[data-container='mod'] > .documentation--buttons { [data-container='mod'] > .documentation--buttons {
grid-column: span 5; grid-column: span 5;
} }
main section[data-container='mod'] > .documentation--body { [data-container='mod'] > .documentation--body {
grid-column: span 4; grid-column: span 4;
} }
} }
main section[data-container] article { [data-container] article {
border-radius: 5px; border-radius: 5px;
box-shadow: rgb(0 0 0 / 10%) 0px 20px 25px -5px, rgb(0 0 0 / 4%) 0px 10px 10px -5px; box-shadow: rgb(0 0 0 / 10%) 0px 20px 25px -5px, rgb(0 0 0 / 4%) 0px 10px 10px -5px;
border: 1px solid var(--theme--divider); border: 1px solid var(--theme--divider);
background: var(--theme--page); background: var(--theme--page);
} }
main section[data-container] article img { [data-container] article img {
max-width: 100%; max-width: 100%;
} }
main section[data-container] article > div {
padding: 1rem;
}
.documentation--buttons, .documentation--buttons,
.library--expand { .library--expand {
@ -322,7 +320,11 @@ main section[data-container] article > div {
padding-bottom: 0.25rem; padding-bottom: 0.25rem;
} }
main section[data-container='mod'] .library--card, .library--card {
padding: 1rem;
}
[data-container='mod'] .library--card,
.documentation--body { .documentation--body {
max-height: calc(100vh - 10rem); max-height: calc(100vh - 10rem);
overflow: auto; overflow: auto;

View File

@ -2,13 +2,12 @@
<html lang="en" style="opacity: 0"> <html lang="en" style="opacity: 0">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>notion-enhancer</title> <title>notion-enhancer</title>
</head> </head>
<body> <body>
<header> <header>
<p><img width="24" src="../../icons/colour.svg" /></p> <p><img alt="" width="24" src="../../icons/colour.svg" /></p>
<h1><a href="?view=library" data-target="library">library</a></h1> <h1><a href="?view=library" data-target="library">library</a></h1>
<h1><a href="?view=alerts" data-target="alerts">alerts</a></h1> <h1><a href="?view=alerts" data-target="alerts">alerts</a></h1>
<h1><a href="https://github.com/notion-enhancer/extension">github</a></h1> <h1><a href="https://github.com/notion-enhancer/extension">github</a></h1>

View File

@ -14,50 +14,45 @@ for (let mod of await registry.get()) {
} }
} }
// why a tagged template? because it syntax highlights
// https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
const html = (html, ...templates) =>
html.map((str) => str + (templates.shift() || '')).join('');
const components = {}; const components = {};
components.card = { components.card = {
preview: ({ preview = '' }) => preview: ({ preview = '' }) =>
web.createElement(html`<img web.createElement(web.html`<img
alt="" alt=""
class="library--preview" class="library--preview"
src="${web.htmlEscape(preview)}" src="${web.escapeHtml(preview)}"
/>`), />`),
name: ({ name, id, version }) => name: ({ name, id, version }) =>
web.createElement(html`<label web.createElement(web.html`<label
for="enable--${web.htmlEscape(id)}" for="enable--${web.escapeHtml(id)}"
class="library--title library--toggle_label" class="library--title library--toggle_label"
> >
<input type="checkbox" id="enable--${web.htmlEscape(id)}" /> <input type="checkbox" id="enable--${web.escapeHtml(id)}" />
<h2> <h2>
<span> <span>
${web.htmlEscape(name)} ${web.escapeHtml(name)}
<span class="library--version">v${web.htmlEscape(version)}</span> <span class="library--version">v${web.escapeHtml(version)}</span>
</span> </span>
<span class="library--toggle"></span> <span class="library--toggle"></span>
</h2> </h2>
</label>`), </label>`),
tags: ({ tags = [] }) => tags: ({ tags = [] }) =>
web.createElement(html`<ul class="library--tags"> web.createElement(web.html`<ul class="library--tags">
${tags.map((tag) => html`<li>#${web.htmlEscape(tag)}</li>`).join('')} ${tags.map((tag) => web.html`<li>#${web.escapeHtml(tag)}</li>`).join('')}
</ul>`), </ul>`),
description: ({ description }) => description: ({ description }) =>
web.createElement( web.createElement(
html`<p class="library--description">${markdown.renderInline(description)}</p>` web.html`<p class="library--description">${markdown.renderInline(description)}</p>`
), ),
authors: ({ authors }) => authors: ({ authors }) =>
web.createElement(html`<ul class="library--authors"> web.createElement(web.html`<ul class="library--authors">
${authors ${authors
.map( .map(
(author) => (author) =>
html`<li> web.html`<li>
<a href="${web.htmlEscape(author.url)}"> <a href="${web.escapeHtml(author.url)}">
<img src="${web.htmlEscape(author.icon)}" /> <img alt="" src="${web.escapeHtml(author.icon)}" />
<span>${web.htmlEscape(author.name)}</span> <span>${web.escapeHtml(author.name)}</span>
</a> </a>
</li>` </li>`
) )
@ -65,16 +60,16 @@ components.card = {
</ul>`), </ul>`),
expand: async ({ id }) => expand: async ({ id }) =>
web.createElement( web.createElement(
html`<p class="library--expand"> web.html`<p class="library--expand">
<a href="?view=mod&id=${web.htmlEscape(id)}"> <a href="?view=mod&id=${web.escapeHtml(id)}">
<span>${await fs.getText('icons/fontawesome/long-arrow-alt-right.svg')}</span> <span>${await fs.getText('icons/fontawesome/long-arrow-alt-right.svg')}</span>
<span>settings & documentation</span> <span>settings & documentation</span>
</a> </a>
</p>` </p>`
), ),
async _generate(mod) { async _generate(mod) {
const card = web.createElement(html`<article class="library--card"></article>`), const card = web.createElement(web.html`<article class="library--card"></article>`),
body = web.createElement(html`<div></div>`); body = web.createElement(web.html`<div></div>`);
card.append(this.preview(mod)); card.append(this.preview(mod));
body.append(this.name(mod)); body.append(this.name(mod));
body.append(this.tags(mod)); body.append(this.tags(mod));
@ -87,36 +82,38 @@ components.card = {
}; };
components.options = { components.options = {
toggle: (id, { key, label, value }) => toggle: (id, { key, label, value }) =>
web.createElement(html`<label web.createElement(web.html`<label
for="toggle--${web.htmlEscape(`${id}.${key}`)}" for="toggle--${web.escapeHtml(`${id}.${key}`)}"
class="library--toggle_label" class="library--toggle_label"
> >
<input type="checkbox" id="toggle--${web.htmlEscape(`${id}.${key}`)}" /> <input type="checkbox" id="toggle--${web.escapeHtml(`${id}.${key}`)}" />
<p><span>${label}</span><span class="library--toggle"></span></p <p><span>${label}</span><span class="library--toggle"></span></p
></label>`), ></label>`),
select: async (id, { key, label, values }) => select: async (id, { key, label, values }) =>
web.createElement(html`<label web.createElement(web.html`<label
for="select--${web.htmlEscape(`${id}.${key}`)}" for="select--${web.escapeHtml(`${id}.${key}`)}"
class="library--select_label" class="library--select_label"
> >
<p>${label}</p> <p>${label}</p>
<p class="library--select"> <p class="library--select">
<span> ${await fs.getText('icons/fontawesome/caret-down.svg')}</span> <span> ${await fs.getText('icons/fontawesome/caret-down.svg')}</span>
<select id="select--${web.htmlEscape(`${id}.${key}`)}"> <select id="select--${web.escapeHtml(`${id}.${key}`)}">
${values.map( ${values.map(
(value) => (value) =>
html`<option value="${web.htmlEscape(value)}">${web.htmlEscape(value)}</option>` web.html`<option value="${web.escapeHtml(value)}">${web.escapeHtml(
value
)}</option>`
)} )}
</select> </select>
</p> </p>
</label>`), </label>`),
text(id, { key, label, value }) { text(id, { key, label, value }) {
const opt = web.createElement(html`<label const opt = web.createElement(web.html`<label
for="text--${web.htmlEscape(`${id}.${key}`)}" for="text--${web.escapeHtml(`${id}.${key}`)}"
class="library--text_label" class="library--text_label"
> >
<p>${label}</p> <p>${label}</p>
<textarea id="text--${web.htmlEscape(`${id}.${key}`)}" rows="1"></textarea> <textarea id="text--${web.escapeHtml(`${id}.${key}`)}" rows="1"></textarea>
</label>`); </label>`);
opt.querySelector('textarea').addEventListener('input', (ev) => { opt.querySelector('textarea').addEventListener('input', (ev) => {
ev.target.style.removeProperty('--txt--scroll-height'); ev.target.style.removeProperty('--txt--scroll-height');
@ -125,29 +122,29 @@ components.options = {
return opt; return opt;
}, },
number: (id, { key, label, value }) => number: (id, { key, label, value }) =>
web.createElement(html`<label web.createElement(web.html`<label
for="number--${web.htmlEscape(`${id}.${key}`)}" for="number--${web.escapeHtml(`${id}.${key}`)}"
class="library--number_label" class="library--number_label"
> >
<p>${web.htmlEscape(label)}</p> <p>${web.escapeHtml(label)}</p>
<input id="number--${web.htmlEscape(`${id}.${key}`)}" type="number" /> <input id="number--${web.escapeHtml(`${id}.${key}`)}" type="number" />
</label>`), </label>`),
async file(id, { key, label, extensions }) { async file(id, { key, label, extensions }) {
const opt = web.createElement(html`<label const opt = web.createElement(web.html`<label
for="file--${web.htmlEscape(`${id}.${key}`)}" for="file--${web.escapeHtml(`${id}.${key}`)}"
class="library--file_label" class="library--file_label"
> >
<input <input
type="file" type="file"
id="file--${web.htmlEscape(`${id}.${key}`)}" id="file--${web.escapeHtml(`${id}.${key}`)}"
${web.htmlEscape( ${web.escapeHtml(
extensions && extensions.length extensions && extensions.length
? ` accept="${web.htmlEscape(extensions.join(','))}"` ? ` accept="${web.escapeHtml(extensions.join(','))}"`
: '' : ''
)} )}
/> />
<p>${web.htmlEscape(label)}</p> <p>${web.escapeHtml(label)}</p>
<p class="library--file"> <p class="library--file">
<span>${await fs.getText('icons/fontawesome/file.svg')}</span> <span>${await fs.getText('icons/fontawesome/file.svg')}</span>
<span class="library--file_path">choose file...</span> <span class="library--file_path">choose file...</span>
@ -162,7 +159,7 @@ components.options = {
const card = await components.card._generate(mod); const card = await components.card._generate(mod);
card.querySelector('.library--expand').remove(); card.querySelector('.library--expand').remove();
if (mod.options && mod.options.length) { if (mod.options && mod.options.length) {
const options = web.createElement(html`<div class="library--options"></div>`), const options = web.createElement(web.html`<div class="library--options"></div>`),
inputs = await Promise.all(mod.options.map((opt) => this[opt.type](mod.id, opt))); inputs = await Promise.all(mod.options.map((opt) => this[opt.type](mod.id, opt)));
inputs.forEach((opt) => options.append(opt)); inputs.forEach((opt) => options.append(opt));
card.append(options); card.append(options);
@ -172,7 +169,7 @@ components.options = {
}; };
components.documentation = { components.documentation = {
buttons: async ({ _dir }) => buttons: async ({ _dir }) =>
web.createElement(html`<p class="documentation--buttons"> web.createElement(web.html`<p class="documentation--buttons">
<a href="?view=library"> <a href="?view=library">
<span>${await fs.getText('icons/fontawesome/long-arrow-alt-left.svg')}</span> <span>${await fs.getText('icons/fontawesome/long-arrow-alt-left.svg')}</span>
<span>back to library</span> <span>back to library</span>
@ -186,12 +183,17 @@ components.documentation = {
<span>view source code</span> <span>view source code</span>
</a> </a>
</p>`), </p>`),
readme: async (mod) => readme: async (mod) => {
web.createElement(html`<article class="documentation--body"> const readme = web.createElement(web.html`<article class="documentation--body">
${(await fs.isFile(`repo/${mod._dir}/README.md`)) ${
? markdown.render(await fs.getText(`repo/${mod._dir}/README.md`)) (await fs.isFile(`repo/${mod._dir}/README.md`))
: ''} ? markdown.render(await fs.getText(`repo/${mod._dir}/README.md`))
</article>`), : ''
}
</article>`);
(await web.Prism()).highlightAllUnder(readme);
return readme;
},
}; };
const views = { const views = {
$container: document.querySelector('[data-container]'), $container: document.querySelector('[data-container]'),
@ -204,10 +206,14 @@ const views = {
i++; i++;
} while (anchor.nodeName !== 'A'); } while (anchor.nodeName !== 'A');
if (location.search !== anchor.getAttribute('href')) { if (location.search !== anchor.getAttribute('href')) {
window.history.pushState({}, '', anchor.href); window.history.pushState({ search: anchor.href }, '', anchor.href);
this._load(); this._load();
} }
}, },
_navigator(event) {
event.preventDefault();
console.log(event);
},
_reset() { _reset() {
document document
.querySelectorAll('a[href^="?"]') .querySelectorAll('a[href^="?"]')
@ -278,8 +284,11 @@ const views = {
}, },
}; };
views._router = views._router.bind(views); views._router = views._router.bind(views);
views._navigator = views._navigator.bind(views);
views._load(); views._load();
window.addEventListener('popstate', (ev) => views._load()); window.addEventListener('popstate', (ev) => {
if (ev.state) views._load();
});
function theme() { function theme() {
chrome.storage.local.get(['notion.theme'], (result) => { chrome.storage.local.get(['notion.theme'], (result) => {