Skip to content

Commit 8536870

Browse files
committed
add qr code option to current page
1 parent 7d5d714 commit 8536870

File tree

17 files changed

+704
-6
lines changed

17 files changed

+704
-6
lines changed

.changeset/nasty-suits-compete.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@hyperbook/markdown": minor
3+
"@hyperbook/types": minor
4+
---
5+
6+
add option to show a qr code to the current page

packages/markdown/assets/client.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ var hyperbook = (function () {
3333
const tocDrawerEl = document.getElementById("toc-drawer");
3434
tocDrawerEl.open = !tocDrawerEl.open;
3535
}
36+
37+
function qrcodeOpen() {
38+
const qrCodeDialog = document.getElementById("qrcode-dialog");
39+
qrCodeDialog.showModal();
40+
}
41+
42+
function qrcodeClose() {
43+
const qrCodeDialog = document.getElementById("qrcode-dialog");
44+
qrCodeDialog.close();
45+
}
46+
3647
function navToggle() {
3748
const navDrawerEl = document.getElementById("nav-drawer");
3849
navDrawerEl.open = !navDrawerEl.open;
@@ -83,5 +94,7 @@ var hyperbook = (function () {
8394
toggleBookmark,
8495
navToggle,
8596
tocToggle,
97+
qrcodeOpen,
98+
qrcodeClose,
8699
};
87100
})();

packages/markdown/assets/content.css

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ figure {
370370
background-color: var(--color-text);
371371
}
372372

373-
.hyperbook-markdown #toc-toggle {
373+
.hyperbook-markdown #toc-toggle,
374+
.hyperbook-markdown #qrcode-open {
374375
background: var(--color-background);
375376
border-color: var(--color-nav-border);
376377
cursor: pointer;
@@ -399,7 +400,77 @@ figure {
399400
text-decoration: underline;
400401
}
401402

402-
.hyperbook-markdown #toc-toggle {
403+
.hyperbook-markdown #qrcode-dialog {
404+
background: var(--color-background);
405+
border: 1px solid var(--color-brand);
406+
width: 100%;
407+
height: 100%;
408+
}
409+
410+
#qrcode-dialog .container {
411+
position: absolute;
412+
top: 0;
413+
bottom: 0;
414+
right: 0;
415+
left: 0;
416+
padding: 16px;
417+
display: flex;
418+
flex-direction: column;
419+
align-items: center;
420+
justify-content: center;
421+
}
422+
423+
#qrcode-dialog .info {
424+
color: var(--color-text);
425+
font-size: 1.25rem;
426+
margin-top: 8px;
427+
}
428+
429+
#qrcode-dialog .close {
430+
background: none;
431+
border: none;
432+
font-size: 2rem;
433+
color: var(--color-text);
434+
cursor: pointer;
435+
position: absolute;
436+
font: monospace;
437+
top: 0px;
438+
right: 0px;
439+
width: 48px;
440+
height: 48px;
441+
display: flex;
442+
justify-content: center;
443+
align-items: center;
444+
background: var(--color-background);
445+
border-radius: 8px;
446+
}
447+
448+
#qrcode-dialog .close:hover .close-icon {
449+
background-color: var(--color-brand);
450+
}
451+
452+
.hyperbook-markdown #qrcode-dialog svg {
453+
width: 100%;
454+
max-width: 512px;
455+
margin: 0 auto;
456+
}
457+
458+
.hyperbook-markdown .close-icon {
459+
background-color: var(--color-text);
460+
width: 32px;
461+
height: 32px;
462+
mask-image: url('data:image/svg+xml,<svg width="32px" height="32px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M5.29289 5.29289C5.68342 4.90237 6.31658 4.90237 6.70711 5.29289L12 10.5858L17.2929 5.29289C17.6834 4.90237 18.3166 4.90237 18.7071 5.29289C19.0976 5.68342 19.0976 6.31658 18.7071 6.70711L13.4142 12L18.7071 17.2929C19.0976 17.6834 19.0976 18.3166 18.7071 18.7071C18.3166 19.0976 17.6834 19.0976 17.2929 18.7071L12 13.4142L6.70711 18.7071C6.31658 19.0976 5.68342 19.0976 5.29289 18.7071C4.90237 18.3166 4.90237 17.6834 5.29289 17.2929L10.5858 12L5.29289 6.70711C4.90237 6.31658 4.90237 5.68342 5.29289 5.29289Z" fill="%230F1729"/></svg>');
463+
}
464+
465+
.hyperbook-markdown .qrcode-icon {
466+
background-color: var(--color-text);
467+
width: 32px;
468+
height: 32px;
469+
mask-image: url('data:image/svg+xml,<svg width="32px" height="32px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3 9h6V3H3zm1-5h4v4H4zm1 1h2v2H5zm10 4h6V3h-6zm1-5h4v4h-4zm1 1h2v2h-2zM3 21h6v-6H3zm1-5h4v4H4zm1 1h2v2H5zm15 2h1v2h-2v-3h1zm0-3h1v1h-1zm0-1v1h-1v-1zm-10 2h1v4h-1v-4zm-4-7v2H4v-1H3v-1h3zm4-3h1v1h-1zm3-3v2h-1V3h2v1zm-3 0h1v1h-1zm10 8h1v2h-2v-1h1zm-1-2v1h-2v2h-2v-1h1v-2h3zm-7 4h-1v-1h-1v-1h2v2zm6 2h1v1h-1zm2-5v1h-1v-1zm-9 3v1h-1v-1zm6 5h1v2h-2v-2zm-3 0h1v1h-1v1h-2v-1h1v-1zm0-1v-1h2v1zm0-5h1v3h-1v1h-1v1h-1v-2h-1v-1h3v-1h-1v-1zm-9 0v1H4v-1zm12 4h-1v-1h1zm1-2h-2v-1h2zM8 10h1v1H8v1h1v2H8v-1H7v1H6v-2h1v-2zm3 0V8h3v3h-2v-1h1V9h-1v1zm0-4h1v1h-1zm-1 4h1v1h-1zm3-3V6h1v1z"/><path fill="none" d="M0 0h24v24H0z"/></svg>');
470+
}
471+
472+
.hyperbook-markdown #toc-toggle,
473+
.hyperbook-markdown #qrcode-open {
403474
position: fixed;
404475
padding: 4px;
405476
top: 90px;
@@ -413,7 +484,12 @@ figure {
413484
z-index: 1000;
414485
}
415486

416-
.hyperbook-markdown #toc-toggle:hover {
487+
.hyperbook-markdown #qrcode-open {
488+
top: 140px;
489+
}
490+
491+
.hyperbook-markdown #toc-toggle:hover,
492+
.hyperbook-markdown #qrcode-toggle:hover {
417493
opacity: 1;
418494
}
419495

packages/markdown/devBuild.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const markdown = await fs.readFile("dev.md", "utf8");
66

77
const result = await process(markdown, {
88
root: "",
9+
qrcode: true,
910
config: {
1011
name: "Hyperbook Dokumenation",
1112
description: "Dokumentation für Hyperbook erstellt mit Hyperbook",

packages/markdown/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@rehype-pretty/transformers": "^0.13.2",
4242
"decircular": "^1.0.0",
4343
"handlebars": "^4.7.8",
44+
"hast-util-from-html": "^2.0.3",
4445
"is-obj": "^3.0.0",
4546
"js-base64": "^3.7.7",
4647
"mdast-util-directive": "^3.0.0",

packages/markdown/src/process.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import remarkDirectiveStruktog from "./remarkDirectiveStruktog";
4545
import remarkDirectiveTerm from "./remarkDirectiveTerm";
4646
import remarkLink from "./remarkLink";
4747
import remarkDirectivePagelist from "./remarkDirectivePagelist";
48+
import rehypeQrCode from "./rehypeQrCode";
4849

4950
const remark = (ctx: HyperbookContext) => {
5051
const remarkPlugins: PluggableList = [
@@ -88,6 +89,7 @@ const remark = (ctx: HyperbookContext) => {
8889

8990
const rehypePlugins: PluggableList = [
9091
rehypeTableOfContents(ctx),
92+
rehypeQrCode(ctx),
9193
rehypeKatex,
9294
[
9395
rehypePrettyCode,
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Register directive nodes in mdast:
2+
/// <reference types="mdast-util-directive" />
3+
//
4+
import { HyperbookContext } from "@hyperbook/types";
5+
import { ElementContent, Root } from "hast";
6+
import { VFile } from "vfile";
7+
import QRCode from "qrcode-svg";
8+
import { fromHtml } from "hast-util-from-html";
9+
10+
export default (ctx: HyperbookContext) => () => {
11+
const qrcode = ctx.config.qrcode || ctx.navigation.current?.qrcode || true;
12+
return (tree: Root, file: VFile) => {
13+
const originalChildren = tree.children as ElementContent[];
14+
15+
if (!qrcode || !ctx.navigation.current?.href) {
16+
return;
17+
}
18+
19+
const qr = new QRCode({
20+
content: ctx.navigation.current.href,
21+
padding: 0,
22+
width: 512,
23+
height: 512,
24+
color: "var(--color-text)",
25+
container: "svg-viewbox",
26+
background: "var(--color-background)",
27+
ecl: "M",
28+
}).svg();
29+
30+
const qrcodeDialog: ElementContent[] = [
31+
{
32+
type: "element",
33+
tagName: "button",
34+
properties: {
35+
id: "qrcode-open",
36+
onclick: "hyperbook.qrcodeOpen()",
37+
title: "QR-Code",
38+
},
39+
children: [
40+
{
41+
type: "element",
42+
tagName: "div",
43+
properties: {
44+
class: "qrcode-icon",
45+
},
46+
children: [],
47+
},
48+
],
49+
},
50+
{
51+
type: "element",
52+
tagName: "dialog",
53+
properties: {
54+
id: "qrcode-dialog",
55+
},
56+
children: [
57+
{
58+
type: "element",
59+
tagName: "div",
60+
properties: {
61+
class: "container",
62+
},
63+
children: [
64+
...(fromHtml(qr).children as any),
65+
{
66+
type: "element",
67+
tagName: "div",
68+
properties: {
69+
class: "info",
70+
},
71+
children: [
72+
{
73+
type: "text",
74+
value: `${ctx.config.name}: ${ctx.makeUrl(
75+
ctx.navigation.current?.href || "",
76+
"public",
77+
)}`,
78+
},
79+
],
80+
},
81+
],
82+
},
83+
{
84+
type: "element",
85+
tagName: "button",
86+
properties: {
87+
class: "close",
88+
onclick: "hyperbook.qrcodeClose()",
89+
},
90+
children: [
91+
{
92+
type: "element",
93+
tagName: "div",
94+
properties: {
95+
class: "close-icon",
96+
},
97+
children: [],
98+
},
99+
],
100+
},
101+
],
102+
},
103+
];
104+
105+
if (
106+
originalChildren[0].type === "element" &&
107+
originalChildren[0].tagName === "div"
108+
) {
109+
originalChildren[0].children.push(...qrcodeDialog);
110+
}
111+
112+
tree.children = originalChildren;
113+
};
114+
};

packages/markdown/src/rehypeTableOfContents.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export default (ctx: HyperbookContext) => () => {
1111
const headings = file.data.headings || [];
1212
const originalChildren = tree.children as ElementContent[];
1313

14+
if (!showToc) {
15+
return;
16+
}
17+
1418
const tocSidebar: ElementContent[] = [
1519
{
1620
type: "element",

0 commit comments

Comments
 (0)