Compare commits

..

2 Commits

Author SHA1 Message Date
Kelsey Jackson
ed10f36b28 renamed some files 2024-12-18 20:40:35 -06:00
Kelsey Jackson
a13be817db switching to change input label styling 2024-12-18 20:11:41 -06:00
1703 changed files with 37905 additions and 33826 deletions

View File

@@ -4,13 +4,11 @@
name: Client Tests
on:
workflow_dispatch:
push:
branches: [next]
pull_request:
branches: [next]
jobs:
client_test:
runs-on: ubuntu-latest
@@ -32,17 +30,10 @@ jobs:
run: npm ci
- name: Lint
run: npm run prettier
working-directory: ./packages/webawesome
- name: Build
run: npm run build
working-directory: ./packages/webawesome
- name: Install Playwright
run: npx playwright install --with-deps
working-directory: ./packages/webawesome
- name: Run CSR tests
# FAIL_FAST to fail on first failing test.
run: FAIL_FAST="true" CSR_ONLY="true" npm run test
working-directory: ./packages/webawesome

View File

@@ -1,12 +1,11 @@
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
# # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: SSR Tests
on:
# push:
# branches: [next]
workflow_dispatch:
push:
branches: [next]
jobs:
ssr_test:
@@ -26,17 +25,17 @@ jobs:
cache: 'npm'
- name: Install dependencies
run: npm ci
# Just lint here too. Save some GH Action minutes and not need to use "depends_on" or anything.
- name: Lint
run: npm run prettier
- name: Build
run: npm run build
working-directory: ./packages/webawesome
- name: Install Playwright
run: npx playwright install --with-deps
working-directory: ./packages/webawesome
- name: Run SSR tests
# FAIL_FAST to fail on first failing test.
run: FAIL_FAST="true" SSR_ONLY="true" npm run test
working-directory: ./packages/webawesome

10
.gitignore vendored
View File

@@ -1,12 +1,12 @@
_site
.cache
.DS_Store
package.json
package-lock.json
dist/
dist-cdn/
docs/public/pagefind
node_modules
packages/**/*/src/react
src/react
.astro
cdn/
yarn.lock
_bundle_
/packages/webawesome-pro
/packages/webawesome-app

View File

@@ -1,23 +1,15 @@
# Files are relative to .prettierignore at the root of this monorepo.
# <https://github.com/prettier/prettier-vscode/issues/1252>
*.hbs
*.md
!packages/webawesome/docs/docs/patterns/**/*.md
docs/docs/patterns/blog-news/post-list.md
**/*/.cache
.cache
.github
cspell.json
packages/**/*/dist
packages/**/*/dist-cdn
packages/**/*/docs/search.json
packages/**/*/src/components/icon/icons
packages/**/*/src/react/index.ts
**/*/package.json
**/*/package-lock.json
**/*/tsconfig.json
**/*/tsconfig.prod.json
dist
docs/search.json
src/components/icon/icons
src/react/index.ts
node_modules
packages/**/*/_site
packages/webawesome/docs/assets/scripts/prism-downloaded.js
package.json
package-lock.json
tsconfig.json
cdn
_site

View File

@@ -3,7 +3,6 @@
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bierner.lit-html",
"streetsidesoftware.code-spell-checker",
"ronnidc.nunjucks"
"streetsidesoftware.code-spell-checker"
]
}

View File

@@ -21,7 +21,7 @@ Twitter: [@webawesomer](https://twitter.com/webawesomer)
## Developers ✨
Developers can use this documentation to learn how to build Web Awesome from source. You will need Node.js 14.17 or later to build and run the project locally.
Developers can use this documentation to learn how to build Web Awesome from source. You will need Node >= 14.17 to build and run the project locally.
**You don't need to do any of this to use Web Awesome!** This page is for people who want to contribute to the project, tinker with the source, or create a custom build of Web Awesome.
@@ -29,29 +29,7 @@ If that's not what you're trying to do, the [documentation website](https://weba
### What are you using to build Web Awesome?
Components are built with [Lit](https://lit.dev/), a custom elements base class that provides an intuitive API and reactive data binding. The build is a custom script with bundling powered by [esbuild](https://esbuild.github.io/).
### Understanding the Web Awesome monorepo
Web Awesome uses [npm workspaces](https://docs.npmjs.com/cli/v11/using-npm/workspaces) for its monorepo structure and is fairly minimal in what it provides.
By using npm workspaces and a monorepo structure, we can get consistent builds, shared configurations, and reduced duplication across repositories which reduces regressions and forces consistency across `webawesome`, `webawesome-pro`, and `webawesome-app`.
Generally, if you plan to only work with the free version of `webawesome` it is easiest to go to `packages/webawesome` and run all commands from there.
### Where do npm dependencies go?
Any dependencies intended to be used across all packages (i.e., `prettier`, `eslint`) that are **not** used at runtime should be in the root `devDependencies` of `package.json`.
```bash
npm install -D -w prettier
```
Any dependencies that will be used at runtime by a package should be part of the specific package's `dependencies` such as `lit`. This is required because if that dependency is not in the `packages/*/package.json`, it will not be installed when used via npm.
Individual packages are also free to install `devDependencies` as needed as long as they are specific to that package only.
To install a package specific to a Web Awesome package, change your working directory to that package's root (i.e., `cd packages/webawesome && npm install <package-name>`).
Components are built with [LitElement](https://lit-element.polymer-project.org/), a custom elements base class that provides an intuitive API and reactive data binding. The build is a custom script with bundling powered by [esbuild](https://esbuild.github.io/).
### Forking the Repo
@@ -65,49 +43,36 @@ npm install
### Developing
Once you've cloned the repo, run the following command from the respective directory within `packages/*`.
Once you've cloned the repo, run the following command.
```bash
cd packages/webawesome
npm start
```
This will spin up the dev server. After the initial build, a browser will open automatically. There is currently no hot module reloading (HMR), as browsers don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically.
This will spin up the dev server. After the initial build, a browser will open automatically. There is currently no hot module reloading (HMR), as browser's don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically.
### Building
To generate a production build, run the following command.
```bash
cd packages/webawesome
npm run build
```
You can also run `npm run build:serve` to start an [`http-server`](https://www.npmjs.com/package/http-server) instance on `http://localhost:4000` after the build completes, so you can preview the production build.
### Creating New Components
To scaffold a new component, run the following command, replacing `wa-tag-name` with the desired tag name.
```bash
cd packages/webawesome
npm run create wa-tag-name
```
This will generate a source file, a stylesheet, and a docs page for you. When you start the dev server, you'll find the new component in the "Components" section of the sidebar.
### Adding additional packages
Right now the only additional packages are in private repositories.
To add additional packages from other repositories, run `git clone <url> packages/<package-name>` to clone your repo into `packages/`.
Make sure to run `npm install` at the root of the monorepo after adding your package!
### Contributing
Web Awesome is an open source project and contributions are encouraged! If you're interesting in contributing, please review the [contribution guidelines](CONTRIBUTING.md) first.
## License
Web Awesome is available under the terms of the [MIT License](LICENSE.md).
Web Awesome is available under the terms of the MIT license.

View File

@@ -1,6 +0,0 @@
3.0.0-beta.1
3.0.0-beta.2
3.0.0-beta.3
3.0.0-beta.4
3.0.0-beta.5
3.0.0-beta.6

View File

@@ -8,28 +8,23 @@
"APG",
"apos",
"atrule",
"autocapitalize",
"autocorrect",
"autofix",
"autofocus",
"autoload",
"autoloader",
"autoloading",
"autoplay",
"bezier",
"Blockquotes",
"boxicons",
"CACHEABLE",
"callout",
"callouts",
"canvastext",
"chatbubble",
"checkmark",
"Clippy",
"codebases",
"codepen",
"colocated",
"colorjs",
"colour",
"combobox",
"Commonmark",
@@ -45,22 +40,16 @@
"csspart",
"cssproperty",
"cssstate",
"datalist",
"datetime",
"describedby",
"dictsort",
"Docsify",
"dogfood",
"dropdowns",
"easings",
"ecommerce",
"eleventy",
"elif",
"endfor",
"endmarkdown",
"endraw",
"endregion",
"endset",
"enterkeyhint",
"eqeqeq",
"erroneou",
@@ -68,10 +57,7 @@
"esbuild",
"exportmaps",
"exportparts",
"fetchpriority",
"fieldsets",
"focusin",
"focusout",
"fontawesome",
"formaction",
"formdata",
@@ -81,25 +67,21 @@
"formtarget",
"FOUC",
"FOUCE",
"Frontmatter",
"fullscreen",
"gestern",
"giga",
"globby",
"Grayscale",
"groupby",
"haspopup",
"heroicons",
"hexa",
"Hotwire",
"hrefs",
"Iconoir",
"Iframes",
"iife",
"inputmode",
"ionicon",
"ionicons",
"jank",
"jsDelivr",
"jsfiddle",
"keydown",
@@ -135,12 +117,8 @@
"noindex",
"noopener",
"noreferrer",
"noscript",
"Notdog",
"novalidate",
"nowrap",
"Numberish",
"nums",
"oklab",
"oklch",
"onscrollend",
@@ -150,12 +128,10 @@
"petabit",
"Preact",
"preconnect",
"prerendered",
"prismjs",
"progressbar",
"radiogroup",
"Railsbyte",
"referrerpolicy",
"remixicon",
"reregister",
"resizer",
@@ -172,9 +148,7 @@
"scrollbars",
"scrollend",
"scroller",
"Scrollers",
"Segoe",
"selectattr",
"semibold",
"shadowrootmode",
"Shortcode",
@@ -183,7 +157,6 @@
"slotchange",
"smartquotes",
"spacebar",
"srcdoc",
"stylesheet",
"svgs",
"Tabbable",
@@ -208,7 +181,6 @@
"typeof",
"unbundles",
"unbundling",
"Uncategorized",
"unicons",
"unsanitized",
"unsupportive",

View File

@@ -1,15 +1,11 @@
import { jsxTypesPlugin } from '@wc-toolkit/jsx-types';
import { customElementJetBrainsPlugin } from 'custom-element-jet-brains-integration';
import { customElementVsCodePlugin } from 'custom-element-vs-code-integration';
// import { customElementVuejsPlugin } from 'custom-element-vuejs-integration';
import { parse } from 'comment-parser';
import fs from 'fs';
import * as path from 'node:path';
import { pascalCase } from 'pascal-case';
import * as url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const packageData = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
const packageData = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const { name, description, version, author, homepage, license } = packageData;
const outdir = 'dist-cdn';
@@ -165,7 +161,6 @@ export default {
],
}),
// Generate custom JetBrains data
customElementJetBrainsPlugin({
outdir: './dist-cdn',
excludeCss: true,
@@ -178,16 +173,6 @@ export default {
},
}),
// Generate JSX types (see https://wc-toolkit.com/integrations/jsx/)
jsxTypesPlugin({
fileName: 'custom-elements-jsx.d.ts',
outdir,
defaultExport: true,
componentTypePath: (_name, _tag, modulePath) => {
return `./${modulePath}`;
},
}),
//
// TODO - figure out why this broke when events were updated
//

165
docs/.eleventy.js Normal file
View File

@@ -0,0 +1,165 @@
import { anchorHeadingsPlugin } from './_utils/anchor-headings.js';
import { codeExamplesPlugin } from './_utils/code-examples.js';
import { copyCodePlugin } from './_utils/copy-code.js';
import { currentLink } from './_utils/current-link.js';
import { highlightCodePlugin } from './_utils/highlight-code.js';
import { markdown } from './_utils/markdown.js';
import { removeDataAlphaElements } from './_utils/remove-data-alpha-elements.js';
// import { formatCodePlugin } from './_utils/format-code.js';
import litPlugin from '@lit-labs/eleventy-plugin-lit';
import { readFile } from 'fs/promises';
import componentList from './_data/componentList.js';
import * as filters from './_utils/filters.js';
import { outlinePlugin } from './_utils/outline.js';
import { replaceTextPlugin } from './_utils/replace-text.js';
import { searchPlugin } from './_utils/search.js';
import process from 'process';
const packageData = JSON.parse(await readFile('./package.json', 'utf-8'));
const isAlpha = process.argv.includes('--alpha');
const isDev = process.argv.includes('--develop');
export default function (eleventyConfig) {
// NOTE - alpha setting removes certain pages
if (isAlpha) {
eleventyConfig.ignores.add('**/experimental/**');
eleventyConfig.ignores.add('**/layout/**');
eleventyConfig.ignores.add('**/patterns/**');
eleventyConfig.ignores.add('**/style-utilities/**');
eleventyConfig.ignores.add('**/components/code-demo.md');
eleventyConfig.ignores.add('**/components/viewport-demo.md');
}
// Add template data
eleventyConfig.addGlobalData('package', packageData);
eleventyConfig.addGlobalData('isAlpha', isAlpha);
// Template filters - {{ content | filter }}
eleventyConfig.addFilter('inlineMarkdown', content => markdown.renderInline(content || ''));
eleventyConfig.addFilter('markdown', content => markdown.render(content || ''));
for (let name in filters) {
eleventyConfig.addFilter(name, filters[name]);
}
eleventyConfig.addFilter('sort', (arr, key = 'data.title') => {
key = key.split('.');
return arr.sort((a, b) => {
let aVal = key.reduce((obj, i) => obj?.[i], a);
let bVal = key.reduce((obj, i) => obj?.[i], b);
return aVal.localeCompare(bVal);
});
});
// Shortcodes - {% shortCode arg1, arg2 %}
eleventyConfig.addShortcode('cdnUrl', location => {
return `https://early.webawesome.com/webawesome@${packageData.version}/dist/` + location.replace(/^\//, '');
});
// Helpers
// Remove elements that have [data-alpha="remove"]
eleventyConfig.addPlugin(removeDataAlphaElements({ isAlpha }));
// Use our own markdown instance
eleventyConfig.setLibrary('md', markdown);
// Add anchors to headings
eleventyConfig.addPlugin(anchorHeadingsPlugin({ container: '#content' }));
// Add an outline to the page
eleventyConfig.addPlugin(
outlinePlugin({
container: '#content',
target: '.outline-links',
selector: 'h2, h3',
ifEmpty: doc => {
doc.querySelector('#outline')?.remove();
},
}),
);
// Add current link classes
eleventyConfig.addPlugin(currentLink());
// Add code examples for `<code class="example">` blocks
eleventyConfig.addPlugin(codeExamplesPlugin);
// Highlight code blocks with Prism
eleventyConfig.addPlugin(highlightCodePlugin());
// Add copy code buttons to code blocks
eleventyConfig.addPlugin(copyCodePlugin());
// Various text replacements
eleventyConfig.addPlugin(
replaceTextPlugin([
// Replace [issue:1234] with a link to the issue on GitHub
{
replace: /\[pr:([0-9]+)\]/gs,
replaceWith: '<a href="https://github.com/shoelace-style/webawesome/pull/$1">#$1</a>',
},
// Replace [pr:1234] with a link to the pull request on GitHub
{
replace: /\[issue:([0-9]+)\]/gs,
replaceWith: '<a href="https://github.com/shoelace-style/webawesome/issues/$1">#$1</a>',
},
// Replace [discuss:1234] with a link to the discussion on GitHub
{
replace: /\[discuss:([0-9]+)\]/gs,
replaceWith: '<a href="https://github.com/shoelace-style/webawesome/discussions/$1">#$1</a>',
},
]),
);
// SSR plugin
if (!isDev) {
//
// Problematic components in SSR land:
// - animation (breaks on navigation + ssr with Turbo)
// - mutation-observer (why SSR this?)
// - resize-observer (why SSR this?)
// - tooltip (why SSR this?)
//
const omittedModules = [];
const componentModules = componentList
.filter(component => !omittedModules.includes(component.tagName.split(/wa-/)[1]))
.map(component => {
const name = component.tagName.split(/wa-/)[1];
return `./dist/components/${name}/${name}.js`;
});
eleventyConfig.addPlugin(litPlugin, {
mode: 'worker',
componentModules,
});
}
// Build the search index
eleventyConfig.addPlugin(
searchPlugin({
filename: '',
selectorsToIgnore: ['code.example'],
getContent: doc => doc.querySelector('#content')?.textContent ?? '',
}),
);
// Production-only plugins
//
// TODO - disabled because it takes about a minute to run now
//
// if (!isDev) {
// // Run Prettier on each file (prod only because it can be slow)
// eleventyConfig.addPlugin(formatCodePlugin());
// }
return {
markdownTemplateEngine: 'njk',
dir: {
includes: '_includes',
layouts: '_layouts',
},
templateFormats: ['njk', 'md'],
};
}

View File

@@ -0,0 +1,75 @@
/**
* @module components Fetches components from custom-elements.json and exposes them in a saner format.
*/
import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const manifest = JSON.parse(readFileSync(resolve(__dirname, '../../dist/custom-elements.json'), 'utf-8'));
const components = manifest.modules.flatMap(module => {
return module.declarations
.filter(c => c?.customElement)
.map(declaration => {
// Generate the dist path based on the src path and attach it to the component
declaration.path = module.path.replace(/^src\//, 'dist/').replace(/\.ts$/, '.js');
// Remove private members and those that lack a description
const members = declaration.members?.filter(member => member.description && member.privacy !== 'private');
const methods = members?.filter(prop => prop.kind === 'method' && prop.privacy !== 'private');
const attributes = declaration.attributes ?? [];
const properties = members?.filter(prop => {
// Look for a corresponding attribute
const attribute = attributes?.find(attr => attr.fieldName === prop.name);
if (attribute) {
prop.attribute = attribute.name || attribute.fieldName;
}
return prop.kind === 'field' && prop.privacy !== 'private';
});
return {
...declaration,
slug: declaration.tagName.replace(/^wa-/, ''),
methods,
attributes,
properties,
};
});
});
// Build dependency graphs
components.forEach(component => {
const dependencies = [];
// Recursively fetch sub-dependencies
function getDependencies(tag) {
const cmp = components.find(c => c.tagName === tag);
if (!cmp || !Array.isArray(component.dependencies)) {
return;
}
cmp.dependencies?.forEach(dependentTag => {
if (!dependencies.includes(dependentTag)) {
dependencies.push(dependentTag);
}
getDependencies(dependentTag);
});
}
getDependencies(component.tagName);
component.dependencies = dependencies.sort();
});
// Sort by name
components.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
export default components;

3
docs/_data/components.js Normal file
View File

@@ -0,0 +1,3 @@
import componentList from './componentList.js';
export default Object.fromEntries(componentList.map(component => [component.slug, component]));

View File

@@ -0,0 +1,43 @@
import components from './components.js';
const by = {
attribute: {},
slot: {},
event: {},
method: {},
cssPart: {},
cssProperty: {},
};
function getAll(component, type) {
let prop = type + 's';
if (type === 'cssProperty') {
prop = 'cssProperties';
}
return component[prop] ?? [];
}
for (const componentName in components) {
const component = components[componentName];
for (const type of ['attribute', 'slot', 'event', 'method', 'cssPart', 'cssProperty']) {
for (const item of getAll(component, type)) {
by[type][item.name] ??= [];
by[type][item.name].push(component);
}
}
}
// Sort by descending number of components
const sortByLengthDesc = (a, b) => b[1].length - a[1].length;
for (const key in by) {
by[key] = sortObject(by[key], sortByLengthDesc);
}
export default by;
function sortObject(obj, sorter) {
return Object.fromEntries(Object.entries(obj).sort(sorter));
}

File diff suppressed because one or more lines are too long

178
docs/_includes/base.njk Normal file
View File

@@ -0,0 +1,178 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description }}">
<meta name="theme-color" content="#f36944">
{% if noindex %}<meta name="robots" content="noindex">{% endif %}
<title>{{ title }}</title>
<link rel="icon" href="/assets/images/webawesome-logo.svg" />
<link rel="apple-touch-icon" href="/assets/images/app-icon.png">
{# Scripts #}
{# Hydration stuff #}
<script src="/assets/scripts/hydration-errors.js"></script>
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
<script type="module" src="/assets/scripts/code-examples.js"></script>
<script type="module" src="/assets/scripts/color-scheme.js"></script>
<script type="module" src="/assets/scripts/copy-code.js"></script>
<script type="module" src="/assets/scripts/preset-theme.js"></script>
<script type="module" src="/assets/scripts/scroll.js"></script>
<script type="module" src="/assets/scripts/turbo.js"></script>
<script type="module" src="/assets/scripts/search.js"></script>
<script type="module" src="/assets/scripts/outline.js"></script>
<script defer data-domain="backers.webawesome.com" src="https://plausible.io/js/script.js"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<link rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/default.css" />
<link rel="stylesheet" href="/dist/styles/applied.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />
{# Docs styles #}
<link rel="stylesheet" href="/assets/styles/docs.css" />
{# Set the theme to prevent flashing #}
<script>
function getColorScheme() {
return localStorage.getItem('colorScheme') || 'auto';
}
function getPresetTheme () {
return localStorage.getItem('presetTheme') || 'default';
}
function isDark() {
const colorScheme = getColorScheme()
if (colorScheme === 'auto') {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
return colorScheme === 'dark';
}
const oldStylesheet = document.querySelector("#theme-stylesheet")
const newStylesheet = document.createElement("link")
let preset = getPresetTheme()
newStylesheet.href = `/dist/styles/themes/${preset}.css`
newStylesheet.rel = "preload"
newStylesheet.as = "style"
document.head.append(newStylesheet)
function updateStylesheet () {
newStylesheet.rel = "stylesheet"
newStylesheet.id = "theme-stylesheet"
requestAnimationFrame(() => oldStylesheet.remove())
}
newStylesheet.addEventListener("load", updateStylesheet)
document.documentElement.classList.toggle(
`wa-theme-${preset}-dark`,
isDark()
);
</script>
</head>
<body class="layout-{{ layout | stripExtension }}">
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
<wa-page view="desktop" disable-navigation-toggle="">
<header slot="header">
{# Logo #}
<div id="docs-branding">
{# Nav toggle #}
<wa-button appearance="plain" size="small" data-toggle-nav>
<wa-icon name="bars" label="Toggle navigation"></wa-icon>
</wa-button>
<a href="/" aria-label="Web Awesome">
<span class="only-desktop">{% include "logo.njk" %}</span>
<span class="only-mobile">{% include "logo-simple.njk" %}</span>
</a>
<small id="version-number" class="only-desktop">{{ package.version }}</small>
<wa-badge variant="warning" appearance="filled" class="only-desktop">Alpha</wa-badge>
</div>
<div id="docs-toolbar">
{# Desktop selectors #}
<div class="only-desktop">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
{# Search #}
<wa-button id="search-trigger" appearance="outlined" size="small" data-search>
<wa-icon slot="prefix" name="magnifying-glass"></wa-icon>
Search
<kbd slot="suffix" class="only-desktop">/</kbd>
</wa-button>
</div>
</header>
{# Sidebar #}
{% if hasSidebar %}
{# Mobile selectors #}
<div class="only-mobile" slot="navigation-header">
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
</div>
<div slot="navigation" id="sidebar" class="docs-aside" data-remember-scroll>
{% include "sidebar.njk" %}
</div>
{% endif %}
{# Outline #}
{% if hasOutline %}
<aside slot="aside" id="outline" class="docs-aside">
<nav id="outline-standard" class="outline-links">
<h2><a href="#content">{{ title }}</a></h2>
</nav>
</aside>
{% endif %}
{# Main #}
<main id="content">
{# Expandable outline #}
<nav id="outline-expandable">
<details class="outline-links">
<summary>On this page</summary>
</details>
</nav>
{% set breadcrumbs = page.url | breadcrumbs %}
{% if breadcrumbs.length > 0 %}
<wa-breadcrumb id="docs-breadcrumbs">
{% for crumb in breadcrumbs %}
<wa-breadcrumb-item href="{{ crumb.url }}">{{ crumb.title }}</wa-breadcrumb-item>
{% endfor %}
<wa-breadcrumb-item>{# Current page #}</wa-breadcrumb-item>
</wa-breadcrumb>
{% else %}
{% endif %}
{% block beforeContent %}{% endblock %}
{% block content %}
<h1 class="title">{{ title }}</h1>
{{ content | safe }}
{% endblock %}
{% block afterContent %}{% endblock %}
</main>
{% include 'search.njk' %}
</wa-page>
</body>
</html>

View File

@@ -0,0 +1,15 @@
{# Color scheme selector #}
<wa-dropdown id="color-scheme-selector">
<wa-button slot="trigger" appearance="filled" size="small" pill caret title="Press \ to toggle">
<wa-icon class="only-light" slot="prefix" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="prefix" name="moon" variant="regular"></wa-icon>
<span class="only-light">Light</span>
<span class="only-dark">Dark</span>
</wa-button>
<wa-menu>
<wa-menu-item type="checkbox" value="light">Light</wa-menu-item>
<wa-menu-item type="checkbox" value="dark">Dark</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item type="checkbox" value="auto">System</wa-menu-item>
</wa-menu>
</wa-dropdown>

View File

Before

Width:  |  Height:  |  Size: 742 B

After

Width:  |  Height:  |  Size: 742 B

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,26 @@
<div id="page_slots_demo">
<link rel="stylesheet" href="/assets/examples/page-demo/demo.css">
{% set slots = components.page.slots %}
<fieldset id="page_slots_fieldset">
<legend>Slots</legend>
<div class="options">
{% for slot in slots %}
{% if (slot.name != "skip-to-content") and (slot.name != "navigation-toggle-icon") %}
<wa-checkbox name="slot" value="{{ slot.name }}" {{ 'checked' if slot.name != "menu" and slot.name != 'navigation-toggle' | safe}} class="{{ 'default' if not slot.name }}"
data-description="{{ slot.description | inlineMarkdown }}" title="{{ slot.description | inlineMarkdown | striptags | safe }}">
{{ slot.name or "(default)" }}
</wa-checkbox>
{% endif %}
{% endfor %}
</div>
</fieldset>
<wa-viewport-demo viewport="1000">
<iframe srcdoc="" id="page_slots_iframe"></iframe>
</wa-viewport-demo>
</div>
<script type="module">
const cacheBust = new Date().toString()
import(`/assets/examples/page-demo/demo.js?${cacheBust}`)
</script>

View File

@@ -0,0 +1,18 @@
{# Preset theme selector #}
<wa-dropdown id="preset-theme-selector">
<wa-button slot="trigger" appearance="filled" size="small" pill caret>
<wa-icon slot="prefix" name="paintbrush" variant="regular"></wa-icon>
<span id="preset-theme-selector__text">Default</span>
</wa-button>
<wa-menu>
<wa-menu-item type="checkbox" value="default">Default</wa-menu-item>
<wa-menu-item type="checkbox" value="classic">Classic</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="fa">Font Awesome</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="active">Active</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="brutalist">Brutalism</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="glassy">Glassy</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="migration">Migration</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="playful">Playful</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="premium">Premium</wa-menu-item>
</wa-menu>
</wa-dropdown>

View File

@@ -1,4 +1,4 @@
<wa-dialog id="site-search" without-header light-dismiss>
<wa-dialog id="site-search" no-header light-dismiss>
<div id="site-search-container">
{# Header #}
<header>
@@ -8,7 +8,7 @@
type="search"
appearance="filled"
size="large"
with-clear
clearable
placeholder="Search"
autofocus
autocomplete="off"
@@ -24,7 +24,7 @@
aria-haspopup="listbox"
aria-activedescendant
>
<wa-icon slot="start" name="search"></wa-icon>
<wa-icon slot="prefix" name="search"></wa-icon>
</wa-input>
</div>
</header>

150
docs/_includes/sidebar.njk Normal file
View File

@@ -0,0 +1,150 @@
{# Getting started #}
<h2>Getting Started</h2>
<ul>
<li><a href="/docs/installation">Installation</a></li>
<li><a href="/docs/usage">Usage</a></li>
<li><a href="/docs/themes">Themes</a></li>
<li><a href="/docs/customizing">Customizing</a></li>
<li><a href="/docs/form-controls">Form Controls</a></li>
<li><a href="/docs/localization">Localization</a></li>
</ul>
{# Resources #}
<h2>Resources</h2>
<ul>
<li><a href="https://github.com/shoelace-style/webawesome-alpha/discussions" target="_blank">Help &amp; Support</a></li>
<li><a href="/docs/resources/community">Community</a></li>
<li><a href="/docs/resources/accessibility">Accessibility</a></li>
<li><a href="/docs/resources/contributing">Contributing</a></li>
<li><a href="/docs/resources/changelog">Changelog</a></li>
</ul>
{# Components #}
<wa-details{{ ' open' if '/components/' in page.url }}>
<h2 slot=summary>
<a href="/docs/components/" title="Overview">Components
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
{% for component in collections.component | sort %}
{% if not component.data.parent and not (isAlpha and component.data.isAlpha) %}
<li>
<a href="/docs/components/{{ component.fileSlug }}">{{ component.data.title }}</a>
{% if components[component.fileSlug].status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
{% if component.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
<ul>
{% for child in collections.component | sort %}
{% if child.data.parent == component.fileSlug and not (isAlpha and child.data.isAlpha) %}
<li>
<a href="/docs/components/{{ child.fileSlug }}">{{ child.data.title }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
</ul>
</wa-details>
<wa-details{{ ' open' if '/natives/' in page.url }}>
<h2 slot=summary>
<a href="/docs/natives/" title="Overview">Natives
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
{% for page in collections.natives | sort %}
<li>
<a href="/docs/natives/{{ page.fileSlug }}">{{ page.data.title }}</a>
</li>
{% endfor %}
</ul>
</wa-details>
{# Layout #}
{% if not isAlpha %}
<h2>
<a href="/docs/layout" title="Overview">Layout
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
<li><a href="/docs/components/page">Page</a></li>
<li><a href="/docs/layout/cluster">Cluster</a></li>
<li><a href="/docs/layout/flank">Flank</a></li>
<li><a href="/docs/layout/frame">Frame</a></li>
<li><a href="/docs/layout/grid">Grid</a></li>
<li><a href="/docs/layout/split">Split</a></li>
<li><a href="/docs/layout/stack">Stack</a></li>
</ul>
{% endif %}
{# Patterns #}
{% if not isAlpha %}
<h2>Patterns</h2>
<ul>
<li><a href="/docs/patterns/app">Web App</a></li>
<li><a href="/docs/patterns/ecommerce">E-commerce</a>
<ul>
<li><a href="/docs/patterns/ecommerce-product-review">Product Reviews</a></li>
<li><a href="/docs/patterns/ecommerce-product-list">Product Lists</a></li>
<li><a href="/docs/patterns/ecommerce-category-preview">Category Previews</a></li>
<li><a href="/docs/patterns/ecommerce-shopping-cart">Shopping Carts</a></li>
<li><a href="/docs/patterns/ecommerce-category-filter">Category Filters</a></li>
<li><a href="/docs/patterns/ecommerce-product-detail">Product Detail</a></li>
<li><a href="/docs/patterns/ecommerce-order-summary">Order Summaries</a></li>
<li><a href="/docs/patterns/ecommerce-order-history">Order History</a></li>
</ul>
</li>
<li><a href="/docs/patterns/blog">Blog</a></li>
<li><a href="/docs/patterns/news">News</a></li>
</ul>
{% endif %}
{# Theming #}
<h2>
<a href="/docs/theming" title="Overview">Theming
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
<li>
<a href="/docs/theming/color">Color</a>
</li>
<li>
<a href="/docs/theming/typography">Typography</a>
</li>
<li>
<a href="/docs/theming/space">Space</a>
</li>
<li>
<a href="/docs/theming/borders">Borders</a>
</li>
<li>
<a href="/docs/theming/focus">Focus</a>
</li>
<li>
<a href="/docs/theming/shadows">Shadows</a>
</li>
<li>
<a href="/docs/theming/transitions">Transitions</a>
</li>
<li>
<a href="/docs/theming/component-groups">Component Groups</a>
</li>
</ul>
{# Style Utilities #}
{% if not isAlpha %}
<h2>Style Utilities</h2>
<ul>
<li><a href="/docs/style-utilities/align-items">Align Items</a></li>
<li><a href="/docs/style-utilities/border-radius">Border Radius</a></li>
<li><a href="/docs/style-utilities/gap">Gap</a></li>
<li><a href="/docs/style-utilities/text">Text</a></li>
</ul>
{% endif %}

View File

Before

Width:  |  Height:  |  Size: 936 B

After

Width:  |  Height:  |  Size: 936 B

View File

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 380 B

View File

Before

Width:  |  Height:  |  Size: 754 B

After

Width:  |  Height:  |  Size: 754 B

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 742 B

After

Width:  |  Height:  |  Size: 742 B

View File

Before

Width:  |  Height:  |  Size: 670 B

After

Width:  |  Height:  |  Size: 670 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 6C0 2.68629 2.68629 0 6 0H26C29.3137 0 32 2.68629 32 6V26C32 29.3137 29.3137 32 26 32H6C2.68629 32 0 29.3137 0 26V6Z" fill="var(--wa-color-neutral-fill-normal)"/>
<path d="M23.4688 13.2188C23.5938 13.5 23.5 13.7812 23.2812 14L21.9375 15.2188C21.9688 15.4688 21.9688 15.75 21.9688 16C21.9688 16.2812 21.9688 16.5625 21.9375 16.8125L23.2812 18.0312C23.5 18.2188 23.5938 18.5312 23.4688 18.8125C23.3438 19.1875 23.1875 19.5312 23 19.875L22.8438 20.125C22.625 20.4688 22.4062 20.8125 22.1562 21.0938C21.9688 21.3438 21.6562 21.4062 21.375 21.3125L19.6562 20.7812C19.2188 21.0938 18.75 21.3438 18.2812 21.5625L17.875 23.3438C17.8125 23.625 17.5938 23.8438 17.3125 23.9062C16.875 23.9688 16.4375 24 15.9688 24C15.5312 24 15.0938 23.9688 14.6562 23.9062C14.375 23.8438 14.1562 23.625 14.0938 23.3438L13.6875 21.5625C13.1875 21.3438 12.75 21.0938 12.3125 20.7812L10.5938 21.3125C10.3125 21.4062 10 21.3438 9.8125 21.125C9.5625 20.8125 9.34375 20.4688 9.125 20.125L8.96875 19.875C8.78125 19.5312 8.625 19.1875 8.5 18.8125C8.375 18.5312 8.46875 18.25 8.6875 18.0312L10.0312 16.8125C10 16.5625 10 16.2812 10 16C10 15.75 10 15.4688 10.0312 15.2188L8.6875 14C8.46875 13.7812 8.375 13.5 8.5 13.2188C8.625 12.8438 8.78125 12.5 8.96875 12.1562L9.125 11.9062C9.34375 11.5625 9.5625 11.2188 9.8125 10.9062C10 10.6875 10.3125 10.625 10.5938 10.7188L12.3125 11.25C12.75 10.9375 13.2188 10.6562 13.6875 10.4688L14.0938 8.6875C14.1562 8.40625 14.375 8.1875 14.6562 8.125C15.0938 8.0625 15.5312 8 16 8C16.4375 8 16.875 8.0625 17.3125 8.125C17.5938 8.15625 17.8125 8.40625 17.875 8.6875L18.2812 10.4688C18.7812 10.6562 19.2188 10.9375 19.6562 11.25L21.375 10.7188C21.6562 10.625 21.9688 10.6875 22.1562 10.9062C22.4062 11.2188 22.625 11.5625 22.8438 11.9062L23 12.1562C23.1875 12.5 23.3438 12.8438 23.5 13.2188H23.4688ZM16 18.5C16.875 18.5 17.6875 18.0312 18.1562 17.25C18.5938 16.5 18.5938 15.5312 18.1562 14.75C17.6875 14 16.875 13.5 16 13.5C15.0938 13.5 14.2812 14 13.8125 14.75C13.375 15.5312 13.375 16.5 13.8125 17.25C14.2812 18.0312 15.0938 18.5 16 18.5Z" fill="var(--wa-color-neutral-on-normal)"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 518 B

After

Width:  |  Height:  |  Size: 518 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 524 B

After

Width:  |  Height:  |  Size: 524 B

View File

Before

Width:  |  Height:  |  Size: 718 B

After

Width:  |  Height:  |  Size: 718 B

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 531 B

View File

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

View File

Before

Width:  |  Height:  |  Size: 521 B

After

Width:  |  Height:  |  Size: 521 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 614 B

After

Width:  |  Height:  |  Size: 614 B

View File

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 337 B

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 883 B

View File

Before

Width:  |  Height:  |  Size: 447 B

After

Width:  |  Height:  |  Size: 447 B

View File

Before

Width:  |  Height:  |  Size: 388 B

After

Width:  |  Height:  |  Size: 388 B

View File

Before

Width:  |  Height:  |  Size: 540 B

After

Width:  |  Height:  |  Size: 540 B

View File

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

View File

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 547 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 655 B

View File

Before

Width:  |  Height:  |  Size: 596 B

After

Width:  |  Height:  |  Size: 596 B

View File

@@ -2,7 +2,7 @@
<path fill-rule="evenodd" clip-rule="evenodd" d="M48.8665 59.1993L33.7329 33H64C63.8352 38.2705 62.3694 43.4244 59.7264 48C57.0833 52.5756 53.3507 56.4213 48.8665 59.1993Z" fill="var(--wa-color-green-70)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M32 64C26.714 64 21.5155 62.6919 16.8665 60.1993L32 34L47.1336 60.1993C42.4845 62.6919 37.286 64 32 64Z" fill="var(--wa-color-blue-60)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.27365 48C1.63063 43.4244 0.164839 38.2706 0 33L30.2671 33L15.1336 59.1993C10.6493 56.4213 6.91666 52.5756 4.27365 48Z" fill="var(--wa-color-indigo-60)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.27365 16C6.91667 11.4244 10.6493 7.57868 15.1336 4.80072L30.2671 31L0 31C0.16484 25.7295 1.63063 20.5756 4.27365 16Z" fill="var(--wa-color-purple-60)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.27365 16C6.91667 11.4244 10.6493 7.57868 15.1336 4.80072L30.2671 31L0 31C0.16484 25.7295 1.63063 20.5756 4.27365 16Z" fill="var(--wa-color-violet-60)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M32 30L16.8665 3.80072C21.5155 1.30813 26.714 0 32 0C37.286 0 42.4845 1.30813 47.1336 3.80072L32 30Z" fill="var(--wa-color-red-60)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.7329 31L48.8665 4.80072C53.3507 7.57868 57.0833 11.4244 59.7264 16C62.3694 20.5756 63.8352 25.7294 64 31L33.7329 31Z" fill="var(--wa-color-yellow-80)"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 502 B

After

Width:  |  Height:  |  Size: 502 B

View File

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 790 B

View File

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 697 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

68
docs/_layouts/blank.njk Normal file
View File

@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description }}">
{% if noindex %}<meta name="robots" content="noindex">{% endif %}
<title>{{ title }}</title>
<link rel="icon" href="/assets/images/webawesome-logo.svg" />
<link rel="apple-touch-icon" href="/assets/images/app-icon.png">
{# Scripts #}
{# Hydration stuff #}
<script src="/assets/scripts/hydration-errors.js"></script>
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<link rel="stylesheet" id="theme-stylesheet" />
<link rel="stylesheet" href="/dist/styles/applied.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />
{# Set the theme to prevent flashing #}
<script>
function getColorScheme() {
return localStorage.getItem('colorScheme') || 'auto';
}
function getPresetTheme () {
return localStorage.getItem('presetTheme') || 'default';
}
function isDark() {
const colorScheme = getColorScheme()
if (colorScheme === 'auto') {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
return colorScheme === 'dark';
}
const stylesheet = document.getElementById("theme-stylesheet")
let preset = getPresetTheme()
stylesheet.href = `/dist/styles/themes/${preset}.css`
document.documentElement.classList.toggle(
`wa-theme-${preset}-dark`,
isDark()
);
</script>
</head>
<body class="layout-{{ layout | stripExtension }}">
{% block beforeContent %}{% endblock %}
{% block content %}
{{ content | safe }}
{% endblock %}
{% block afterContent %}{% endblock %}
</body>
</html>

View File

@@ -1,10 +1,15 @@
{% extends '../_layouts/docs.njk' %}
{% set component = getComponent('wa-' + page.fileSlug) %}
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% set component = components[page.fileSlug] %}
{% set description = component.summary %}
{% extends '../_includes/base.njk' %}
{# Component header #}
{% block beforeContent %}
<h1 class="title">{{ title }}</h1>
<div class="component-info">
<code class="component-tag">&lt;{{ component.tagName }}&gt;</code>
<code class="tag">&lt;{{ component.tagName }}&gt;</code>
<wa-badge variant="neutral">Since {{ component.since }}</wa-badge>
<wa-badge
{% if component.status == 'stable' %}variant="brand"{% endif %}
@@ -12,10 +17,24 @@
>
{{ component.status }}
</wa-badge>
{% if isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
</div>
<p class="component-summary">
<p class="summary">
{{ component.summary | inlineMarkdown | safe }}
</p>
{% if natives %}
<wa-callout variant="success">
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
Just want the styles?
Check out <a href="/docs/natives/{{ natives }}/">{{ ('/docs/natives/' + natives + '/') | getTitleFromUrl }} natives</a>!
</wa-callout>
{% endif %}
{% endblock %}
{# Content #}
{% block content %}
{{ content | safe }}
{% endblock %}
{# Component API #}
@@ -25,8 +44,8 @@
<h2>Slots</h2>
<p>Learn more about <a href="/docs/usage/#slots">using slots</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
@@ -48,7 +67,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# Properties #}
@@ -56,13 +75,13 @@
<h2>Attributes & Properties</h2>
<p>Learn more about <a href="/docs/usage/#attributes-and-properties">attributes and properties</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
<th class="table-description">Description</th>
<th class="table-reflect">Reflects</th>
<th class="table-reflects">Reflects</th>
</tr>
</thead>
<tbody>
@@ -83,7 +102,7 @@
<div><small><strong>Default</strong>&nbsp;<code>{{ prop.default | inlineMarkdown | safe }}</code></small></div>
{% endif %}
</td>
<td class="table-reflect">
<td class="table-checkmark">
{% if prop.reflects %}
<wa-icon name="check"></wa-icon>
{% endif %}
@@ -95,7 +114,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# Methods #}
@@ -103,8 +122,8 @@
<h2>Methods</h2>
<p>Learn more about <a href="/docs/usage/#methods">methods</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
@@ -130,7 +149,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# Events #}
@@ -138,8 +157,8 @@
<h2>Events</h2>
<p>Learn more about <a href="/docs/usage/#events">events</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
@@ -157,7 +176,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# Custom Properties #}
@@ -165,8 +184,8 @@
<h2>CSS custom properties</h2>
<p>Learn more about <a href="/docs/customizing/#custom-properties">CSS custom properties</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
@@ -189,7 +208,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# Custom States #}
@@ -197,8 +216,8 @@
<h2>Custom States</h2>
<p>Learn more about <a href="/docs/customizing/#custom-states">custom states</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
@@ -216,7 +235,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# CSS Parts #}
@@ -224,8 +243,8 @@
<h2>CSS parts</h2>
<p>Learn more about <a href="/docs/customizing/#css-parts">CSS parts</a>.</p>
<wa-scroller>
<table class="component-table wa-hover-rows">
<div class="table-scroll">
<table class="component-table">
<thead>
<tr>
<th class="table-name">Name</th>
@@ -241,7 +260,7 @@
{% endfor %}
</tbody>
</table>
</wa-scroller>
</div>
{% endif %}
{# Dependencies #}
@@ -261,12 +280,9 @@
{# Importing #}
<h2>Importing</h2>
<p>
The <a href="/docs/#quick-start-autoloading-via-cdn">autoloader</a> is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
The <a href="/docs/#autoloading">autoloader</a> is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
</p>
{% set componentName = component.tagName | stripPrefix %}
{% set componentPath = ["components/", componentName, "/", componentName, ".js"] | join("") %}
<wa-tab-group label="How would you like to import this component?">
<wa-tab panel="cdn">CDN</wa-tab>
<wa-tab panel="npm">npm</wa-tab>
@@ -275,34 +291,19 @@
<p>
To manually import this component from the CDN, use the following code.
</p>
<pre><code class="language-js">import '{% cdnUrl componentPath %}';</code></pre>
<pre><code class="language-js">import '{% cdnUrl component.path %}';</code></pre>
</wa-tab-panel>
<wa-tab-panel name="npm">
<p>
To manually import this component from NPM, use the following code.
</p>
<pre><code class="language-js">import '@awesome.me/webawesome/dist/{{ componentPath }}';</code></pre>
Coming soon!
</wa-tab-panel>
<wa-tab-panel name="react">
Coming soon!
{# NOTE - disabled for alpha
<p>
To manually import this component from React, use the following code.
</p>
<pre><code class="language-js">import {{ component.name }} from '@awesome.me/webawesome/dist/react/{{ componentName }}';</code></pre>
<pre><code class="language-js">import '@shoelace-style/webawesome/react/{{ component.tagName | stripPrefix }}';</code></pre>
#}
</wa-tab-panel>
</wa-tab-group>
<wa-divider></wa-divider>
<div class="component-help">
<strong>Need a hand?</strong>
<wa-button size="small" appearance="filled" variant="neutral" href="https://github.com/shoelace-style/webawesome/issues" target="_blank">
<wa-icon slot="start" variant="regular" name="bug"></wa-icon>
Report a bug
</wa-button>
<wa-button size="small" appearance="filled" variant="neutral" href="https://github.com/shoelace-style/webawesome/discussions" target="_blank">
<wa-icon slot="start" variant="regular" name="message-question"></wa-icon>
Ask for help
</wa-button>
</div>
{% endblock %}

55
docs/_layouts/element.njk Normal file
View File

@@ -0,0 +1,55 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends '../_includes/base.njk' %}
{# Component header #}
{% block beforeContent %}
<h1 class="title">{{ title }}</h1>
<div class="component-info">
{% for tag, url in elements %}
<code class="tag"><a href="{{ url }}">{{ tag }}</a></code>
{% endfor %}
{% if since %}<wa-badge variant="neutral">Since {{ since }}</wa-badge>{% endif %}
{% if status %}
<wa-badge
{% if status == 'stable' %}variant="brand"{% endif %}
{% if status == 'experimental' %}variant="warning"{% endif %}
>
{{ status }}
</wa-badge>
{% endif %}
{% if isPro %}
<wa-badge class="pro">PRO</wa-badge>
{% endif %}
</div>
{% if description -%}
<p class="summary">{{ description | inlineMarkdown | safe }}</p>
{%- endif %}
{% if component %}
<wa-callout variant="success">
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
Want to do more?
Check out the {% for name in (component | toArray) -%}
{{ ' and ' if loop.last and not loop.first }}<a href="/docs/components/{{ name }}"><code>&lt;wa-{{ name }}&gt;</code></a>{{ ', ' if not loop.last }}
{%- endfor %} component{{ 's' if (component | isArray) }}</a>!
</wa-callout>
{% endif %}
{% endblock %}
{# Content #}
{% block content %}
{{ content | safe }}
{% endblock %}
{# Component API #}
{% block afterContent %}
{# Slots #}
{% if css_file %}
<h2>Using these styles</h2>
<p>If you want to use these styles without using the entirety of Web Awesome Natives, you can include the following CSS files:</p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,4 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends "../_includes/base-wide.njk" %}

4
docs/_layouts/page.njk Normal file
View File

@@ -0,0 +1,4 @@
{% set hasSidebar = true %}
{% set hasOutline = false %}
{% extends "../_includes/base.njk" %}

View File

@@ -0,0 +1,4 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends "../_includes/base.njk" %}

View File

@@ -0,0 +1,84 @@
import { parse } from 'node-html-parser';
import slugify from 'slugify';
import { v4 as uuid } from 'uuid';
function createId(text) {
let slug = slugify(String(text), {
remove: /[^\w|\s]/g,
lower: true,
});
// ids must start with a letter
if (!/^[a-z]/i.test(slug)) {
slug = `wa_${slug}`;
}
return slug;
}
/**
* Eleventy plugin to add anchors to headings to content.
*/
export function anchorHeadingsPlugin(options = {}) {
options = {
container: 'body',
headingSelector: 'h2, h3, h4, h5, h6',
anchorLabel: 'Jump to heading',
...options,
};
return function (eleventyConfig) {
eleventyConfig.addTransform('anchor-headings', content => {
const doc = parse(content);
const container = doc.querySelector(options.container);
if (!container) {
return content;
}
// Look for headings
container.querySelectorAll(options.headingSelector).forEach(heading => {
const hasAnchor = heading.querySelector('a');
const existingId = heading.getAttribute('id');
const clone = parse(heading.outerHTML);
// Create a clone of the heading so we can remove [data-no-anchor] elements from the text content
clone.querySelectorAll('[data-no-anchor]').forEach(el => el.remove());
if (hasAnchor) {
return;
}
let id = existingId;
if (!id) {
const slug = createId(clone.textContent ?? '') ?? uuid().slice(-12);
id = slug;
let suffix = 1;
// Make sure the slug is unique in the document
while (doc.getElementById(id) !== null) {
id = `${slug}-${++suffix}`;
}
}
// Create the anchor
const anchor = parse(`
<a href="#${encodeURIComponent(id)}">
<span class="wa-visually-hidden"></span>
<span aria-hidden="true">#</span>
</a>
`);
anchor.querySelector('.wa-visually-hidden').textContent = options.anchorLabel;
// Update the heading
if (!existingId) {
heading.setAttribute('id', id);
}
heading.classList.add('anchor-heading');
heading.appendChild(anchor);
});
return doc.toString();
});
};
}

View File

@@ -0,0 +1,190 @@
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, attributes }) {
attributes = {
open,
include: `link[rel=stylesheet][href^='/dist/']`,
...attributes,
};
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 === undefined) {
// Slot in pre-rendered preview
preview = `<div style="display:contents" slot="preview">${code.textContent}</div>`;
// 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 `${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(eleventyConfig, options = {}) {
const defaultOptions = {
container: 'body',
defaultOpen: (code, { outputPathIndex }) => {
return (
outputPathIndex === 1 && // is first
code.textContent.length < 500
); // is short
},
};
options = { ...defaultOptions, ...options };
const stats = {
inputPaths: {},
outputPaths: {},
};
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
attributes: {},
};
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;
}
}
for (const attribute of ['viewport', 'include']) {
if (code.hasAttribute(attribute)) {
localOptions.attributes[attribute] = code.getAttribute(attribute);
code.removeAttribute(attribute);
}
}
if (Object.keys(localOptions.attributes).length > 0) {
// attributes only work on the new syntax
localOptions.new = true;
}
if (localOptions.open === undefined) {
if (localOptions.defaultOpen === true) {
localOptions.open = localOptions.defaultOpen;
} else if (typeof localOptions.defaultOpen === 'function') {
localOptions.open = localOptions.defaultOpen(code, {
pre,
inputPathIndex: stats.inputPaths[inputPath],
outputPathIndex: stats.outputPaths[outputPath],
});
}
}
const template = localOptions.new ? 'new' : 'old';
const codeExample = parse(templates[template](pre, code, localOptions));
pre.replaceWith(codeExample);
});
return doc.toString();
});
}

32
docs/_utils/copy-code.js Normal file
View File

@@ -0,0 +1,32 @@
import { parse } from 'node-html-parser';
/**
* Eleventy plugin to add copy buttons to code blocks.
*/
export function copyCodePlugin(options = {}) {
options = {
container: 'body',
...options,
};
return function (eleventyConfig) {
eleventyConfig.addTransform('copy-code', content => {
const doc = parse(content, { blockTextElements: { code: true } });
const container = doc.querySelector(options.container);
if (!container) {
return content;
}
// Look for code blocks
container.querySelectorAll('pre > code').forEach(code => {
const pre = code.closest('pre');
// Add a copy button (we set the copy data at runtime to reduce page bloat)
pre.innerHTML = `<wa-copy-button class="copy-button" hoist></wa-copy-button>` + pre.innerHTML;
});
return doc.toString();
});
};
}

View File

@@ -24,25 +24,30 @@ function normalize(pathname) {
/**
* Eleventy plugin to decorate current links with a custom class.
*/
export function currentLinkTransformer(options = {}) {
export function currentLink(options = {}) {
options = {
container: 'body',
className: 'current',
...options,
};
return function (doc) {
const container = doc.querySelector(options.container);
return function (eleventyConfig) {
eleventyConfig.addTransform('current-link', function (content) {
const doc = parse(content);
const container = doc.querySelector(options.container);
if (!container) {
return;
}
// Compare the href attribute to 11ty's page URL
container.querySelectorAll('a[href]').forEach(a => {
if (normalize(a.getAttribute('href')) === normalize(this.page.url)) {
a.classList.add(options.className);
if (!container) {
return content;
}
// Compare the href attribute to 11ty's page URL
container.querySelectorAll('a[href]').forEach(a => {
if (normalize(a.getAttribute('href')) === normalize(this.page.url)) {
a.classList.add(options.className);
}
});
return doc.toString();
});
};
}

79
docs/_utils/filters.js Normal file
View File

@@ -0,0 +1,79 @@
import { parse } from 'path';
export function stripExtension(string) {
return parse(string).name;
}
export function stripPrefix(content) {
return content.replace(/^wa-/, '');
}
// Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited.
// With Prettier 3, this means a leading pipe will exist be present when the line wraps.
export function trimPipes(content) {
return typeof content === 'string' ? content.replace(/^(\s|\|)/g, '').replace(/(\s|\|)$/g, '') : content;
}
export function keys(obj) {
return Object.keys(obj);
}
export function log(firstArg, ...rest) {
console.log(firstArg, ...rest);
return firstArg;
}
function getCollection(name) {
// From https://github.com/11ty/eleventy/blob/d3d24ccddb804e6e14773501d8c4e07e2c4b9c2b/src/Filters/GetLocaleCollectionItem.js#L39-L43
return this.collections?.[name] || this.ctx?.collections?.[name] || this.context?.environments?.collections?.[name];
}
export function getCollectionItemFromUrl(url, collection) {
collection ??= getCollection.call(this, 'all') || [];
return collection.find(item => item.url === url);
}
export function getTitleFromUrl(url, collection) {
const item = getCollectionItemFromUrl.call(this, url, collection);
return item?.data.title || '';
}
export function breadcrumbs(url, { withCurrent = false } = {}) {
const parts = url.split('/').filter(Boolean);
const ret = [];
while (parts.length) {
let partialUrl = '/' + parts.join('/') + '/';
let item = getCollectionItemFromUrl.call(this, partialUrl);
if (item && (partialUrl !== url || withCurrent)) {
let title = item.data.title;
if (title) {
ret.unshift({ url: partialUrl, title });
}
}
parts.pop();
if (item?.data.parent) {
let parentURL = item.data.parent;
if (!item.data.parent.startsWith('/')) {
// Parent is in the same directory
parts.push(item.data.parent);
parentURL = '/' + parts.join('/') + '/';
}
let parentBreadcrumbs = breadcrumbs.call(this, parentURL, { withCurrent: true });
return [...parentBreadcrumbs, ...ret];
}
}
return ret;
}
export function isArray(value) {
return Array.isArray(value);
}
export function toArray(value) {
return isArray(value) ? value : [value];
}

Some files were not shown because too many files have changed in this diff Show More