From 55aa3cf4aaab91780005921c04a731e47b0d7e47 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:31:44 -0700 Subject: [PATCH] changelog dialog --- CHANGELOG.md | 26 + www/package.json | 1 + www/pnpm-lock.yaml | 9 + www/rsbuild.config.ts | 7 + www/src/ts/app/app.ts | 53 +- www/src/ts/app/gfm-styles.ts | 1113 ++++++++++++++++++++++++++++++++++ www/src/ts/app/nav.ts | 9 + www/src/ts/app/welcome.ts | 75 +++ www/src/ts/utils.ts | 4 +- 9 files changed, 1293 insertions(+), 4 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 www/src/ts/app/gfm-styles.ts create mode 100644 www/src/ts/app/welcome.ts diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ba9bb52 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +## v0.2.0 + +### Share VM State! + +New in this release is the ability to share the entire VM with you share a link. This means code; connected devices and their state; as well as the state of the stack, registers, and line number of the active IC! + +Additionally you can now save and load any number of sessions in your browser. Access this functionality from the main menu. + +Also! the project has officially moved to https://ic10emu.dev . Old share links *should* redirect, but if not simply copy the fragment (the part of the url starting with the `#` symbol) + +#### List of changes + + - Move build system from Webpack to [Rsbuild](https://rsbuild.dev/) (way faster build times). + - VM now supports exporting and restoring a frozen state. + - Share links updates to use frozen vm state. + - Save and load sessions from the browser's IndexedDB storage. + - project now includes tailwindcss to make frontend dev easier. + - Changelog dialog to notify users of updates. + +## v0.1.0 + +### **Initial Release**: + +IC10emu is released to the public! edit and share your IC10 scripts! + + - view and edit stack and registers diff --git a/www/package.json b/www/package.json index 465ebd8..d137442 100644 --- a/www/package.json +++ b/www/package.json @@ -62,6 +62,7 @@ "jquery": "^3.7.1", "lit": "^3.1.3", "lzma-web": "^3.0.1", + "marked": "^12.0.2", "stream-browserify": "^3.0.0", "uuid": "^9.0.1", "vm-browserify": "^1.1.2" diff --git a/www/pnpm-lock.yaml b/www/pnpm-lock.yaml index 9f5fff5..f9db843 100644 --- a/www/pnpm-lock.yaml +++ b/www/pnpm-lock.yaml @@ -53,6 +53,9 @@ dependencies: lzma-web: specifier: ^3.0.1 version: 3.0.1 + marked: + specifier: ^12.0.2 + version: 12.0.2 stream-browserify: specifier: ^3.0.0 version: 3.0.0 @@ -2920,6 +2923,12 @@ packages: resolution: {integrity: sha512-sb5cdfd+PLNljK/HUgYzvnz4G7r0GFK8sonyGrqJS0FVyUQjFYcnmU2LqTWFi6r48lH1ZBstnxyLWepKM/t7QA==} dev: false + /marked@12.0.2: + resolution: {integrity: sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==} + engines: {node: '>= 18'} + hasBin: true + dev: false + /md5.js@1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: diff --git a/www/rsbuild.config.ts b/www/rsbuild.config.ts index 1ba6afb..6b91272 100644 --- a/www/rsbuild.config.ts +++ b/www/rsbuild.config.ts @@ -37,6 +37,13 @@ export default defineConfig({ ), to: "shoelace/assets", }, + { + from: path.resolve( + __dirname, + "../CHANGELOG.md" + ), + to: "static/", + } ], }), new CssExtractRspackPlugin(), diff --git a/www/src/ts/app/app.ts b/www/src/ts/app/app.ts index 9af4435..f89ce51 100644 --- a/www/src/ts/app/app.ts +++ b/www/src/ts/app/app.ts @@ -21,6 +21,8 @@ import { openFile, saveFile } from "../utils"; import "../virtual_machine/ui"; import "./save"; import { SaveDialog } from "./save"; +import "./welcome"; +import { AppWelcome } from "./welcome"; declare global { const __COMMIT_HASH__: string; @@ -61,6 +63,7 @@ export class App extends BaseElement { @query("ace-ic10") editor: IC10Editor; @query("session-share-dialog") shareDialog: ShareSessionDialog; @query("save-dialog") saveDialog: SaveDialog; + @query("app-welcome") appWelcome: AppWelcome; // get editor() { // return this.renderRoot.querySelector("ace-ic10") as IC10Editor; @@ -83,6 +86,7 @@ export class App extends BaseElement { root.addEventListener("app-export", this._handleExport.bind(this)); root.addEventListener("app-save", this._handleSave.bind(this)); root.addEventListener("app-load", this._handleLoad.bind(this)); + root.addEventListener("app-changelog", this._handleChangelog.bind(this)); return root; } @@ -104,11 +108,54 @@ export class App extends BaseElement { + `; } - firstUpdated(): void {} + firstUpdated(): void { + setTimeout(() => { + this.checkSeenVersion(); + }, 2000); + } + + checkSeenVersion() { + const seenVersionsStr = window.localStorage.getItem("seenVersions"); + let seenVersions: string[] = []; + if (seenVersionsStr !== null && seenVersionsStr.length > 0) { + try { + const saved = JSON.parse(seenVersionsStr); + seenVersions = saved; + } catch (e) { + console.log("error pulling seen versions", e); + } + } + const ourVer = `${this.appVersion}_${this.gitVer}_${this.buildDate}`; + if (!seenVersions.includes(ourVer)) { + this.appWelcome.show(); + } + } + + afterWelcomeHide() { + const seenVersionsStr = window.localStorage.getItem("seenVersions"); + const seenVersions: string[] = []; + if (seenVersionsStr !== null && seenVersionsStr.length > 0) { + try { + const saved = JSON.parse(seenVersionsStr); + seenVersions.concat(saved); + } catch (e) { + console.log("error pulling seen versions", e); + } + } + const unique = new Set(seenVersions); + const ourVer = `${this.appVersion}_${this.gitVer}_${this.buildDate}`; + if (this.appWelcome.dontShowAgain) { + unique.add(ourVer) + } else { + unique.delete(ourVer) + } + window.localStorage.setItem("seenVersions", JSON.stringify(Array.from(unique))); + } _handleShare(_e: Event) { // TODO: @@ -130,6 +177,10 @@ export class App extends BaseElement { _handleOpenFile(_e: Event) { openFile(window.Editor.editor); } + + _handleChangelog(_e: Event) { + this.appWelcome.show(); + } } diff --git a/www/src/ts/app/gfm-styles.ts b/www/src/ts/app/gfm-styles.ts new file mode 100644 index 0000000..4284123 --- /dev/null +++ b/www/src/ts/app/gfm-styles.ts @@ -0,0 +1,1113 @@ +import { css } from "lit"; + +export const gfmStyles = css` + /*dark*/ + + .markdown-body { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + margin: 0; + color: #e6edf3; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font-size: 16px; + line-height: 1.5; + word-wrap: break-word; + } + + .markdown-body .octicon { + display: inline-block; + fill: currentColor; + vertical-align: text-bottom; + } + + .markdown-body h1:hover .anchor .octicon-link:before, + .markdown-body h2:hover .anchor .octicon-link:before, + .markdown-body h3:hover .anchor .octicon-link:before, + .markdown-body h4:hover .anchor .octicon-link:before, + .markdown-body h5:hover .anchor .octicon-link:before, + .markdown-body h6:hover .anchor .octicon-link:before { + width: 16px; + height: 16px; + content: " "; + display: inline-block; + background-color: currentColor; + -webkit-mask-image: url("data:image/svg+xml,"); + mask-image: url("data:image/svg+xml,"); + } + + .markdown-body details, + .markdown-body figcaption, + .markdown-body figure { + display: block; + } + + .markdown-body summary { + display: list-item; + } + + .markdown-body [hidden] { + display: none !important; + } + + .markdown-body a { + background-color: transparent; + color: #2f81f7; + text-decoration: none; + } + + .markdown-body abbr[title] { + border-bottom: none; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + } + + .markdown-body b, + .markdown-body strong { + font-weight: 600; + } + + .markdown-body dfn { + font-style: italic; + } + + .markdown-body h1 { + margin: 0.67em 0; + font-weight: 600; + padding-bottom: 0.3em; + font-size: 2em; + border-bottom: 1px solid #21262d; + } + + .markdown-body mark { + background-color: rgba(187, 128, 9, 0.15); + color: #e6edf3; + } + + .markdown-body small { + font-size: 90%; + } + + .markdown-body sub, + .markdown-body sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + + .markdown-body sub { + bottom: -0.25em; + } + + .markdown-body sup { + top: -0.5em; + } + + .markdown-body img { + border-style: none; + max-width: 100%; + box-sizing: content-box; + background-color: #0d1117; + } + + .markdown-body code, + .markdown-body kbd, + .markdown-body pre, + .markdown-body samp { + font-family: monospace; + font-size: 1em; + } + + .markdown-body figure { + margin: 1em 40px; + } + + .markdown-body hr { + box-sizing: content-box; + overflow: hidden; + background: transparent; + border-bottom: 1px solid #21262d; + height: 0.25em; + padding: 0; + margin: 24px 0; + background-color: #30363d; + border: 0; + } + + .markdown-body input { + font: inherit; + margin: 0; + overflow: visible; + font-family: inherit; + font-size: inherit; + line-height: inherit; + } + + .markdown-body [type="button"], + .markdown-body [type="reset"], + .markdown-body [type="submit"] { + -webkit-appearance: button; + appearance: button; + } + + .markdown-body [type="checkbox"], + .markdown-body [type="radio"] { + box-sizing: border-box; + padding: 0; + } + + .markdown-body [type="number"]::-webkit-inner-spin-button, + .markdown-body [type="number"]::-webkit-outer-spin-button { + height: auto; + } + + .markdown-body [type="search"]::-webkit-search-cancel-button, + .markdown-body [type="search"]::-webkit-search-decoration { + -webkit-appearance: none; + appearance: none; + } + + .markdown-body ::-webkit-input-placeholder { + color: inherit; + opacity: 0.54; + } + + .markdown-body ::-webkit-file-upload-button { + -webkit-appearance: button; + appearance: button; + font: inherit; + } + + .markdown-body a:hover { + text-decoration: underline; + } + + .markdown-body ::placeholder { + color: #6e7681; + opacity: 1; + } + + .markdown-body hr::before { + display: table; + content: ""; + } + + .markdown-body hr::after { + display: table; + clear: both; + content: ""; + } + + .markdown-body table { + border-spacing: 0; + border-collapse: collapse; + display: block; + width: max-content; + max-width: 100%; + overflow: auto; + } + + .markdown-body td, + .markdown-body th { + padding: 0; + } + + .markdown-body details summary { + cursor: pointer; + } + + .markdown-body details:not([open]) > *:not(summary) { + display: none !important; + } + + .markdown-body a:focus, + .markdown-body [role="button"]:focus, + .markdown-body input[type="radio"]:focus, + .markdown-body input[type="checkbox"]:focus { + outline: 2px solid #2f81f7; + outline-offset: -2px; + box-shadow: none; + } + + .markdown-body a:focus:not(:focus-visible), + .markdown-body [role="button"]:focus:not(:focus-visible), + .markdown-body input[type="radio"]:focus:not(:focus-visible), + .markdown-body input[type="checkbox"]:focus:not(:focus-visible) { + outline: solid 1px transparent; + } + + .markdown-body a:focus-visible, + .markdown-body [role="button"]:focus-visible, + .markdown-body input[type="radio"]:focus-visible, + .markdown-body input[type="checkbox"]:focus-visible { + outline: 2px solid #2f81f7; + outline-offset: -2px; + box-shadow: none; + } + + .markdown-body a:not([class]):focus, + .markdown-body a:not([class]):focus-visible, + .markdown-body input[type="radio"]:focus, + .markdown-body input[type="radio"]:focus-visible, + .markdown-body input[type="checkbox"]:focus, + .markdown-body input[type="checkbox"]:focus-visible { + outline-offset: 0; + } + + .markdown-body kbd { + display: inline-block; + padding: 3px 5px; + font: + 11px ui-monospace, + SFMono-Regular, + SF Mono, + Menlo, + Consolas, + Liberation Mono, + monospace; + line-height: 10px; + color: #e6edf3; + vertical-align: middle; + background-color: #161b22; + border: solid 1px rgba(110, 118, 129, 0.4); + border-bottom-color: rgba(110, 118, 129, 0.4); + border-radius: 6px; + box-shadow: inset 0 -1px 0 rgba(110, 118, 129, 0.4); + } + + .markdown-body h1, + .markdown-body h2, + .markdown-body h3, + .markdown-body h4, + .markdown-body h5, + .markdown-body h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25; + } + + .markdown-body h2 { + font-weight: 600; + padding-bottom: 0.3em; + font-size: 1.5em; + border-bottom: 1px solid #21262d; + } + + .markdown-body h3 { + font-weight: 600; + font-size: 1.25em; + } + + .markdown-body h4 { + font-weight: 600; + font-size: 1em; + } + + .markdown-body h5 { + font-weight: 600; + font-size: 0.875em; + } + + .markdown-body h6 { + font-weight: 600; + font-size: 0.85em; + color: #848d97; + } + + .markdown-body p { + margin-top: 0; + margin-bottom: 10px; + } + + .markdown-body blockquote { + margin: 0; + padding: 0 1em; + color: #848d97; + border-left: 0.25em solid #30363d; + } + + .markdown-body ul, + .markdown-body ol { + margin-top: 0; + margin-bottom: 0; + padding-left: 2em; + list-style-type: disc; + } + + .markdown-body ol ol, + .markdown-body ul ol { + list-style-type: lower-roman; + } + + .markdown-body ul ul ol, + .markdown-body ul ol ol, + .markdown-body ol ul ol, + .markdown-body ol ol ol { + list-style-type: lower-alpha; + } + + .markdown-body dd { + margin-left: 0; + } + + .markdown-body tt, + .markdown-body code, + .markdown-body samp { + font-family: + ui-monospace, + SFMono-Regular, + SF Mono, + Menlo, + Consolas, + Liberation Mono, + monospace; + font-size: 12px; + } + + .markdown-body pre { + margin-top: 0; + margin-bottom: 0; + font-family: + ui-monospace, + SFMono-Regular, + SF Mono, + Menlo, + Consolas, + Liberation Mono, + monospace; + font-size: 12px; + word-wrap: normal; + } + + .markdown-body .octicon { + display: inline-block; + overflow: visible !important; + vertical-align: text-bottom; + fill: currentColor; + } + + .markdown-body input::-webkit-outer-spin-button, + .markdown-body input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; + appearance: none; + } + + .markdown-body .mr-2 { + margin-right: 8px !important; + } + + .markdown-body::before { + display: table; + content: ""; + } + + .markdown-body::after { + display: table; + clear: both; + content: ""; + } + + .markdown-body > *:first-child { + margin-top: 0 !important; + } + + .markdown-body > *:last-child { + margin-bottom: 0 !important; + } + + .markdown-body a:not([href]) { + color: inherit; + text-decoration: none; + } + + .markdown-body .absent { + color: #f85149; + } + + .markdown-body .anchor { + float: left; + padding-right: 4px; + margin-left: -20px; + line-height: 1; + } + + .markdown-body .anchor:focus { + outline: none; + } + + .markdown-body p, + .markdown-body blockquote, + .markdown-body ul, + .markdown-body ol, + .markdown-body dl, + .markdown-body table, + .markdown-body pre, + .markdown-body details { + margin-top: 0; + margin-bottom: 16px; + } + + .markdown-body blockquote > :first-child { + margin-top: 0; + } + + .markdown-body blockquote > :last-child { + margin-bottom: 0; + } + + .markdown-body h1 .octicon-link, + .markdown-body h2 .octicon-link, + .markdown-body h3 .octicon-link, + .markdown-body h4 .octicon-link, + .markdown-body h5 .octicon-link, + .markdown-body h6 .octicon-link { + color: #e6edf3; + vertical-align: middle; + visibility: hidden; + } + + .markdown-body h1:hover .anchor, + .markdown-body h2:hover .anchor, + .markdown-body h3:hover .anchor, + .markdown-body h4:hover .anchor, + .markdown-body h5:hover .anchor, + .markdown-body h6:hover .anchor { + text-decoration: none; + } + + .markdown-body h1:hover .anchor .octicon-link, + .markdown-body h2:hover .anchor .octicon-link, + .markdown-body h3:hover .anchor .octicon-link, + .markdown-body h4:hover .anchor .octicon-link, + .markdown-body h5:hover .anchor .octicon-link, + .markdown-body h6:hover .anchor .octicon-link { + visibility: visible; + } + + .markdown-body h1 tt, + .markdown-body h1 code, + .markdown-body h2 tt, + .markdown-body h2 code, + .markdown-body h3 tt, + .markdown-body h3 code, + .markdown-body h4 tt, + .markdown-body h4 code, + .markdown-body h5 tt, + .markdown-body h5 code, + .markdown-body h6 tt, + .markdown-body h6 code { + padding: 0 0.2em; + font-size: inherit; + } + + .markdown-body summary h1, + .markdown-body summary h2, + .markdown-body summary h3, + .markdown-body summary h4, + .markdown-body summary h5, + .markdown-body summary h6 { + display: inline-block; + } + + .markdown-body summary h1 .anchor, + .markdown-body summary h2 .anchor, + .markdown-body summary h3 .anchor, + .markdown-body summary h4 .anchor, + .markdown-body summary h5 .anchor, + .markdown-body summary h6 .anchor { + margin-left: -40px; + } + + .markdown-body summary h1, + .markdown-body summary h2 { + padding-bottom: 0; + border-bottom: 0; + } + + .markdown-body ul.no-list, + .markdown-body ol.no-list { + padding: 0; + list-style-type: none; + } + + .markdown-body ol[type="a s"] { + list-style-type: lower-alpha; + } + + .markdown-body ol[type="A s"] { + list-style-type: upper-alpha; + } + + .markdown-body ol[type="i s"] { + list-style-type: lower-roman; + } + + .markdown-body ol[type="I s"] { + list-style-type: upper-roman; + } + + .markdown-body ol[type="1"] { + list-style-type: decimal; + } + + .markdown-body div > ol:not([type]) { + list-style-type: decimal; + } + + .markdown-body ul ul, + .markdown-body ul ol, + .markdown-body ol ol, + .markdown-body ol ul { + margin-top: 0; + margin-bottom: 0; + } + + .markdown-body li > p { + margin-top: 16px; + } + + .markdown-body li + li { + margin-top: 0.25em; + } + + .markdown-body dl { + padding: 0; + } + + .markdown-body dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: 600; + } + + .markdown-body dl dd { + padding: 0 16px; + margin-bottom: 16px; + } + + .markdown-body table th { + font-weight: 600; + } + + .markdown-body table th, + .markdown-body table td { + padding: 6px 13px; + border: 1px solid #30363d; + } + + .markdown-body table td > :last-child { + margin-bottom: 0; + } + + .markdown-body table tr { + background-color: #0d1117; + border-top: 1px solid #21262d; + } + + .markdown-body table tr:nth-child(2n) { + background-color: #161b22; + } + + .markdown-body table img { + background-color: transparent; + } + + .markdown-body img[align="right"] { + padding-left: 20px; + } + + .markdown-body img[align="left"] { + padding-right: 20px; + } + + .markdown-body .emoji { + max-width: none; + vertical-align: text-top; + background-color: transparent; + } + + .markdown-body span.frame { + display: block; + overflow: hidden; + } + + .markdown-body span.frame > span { + display: block; + float: left; + width: auto; + padding: 7px; + margin: 13px 0 0; + overflow: hidden; + border: 1px solid #30363d; + } + + .markdown-body span.frame span img { + display: block; + float: left; + } + + .markdown-body span.frame span span { + display: block; + padding: 5px 0 0; + clear: both; + color: #e6edf3; + } + + .markdown-body span.align-center { + display: block; + overflow: hidden; + clear: both; + } + + .markdown-body span.align-center > span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: center; + } + + .markdown-body span.align-center span img { + margin: 0 auto; + text-align: center; + } + + .markdown-body span.align-right { + display: block; + overflow: hidden; + clear: both; + } + + .markdown-body span.align-right > span { + display: block; + margin: 13px 0 0; + overflow: hidden; + text-align: right; + } + + .markdown-body span.align-right span img { + margin: 0; + text-align: right; + } + + .markdown-body span.float-left { + display: block; + float: left; + margin-right: 13px; + overflow: hidden; + } + + .markdown-body span.float-left span { + margin: 13px 0 0; + } + + .markdown-body span.float-right { + display: block; + float: right; + margin-left: 13px; + overflow: hidden; + } + + .markdown-body span.float-right > span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: right; + } + + .markdown-body code, + .markdown-body tt { + padding: 0.2em 0.4em; + margin: 0; + font-size: 85%; + white-space: break-spaces; + background-color: rgba(110, 118, 129, 0.4); + border-radius: 6px; + } + + .markdown-body code br, + .markdown-body tt br { + display: none; + } + + .markdown-body del code { + text-decoration: inherit; + } + + .markdown-body samp { + font-size: 85%; + } + + .markdown-body pre code { + font-size: 100%; + } + + .markdown-body pre > code { + padding: 0; + margin: 0; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; + } + + .markdown-body .highlight { + margin-bottom: 16px; + } + + .markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal; + } + + .markdown-body .highlight pre, + .markdown-body pre { + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + color: #e6edf3; + background-color: #161b22; + border-radius: 6px; + } + + .markdown-body pre code, + .markdown-body pre tt { + display: inline; + max-width: auto; + padding: 0; + margin: 0; + overflow: visible; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; + } + + .markdown-body .csv-data td, + .markdown-body .csv-data th { + padding: 5px; + overflow: hidden; + font-size: 12px; + line-height: 1; + text-align: left; + white-space: nowrap; + } + + .markdown-body .csv-data .blob-num { + padding: 10px 8px 9px; + text-align: right; + background: #0d1117; + border: 0; + } + + .markdown-body .csv-data tr { + border-top: 0; + } + + .markdown-body .csv-data th { + font-weight: 600; + background: #161b22; + border-top: 0; + } + + .markdown-body [data-footnote-ref]::before { + content: "["; + } + + .markdown-body [data-footnote-ref]::after { + content: "]"; + } + + .markdown-body .footnotes { + font-size: 12px; + color: #848d97; + border-top: 1px solid #30363d; + } + + .markdown-body .footnotes ol { + padding-left: 16px; + } + + .markdown-body .footnotes ol ul { + display: inline-block; + padding-left: 16px; + margin-top: 16px; + } + + .markdown-body .footnotes li { + position: relative; + } + + .markdown-body .footnotes li:target::before { + position: absolute; + top: -8px; + right: -8px; + bottom: -8px; + left: -24px; + pointer-events: none; + content: ""; + border: 2px solid #1f6feb; + border-radius: 6px; + } + + .markdown-body .footnotes li:target { + color: #e6edf3; + } + + .markdown-body .footnotes .data-footnote-backref g-emoji { + font-family: monospace; + } + + .markdown-body .pl-c { + color: #8b949e; + } + + .markdown-body .pl-c1, + .markdown-body .pl-s .pl-v { + color: #79c0ff; + } + + .markdown-body .pl-e, + .markdown-body .pl-en { + color: #d2a8ff; + } + + .markdown-body .pl-smi, + .markdown-body .pl-s .pl-s1 { + color: #c9d1d9; + } + + .markdown-body .pl-ent { + color: #7ee787; + } + + .markdown-body .pl-k { + color: #ff7b72; + } + + .markdown-body .pl-s, + .markdown-body .pl-pds, + .markdown-body .pl-s .pl-pse .pl-s1, + .markdown-body .pl-sr, + .markdown-body .pl-sr .pl-cce, + .markdown-body .pl-sr .pl-sre, + .markdown-body .pl-sr .pl-sra { + color: #a5d6ff; + } + + .markdown-body .pl-v, + .markdown-body .pl-smw { + color: #ffa657; + } + + .markdown-body .pl-bu { + color: #f85149; + } + + .markdown-body .pl-ii { + color: #f0f6fc; + background-color: #8e1519; + } + + .markdown-body .pl-c2 { + color: #f0f6fc; + background-color: #b62324; + } + + .markdown-body .pl-sr .pl-cce { + font-weight: bold; + color: #7ee787; + } + + .markdown-body .pl-ml { + color: #f2cc60; + } + + .markdown-body .pl-mh, + .markdown-body .pl-mh .pl-en, + .markdown-body .pl-ms { + font-weight: bold; + color: #1f6feb; + } + + .markdown-body .pl-mi { + font-style: italic; + color: #c9d1d9; + } + + .markdown-body .pl-mb { + font-weight: bold; + color: #c9d1d9; + } + + .markdown-body .pl-md { + color: #ffdcd7; + background-color: #67060c; + } + + .markdown-body .pl-mi1 { + color: #aff5b4; + background-color: #033a16; + } + + .markdown-body .pl-mc { + color: #ffdfb6; + background-color: #5a1e02; + } + + .markdown-body .pl-mi2 { + color: #c9d1d9; + background-color: #1158c7; + } + + .markdown-body .pl-mdr { + font-weight: bold; + color: #d2a8ff; + } + + .markdown-body .pl-ba { + color: #8b949e; + } + + .markdown-body .pl-sg { + color: #484f58; + } + + .markdown-body .pl-corl { + text-decoration: underline; + color: #a5d6ff; + } + + .markdown-body g-emoji { + display: inline-block; + min-width: 1ch; + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-size: 1em; + font-style: normal !important; + font-weight: 400; + line-height: 1; + vertical-align: -0.075em; + } + + .markdown-body g-emoji img { + width: 1em; + height: 1em; + } + + .markdown-body .task-list-item { + list-style-type: none; + } + + .markdown-body .task-list-item label { + font-weight: 400; + } + + .markdown-body .task-list-item.enabled label { + cursor: pointer; + } + + .markdown-body .task-list-item + .task-list-item { + margin-top: 4px; + } + + .markdown-body .task-list-item .handle { + display: none; + } + + .markdown-body .task-list-item-checkbox { + margin: 0 0.2em 0.25em -1.4em; + vertical-align: middle; + } + + .markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox { + margin: 0 -1.6em 0.25em 0.2em; + } + + .markdown-body .contains-task-list { + position: relative; + } + + .markdown-body .contains-task-list:hover .task-list-item-convert-container, + .markdown-body + .contains-task-list:focus-within + .task-list-item-convert-container { + display: block; + width: auto; + height: 24px; + overflow: visible; + clip: auto; + } + + .markdown-body ::-webkit-calendar-picker-indicator { + filter: invert(50%); + } + + .markdown-body .markdown-alert { + padding: 8px 16px; + margin-bottom: 16px; + color: inherit; + border-left: 0.25em solid #30363d; + } + + .markdown-body .markdown-alert > :first-child { + margin-top: 0; + } + + .markdown-body .markdown-alert > :last-child { + margin-bottom: 0; + } + + .markdown-body .markdown-alert .markdown-alert-title { + display: flex; + font-weight: 500; + align-items: center; + line-height: 1; + } + + .markdown-body .markdown-alert.markdown-alert-note { + border-left-color: #1f6feb; + } + + .markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title { + color: #2f81f7; + } + + .markdown-body .markdown-alert.markdown-alert-important { + border-left-color: #8957e5; + } + + .markdown-body + .markdown-alert.markdown-alert-important + .markdown-alert-title { + color: #a371f7; + } + + .markdown-body .markdown-alert.markdown-alert-warning { + border-left-color: #9e6a03; + } + + .markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title { + color: #d29922; + } + + .markdown-body .markdown-alert.markdown-alert-tip { + border-left-color: #238636; + } + + .markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title { + color: #3fb950; + } + + .markdown-body .markdown-alert.markdown-alert-caution { + border-left-color: #da3633; + } + + .markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title { + color: #f85149; + } +`; diff --git a/www/src/ts/app/nav.ts b/www/src/ts/app/nav.ts index 51389cd..a607159 100644 --- a/www/src/ts/app/nav.ts +++ b/www/src/ts/app/nav.ts @@ -157,6 +157,11 @@ export class Nav extends BaseElement { Demo + + + Changelog + + @@ -246,6 +251,10 @@ export class Nav extends BaseElement { break; case "preset-demo": window.location.hash = "demo"; + break; + case "changelog": + this.dispatchEvent(new CustomEvent("app-changelog", { bubbles: true })); + break; default: console.log("Unknown main menu item", item.value); } diff --git a/www/src/ts/app/welcome.ts b/www/src/ts/app/welcome.ts new file mode 100644 index 0000000..b93faae --- /dev/null +++ b/www/src/ts/app/welcome.ts @@ -0,0 +1,75 @@ +import { html, css } from "lit"; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { customElement, property, query, state } from "lit/decorators.js"; +import { BaseElement, defaultCss } from "../components"; +import { SlDialog, SlSwitch } from "@shoelace-style/shoelace"; +import { until } from "lit/directives/until.js"; + +import "@shoelace-style/shoelace/dist/components/spinner/spinner.js"; +import '@shoelace-style/shoelace/dist/components/switch/switch.js'; + +import { marked } from "marked"; +import { gfmStyles } from "./gfm-styles"; + +@customElement("app-welcome") +export class AppWelcome extends BaseElement { + static styles = [ + ...defaultCss, + gfmStyles, + css` + .welcome-dialog { + --width: 42rem; + } + `, + ]; + + @property({ type: Boolean }) dontShowAgain: boolean; + + constructor() { + super(); + this.dontShowAgain = true; + } + + @query("sl-dialog.welcome-dialog") dialog: SlDialog; + @query("sl-switch.dont-show-switch") dontShowSwitch: SlSwitch; + + hide() { + this.dialog?.hide(); + } + + show() { + this.dialog?.show(); + } + + async getChangelog() { + const response = await fetch("static/CHANGELOG.md"); + const blob = await response.blob(); + const markdown = await blob.text(); + const renderedText = await marked(markdown, { + async: true, + gfm: true, + }); + return unsafeHTML(renderedText); + } + + render() { + return html` + +
Hey there!
+

Looks like there have been some updates since you've last visit.

+
+

Check out the changelog below.

+
+ ${until(this.getChangelog(), html``)} +
+
+ Don't show again +
+
+ `; + } + + _dontShowSwitchChange(e: CustomEvent) { + this.dontShowAgain = this.dontShowSwitch.checked; + } +} diff --git a/www/src/ts/utils.ts b/www/src/ts/utils.ts index e7e7b07..62c94b6 100644 --- a/www/src/ts/utils.ts +++ b/www/src/ts/utils.ts @@ -13,9 +13,7 @@ export function docReady(fn: () => void) { } function isZeroNegative(zero: number) { - const isZero = zero === 0; - const isNegative = 1 / zero === -Infinity; - return isNegative && isZero; + return Object.is(zero, -0) } export function numberToString(n: number): string {