diff --git a/.changeset/nasty-suits-compete.md b/.changeset/nasty-suits-compete.md new file mode 100644 index 00000000..f89fa1f5 --- /dev/null +++ b/.changeset/nasty-suits-compete.md @@ -0,0 +1,6 @@ +--- +"@hyperbook/markdown": minor +"@hyperbook/types": minor +--- + +add option to show a qr code to the current page diff --git a/packages/markdown/assets/client.js b/packages/markdown/assets/client.js index e30f3669..3698b4f9 100644 --- a/packages/markdown/assets/client.js +++ b/packages/markdown/assets/client.js @@ -33,6 +33,17 @@ var hyperbook = (function () { const tocDrawerEl = document.getElementById("toc-drawer"); tocDrawerEl.open = !tocDrawerEl.open; } + + function qrcodeOpen() { + const qrCodeDialog = document.getElementById("qrcode-dialog"); + qrCodeDialog.showModal(); + } + + function qrcodeClose() { + const qrCodeDialog = document.getElementById("qrcode-dialog"); + qrCodeDialog.close(); + } + function navToggle() { const navDrawerEl = document.getElementById("nav-drawer"); navDrawerEl.open = !navDrawerEl.open; @@ -83,5 +94,7 @@ var hyperbook = (function () { toggleBookmark, navToggle, tocToggle, + qrcodeOpen, + qrcodeClose, }; })(); diff --git a/packages/markdown/assets/content.css b/packages/markdown/assets/content.css index c25ea83b..fc8e106b 100644 --- a/packages/markdown/assets/content.css +++ b/packages/markdown/assets/content.css @@ -370,7 +370,8 @@ figure { background-color: var(--color-text); } -.hyperbook-markdown #toc-toggle { +.hyperbook-markdown #toc-toggle, +.hyperbook-markdown #qrcode-open { background: var(--color-background); border-color: var(--color-nav-border); cursor: pointer; @@ -399,7 +400,84 @@ figure { text-decoration: underline; } -.hyperbook-markdown #toc-toggle { +.hyperbook-markdown #qrcode-dialog { + background: var(--color-background); + border: 1px solid var(--color-brand); + width: 100%; + height: 100%; +} + +#qrcode-dialog .container { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; + padding: 16px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; +} + +#qrcode-dialog .name { + color: var(--color-text); + text-align: center; + font-size: 2rem; +} + +#qrcode-dialog .url { + color: var(--color-text); + text-align: center; + font-size: 1.25rem; +} + +#qrcode-dialog .close { + background: none; + border: none; + font-size: 2rem; + color: var(--color-text); + cursor: pointer; + position: absolute; + font: monospace; + top: 0px; + right: 0px; + width: 48px; + height: 48px; + display: flex; + justify-content: center; + align-items: center; + background: var(--color-background); + border-radius: 8px; +} + +#qrcode-dialog .close:hover .close-icon { + background-color: var(--color-brand); +} + +.hyperbook-markdown #qrcode-dialog svg { + width: 100%; + max-width: 512px; + margin: 0 auto; +} + +.hyperbook-markdown .close-icon { + background-color: var(--color-text); + width: 32px; + height: 32px; + mask-image: url('data:image/svg+xml,'); +} + +.hyperbook-markdown .qrcode-icon { + background-color: var(--color-text); + width: 32px; + height: 32px; + mask-image: url('data:image/svg+xml,'); +} + +.hyperbook-markdown #toc-toggle, +.hyperbook-markdown #qrcode-open { position: fixed; padding: 4px; top: 90px; @@ -413,7 +491,12 @@ figure { z-index: 1000; } -.hyperbook-markdown #toc-toggle:hover { +.hyperbook-markdown #qrcode-open { + top: 140px; +} + +.hyperbook-markdown #toc-toggle:hover, +.hyperbook-markdown #qrcode-toggle:hover { opacity: 1; } diff --git a/packages/markdown/devBuild.mjs b/packages/markdown/devBuild.mjs index 0ff92672..3b72b6af 100644 --- a/packages/markdown/devBuild.mjs +++ b/packages/markdown/devBuild.mjs @@ -6,6 +6,7 @@ const markdown = await fs.readFile("dev.md", "utf8"); const result = await process(markdown, { root: "", + qrcode: true, config: { name: "Hyperbook Dokumenation", description: "Dokumentation für Hyperbook erstellt mit Hyperbook", diff --git a/packages/markdown/package.json b/packages/markdown/package.json index f9317a73..4edb6222 100644 --- a/packages/markdown/package.json +++ b/packages/markdown/package.json @@ -41,6 +41,7 @@ "@rehype-pretty/transformers": "^0.13.2", "decircular": "^1.0.0", "handlebars": "^4.7.8", + "hast-util-from-html": "^2.0.3", "is-obj": "^3.0.0", "js-base64": "^3.7.7", "mdast-util-directive": "^3.0.0", diff --git a/packages/markdown/src/process.ts b/packages/markdown/src/process.ts index 949342cc..0748dd79 100644 --- a/packages/markdown/src/process.ts +++ b/packages/markdown/src/process.ts @@ -45,6 +45,7 @@ import remarkDirectiveStruktog from "./remarkDirectiveStruktog"; import remarkDirectiveTerm from "./remarkDirectiveTerm"; import remarkLink from "./remarkLink"; import remarkDirectivePagelist from "./remarkDirectivePagelist"; +import rehypeQrCode from "./rehypeQrCode"; const remark = (ctx: HyperbookContext) => { const remarkPlugins: PluggableList = [ @@ -88,6 +89,7 @@ const remark = (ctx: HyperbookContext) => { const rehypePlugins: PluggableList = [ rehypeTableOfContents(ctx), + rehypeQrCode(ctx), rehypeKatex, [ rehypePrettyCode, diff --git a/packages/markdown/src/rehypeQrCode.ts b/packages/markdown/src/rehypeQrCode.ts new file mode 100644 index 00000000..70a74e60 --- /dev/null +++ b/packages/markdown/src/rehypeQrCode.ts @@ -0,0 +1,127 @@ +// Register directive nodes in mdast: +/// +// +import { HyperbookContext } from "@hyperbook/types"; +import { ElementContent, Root } from "hast"; +import { VFile } from "vfile"; +import QRCode from "qrcode-svg"; +import { fromHtml } from "hast-util-from-html"; + +export default (ctx: HyperbookContext) => () => { + const qrcode = ctx.config.qrcode || ctx.navigation.current?.qrcode || true; + return (tree: Root, file: VFile) => { + const originalChildren = tree.children as ElementContent[]; + + if (!qrcode || !ctx.navigation.current?.href) { + return; + } + + const qr = new QRCode({ + content: ctx.navigation.current.href, + padding: 0, + width: 512, + height: 512, + color: "var(--color-text)", + container: "svg-viewbox", + background: "var(--color-background)", + ecl: "M", + }).svg(); + + const qrcodeDialog: ElementContent[] = [ + { + type: "element", + tagName: "button", + properties: { + id: "qrcode-open", + onclick: "hyperbook.qrcodeOpen()", + title: "QR-Code", + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + class: "qrcode-icon", + }, + children: [], + }, + ], + }, + { + type: "element", + tagName: "dialog", + properties: { + id: "qrcode-dialog", + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + class: "container", + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + class: "name", + }, + children: [ + { + type: "text", + value: ctx.navigation.current.name || ctx.config.name, + }, + ], + }, + ...(fromHtml(qr).children as any), + { + type: "element", + tagName: "div", + properties: { + class: "url", + }, + children: [ + { + type: "text", + value: `${ctx.makeUrl( + ctx.navigation.current?.href || "", + "public", + )}`, + }, + ], + }, + ], + }, + { + type: "element", + tagName: "button", + properties: { + class: "close", + onclick: "hyperbook.qrcodeClose()", + }, + children: [ + { + type: "element", + tagName: "div", + properties: { + class: "close-icon", + }, + children: [], + }, + ], + }, + ], + }, + ]; + + if ( + originalChildren[0].type === "element" && + originalChildren[0].tagName === "div" + ) { + originalChildren[0].children.push(...qrcodeDialog); + } + + tree.children = originalChildren; + }; +}; diff --git a/packages/markdown/src/rehypeTableOfContents.ts b/packages/markdown/src/rehypeTableOfContents.ts index f4b2512e..e0a89669 100644 --- a/packages/markdown/src/rehypeTableOfContents.ts +++ b/packages/markdown/src/rehypeTableOfContents.ts @@ -11,6 +11,10 @@ export default (ctx: HyperbookContext) => () => { const headings = file.data.headings || []; const originalChildren = tree.children as ElementContent[]; + if (!showToc) { + return; + } + const tocSidebar: ElementContent[] = [ { type: "element", diff --git a/packages/markdown/tests/__snapshots__/process.test.ts.snap b/packages/markdown/tests/__snapshots__/process.test.ts.snap index 9ca96cf0..8eecbaf1 100644 --- a/packages/markdown/tests/__snapshots__/process.test.ts.snap +++ b/packages/markdown/tests/__snapshots__/process.test.ts.snap @@ -88,7 +88,243 @@ HYPERBOOK_ASSETS = "assets/"
def func():
   pass
- + + +
+
Markdown Referenz
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/markdown
+
+
✎ GitHub© Copyright 2024 by OpenPatch
" `; @@ -384,7 +620,243 @@ HYPERBOOK_ASSETS = "assets/" - + + +
+
Markdown Referenz
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/markdown
+
+
✎ GitHub© Copyright 2024 by OpenPatch
" `; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index d473fcd3..93ca99e5 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -37,6 +37,7 @@ export type Language = "de" | "en" | "fr" | "es" | "it" | "pt" | "nl"; export type HyperbookPageFrontmatter = { name: string; lang?: Language; + qrcode?: boolean; description?: string; keywords?: string[]; scripts?: string[]; @@ -76,6 +77,7 @@ export type HyperbookJson = { description?: string; logo?: string; allowDangerousHtml?: boolean; + qrcode?: boolean; author?: { name?: string; url?: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0044220f..d3407727 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -208,6 +208,9 @@ importers: handlebars: specifier: ^4.7.8 version: 4.7.8 + hast-util-from-html: + specifier: ^2.0.3 + version: 2.0.3 is-obj: specifier: ^3.0.0 version: 3.0.0 diff --git a/website/de/book/configuration/book.md b/website/de/book/configuration/book.md index 939ca42e..a9cad128 100644 --- a/website/de/book/configuration/book.md +++ b/website/de/book/configuration/book.md @@ -34,7 +34,8 @@ von Optionen, die du definieren kannst. Optionen mit einem "\*" müssen gesetzt | links | Hier können Links hinzugefügt werden, welche in der rechten oberen Ecke angezeigt werden. Schaue dir dazu das untere Beispiel an. | | styles | Hier können Links zu eigenen CSS-Styles gesetzt werden. | | scripts | Hier können Links zu eigenen JavaScript-Dateien gesetzt werden. | -| allowDangerousHtml | Erlaube HTML im Hyperbook. Dies kann zu inkompatibilität in zukünftigen Versionen führen. | +| allowDangerousHtml | Erlaube HTML im Hyperbook. Dies kann zu Inkompatibilität in zukünftigen Versionen führen. | +| qrcode | Zeigt ein Icon, um einen QR-Code zur aktuellen Seite anzuzeigen. | Hier ist eine Beispielkonfiguration: diff --git a/website/de/book/configuration/page.md b/website/de/book/configuration/page.md index 91d68bae..2718557a 100644 --- a/website/de/book/configuration/page.md +++ b/website/de/book/configuration/page.md @@ -41,5 +41,6 @@ Hier sind die Eigenschaften, die im Frontmatter gesetzt werden können: | next | Ein absoluter Pfad zur nächsten Seite. Dies überschreibt index und hide. Du kannst außerdem nichts setzen, sodass der Button versteckt wird. | | hide | Verstecke die Seite von der Navigation. | | toc | Zeige ein Inhaltsverzeichnis. Diese ist standardmäßig aktiviert für Seiten und deaktiviert für Begriffe im Glossar. | +| qrcode | Zeigt ein Icon, um einen QR-Code zur Seite anzuzeigen | | styles | Hier können Links zu eigenen CSS-Styles gesetzt werden. | | scripts | Hier können Links zu eigenen JavaScript-Dateien gesetzt werden. | diff --git a/website/de/hyperbook.json b/website/de/hyperbook.json index 65de4258..a0d55164 100644 --- a/website/de/hyperbook.json +++ b/website/de/hyperbook.json @@ -1,5 +1,6 @@ { "name": "Hyperbook Dokumenation", + "qrcode": true, "description": "Dokumentation für Hyperbook erstellt mit Hyperbook", "author": { "name": "OpenPatch", diff --git a/website/en/book/configuration/book.md b/website/en/book/configuration/book.md index c9e523fd..1527d1ba 100644 --- a/website/en/book/configuration/book.md +++ b/website/en/book/configuration/book.md @@ -34,6 +34,7 @@ can and part wise must set (indicated by a \*). | styles | Here you can add Links to custom CSS files. | | scripts | Here you can add links to custom JavaScript files. | | allowDangerousHtml | Allow HTML. This can lead to incompatibilities in future versions. | +| qrcode | Shows an icon, which opens a qr code to the current page. | Here is an example configuration: diff --git a/website/en/book/configuration/page.md b/website/en/book/configuration/page.md index f3ac6870..a8dfd992 100644 --- a/website/en/book/configuration/page.md +++ b/website/en/book/configuration/page.md @@ -34,3 +34,4 @@ Here are the properties you can set in the frontmatter: | toc | Show or hide a table of content for the page. This is on for pages and off for glossary entries by default | | styles | Here you can add Links to custom CSS files. | | scripts | Here you can add links to custom JavaScript files. | +| qrcode | Shows an icon, which opens a qr code to this page. | diff --git a/website/en/hyperbook.json b/website/en/hyperbook.json index cb4e0638..56d6738f 100644 --- a/website/en/hyperbook.json +++ b/website/en/hyperbook.json @@ -1,5 +1,6 @@ { "name": "Hyperbook Documentation", + "qrcode": true, "description": "Documentation for Hyperbook created with Hyperbook", "author": { "name": "OpenPatch",