shoelace/docs/assets/plugins/metadata/metadata.js

399 wiersze
11 KiB
JavaScript
Czysty Zwykły widok Historia

2020-07-15 21:30:37 +00:00
(() => {
let metadataStore;
2021-02-26 14:09:13 +00:00
function getAttrName(propName) {
return propName.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`).replace(/^-/, '');
}
2020-07-15 21:30:37 +00:00
function createPropsTable(props) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Property</th>
<th>Description</th>
<th>Type</th>
<th>Default</th>
</tr>
</thead>
<tbody>
${props
2021-02-26 14:09:13 +00:00
.map(prop => {
const attr = getAttrName(prop.name);
return `
<tr>
<td>
<code>${escapeHtml(prop.name)}</code>
${
prop.name !== attr
? `
<br>
<small>
2021-03-07 14:20:04 +00:00
<sl-tooltip content="Use this attribute in your HTML">
2021-02-26 14:09:13 +00:00
<code class="attribute-tooltip">${escapeHtml(attr)}</code>
</sl-tooltip>
</small>`
: ''
}
</td>
<td>${escapeHtml(prop.description)}</td>
<td><code style="white-space: normal;">${escapeHtml(prop.type)}</code></td>
<td><code style="white-space: normal;">${escapeHtml(prop.defaultValue)}</code></td>
</tr>
`;
})
2020-07-15 21:30:37 +00:00
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createEventsTable(events) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Event</th>
<th>Description</th>
2021-03-07 14:10:45 +00:00
<th>Details</th>
2020-07-15 21:30:37 +00:00
</tr>
</thead>
<tbody>
${events
.map(
event => `
<tr>
2021-02-26 14:09:13 +00:00
<td><code>${escapeHtml(event.name)}</code></td>
<td>${escapeHtml(event.description)}</td>
2021-03-06 17:01:39 +00:00
<td><code style="white-space: normal;">${escapeHtml(event.details)}</code></td>
2020-07-15 21:30:37 +00:00
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createMethodsTable(methods) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Method</th>
<th>Description</th>
2021-02-26 14:09:13 +00:00
<th>Arguments</th>
2020-07-15 21:30:37 +00:00
</tr>
</thead>
<tbody>
${methods
.map(
method => `
2021-02-26 14:09:13 +00:00
<tr>
<td><code>${escapeHtml(method.name)}</code></td>
<td>${escapeHtml(method.description)}</td>
<td>
${
method.params.length
? `
<code style="white-space: normal;">${escapeHtml(
method.params.map(param => `${param.name}: ${param.type}`).join(', ')
)}</code>
`
: ''
}
</td>
</tr>
`
2020-07-15 21:30:37 +00:00
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createSlotsTable(slots) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Slot</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${slots
.map(
slot => `
<tr>
<td><code>${slot.name ? escapeHtml(slot.name) : '(default)'}</code></td>
2021-02-26 14:09:13 +00:00
<td>${escapeHtml(slot.description)}</td>
2020-07-15 21:30:37 +00:00
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createCustomPropertiesTable(styles) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${styles
.map(
style => `
<tr>
2020-07-16 11:25:28 +00:00
<td><code>${escapeHtml(style.name)}</code></td>
2021-02-26 14:09:13 +00:00
<td>${escapeHtml(style.description)}</td>
2020-07-15 21:30:37 +00:00
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createPartsTable(parts) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${parts
.map(
part => `
<tr>
<td><code>${escapeHtml(part.name)}</code></td>
2021-02-26 14:09:13 +00:00
<td>${escapeHtml(part.description)}</td>
2020-07-15 21:30:37 +00:00
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
2021-02-26 14:09:13 +00:00
function createDependenciesList(targetComponent, allComponents) {
2021-01-06 17:59:36 +00:00
const ul = document.createElement('ul');
2021-02-26 14:09:13 +00:00
const dependencies = [];
2021-01-06 17:59:36 +00:00
2021-02-26 14:09:13 +00:00
// Recursively fetch subdependencies
function getDependencies(tag) {
const component = allComponents.find(c => c.tag === tag);
if (!component && !Array.isArray(component.dependencies)) {
return [];
}
component.dependencies.map(tag => {
if (!dependencies.includes(tag)) {
dependencies.push(tag);
2021-01-06 18:25:59 +00:00
}
2021-02-26 14:09:13 +00:00
getDependencies(tag);
2021-01-06 18:25:59 +00:00
});
2021-02-26 14:09:13 +00:00
}
2021-01-06 17:59:36 +00:00
2021-02-26 14:09:13 +00:00
getDependencies(targetComponent);
dependencies.sort().map(tag => {
2021-01-06 18:25:59 +00:00
const li = document.createElement('li');
2021-02-26 14:09:13 +00:00
li.innerHTML = `<code>&lt;${tag}&gt;</code>`;
2021-01-06 18:25:59 +00:00
ul.appendChild(li);
});
2020-07-15 21:30:37 +00:00
return ul.outerHTML;
}
function escapeHtml(html) {
return (html + '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
.replace(/`(.*?)`/g, '<code>$1</code>');
}
function getMetadata() {
return new Promise((resolve, reject) => {
// Simple caching to prevent multiple XHR requests
if (metadataStore) {
return resolve(metadataStore);
}
2021-03-25 12:15:26 +00:00
fetch('/dist/metadata.json')
2020-07-15 21:30:37 +00:00
.then(res => res.json())
.then(data => {
metadataStore = data;
resolve(metadataStore);
})
.catch(err => console.error(err));
});
}
if (!window.$docsify) {
throw new Error('Docsify must be loaded before installing this plugin.');
}
window.$docsify.plugins.push((hook, vm) => {
hook.mounted(function () {
2021-02-26 14:09:13 +00:00
getMetadata().then(metadata => {
const target = document.querySelector('.app-name');
// Add version
const version = document.createElement('div');
version.classList.add('sidebar-version');
version.textContent = metadata.version;
target.appendChild(version);
// Add repo buttons
const buttons = document.createElement('div');
buttons.classList.add('sidebar-buttons');
buttons.innerHTML = `
2020-07-29 14:37:22 +00:00
<a class="repo-button repo-button--small repo-button--sponsor" href="https://github.com/sponsors/claviska" rel="noopener" target="_blank">
<sl-icon name="heart"></sl-icon> Sponsor
</a>
<a class="repo-button repo-button--small repo-button--github" href="https://github.com/shoelace-style/shoelace/stargazers" rel="noopener" target="_blank">
2021-02-26 14:09:13 +00:00
<sl-icon name="github"></sl-icon> <span class="github-star-count">Star</span>
2020-07-29 14:37:22 +00:00
</a>
<a class="repo-button repo-button--small repo-button--twitter" href="https://twitter.com/shoelace_style" rel="noopener" target="_blank">
2021-02-26 14:09:13 +00:00
<sl-icon name="twitter"></sl-icon> Follow
2020-07-29 14:37:22 +00:00
</a>
`;
2021-02-26 14:09:13 +00:00
target.appendChild(buttons);
});
2020-07-15 21:30:37 +00:00
});
hook.beforeEach(async function (content, next) {
const metadata = await getMetadata();
// Replace %VERSION% placeholders
content = content.replace(/%VERSION%/g, metadata.version);
// Handle [component-header] tags
content = content.replace(/\[component-header:([a-z-]+)\]/g, (match, tag) => {
2021-02-26 14:09:13 +00:00
const component = metadata.components.filter(data => data.tag === tag)[0];
2020-07-15 21:30:37 +00:00
let result = '';
2021-02-26 14:09:13 +00:00
if (!component) {
2020-07-15 21:30:37 +00:00
console.error('Component not found in metadata: ' + tag);
next(content);
}
2020-10-16 11:36:43 +00:00
let badgeType = 'info';
2021-02-26 14:09:13 +00:00
if (component.status === 'stable') badgeType = 'primary';
if (component.status === 'experimental') badgeType = 'warning';
if (component.status === 'planned') badgeType = 'info';
if (component.status === 'deprecated') badgeType = 'danger';
2020-07-15 21:30:37 +00:00
2020-10-16 11:36:43 +00:00
result += `
<div class="component-header">
<div class="component-header__tag">
2021-02-26 14:09:13 +00:00
<code>${component.className} | &lt;${component.tag}&gt;</code>
2020-07-15 21:30:37 +00:00
</div>
2020-10-16 11:36:43 +00:00
<div class="component-header__info">
<sl-badge type="info" pill>
2021-02-26 14:09:13 +00:00
Since ${component.since || '?'}
2020-10-16 11:36:43 +00:00
</sl-badge>
<sl-badge type="${badgeType}" pill style="text-transform: capitalize;">
2021-02-26 14:09:13 +00:00
${component.status}
2020-10-16 11:36:43 +00:00
</sl-badge>
</div>
</div>
`;
2020-07-15 21:30:37 +00:00
return result.replace(/^ +| +$/gm, '');
});
// Handle [component-metadata] tags
content = content.replace(/\[component-metadata:([a-z-]+)\]/g, (match, tag) => {
2021-02-26 14:09:13 +00:00
const component = metadata.components.filter(data => data.tag === tag)[0];
2020-07-15 21:30:37 +00:00
let result = '';
2021-02-26 14:09:13 +00:00
if (!component) {
2020-07-15 21:30:37 +00:00
console.error('Component not found in metadata: ' + tag);
next(content);
}
2021-02-26 14:09:13 +00:00
if (component.props.length) {
2020-07-15 21:30:37 +00:00
result += `
## Properties
2021-02-26 14:09:13 +00:00
${createPropsTable(component.props)}
2020-07-15 21:30:37 +00:00
`;
}
2021-02-26 14:09:13 +00:00
if (component.events.length) {
2020-07-15 21:30:37 +00:00
result += `
## Events
2021-02-26 14:09:13 +00:00
${createEventsTable(component.events)}
2020-07-15 21:30:37 +00:00
`;
}
2021-02-26 14:09:13 +00:00
if (component.methods.length) {
2020-07-15 21:30:37 +00:00
result += `
## Methods
2021-02-26 14:09:13 +00:00
${createMethodsTable(component.methods)}
2020-07-15 21:30:37 +00:00
`;
}
2021-02-26 14:09:13 +00:00
if (component.slots.length) {
2020-07-15 21:30:37 +00:00
result += `
## Slots
2021-02-26 14:09:13 +00:00
${createSlotsTable(component.slots)}
2020-07-15 21:30:37 +00:00
`;
}
2021-02-26 14:09:13 +00:00
if (component.cssCustomProperties.length) {
2020-07-15 21:30:37 +00:00
result += `
## CSS Custom Properties
2021-02-26 14:09:13 +00:00
${createCustomPropertiesTable(component.cssCustomProperties)}
2020-07-15 21:30:37 +00:00
`;
}
2021-02-26 14:09:13 +00:00
if (component.parts.length) {
2020-07-15 21:30:37 +00:00
result += `
## CSS Parts
2021-02-26 14:09:13 +00:00
${createPartsTable(component.parts)}
2020-07-15 21:30:37 +00:00
`;
}
2021-02-26 14:09:13 +00:00
if (component.dependencies.length) {
2020-07-15 21:30:37 +00:00
result += `
2021-01-06 17:59:36 +00:00
## Dependencies
2020-07-15 21:30:37 +00:00
2021-03-06 17:01:39 +00:00
This component has the following dependencies so, if you're [cherry picking](/getting-started/installation#cherry-picking),
2021-02-26 14:09:13 +00:00
be sure to import these components in addition to <code>&lt;${tag}&gt;</code>.
2020-07-15 21:30:37 +00:00
2021-02-26 14:09:13 +00:00
${createDependenciesList(component.tag, metadata.components)}
2020-07-15 21:30:37 +00:00
`;
}
// Strip whitespace so markdown doesn't process things as code blocks
return result.replace(/^ +| +$/gm, '');
});
next(content);
});
});
})();