diff --git a/CHANGELOG.md b/CHANGELOG.md index 604fc37..1afeab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,29 @@ # Changelog -## v0.2.1-beta.3 +## v0.2.2 -### Updated project using `deno fmt` +### Added the `Markdown` component + +- `/components/Markdown/index.tsx` +- `/components/Markdown/setup.ts` +- `/routes/md.tsx` +- `/mod.ts` +- `/src/scss/components.scss` + +### Added `deno-gfm` project adapted to this case. + +- `/src/katex.ts` +- `/src/markdown.ts` + +### Minor updates + +- Removed `/static/test.txt` +- `/static/content.md` +- `/import_map.json` ## Changes so far -- ⏳ Markdown component +- ✅ Markdown component - Better task scripts. ## Roadmap @@ -20,6 +37,7 @@ - [x] Select (focus) - [x] TextArea (focus) - [x] Link (focus, hover) + - [ ] Markdown (heading link hover) - [ ] Create an organized collection of island functions - [ ] Update component features - [ ] **Card**: Add text, image, gradient spacers, and chips feature. @@ -30,7 +48,7 @@ - [x] **Header**, **Footer**: Add spacers with gradients that change. - [ ] Add components - [ ] Time - - [ ] Markdown + - [x] Markdown - [ ] Menu - [ ] Page - [ ] Fieldset diff --git a/components/Markdown/index.tsx b/components/Markdown/index.tsx new file mode 100644 index 0000000..40f19cb --- /dev/null +++ b/components/Markdown/index.tsx @@ -0,0 +1,14 @@ +import setup, { iMarkdown } from './setup.ts'; + +export default function (props: Partial) { + const { c, fref, markdown_content, renderOptions, ...p } = setup(props); + + return ( +
+ ); +} diff --git a/components/Markdown/setup.ts b/components/Markdown/setup.ts new file mode 100644 index 0000000..f13c11d --- /dev/null +++ b/components/Markdown/setup.ts @@ -0,0 +1,38 @@ +import { applyDefaults, cn, opt, partializeClasses } from '../../src/utils.ts'; +import { iComponent } from '../../src/types.ts'; +import { RenderOptions } from '@/src/markdown.ts'; +import { render } from '@/src/markdown.ts'; + +export type iMarkdown = iComponent & { + markdown_content: string; + renderOptions: RenderOptions; +}; + +const defaults: iMarkdown = { + markdown_content: '', + renderOptions: { + allowIframes: true, + allowMath: true, + customClasses: { + paragraph: ['comp-text', 'txt-paragraph'], + heading: ['comp-text'], + code: ['comp-code_wrapper'], + codespan: ['comp-code', 'comp-code_wrapper', 'clr-bg-panel'], + link: ['comp-link'], + hr: ['comp-separator'], + }, + }, +}; + +export default (props: Partial) => { + const p = applyDefaults(defaults, props); + + const classes = partializeClasses({ + markdown: opt(cn('comp-markdown'), p.class, p.nostyle), + }); + + p.markdown_content = render(p.markdown_content, p.renderOptions); + + delete p.class; + return { c: classes, ...p }; +}; diff --git a/import_map.json b/import_map.json index f8b90c6..3f424e9 100644 --- a/import_map.json +++ b/import_map.json @@ -1,5 +1,6 @@ { "imports": { + "@/": "./", "$fresh/": "https://deno.land/x/fresh@1.3.1/", "preact": "https://esm.sh/preact@10.11.0", "preact/": "https://esm.sh/preact@10.11.0/", diff --git a/mod.ts b/mod.ts index 9a8c8c7..9cdd6ed 100644 --- a/mod.ts +++ b/mod.ts @@ -14,6 +14,7 @@ export { default as Code } from './components/Code/index.tsx'; export { default as Separator } from './components/Separator/index.tsx'; export { default as Linkmap } from './components/Linkmap/index.tsx'; export { default as Panel } from './components/Panel/index.tsx'; +export { default as Markdown } from './components/Markdown/index.tsx'; export * from './src/enums.ts'; export * from './src/types.ts'; export * from './src/utils.ts'; diff --git a/routes/md.tsx b/routes/md.tsx index a96e9a8..87b09fe 100644 --- a/routes/md.tsx +++ b/routes/md.tsx @@ -1,22 +1,23 @@ -import { render } from '../../deno-gfm/mod.ts'; - -const CONTENT_PATH = new URL('../static/content.md', import.meta.url); -const TEST_PATH = new URL('../static/test.txt', import.meta.url); +import { Main, Markdown } from '@/mod.ts'; +import 'https://esm.sh/prismjs@1.29.0'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-jsx?no-check&pin=v57'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-typescript?no-check&pin=v57'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-tsx?no-check&pin=v57'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-bash?no-check&pin=v57'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-powershell?no-check&pin=v57'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-json?no-check&pin=v57'; +import 'https://esm.sh/prismjs@1.29.0/components/prism-diff?no-check&pin=v57'; export default async function Md() { - const markdown = await (await fetch(CONTENT_PATH)).text(); - const test = await (await fetch(TEST_PATH)).text(); - - const body = render(markdown, { - allowIframes: true, - allowMath: true, - customClasses: { - // list: ['asdf'], - }, - }); - - console.log(test === body ? 'good' : 'bad'); + const markdown = + await (await fetch(new URL('../static/content.md', import.meta.url))) + .text(); - // return
; - return
{body}
; + return ( +
+
+ +
+
+ ); } diff --git a/src/katex.ts b/src/katex.ts new file mode 100644 index 0000000..991883f --- /dev/null +++ b/src/katex.ts @@ -0,0 +1,140 @@ +/** @type {string} */ +export const KATEX_CSS = + `@font-face{font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_AMS-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_AMS-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype")}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Fraktur-Bold.ttf) format("truetype")}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Fraktur-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Bold.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-BoldItalic.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Italic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Italic.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Main-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Math-BoldItalic.ttf) format("truetype")}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Math-Italic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Math-Italic.ttf) format("truetype")}@font-face{font-family:"KaTeX_SansSerif";font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Bold.ttf) format("truetype")}@font-face{font-family:"KaTeX_SansSerif";font-style:italic;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Italic.ttf) format("truetype")}@font-face{font-family:"KaTeX_SansSerif";font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_SansSerif-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Script-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Script-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size1-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size1-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size2-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size2-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size3-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size3-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size4-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Size4-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/fonts/KaTeX_Typewriter-Regular.ttf) format("truetype")}.katex{text-rendering:auto;font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.16.4"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.83333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.16666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.66666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.45666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.14666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.85714286em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.46857143em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.96285714em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.55428571em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.66666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.77777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.88888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.30444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.76444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.58333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.66666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72833333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.07333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.41666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.48611111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.55555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.44027778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.72777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.28935185em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.34722222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.40509259em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.46296296em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.52083333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20023148em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.43981481em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.24108004em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.28929605em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.33751205em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.38572806em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.43394407em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48216008em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57859209em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69431051em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.83317261em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.19961427em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.20096463em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.24115756em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.28135048em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.32154341em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.36173633em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.40192926em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.48231511em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.57877814em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.69453376em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.83360129em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}`; + +export const KATEX_CLASSES = [ + 'katex', + 'katex-version', + 'katex-mathml', + 'katex-html', + 'newline', + 'base', + 'strut', + 'textbf', + 'textit', + 'textrm', + 'textsf', + 'texttt', + 'mathnormal', + 'mathit', + 'mathrm', + 'mathbf', + 'boldsymbol', + 'amsrm', + 'mathbb', + 'textbb', + 'mathcal', + 'mathfrak', + 'textfrak', + 'mathtt', + 'mathscr', + 'textscr', + 'mathsf', + 'mathboldsf', + 'textboldsf', + 'mathitsf', + 'textitsf', + 'mainrm', + 'vlist-t', + 'vlist-r', + 'vlist', + 'pstrut', + 'vlist-t2', + 'vlist-s', + 'vbox', + 'hbox', + 'thinbox', + 'msupsub', + 'mfrac', + 'frac-line', + 'hdashline', + 'hline', + 'overline', + 'overline-line', + 'rule', + 'underline', + 'underline-line', + 'mspace', + 'clap', + 'llap', + 'rlap', + 'inner', + 'fix', + 'sqrt', + 'root', + 'fontsize-ensurer', + 'reset-size1', + 'size1', + 'sizing', + 'size2', + 'size3', + 'size4', + 'size5', + 'size6', + 'size7', + 'size8', + 'size9', + 'size10', + 'size11', + 'reset-size2', + 'reset-size3', + 'reset-size4', + 'reset-size5', + 'reset-size6', + 'reset-size7', + 'reset-size8', + 'reset-size9', + 'reset-size10', + 'reset-size11', + 'delimsizing', + 'mult', + 'delim-size1', + 'delim-size4', + 'nulldelimiter', + 'delimcenter', + 'op-symbol', + 'small-op', + 'large-op', + 'accent', + 'op-limits', + 'accent-body', + 'accent-full', + 'overlay', + 'mtable', + 'vertical-separator', + 'arraycolsep', + 'col-align-c', + 'col-align-l', + 'col-align-r', + 'svg-align', + 'stretchy', + 'hide-tail', + 'halfarrow-left', + 'halfarrow-right', + 'brace-left', + 'brace-center', + 'brace-right', + 'x-arrow-pad', + 'cd-arrow-pad', + 'mover', + 'munder', + 'x-arrow', + 'boxpad', + 'fbox', + 'fcolorbox', + 'cancel-pad', + 'cancel-lap', + 'sout', + 'angl', + 'anglpad', + 'eqn-num', + 'mml-eqn-num', + 'mtr-glue', + 'cd-vert-arrow', + 'cd-label-left', + 'cd-label-right', + 'katex-display', + 'tag', + 'leqno', + 'fleqn', +]; diff --git a/src/markdown.ts b/src/markdown.ts new file mode 100644 index 0000000..da0cfaa --- /dev/null +++ b/src/markdown.ts @@ -0,0 +1,402 @@ +/// +/// +/// +/// +/// +/// +import { emojify } from 'https://deno.land/x/emoji@0.3.0/mod.ts'; +import * as Marked from 'https://esm.sh/marked@5.1.0/'; +import { mangle } from 'https://esm.sh/marked-mangle@v1.1.0/'; +import { gfmHeadingId } from 'https://esm.sh/marked-gfm-heading-id@3.0.4/'; +import { default as Prism } from 'https://esm.sh/prismjs@1.29.0'; +import { default as sanitizeHtml } from 'https://esm.sh/sanitize-html@2.8.1?target=esnext'; +import { escape as htmlEscape } from 'https://esm.sh/he@1.2.0'; +import { default as katex } from 'https://esm.sh/katex@0.16.8/dist/katex.mjs'; +import { KATEX_CLASSES } from './katex.ts'; +export { KATEX_CSS } from './katex.ts'; +export { Marked }; + +Marked.marked.use(mangle()); +Marked.marked.use(gfmHeadingId()); + +class Renderer extends Marked.Renderer { + allowMath: boolean; + customClasses: Partial; + + constructor(options: Marked.marked.MarkedOptions & RenderOptions = {}) { + super(options); + this.allowMath = options.allowMath ?? false; + this.customClasses = options.customClasses ?? {}; + } + + heading( + text: string, + level: 1 | 2 | 3 | 4 | 5 | 6, + raw: string, + slugger: Marked.Slugger, + ): string { + const slug = slugger.slug(raw); + return `${text}`; + } + + image(src: string, title: string | null, alt: string | null) { + return `${
+      alt ?? ''
+    }`; + } + + code(code: string, language?: string) { + // a language of `ts, ignore` should really be `ts` + // and it should be lowercase to ensure it has parity with regular github markdown + language = language?.split(',')?.[0].toLocaleLowerCase(); + + // transform math code blocks into HTML+MathML + // https://github.blog/changelog/2022-06-28-fenced-block-syntax-for-mathematical-expressions/ + if (language === 'math' && this.allowMath) { + return katex.renderToString(code, { displayMode: true }); + } + const grammar = + language && Object.hasOwnProperty.call(Prism.languages, language) + ? Prism.languages[language] + : undefined; + if (grammar === undefined) { + return `
${
+        htmlEscape(
+          code,
+        )
+      }
`; + } + const html = Prism.highlight(code, grammar, language!); + return `
${html}
`; + } + + link(href: string, title: string | null, text: string) { + const titleAttr = title ? ` title="${title}"` : ''; + if (href.startsWith('#')) { + return `${text}`; + } + if (this.options.baseUrl) { + try { + href = new URL(href, this.options.baseUrl).href; + } catch (_) { + // + } + } + return `${text}`; + } + + blockquote(quote: string) { + return `
\n${quote}
\n`; + } + + hr() { + return this.options.xhtml + ? `
\n` + : `
\n`; + } + + list(body: string, ordered: boolean, start: number) { + const type = ordered ? 'ol' : 'ul', + startatt = (ordered && start !== 1) ? (' start="' + start + '"') : ''; + return '<' + type + startatt + customClass(this.customClasses.list) + + '>\n' + body + '\n'; + } + + listitem(text: string) { + return `
  • ${text}
  • \n`; + } + + checkbox(checked: boolean) { + return ` '; + } + + paragraph(text: string) { + return `

    ${text}

    \n`; + } + + table(header: string, body: string) { + if (body) body = `${body}`; + + return '\n' + + '\n' + + header + + '\n' + + body + + '\n'; + } + + tablerow(content: string) { + return `\n${content}\n`; + } + + tablecell(content: string, flags: any) { + const className = customClass(this.customClasses.tablecell); + const type = flags.header ? 'th' : 'td'; + const tag = flags.align + ? `<${type} ${className} align="${flags.align}">` + : `<${type} ${className}>`; + return tag + content + `\n`; + } + + strong(text: string) { + return `${text}`; + } + + em(text: string) { + return `${text}`; + } + + codespan(text: string) { + return `${text}`; + } + + del(text: string) { + return `${text}`; + } +} + +/** Convert inline and block math to katex */ +function mathify(markdown: string) { + // Deal with block math + markdown = markdown.replace(/\$\$\s(.+?)\s\$\$/g, (match, p1) => { + try { + return katex.renderToString(p1.trim(), { displayMode: true }); + } catch (e) { + console.warn(e); + // Don't replace the math if there's an error + return match; + } + }); + + // Deal with inline math + markdown = markdown.replace(/\s\$((?=\S).*?(?=\S))\$/g, (match, p1) => { + try { + return ' ' + katex.renderToString(p1, { displayMode: false }); + } catch (e) { + console.warn(e); + // Don't replace the math if there's an error + return match; + } + }); + + return markdown; +} + +const customClass = (classStr?: string[], ...staticClasses: string[]) => + classStr ? ` class="${classStr.concat(staticClasses).join(' ')}" ` : ''; + +export interface RenderOptions { + baseUrl?: string; + mediaBaseUrl?: string; + inline?: boolean; + allowIframes?: boolean; + allowMath?: boolean; + disableHtmlSanitization?: boolean; + customClasses?: Partial; +} + +interface customClasses { + // Block + code: string[]; + blockquote: string[]; + heading: string[]; + hr: string[]; + list: string[]; + listitem: string[]; + checkbox: string[]; + paragraph: string[]; + table: string[]; + tablerow: string[]; + tablecell: string[]; + // Inline + strong: string[]; + em: string[]; + codespan: string[]; + del: string[]; + link: string[]; + image: string[]; +} + +export function render( + this: any, + markdown: string, + opts: RenderOptions = {}, +): string { + opts.mediaBaseUrl ??= opts.baseUrl; + markdown = emojify(markdown); + if (opts.allowMath) { + markdown = mathify(markdown); + } + + const marked_opts = { + baseUrl: opts.baseUrl, + gfm: true, + renderer: new Renderer(opts), + }; + + const html = opts.inline + ? Marked.marked.parseInline(markdown, marked_opts) + : Marked.marked.parse(markdown, marked_opts); + + if (opts.disableHtmlSanitization) { + return html; + } + + let allowedTags = sanitizeHtml.defaults.allowedTags.concat([ + 'img', + 'video', + 'svg', + 'path', + 'circle', + 'figure', + 'figcaption', + 'del', + 'details', + 'summary', + ]); + if (opts.allowIframes) { + allowedTags.push('iframe'); + } + if (opts.allowMath) { + allowedTags = allowedTags.concat([ + 'math', + 'maction', + 'annotation', + 'annotation-xml', + 'menclose', + 'merror', + 'mfenced', + 'mfrac', + 'mi', + 'mmultiscripts', + 'mn', + 'mo', + 'mover', + 'mpadded', + 'mphantom', + 'mprescripts', + 'mroot', + 'mrow', + 'ms', + 'semantics', + 'mspace', + 'msqrt', + 'mstyle', + 'msub', + 'msup', + 'msubsup', + 'mtable', + 'mtd', + 'mtext', + 'mtr', + ]); + } + + function transformMedia(tagName: string, attribs: sanitizeHtml.Attributes) { + if (opts.mediaBaseUrl && attribs.src) { + try { + attribs.src = new URL(attribs.src, opts.mediaBaseUrl).href; + } catch { + delete attribs.src; + } + } + return { tagName, attribs }; + } + + const allCustomClasses = []; + if (opts.customClasses) { + for (const [_key, value] of Object.entries(opts.customClasses)) { + allCustomClasses.push(...(value as string[])); + } + } + + return sanitizeHtml(html, { + transformTags: { + img: transformMedia, + video: transformMedia, + }, + allowedTags, + allowedAttributes: { + ...sanitizeHtml.defaults.allowedAttributes, + img: ['src', 'alt', 'height', 'width', 'align'], + video: [ + 'src', + 'alt', + 'height', + 'width', + 'autoplay', + 'muted', + 'loop', + 'playsinline', + 'poster', + ], + a: ['id', 'aria-hidden', 'href', 'tabindex', 'rel', 'target'], + svg: ['viewbox', 'width', 'height', 'aria-hidden', 'background'], + path: ['fill-rule', 'd'], + circle: ['cx', 'cy', 'r', 'stroke', 'stroke-width', 'fill', 'alpha'], + span: opts.allowMath ? ['aria-hidden', 'style'] : [], + h1: ['id'], + h2: ['id'], + h3: ['id'], + h4: ['id'], + h5: ['id'], + h6: ['id'], + iframe: ['src', 'width', 'height'], // Only used when iframe tags are allowed in the first place. + math: ['xmlns'], // Only enabled when math is enabled + annotation: ['encoding'], // Only enabled when math is enabled + }, + allowedClasses: { + div: ['highlight', 'highlight-source-*', 'notranslate'], + span: [ + 'token', + 'keyword', + 'operator', + 'number', + 'boolean', + 'function', + 'string', + 'comment', + 'class-name', + 'regex', + 'regex-delimiter', + 'tag', + 'attr-name', + 'punctuation', + 'script-punctuation', + 'script', + 'plain-text', + 'property', + 'prefix', + 'line', + 'deleted', + 'inserted', + ...(opts.allowMath ? KATEX_CLASSES : []), + ], + a: ['anchor'], + svg: ['octicon', 'octicon-link'], + '*': allCustomClasses, + }, + allowProtocolRelative: false, + }); +} diff --git a/src/scss/components.scss b/src/scss/components.scss index a3b4469..71cebad 100644 --- a/src/scss/components.scss +++ b/src/scss/components.scss @@ -314,3 +314,120 @@ width: max-content; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Markdown +.comp-markdown { + .keyword, + .function, + .property { + color: var(--clr-txt-personality); + } + + .class-name, + .tag, + .script { + color: var(--clr-txt-base); + } + + .punctuation, + .operator, + .script-punctuation { + color: var(--clr-bg-disabled); + } + + .number, + .boolean, + .string, + .regex, + .attr-name { + color: var(--clr-txt-error); + } + + .regex-delimiter { + color: var(--clr-bg-error); + } + + h1.comp-text { + font: var(--txt-title) var(--font-heading); + color: var(--clr-txt-personality); + + svg { + fill: var(--clr-txt-personality); + } + } + + h2.comp-text { + font: var(--txt-heading) var(--font-heading); + color: var(--clr-txt-personality); + + svg { + fill: var(--clr-txt-personality); + } + } + + h3.comp-text { + font: var(--txt-subheading) var(--font-base); + + svg { + fill: var(--clr-txt-base); + } + } + + h1, + h2, + h3 { + &.comp-text { + font-weight: 600; + margin-bottom: var(--s-one-and-half); + margin-top: var(--s-triple); + display: flex; + align-items: center; + position: relative; + + a { + position: absolute; + left: calc(var(--s-double) * -1); + display: none; + padding-right: var(--s-half); + + svg { + width: var(--s-one-and-half); + height: var(--s-one-and-half); + } + } + + &:hover { + a { + display: block; + } + } + } + } + + h4, + h5, + h6 { + &.comp-text { + a { + display: none; + } + } + } + + .comp-code_wrapper pre { + background-color: var(--clr-bg-panel); + border-radius: var(--s-quarter); + padding: var(--s-one-and-half); + width: calc(100% + var(--s-triple)); + right: var(--s-one-and-half); + position: relative; + overflow-x: scroll; + + @include media(only-on($breakpoints, sm)) { + padding: var(--s-half); + width: calc(100% + var(--s-single)); + right: var(--s-half); + } + } +} diff --git a/static/content.md b/static/content.md index 4637e69..ce44059 100644 --- a/static/content.md +++ b/static/content.md @@ -1,3 +1,13 @@ +# Heading 1 + +#### Heading 4 + +##### Heading 5 + +###### Heading 6 + +--- + ```JSON { "json": { @@ -18,9 +28,7 @@ import { build } from 'https://deno.land/x/esbuild/mod.ts'; import sassPlugin from 'https://deno.land/x/esbuild_plugin_sass_deno/mod.ts'; build({ - entryPoints: [ - 'example/in.ts', - ], + entryPoints: ['example/in.ts'], bundle: true, outfile: 'example/out.js', plugins: [sassPlugin()], @@ -32,8 +40,7 @@ build({ ```ts import styles from './styles.scss'; -document.getElementsByTagName('head')[0].innerHTML += - ``; +document.getElementsByTagName('head')[0].innerHTML += ``; ``` ~~Some strikethrough `text`~~ @@ -65,8 +72,10 @@ You can even typeset individual letters or whole sentences inline just like $x$ or $Quadratic \; formula$. You can also use math blocks to typeset whole equations with $\LaTeX$: -$$ \begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ -\dot{z} & = -\beta z + xy \end{aligned} $$ +$$ +\begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ +\dot{z} & = -\beta z + xy \end{aligned} +$$ # Deno @@ -183,10 +192,7 @@ import { h, IS_BROWSER, useState } from '../deps.ts'; export default function Home() { return (
    -

    - Welcome to `fresh`. Try update this message in the ./pages/index.tsx - file, and refresh. -

    +

    Welcome to `fresh`. Try update this message in the ./pages/index.tsx file, and refresh.

    {IS_BROWSER ? 'Viewing browser render.' : 'Viewing JIT render.'}

    @@ -198,16 +204,10 @@ function Counter() { return (

    {count}

    - -
    diff --git a/static/style.css b/static/style.css index e60f350..784271a 100644 --- a/static/style.css +++ b/static/style.css @@ -566,6 +566,102 @@ button { width: max-content; } +.comp-markdown .keyword, +.comp-markdown .function, +.comp-markdown .property { + color: var(--clr-txt-personality); +} +.comp-markdown .class-name, +.comp-markdown .tag, +.comp-markdown .script { + color: var(--clr-txt-base); +} +.comp-markdown .punctuation, +.comp-markdown .operator, +.comp-markdown .script-punctuation { + color: var(--clr-bg-disabled); +} +.comp-markdown .number, +.comp-markdown .boolean, +.comp-markdown .string, +.comp-markdown .regex, +.comp-markdown .attr-name { + color: var(--clr-txt-error); +} +.comp-markdown .regex-delimiter { + color: var(--clr-bg-error); +} +.comp-markdown h1.comp-text { + font: var(--txt-title) var(--font-heading); + color: var(--clr-txt-personality); +} +.comp-markdown h1.comp-text svg { + fill: var(--clr-txt-personality); +} +.comp-markdown h2.comp-text { + font: var(--txt-heading) var(--font-heading); + color: var(--clr-txt-personality); +} +.comp-markdown h2.comp-text svg { + fill: var(--clr-txt-personality); +} +.comp-markdown h3.comp-text { + font: var(--txt-subheading) var(--font-base); +} +.comp-markdown h3.comp-text svg { + fill: var(--clr-txt-base); +} +.comp-markdown h1.comp-text, +.comp-markdown h2.comp-text, +.comp-markdown h3.comp-text { + font-weight: 600; + margin-bottom: var(--s-one-and-half); + margin-top: var(--s-triple); + display: flex; + align-items: center; + position: relative; +} +.comp-markdown h1.comp-text a, +.comp-markdown h2.comp-text a, +.comp-markdown h3.comp-text a { + position: absolute; + left: calc(var(--s-double) * -1); + display: none; + padding-right: var(--s-half); +} +.comp-markdown h1.comp-text a svg, +.comp-markdown h2.comp-text a svg, +.comp-markdown h3.comp-text a svg { + width: var(--s-one-and-half); + height: var(--s-one-and-half); +} +.comp-markdown h1.comp-text:hover a, +.comp-markdown h2.comp-text:hover a, +.comp-markdown h3.comp-text:hover a { + display: block; +} +.comp-markdown h4.comp-text a, +.comp-markdown h5.comp-text a, +.comp-markdown h6.comp-text a { + display: none; +} +.comp-markdown .comp-code_wrapper pre { + background-color: var(--clr-bg-panel); + border-radius: var(--s-quarter); + padding: var(--s-one-and-half); + width: calc(100% + var(--s-triple)); + right: var(--s-one-and-half); + position: relative; + overflow-x: scroll; +} +@media screen and (max-width: 39.9375em) { + .comp-markdown .comp-code_wrapper pre { + padding: var(--s-half); + width: calc(100% + var(--s-single)); + right: var(--s-half); + } +} + .comp-button, .comp-input, .comp-select, diff --git a/static/test.txt b/static/test.txt deleted file mode 100644 index 2503180..0000000 --- a/static/test.txt +++ /dev/null @@ -1,141 +0,0 @@ -
    {
    -  "json": {
    -    "name": "Deno"
    -  }
    -}
    - hello
    -+ world
      -
    • Buildscript
    • -
    -
    import { build } from "https://deno.land/x/esbuild/mod.ts";
    -import sassPlugin from "https://deno.land/x/esbuild_plugin_sass_deno/mod.ts";
    -
    -build({
    -  entryPoints: [
    -    "example/in.ts",
    -  ],
    -  bundle: true,
    -  outfile: "example/out.js",
    -  plugins: [sassPlugin()],
    -});
      -
    • Main Entrypoint File:
    • -
    -
    import styles from "./styles.scss";
    -
    -document.getElementsByTagName("head")[0].innerHTML +=
    -  `<style>${styles}</style>`;

    Some strikethrough text

    -
    - Summary -

    Some Details - -

    even more details

    -

    -
    - -

    Math rendering

    We support code blocks with the "math" type!

    -Gμv=8πGc4TμvG_{\mu v} = \frac{8 \pi G}{c^4} T_{\mu v}

    We also support math blocks and inline math blocks as well!

    -

    When a0a \ne 0, there are two solutions to (ax2+bx+c=0)(ax^2 + bx + c = 0) and they are

    -

    x=b±b24ac2ax = {-b \pm \sqrt{b^2-4ac} \over 2a}

    -

    You can even typeset individual letters or whole sentences inline just like xx -or Quadratic  formulaQuadratic ; formula. You can also use math blocks to typeset whole -equations with LaTeX\LaTeX: - \begin{aligned} \dot{x} & = \sigma(y-x) \ \dot{y} & = \rho x - y - xz \ -\dot{z} & = -\beta z + xy \end{aligned}

    -

    Deno

    Build Status - Cirrus Twitter handle -Discord Chat

    -the deno mascot dinosaur standing in the rain - -

    Deno is a simple, modern and secure runtime for JavaScript and -TypeScript that uses V8 and is built in Rust.

    -

    Features

      -
    • Secure by default. No file, network, or environment access, unless explicitly -enabled.
    • -
    • Supports TypeScript out of the box.
    • -
    • Ships only a single executable file.
    • -
    • Built-in utilities like a dependency inspector (deno info) and a code -formatter (deno fmt).
    • -
    • Set of reviewed standard modules that are guaranteed to work with -Deno.
    • -
    -

    Install

    Shell (Mac, Linux):

    -
    curl -fsSL https://deno.land/x/install/install.sh | sh

    PowerShell (Windows):

    -
    iwr https://deno.land/x/install/install.ps1 -useb | iex

    Homebrew (Mac):

    -
    brew install deno

    Chocolatey (Windows):

    -
    choco install deno

    Scoop (Windows):

    -
    scoop install deno

    Build and install from source using Cargo:

    -
    cargo install deno --locked

    See -deno_install -and releases for other options.

    -

    Getting Started

    Try running a simple program:

    -
    deno run https://deno.land/std/examples/welcome.ts

    Or a more complex one:

    -
    const listener = Deno.listen({ port: 8000 });
    -console.log("http://localhost:8000/");
    -
    -for await (const conn of listener) {
    -  serve(conn);
    -}
    -
    -async function serve(conn: Deno.Conn) {
    -  for await (const { respondWith } of Deno.serveHttp(conn)) {
    -    respondWith(new Response("Hello world"));
    -  }
    -}

    You can find a deeper introduction, examples, and environment setup guides in -the manual.

    - - -

    The complete API reference is available at the runtime -documentation.

    -

    Contributing

    We appreciate your help!

    -

    To contribute, please read our -contributing instructions.

    -
    /** @jsx h */
    -import { h, IS_BROWSER, useState } from "../deps.ts";
    -
    -export default function Home() {
    -  return (
    -    <div>
    -      <p>
    -        Welcome to `fresh`. Try update this message in the ./pages/index.tsx
    -        file, and refresh.
    -      </p>
    -      <Counter />
    -      <p>{IS_BROWSER ? "Viewing browser render." : "Viewing JIT render."}</p>
    -    </div>
    -  );
    -}
    -
    -function Counter() {
    -  const [count, setCount] = useState(0);
    -  return (
    -    <div>
    -      <p>{count}</p>
    -      <button
    -        onClick={() => setCount(count - 1)}
    -        disabled={!IS_BROWSER}
    -      >
    -        -1
    -      </button>
    -      <button
    -        onClick={() => setCount(count + 1)}
    -        disabled={!IS_BROWSER}
    -      >
    -        +1
    -      </button>
    -    </div>
    -  );
    -}
    -
    -export const config: PageConfig = { runtimeJS: true };
    - -
    Figure 1. The deno mascot dinosaur standing in the rain.
    -