@tblaisot/prez-as-adoc 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +18 -0
- package/README.adoc +30 -0
- package/asciidoctor/extensions/slides_treeprocessor.js +96 -0
- package/asciidoctor/extensions/speaker_notes_treeprocessor.js +40 -0
- package/asciidoctor/templates/admonition.js +10 -0
- package/asciidoctor/templates/document.js +86 -0
- package/asciidoctor/templates/package.json +3 -0
- package/asciidoctor/templates/preamble.js +11 -0
- package/asciidoctor/templates/section.js +29 -0
- package/asciidoctor/templates/slide.js +54 -0
- package/asciidoctor/templates/speaker_note.js +12 -0
- package/asciidoctor/templates/title.js +24 -0
- package/bespoke-plugins/bespoke-classes.js +44 -0
- package/bespoke-plugins/bespoke-debug.js +30 -0
- package/bespoke-plugins/bespoke-editor.js +96 -0
- package/bespoke-plugins/bespoke-hash.js +89 -0
- package/bespoke-plugins/bespoke-nav.js +46 -0
- package/bespoke-plugins/bespoke-overview.js +21 -0
- package/bespoke-plugins/bespoke-progress.js +18 -0
- package/bespoke-plugins/bespoke-scale.js +45 -0
- package/bespoke-plugins/bespoke-speaker.js +112 -0
- package/bespoke-plugins/bespoke-view-mode.js +51 -0
- package/bin/prez-as-adoc.js +52 -0
- package/package.json +30 -0
- package/statics/assets/bespoke-speaker.css +193 -0
- package/statics/assets/bespoke-speaker.html +45 -0
- package/statics/assets/bespoke-speaker.js +100 -0
- package/statics/styles/blocks/progress.css +56 -0
- package/statics/styles/debug.css +9 -0
- package/statics/styles/deck/deck-full.css +19 -0
- package/statics/styles/deck/deck-grid.css +13 -0
- package/statics/styles/deck/deck-list.css +58 -0
- package/statics/styles/deck/deck-pointless.css +5 -0
- package/statics/styles/deck/deck-print.css +11 -0
- package/statics/styles/deck/deck.css +31 -0
- package/statics/styles/main.css +6 -0
- package/statics/styles/normalize.css +226 -0
- package/statics/styles/slide/slide-full.css +16 -0
- package/statics/styles/slide/slide-list.css +31 -0
- package/statics/styles/slide/slide.css +28 -0
- package/vitejs/plugins/prez-as-adoc-plugin.js +114 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Publish Package to npmjs
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v3
|
|
10
|
+
# Setup .npmrc file to publish to npm
|
|
11
|
+
- uses: actions/setup-node@v3
|
|
12
|
+
with:
|
|
13
|
+
node-version: '16.x'
|
|
14
|
+
registry-url: 'https://registry.npmjs.org'
|
|
15
|
+
- run: npm ci
|
|
16
|
+
- run: npm publish --access public
|
|
17
|
+
env:
|
|
18
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.adoc
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
= prez-as-adoc
|
|
2
|
+
|
|
3
|
+
This is a project to generate Bespoke slide deck.
|
|
4
|
+
|
|
5
|
+
It allow to use slide templates (layout).
|
|
6
|
+
|
|
7
|
+
It can be used as a CLI or as a Vite plugin (prefered method).
|
|
8
|
+
|
|
9
|
+
== Usage as CLI
|
|
10
|
+
|
|
11
|
+
[source,bash]
|
|
12
|
+
----
|
|
13
|
+
prez-as-adoc --base_dir=./src --to_dir=./dist --slides-templates=./slide-templates ./src/index.adoc
|
|
14
|
+
----
|
|
15
|
+
|
|
16
|
+
== Usage as Vite Plugin
|
|
17
|
+
|
|
18
|
+
.vite.config.js
|
|
19
|
+
[source,bash]
|
|
20
|
+
----
|
|
21
|
+
// vite.config.js
|
|
22
|
+
import { prezAsAdocPlugin } from '@tblaisot/prez-as-adoc/vitejs/plugins/prez-as-adoc-plugin.js'
|
|
23
|
+
import { defineConfig } from 'vite'
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
plugins: [
|
|
27
|
+
prezAsAdocPlugin({slidesTemplates: ['./slide-templates']})
|
|
28
|
+
]
|
|
29
|
+
})
|
|
30
|
+
----
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {HELPERS} from "@tblaisot/asciidoctor-js-templates";
|
|
2
|
+
const {sectionTitle, slice_text, $h, $div} = HELPERS;
|
|
3
|
+
|
|
4
|
+
function debugAST(node) {
|
|
5
|
+
return {
|
|
6
|
+
context: node.getContext(),
|
|
7
|
+
blocks: node.getBlocks().map(n => debugAST(n)),
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function register(registry) {
|
|
12
|
+
registry.treeProcessor(function () {
|
|
13
|
+
const self = this
|
|
14
|
+
self.process(function (document) {
|
|
15
|
+
|
|
16
|
+
// document.findBy({context: 'page_break'}).forEach((node) => {
|
|
17
|
+
// const parentSection = node.getParent();
|
|
18
|
+
// const breakIndex = parentSection.getBlocks().indexOf(node)
|
|
19
|
+
// const blockAfterBreak = parentSection.getBlocks().slice(breakIndex)
|
|
20
|
+
// const grandParentSection = parentSection.getParent();
|
|
21
|
+
// const slide = self.createBlock(document, 'slide', '', {...parentSection.getAttributes(), level: parentSection.getLevel()});
|
|
22
|
+
// blockAfterBreak.forEach((block) => {
|
|
23
|
+
// slide.getBlocks().push(block);
|
|
24
|
+
// })
|
|
25
|
+
// grandParentSection.getBlocks().splice(grandParentSection.getBlocks().indexOf(parentSection), 0, slide);
|
|
26
|
+
//
|
|
27
|
+
// // remove block after
|
|
28
|
+
// parentSection.getBlocks().splice(breakIndex, parentSection.getBlocks().length - parentSection.getBlocks() - 1)
|
|
29
|
+
// })
|
|
30
|
+
|
|
31
|
+
function recurse(node) {
|
|
32
|
+
const sections = node.getSections()
|
|
33
|
+
if (sections.length === 0) return;
|
|
34
|
+
sections.forEach((section) => {
|
|
35
|
+
const slide = self.createBlock(document, 'slide', '', {
|
|
36
|
+
...section.getAttributes(),
|
|
37
|
+
level: section.getLevel()
|
|
38
|
+
});
|
|
39
|
+
const title = self.createBlock(slide, 'title', sectionTitle(section), {
|
|
40
|
+
level: section.getLevel(),
|
|
41
|
+
slot: 'title'
|
|
42
|
+
});
|
|
43
|
+
slide.getBlocks().push(title)
|
|
44
|
+
section.getBlocks().forEach((block) => {
|
|
45
|
+
slide.getBlocks().push(block);
|
|
46
|
+
})
|
|
47
|
+
node.getBlocks().splice(node.getBlocks().indexOf(section), 1); // remove node from parent
|
|
48
|
+
document.getBlocks().push(slide); // push slide to first level of the document
|
|
49
|
+
recurse(slide)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
recurse(document)
|
|
54
|
+
// console.log(JSON.stringify(debugAST(document), null, 2))
|
|
55
|
+
|
|
56
|
+
// create title slide
|
|
57
|
+
const attrName = document.getAttribute('slide-template-attr', 'slide-template', 'slide-template-attr');
|
|
58
|
+
|
|
59
|
+
const title_slide = self.createBlock(document, 'slide', '', {
|
|
60
|
+
[attrName]: 'title-slide', ...document.getAttributes(),
|
|
61
|
+
level: 0
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const _title_obj = document.getDoctitle({partition: true, use_fallback: true});
|
|
65
|
+
if (_title_obj.subtitle) {
|
|
66
|
+
const _slice = document.getHeader().isOption('slice');
|
|
67
|
+
const title1 = self.createBlock(title_slide, 'title', slice_text(_title_obj.main, _slice), {
|
|
68
|
+
level: 1,
|
|
69
|
+
slot: 'title'
|
|
70
|
+
});
|
|
71
|
+
const title2 = self.createBlock(title_slide, 'title', slice_text(_title_obj.subtitle, _slice), {
|
|
72
|
+
level: 2,
|
|
73
|
+
slot: 'subtitle'
|
|
74
|
+
});
|
|
75
|
+
title_slide.getBlocks().push(title1)
|
|
76
|
+
title_slide.getBlocks().push(title2)
|
|
77
|
+
} else {
|
|
78
|
+
const title = self.createBlock(title_slide, 'title', document.getHeader().getTitle(), {
|
|
79
|
+
level: 1,
|
|
80
|
+
slot: 'title'
|
|
81
|
+
});
|
|
82
|
+
title_slide.getBlocks().push(title)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const preambles = document.findBy({context: 'preamble'});
|
|
86
|
+
title_slide.getBlocks().push(...preambles);
|
|
87
|
+
|
|
88
|
+
document.getBlocks().splice(0, 0, title_slide);
|
|
89
|
+
|
|
90
|
+
// remove preamble block from document
|
|
91
|
+
document.getBlocks().splice(document.getBlocks().findIndex(b => b === preambles[0]), 1);
|
|
92
|
+
|
|
93
|
+
return document;
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function register(registry) {
|
|
2
|
+
registry.treeProcessor(function () {
|
|
3
|
+
const self = this
|
|
4
|
+
self.process(function (document) {
|
|
5
|
+
function recurse(node) {
|
|
6
|
+
const sections = node.getSections()
|
|
7
|
+
if(sections.length === 0) return;
|
|
8
|
+
sections.forEach((section) => {
|
|
9
|
+
section.findBy()
|
|
10
|
+
recurse(slide)
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
recurse(document)
|
|
15
|
+
document.findBy({context: 'open'}).forEach((node) => {
|
|
16
|
+
if (node.hasRole('aside') || node.hasRole('speaker') || node.hasRole('notes')) {
|
|
17
|
+
const note = self.createBlock(document, 'speaker_note', '', {...node.getAttributes()});
|
|
18
|
+
const blocks = node.getParent().getBlocks()
|
|
19
|
+
const node_idx = blocks.indexOf(node)
|
|
20
|
+
node.getBlocks().forEach((block) => {
|
|
21
|
+
note.getBlocks().push(block);
|
|
22
|
+
})
|
|
23
|
+
blocks[node_idx] = note;
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
document.findBy({context: 'admonition'}).forEach((node) => {
|
|
27
|
+
if (node.hasRole('aside') || node.hasRole('speaker') || node.hasRole('notes')) {
|
|
28
|
+
const note = self.createBlock(document, 'speaker_note', '', {...node.getAttributes()});
|
|
29
|
+
const blocks = node.getParent().getBlocks()
|
|
30
|
+
const node_idx = blocks.indexOf(node)
|
|
31
|
+
node.getBlocks().forEach((block) => {
|
|
32
|
+
note.getBlocks().push(block);
|
|
33
|
+
})
|
|
34
|
+
blocks[node_idx] = note;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
return document;
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
|
|
2
|
+
const {admonition: admonition_template} = TEMPLATES;
|
|
3
|
+
const {$aside} = HELPERS;
|
|
4
|
+
|
|
5
|
+
module.exports = function ({node}) {
|
|
6
|
+
if (node.hasRole('speaker')) {
|
|
7
|
+
return $aside({role: 'notes', class: 'speaker-notes'}, node.getContent())
|
|
8
|
+
}
|
|
9
|
+
return admonition_template({node})
|
|
10
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
|
|
2
|
+
const {$, $metaIf, toAttribute, toAttributes,isEmptyString} = HELPERS;
|
|
3
|
+
|
|
4
|
+
function getFavicon(node) {
|
|
5
|
+
let favicon = ''
|
|
6
|
+
if (node.document.hasAttribute('favicon')) {
|
|
7
|
+
let icon_href = node.document.getAttribute('favicon');
|
|
8
|
+
if (isEmptyString(icon_href)) {
|
|
9
|
+
icon_href = 'favicon.ico';
|
|
10
|
+
}
|
|
11
|
+
const icon_ext = icon_href.split('.').pop();
|
|
12
|
+
const icon_type = icon_ext === 'ico' ? 'image/x-icon' : `image/${icon_ext}`;
|
|
13
|
+
favicon = $('link', {rel: "icon", type: icon_type, href: icon_href});
|
|
14
|
+
}
|
|
15
|
+
return favicon
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// false needs to be verbatim everything else is a string.
|
|
19
|
+
// Calling side isn't responsible for quoting so we are doing it here
|
|
20
|
+
function toValidSlideNumber(val) {
|
|
21
|
+
// corner case: empty is empty attribute which is true
|
|
22
|
+
if (val === "") {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
// using toString here handles both the 'false' string and the false boolean
|
|
26
|
+
return val.toString() === 'false' ? false : `'${val}'`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns formatted style/link and script tags for header.
|
|
31
|
+
*/
|
|
32
|
+
module.exports = function ({node}) {
|
|
33
|
+
const document_content = node.getContent();
|
|
34
|
+
let docinfo_content_header = node.getDocinfo('header', '.html');
|
|
35
|
+
let docinfo_content_head = node.getDocinfo('head', '.html');
|
|
36
|
+
let docinfo_content_footer = node.getDocinfo('footer', '.html');
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if (node.getNoheader() || isEmptyString(docinfo_content_header)) {
|
|
40
|
+
docinfo_content_header = '';
|
|
41
|
+
}
|
|
42
|
+
if (isEmptyString(docinfo_content_footer)) {
|
|
43
|
+
docinfo_content_footer = '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const scripts=node.getAttribute('scripts', '').split(',').map(script => `<script type="module" src="${script}"></script>`)
|
|
47
|
+
const stylesheets=node.getAttribute('stylesheets', '').split(',').map(style => `<link rel="stylesheet" type="text/css" href="${style}">`)
|
|
48
|
+
|
|
49
|
+
return `
|
|
50
|
+
<!DOCTYPE html>
|
|
51
|
+
<html ${toAttribute('lang', node.hasAttribute('nolang') ? '' : node.getAttribute('lang', 'en'))}>
|
|
52
|
+
<head>
|
|
53
|
+
<meta charset="utf-8">
|
|
54
|
+
${$('title', {}, node.getDoctitle() || node.getAttribute('untitled-label'))}
|
|
55
|
+
${getFavicon(node)}
|
|
56
|
+
${$metaIf('application-name', node.getAttribute('app-name'))}
|
|
57
|
+
${$metaIf('author', node.getAttribute('authors'))}
|
|
58
|
+
${$metaIf('copyright', node.getAttribute('copyright'))}
|
|
59
|
+
${$metaIf('description', node.getAttribute('description'))}
|
|
60
|
+
${$metaIf('keywords', node.getAttribute('keywords'))}
|
|
61
|
+
${$('meta', {name: 'generator', content: `Asciidoctor ${node.getAttribute('asciidoctor-version')}`})}
|
|
62
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
|
|
63
|
+
${stylesheets}
|
|
64
|
+
${docinfo_content_head}
|
|
65
|
+
</head>
|
|
66
|
+
<body ${toAttributes({
|
|
67
|
+
id: node.getId(),
|
|
68
|
+
class: [
|
|
69
|
+
node.getAttribute('doctype'),
|
|
70
|
+
node.getAttribute('docrole') || node.getAttribute('role'),
|
|
71
|
+
]
|
|
72
|
+
})}>
|
|
73
|
+
${docinfo_content_header}
|
|
74
|
+
<div class="slides">
|
|
75
|
+
<!-- START CONTENT -->
|
|
76
|
+
${document_content}
|
|
77
|
+
<!-- END CONTENT -->
|
|
78
|
+
</div>
|
|
79
|
+
${docinfo_content_footer}
|
|
80
|
+
${scripts}
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
|
83
|
+
`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
|
|
2
|
+
const {$h, $a, $section, sectionTitle,isDefined} = HELPERS;
|
|
3
|
+
|
|
4
|
+
module.exports = function ({node}) {
|
|
5
|
+
let content = '';
|
|
6
|
+
if (isDefined(node.getId())) {
|
|
7
|
+
if (node.document.hasAttribute('sectanchors')) {
|
|
8
|
+
content += $a({class: "anchor", href: `#${node.getId()}`, 'aria-hidden': "true"})
|
|
9
|
+
}
|
|
10
|
+
if (node.document.hasAttribute('sectlinks')) {
|
|
11
|
+
content += $a({class: "link", href: `#${node.getId()}`}, sectionTitle(node))
|
|
12
|
+
} else {
|
|
13
|
+
content += sectionTitle(node)
|
|
14
|
+
}
|
|
15
|
+
} else {
|
|
16
|
+
content += sectionTitle(node)
|
|
17
|
+
}
|
|
18
|
+
return $section({
|
|
19
|
+
class: ['doc-section', `level-${node.getLevel()}`, node.getRole()],
|
|
20
|
+
},
|
|
21
|
+
$h({
|
|
22
|
+
level: node.getLevel() + 1,
|
|
23
|
+
id: node.getId()
|
|
24
|
+
},
|
|
25
|
+
content
|
|
26
|
+
),
|
|
27
|
+
node.getContent()
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const {resolve} = require("path");
|
|
2
|
+
const {readFileSync, existsSync} = require("fs");
|
|
3
|
+
const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
|
|
4
|
+
const {$, isEmptyString} = HELPERS;
|
|
5
|
+
|
|
6
|
+
function resolveTemplate(paths, templateName) {
|
|
7
|
+
// find in folders
|
|
8
|
+
for(let path of paths){
|
|
9
|
+
const templatePath = resolve(path,`${templateName}-slide.html`)
|
|
10
|
+
if(existsSync(templatePath)){
|
|
11
|
+
return readFileSync(templatePath, {encoding: 'utf-8'});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`No Match found for template "${templateName}" in folders ${JSON.stringify(this._paths)}`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = function ({node}) {
|
|
18
|
+
const templateAttrName = node.getAttribute('slide-template-attr', 'template', 'slide-template-attr');
|
|
19
|
+
const defaultTemplate = node.getAttribute('slide-default-template', '', 'slide-default-template');
|
|
20
|
+
const template = node.getAttribute(templateAttrName, defaultTemplate);
|
|
21
|
+
|
|
22
|
+
let slideContent = '';
|
|
23
|
+
|
|
24
|
+
if (isEmptyString(template)) {
|
|
25
|
+
slideContent = node.getBlocks().map(n => n.convert()).join('\n')
|
|
26
|
+
} else {
|
|
27
|
+
slideContent = resolveTemplate(node.document.getAttribute('slide-template-dirs'), template);
|
|
28
|
+
const blockBySlot = node.getBlocks().reduce(
|
|
29
|
+
(acc, n) => {
|
|
30
|
+
const slot = n.getAttribute('slot') || 'default'
|
|
31
|
+
if (!acc[slot]) {
|
|
32
|
+
acc[slot] = [];
|
|
33
|
+
}
|
|
34
|
+
acc[slot].push(n);
|
|
35
|
+
return acc;
|
|
36
|
+
},
|
|
37
|
+
{});
|
|
38
|
+
// Special slot
|
|
39
|
+
blockBySlot['all'] = node.getBlocks();
|
|
40
|
+
Object.entries(blockBySlot).forEach(([slotname, blocks]) => {
|
|
41
|
+
const content = $(blocks.map(n => n.convert()));
|
|
42
|
+
slideContent = slideContent.replace(`<!-- slot=${slotname} -->`, content);
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
return $('section', {
|
|
46
|
+
class: [
|
|
47
|
+
'slide',
|
|
48
|
+
template,
|
|
49
|
+
node.getRole()
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
slideContent
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
|
|
2
|
+
const {$} = HELPERS;
|
|
3
|
+
|
|
4
|
+
module.exports = function ({node}) {
|
|
5
|
+
return $('aside',
|
|
6
|
+
{
|
|
7
|
+
id: node.getId(),
|
|
8
|
+
class: ['speaker-notes'],
|
|
9
|
+
},
|
|
10
|
+
node.getBlocks().map(block => block.convert()).join('\n')
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
|
|
2
|
+
const {$, $h, $a, isDefined, sectionTitle} = HELPERS;
|
|
3
|
+
|
|
4
|
+
module.exports = function ({node}) {
|
|
5
|
+
let content = '';
|
|
6
|
+
if (isDefined(node.getId())) {
|
|
7
|
+
if (node.document.hasAttribute('sectanchors')) {
|
|
8
|
+
content += $a({class: "anchor", href: `#${node.getId()}`, 'aria-hidden': "true"})
|
|
9
|
+
}
|
|
10
|
+
if (node.document.hasAttribute('sectlinks')) {
|
|
11
|
+
content += $a({class: "link", href: `#${node.getId()}`}, node.getContent())
|
|
12
|
+
} else {
|
|
13
|
+
content += node.getContent()
|
|
14
|
+
}
|
|
15
|
+
} else {
|
|
16
|
+
content += node.getContent()
|
|
17
|
+
}
|
|
18
|
+
return $h({
|
|
19
|
+
level: node.getAttribute('level') + 1,
|
|
20
|
+
id: node.getId()
|
|
21
|
+
},
|
|
22
|
+
content
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export default function () {
|
|
2
|
+
return function (deck) {
|
|
3
|
+
function addClass(el, cls) {
|
|
4
|
+
el.classList.add(cls);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function removeClass(el, cls) {
|
|
8
|
+
el.className = el.className
|
|
9
|
+
.replace(new RegExp('(\\s|^)' +cls + '(\\s|$)', 'g'), ' ')
|
|
10
|
+
.trim();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function deactivate(el, index) {
|
|
14
|
+
const activeSlide = deck.slides[deck.slide()];
|
|
15
|
+
const offset = index - deck.slide();
|
|
16
|
+
const offsetClass = offset > 0 ? 'after' : 'before';
|
|
17
|
+
|
|
18
|
+
// removeClass(el, 'before(-\\d+)?');
|
|
19
|
+
// removeClass(el, 'after(-\\d+)?');
|
|
20
|
+
removeClass(el, 'active');
|
|
21
|
+
removeClass(el, 'inactive');
|
|
22
|
+
removeClass(el, 'before');
|
|
23
|
+
removeClass(el, 'after');
|
|
24
|
+
|
|
25
|
+
if (el !== activeSlide) {
|
|
26
|
+
addClass(el, 'inactive');
|
|
27
|
+
addClass(el, offsetClass);
|
|
28
|
+
// addClass(el, 'slide-' + offsetClass);
|
|
29
|
+
// addClass(el, 'slide-' + offsetClass + '-' + Math.abs(offset));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
addClass(deck.parent, 'parent');
|
|
34
|
+
// deck.slides.map(function (el) {
|
|
35
|
+
// addClass(el, 'slide');
|
|
36
|
+
// });
|
|
37
|
+
|
|
38
|
+
deck.on('activate', function (e) {
|
|
39
|
+
deck.slides.map(deactivate);
|
|
40
|
+
addClass(e.slide, 'active');
|
|
41
|
+
removeClass(e.slide, 'inactive');
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
const KEY_D = "d";
|
|
3
|
+
const DEBUG_CLASS='debug';
|
|
4
|
+
|
|
5
|
+
export default function () {
|
|
6
|
+
return function (deck) {
|
|
7
|
+
|
|
8
|
+
function debugOverflow(){
|
|
9
|
+
if(deck.parent.classList.contains(DEBUG_CLASS)) {
|
|
10
|
+
const currentSlide = deck.slides[deck.slide()];
|
|
11
|
+
Array.from(currentSlide.children).forEach(el => {
|
|
12
|
+
if (el.scrollHeight > currentSlide.clientHeight) {
|
|
13
|
+
deck.parent.classList.add("overflowing");
|
|
14
|
+
} else {
|
|
15
|
+
deck.parent.classList.remove("overflowing");
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
deck.addKeyHandler(KEY_D, () => {
|
|
21
|
+
deck.parent.classList.toggle(DEBUG_CLASS);
|
|
22
|
+
debugOverflow();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
deck.on('activate', function (e) {
|
|
26
|
+
debugOverflow()
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const KEY_E = "e";
|
|
2
|
+
const EDITOR_CLASS = 'editor';
|
|
3
|
+
|
|
4
|
+
export default function () {
|
|
5
|
+
return function (deck) {
|
|
6
|
+
let preview;
|
|
7
|
+
let previewContainer;
|
|
8
|
+
|
|
9
|
+
function scrollIntoView() {
|
|
10
|
+
const currentSlide = deck.slides[deck.slide()];
|
|
11
|
+
currentSlide.scrollIntoView({block: 'center', inline: 'center'});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function updateScaleList() {
|
|
15
|
+
const firstSlide = deck.slides[0];
|
|
16
|
+
const innerWidth = deck.parent.offsetWidth;
|
|
17
|
+
const innerHeight = deck.parent.offsetHeight;
|
|
18
|
+
const { offsetWidth, offsetHeight } = firstSlide;
|
|
19
|
+
|
|
20
|
+
const listScale = 1 / Math.max(offsetWidth / innerWidth, offsetHeight / innerHeight);
|
|
21
|
+
|
|
22
|
+
deck.parent.style.setProperty('--deck-list-scale', listScale);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function updateScalePreview() {
|
|
26
|
+
const innerWidth = preview.offsetWidth;
|
|
27
|
+
const innerHeight = preview.offsetHeight;
|
|
28
|
+
const {offsetWidth, offsetHeight} = previewContainer.children[0];
|
|
29
|
+
|
|
30
|
+
const fullScale = 1 / Math.max(offsetWidth / innerWidth, offsetHeight / innerHeight);
|
|
31
|
+
|
|
32
|
+
preview.style.setProperty('--deck-full-scale', fullScale);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const eventsHandlers = [];
|
|
36
|
+
|
|
37
|
+
function bindSlideClick() {
|
|
38
|
+
deck.slides.forEach((slide, index) => {
|
|
39
|
+
eventsHandlers.push(slide.addEventListener('click', () => {
|
|
40
|
+
deck.slide(index)
|
|
41
|
+
}));
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function unbindSlideClick() {
|
|
46
|
+
deck.slides.forEach((slide, index) => {
|
|
47
|
+
slide.removeEventListener('click', eventsHandlers[index]);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function mountEditor() {
|
|
52
|
+
deck.parent.classList.add('list')
|
|
53
|
+
preview = document.createElement('div');
|
|
54
|
+
preview.classList.add('preview');
|
|
55
|
+
previewContainer = document.createElement('div');
|
|
56
|
+
previewContainer.classList.add('slides', 'full');
|
|
57
|
+
preview.appendChild(previewContainer);
|
|
58
|
+
document.body.appendChild(preview);
|
|
59
|
+
updatePreview();
|
|
60
|
+
bindSlideClick();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function unmountEditor() {
|
|
64
|
+
deck.parent.classList.remove('list')
|
|
65
|
+
preview.removeChild(previewContainer);
|
|
66
|
+
previewContainer = null;
|
|
67
|
+
document.body.removeChild(preview);
|
|
68
|
+
preview = null;
|
|
69
|
+
unbindSlideClick();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function updatePreview() {
|
|
73
|
+
if (previewContainer) {
|
|
74
|
+
previewContainer.innerHTML = deck.slides[deck.slide()]?.outerHTML;
|
|
75
|
+
updateScalePreview();
|
|
76
|
+
updateScaleList();
|
|
77
|
+
scrollIntoView();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
deck.addKeyHandler(KEY_E, () => {
|
|
82
|
+
deck.toogleMode(EDITOR_CLASS);
|
|
83
|
+
});
|
|
84
|
+
deck.on('viewmode', function (e) {
|
|
85
|
+
if (e.current === EDITOR_CLASS) {
|
|
86
|
+
mountEditor();
|
|
87
|
+
} else if (preview) {
|
|
88
|
+
unmountEditor();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
deck.on('activate', function (e) {
|
|
92
|
+
updatePreview()
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
};
|
|
96
|
+
};
|