mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
Add <wa-code-demo> and <wa-viewport-demo> and use them by default
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
This commit is contained in:
@@ -1,82 +1,163 @@
|
||||
import { parse } from 'node-html-parser';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
const templates = {
|
||||
old(pre, code, { open, buttons, edit }) {
|
||||
const id = `code-example-${uuid().slice(-12)}`;
|
||||
let preview = code.textContent;
|
||||
|
||||
// Run preview scripts as modules to prevent collisions
|
||||
const root = parse(preview, { blockTextElements: { script: true } });
|
||||
root.querySelectorAll('script').forEach(script => script.setAttribute('type', 'module'));
|
||||
preview = root.toString();
|
||||
|
||||
return `
|
||||
<div class="code-example ${open ? 'open' : ''}">
|
||||
<div class="code-example-preview">
|
||||
${preview}
|
||||
</div>
|
||||
<div class="code-example-source" id="${id}">
|
||||
${pre.outerHTML}
|
||||
</div>
|
||||
${
|
||||
buttons
|
||||
? `
|
||||
<div class="code-example-buttons">
|
||||
<button
|
||||
class="code-example-toggle"
|
||||
type="button"
|
||||
aria-expanded="${open ? 'true' : 'false'}"
|
||||
aria-controls="${id}"
|
||||
>
|
||||
Code
|
||||
<wa-icon name="chevron-down"></wa-icon>
|
||||
</button>
|
||||
${
|
||||
edit
|
||||
? `
|
||||
<button class="code-example-pen" type="button">
|
||||
<wa-icon name="pen-to-square"></wa-icon>
|
||||
Edit
|
||||
</button>
|
||||
`
|
||||
: ''
|
||||
}
|
||||
`
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
new(pre, code, { open, first }) {
|
||||
const attributes = {
|
||||
include: 'link[rel=stylesheet]',
|
||||
open
|
||||
};
|
||||
|
||||
if (code.hasAttribute('data-viewport')) {
|
||||
attributes.viewport = code.getAttribute('data-viewport');
|
||||
}
|
||||
|
||||
const attributesString = Object.entries(attributes)
|
||||
.map(([key, value]) => {
|
||||
if (value === true) {
|
||||
return key;
|
||||
}
|
||||
if (value === false || value === null) {
|
||||
return '';
|
||||
}
|
||||
return `${key}="${value}"`;
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
let includes = '';
|
||||
if (first) {
|
||||
includes = `
|
||||
<template class="wa-code-demo-include-isolated">
|
||||
<script src="/dist/webawesome/loader.js" type="module"></script>
|
||||
</template>`;
|
||||
}
|
||||
|
||||
let preview = '';
|
||||
if (!attributes.viewport) {
|
||||
preview = `<div style="display:contents" slot="preview">${code.textContent}</div>`;
|
||||
}
|
||||
|
||||
return `${includes}
|
||||
<wa-code-demo ${attributesString}>
|
||||
${preview}
|
||||
${pre.outerHTML}
|
||||
</wa-code-demo>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Eleventy plugin to turn `<code class="example">` blocks into live examples.
|
||||
*/
|
||||
export function codeExamplesPlugin(options = {}) {
|
||||
export function codeExamplesPlugin(eleventyConfig, options = {}) {
|
||||
options = {
|
||||
container: 'body',
|
||||
firstOpen: true,
|
||||
...options
|
||||
};
|
||||
|
||||
return function (eleventyConfig) {
|
||||
eleventyConfig.addTransform('code-examples', content => {
|
||||
const doc = parse(content, { blockTextElements: { code: true } });
|
||||
const container = doc.querySelector(options.container);
|
||||
const stats = {
|
||||
inputPaths: {},
|
||||
outputPaths: {}
|
||||
};
|
||||
|
||||
if (!container) {
|
||||
return content;
|
||||
eleventyConfig.addTransform('code-examples', function (content) {
|
||||
const { inputPath, outputPath } = this.page;
|
||||
|
||||
const doc = parse(content, { blockTextElements: { code: true } });
|
||||
const container = doc.querySelector(options.container);
|
||||
|
||||
if (!container) {
|
||||
return content;
|
||||
}
|
||||
|
||||
// Look for external links
|
||||
container.querySelectorAll('code.example').forEach(code => {
|
||||
stats.inputPaths[inputPath] ??= 0;
|
||||
stats.outputPaths[outputPath] ??= 0;
|
||||
stats.inputPaths[inputPath]++;
|
||||
stats.outputPaths[outputPath]++;
|
||||
|
||||
const pre = code.closest('pre');
|
||||
const first = stats.inputPaths[inputPath] === 1;
|
||||
|
||||
const localOptions = {
|
||||
...options,
|
||||
first,
|
||||
|
||||
// Modifier defaults
|
||||
edit: true,
|
||||
buttons: true,
|
||||
new: true, // comment this line to default back to the old demos
|
||||
open: options.firstOpen ? first : false // default to first open
|
||||
};
|
||||
|
||||
for (const prop of ['new', 'open', 'buttons', 'edit']) {
|
||||
if (code.classList.contains(prop)) {
|
||||
localOptions[prop] = true;
|
||||
} else if (code.classList.contains(`no-${prop}`)) {
|
||||
localOptions[prop] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for external links
|
||||
container.querySelectorAll('code.example').forEach(code => {
|
||||
const pre = code.closest('pre');
|
||||
const hasButtons = !code.classList.contains('no-buttons');
|
||||
const isOpen = code.classList.contains('open') || !hasButtons;
|
||||
const noEdit = code.classList.contains('no-edit');
|
||||
const id = `code-example-${uuid().slice(-12)}`;
|
||||
let preview = pre.textContent;
|
||||
if (code.hasAttribute('data-viewport')) {
|
||||
// viewport attribute only works on the new syntax
|
||||
localOptions.new = true;
|
||||
}
|
||||
|
||||
// Run preview scripts as modules to prevent collisions
|
||||
const root = parse(preview, { blockTextElements: { script: true } });
|
||||
root.querySelectorAll('script').forEach(script => script.setAttribute('type', 'module'));
|
||||
preview = root.toString();
|
||||
const template = localOptions.new ? 'new' : 'old';
|
||||
const codeExample = parse(templates[template](pre, code, localOptions));
|
||||
|
||||
const codeExample = parse(`
|
||||
<div class="code-example ${isOpen ? 'open' : ''}">
|
||||
<div class="code-example-preview">
|
||||
${preview}
|
||||
</div>
|
||||
<div class="code-example-source" id="${id}">
|
||||
${pre.outerHTML}
|
||||
</div>
|
||||
${
|
||||
hasButtons
|
||||
? `
|
||||
<div class="code-example-buttons">
|
||||
<button
|
||||
class="code-example-toggle"
|
||||
type="button"
|
||||
aria-expanded="${isOpen ? 'true' : 'false'}"
|
||||
aria-controls="${id}"
|
||||
>
|
||||
Code
|
||||
<wa-icon name="chevron-down"></wa-icon>
|
||||
</button>
|
||||
|
||||
${
|
||||
noEdit
|
||||
? ''
|
||||
: `
|
||||
<button class="code-example-pen" type="button">
|
||||
<wa-icon name="pen-to-square"></wa-icon>
|
||||
Edit
|
||||
</button>
|
||||
`
|
||||
}
|
||||
|
||||
`
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
pre.replaceWith(codeExample);
|
||||
});
|
||||
|
||||
return doc.toString();
|
||||
pre.replaceWith(codeExample);
|
||||
});
|
||||
};
|
||||
|
||||
return doc.toString();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user