Compare commits

..

110 Commits

Author SHA1 Message Date
Kelsey Jackson
c3de5a8915 removed old file 2025-03-14 16:02:39 -05:00
Kelsey Jackson
c18aa23d76 merging pattern-maiin 2025-03-14 16:00:32 -05:00
Kelsey Jackson
54e14a20c0 Merge pull request #703 from shoelace-style/kj/e-commerce-patterns
Kj/e commerce patterns
2025-03-14 15:57:58 -05:00
Kelsey Jackson
97b8e96a6e Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-03-14 15:56:08 -05:00
Kelsey Jackson
55a362b741 Merge branch 'pattern-main' into kj/app-pattern 2025-03-14 15:55:45 -05:00
Kelsey Jackson
d9cafdafb7 Merge branch 'next' into pattern-main 2025-03-14 15:55:15 -05:00
Kelsey Jackson
81bf6865ec big switchover 2025-03-14 06:10:40 -05:00
lindsaym-fa
873eb47d18 Clean up utility usage and code formatting for product previews 2025-03-11 17:20:07 -04:00
lindsaym-fa
a564d3061f Clean up utility usage and code formatting for order summaries 2025-03-11 14:22:04 -04:00
Kelsey Jackson
ef865396f2 switching machines
:
2025-03-11 09:26:58 -05:00
Kelsey Jackson
903085257d removed store navigation 2025-03-07 11:12:39 -06:00
Kelsey Jackson
27237441a1 some heavy duty updates 2025-03-07 10:59:24 -06:00
Kelsey Jackson
b0291653f8 more polish 2025-03-06 22:43:13 -06:00
Kelsey Jackson
3962c50844 added review variant 2025-03-06 12:59:44 -06:00
Kelsey Jackson
314801c368 updated reviews 2025-03-05 16:40:36 -06:00
Kelsey Jackson
dc30ed8503 updated incentive images 2025-03-05 16:37:49 -06:00
lindsaym-fa
e12be798b8 Clean up utilities and formatting, replace placeholder text in order history 2025-03-04 14:30:00 -05:00
Kelsey Jackson
7f29f1b4ea started updating with style utilities 2025-03-04 13:09:41 -06:00
lindsaym-fa
3563d6a2dd Clean up utility usage and code formatting for category previews 2025-03-04 12:14:48 -05:00
Kelsey Jackson
007d93077f updated incentives 2025-03-04 11:04:31 -06:00
Kelsey Jackson
80b78aeb16 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-03-04 10:14:31 -06:00
Kelsey Jackson
8bc8ea85a5 Merge branch 'next' into pattern-main 2025-03-04 10:14:14 -06:00
Kelsey Jackson
61a6cd9fb9 updated image 2025-03-03 14:46:54 -06:00
Kelsey Jackson
7fb3fd5982 updated product preview 2025-03-03 14:22:45 -06:00
Kelsey Jackson
dc580b3351 committing to pull down changes 2025-03-03 10:38:10 -06:00
lindsaym-fa
74719d4c06 Refactor shopping cart patterns 2025-02-28 15:46:06 -05:00
Kelsey Jackson
47a7cdedd0 switching machines 2025-02-28 09:37:05 -06:00
lindsaym-fa
d906940726 Refactor product overview patterns 2025-02-27 17:04:10 -05:00
Kelsey Jackson
a782470c6a more polish 2025-02-27 11:47:56 -06:00
lindsaym-fa
de175ed4a1 Refactor product list patterns 2025-02-26 11:39:41 -05:00
lindsaym-fa
3612f8fdfa Add link style utilities 2025-02-26 11:39:11 -05:00
Kelsey Jackson
bc76df4b31 switching machines 2025-02-26 07:31:36 -06:00
lindsaym-fa
9ad7f4a6be Reorganize app patterns into separate pages 2025-02-25 12:02:29 -05:00
Kelsey Jackson
a7457630aa inital commit 2025-02-24 16:45:27 -06:00
Kelsey Jackson
e19928123f Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-02-24 11:05:08 -06:00
Kelsey Jackson
e644862f58 Merge branch 'next' into pattern-main 2025-02-24 11:04:45 -06:00
Kelsey Jackson
76529c628e committing to bring branches up to next 2025-02-24 11:04:07 -06:00
Kelsey Jackson
62ded7b15a updated order history 2025-02-21 15:27:43 -06:00
Kelsey Jackson
65af9980f1 updated content for category preview 2025-02-21 10:08:33 -06:00
Kelsey Jackson
db592194fd updtated content 2025-02-21 09:45:19 -06:00
Kelsey Jackson
0f9ea14033 unlisted links 2025-02-19 11:12:05 -06:00
Kelsey Jackson
057b76a10a created e-commerce index 2025-02-19 10:09:42 -06:00
Kelsey Jackson
b466ba9d0f Merge pull request #748 from shoelace-style/lm/ecommerce-patterns-revisions
Suggested Revisions to E-commerce Patterns
2025-02-18 13:34:45 -06:00
Kelsey Jackson
9c979931da fixed conflicts 2025-02-18 13:33:46 -06:00
Kelsey Jackson
898311590a switching branches to merge 2025-02-18 13:31:53 -06:00
Kelsey Jackson
5f4510f355 more tweaks 2025-02-18 09:56:49 -06:00
Kelsey Jackson
b8eeb3db23 a little more polish 2025-02-14 07:42:36 -06:00
lindsaym-fa
8574270340 Add checkout form example 2025-02-13 23:06:50 -05:00
lindsaym-fa
aa042a0a6e Merge branch 'kj/e-commerce-patterns' into lm/ecommerce-patterns-revisions 2025-02-13 21:53:47 -05:00
Kelsey Jackson
fe81a41a6b Merge branch 'kj/e-commerce-patterns' of github.com:shoelace-style/webawesome into kj/e-commerce-patterns 2025-02-13 15:09:27 -06:00
Kelsey Jackson
f3628ad2d8 tweaked customer review 2025-02-13 15:08:30 -06:00
lindsaym-fa
169337077d Add docs layout for patterns with stylesheet 2025-02-13 15:49:09 -05:00
lindsaym-fa
406d9a9708 Update category descriptions and headings 2025-02-13 15:47:21 -05:00
lindsaym-fa
faaf75c0a2 Add "What's a Pattern?" and "Using Patterns" to index 2025-02-13 13:22:46 -05:00
Kelsey Jackson
13b67db869 Merge branch 'kj/e-commerce-patterns' of github.com:shoelace-style/webawesome into kj/e-commerce-patterns 2025-02-13 10:35:40 -06:00
Kelsey Jackson
b7fdda4b03 cleaned up checkout form 2025-02-13 10:35:31 -06:00
lindsaym-fa
d60e675702 Reimplement checkout form revisions 2025-02-13 10:23:46 -05:00
lindsaym-fa
414a318f0b Revert checkout form changes in attempt to improve diff 2025-02-13 10:00:45 -05:00
lindsaym-fa
ff8ed89645 Merge branch 'kj/e-commerce-patterns' into lm/ecommerce-patterns-revisions 2025-02-13 09:55:45 -05:00
lindsaym-fa
e027ab1291 Fix typo in file name 2025-02-13 09:52:56 -05:00
lindsaym-fa
d8f97b15b4 Add missing file extension 2025-02-13 09:52:00 -05:00
Kelsey Jackson
a8ed6f2c19 tweaked order summary 2025-02-12 16:14:21 -06:00
Kelsey Jackson
c7f5dc69ad cleaned up shopping cart 2025-02-12 15:07:03 -06:00
lindsaym-fa
42381722c5 Re-add navigation to "Product Features" carousel 2025-02-12 15:10:42 -05:00
lindsaym-fa
b2f9ec573f Merge branch 'kj/e-commerce-patterns' into lm/ecommerce-patterns-revisions 2025-02-12 15:05:33 -05:00
lindsaym-fa
b85e59b8ca "Checkout Form" revisions 2025-02-12 15:01:29 -05:00
Kelsey Jackson
8bd69694ce tweak category preview 2025-02-12 13:28:00 -06:00
Kelsey Jackson
7672923479 tweaked order history 2025-02-12 12:05:43 -06:00
Kelsey Jackson
c94006c6aa tweaked product overview 2025-02-12 11:21:17 -06:00
Kelsey Jackson
91ce2f2271 cleaned up product list 2025-02-12 10:08:51 -06:00
lindsaym-fa
9c609e44de "Category Filters" revisions + wa-placeholder utility 2025-02-11 17:06:40 -05:00
lindsaym-fa
28a8e4250a Revisions to "Product Features" 2025-02-11 17:05:38 -05:00
Kelsey Jackson
656a38cd3d updated prouct preview 2025-02-11 11:58:52 -06:00
Kelsey Jackson
9b90e56b45 more filter work 2025-02-11 10:57:29 -06:00
Kelsey Jackson
0c84a2ff37 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-02-11 09:11:36 -06:00
Kelsey Jackson
511cca7931 Merge branch 'next' into pattern-main 2025-02-11 09:10:58 -06:00
Kelsey Jackson
2069d223f0 adding some polish 2025-02-11 09:10:18 -06:00
Kelsey Jackson
37d2455965 updated descriptions 2025-02-10 14:37:00 -06:00
Kelsey Jackson
85b05fc655 editing descriptions 2025-02-07 15:50:15 -06:00
Kelsey Jackson
52328d9805 fixing conflicts 2025-02-07 14:24:40 -06:00
Kelsey Jackson
2c89c5f510 switching machines 2025-02-07 11:42:00 -06:00
Kelsey Jackson
5ac9e8cff1 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-02-05 12:16:50 -06:00
Kelsey Jackson
e238e35b3b Merge branch 'next' into pattern-main 2025-02-05 12:16:22 -06:00
Kelsey Jackson
c6d8d37871 switching machines 2025-01-31 09:43:40 -06:00
Kelsey Jackson
4dddb183fd updated width of container 2025-01-29 13:39:51 -06:00
Kelsey Jackson
d49ed53e9a added utilities to order-summary 2025-01-29 13:33:48 -06:00
Kelsey Jackson
99e2ffc17b added utilities to order history 2025-01-29 13:06:14 -06:00
Kelsey Jackson
97c79c29b9 Merge branch 'kj/e-commerce-patterns' of github.com:shoelace-style/webawesome into kj/e-commerce-patterns 2025-01-29 12:32:10 -06:00
Kelsey Jackson
7da9f53e27 filter work 2025-01-28 15:04:03 -06:00
Kelsey Jackson
a9cc02193f updated some patterns 2025-01-27 13:30:18 -06:00
Kelsey Jackson
9ad1c8f060 updated product list patterns 2025-01-27 13:17:09 -06:00
Kelsey Jackson
e0eaea2024 upated the product detail patterns 2025-01-27 11:20:40 -06:00
Kelsey Jackson
a8b7b6a93f Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-01-23 08:56:50 -06:00
Kelsey Jackson
581e47043a Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-01-22 18:50:38 -06:00
Kelsey Jackson
9ffe0cfe3c Merge branch 'next' into pattern-main 2025-01-22 18:50:11 -06:00
Kelsey Jackson
45df4a924f commiting to switch machines 2025-01-22 14:08:14 -06:00
Kelsey Jackson
43eed9d15e Merge branch 'next' into kj/e-commerce-patterns 2025-01-22 12:30:32 -06:00
Kelsey Jackson
a0ff411463 commiting to merge in next 2025-01-22 12:27:47 -06:00
Kelsey Jackson
04cd027c7e started split image pattern: 2025-01-17 14:44:14 -06:00
Kelsey Jackson
a68a157ebc switching machines 2025-01-15 16:41:13 -06:00
Kelsey Jackson
b2a24a3b52 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-01-09 11:31:46 -06:00
Kelsey Jackson
cbb456ffda switching machines 2025-01-09 11:29:32 -06:00
Kelsey Jackson
e0038c3125 Initial Commit 2025-01-09 10:59:33 -06:00
Kelsey Jackson
3e5d3120b1 Merge branch 'next' into kj/e-commerce-patterns 2025-01-08 16:19:29 -06:00
Kelsey Jackson
020f4cbaed building out the filter 2025-01-07 11:26:29 -06:00
Kelsey Jackson
9106bb88cf fixed merge conflicts 2025-01-06 10:34:51 -06:00
Kelsey Jackson
a822ab98c8 Merge branch 'next' into kj/e-commerce-patterns 2025-01-02 11:57:42 -06:00
Kelsey Jackson
026777c085 started invoice table 2024-12-18 09:53:15 -06:00
Kelsey Jackson
6d87b9b24a Merge branch 'next' into kj/e-commerce-patterns 2024-12-17 12:23:27 -06:00
Kelsey Jackson
d5affa01e9 dividing up e-commerce patterns 2024-12-11 15:06:01 -06:00
240 changed files with 3638 additions and 6545 deletions

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:

View File

@@ -1,4 +1,3 @@
import * as path from 'node:path';
import { anchorHeadingsPlugin } from './_utils/anchor-headings.js';
import { codeExamplesPlugin } from './_utils/code-examples.js';
import { copyCodePlugin } from './_utils/copy-code.js';
@@ -7,10 +6,9 @@ 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 litPlugin from '@lit-labs/eleventy-plugin-lit';
import { readFile } from 'fs/promises';
import nunjucks from 'nunjucks';
// import componentList from './_data/componentList.js';
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';
@@ -18,10 +16,7 @@ import { searchPlugin } from './_utils/search.js';
import process from 'process';
import * as url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const packageData = JSON.parse(await readFile(path.join(__dirname, '..', 'package.json'), 'utf-8'));
const packageData = JSON.parse(await readFile('./package.json', 'utf-8'));
const isAlpha = process.argv.includes('--alpha');
const isDev = process.argv.includes('--develop');
@@ -29,28 +24,12 @@ const globalData = {
package: packageData,
isAlpha,
layout: 'page.njk',
server: {
head: '',
loginOrAvatar: '',
flashes: '',
},
};
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
const passThrough = [...passThroughExtensions.map(ext => 'docs/**/*.' + ext)];
export default function (eleventyConfig) {
/**
* If you plan to add or remove any of these extensions, make sure to let either Konnor or Cory know as these passthrough extensions
* will also need to be updated in the Web Awesome App.
*/
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
const baseDir = process.env.BASE_DIR || 'docs';
const passThrough = [...passThroughExtensions.map(ext => path.join(baseDir, '**/*.' + ext))];
/**
* This is the guard we use for now to make sure our final built files dont need a 2nd pass by the server. This keeps us able to still deploy the bare HTML files on Vercel until the app is ready.
*/
const serverBuild = process.env.WEBAWESOME_SERVER === 'true';
// NOTE - alpha setting removes certain pages
if (isAlpha) {
eleventyConfig.ignores.add('**/experimental/**');
@@ -76,38 +55,7 @@ export default function (eleventyConfig) {
// Shortcodes - {% shortCode arg1, arg2 %}
eleventyConfig.addShortcode('cdnUrl', location => {
return `https://early.webawesome.com/webawesome@${packageData.version}/dist/` + (location || '').replace(/^\//, '');
});
// Turns `{% server "foo" %} into `{{ server.foo | safe }}` when the WEBAWESOME_SERVER variable is set to "true"
eleventyConfig.addShortcode('server', function (property) {
if (serverBuild) {
return `{{ server.${property} | safe }}`;
}
return '';
});
eleventyConfig.addTransform('second-nunjucks-transform', function NunjucksTransform(content) {
// For a server build, we expect a server to run the second transform.
if (serverBuild) {
return content;
}
// Only run the transform on files nunjucks would transform.
if (!this.page.inputPath.match(/.(md|html|njk)$/)) {
return content;
}
/** This largely mimics what an app would do and just stubs out what we don't care about. */
return nunjucks.renderString(content, {
// Stub the server EJS shortcodes.
server: {
head: '',
loginOrAvatar: '',
flashes: '',
},
});
return `https://early.webawesome.com/webawesome@${packageData.version}/dist/` + location.replace(/^\//, '');
});
// Paired shortcodes - {% shortCode %}content{% endShortCode %}
@@ -169,6 +117,29 @@ export default function (eleventyConfig) {
]),
);
// 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({
@@ -195,31 +166,6 @@ export default function (eleventyConfig) {
eleventyConfig.addPassthroughCopy(glob);
}
// // SSR plugin
// // Make sure this is the last thing, we don't want to run the risk of accidentally transforming shadow roots with the nunjucks 2nd transform.
// 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];
// const componentDirectory = process.env.UNBUNDLED_DIST_DIRECTORY || path.join('.', 'dist');
// return path.join(componentDirectory, 'components', name, `${name}.js`);
// });
//
// eleventyConfig.addPlugin(litPlugin, {
// mode: 'worker',
// componentModules,
// });
// }
return {
markdownTemplateEngine: 'njk',
dir: {

View File

@@ -1,9 +0,0 @@
import { inlined } from '../../dist/components/icon/library.wa.js';
let { classic } = inlined;
let { solid, regular } = classic;
export default [
...Object.entries(solid).map(([name, svg]) => ({ name, family: 'solid', variant: 'solid', svg })),
...Object.entries(regular).map(([name, svg]) => ({ name, family: 'regular', variant: 'regular', svg })),
];

View File

@@ -1,9 +1,10 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}" class="wa-cloak">
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
{% include 'head.njk' %}
<meta name="theme-color" content="#f36944">
<script type="module" src="/assets/scripts/code-examples.js"></script>
<script type="module" src="/assets/scripts/scroll.js"></script>
<script type="module" src="/assets/scripts/turbo.js"></script>
@@ -19,7 +20,7 @@
</head>
<body class="layout-{{ layout | stripExtension }}{{ ' page-wide' if wide }}">
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
<wa-page view="desktop" disable-navigation-toggle="" mobile-breakpoint="1140">
<wa-page view="desktop" disable-navigation-toggle="">
<header slot="header" class="wa-split">
{# Logo #}
<div id="docs-branding">
@@ -32,13 +33,13 @@
<span class="wa-desktop-only">{% include "logo.njk" %}</span>
<span class="wa-mobile-only">{% include "logo-simple.njk" %}</span>
</a>
<small id="version-number" class="wa-desktop-only">{{ package.version }}</small>
<wa-badge variant="warning" appearance="filled" class="wa-desktop-only">Alpha</wa-badge>
<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" class="wa-cluster wa-gap-xs">
{# Desktop selectors #}
<div class="wa-desktop-only wa-cluster wa-gap-xs">
<div class="only-desktop wa-cluster wa-gap-xs">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
@@ -47,11 +48,8 @@
<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="wa-desktop-only">/</kbd>
<kbd slot="suffix" class="only-desktop">/</kbd>
</wa-button>
{# Login #}
{% server "loginOrAvatar" %}
</div>
</header>
@@ -78,19 +76,14 @@
</aside>
{% endif %}
{# Main #}
<main id="content">
{# Expandable outline #}
{% if hasOutline %}
<nav id="outline-expandable">
<details class="outline-links">
<summary>On this page</summary>
</details>
</nav>
{% endif %}
<div id="flashes">{% server "flashes" %}</div>
{% block header %}
{% include 'breadcrumbs.njk' %}

View File

@@ -1,11 +1,8 @@
{% set ancestors = page.url | ancestors %}
{% if ancestors.length > 0 %}
{% set breadcrumbs = page.url | breadcrumbs %}
{% if breadcrumbs.length > 0 %}
<wa-breadcrumb id="docs-breadcrumbs">
{% for ancestor in ancestors %}
{% if ancestor.page.url != "/" %}
<wa-breadcrumb-item href="{{ ancestor.page.url }}">{{ ancestor.data.title }}</wa-breadcrumb-item>
{% endif %}
{% 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>

View File

@@ -1,18 +1,12 @@
{# Cards for pages listed by category #}
<section id="grid" class="index-grid">
{% set groupedPages = allPages | groupPages(categories, page) %}
{% for category, pages in groupedPages -%}
{% if groupedPages.meta.groupCount > 1 and pages.length > 0 %}
<h2 class="index-category" id="{{ category | slugify }}">
{% if pages.meta.url %}<a href="{{ pages.meta.url }}">{{ pages.meta.title }}</a>
{% else %}
{{ pages.meta.title }}
{% endif %}
</h2>
{% endif %}
{%- for page in pages -%}
{% include "page-card.njk" %}
{%- endfor -%}
{% for category, pages in allPages | groupByTags(categories) -%}
<h2 class="index-category">{{ category | getCategoryTitle(categories) }}</h2>
{%- for page in pages -%}
{%- if not page.data.parent or listChildren -%}
{% include "page-card.njk" %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
</section>

View File

@@ -23,12 +23,10 @@
<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">
{# Internal components #}
<script type="module" src="/assets/components/scoped.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.loader.js"></script>
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<script type="module" src="/assets/scripts/theme-picker.js"></script>
{# Preset Theme #}
@@ -49,6 +47,3 @@
<link rel="stylesheet" href="/dist/styles/webawesome.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />
{# Used by Web Awesome App to inject other assets into the head. #}
{% server "head" %}

View File

@@ -2,7 +2,7 @@
<a href="{{ page.url }}"{{ page.data.keywords | attr('data-keywords') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" ignore missing %}
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">{{ page.data.title }}</span>
{% if pageSubtitle -%}

View File

@@ -1,12 +1,9 @@
{# Some collections (like "patterns") will not have any items in the alpha build for example. So this checks to make sure the collection exists. #}
{% if collections[tag] -%}
{% set groupUrl %}/docs/{{ tag }}/{% endset %}
{% set groupItem = groupUrl | getCollectionItemFromUrl %}
{% set children = groupItem.data.children if groupItem.data.children.length > 0 else (collections[tag] | sort) %}
<wa-details {{ ((tag in (tags or [])) or (groupUrl in page.url)) | attr('open') }}>
<h2 slot="summary">
{% if groupItem %}
{% if groupUrl | getCollectionItemFromUrl %}
<a href="{{ groupUrl }}" title="Overview">{{ title or (tag | capitalize) }}
<wa-icon name="grid-2"></wa-icon>
</a>
@@ -15,8 +12,10 @@
{% endif %}
</h2>
<ul>
{% for page in children %}
{% for page in collections[tag] | sort %}
{% if not page.data.parent -%}
{% include 'sidebar-link.njk' %}
{%- endif %}
{% endfor %}
</ul>
</wa-details>

View File

@@ -1,4 +1,4 @@
{% if page | show -%}
{% if not (isAlpha and page.data.noAlpha) and page.fileSlug != tag and not page.data.unlisted -%}
<li>
<a href="{{ page.url }}">{{ page.data.title }}</a>
{% if page.data.status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}

View File

@@ -1,7 +1,7 @@
{# Getting started #}
<h2>Getting Started</h2>
<ul>
<li><a href="/docs/">Installation</a></li>
<li><a href="/docs/installation">Installation</a></li>
<li><a href="/docs/usage">Usage</a></li>
<li><a href="/docs/customizing">Customizing</a></li>
<li><a href="/docs/form-controls">Form Controls</a></li>

View File

@@ -1,8 +0,0 @@
<svg width="96" height="57" viewBox="0 0 96 57" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 1H84C90.0751 1 95 5.92487 95 12V45C95 51.0751 90.0751 56 84 56H12C5.92487 56 1 51.0751 1 45V12C1 5.92487 5.92487 1 12 1Z" fill="white" stroke="#E4E5E9" stroke-width="2"/>
<rect x="7" y="39" width="50" height="11" rx="4" fill="#4895FD"/>
<rect x="7" y="8" width="41" height="5" fill="#616D8A"/>
<rect x="7" y="19.75" width="76" height="3" fill="#D9D9D9"/>
<rect x="7" y="25" width="76" height="3" fill="#D9D9D9"/>
<rect x="7" y="32" width="76" height="3" fill="#D9D9D9"/>
</svg>

Before

Width:  |  Height:  |  Size: 587 B

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,20 +1,31 @@
{% set paletteId = palette.fileSlug or page.fileSlug %}
{% set suffixes = ['-80', '', '-20'] %}
{% set width = 20 %}
{% set height = 12 %}
{% set height_core = 20 %}
{% set gap_x = 4 %}
{% set gap_y = 4 %}
<wa-scoped class="palette-icon-host">
<template>
<link rel="stylesheet" href="/dist/styles/color/{{ paletteId }}.css">
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
{% set total_width = (width + gap_x) * hues|length %}
{% set total_height = (height + gap_y) * suffixes|length + (height_core - height) %}
<svg viewBox="0 0 {{ total_width }} {{ total_height }}" fill="none" xmlns="http://www.w3.org/2000/svg" class="wa-palette-{{ paletteId }} palette-icon">
<style>
@import url('/dist/styles/color/{{ paletteId }}.css') layer(palette.{{ paletteId }});
.palette-icon {
height: 8ch;
}
</style>
<div class="palette-icon" style="--hues: {{ hues|length }}; --suffixes: {{ suffixes|length }}">
{% for hue in hues -%}
{% set hueIndex = loop.index %}
{% for suffix in suffixes -%}
<div class="swatch"
data-hue="{{ hue }}" data-suffix="{{ suffix }}"
style="--color: var(--wa-color-{{ hue }}{{ suffix }}); grid-column: {{ hueIndex }}; grid-row: {{ loop.index }}">&nbsp;</div>
{%- endfor %}
{%- endfor %}
</div>
</template>
</wa-scoped>
{% for hue in hues -%}
{% set hueIndex = loop.index0 %}
{% set y = 0 %}
{% for suffix in suffixes -%}
{% set swatch_height = height if suffix else height_core %}
<rect x="{{ hueIndex * (width + gap_x) }}" y="{{ y }}"
width="{{ width }}" height="{{ swatch_height }}"
fill="var(--wa-color-{{ hue }}{{ suffix }})" rx="2" />
{% set y = y + swatch_height + gap_y %}
{%- endfor %}
{% endfor %}
</svg>

View File

@@ -1,13 +1,13 @@
{% set themeId = theme.fileSlug %}
<wa-scoped class="theme-icon-host theme-color-icon-host">
<template>
<div>
<template shadowrootmode="open">
<link rel="stylesheet" href="/dist/styles/utilities.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ page.fileSlug or 'default' }}.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}/color.css">
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
<div class="theme-icon theme-color-icon wa-theme-{{ themeId }}">
<div class="theme-color-icon wa-theme-{{ themeId }}">
<div class="wa-brand wa-accent">A</div>
<div class="wa-brand wa-outlined">A</div>
<div class="wa-brand wa-filled">A</div>
@@ -21,4 +21,4 @@
{# <div class="wa-warning wa-outlined wa-filled"><wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon></div> #}
</div>
</template>
</wa-scoped>
</div>

View File

@@ -1,16 +1,16 @@
{% set themeId = theme.fileSlug or page.fileSlug %}
{% set themeId = theme.fileSlug %}
<wa-scoped class="theme-icon-host theme-typography-icon-host">
<template>
<div>
<template shadowrootmode="open">
<link rel="stylesheet" href="/dist/styles/native/content.css">
<link rel="stylesheet" href="/dist/styles/native/blockquote.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ page.fileSlug or 'default' }}.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}/typography.css">
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
<div class="theme-icon theme-typography-icon wa-theme-{{ themeId }}" data-no-outline data-no-anchor role="presentation">
<div class="theme-typography-icon wa-theme-{{ themeId }}" data-no-outline data-no-anchor role="presentation">
<h3>Title</h3>
<p>Body text</p>
</div>
</template>
</wa-scoped>
</div>

View File

@@ -1,29 +0,0 @@
{% set themeId = theme.fileSlug or page.fileSlug %}
<wa-scoped class="theme-icon-host theme-overall-icon-host">
<template>
<link rel="stylesheet" href="/dist/styles/utilities.css">
<link rel="stylesheet" href="/dist/styles/native/content.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}.css">
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
<div class="theme-icon theme-overall-icon" role="presentation" data-no-anchor data-no-outline>
<div class="row row-1">
<h2>Aa</h2>
<div class="swatches">
<div class="wa-brand"></div>
<div class="wa-success"></div>
<div class="wa-warning"></div>
<div class="wa-danger"></div>
<div class="wa-neutral"></div>
</div>
</div>
<div class="row row-2">
<wa-input value="Input" size="small" inert></wa-input>
<wa-button size="small" variant="brand" inert>Go</wa-button>
</div>
</div>
</template>
</wa-scoped>

View File

@@ -255,7 +255,7 @@
{# 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/installation/#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.
</p>
<wa-tab-group label="How would you like to import this component?">

View File

@@ -1,5 +1,6 @@
---
layout: page-outline
tags: ["overview"]
---
{% set forTag = forTag or (page.url | split('/') | last) %}
{% if description %}
@@ -12,10 +13,8 @@ layout: page-outline
</wa-input>
</div>
{% set allPages = allPages or collections[forTag] %}
{% if allPages and allPages.length > 0 %}
{% set allPages = collections[forTag] %}
{% include "grouped-pages.njk" %}
{% endif %}
<link href="/assets/styles/filter.css" rel="stylesheet">
<script type="module" src="/assets/scripts/filter.js"></script>

View File

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

View File

@@ -30,21 +30,12 @@
{% include 'breadcrumbs.njk' %}
<h1 class="title">
<span v-content="title">{{ title }}</span>
<template v-if="saved || tweaked">
<wa-icon-button name="pencil" label="Rename palette" @click="rename"></wa-icon-button>
<wa-icon-button v-if="saved" class="delete" name="trash" label="Delete palette" @click="deleteSaved"></wa-icon-button>
<wa-button @click="save()" :disabled="!unsavedChanges"
:variant="unsavedChanges ? 'success' : 'neutral'" size="small" :appearance="unsavedChanges ? 'accent' : 'outlined'">
<span slot="prefix" class="icon-modifier">
<wa-icon name="sidebar" variant="regular"></wa-icon>
<wa-icon name="circle-plus" class="modifier" style="color: light-dark(var(--wa-color-green-70), var(--wa-color-green-60));"></wa-icon>
</span>
<span v-content="unsavedChanges ? 'Save' : 'Saved'">Save</span>
</wa-button>
</template>
<h1 v-if="saved" class="title">
{% raw %}{{ saved.title }}{% endraw %}
<wa-icon-button name="pencil" label="Rename palette" @click="rename"></wa-icon-button>
<wa-icon-button class="delete" name="trash" label="Delete palette" @click="deleteSaved"></wa-icon-button>
</h1>
<h1 v-if="!saved" class="title">{{ title }}</h1>
<div class="block-info">
<code class="class">.wa-palette-{{ paletteId }}</code>
@@ -68,7 +59,7 @@
<wa-icon name="sliders-simple" slot="icon" variant="regular"></wa-icon>
This palette has been tweaked.
<div class="wa-cluster wa-gap-xs">
<wa-tag v-for="tweakHumanReadable, param in tweaksHumanReadable" removable @wa-remove="reset(param)" v-content="tweakHumanReadable"></wa-tag>
<wa-tag v-for="tweakHumanReadable, param in tweaksHumanReadable" removable @wa-remove="reset(param)">{% raw %}{{ tweakHumanReadable }}{% endraw %}</wa-tag>
</div>
<wa-button @click="reset()" appearance="outlined" variant="danger">
@@ -77,6 +68,13 @@
</span>
Reset
</wa-button>
<wa-button v-if="!saved" @click="save" variant="success">
<span slot="prefix" class="icon-modifier">
<wa-icon name="sidebar" variant="regular"></wa-icon>
<wa-icon name="circle-plus" class="modifier" style="color: light-dark(var(--wa-color-green-70), var(--wa-color-green-60));"></wa-icon>
</span>
Save
</wa-button>
</wa-callout>
<table class="colors main wa-palette-{{ paletteId }}">
@@ -126,7 +124,7 @@
{% for h in hues -%}
{%- if h !== 'gray' -%}
<wa-radio-button id="gray-undertone-{{ h }}" value="{{ h }}" label="{{ h | capitalize }}" style="--color: var(--wa-color-{{ h }})"></wa-radio-button>
<wa-tooltip for="gray-undertone-{{ h }}">
<wa-tooltip for="gray-undertone-{{ h }}" hoist>
{{ h | capitalize }}
</wa-tooltip>
{%- endif -%}
@@ -141,7 +139,7 @@
@input="tweaking.grayChroma = true" @change="tweaking.grayChroma = false">
<div slot="label">
Gray colorfulness
<wa-icon-button @click="grayChroma = originalGrayChroma" class="clear-button" name="system:circle-xmark" variant="regular" label="Reset"></wa-icon-button>
<wa-icon-button @click="grayChroma = originalGrayChroma" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
</div>
</wa-slider>
<div class="label-min">Neutral</div>
@@ -160,7 +158,7 @@
@change="tweaking.hue = tweaking.{{ hue }} = false">
<div slot="label">
Tweak {{ hue }} hue
<wa-icon-button @click="hueShifts.{{ hue }} = 0" class="clear-button" name="system:circle-xmark" variant="regular" label="Reset"></wa-icon-button>
<wa-icon-button @click="hueShifts.{{ hue }} = 0" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
</div>
</wa-slider>
<div class="label-min">More {{hueBefore}}</div>
@@ -204,7 +202,7 @@ style="--min: {{ chromaScaleBounds[0] }}; --max: {{ chromaScaleBounds[1] }};">
@change="tweaking.chroma = false">
<div slot="label">
Overall colorfulness
<wa-icon-button @click="chromaScale = 1" class="clear-button" name="system:circle-xmark" variant="regular" label="Reset"></wa-icon-button>
<wa-icon-button @click="chromaScale = 1" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
</div>
</wa-slider>
<div class="label-min">More muted</div>

View File

@@ -1,5 +1,5 @@
{% extends '../_layouts/block.njk' %}
{% block head %}
<link href="/docs/patterns/patterns.css" rel="stylesheet">
<link href="{{ page.url }}../patterns.css" rel="stylesheet">
{% endblock %}

View File

@@ -25,8 +25,8 @@ wa_data.palettes = {
{% endfor %}
};
</script>
<link href="/docs/themes/remix.css" rel="stylesheet">
<script src="/docs/themes/remix.js" type="module"></script>
<link href="{{ page.url }}../remix.css" rel="stylesheet">
<script src="{{ page.url }}../remix.js" type="module"></script>
{% endblock %}
{% block header %}
@@ -68,7 +68,7 @@ wa_data.palettes = {
<wa-option label="{{ palette.data.title }}" value="{{ palette.fileSlug if not currentPalette }}" {{ (palette.fileSlug if currentPalette) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/" + (palette.data.icon or "thumbnail-placeholder") + ".njk" ignore missing %}
{% include "svgs/" + (palette.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">
{{ palette.data.title }}

View File

@@ -102,7 +102,12 @@ const templates = {
export function codeExamplesPlugin(eleventyConfig, options = {}) {
const defaultOptions = {
container: 'body',
defaultOpen: () => false,
defaultOpen: (code, { outputPathIndex }) => {
return (
outputPathIndex === 1 && // is first
code.textContent.length < 500
); // is short
},
};
options = { ...defaultOptions, ...options };

View File

@@ -33,7 +33,7 @@ export function copyCodePlugin(eleventyConfig, options = {}) {
// Add a copy button
pre.innerHTML += `<wa-icon-button href="#${preId}" class="block-link-icon" name="link"></wa-icon-button>
<wa-copy-button from="${codeId}" class="copy-button"></wa-copy-button>`;
<wa-copy-button from="${codeId}" class="copy-button" hoist></wa-copy-button>`;
});
return doc.toString();

View File

@@ -29,9 +29,6 @@ function getCollection(name) {
}
export function getCollectionItemFromUrl(url, collection) {
if (!url) {
return null;
}
collection ??= getCollection.call(this, 'all') || [];
return collection.find(item => item.url === url);
}
@@ -45,33 +42,35 @@ export function split(text, separator) {
return (text + '').split(separator).filter(Boolean);
}
export function ancestors(url, { withCurrent = false, withRoot = false } = {}) {
let ret = [];
let currentUrl = url;
let currentItem = getCollectionItemFromUrl.call(this, url);
export function breadcrumbs(url, { withCurrent = false } = {}) {
const parts = split(url, '/');
const ret = [];
if (!currentItem) {
// Might have eleventyExcludeFromCollections, jump to parent
let parentUrl = this.ctx.parentUrl;
if (parentUrl) {
url = parentUrl;
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];
}
}
for (let item; (item = getCollectionItemFromUrl.call(this, url)); url = item.data.parentUrl) {
ret.unshift(item);
}
if (!withRoot && ret[0]?.page.url === '/') {
// Remove root
ret.shift();
}
if (!withCurrent && ret.at(-1)?.page.url === currentUrl) {
// Remove current page
ret.pop();
}
return ret;
}
@@ -178,196 +177,72 @@ export function sort(arr, by = { 'data.order': 1, 'data.title': '' }) {
});
}
export function show(page) {
return !(page.data.noAlpha && page.data.isAlpha) && !page.data.unlisted;
}
/**
* Group an 11ty collection (or any array of objects with a `data.tags` property) by certain tags.
* @param {object[]} collection
* @param { Object<string, string> | string[]} [options] Options object or array of tags to group by.
* @param {string[] | true} [options.tags] Tags to group by. If true, groups by all tags.
* If not provided/empty, defaults to grouping by page hierarchy, with any pages with more than 1 children becoming groups.
* @param {string[]} [options.groups] The groups to use if only a subset or a specific order is desired. Defaults to `options.tags`.
* @param {string[]} [options.titles] Any title overrides for groups.
* @param {string | false} [options.other="Other"] The title to use for the "Other" group. If `false`, the "Other" group is removed..
* @returns { Object.<string, object[]> } An object of group ids to arrays of page objects.
* @param { Object<string, string> | (string | Object<string, string>)[]} [tags] The tags to group by. If not provided/empty, defaults to grouping by all tags.
* @returns { Object.<string, object[]> } An object with keys for each tag, and an array of items for each tag.
*/
export function groupPages(collection, options = {}, page) {
export function groupByTags(collection, tags) {
if (!collection) {
console.error(`Empty collection passed to groupPages() to group by ${JSON.stringify(options)}`);
console.error(`Empty collection passed to groupByTags() to group by ${JSON.stringify(tags)}`);
}
if (!tags) {
// Default to grouping by union of all tags
tags = Array.from(new Set(collection.flatMap(item => item.data.tags)));
} else if (Array.isArray(tags)) {
// May contain objects of one-off tag -> label mappings
tags = tags.map(tag => (typeof tag === 'object' ? Object.keys(tag)[0] : tag));
} else if (typeof tags === 'object') {
// tags is an object of tags to labels, so we just want the keys
tags = Object.keys(tags);
}
if (Array.isArray(options)) {
options = { tags: options };
}
let { tags, groups, titles = {}, other = 'Other', filter = show } = options;
if (groups === undefined && Array.isArray(tags)) {
groups = tags;
}
let grouping;
if (tags) {
grouping = {
isGroup: item => undefined,
getCandidateGroups: item => item.data.tags,
getGroupMeta: group => ({}),
};
} else {
grouping = {
isGroup: item => (item.data.children.length >= 2 ? item.page.url : undefined),
getCandidateGroups: item => {
let parentUrl = item.data.parentUrl;
if (page?.url === parentUrl) {
return [];
}
return [parentUrl];
},
getGroupMeta: group => {
let item = byUrl[group] || getCollectionItemFromUrl.call(this, group);
return {
title: item?.data.title,
url: group,
item,
};
},
sortGroups: groups => sort(groups.map(url => byUrl[url]).filter(Boolean)).map(item => item.page.url),
};
}
let byUrl = {};
let byParentUrl = {};
if (filter) {
collection = collection.filter(filter);
}
let ret = Object.fromEntries(tags.map(tag => [tag, []]));
ret.other = [];
for (let item of collection) {
let url = item.page.url;
let parentUrl = item.data.parentUrl;
let categorized = false;
byUrl[url] = item;
if (parentUrl) {
byParentUrl[parentUrl] ??= [];
byParentUrl[parentUrl].push(item);
}
}
let urlToGroups = {};
for (let item of collection) {
let url = item.page.url;
let parentUrl = item.data.parentUrl;
if (grouping.isGroup(item)) {
continue;
}
let parentItem = byUrl[parentUrl];
if (parentItem && !grouping.isGroup(parentItem)) {
// Their parent is also here and is not a group
continue;
}
let candidateGroups = grouping.getCandidateGroups(item);
if (groups) {
candidateGroups = candidateGroups.filter(group => groups.includes(group));
}
urlToGroups[url] ??= [];
for (let group of candidateGroups) {
urlToGroups[url].push(group);
}
}
let ret = {};
for (let url in urlToGroups) {
let groups = urlToGroups[url];
let item = byUrl[url];
if (groups.length === 0) {
// Not filtered out but also not categorized
groups = ['other'];
}
for (let group of groups) {
ret[group] ??= [];
ret[group].push(item);
if (!ret[group].meta) {
if (group === 'other') {
ret[group].meta = { title: other };
} else {
ret[group].meta = grouping.getGroupMeta(group);
ret[group].meta.title = titles[group] ?? ret[group].meta.title ?? capitalize(group);
}
for (let tag of tags) {
if (item.data.tags.includes(tag)) {
ret[tag].push(item);
categorized = true;
}
}
}
if (other === false) {
delete ret.other;
}
// Sort
let sortedGroups = groups ?? grouping.sortGroups?.(Object.keys(ret));
if (sortedGroups) {
ret = sortObject(ret, sortedGroups);
} else {
// At least make sure other is last
if (ret.other) {
let otherGroup = ret.other;
delete ret.other;
ret.other = otherGroup;
if (!categorized) {
ret.other.push(item);
}
}
Object.defineProperty(ret, 'meta', {
value: {
groupCount: Object.keys(ret).length,
},
enumerable: false,
});
return ret;
}
/**
* Sort an object by its keys
* @param {*} obj
* @param {function | string[]} order
*/
function sortObject(obj, order) {
let ret = {};
let sortedKeys = Array.isArray(order) ? order : Object.keys(obj).sort(order);
for (let key of sortedKeys) {
if (key in obj) {
ret[key] = obj[key];
}
}
// Add any keys that weren't in the order
for (let key in obj) {
if (!(key in ret)) {
ret[key] = obj[key];
// Remove empty categories
for (let category in ret) {
if (ret[category].length === 0) {
delete ret[category];
}
}
return ret;
}
function capitalize(str) {
str += '';
return str.charAt(0).toUpperCase() + str.slice(1);
export function getCategoryTitle(category, categories) {
let title;
if (Array.isArray(categories)) {
// Find relevant entry
// [{id: "Title"}, id2, ...]
title = categories.find(entry => typeof entry === 'object' && entry?.[category])?.[category];
} else if (typeof categories === 'object') {
// {id: "Title", id2: "Title 2", ...}
title = categories[category];
}
if (title) {
return title;
}
// Capitalized
return category.charAt(0).toUpperCase() + category.slice(1);
}
const IDENTITY = x => x;

View File

@@ -39,7 +39,7 @@ export function outlinePlugin(options = {}) {
}
// Create a clone of the heading so we can remove links and [data-no-outline] elements from the text content
clone.querySelectorAll('.wa-visually-hidden, [hidden], [aria-hidden="true"]').forEach(el => el.remove());
clone.querySelectorAll('a').forEach(a => a.remove());
clone.querySelectorAll('[data-no-outline]').forEach(el => el.remove());
// Generate the link

View File

@@ -2,7 +2,6 @@
import { mkdir, writeFile } from 'fs/promises';
import lunr from 'lunr';
import { parse } from 'node-html-parser';
import * as path from 'path';
import { dirname, join } from 'path';
function collapseWhitespace(string) {
@@ -53,9 +52,8 @@ export function searchPlugin(options = {}) {
return content;
});
eleventyConfig.on('eleventy.after', ({ directories }) => {
const { output } = directories;
const outputFilename = path.resolve(join(output, 'search.json'));
eleventyConfig.on('eleventy.after', ({ dir }) => {
const outputFilename = join(dir.output, 'search.json');
const map = [];
const searchIndex = lunr(async function () {
let index = 0;

View File

@@ -1,171 +0,0 @@
/**
* Low-level utility to encapsulate a bit of HTML (mainly to apply certain stylesheets to it without them leaking to the rest of the page)
* Usage: <wa-scoped><template><!-- your HTML here --></template></wa-scoped>
*/
import { discover } from '/dist/webawesome.js';
const imports = new Set();
const fontFaceRules = new Set();
export default class WaScoped extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.observer = new MutationObserver(() => this.render());
this.observer.observe(this, { childList: true, subtree: true, characterData: true });
}
connectedCallback() {
this.render();
this.ownerDocument.documentElement.addEventListener('wa-color-scheme-change', e =>
this.#applyDarkMode(e.detail.dark),
);
}
render() {
this.observer.takeRecords();
this.observer.disconnect();
this.shadowRoot.innerHTML = '';
// To avoid mutating this.childNodes while iterating over it
let nodes = [];
for (let template of this.childNodes) {
// Other solutions we can try if needed: <script type="text/html">, or comment nodes
if (template instanceof HTMLTemplateElement) {
if (template.content.childNodes.length > 0) {
nodes.push(template.content.cloneNode(true));
} else if (template.childNodes.length > 0) {
// Fake template, suck its children out of the light DOM
nodes.push(...template.childNodes);
}
} else {
// Regular child, suck it out of the light DOM
nodes.push(template);
}
}
this.shadowRoot.append(...nodes);
this.#fixStyles();
this.#applyDarkMode();
discover(this.shadowRoot);
this.observer.observe(this, { childList: true, subtree: true, characterData: true });
}
#applyDarkMode(isDark = getComputedStyle(this).colorScheme === 'dark') {
// Hack to make dark mode work
// NOTE If any child nodes actually have .wa-dark, this will override it
for (let node of this.shadowRoot.children) {
node.classList.toggle('wa-dark', isDark);
}
this.classList.toggle('wa-dark', isDark);
}
/**
* @font-face does not work in shadow DOM in Chrome & FF, as of March 2025 https://issues.chromium.org/issues/41085401
* This works around this issue by traversing the shadow DOM CSS looking
* for @font-face rules or CSS imports to known font providers and copies them to the main document
*/
async #fixStyles() {
let styleElements = [...this.shadowRoot.querySelectorAll('link[rel="stylesheet"], style')];
let loadStates = styleElements.map(element => {
try {
if (element.sheet?.cssRules) {
// Already loaded
return Promise.resolve(element.sheet);
}
} catch (e) {
// CORS
return Promise.resolve(null);
}
return new Promise((resolve, reject) => {
element.addEventListener('load', e => resolve(element.sheet));
element.addEventListener('error', e => reject(null));
});
});
await Promise.allSettled(loadStates);
let fontRules = findFontFaceRules(...this.shadowRoot.styleSheets);
if (!fontRules.length) {
return;
}
let doc = this.ownerDocument;
// Why not adoptedStyleSheets? Can't have @import in those yet
let id = `wa-scoped-hoisted-fonts`;
let style = doc.head.querySelector('style#' + id);
if (!style) {
style = Object.assign(doc.createElement('style'), { id, textContent: ' ' });
doc.head.append(style);
}
let sheet = style.sheet;
for (let rule of fontRules) {
let cssText = rule.cssText;
if (rule.type === CSSRule.FONT_FACE_RULE) {
if (fontFaceRules.has(cssText)) {
continue;
}
fontFaceRules.add(cssText);
sheet.insertRule(cssText);
} else if (rule.type === CSSRule.IMPORT_RULE) {
if (imports.has(rule.href)) {
continue;
}
imports.add(rule.href);
sheet.insertRule(cssText, 0);
}
}
}
static observedAttributes = [];
}
customElements.define('wa-scoped', WaScoped);
export const WEB_FONT_HOSTS = [
'fonts.googleapis.com',
'fonts.gstatic.com',
'use.typekit.net',
'fonts.adobe.com',
'kit.fontawesome.com',
'pro.fontawesome.com',
'cdn.materialdesignicons.com',
];
function findFontFaceRules(...stylesheets) {
let ret = [];
for (let sheet of stylesheets) {
let rules;
try {
rules = sheet.cssRules;
} catch (e) {
// CORS
continue;
}
for (let rule of rules) {
if (rule.type === CSSRule.FONT_FACE_RULE) {
ret.push(rule);
} else if (rule.type === CSSRule.IMPORT_RULE) {
if (WEB_FONT_HOSTS.some(host => rule.href.includes(host))) {
ret.push(rule);
} else if (rule.styleSheet) {
ret.push(...findFontFaceRules(rule.styleSheet));
}
}
}
}
return ret;
}

View File

@@ -0,0 +1,59 @@
document.addEventListener('click', event => {
const toggle = event.target?.closest('.code-example-toggle');
const pen = event.target?.closest('.code-example-pen');
// Toggle source
if (toggle) {
const codeExample = toggle.closest('.code-example');
const isOpen = !codeExample.classList.contains('open');
toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
codeExample.classList.toggle('open', isOpen);
}
// Edit in CodePen
if (pen) {
const codeExample = pen.closest('.code-example');
const code = codeExample.querySelector('code');
const cdnUrl = document.documentElement.dataset.cdnUrl;
const html =
`<script type="module" src="${cdnUrl}webawesome.loader.js"></script>\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/themes/default.css">\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/webawesome.css">\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/utilities.css">\n\n` +
`${code.textContent}`;
const css = 'html > body {\n padding: 2rem !important;\n}';
const js = '';
const form = document.createElement('form');
form.action = 'https://codepen.io/pen/define';
form.method = 'POST';
form.target = '_blank';
const data = {
title: '',
description: '',
tags: ['webawesome'],
editors: '1000',
head: '<meta name="viewport" content="width=device-width">',
html_classes: '',
css_external: '',
js_external: '',
js_module: true,
js_pre_processor: 'none',
html,
css,
js,
};
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'data';
input.value = JSON.stringify(data);
form.append(input);
document.documentElement.append(form);
form.submit();
form.remove();
}
});

View File

@@ -1,11 +1,3 @@
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
function updateResults(input) {
const filter = input.value.toLowerCase().trim();
let filtered = Boolean(filter);
@@ -26,10 +18,8 @@ function updateResults(input) {
}
}
const debouncedUpdateResults = debounce(updateResults, 300);
document.documentElement.addEventListener('input', e => {
if (e.target?.matches('#block-filter wa-input')) {
debouncedUpdateResults(e.target);
updateResults(e.target);
}
});

View File

@@ -1,167 +0,0 @@
const my = (globalThis.my = new EventTarget());
export default my;
class PersistedArray extends Array {
constructor(key) {
super();
this.key = key;
if (this.key) {
this.fromLocalStorage();
}
// Items were updated in another tab
addEventListener('storage', event => {
if (event.key === this.key || !event.key) {
this.fromLocalStorage();
}
});
}
/**
* Update data from local storage
*/
fromLocalStorage() {
// First, empty the array
this.splice(0, this.length);
// Then, fill it with the data from local storage
let saved = localStorage[this.key] ? JSON.parse(localStorage[this.key]) : null;
if (saved) {
this.push(...saved);
}
}
/**
* Write data to local storage
*/
toLocalStorage() {
if (this.length > 0) {
localStorage[this.key] = JSON.stringify(this);
} else {
delete localStorage[this.key];
}
}
}
class SavedEntities extends EventTarget {
constructor({ key, type, url }) {
super();
this.key = key;
this.type = type;
this.url = url ?? type + 's';
this.saved = new PersistedArray(key);
let all = this;
this.entityPrototype = {
type: this.type,
baseUrl: this.baseUrl,
get url() {
return all.getURL(this);
},
get parentUrl() {
return all.getParentURL(this);
},
delete() {
all.delete(this);
},
};
}
getUid() {
if (this.saved.length === 0) {
return 1;
}
let uids = new Set(this.saved.map(p => p.uid));
// Find first available number
for (let i = 1; i <= this.saved.length + 1; i++) {
if (!uids.has(i)) {
return i;
}
}
}
get baseUrl() {
return `/docs/${this.url}/`;
}
getURL(entity) {
return this.getParentURL(entity) + entity.search;
}
getParentURL(entity) {
return this.baseUrl + entity.id + '/';
}
getObject(entity) {
let ret = Object.create(this.entityPrototype, Object.getOwnPropertyDescriptors(entity));
// debugger;
return ret;
}
/**
* Save an entity, either by updating its existing entry or creating a new one
* @param {object} entity
*/
save(entity) {
if (!entity.uid) {
// First time saving
entity.uid = this.getUid();
}
let savedPalettes = this.saved;
let existingIndex = entity.uid ? this.saved.findIndex(p => p.uid === entity.uid) : -1;
let newIndex = existingIndex > -1 ? existingIndex : savedPalettes.length;
this.saved.splice(newIndex, 1, entity);
this.saved.toLocalStorage();
this.dispatchEvent(new CustomEvent('save', { detail: this.getObject(entity) }));
return entity;
}
delete(entity) {
let count = this.saved.length;
if (count === 0 || !entity?.uid) {
// No stored entities or this entity has not been saved
return;
}
// TODO improve UX of this
if (!confirm(`Are you sure you want to delete ${this.type}${entity.title}”?`)) {
return;
}
for (let index; (index = this.saved.findIndex(p => p.uid === entity.uid)) > -1; ) {
this.saved.splice(index, 1);
}
if (this.saved.length === count) {
// Nothing was removed
return;
}
this.saved.toLocalStorage();
this.dispatchEvent(new CustomEvent('delete', { detail: this.getObject(entity) }));
}
dispatchEvent(event) {
super.dispatchEvent(event);
my.dispatchEvent(event);
}
}
my.palettes = new SavedEntities({
key: 'savedPalettes',
type: 'palette',
});

View File

@@ -1,119 +1,254 @@
import my from '/assets/scripts/my.js';
const sidebar = (globalThis.sidebar = {});
const sidebar = {
addChild(a, parentA) {
let parentLi = parentA.closest('li');
let ul = parentLi.querySelector(':scope > ul');
ul ??= parentLi.appendChild(document.createElement('ul'));
let li = document.createElement('li');
li.append(a);
ul.appendChild(li);
// If we are on the same page, update the current link
let url = location.href.replace(/#.+$/, '');
if (url.startsWith(a.href)) {
// Remove existing current
for (let current of document.querySelectorAll('#sidebar a.current')) {
current.classList.remove('current');
}
a.classList.add('current');
}
return a;
},
removeLink(a) {
if (!a || !a.isConnected) {
// Link doesn't exist or is already removed
sidebar.palettes = {
render() {
if (this.saved.length === 0) {
return;
}
let li = a?.closest('li');
let ul = li?.closest('ul');
let parentA = ul?.closest('li')?.querySelector(':scope > a');
li?.remove();
if (ul?.children.length === 0) {
ul.remove();
for (let palette of this.saved) {
sidebar.palette.render(palette);
}
if (a.classList.contains('current')) {
// If the deleted palette was the current one, the current one is now the parent
parentA.classList.add('current');
}
sidebar.updateCurrent();
},
findEntity(entity) {
return document.querySelector(`#sidebar a[href^="${entity.baseUrl}"][data-uid="${entity.uid}"]`);
updateSaved() {
this.saved = localStorage.savedPalettes ? JSON.parse(localStorage.savedPalettes) : [];
},
renderEntity(entity) {
let { url, parentUrl } = entity;
save(saved = this.saved) {
this.saved = saved ?? [];
// Find parent
let parentA = document.querySelector(`#sidebar a[href="${parentUrl}"]`);
let parentLi = parentA?.closest('li');
if (!parentLi) {
throw new Error(`Cannot find parent url ${parentUrl}`);
}
// Find existing
let a = this.findEntity(entity);
let alreadyExisted = !!a;
a ??= document.createElement('a');
a.textContent = entity.title;
a.href = url;
if (!alreadyExisted) {
a.dataset.uid = entity.uid;
a = sidebar.addChild(a, parentA);
// This is mainly to port Pro badges
let badges = Array.from(parentLi.querySelectorAll('wa-badge'), badge => badge.cloneNode(true));
let append = [...badges];
if (entity.delete) {
let deleteButton = Object.assign(document.createElement('wa-icon-button'), {
name: 'trash',
label: 'Delete',
className: 'delete',
});
deleteButton.addEventListener('click', () => entity.delete());
append.push(deleteButton);
}
if (append.length > 0) {
a.closest('li').append(' ', ...append);
}
}
},
render() {
for (let type in my) {
let controller = my[type];
if (!controller.saved) {
continue;
}
for (let entity of controller.saved) {
let object = controller.getObject(entity);
this.renderEntity(object);
}
if (saved.length > 0) {
localStorage.savedPalettes = JSON.stringify(saved);
} else {
delete localStorage.savedPalettes;
}
},
};
globalThis.sidebar = sidebar;
sidebar.palettes.updateSaved();
addEventListener('storage', event => sidebar.palettes.updateSaved());
// Update sidebar when my saved stuff changes
my.addEventListener('delete', e => sidebar.removeLink(sidebar.findEntity(e.detail)));
my.addEventListener('save', e => sidebar.renderEntity(e.detail));
sidebar.palette = {
getUid() {
let savedPalettes = sidebar.palettes.saved;
let uids = new Set(savedPalettes.map(p => p.uid));
if (savedPalettes.length === 0) {
return 1;
}
// Find first available number
for (let i = 1; i <= savedPalettes.length + 1; i++) {
if (!uids.has(i)) {
return i;
}
}
},
equals(p1, p2) {
if (!p1 || !p2) {
return false;
}
return p1.id === p2.id && p1.uid === p2.uid;
},
delete(palette) {
let savedPalettes = sidebar.palettes.saved;
let count = savedPalettes.length;
if (count === 0) {
return;
}
// TODO improve UX of this
if (!confirm(`Are you sure you want to delete palette “${palette.title}”?`)) {
return;
}
savedPalettes = savedPalettes.filter(p => !sidebar.palette.equals(palette, p));
if (savedPalettes.length === count) {
// Nothing was removed
return;
}
// Update UI
let pathname = `/docs/palettes/${palette.id}/`;
let url = pathname + palette.search;
let uls = new Set();
for (let a of document.querySelectorAll(`#sidebar a[href="${url}"]`)) {
let li = a.closest('li');
let ul = li.closest('ul');
uls.add(ul);
li.remove();
}
// Remove empty lists
for (let ul of uls) {
if (!ul.children.length) {
ul.remove();
}
}
sidebar.updateCurrent();
sidebar.palettes.save(savedPalettes);
if (sidebar.palette.equals(globalThis.paletteApp?.saved, palette)) {
paletteApp.postDelete();
}
},
getSaved(palette, savedPalettes = sidebar.palettes.saved) {
return savedPalettes.find(p => sidebar.palette.equals(p, palette));
},
render(palette) {
// Find existing <a>
let { title, id, search, uid } = palette;
for (let a of document.querySelectorAll(`#sidebar a[href^="/docs/palettes/${id}/"][data-uid="${uid}"]`)) {
// Palette already in sidebar, just update it
a.textContent = palette.title;
a.href = `/docs/palettes/${id}/${search}`;
return;
}
let pathname = `/docs/palettes/${id}/`;
let url = pathname + search;
let parentA = document.querySelector(`a[href="${pathname}"]`);
let parentLi = parentA?.closest('li');
let a;
if (parentLi) {
a = Object.assign(document.createElement('a'), { href: url, textContent: title });
a.dataset.uid = uid;
let badges = [...parentLi.querySelectorAll('wa-badge')].map(badge => badge.cloneNode(true));
let ul = parentLi.querySelector('ul') ?? parentLi.appendChild(document.createElement('ul'));
let li = document.createElement('li');
let deleteButton = Object.assign(document.createElement('wa-icon-button'), {
name: 'trash',
label: 'Delete',
className: 'delete',
});
deleteButton.addEventListener('click', () => {
let palette = { id, uid, title: a.textContent, search: a.search };
sidebar.palette.delete(palette);
});
li.append(a, ' ', ...badges, deleteButton);
ul.appendChild(li);
}
},
save(palette, saved) {
let savedPalettes = sidebar.palettes.saved;
let existing = this.getSaved(saved ?? palette, savedPalettes);
let oldValues;
if (existing) {
// Rename
oldValues = { ...existing };
Object.assign(existing, palette);
} else {
savedPalettes.push(palette);
}
this.render(palette, oldValues);
sidebar.updateCurrent();
sidebar.palettes.save(savedPalettes);
},
};
sidebar.updateCurrent = function () {
// Find the sidebar link with the longest shared prefix with the current URL
let pathParts = location.pathname.split('/').filter(Boolean);
let prefixes = [];
if (pathParts.length === 1) {
// If at /docs/ we just use that, otherwise we want at least two parts (/docs/xxx/)
prefixes.push('/' + pathParts[0] + '/');
} else {
for (let i = 2; i <= pathParts.length; i++) {
prefixes.push('/' + pathParts.slice(0, i).join('/') + '/');
}
}
// Last prefix includes the search too (if any)
if (location.search) {
let params = new URLSearchParams(location.search);
params.sort();
prefixes.push(prefixes.at(-1) + location.search);
}
// We want to start from the longest prefix
prefixes.reverse();
let candidates;
let matchingPrefix;
for (let prefix of prefixes) {
candidates = document.querySelectorAll(`#sidebar a[href^="${prefix}"]`);
if (candidates.length > 0) {
matchingPrefix = prefix;
break;
}
}
if (!matchingPrefix) {
// Abort mission
return;
}
if (matchingPrefix === pathParts.at(-1)) {
// Full path matches, check search
if (location.search) {
candidates = [...candidates];
let searchParams = new URLSearchParams(location.search);
if (searchParams.has('uid')) {
// Only consider candidates with the same uid
candidates = candidates.filter(a => {
let params = new URLSearchParams(a.search);
return params.get('uid') === searchParams.get('uid');
});
} else {
// Sort candidates based on how many params they have in common, in descending order
candidates = candidates.sort((a, b) => {
return countSharedSearchParams(searchParams, b.search) - countSharedSearchParams(searchParams, a.search);
});
}
}
}
if (candidates.length > 0) {
for (let current of document.querySelectorAll('#sidebar a.current')) {
current.classList.remove('current');
}
candidates[0].classList.add('current');
}
};
sidebar.render = function () {
this.palettes.render();
};
sidebar.render();
window.addEventListener('turbo:render', () => sidebar.render());
function countSharedSearchParams(searchParams, search) {
if (!search || search === '?') {
return 0;
}
let params = new URLSearchParams(search);
return [...searchParams.keys()].filter(k => params.get(k) === searchParams.get(k)).length;
}

View File

@@ -1,5 +1,14 @@
import { domChange } from './util/dom-change.js';
export { domChange };
// Helper for view transitions
export function domChange(fn, { behavior = 'smooth' } = {}) {
const canUseViewTransitions =
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (canUseViewTransitions && behavior === 'smooth') {
document.startViewTransition(fn);
} else {
fn(true);
}
}
export function nextFrame() {
return new Promise(resolve => requestAnimationFrame(resolve));
@@ -91,7 +100,6 @@ const colorScheme = new ThemeAspect({
domChange(() => {
let dark = this.computedValue === 'dark';
document.documentElement.classList.toggle(`wa-dark`, dark);
document.documentElement.dispatchEvent(new CustomEvent('wa-color-scheme-change', { detail: { dark } }));
});
},
});
@@ -106,6 +114,6 @@ document.addEventListener('keydown', event => {
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
) {
event.preventDefault();
colorScheme.set(colorScheme.get() === 'dark' ? 'light' : 'dark');
colorScheme.set(theming.colorScheme.resolvedValue === 'dark' ? 'light' : 'dark');
}
});

View File

@@ -1,6 +1,3 @@
import 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm';
import { preventTurboFouce } from '/dist/webawesome.js';
if (!window.___turboScrollPositions___) {
window.___turboScrollPositions___ = {};
}
@@ -73,4 +70,3 @@ function fixDSD(e) {
window.addEventListener('turbo:before-cache', saveScrollPosition);
window.addEventListener('turbo:before-render', restoreScrollPosition);
window.addEventListener('turbo:render', restoreScrollPosition);
preventTurboFouce();

View File

@@ -13,42 +13,56 @@ export default class Permalink extends URLSearchParams {
return Object.fromEntries(this.entries());
}
set(key, value, defaultValue) {
if (equals(value, defaultValue) || equals(value, '')) {
value = null;
#mappings = new WeakMap();
mapObject(obj, mapping = {}) {
this.#mappings.set(obj, mapping);
}
readFrom(obj) {
let mapping = this.#mappings.get(obj) ?? {};
let { keyFrom = IDENTITY, valueFrom = IDENTITY } = mapping;
for (let key in obj) {
let value = obj[key];
let mappedValue = valueFrom(value);
let mappedKey = keyFrom(key);
this.set(mappedKey, mappedValue);
}
}
value ??= null; // undefined -> null
writeTo(obj) {
let mapping = this.#mappings.get(obj) ?? {};
let { keyTo = IDENTITY, valueTo = IDENTITY, canExtend = false } = mapping;
let oldValue = Array.isArray(value) ? this.getAll(key) : this.get(key);
let changed = !equals(value, oldValue);
for (let [key, value] of this) {
let mappedKey = keyTo(key);
let mappedValue = valueTo(value);
if (!changed) {
// Nothing to do here
return;
}
if (Array.isArray(value)) {
super.delete(key);
value = value.slice();
for (let v of value) {
if (v || v === 0) {
if (typeof v === 'object') {
super.append(key, JSON.stringify(v));
} else {
super.append(key, v);
}
}
if (canExtend || mappedKey in obj) {
obj[mappedKey] = mappedValue;
}
} else if (value === null) {
}
}
set(key, value, defaultValue) {
let oldValue = this.get(key);
if (!value || value == defaultValue) {
super.delete(key);
if (oldValue) {
this.changed = true;
}
} else {
super.set(key, value);
if (String(value) !== String(oldValue)) {
this.changed = true;
}
}
this.sort();
this.changed ||= changed;
}
/**
@@ -65,40 +79,3 @@ export default class Permalink extends URLSearchParams {
}
}
}
function equals(value, oldValue) {
if (Array.isArray(value) || Array.isArray(oldValue)) {
value = toArray(value);
oldValue = toArray(oldValue);
if (value.length !== oldValue.length) {
return false;
}
return value.every((v, i) => equals(v, oldValue[i]));
}
// (value ?? oldValue ?? true) returns true if they're both empty (null or undefined)
[value, oldValue] = [value, oldValue].map(v => (!v && v !== false && v !== 0 ? null : v));
return value === oldValue || String(value) === String(oldValue);
}
/**
* Convert a value to an array. `undefined` and `null` values are converted to an empty array.
* @param {*} value - The value to convert.
* @returns {any[]} The converted array.
*/
function toArray(value) {
value ??= [];
if (Array.isArray(value)) {
return value;
}
// Don't convert "foo" into ["f", "o", "o"]
if (typeof value !== 'string' && typeof value[Symbol.iterator] === 'function') {
return Array.from(value);
}
return [value];
}

View File

@@ -1,37 +0,0 @@
let initialPageLoadComplete = document.readyState === 'complete';
if (!initialPageLoadComplete) {
window.addEventListener('load', () => {
initialPageLoadComplete = true;
});
}
/**
* Helper for performing a DOM change using a view transition, wherever supported and reduced motion is not desired.
* @param {function} fn - Function to perform the DOM change. If async, must resolve when the change is complete.
* @param {object} [options] - Options for the transition
* @param {'smooth' | 'instant'} [options.behavior] - Transition behavior. Defaults to 'smooth'. 'instant' will skip the transition.
* @param {boolean} [options.ignoreInitialLoad] - If true, will skip the transition on initial page load. Defaults to true.
*/
export function domChange(fn, { behavior = 'smooth', ignoreInitialLoad = true } = {}) {
const canUseViewTransitions =
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// Skip transitions on initial page load
if (!initialPageLoadComplete && ignoreInitialLoad) {
fn(false);
return null;
}
if (canUseViewTransitions && behavior === 'smooth') {
const transition = document.startViewTransition(() => {
fn(true);
// Wait a brief delay before finishing the transition to prevent jumpiness
return new Promise(resolve => setTimeout(resolve, 200));
});
return transition;
} else {
fn(false);
return null;
}
}

View File

@@ -1,22 +0,0 @@
// Like v-text, but doesn't complain if the element has content,
// making it possible to use in a PE fashion, with the contents being the fallback
export default function content(el, { value, arg }) {
if (!el.dataset.fallback) {
// Store the original content as a fallback the first time
el.dataset.fallback = el.textContent;
}
if (value === '') {
value = el.dataset.fallback;
} else {
if (arg === 'number') {
value = Number(value).toLocaleString(undefined, { maximumSignificantDigits: 2 });
}
}
if (arg === 'html') {
el.innerHTML = value;
} else {
el.textContent = value;
}
}

View File

@@ -1,110 +0,0 @@
import my from '/assets/scripts/my.js';
import Permalink from '/assets/scripts/tweak/permalink.js';
export default {
data() {
return {
uid: undefined,
saved: null,
unsavedChanges: false,
permalink: new Permalink(),
};
},
created() {
if (this.permalink.has('uid')) {
this.uid = Number(this.permalink.get('uid'));
this.saved = this.controller.saved.find(p => p.uid === this.uid);
}
this.controller.addEventListener('delete', ({ detail: entity }) => {
if (entity.uid === this.saved?.uid) {
this.postDelete();
}
});
},
mounted() {
this.$nextTick().then(() => {
if (!location.search || this.saved) {
this.unsavedChanges = false;
}
});
},
computed: {
controller() {
return my[this.collection];
},
title() {
if (this.saved) {
return this.saved.title;
} else if (this.unsavedChanges) {
return this.defaultTitle;
} else {
return this.originalTitle;
}
},
},
watch: {
saved: {
deep: true,
handler() {
this.unsavedChanges = !this.saved;
},
},
},
methods: {
async save({ title } = {}) {
let uid = this.uid;
this.saved ??= { uid: this.uid };
this.saved.id = this.id;
if (title) {
// Renaming
this.saved.title = title;
} else {
this.saved.title ??= this.defaultTitle;
}
this.saved.search = location.search;
this.saved = this.controller.save(this.saved);
if (uid !== this.saved.uid) {
// UID changed (most likely from saving a new entity)
this.uid = this.saved.uid;
this.permalink.set('uid', this.uid);
this.permalink.updateLocation();
await this.$nextTick();
this.save(); // Save again to update the search param to include the UID
}
this.unsavedChanges = false;
},
rename() {
let newTitle = prompt('Title:', this.saved?.title ?? this.defaultTitle);
if (newTitle && newTitle !== this.saved?.title) {
this.save({ title: newTitle });
}
},
// Cannot name this delete() because Vue complains
deleteSaved() {
this.controller.delete(this.saved);
},
postDelete() {
this.saved = null;
this.permalink.delete('uid');
this.uid = undefined;
this.permalink.updateLocation();
},
},
};

View File

@@ -0,0 +1,87 @@
.code-example {
border: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
border-radius: var(--wa-border-radius-l);
color: var(--wa-color-text-normal);
margin-block-end: var(--wa-flow-spacing);
}
.code-example-preview {
padding: 2rem;
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
> :first-child {
margin-block-start: 0;
}
> :last-child {
margin-block-end: 0;
}
}
.code-example-source {
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
}
.code-example:not(.open) .code-example-source {
display: none;
}
.code-example.open .code-example-toggle wa-icon {
rotate: 180deg;
}
.code-example-source pre {
position: relative;
border-radius: 0;
margin: 0;
white-space: normal;
}
.code-example-source:not(:has(+ .code-example-buttons)) {
border-bottom: none;
pre {
border-bottom-right-radius: var(--wa-border-radius-l);
border-bottom-left-radius: var(--wa-border-radius-l);
}
}
.code-example-buttons {
display: flex;
align-items: stretch;
button {
all: unset;
flex: 1 0 auto;
font-size: 0.875rem;
color: var(--wa-color-text-quiet);
border-left: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
text-align: center;
padding: 0.5rem;
cursor: pointer;
&:first-of-type {
border-left: none;
border-bottom-left-radius: var(--wa-border-radius-l);
}
&:last-of-type {
border-bottom-right-radius: var(--wa-border-radius-l);
}
&:focus-visible {
outline: var(--wa-focus-ring);
}
}
.code-example-pen {
flex: 0 0 100px;
white-space: nowrap;
}
wa-icon {
width: 1em;
height: 1em;
vertical-align: -2px;
}
}

View File

@@ -1,9 +1,9 @@
@import 'code-examples.css';
@import 'code-highlighter.css';
@import 'copy-code.css';
@import 'outline.css';
@import 'search.css';
@import 'cera_typeface.css';
@import 'theme-icons.css';
:root {
--wa-brand-orange: #f36944;
@@ -370,22 +370,10 @@ wa-page > main:has(> .index-grid) {
.index-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(auto-fit, minmax(min(22ch, 100%), 1fr));
gap: var(--wa-space-2xl);
margin-block-end: var(--wa-space-3xl);
@media screen and (max-width: 1470px) {
grid-template-columns: repeat(3, 1fr);
}
@media screen and (max-width: 960px) {
grid-template-columns: repeat(2, 1fr);
}
@media screen and (max-width: 500px) {
grid-template-columns: repeat(1, 1fr);
}
a {
border-radius: var(--wa-border-radius-l);
text-decoration: none;
@@ -412,6 +400,7 @@ wa-page > main:has(> .index-grid) {
&::part(header) {
background-color: var(--header-background, var(--wa-color-neutral-fill-quiet));
border-bottom: none;
display: flex;
align-items: center;
justify-content: center;
@@ -607,6 +596,13 @@ table.colors {
margin-block-end: var(--wa-flow-spacing);
}
/** mobile */
@media screen and (max-width: 768px) {
wa-page .only-desktop {
display: none;
}
}
/** desktop */
@media screen and not (max-width: 768px) {
/* Navigation sidebar */

View File

@@ -7,9 +7,8 @@
margin: 0 auto;
overflow: hidden;
&::part(dialog) {
margin-block-start: 10vh;
margin-block-end: 0;
&::part(base) {
margin-block: 10rem;
}
&::part(body) {
@@ -24,20 +23,20 @@
@media screen and (max-width: 900px) {
max-width: calc(100% - 2rem);
&::part(dialog) {
&::part(base) {
margin-block: 1rem;
}
#site-search-container {
max-height: none;
}
}
}
#site-search-container {
display: flex;
flex-direction: column;
max-height: calc(100vh - 18rem);
max-height: calc(100vh - 20rem);
@media screen and (max-width: 900px) {
max-height: calc(100dvh - 2rem);
}
}
/* Header */

View File

@@ -1,61 +1,3 @@
wa-card:has(> .theme-icon-host, > [slot='header'] > .theme-icon-host) {
&::part(header) {
/* We want to add a background color, so any spacing needs to go on .theme-icon */
flex: 1;
padding: 0;
min-block-size: 0;
}
[slot='header'] {
width: 100%;
}
}
.theme-icon-host,
.palette-icon-host {
flex: 1;
border-radius: inherit;
&[slot='header'],
[slot='header']:has(&) {
flex: 1;
border-radius: inherit;
}
}
.palette-icon {
display: grid;
grid-template-columns: repeat(var(--hues, 9), 1fr);
gap: var(--wa-space-3xs);
min-width: 20ch;
min-height: 9ch;
align-content: center;
.swatch {
height: 0.7em;
background: var(--color);
border-radius: var(--wa-border-radius-s);
&[data-suffix=''] {
height: 1.1em;
}
}
}
.theme-icon {
min-width: 18ch;
padding: var(--wa-space-xs) var(--wa-space-m);
border-radius: inherit;
box-sizing: border-box;
h2,
h3,
p {
margin-block: 0;
padding: 0;
}
}
.theme-color-icon {
display: grid;
gap: var(--wa-space-xs);
@@ -83,50 +25,10 @@ wa-card:has(> .theme-icon-host, > [slot='header'] > .theme-icon-host) {
display: flex;
flex-direction: column;
gap: var(--wa-space-xs);
}
.theme-overall-icon {
display: flex;
flex-flow: column;
gap: var(--wa-space-xs);
justify-content: center;
width: 100%;
min-height: 7.5rem;
box-sizing: border-box;
background: var(--wa-color-surface-lowered);
.row {
display: flex;
gap: var(--wa-space-xs);
align-items: center;
justify-content: space-between;
}
.row-2 {
display: grid;
grid-template-columns: 1fr auto;
contain: inline-size;
width: 100%;
wa-input {
min-width: 1em;
}
}
.swatches {
display: flex;
gap: var(--wa-space-3xs);
> div {
width: 1.25rem;
height: 1.25rem;
border-radius: var(--wa-border-radius-s);
background: var(--wa-color-fill-loud);
color: var(--wa-color-on-loud);
&.wa-brand {
width: 2.5rem;
}
}
h3,
p {
margin-block: 0;
padding: 0;
}
}

View File

@@ -167,7 +167,7 @@ Other elements can also be placed inside button groups:
<wa-button-group label="Example Button Group">
<wa-button>Button</wa-button>
<button>Native Button</button>
<wa-dropdown>
<wa-dropdown hoist>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
<wa-menu-item>Item 1</wa-menu-item>
@@ -185,7 +185,7 @@ Create a split button using a button and a dropdown. Use a [visually hidden](/do
```html {.example}
<wa-button-group label="Example Button Group">
<wa-button variant="brand">Save</wa-button>
<wa-dropdown placement="bottom-end">
<wa-dropdown placement="bottom-end" hoist>
<wa-button slot="trigger" variant="brand" caret>
<span class="wa-visually-hidden">More options</span>
</wa-button>

View File

@@ -15,9 +15,9 @@ icon: card
<strong>Mittens</strong><br />
This kitten is as cute as he is playful. Bring him home today!<br />
<small class="wa-caption-m">6 weeks old</small>
<small>6 weeks old</small>
<div slot="footer" class="wa-split">
<div slot="footer">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating label="Rating"></wa-rating>
</div>
@@ -27,6 +27,16 @@ icon: card
.card-overview {
width: 300px;
}
.card-overview small {
color: var(--wa-color-text-quiet);
}
.card-overview [slot='footer'] {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
```
@@ -55,9 +65,9 @@ If using SSR, you need to also use the `with-header` attribute to add a header t
```html {.example}
<wa-card with-header class="card-header">
<div slot="header" class="wa-split">
<div slot="header">
Header Title
<wa-icon-button name="gear" variant="solid" label="Settings" class="wa-size-m"></wa-icon-button>
<wa-icon-button name="gear" variant="solid" label="Settings"></wa-icon-button>
</div>
This card has a header. You can put all sorts of things in it!
@@ -68,9 +78,19 @@ If using SSR, you need to also use the `with-header` attribute to add a header t
max-width: 300px;
}
.card-header [slot='header'] {
display: flex;
align-items: center;
justify-content: space-between;
}
.card-header h3 {
margin: 0;
}
.card-header wa-icon-button {
font-size: var(--wa-font-size-m);
}
</style>
```
@@ -83,7 +103,7 @@ If using SSR, you need to also use the `with-footer` attribute to add a footer t
<wa-card with-footer class="card-footer">
This card has a footer. You can put all sorts of things in it!
<div slot="footer" class="wa-split">
<div slot="footer">
<wa-rating></wa-rating>
<wa-button variant="brand">Preview</wa-button>
</div>
@@ -93,6 +113,12 @@ If using SSR, you need to also use the `with-footer` attribute to add a footer t
.card-footer {
max-width: 300px;
}
.card-footer [slot='footer'] {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
```
@@ -127,7 +153,7 @@ Use the `size` attribute to change a card's size.
<wa-card with-footer size="small">
This is a small card.
<footer slot="footer" class="wa-split">
<footer slot="footer" class="wa-flank">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
@@ -136,7 +162,7 @@ Use the `size` attribute to change a card's size.
<wa-card with-footer size="medium">
This is a medium card (default).
<footer slot="footer" class="wa-split">
<footer slot="footer" class="wa-flank">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
@@ -145,39 +171,14 @@ Use the `size` attribute to change a card's size.
<wa-card with-footer size="large">
This is a large card.
<footer slot="footer" class="wa-split">
<footer slot="footer" class="wa-flank">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
</div>
```
### Appearance
Use the `appearance` attribute to change the card's visual appearance.
```html {.example}
<div class="wa-grid">
<wa-card>
<img
slot="image"
src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
alt="A kitten sits patiently between a terracotta pot and decorative grasses."
/>
<div slot="header">Outlined (default)</div>
Card content.
</wa-card>
{% for appearance in ['outlined filled', 'outlined accent', 'plain', 'filled', 'accent'] -%}
<wa-card appearance="{{ appearance }}">
<img
slot="image"
src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
alt="A kitten sits patiently between a terracotta pot and decorative grasses."
/>
<div slot="header">{{ appearance | capitalize }}</div>
Card content.
</wa-card>
{%- endfor %}
</div>
```
<style>
</style>

View File

@@ -3,7 +3,6 @@ title: Code Demo
description: Code demos can be used to render code examples as inline live demos.
tags: component
noAlpha: true
isPro: true
---
```html {.example}

View File

@@ -77,31 +77,6 @@ The details component automatically adapts to right-to-left languages:
</wa-details>
```
### Appearance
Use the `appearance` attribute to change the elements visual appearance.
```html {.example}
<div class="wa-stack">
<wa-details summary="Outlined (default)">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</wa-details>
<wa-details summary="Filled" appearance="filled">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</wa-details>
<wa-details summary="Filled + Outlined" appearance="filled outlined">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</wa-details>
<wa-details summary="Plain" appearance="plain">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</wa-details>
</div>
```
### Grouping Details
Details are designed to function independently, but you can simulate a group or "accordion" where only one is shown at a time by listening for the `wa-show` event.

View File

@@ -88,10 +88,10 @@ You can add the special `data-dialog="close"` attribute to a button inside the d
### Custom Width
Just use the `--width` custom property to set the dialog's width.
Just use the CSS `width` property to set the dialog's width.
```html {.example}
<wa-dialog label="Dialog" with-header with-footer class="dialog-width" style="--width: 50vw;">
<wa-dialog label="Dialog" with-header with-footer class="dialog-width" style="width: 50vw;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<wa-button slot="footer" variant="brand" data-dialog="close">Close</wa-button>
</wa-dialog>

View File

@@ -180,3 +180,38 @@ To create a submenu, nest an `<wa-menu slot="submenu">` element in a [menu item]
:::warning
As a UX best practice, avoid using more than one level of submenu when possible.
:::
### Hoisting
Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
```html {.example}
<div class="dropdown-hoist">
<wa-dropdown>
<wa-button slot="trigger" caret>No Hoist</wa-button>
<wa-menu>
<wa-menu-item>Item 1</wa-menu-item>
<wa-menu-item>Item 2</wa-menu-item>
<wa-menu-item>Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-dropdown hoist>
<wa-button slot="trigger" caret>Hoist</wa-button>
<wa-menu>
<wa-menu-item>Item 1</wa-menu-item>
<wa-menu-item>Item 2</wa-menu-item>
<wa-menu-item>Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
</div>
<style>
.dropdown-hoist {
position: relative;
border: solid 2px var(--wa-color-surface-border);
padding: var(--wa-space-m);
overflow: hidden;
}
</style>
```

View File

@@ -17,94 +17,11 @@ Not sure which icon to use? [Find the perfect icon over at Font Awesome!](https:
The default icon library is Font Awesome Free, which comes with two icon families: `classic` and `brands`. Use the `family` attribute to set the icon family.
Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regular`, and `solid`. Font Awesome Pro users can [provide their kit code](/docs/#using-font-awesome-kit-codes) to unlock additional families, including `sharp`, `duotone`, and `sharp-duotone`. For these icon families, use the `variant` attribute to set the variant.
Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regular`, and `solid`. Font Awesome Pro users can [provide their kit code](/docs/installation/#using-font-awesome-kit-codes) to unlock additional families, including `sharp` and `duotone`. For these icon families, use the `variant` attribute to set the variant.
```html {.example}
<wa-icon family="brands" name="font-awesome"></wa-icon>
<wa-icon family="brands" name="web-awesome"></wa-icon>
<wa-icon family="classic" variant="light" name="sparkles"></wa-icon>
<wa-icon family="sharp" variant="solid" name="fire"></wa-icon>
<wa-icon family="duotone" variant="regular" name="cake-slice"></wa-icon>
```
### Setting defaults via CSS
You can use certain CSS custom properties to set icon defaults, not just on the icon itself, but any ancestor.
This can be useful when you want certain parameters to vary based on context, e.g. icons inside callouts or all icons for a given theme.
:::warning
These CSS properties are intended to set **defaults**, and thus only make a difference when the corresponding attributes are not set.
In future versions of Web Awesome, we may change this behavior to allow CSS properties to override attributes if `!important` is used.
:::
For example, here is how you can use CSS custom properties to set a default icon for each type of callout:
```html {.example}
<wa-callout>
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
This is a normal callout.
</wa-callout>
<wa-callout variant="danger">
<wa-icon slot="icon" name="dumpster-fire" variant="solid"></wa-icon>
This is a callout with an explicit icon, which overrides these defaults.
</wa-callout>
<wa-callout variant="warning">
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
Here be dragons.
</wa-callout>
<wa-callout variant="danger">
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
Here be more dragons.
</wa-callout>
<wa-callout variant="success">
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
Success!
</wa-callout>
<style>
wa-callout {
--wa-icon-variant: regular;
--wa-icon-name: info-circle;
&[variant="warning"] {
--wa-icon-name: triangle-exclamation;
}
&[variant="danger"] {
--wa-icon-name: circle-exclamation;
}
&[variant="success"] {
--wa-icon-name: circle-check;
}
}
</style>
```
You can even set icons dynamically, as a response to user interaction or media queries.
For example, here's how we can change the icon on hover:
```html {.example}
<wa-button class="github" href="https://github.com/webawesome/webawesome"><wa-icon slot="prefix" fixed-width></wa-icon> GitHub Repo</wa-button>
<style>
.github {
--wa-icon-name: github;
--wa-icon-family: brands;
&:hover {
--wa-icon-name: arrow-up-right-from-square;
--wa-icon-family: classic;
}
}
</style>
<wa-icon family="brands" name="font-awesome"></wa-icon>
<wa-icon family="brands" name="web-awesome"></wa-icon>
```
### Colors
@@ -186,8 +103,7 @@ Custom icons can be loaded individually with the `src` attribute. Only SVGs on a
You can register additional icons to use with the `<wa-icon>` component through icon libraries. Icon files can exist locally or on a CORS-enabled endpoint (e.g. a CDN). There is no limit to how many icon libraries you can register and there is no cost associated with registering them, as individual icons are only requested when they're used.
Web Awesome ships with one built-in icon library: `default`.
The [default icon library](#customizing-the-default-library) is provided courtesy of [Font Awesome](https://fontawesome.com/).
Web Awesome ships with two built-in icon libraries, `default` and `system`. The [default icon library](#customizing-the-default-library) is provided courtesy of [Font Awesome](https://fontawesome.com/). The [system icon library](#customizing-the-system-library) contains only a small subset of icons that are used internally by Web Awesome components.
To register an additional icon library, use the `registerIconLibrary()` function that's exported from `dist/webawesome.js`. At a minimum, you must provide a name and a resolver function. The resolver function translates an icon name to a URL where the corresponding SVG file exists. Refer to the examples below to better understand how it works.
@@ -199,9 +115,8 @@ Here's an example that registers an icon library located in the `/assets/icons`
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'my-icons',
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
registerIconLibrary('my-icons', {
resolver: (name, family, variant) => `/assets/icons/${name}.svg`,
mutator: svg => svg.setAttribute('fill', 'currentColor')
});
</script>
@@ -216,289 +131,6 @@ To display an icon, set the `library` and `name` attributes of an `<wa-icon>` el
If an icon is used before registration occurs, it will be empty initially but shown when registered.
### Customizing the Default Icon Library
The default icon library contains over 2,000 icons courtesy of [Font Awesome](https://fontawesome.com/).
These are the icons that display when you use `<wa-icon>` without the `library` attribute.
If you prefer to have these icons resolve to a different icon library, simply register it using the `default` name:
For example, this will change the default icon library to use [Bootstrap Icons](https://icons.getbootstrap.com/) loaded from the jsDelivr CDN.
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('default', {
name: 'default',
getUrl: (name, family) => {
const suffix = family === 'filled' ? '-fill' : '';
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
}
});
</script>
```
You can also register an existing library as the default:
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
let myIcons = registerIconLibrary({
name: 'my-icons',
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
mutator: svg => svg.setAttribute('fill', 'currentColor')
});
// Alias of my-icons to default
registerIconLibrary('default', myIcons);
</script>
```
This allows you to have multiple libraries that co-exist, only one of which is the default.
### Customizing system icons
Web Awesome components use a number of icons internally.
For example, the checkmark icon in `<wa-checkbox>` or the chevron used in `<wa-details>`.
These icons have a `system:` prefix in their name, e.g. `system:check` or `system:chevron-down`.
To specify how these map to your icon library, you can define a `system()` function that maps Web Awesomes system icons to your librarys icons.
The `system()` function receives the icon name, family and variant as arguments and returns an object with the new `name`, `family`, and `variant`.
For example, here is how to define system icon mappings for the Bootstrap Icons library:
```js
import { registerIconLibrary } from '/dist/webawesome.js';
let system = {
filled: ['circle', 'pause', 'play', 'star', 'user'],
nameMap: {
'check': 'check-lg',
'circle': 'circle',
'circle-xmark': 'x-circle',
'eye-dropper': 'eyedropper',
'eye': 'eye',
'eye-slash': 'eye-slash',
'grip-vertical': 'grip-vertical',
'indeterminate': 'dash-lg',
'minus': 'dash-lg',
'pause': 'pause',
'play': 'play',
'user': 'person',
'xmark': 'x-lg',
}
};
registerIconLibrary({
name: 'bootstrap-icons',
system(name, family) {
return {
// Transform names where different
name: system.nameMap[name] || name,
// Default to non-filled as many of system's "solid" icons are not filled in Bootstrap Icons
family: system.filled.includes(name) ? 'filled' : ''
};
},
getUrl: (name, family) => {
const suffix = family === 'filled' ? '-fill' : '';
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
}
});
```
You can also specify a `library` key to resolve a system icon through a different library, e.g. WAs default icon library.
For example, the code above will try to resolve any system icons through your library and only fall back to WA's default library if they fail to load.
This maximizes the odds that icons from your library are used, but can also be unpredictable.
To resolve any system icon you have not vetted via the Web Awesome default library, you can use the `library` key:
```js
let system = {
filled: ['circle', 'pause', 'play', 'star', 'user'],
nameMap: {
'chevron-down': 'chevron-down',
'chevron-left': 'chevron-left',
'chevron-right': 'chevron-right',
'check': 'check-lg',
'circle': 'circle',
'eye-dropper': 'eyedropper',
'grip-vertical': 'grip-vertical',
'indeterminate': 'dash-lg',
'pause': 'pause',
'play': 'play',
'circle-xmark': 'x-circle',
'grip-vertical': 'grip-vertical',
'eye-slash': 'eye-slash',
'eye': 'eye',
'user': 'person',
'xmark': 'x-lg',
}
};
registerIconLibrary({
name: 'bootstrap-icons',
system(name, family) {
if (!system.nameMap[name]) {
// If the icon is not known, use the default library
return { library: 'wa', name, family, variant };
}
return {
name: system.nameMap[name],
family: system.filled.includes(name) ? 'filled' : ''
};
},
getUrl: (name, family) => {
const suffix = family === 'filled' ? '-fill' : '';
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
}
});
```
#### Index of All System Icons { #system-icons-index }
These are all system icons used currently by Web Awesome components (`system:` prefix omitted for readability):
| Name | Variant | Icon |
| --- | --- | --- |
{%- for icon in systemIcons %}
| `{{ icon.name }}` | `{{ icon.variant }}` | <wa-icon library="wa" name="system:{{ icon.name }}" family="classic" variant="{{ icon.variant }}"></wa-icon> |
{%- endfor %}
### Inlined icons { #inlined }
Inlined icons are SVG icons that are loaded directly from code rather than from HTTP requests, making them load faster in your application.
Inlining critical icons improves performance by eliminating HTTP requests, reducing load times, and ensuring they are immediately available.
As an example, all of [Web Awesomes default system icons](#system-icons-index) are inlined, and we strongly advise you inline the corresponding icons in your custom icon libraries as well.
#### How to Use Inlined Icons
The `inlined` property allows you to provide icon SVG markup directly in your code.
This creates a mapping of `(name, family, variant)` to SVG markup.
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'default',
getUrl: name => `/path/to/custom/icons/${name}.svg`,
inlined: {
check: '<svg xmlns="http://www.w3.org/2000/svg">...</svg>',
}
});
</script>
```
The structure of the `inlined` property is as follows:
- For simple libraries (no families or variants): `{ name: svg }`
- For libraries with families (no variants): `{ family: { name: svg } }`
- For complex libraries (with both family and variant): `{ family: { variant: { name: svg } } }`
#### Adding More Inlined Icons
To add additional icons to an existing library, use the `inline()` method:
```js
import { getIconLibrary } from '/dist/webawesome.js';
let defaultLibrary = getIconLibrary('default');
defaultLibrary.inline({
classic: { // family
regular: { // variant
'circle-info': '<svg xmlns="http://www.w3.org/2000/svg">...</svg>',
'triangle-exclamation': '<svg xmlns="http://www.w3.org/2000/svg">...</svg>'
// ...
}
}
});
```
#### Best Practice
When using custom icon libraries with Web Awesome components, always inline system icons to ensure optimal performance.
### Customize icon markup, for SVG sprites and more
By default, icon markup is produced by fetching the URL returned by the `getUrl()` function.
You can provide a `getMarkup()` function to customize this.
A common use case for that is SVG sprites, often used to improve performance by avoiding multiple trips for each SVG.
The browser will load the sprite sheet once and then you reference the particular SVG within the sprite sheet using its id:
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'sprite',
getUrl: name => `/assets/images/sprite.svg#${name}`,
getMarkup: url => `<svg fill="currentColor"><use href="${url}"></use></svg>`
});
</script>
```
As always, make sure to benchmark these changes. When using HTTP/2, it may in fact be more bandwidth-friendly to use multiple small requests instead of 1 large sprite sheet.
:::warning
When using sprite sheets, the `wa-load` and `wa-error` events will not fire.
For security reasons, browsers may apply the same-origin policy on `<use>` elements located in the `<wa-icon>` shadow DOM and may refuse to load a cross-origin URL. There is currently no defined way to set a cross-origin policy for `<use>` elements. For this reason, sprite sheets should only be used if you're self-hosting them.
:::
### Fallbacks
By default, if an icon fails to load, WA will retry using the WA default icon library, and if that also fails, a blank icon will be displayed.
You can provide a `fallback()` function to customize this behavior.
Some examples for common use cases follow.
If you never want icons outside your library to display:
```js
registerIconLibrary({
name: 'my-icons',
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
fallback: (name, family, variant) => {
// Don't show anything if an icon is not found
return null;
}
});
```
If you want to display a certain designated "missing icon" icon:
```js
registerIconLibrary({
name: 'my-icons',
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
inlined: {
// Make sure the missing icon never fails by inlining it:
'missing-icon': '<svg xmlns="http://www.w3.org/2000/svg">...</svg>'
}
fallback: (name, family, variant) => {
return {name: 'missing-icon'};
}
});
```
If you want to retry with the default family and variant:
```js
registerIconLibrary({
name: 'my-icons',
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
fallback: (name, family, variant) => {
if (family !== 'classic' || variant !== 'solid') {
return { name, family: 'classic', variant: 'solid' };
}
}
});
```
## Icon Library Examples { #icon-libraries }
The following examples demonstrate how to register a number of popular, open source icon libraries via CDN. Feel free to adapt the code as you see fit to use your own origin or naming conventions.
### Bootstrap Icons
@@ -511,42 +143,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/tw
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
let system = {
filled: ['circle', 'pause', 'play', 'star', 'user'],
nameMap: {
'chevron-down': 'chevron-down',
'chevron-left': 'chevron-left',
'chevron-right': 'chevron-right',
'check': 'check-lg',
'circle': 'circle',
'eye-dropper': 'eyedropper',
'grip-vertical': 'grip-vertical',
'indeterminate': 'dash-lg',
'pause': 'pause',
'play': 'play',
'circle-xmark': 'x-circle',
'grip-vertical': 'grip-vertical',
'eye-slash': 'eye-slash',
'eye': 'eye',
'user': 'person',
'xmark': 'x-lg',
}
};
registerIconLibrary({
name: 'default',
system(name, family) {
if (!system.nameMap[name]) {
// If the icon is not known, use the default library
return { library: 'wa', name: name, family, variant };
}
return {
name: system.nameMap[name],
family: system.filled.includes(name) ? 'filled' : ''
};
},
getUrl: (name, family) => {
registerIconLibrary('default', {
resolver: (name, family) => {
const suffix = family === 'filled' ? '-fill' : '';
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
}
@@ -564,9 +162,8 @@ Icons in this library are licensed under the [Creative Commons 4.0 License](http
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'boxicons',
getUrl: name => {
registerIconLibrary('boxicons', {
resolver: name => {
let folder = 'regular';
if (name.substring(0, 4) === 'bxs-') folder = 'solid';
if (name.substring(0, 4) === 'bxl-') folder = 'logos';
@@ -619,9 +216,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'lucide',
getUrl: name => `https://cdn.jsdelivr.net/npm/lucide-static@0.16.29/icons/${name}.svg`
registerIconLibrary('lucide', {
resolver: name => `https://cdn.jsdelivr.net/npm/lucide-static@0.16.29/icons/${name}.svg`
});
</script>
```
@@ -636,9 +232,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/ta
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'heroicons',
getUrl: name => `https://cdn.jsdelivr.net/npm/heroicons@2.0.1/24/outline/${name}.svg`
registerIconLibrary('heroicons', {
resolver: name => `https://cdn.jsdelivr.net/npm/heroicons@2.0.1/24/outline/${name}.svg`
});
</script>
@@ -662,9 +257,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'iconoir',
getUrl: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`
registerIconLibrary('iconoir', {
resolver: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`
});
</script>
@@ -688,9 +282,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/io
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'ionicons',
getUrl: name => `https://cdn.jsdelivr.net/npm/ionicons@5.1.2/dist/ionicons/svg/${name}.svg`,
registerIconLibrary('ionicons', {
resolver: name => `https://cdn.jsdelivr.net/npm/ionicons@5.1.2/dist/ionicons/svg/${name}.svg`,
mutator: svg => {
svg.setAttribute('fill', 'currentColor');
svg.setAttribute('stroke', 'currentColor');
@@ -734,9 +327,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/mi
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'jam',
getUrl: name => `https://cdn.jsdelivr.net/npm/jam-icons@2.0.0/svg/${name}.svg`,
registerIconLibrary('jam', {
resolver: name => `https://cdn.jsdelivr.net/npm/jam-icons@2.0.0/svg/${name}.svg`,
mutator: svg => svg.setAttribute('fill', 'currentColor')
});
</script>
@@ -768,9 +360,8 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'material',
getUrl: name => {
registerIconLibrary('material', {
resolver: name => {
const match = name.match(/^(.*?)(_(round|sharp))?$/);
return `https://cdn.jsdelivr.net/npm/@material-icons/svg@1.0.5/svg/${match[1]}/${match[3] || 'outline'}.svg`;
},
@@ -812,9 +403,8 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'remixicon',
getUrl: name => {
registerIconLibrary('remixicon', {
resolver: name => {
const match = name.match(/^(.*?)\/(.*?)?$/);
match[1] = match[1].charAt(0).toUpperCase() + match[1].slice(1);
return `https://cdn.jsdelivr.net/npm/remixicon@2.5.0/icons/${match[1]}/${match[2]}.svg`;
@@ -850,9 +440,8 @@ Icons in this library are licensed under the [MIT License](https://github.com/ta
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'tabler',
getUrl: name => `https://cdn.jsdelivr.net/npm/@tabler/icons@1.68.0/icons/${name}.svg`,
registerIconLibrary('tabler', {
resolver: name => `https://cdn.jsdelivr.net/npm/@tabler/icons@1.68.0/icons/${name}.svg`,
mutator: svg => {
svg.style.fill = 'none';
svg.setAttribute('stroke', 'currentColor');
@@ -887,9 +476,8 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary({
name: 'unicons',
getUrl: name => {
registerIconLibrary('unicons', {
resolver: name => {
const match = name.match(/^(.*?)(-s)?$/);
return `https://cdn.jsdelivr.net/npm/@iconscout/unicons@3.0.3/svg/${match[2] === '-s' ? 'solid' : 'line'}/${
match[1]
@@ -916,6 +504,61 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
</div>
```
### Customizing the Default Library
The default icon library contains over 2,000 icons courtesy of [Font Awesome](https://fontawesome.com/). These are the icons that display when you use `<wa-icon>` without the `library` attribute. If you prefer to have these icons resolve elsewhere or to a different icon library, register an icon library using the `default` name and a custom resolver.
For example, this will change the default icon library to use [Bootstrap Icons](https://icons.getbootstrap.com/) loaded from the jsDelivr CDN.
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('default', {
resolver: (name, family) => {
const suffix = family === 'filled' ? '-fill' : '';
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
}
});
</script>
```
#### Customize the default library to use SVG sprites
To improve performance you can use a SVG sprites to avoid multiple trips for each SVG. The browser will load the sprite sheet once and then you reference the particular SVG within the sprite sheet using hash selector.
As always, make sure to benchmark these changes. When using HTTP/2, it may in fact be more bandwidth-friendly to use multiple small requests instead of 1 large sprite sheet.
:::warning
When using sprite sheets, the `wa-load` and `wa-error` events will not fire.
For security reasons, browsers may apply the same-origin policy on `<use>` elements located in the `<wa-icon>` shadow DOM and may refuse to load a cross-origin URL. There is currently no defined way to set a cross-origin policy for `<use>` elements. For this reason, sprite sheets should only be used if you're self-hosting them.
:::
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('sprite', {
resolver: name => `/assets/images/sprite.svg#${name}`,
mutator: svg => svg.setAttribute('fill', 'currentColor'),
spriteSheet: true
});
</script>
```
### Customizing the System Library
The system library contains only the icons used internally by Web Awesome components. Unlike the default icon library, the system library does not rely on physical assets. Instead, its icons are hard-coded as data URIs into the resolver to ensure their availability.
If you want to change the icons Web Awesome uses internally, you can register an icon library using the `system` name and a custom resolver. If you choose to do this, it's your responsibility to provide all of the icons that are required by components. You can reference `src/components/library.system.ts` for a complete list of system icons used by Web Awesome.
```html
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('system', {
resolver: name => `/path/to/custom/icons/${name}.svg`
});
</script>
```

View File

@@ -1,16 +1,14 @@
---
title: Comparer
description: Compare visual differences between similar content with a sliding panel.
title: Image Comparer
description: Compare visual differences between similar photos with a sliding panel.
tags: [imagery, niche]
icon: comparer
icon: image-comparer
---
This is especially useful for comparing images, but can be used for comparing any type of content (for an example of using it to compare entire UIs, check out our [theme pages](/docs/themes/default/)).
For best results, use content that shares the same dimensions.
The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
```html {.example}
<wa-comparer>
<wa-image-comparer>
<img
slot="before"
src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&sat=-100&bri=-5"
@@ -21,7 +19,7 @@ The slider can be controlled by dragging or pressing the left and right arrow ke
src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80"
alt="Color version of kittens in a basket looking around."
/>
</wa-comparer>
</wa-image-comparer>
```
## Examples
@@ -31,7 +29,7 @@ The slider can be controlled by dragging or pressing the left and right arrow ke
Use the `position` attribute to set the initial position of the slider. This is a percentage from `0` to `100`.
```html {.example}
<wa-comparer position="25">
<wa-image-comparer position="25">
<img
slot="before"
src="https://images.unsplash.com/photo-1520903074185-8eca362b3dce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1200&q=80"
@@ -42,5 +40,5 @@ Use the `position` attribute to set the initial position of the slider. This is
src="https://images.unsplash.com/photo-1520640023173-50a135e35804?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2250&q=80"
alt="A person sitting on a yellow curb tying shoelaces on a boot."
/>
</wa-comparer>
</wa-image-comparer>
```

View File

@@ -2,10 +2,13 @@
title: Components
description: Components are the essential building blocks to create intuitive, cohesive experiences. Browse the library of customizable, framework-friendly web components included in Web Awesome.
layout: overview
override:tags: []
categories:
tags: [actions, feedback, imagery, inputs, navigation, organization, helpers]
titles:
feedback: 'Feedback & Status'
helpers: 'Utilities'
- actions
- feedback: 'Feedback & Status'
- imagery
- inputs
- navigation
- organization
- helpers: 'Utilities'
override:tags: []
---

View File

@@ -885,4 +885,4 @@ If you dont want to use [native styles](/docs/native/), you can include this
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/components/page.css' %}" />
```
```

View File

@@ -468,20 +468,75 @@ Use the `sync` attribute to make the popup the same width or height as the ancho
</script>
```
### Positioning Strategy
By default, the popup is positioned using an absolute positioning strategy. However, if your anchor is fixed or exists within a container that has `overflow: auto|hidden`, the popup risks being clipped. To work around this, you can use a fixed positioning strategy by setting the `strategy` attribute to `fixed`.
The fixed positioning strategy reduces jumpiness when the anchor is fixed and allows the popup to break out containers that clip. When using this strategy, it's important to note that the content will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
In this example, you can see how the popup breaks out of the overflow container when it's fixed. The fixed positioning strategy tends to be less performant than absolute, so avoid using it unnecessarily.
Toggle the switch and scroll the container to see the difference.
```html {.example}
<div class="popup-strategy">
<div class="overflow">
<wa-popup placement="top" strategy="fixed" active>
<span slot="anchor"></span>
<div class="box"></div>
</wa-popup>
</div>
<wa-switch checked>Fixed</wa-switch>
</div>
<style>
.popup-strategy .overflow {
position: relative;
height: 300px;
border: solid 2px var(--wa-color-surface-border);
overflow: auto;
}
.popup-strategy span[slot='anchor'] {
display: inline-block;
width: 150px;
height: 150px;
border: dashed 2px var(--wa-color-neutral-fill-loud);
margin: 150px 50px;
}
.popup-strategy .box {
width: 100px;
height: 50px;
background: var(--wa-color-brand-fill-loud);
border-radius: var(--wa-border-radius-m);
}
.popup-strategy wa-switch {
margin-top: 1rem;
}
</style>
<script>
const container = document.querySelector('.popup-strategy');
const popup = container.querySelector('wa-popup');
const fixed = container.querySelector('wa-switch');
fixed.addEventListener('change', () => (popup.strategy = fixed.checked ? 'fixed' : 'absolute'));
</script>
```
### Flip
When the popup doesn't have enough room in its preferred placement, it can automatically flip to keep it in view and visually connected to its anchor.
To enable this, use the `flip` attribute. By default, the popup will flip to the opposite placement, but you can configure preferred fallback placements using `flip-fallback-placement` and `flip-fallback-strategy`. Additional options are available to control the flip behavior's boundary and padding.
By default, flip takes effect when the popup would overflow the viewport.
You can use `boundary="scroll"` to make the popup resize when it overflows its nearest scrollable container instead.
When the popup doesn't have enough room in its preferred placement, it can automatically flip to keep it in view. To enable this, use the `flip` attribute. By default, the popup will flip to the opposite placement, but you can configure preferred fallback placements using `flip-fallback-placement` and `flip-fallback-strategy`. Additional options are available to control the flip behavior's boundary and padding.
Scroll the container to see how the popup flips to prevent clipping.
```html {.example}
<div class="popup-flip">
<div class="overflow">
<wa-popup placement="top" flip active boundary="scroll">
<wa-popup placement="top" flip active>
<span slot="anchor"></span>
<div class="box"></div>
</wa-popup>
@@ -537,7 +592,7 @@ Scroll the container to see how the popup changes it's fallback placement to pre
```html {.example}
<div class="popup-flip-fallbacks">
<div class="overflow">
<wa-popup placement="top" flip flip-fallback-placements="right bottom" flip-fallback-strategy="initial" active boundary="scroll">
<wa-popup placement="top" flip flip-fallback-placements="right bottom" flip-fallback-strategy="initial" active>
<span slot="anchor"></span>
<div class="box"></div>
</wa-popup>
@@ -571,18 +626,14 @@ Scroll the container to see how the popup changes it's fallback placement to pre
### Shift
When a popup is longer than its anchor, it risks overflowing.
In this case, use the `shift` attribute to shift the popup along its axis and back into view. You can customize the shift behavior using `shiftBoundary` and `shift-padding`.
By default, auto-size takes effect when the popup would overflow the viewport.
You can use `boundary="scroll"` to make the popup resize when it overflows its nearest scrollable container instead.
When a popup is longer than its anchor, it risks being clipped by an overflowing container. In this case, use the `shift` attribute to shift the popup along its axis and back into view. You can customize the shift behavior using `shiftBoundary` and `shift-padding`.
Toggle the switch to see the difference.
```html {.example}
<div class="popup-shift">
<div class="overflow">
<wa-popup placement="top" shift shift-padding="10" active boundary="scroll">
<wa-popup placement="top" shift shift-padding="10" active>
<span slot="anchor"></span>
<div class="box"></div>
</wa-popup>
@@ -625,11 +676,7 @@ Toggle the switch to see the difference.
### Auto-size
Use the `auto-size` attribute to tell the popup to resize when necessary to prevent it from overflowing.
Possible values are `horizontal`, `vertical`, and `both`. You can use `autoSizeBoundary` and `auto-size-padding` to customize the behavior of this option. Auto-size works well with `flip`, but if you're using `auto-size-padding` make sure `flip-padding` is the same value.
By default, auto-size takes effect when the popup would overflow the viewport.
You can use `boundary="scroll"` to make the popup resize when it overflows its nearest scrollable container instead.
Use the `auto-size` attribute to tell the popup to resize when necessary to prevent it from getting clipped. Possible values are `horizontal`, `vertical`, and `both`. You can use `autoSizeBoundary` and `auto-size-padding` to customize the behavior of this option. Auto-size works well with `flip`, but if you're using `auto-size-padding` make sure `flip-padding` is the same value.
When using `auto-size`, one or both of `--auto-size-available-width` and `--auto-size-available-height` will be applied to the host element. These values determine the available space the popover has before clipping will occur. Since they cascade, you can use them to set a max-width/height on your popup's content and easily control its overflow.
@@ -638,7 +685,7 @@ Scroll the container to see the popup resize as its available space changes.
```html {.example}
<div class="popup-auto-size">
<div class="overflow">
<wa-popup placement="top" auto-size="both" auto-size-padding="10" active boundary="scroll">
<wa-popup placement="top" auto-size="both" auto-size-padding="10" active>
<span slot="anchor"></span>
<div class="box"></div>
</wa-popup>

View File

@@ -425,3 +425,11 @@ This can be hard to conceptualize, so heres a fairly large example showing how l
</script>
```
<script type="module">
//
// TODO - remove once we switch to the Popover API
//
customElements.whenDefined('wa-select').then(() => {
document.querySelectorAll('wa-code-demo [slot="preview"] wa-select').forEach(select => select.hoist = true);
});
</script>

View File

@@ -129,7 +129,7 @@ Set a matching width and height to make a circle, square, or rounded avatar skel
<style>
.skeleton-avatars wa-skeleton {
display: inline-flex;
display: inline-block;
width: 3rem;
height: 3rem;
margin-right: 0.5rem;

View File

@@ -152,3 +152,25 @@ Use the `--max-width` custom property to change the width the tooltip can grow t
<wa-button id="wrapping-tooltip">Hover me</wa-button>
```
### Hoisting
Tooltips will be clipped if they're inside a container that has `overflow: auto|hidden|scroll`. The `hoist` attribute forces the tooltip to use a fixed positioning strategy, allowing it to break out of the container. In this case, the tooltip will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
```html {.example}
<div class="tooltip-hoist">
<wa-tooltip for="no-hoist">This is a tooltip</wa-tooltip>
<wa-button id="no-hoist">No Hoist</wa-button>
<wa-tooltip for="hoist" hoist>This is a tooltip</wa-tooltip>
<wa-button id="hoist">Hoist</wa-button>
</div>
<style>
.tooltip-hoist {
position: relative;
overflow: hidden;
border: solid 2px var(--wa-color-surface-border);
padding: var(--wa-space-m);
}
</style>
```

View File

@@ -3,7 +3,6 @@ title: Viewport Demo
description: Viewport demos can be used to display an iframe as a resizable, zoomable preview.
tags: component
noAlpha: true
isPro: true
---
```html {.example}

View File

@@ -10,7 +10,7 @@ You can customize the look and feel of Web Awesome at a high level with themes.
Web Awesome uses [themes](/docs/themes) to apply a cohesive look and feel across the entire library. Themes are built with a collection of predefined CSS custom properties, which we call [design tokens](/docs/tokens), and there are many premade themes you can choose from.
To use a theme, simply add a link to the theme's stylesheet to the `<head>` of your page. For example, you can replace the link to `default.css` in the [installation code](/docs/#quick-start-autoloading-via-cdn) with this snippet to use the *Awesome* theme:
To use a theme, simply add a link to the theme's stylesheet to the `<head>` of your page. For example, you can replace the link to `default.css` in the [installation code](/docs/installation/#quick-start-autoloading-via-cdn) with this snippet to use the *Awesome* theme:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/themes/awesome.css' %}" />
@@ -197,7 +197,7 @@ For example, we can give all outlined callouts a thick left border, regardless o
<style>
wa-callout:is(
[appearance~="outlined"],
[appearance~="outlined"],
.wa-outlined
) {
border-left-width: var(--wa-panel-border-radius);

View File

@@ -1,108 +1,10 @@
/**
* Global data for all pages
*/
import { sort } from '../_utils/filters.js';
export default {
eleventyComputed: {
/**
* Default parent slug. Can be overridden by explicitly setting parent in the data.
* It can be either the URL slug of a page in the same directory or a parent directory.
* @returns {string | undefined}
*/
parent(data) {
let { parent, page } = data;
if (parent) {
return parent;
}
return page.url.split('/').filter(Boolean).at(-2);
},
/**
* URL of parent page
* @returns {string | undefined}
*/
parentUrl(data) {
let { parent, page } = data;
return getParentUrl(page.url, parent);
},
/**
* Collection item of parent page
* @returns {object | undefined} Parent page item
*/
parentItem(data) {
let { parentUrl } = data;
return data.collections.all.find(item => item.url === parentUrl);
},
/**
* Child pages of current page
* @returns {object[]} Array of child pages
*/
children(data) {
let { collections, page, parentOf } = data;
let mainTag = data.tags?.[0];
let collection = data.collections[mainTag] ?? [];
if (parentOf) {
return collections[parentOf];
}
let collection = collections.all ?? [];
let url = page.url;
let ret = collection.filter(item => {
return item.data.parentUrl === url;
});
sort(ret);
return ret;
return collection.filter(item => item.data.parent === data.page.fileSlug);
},
},
};
/**
* Resolve a parent slug against a page URL
* @param {string} url - The URL of the page
* @param {string} parent - The slug of the parent page
* @returns {string} The resolved URL of the parent page
*/
function getParentUrl(url, parent) {
if (!parent) {
return undefined;
}
let parts = url.split('/').filter(Boolean);
let ancestorIndex = parts.findLastIndex(part => part === parent);
let retParts = parts.slice();
if (ancestorIndex > -1) {
// parent is an ancestor
retParts.splice(ancestorIndex + 1);
} else {
// parent is a sibling in the same directory
retParts.splice(-1, 1, parent);
}
let ret = retParts.join('/');
if (url.startsWith('/')) {
// If the current page starts with a slash, make sure the parent does too
// This is pretty much always the case with 11ty page URLs
ret = '/' + ret;
}
if (!retParts.at(-1)?.includes('.') && !ret.endsWith('/')) {
// If no extension, make sure to end with a slash
ret += '/';
}
if (ret === '/docs/') {
// We don't want anyone's parent to be "Installation"!
ret = '/';
}
return ret;
}

View File

@@ -1412,8 +1412,7 @@ hasOutline: false
import { registerIconLibrary } from '/dist/webawesome.js';
// Ensure regular icons are always available for the knobs
registerIconLibrary({
name: 'fa-classic-regular',
registerIconLibrary('fa-classic-regular', {
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/regular/${name}.svg`
});
@@ -1454,47 +1453,36 @@ hasOutline: false
break;
case 'premium':
iconFamily.value = 'custom';
registerIconLibrary({
name: 'default',
registerIconLibrary('default', {
resolver: name => `/assets/icons/chunk/${name}.svg`,
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
});
registerIconLibrary({
name: 'system',
registerIconLibrary('system', {
resolver: name => `/assets/icons/chunk/${name}.svg`,
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
});
break;
case 'playful':
iconFamily.value = 'custom';
registerIconLibrary({
name: 'default',
registerIconLibrary('default', {
resolver: name => `/assets/icons/jelly/${name}.svg`,
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
});
registerIconLibrary({
name: 'system',
name: 'system',
name: 'system',
registerIconLibrary('system', {
resolver: name => `/assets/icons/jelly/${name}.svg`,
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
});
break;
caregisterIconLibrary({
registerIconLibrary({
registerIconLibrary({
name: 'default',
case 'brutalist':
iconFamily.value = 'custom';
registerIconLibrary({
name: 'default',
registerIconLibrary('default', {
resolver: name => `/assets/icons/utility/${name}.svg`,
mutator: svg => {
[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));
[...svg.querySelectorAll('[stroke="black"]')].map(el => el.setAttribute('stroke', 'currentColor'));
}
});
registerIconLibrary({
name: 'system',
registerIconLibrary('system', {
resolver: name => `/assets/icons/utility/${name}.svg`,
mutator: svg => {
[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));
@@ -1509,12 +1497,10 @@ hasOutline: false
break;
case 'classic':
iconFamily.value = 'custom';
registerIconLibrary({
name: 'default',
registerIconLibrary('default', {
resolver: name => `/assets/icons/bootstrap/${name}.svg`,
});
registerIconLibrary({
name: 'system',
registerIconLibrary('system', {
resolver: name => `/assets/icons/bootstrap/${name}.svg`,
});
break;
@@ -1545,8 +1531,7 @@ hasOutline: false
iconLibrary = 'sharp-solid';
}
// Ensures sharp-solid variations are available for ratings, etc.
registerIconLibrary({
name: 'always-solid',
registerIconLibrary('always-solid', {
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/sharp-solid/${name}.svg`
});
solidifyRatingStars();
@@ -1572,18 +1557,15 @@ hasOutline: false
iconLibrary = 'solid';
}
// Ensures solid variations are available for radios, ratings, etc.
registerIconLibrary({
name: 'always-solid',
registerIconLibrary('always-solid', {
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/solid/${name}.svg`
});
solidifyRatingStars();
}
registerIconLibrary({
name: 'default',
registerIconLibrary('default', {
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/${iconLibrary}/${name}.svg`
});
registerIconLibrary({
name: 'system',
registerIconLibrary('system', {
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/${iconLibrary}/${name}.svg`
});
};

View File

@@ -32,11 +32,15 @@ To get everything included in Web Awesome, add the following code to the `<head>
This snippet includes three parts:
1. **The default theme**, a stylesheet that gives a cohesive look to Web Awesome components with both light and dark modes
2. **Web Awesome styles**, an optional stylesheet that [styles native HTML elements](/docs/native) and includes [utility classes](/docs/utilities) you can use in your project
2. **Web Awesome styles**, an optional stylesheet that [styles native HTML elements](/docs/native) and includes [utility classes](/docs/utilities) you can use in your project
3. **The autoloader**, a lightweight script watches the DOM for unregistered Web Awesome elements and lazy loads them for you — even if they're added dynamically
Now you can [start using Web Awesome!](/docs/usage)
:::info
While convenient, autoloading may lead to a [Flash of Undefined Custom Elements](https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/). The linked article describes some ways to alleviate it.
:::
---
## Using Font Awesome Kit Codes
@@ -58,7 +62,7 @@ Font Awesome users can set their kit code to unlock Font Awesome Pro icons. You
## Advanced Setup
The autoloader is the easiest way to use Web Awesome, but different projects (or your own preferences!) may require different installation methods.
The autoloader is the easiest way to use Web Awesome, but different projects (or your own preferences!) may require different installation methods.
### Installing via npm
@@ -122,4 +126,4 @@ Most of the magic behind assets is handled internally by Web Awesome, but if you
// Get the path to an asset, e.g. /path/to/assets/file.ext
const assetPath = getBasePath('file.ext');
</script>
```
```

View File

@@ -2,7 +2,6 @@
title: Layout
description: Layout components and utility classes help you organize content that can adapt to any device or screen size. See the [installation instructions](#installation) to use Web Awesome's layout tools in your project.
layout: overview
parentOf: layout
categories: ["components", "utilities"]
override:tags: []
---
@@ -10,7 +9,7 @@ override:tags: []
{% markdown %}
## Installation
Layout components are included in Web Awesome's [autoloader](/docs/#quick-start-autoloading-via-cdn). You can also import them individually via [cherry picking](/docs/#cherry-picking).
Layout components are included in Web Awesome's [autoloader](/docs/installation/#quick-start-autoloading-via-cdn). You can also import them individually via [cherry picking](/docs/installation/#cherry-picking).
Layout utilities are bundled with all [style utilities](/docs/utilities). You can import all Web Awesome page styles (including [native styles](/docs/native/)) by including the following stylesheet in your project:
@@ -23,4 +22,4 @@ Or, you can choose to import _only_ the utilities:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/utilities.css' %}" />
```
{% endmarkdown %}
{% endmarkdown %}

View File

@@ -33,7 +33,7 @@ Use the [variant utility classes](../utilities/color.md) to set the button's sem
### Appearance
Use the [appearance utility classes](/docs/utilities/appearance) to change the button's visual appearance:
Use the [appearance utility classes](../utilities/appearance.md) to change the button's visual appearance:
```html {.example}
<div style="margin-block-end: 1rem;">

View File

@@ -57,7 +57,7 @@ Use the [variant utility classes](../utilities/color.md) to set the callout's co
### Appearance
Use the [appearance utility classes](/docs/utilities/appearance) to change the callout's visual appearance (the default is `outlined filled`).
Use the [appearance utility classes](../utilities/appearance.md) to change the callout's visual appearance (the default is `outlined filled`).
```html {.example}
<article class="wa-callout wa-brand wa-outlined wa-accent">

View File

@@ -19,35 +19,6 @@ file: styles/native/details.css
## Examples
### Appearance
Use the [appearance utility classes](/docs/utilities/appearance) to change the element's visual appearance:
```html {.example}
<div class="wa-stack">
<details>
<summary>Outlined (default)</summary>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</details>
<details class="wa-filled">
<summary>Filled</summary>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</details>
<details class="wa-filled wa-outlined">
<summary>Filled + Outlined</summary>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</details>
<details class="wa-plain">
<summary>Plain</summary>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</details>
</div>
```
### Right-to-Left Languages
The details styling automatically adapts to right-to-left languages:

View File

@@ -11,8 +11,8 @@ file: styles/native/radio.css
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="a" value="1" checked> Option 1</label>
<label><input type="radio" name="a" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
</div>
```
@@ -24,9 +24,9 @@ To set the initial value and checked state, use the `checked` attribute on the c
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="b" value="1" checked> Option 1</label>
<label><input type="radio" name="b" value="2"> Option 2</label>
<label><input type="radio" name="b" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
</div>
```
@@ -36,9 +36,9 @@ Use the `disabled` attribute to disable a radio.
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="c" value="1" checked> Option 1</label>
<label><input type="radio" name="c" value="2" disabled> Option 2</label>
<label><input type="radio" name="c" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2" disabled> Option 2</label>
<label><input type="radio" name="radio" value="3"> Option 3</label>
</div>
```
@@ -49,26 +49,26 @@ Use the [size utilities](/docs/utilities/size) to change the radios' size.
```html {.example}
<fieldset class="wa-size-s wa-cluster">
<legend>Small</legend>
<label><input type="radio" name="d" value="1" checked> Option 1</label>
<label><input type="radio" name="d" value="2"> Option 2</label>
<label><input type="radio" name="d" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="3"> Option 3</label>
</fieldset>
<br />
<fieldset class="wa-size-m wa-cluster">
<legend>Medium</legend>
<label><input type="radio" name="e" value="1" checked> Option 1</label>
<label><input type="radio" name="e" value="2"> Option 2</label>
<label><input type="radio" name="e" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="3"> Option 3</label>
</fieldset>
<br />
<fieldset class="wa-size-l wa-cluster">
<legend>Large</legend>
<label><input type="radio" name="f" value="1" checked> Option 1</label>
<label><input type="radio" name="f" value="2"> Option 2</label>
<label><input type="radio" name="f" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="3"> Option 3</label>
</fieldset>
```
@@ -78,16 +78,16 @@ You can wrap native radios in a flex container to give them a horizontal or vert
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="g" value="1" checked> Option 1</label>
<label><input type="radio" name="g" value="2"> Option 2</label>
<label><input type="radio" name="g" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
</div>
```
```html {.example}
<div class="wa-stack">
<label><input type="radio" name="h" value="1" checked> Option 1</label>
<label><input type="radio" name="h" value="2"> Option 2</label>
<label><input type="radio" name="h" value="3"> Option 3</label>
<label><input type="radio" name="radio" value="1"> Option 1</label>
<label><input type="radio" name="radio" value="2"> Option 2</label>
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
</div>
```

View File

@@ -5,6 +5,6 @@ layout: overview
override:tags: []
forTag: palette
categories:
tags: [other, pro]
other: Free
pro: Pro
---

View File

@@ -6,8 +6,6 @@ import { cssImport, cssLiteral, cssRule } from '../../assets/scripts/tweak/code.
import { maxGrayChroma, moreHue, selectors, urls } from '../../assets/scripts/tweak/data.js';
import { subtractAngles } from '../../assets/scripts/tweak/util.js';
import Prism from '/assets/scripts/prism.js';
import content from '/assets/scripts/vue/directives/content.js';
import savedMixin from '/assets/scripts/vue/mixins/saved.js';
await Promise.all(['wa-slider'].map(tag => customElements.whenDefined(tag)));
@@ -40,25 +38,24 @@ for (let palette in allPalettes) {
const percentFormatter = value => value.toLocaleString(undefined, { style: 'percent' });
let paletteAppSpec = {
mixins: [savedMixin],
data() {
let appRoot = document.querySelector('#palette-app');
let id = appRoot.dataset.paletteId;
let palette = allPalettes[id];
let paletteId = appRoot.dataset.paletteId;
let palette = allPalettes[paletteId];
return {
id,
originalTitle: palette.title,
uid: undefined,
paletteId,
paletteTitle: palette.title,
originalColors: palette.colors,
permalink: new Permalink(),
hueRanges,
hueShifts: Object.fromEntries(hues.map(hue => [hue, 0])),
chromaScale: 1,
grayChroma: undefined,
grayColor: undefined,
tweaking: {},
type: 'palette',
collection: 'palettes',
saved: null,
};
},
@@ -66,16 +63,20 @@ let paletteAppSpec = {
// Non-reactive variables to expose
Object.assign(this, { moreHue });
// Read URL params and apply them. This facilitates permalinks.
this.permalink.mapObject(this.hueShifts, {
keyTo: key => key.replace(/-shift$/, ''),
keyFrom: key => key + '-shift',
valueFrom: value => (!value ? '' : Number(value)),
valueTo: value => (!value ? 0 : Number(value)),
});
this.grayChroma = this.originalGrayChroma;
this.grayColor = this.originalGrayColor;
if (location.search) {
// Read URL params and apply them. This facilitates permalinks.
for (let hue in this.hueShifts) {
if (this.permalink.has(hue + '-shift')) {
this.hueShifts[hue] = Number(this.permalink.get(hue + '-shift'));
}
}
// Update from URL
this.permalink.writeTo(this.hueShifts);
for (let param of ['chroma-scale', 'gray-color', 'gray-chroma']) {
if (this.permalink.has(param)) {
@@ -90,6 +91,12 @@ let paletteAppSpec = {
this[prop] = value;
}
}
if (this.permalink.has('uid')) {
this.uid = Number(this.permalink.get('uid'));
}
this.saved = sidebar.palette.getSaved(this.getPalette());
}
},
@@ -100,11 +107,6 @@ let paletteAppSpec = {
},
computed: {
/** Default palette title for saving */
defaultTitle() {
return this.originalTitle + ' (tweaked)';
},
tweaks() {
return {
hueShifts: this.hueShifts,
@@ -121,7 +123,7 @@ let paletteAppSpec = {
code() {
let ret = {};
for (let language of ['html', 'css']) {
let code = getPaletteCode(this.id, this.colors, this.tweaked, { language, cdnUrl });
let code = getPaletteCode(this.paletteId, this.colors, this.tweaked, { language, cdnUrl });
ret[language] = {
raw: code,
highlighted: Prism.highlight(code, Prism.languages[language], language),
@@ -282,9 +284,7 @@ let paletteAppSpec = {
hueShifts: {
deep: true,
handler() {
for (let hue in this.hueShifts) {
this.permalink.set(hue + '-shift', this.hueShifts[hue], 0);
}
this.permalink.readFrom(this.hueShifts);
},
},
@@ -308,12 +308,69 @@ let paletteAppSpec = {
// Update page URL
this.permalink.updateLocation();
this.unsavedChanges = true;
if (this.saved) {
this.save({ silent: true });
}
},
},
},
methods: {
getPalette() {
return { id: this.paletteId, uid: this.uid, search: location.search };
},
save({ silent } = {}) {
let title = silent
? (this.saved?.title ?? this.paletteTitle)
: prompt('Palette title:', `${this.paletteTitle} (tweaked)`);
if (!title) {
return;
}
let uid = this.uid;
if (!uid) {
// First time saving
this.uid = uid = sidebar.palette.getUid();
this.permalink.set('uid', uid);
this.permalink.updateLocation();
}
let palette = { ...this.getPalette(), uid, title };
sidebar.palette.save(palette, this.saved);
this.saved = palette;
},
rename() {
if (!this.saved) {
return;
}
let newTitle = prompt('New title:', this.saved.title);
if (!newTitle) {
return;
}
this.saved.title = newTitle;
sidebar.palette.save(this.saved);
},
deleteSaved() {
sidebar.palette.delete(this.saved);
},
postDelete() {
this.saved = null;
this.permalink.delete('uid');
this.uid = undefined;
this.permalink.updateLocation();
},
/**
* Remove a specific tweak or all tweaks
* @param {string} [param] - The tweak to remove. If not provided, all tweaks are removed.
@@ -342,7 +399,28 @@ let paletteAppSpec = {
},
directives: {
content,
// Like v-text, but doesn't complain if the element has content,
// making it possible to use in a PE fashion, with the contents being the fallback
content(el, { value, arg }) {
if (!el.dataset.fallback) {
// Store the original content as a fallback the first time
el.dataset.fallback = el.textContent;
}
if (value === '') {
value = el.dataset.fallback;
} else {
if (arg === 'number') {
value = Number(value).toLocaleString(undefined, { maximumSignificantDigits: 2 });
}
}
if (arg === 'html') {
el.innerHTML = value;
} else {
el.textContent = value;
}
},
},
compilerOptions: {

View File

@@ -1,70 +1,43 @@
---
title: Action Panel
description: 'Help users complete tasks efficiently with quick access to key actions.'
icon: action-panel
isPro: true
description: 'These patterns help add user actions to dashboards'
parent: app
tags: app
---
## Examples
## Simple
### Simple
```html {.example}
<wa-card style="max-width: 60ch; margin: auto">
<div class="wa-stack wa-align-items-start">
<wa-card style="max-width: 480px; margin: 0 auto;">
<div class="wa-align-items-start wa-stack wa-gap-xs">
<h3 class="wa-heading-m">New Dashboard</h3>
<p>Arrange your data into a single view to monitor trends and track performance.</p>
<wa-button variant="brand" size="small">Build Dashboard</wa-button>
<p>Arrange your data into a single view.</p>
<wa-button variant="brand">Build Dashboard</wa-button>
</div>
</wa-card>
```
## With Flanked Button
### with right flank
```html {.example}
<wa-card style="max-width: 60ch; margin: auto">
<wa-card style="max-width: 960px; margin: 0 auto;">
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-m">Query with SQL Runner</h3>
<p>Access your database to run ad hoc queries.</p>
<h3 class="wa-heading-m">Query with the SQL Runner</h3>
<p>Access your database to run ad-hoc queries.</p>
</div>
<wa-button variant="brand" size="small">New Query</wa-button>
<wa-button appearance="outlined">New Query</wa-button>
</div>
</wa-card>
```
## With Switch
### with switch
```html {.example}
<wa-card style="max-width: 70ch; margin: auto">
<div class="wa-stack">
<div class="wa-flank:end">
<h3 id="auto-renew-label" class="wa-heading-m">Auto-renew</h3>
<wa-switch size="large" aria-labelledby="auto-renew-label"></wa-switch>
</div>
<p class="wa-body-s">Automatically renew your subscription using your preferred payment method. We'll send you a reminder 30 days before we draft your account.</p>
</div>
</wa-card>
```
## Avatar and Quick actions
```html {.example}
<wa-card style="margin: 0 auto; max-width: 45ch;">
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1532202802379-df93d543bac3?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile-image"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Super Dog</span>
<div class="wa-caption-m wa-cluster wa-gap-xs">
<span>Online</span>
<wa-icon name="circle" style="color: var(--wa-color-green); font-size: 10px;"></wa-icon>
</div>
</div>
<div class="wa-cluster" style="font-size: var(--wa-font-size-l);">
<wa-icon-button name="microphone" label="audio-input"></wa-icon-button>
<wa-icon-button name="headphones" label="audio-output"></wa-icon-button>
<wa-icon-button name="gear" label="settings"></wa-icon-button>
</div>
<wa-card style="max-width: 960px; margin: 0 auto;">
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-m">Auto-renew</h3>
<p>We'll send you a reminder 30 days before we draft your account.</p>
</div>
<wa-switch size="large"></wa-switch>
</div>
</wa-card>
```

View File

@@ -1,336 +0,0 @@
---
title: Activity Log
description: 'Track and organize recent user actions or events.'
---
## Simple
```html {.example}
<div class="wa-stack" style="max-width: 60ch; margin: auto">
<article class="wa-flank:end wa-align-items-baseline" style="--flank-size: 10ch">
<div class="wa-grid">
<div class="wa-cluster">
<wa-icon name="french-fries" fixed-width></wa-icon>
<span>Fast food</span>
</div>
<wa-relative-time sync></wa-relative-time>
</div>
<wa-tag variant="danger">- $5.00</wa-tag>
</article>
<wa-divider></wa-divider>
<article class="wa-flank:end wa-align-items-baseline" style="--flank-size: 10ch">
<div class="wa-grid">
<div class="wa-cluster">
<wa-icon name="piggy-bank" fixed-width></wa-icon>
<span>Refund</span>
</div>
<wa-relative-time date="2025-03-26T09:00:00-04:00"></wa-relative-time>
</div>
<wa-tag variant="success">+ $48.99</wa-tag>
</article>
<wa-divider></wa-divider>
<article class="wa-flank:end wa-align-items-baseline" style="--flank-size: 10ch">
<div class="wa-grid">
<div class="wa-cluster">
<wa-icon name="carrot" fixed-width></wa-icon>
<span>Groceries</span>
</div>
<wa-relative-time date="2025-03-24T09:00:00-04:00"></wa-relative-time>
</div>
<wa-tag variant="danger">- $115.37</wa-tag>
</article>
<wa-divider></wa-divider>
<article class="wa-flank:end wa-align-items-baseline" style="--flank-size: 10ch">
<div class="wa-grid">
<div class="wa-cluster">
<wa-icon name="shirt" fixed-width></wa-icon>
<span>Clothing</span>
</div>
<wa-relative-time date="2025-03-15T09:00:00-04:00"></wa-relative-time>
</div>
<wa-tag variant="danger">- $220.99</wa-tag>
</article>
</div>
```
## Timeline with Icons
```html {.example}
<div class="wa-stack wa-gap-3xs" style="max-width: 60ch; margin: auto">
<article class="wa-flank" style="flex-wrap: nowrap">
<wa-avatar style="--size: 2rem">
<wa-icon slot="icon" name="acorn"></wa-icon>
</wa-avatar>
<div class="wa-flank:end wa-gap-xs">
<span>Buried by <strong>squirrel</strong></span>
<wa-format-date date="2025-04-01" month="short" day="numeric"></wa-format-date>
</div>
</article>
<wa-divider vertical style="height: 1em; margin-left: 1rem"></wa-divider>
<article class="wa-flank" style="flex-wrap: nowrap">
<wa-avatar style="--size: 2rem">
<wa-icon slot="icon" name="seedling"></wa-icon>
</wa-avatar>
<div class="wa-flank:end wa-gap-xs">
<span>Germinated in <strong>nutrient-rich soil</strong></span>
<wa-format-date date="2025-05-29" month="short" day="numeric"></wa-format-date>
</div>
</article>
<wa-divider vertical style="height: 1em; margin-left: 1rem"></wa-divider>
<article class="wa-flank" style="flex-wrap: nowrap">
<wa-avatar style="--size: 2rem">
<wa-icon slot="icon" name="tree-deciduous"></wa-icon>
</wa-avatar>
<div class="wa-flank:end wa-gap-xs">
<span>Matured by <strong>water</strong> and <strong>sunlight</strong></span>
<wa-format-date date="2025-09-15" month="short" day="numeric"></wa-format-date>
</div>
</article>
<wa-divider vertical style="height: 1em; margin-left: 1rem"></wa-divider>
<article class="wa-flank" style="flex-wrap: nowrap">
<wa-avatar style="--size: 2rem">
<wa-icon slot="icon" name="crate-apple"></wa-icon>
</wa-avatar>
<div class="wa-flank:end wa-gap-xs">
<span>Fruit harvested by <strong>you</strong></span>
<wa-format-date date="2025-10-18" month="short" day="numeric"></wa-format-date>
</div>
</article>
</div>
```
## With Expandable Details
```html {.example}
<wa-card style="max-width: 70ch; margin: auto">
<h3 class="wa-heading-m">Monthly Activity</h3>
<div class="wa-stack">
<wa-details>
<span class="wa-heading-m" slot="summary">
February
</span>
<div class="wa-stack">
<article class="wa-flank">
<wa-icon style="font-size: var(--wa-font-size-l)" name="envelope" fixed-width></wa-icon>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Email blasts</span>
<div class="wa-cluster wa-gap-2xs">
<a href="#">Nick Burkhart</a><span>sent to</span><a href="#">likely customers</a>
</div>
</div>
<wa-format-date date="2025-02-28" month="short" day="numeric" class="wa-caption-m"></wa-format-date>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank">
<wa-icon style="font-size: var(--wa-font-size-l)" name="phone" fixed-width></wa-icon>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Spoke with the Pope</span>
<div class="wa-cluster wa-gap-2xs">
<a href="#">Artur Fleck</a><span>for 1 hour</span>
</div>
</div>
<wa-format-date date="2025-02-23" month="short" day="numeric" class="wa-caption-m"></wa-format-date>
</div>
</article>
</div>
</wa-details>
<wa-details>
<span class="wa-heading-m" slot="summary">
March
</span>
<div class="wa-stack">
<article class="wa-flank">
<wa-icon style="font-size: var(--wa-font-size-l)" name="video" fixed-width></wa-icon>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Zoom Call with Northeast office</span>
<div class="wa-cluster wa-gap-2xs">
<a href="#">Axel Foley</a><span>for 47 minutes</span>
</div>
</div>
<wa-format-date date="2025-03-15" month="short" day="numeric" class="wa-caption-m"></wa-format-date>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank">
<wa-icon style="font-size: var(--wa-font-size-l)" name="calendar" fixed-width></wa-icon>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Scheduled birthday party</span>
<div class="wa-cluster wa-gap-2xs">
<a href="#">John Blaze</a><span>in</span><a href="#">Social Events</a>
</div>
</div>
<wa-format-date date="2025-03-03" month="short" day="numeric" class="wa-caption-m"></wa-format-date>
</div>
</article>
</div>
</wa-details>
<wa-details>
<span class="wa-heading-m" slot="summary">
April
</span>
<div class="wa-stack">
<article class="wa-flank">
<wa-icon style="font-size: var(--wa-font-size-l)" family="brands" name="intercom" fixed-width></wa-icon>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Got new lead</span>
<div class="wa-cluster wa-gap-2xs">
<a href="#">Jack Carter</a><span>on Intercom switchboard</span>
</div>
</div>
<wa-format-date date="2025-04-18" month="short" day="numeric" class="wa-caption-m"></wa-format-date>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank">
<wa-icon style="font-size: var(--wa-font-size-l)" name="list-check" fixed-width></wa-icon>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Completed Todo</span>
<div class="wa-cluster wa-gap-2xs">
<a href="#">Huey Freeman</a><span>marked complete on</span><a href="#">Daily Tasks</a>
</div>
</div>
<wa-format-date date="2025-04-02" month="short" day="numeric" class="wa-caption-m"></wa-format-date>
</div>
</article>
</div>
</wa-details>
</div>
</wa-card>
```
## Card Separated
```html {.example}
<div class="wa-stack" style="max-width: 45ch; margin: 0 auto;">
<div class="wa-stack">
<wa-card>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1559188286-a173792c8340?q=80&w=2906&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-stack wa-gap-0">
<div class="wa-split">
<span class="wa-heading-s">Isaiah Hamilton</span>
<wa-relative-time class="wa-caption-s" date="2025-01-15T09:17:00-04:00"></wa-relative-time>
</div>
<p>Who's on first?</p>
<a href="#" class="wa-cluster wa-gap-2xs">
<wa-icon name="reply" family="sharp" variant="regular"></wa-icon>
<span>Reply</span>
</a>
</div>
</div>
</wa-card>
<div class="wa-flank wa-gap-xl">
<wa-divider vertical style="height: auto; align-self: stretch"></wa-divider>
<ul class="wa-stack">
<li class="wa-stack wa-gap-2xs">
<wa-card>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1645288059073-af3e9eb62a29?q=80&w=2936&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-stack wa-gap-0">
<div class="wa-split">
<span class="wa-heading-s">Melvin Hurst</span>
<wa-relative-time class="wa-caption-s" date="2025-02-15T09:17:00-04:00"></wa-relative-time>
</div>
<p>What's on second?</p>
<a href="#" class="wa-cluster wa-gap-2xs">
<wa-icon name="reply" family="sharp" variant="regular"></wa-icon>
<span>Reply</span>
</a>
</div>
</div>
</wa-card>
</li>
<li class="wa-stack wa-gap-2xs">
<wa-card>
<div class="wa-flank wa-align-items-start">
<wa-avatar image="https://images.unsplash.com/photo-1674044494331-8db2ecf18d46?q=80&w=3019&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-stack wa-gap-xs">
<div class="wa-split">
<span class="wa-heading-s">Vanessa Wright</span>
</div>
<wa-textarea size="small" aria-label="Add Your Comment"></wa-textarea>
</div>
</div>
</wa-card>
</li>
</ul>
</div>
</div>
</div>
```
## Divider Separated
```html {.example}
<wa-card with-header style="max-width: 54ch; margin: 0 auto;">
<div slot="header" class="wa-split">
<div>
<span>Notifications</span>
<wa-badge appearance="filled" variant="success" pill>2</wa-badge>
</div>
<wa-icon name="close"></wa-icon>
</div>
<div class="wa-stack">
<article>
<div class="wa-flank wa-align-items-start">
<wa-avatar image="https://images.unsplash.com/photo-1614807547811-4174d3582092?q=80&w=2932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split">
<span><strong>Happy</strong> commented in <a href="#">Reporting Dashboard</a></span>
<wa-icon name="circle" style="color: var(--wa-color-green);"></wa-icon>
</div>
<div class="wa-split">
<span class="wa-caption-m">Friday 3:12PM</span>
<wa-relative-time class="wa-caption-m" date="2025-02-15T09:17:00-04:00"></wa-relative-time>
</div>
<wa-callout variant="neutral">
Really love this approach. I think this is the best solution for the sync issue.
</wa-callout>
</div>
</div>
<wa-divider></wa-divider>
</article>
<article>
<div class="wa-flank wa-align-items-start">
<wa-avatar image="https://images.unsplash.com/photo-1613428800237-c86372070fab?q=80&w=3017&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split">
<span><strong>Charlotte</strong> followed you</span>
<wa-icon name="circle" style="color: var(--wa-color-green);"></wa-icon>
</div>
<div class="wa-split">
<span class="wa-caption-m">Friday 3:04PM</span>
<wa-relative-time class="wa-caption-m" date="2025-02-15T09:17:00-04:00"></wa-relative-time>
</div>
</div>
</div>
<wa-divider></wa-divider>
</article>
<article>
<div class="wa-flank wa-align-items-start">
<wa-avatar image="https://images.unsplash.com/photo-1645288059073-af3e9eb62a29?q=80&w=2936&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Profile image"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split">
<span><strong>Tavitian</strong> invited you to <a href="#">Homepage Redesign</a></span>
</div>
<div class="wa-split">
<span class="wa-caption-m">Friday 2:22PM</span>
<wa-relative-time class="wa-caption-m" date="2025-02-15T09:17:00-04:00"></wa-relative-time>
</div>
<div class="wa-cluster wa-gap-xs">
<wa-button appearance="outlined" size="small">Decline</wa-button>
<wa-button variant="brand" size="small">Accept</wa-button>
</div>
</div>
</div>
<wa-divider></wa-divider>
</article>
</div>
</wa-card>
```

View File

@@ -1,3 +0,0 @@
{
"tags": ["app"]
}

View File

@@ -1,165 +1,75 @@
---
title: Comments
description: 'Enable users to engage in discussions, provide feedback, or record their thoughts.'
isPro: true
description: 'For feedback forms and message boxes'
parent: app
tags: app
---
## Examples
## Card with Header & Footer
```html {.example}
<form style="max-width: 60ch; margin: auto">
<wa-card>
<div slot="header" id="comment-area-label">
<span class="wa-heading-s">Leave a Comment</span>
</div>
<wa-textarea aria-labelledby="comment-area-label"></wa-textarea>
<div slot="footer" class="wa-cluster" style="justify-content: flex-end">
<wa-button appearance="filled" size="small">
### In card with footer
```html{.example}
<form class="comment-box" style="max-width: 960px; margin: 0 auto;">
<wa-card with-footer>
<wa-textarea resize="horizontal"></wa-textarea>
<div slot="footer" class="wa-cluster" style="justify-content: flex-end;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="paperclip" variant="solid"></wa-icon>
Attach a file
</wa-button>
<wa-button variant="brand" size="small">Comment</wa-button>
<wa-button variant="success">Comment</wa-button>
</div>
</wa-card>
</form>
```
## Card with Thread
```html {.example}
<wa-card style="max-width: 60ch; margin: auto">
<div class="wa-stack">
<h3 class="wa-heading-m">Comments</h3>
<wa-textarea aria-label="Comment"></wa-textarea>
<wa-button variant="brand">Add Comment</wa-button>
<wa-divider></wa-divider>
<ul class="wa-stack">
<li class="wa-stack wa-gap-2xs">
<div class="wa-flank">
<wa-avatar initials="RF" label="User avatar"></wa-avatar>
<div class="wa-cluster">
<strong>Robert Fox</strong>
<span class="wa-caption-m">commented <wa-relative-time date="2025-03-31T09:17:00-04:00"></wa-relative-time></span>
</div>
### with avatar and icon buttons
```html{.example}
<div class="wa-callout wa-neutral wa-outlined" style="max-width: 960px; margin: 0 auto;">
<div class="wa-align-items-start wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="User avatar"></wa-avatar>
<div class="wa-stack wa-gap-s">
<wa-textarea placeholder="Add to the conversation..." size="medium"></wa-textarea>
<div class="wa-split">
<div>
<wa-icon-button name="link" variant="solid" label="Bold"></wa-icon-button>
<wa-icon-button name="face-smile" variant="solid" label="Italic"></wa-icon-button>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras convallis mollis nunc, vel tempor sem faucibus nec. Suspendisse potenti. Pellentesque lobortis pulvinar nulla non tempor. Interdum et malesuada fames ac ante ipsum primis in faucibus.</p>
</li>
<div class="wa-flank wa-gap-xl">
<wa-divider vertical style="height: auto; align-self: stretch"></wa-divider>
<ul class="wa-stack">
<li class="wa-stack wa-gap-2xs">
<div class="wa-flank">
<wa-avatar initials="VF" label="User avatar"></wa-avatar>
<div class="wa-cluster">
<strong>Virginia Woolf</strong>
<span class="wa-caption-m">commented <wa-relative-time date="2025-03-31T12:32:00-04:00"></wa-relative-time></span>
</div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras convallis mollis nunc, vel tempor sem faucibus nec.</p>
</li>
<li class="wa-stack wa-gap-2xs">
<div class="wa-flank">
<wa-avatar initials="CV" label="User avatar"></wa-avatar>
<div class="wa-cluster">
<strong>Clarissa Vaughan</strong>
<span class="wa-caption-m">commented <wa-relative-time></wa-relative-time></span>
</div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras convallis mollis nunc, vel tempor sem faucibus nec.</p>
</li>
<li class="wa-cluster">
<wa-icon name="reply"></wa-icon>
<a href="">Leave a reply</a>
</li>
</ul>
</wa-button><wa-button>Comment</wa-button>
</div>
</ul>
</div>
</wa-card>
```
## With Avatar & Additional Actions
```html {.example}
<div class="wa-align-items-start wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="User avatar"></wa-avatar>
<div class="wa-stack wa-gap-s">
<wa-textarea placeholder="Add to the conversation..." aria-label="Add comment"></wa-textarea>
<div class="wa-split">
<div class="wa-cluster wa-gap-s">
<wa-icon-button name="paperclip" label="Attach File" id="attach-button"></wa-icon-button>
<wa-tooltip for="attach-button">Attach File</wa-tooltip>
<wa-icon-button name="face-smile" label="Add Sticker" id="sticker-button"></wa-icon-button>
<wa-tooltip for="sticker-button">Add Sticker</wa-tooltip>
</div>
<wa-button variant="brand">Comment</wa-button>
</div>
</div>
</div>
```
## Rich Card with Multiple Actions
### With multiple actions
```html {.example}
<wa-card with-header with-footer style="max-width: 60ch; margin: auto">
```html{.example}
<wa-card with-header with-footer style="max-width: 640px; margin: 0 auto;">
<div slot="header">
<h3 class="wa-heading-s">I watched...</h3>
<h2 class="wa-heading-s">I watched...</h2>
</div>
<div class="wa-stack">
<div class="wa-flank" style="--flank-size: 3rem">
<div class="wa-frame:portrait wa-border-radius-s">
<img
src="https://images.unsplash.com/photo-1607675742178-f616ae75044b?q=80&w=3435&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="the cover image for the film"
/>
<div class="wa-flank">
<div>
<img src="https://a.ltrbxd.com/resized/film-poster/1/0/2/5/3/3/1/1025331-heretic-2024-0-1000-0-1500-crop.jpg?v=c79c5c8121" width="40"/>
</div>
<span class="wa-heading-l">Heretic</span>
<span class="wa-heading-l">Heretic</span>
</div>
<wa-divider></wa-divider>
<dl class="wa-split">
<dt>Date</dt>
<dd>
<wa-format-date date="2025-03-13T00:00:00.000-04:00" weekday="long" month="long" day="numeric" year="numeric" class="wa-caption-m"></wa-format-date>
</dd>
</dl>
<div class="wa-split">
<span class="wa-heading-s">Date</span><span class="wa-caption-m">Thursday, March 13, 2025</span>
</div>
<wa-divider></wa-divider>
<div class="wa-split">
<wa-rating label="Rating"></wa-rating>
<wa-checkbox>Loved it!</wa-checkbox>
</div>
<wa-divider></wa-divider>
<wa-textarea placeholder="Add review..." aria-label="Add review"></wa-textarea>
<wa-textarea placeholder="Add review..."></wa-textarea>
</div>
<div slot="footer" class="wa-grid">
<wa-button appearance="outlined">Cancel</wa-button>
<wa-button variant="brand">Save</wa-button>
</div>
</wa-card>
```
## With Preview Pane
```html{.example}
<div style="max-width: 60ch; margin: 0 auto;">
<wa-card class="wa-border-radius-square" with-footer>
<h3 class="wa-heading-m">Add a comment</h3>
<wa-tab-group>
<wa-tab panel="write">Write</wa-tab>
<wa-tab panel="preview">Preview</wa-tab>
<wa-tab-panel name="write">
<div class="wa-stack">
<div class="wa-cluster wa-gap-xs" style="justify-content: flex-end;">
<wa-icon-button name="link" label="add link"></wa-icon-button>
<wa-icon-button name="at" label="mention collaborator"></wa-icon-button>
<wa-icon-button name="hashtag" label="change heading"></wa-icon-button>
</div>
<wa-textarea aria-label="Add a comment"></wa-textarea>
</div>
</wa-tab-panel>
<wa-tab-panel name="preview">Your content will render here.</wa-tab-panel>
</wa-tab-group>
<div slot="footer" class="wa-cluster" style="justify-content: flex-end;">
<wa-button appearance="outlined" size="small">Post</wa-button>
</div>
</wa-card>
</div>
```

View File

@@ -1,117 +1,53 @@
---
title: Data Display
description: 'Convey insights, metrics, and aggregate data at a glance.'
isPro: true
description: TODO
parent: app
tags: app
---
## Examples
### With icon
## Simple
```html {.example}
<wa-card>
<div class="wa-grid wa-gap-3xl" style="--min-column-size: 24ch;">
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster wa-gap-xs">
<wa-icon name="sack-dollar"></wa-icon>
<span>Incomes</span>
</div>
<div class="wa-cluster wa-gap-xs" style="color: var(--wa-color-green);">
<wa-icon name="arrow-trend-up"></wa-icon>
<wa-format-number class="wa-heading-s" type="percent" value=".475"></wa-format-number>
</div>
</div>
<wa-format-number class="wa-heading-xl" type="currency" currency="USD" value="175000000" lang="en-US"></wa-format-number>
</div>
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster wa-gap-xs">
<wa-icon name="credit-card"></wa-icon>
<span>Expenses</span>
</div>
<div class="wa-cluster wa-gap-xs" style="color: var(--wa-color-red);">
<wa-icon name="arrow-trend-down"></wa-icon>
<wa-format-number class="wa-heading-s" type="percent" value=".27"></wa-format-number>
</div>
</div>
<wa-format-number class="wa-heading-xl" class="wa-heading-xl" type="currency" currency="USD" value="289472" lang="en-US"></wa-format-number>
</div>
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster wa-gap-xs">
<wa-icon name="seedling"></wa-icon>
<span>Investments</span>
</div>
<div class="wa-cluster wa-gap-xs" style="color: var(--wa-color-green);">
<wa-icon name="arrow-trend-up"></wa-icon>
<wa-format-number class="wa-heading-s" type="percent" value=".14"></wa-format-number>
</div>
</div>
<wa-format-number class="wa-heading-xl" class="wa-heading-xl" type="currency" currency="USD" value="569213" lang="en-US"></wa-format-number>
</div>
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster wa-gap-xs">
<wa-icon name="landmark"></wa-icon>
<span>Mortgages & Loans</span>
</div>
</div>
<wa-format-number class="wa-heading-xl" class="wa-heading-xl" type="currency" currency="USD" value="23904" lang="en-US"></wa-format-number>
</div>
</div>
</wa-card>
```
## Cards with Avatars
```html {.example}
<div class="wa-grid" style="--min-column-size: 30ch">
```html{.example}
<div class="wa-grid" style="max-width: 960px; margin: 0 auto">
<wa-card>
<div class="wa-flank wa-align-items-start">
<wa-avatar shape="rounded">
<wa-icon slot="icon" name="user-group"></wa-icon>
<div class="wa-flank">
<wa-avatar shape="square" label="Square avatar" class="wa-callout wa-neutral">
<wa-icon slot="icon" name="user-plus" variant="solid"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<h3 class="wa-caption-m">Total Subscribers</h3>
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-l">81,779</span>
<wa-badge variant="success" appearance="filled outlined" pill>
<wa-icon fixed-width name="arrow-up" label="Up"></wa-icon>
212
</wa-badge>
<span class="wa-heading-xs">Total Subscribers</span>
<div class="wa-cluster">
<span class="wa-heading-l">71,897</span>
<wa-tag size="small" variant="success" appearance="filled outlined" pill><wa-icon fixed-width name="arrow-up"></wa-icon> 122</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank wa-align-items-start">
<wa-avatar shape="rounded">
<wa-icon slot="icon" name="envelope-open"></wa-icon>
<div class="wa-flank">
<wa-avatar shape="square" label="Square avatar" class="wa-callout wa-neutral">
<wa-icon slot="icon" name="user-plus" variant="solid"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<h3 class="wa-caption-m">Open Rate</h3>
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-l">61.58%</span>
<wa-badge variant="success" appearance="filled outlined" pill>
<wa-icon fixed-width name="arrow-up" label="Up"></wa-icon>
4.5%
</wa-badge>
<span class="wa-heading-xs">Total Subscribers</span>
<div class="wa-cluster">
<span class="wa-heading-l">71,897</span>
<wa-tag size="small" variant="success" appearance="filled outlined" pill><wa-icon fixed-width name="arrow-up"></wa-icon> 122</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank wa-align-items-start">
<wa-avatar shape="rounded">
<wa-icon slot="icon" name="arrow-pointer"></wa-icon>
<div class="wa-flank">
<wa-avatar shape="square" label="Square avatar" class="wa-callout wa-neutral">
<wa-icon slot="icon" name="user-plus" variant="solid"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<h3 class="wa-caption-m">Click Rate</h3>
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-l">25.74%</span>
<wa-badge variant="danger" appearance="filled outlined" pill>
<wa-icon fixed-width name="arrow-down" label="Down"></wa-icon>
2.1%
</wa-badge>
<span class="wa-heading-xs">Total Subscribers</span>
<div class="wa-cluster">
<span class="wa-heading-l">71,897</span>
<wa-tag size="small" variant="success" appearance="filled outlined" pill><wa-icon fixed-width name="arrow-up"></wa-icon> 122</wa-tag>
</div>
</div>
</div>
@@ -119,56 +55,107 @@ isPro: true
</div>
```
## Condensed Card
### Multi column
```html {.example}
<wa-card style="max-width: 50ch; margin: auto">
<div slot="header" class="wa-split">
<h3 class="wa-heading-m"><span style="color: var(--wa-color-text-quiet)">query</span> getUser</h3>
<wa-icon-button id="go-to-query-button" name="chevron-right" label="Go to Query"></wa-icon-button>
<wa-tooltip for="go-to-query-button">Go to Query</wa-tooltip>
</div>
<div class="wa-stack wa-gap-xl">
<div class="wa-split wa-align-items-stretch">
<article class="wa-stack wa-align-items-start wa-gap-xs">
<h4 class="wa-caption-l">Cache Hit Rate</h4>
<div class="wa-cluster wa-heading-2xl">
<wa-progress-ring value="12.3" style="--size: 1em; --track-width: 0.125em"></wa-progress-ring>
<span>12.3%</span>
</div>
<wa-badge appearance="filled outlined" variant="danger"><wa-icon name="arrow-down"></wa-icon> down from 19.6%</wa-badge>
</article>
<article class="wa-stack wa-gap-xs wa-align-items-end">
<h4 class="wa-caption-l">Max CHR</h4>
<span class="wa-heading-2xl">72.6%</span>
<wa-badge appearance="filled outlined" variant="success"><wa-icon name="sparkles"></wa-icon> CHR Impact +5.4%</wa-badge>
</article>
```html{.example}
<div style="max-width: 480px; margin: 0 auto">
<wa-card>
<div>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<article class="wa-stack wa-gap-xl">
<div class="wa-stack wa-gap-xs">
<h4 class="wa-caption-l">Cacheable Bandwidth</h4>
<div class="wa-split">
<span class="wa-heading-2xl">90.5 GB</span>
<span class="wa-caption-xl">69.9%</span>
</div>
<wa-progress-bar value="30.1" label="Cached and non-cacheable bandwidth"></wa-progress-bar>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
<dl class="wa-stack wa-caption-m">
<div class="wa-cluster">
<dt>Cached</dt>
<dd>12.8 GB (9.8%)</dd>
</div>
<div class="wa-cluster">
<dt>Non-Cacheable</dt>
<dd>26.3 GB (20.3%)</dd>
</div>
<div class="wa-cluster">
<dt>Total</dt>
<dd>129.6 GB</dd>
</div>
</dl>
</article>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
</div>
</wa-card>
</div>
```
### Card with condensed information
```html{.example}
<wa-card style="max-width: 480px; margin: 0 auto;">
<div class="wa-stack">
<section class="wa-split">
<a href="#" class="wa-cluster wa-gap-xs wa-align-items-center">
<span class="wa-caption-m">query</span>
<span class="wa-heading-m">getUser</span>
<wa-icon fixed-width name="arrow-right"></wa-icon>
</a>
<wa-icon-button fixed-width name="ellipsis" label="actions"></wa-icon-button>
</section>
<section class="wa-cluster">
<span class="wa-caption-l">7.15M request • 9% • 734msP95</span>
</section>
<section class="wa-split">
<div class="wa-stack wa-gap-xs">
<span class="wa-caption-l">Cache Hit Rate</span>
<span class="wa-heading-2xl">12.3%</span>
<wa-badge appearance="filled outlined" variant="danger"><wa-icon name="arrow-down"></wa-icon> down from 19.6%</wa-badge>
</div>
<div class="wa-stack wa-gap-xs">
<span class="wa-caption-l">Max CHR</span>
<span class="wa-heading-2xl">72.6%</span>
<wa-badge appearance="filled outlined" variant="success"><wa-icon name="arrow-up"></wa-icon> CHR Impact +5.4%</wa-badge>
</div>
</section>
<wa-divider></wa-divider>
<section class="wa-stack">
<span class="wa-heading-m">90.5 GB (69.8%)</span>
<div class="wa-split">
<span>Cacheable Bandwidth</span>
<span class="wa-cluster wa-gap-2xs">
<wa-icon fixed-width name="dollar-sign"></wa-icon>
<span>$9.50</span>
<wa-icon fixed-width name="circle-question"></wa-icon>
</span>
</div>
<div class="wa-stack">
<wa-progress-bar value="9.8" label="Upload progress"></wa-progress-bar>
<span class="wa-caption-m">Cached 12.8GB (9.8%)</span>
<span class="wa-caption-m">Non-Cacheable 26.3GB (91.2)</span>
<span class="wa-heading-s">Total 129.6GB</span>
</div>
</section>
</div>
</wa-card>
```

View File

@@ -1,43 +1,46 @@
---
title: Description List
description: 'Help users digest detailed information in a structured, easy-to-scan format.'
isPro: true
description: 'Shows the user information with labels and values in an easy to read format.'
parent: app
tags: app
---
## Examples
## Left Aligned
```html {.example}
<div class="wa-stack">
### Simple
```html{.example}
<div style="max-width: 960px; margin: 0 auto">
<h3 class="wa-heading-m">Applicant Info</h3>
<p class="wa-caption-m">Details about the applicant and attachments.</p>
<p class="wa-caption-m">Personal details.</p>
<wa-divider></wa-divider>
<dl class="wa-stack wa-gap-2xl">
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Full name</dt>
<dd>Bucky Barnes</dd>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Full name</dt>
<dd class="wa-caption-m">Bucky Barnes</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Application for</dt>
<dd>Machine Learning Engineer</dd>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Application for</dt>
<dd class="wa-caption-m">Machine Learning Engineer</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Email address</dt>
<dd>winter_soldier@example.com</dd>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Email address</dt>
<dd class="wa-caption-m">winter_soldier@example.com</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Salary expectation</dt>
<dd>$240,000</dd>
</div>
<div class="wa-flank wa-align-items-start" style="--flank-size: 20ch;">
<dt>About</dt>
<dd>After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I love, and I'm always striving to atone for those dark days as the Winter Soldier.
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Salary expectation</dt>
<dd class="wa-caption-m">
$240,00
</dd>
</div>
<div class="wa-flank wa-align-items-start" style="--flank-size: 20ch;">
<dt>Attachments</dt>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">About</dt>
<dd class="wa-caption-m">After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I loves, and I'm always striving to atone for those dark days as the Winter Soldier.
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Attachments</dt>
<dd>
<wa-card>
<div class="wa-stack">
<div>
<div class="wa-flank">
<wa-icon name="paperclip"></wa-icon>
<div class="wa-split">
@@ -67,37 +70,38 @@ isPro: true
</div>
```
## Two Column
### Two Column
```html{.example}
<div class="wa-stack">
<h2 class="wa-heading-m">Applicant Info</h2>
<p class="wa-caption-m">Details about the applicant and attachments.</p>
<div style="max-width: 960px; margin: 0 auto">
<h2 class="wa-heading-m">Applicant Information</h2>
<p class="wa-caption-m">Personal details and application.</p>
<wa-divider></wa-divider>
<dl class="wa-grid wa-gap-2xl" style="--min-column-size: 40ch;">
<div class="wa-stack wa-gap-xs">
<dt>Full name</dt>
<dd>Bucky Barnes</dd>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Full name</dt>
<dd class="wa-caption-m">Bucky Barnes</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt>Application for</dt>
<dd>Machine Learning Engineer</dd>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Application for</dt>
<dd class="wa-caption-m">Machine Learning Engineer</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt>Email address</dt>
<dd>winter_soldier@example.com</dd>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Email address</dt>
<dd class="wa-caption-m">winter_soldier@example.com</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt>Salary expectation</dt>
<dd>$240,000</dd>
</div>
<div class="wa-stack wa-gap-xs wa-span-grid">
<dt>About</dt>
<dd>After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I love, and I'm always striving to atone for those dark days as the Winter Soldier.
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Salary expectation</dt>
<dd class="wa-caption-m">
$240,00
</dd>
</div>
<div class="wa-stack wa-gap-xs wa-span-grid">
<dt>Attachments</dt>
<div class="wa-align-items-start wa-flank wa-span-grid" style="--flank-size: 15%;">
<dt class="wa-heading-xs">About</dt>
<dd class="wa-caption-m">After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I loves, and I'm always striving to atone for those dark days as the Winter Soldier.
</dd>
</div>
<div class="wa-align-items-start wa-flank wa-span-grid" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Attachments</dt>
<dd>
<wa-card>
<div>
@@ -129,67 +133,61 @@ isPro: true
</dl>
</div>
```
## Left Aligned with Actions
```html {.example}
<div class="wa-stack">
<h3 class="wa-heading-m">Applicant Info</h3>
<p class="wa-caption-m">Details about the applicant and attachments.</p>
### Multi Column
```html{.example}
<div style="max-width: 960px; margin: 0 auto">
<h2 class="wa-heading-m">Applicant Information</h2>
<p class="wa-caption-m">Personal details and application.</p>
<wa-divider></wa-divider>
<dl class="wa-stack wa-gap-2xl">
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Full name</dt>
<div class="wa-flank:end">
<dd>Bucky Barnes</dd>
<wa-button appearance="plain" variant="brand" size="small">Edit</wa-button>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Full name</dt>
<dd class="wa-caption-m wa-split">
<span>Bucky Barnes</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Application for</dt>
<div class="wa-flank:end">
<dd>Machine Learning Engineer</dd>
<wa-button appearance="plain" variant="brand" size="small">Edit</wa-button>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Application for</dt>
<dd class="wa-caption-m wa-split">
<span>Machine Learning Engineer</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Email address</dt>
<div class="wa-flank:end">
<dd>winter_soldier@example.com</dd>
<wa-button appearance="plain" variant="brand" size="small">Edit</wa-button>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Email address</dt>
<dd class="wa-caption-m wa-split">
<span>winter_soldier@example.com</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Salary expectation</dt>
<div class="wa-flank:end">
<dd>$240,000</dd>
<wa-button appearance="plain" variant="brand" size="small">Edit</wa-button>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Salary expectation</dt>
<dd class="wa-caption-m wa-split">
<span>$240,00</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-flank wa-align-items-start" style="--flank-size: 20ch;">
<dt>About</dt>
<div class="wa-flank:end">
<dd>After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I love, and I'm always striving to atone for those dark days as the Winter Soldier.</dd>
<wa-button appearance="plain" variant="brand" size="small">Edit</wa-button>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">About</dt>
<dd class="wa-caption-m wa-split">
<p style="max-width: 70ch;">After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I loves, and I'm always striving to atone for those dark days as the Winter Soldier.</p>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-flank" style="--flank-size: 20ch;">
<dt>Attachments</dt>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Attachments</dt>
<dd>
<wa-card>
<div class="wa-stack">
<div>
<div class="wa-flank">
<wa-icon name="paperclip"></wa-icon>
<div class="wa-split">
<span class="wa-caption-m wa-cluster">
<span>bb_resume.pdf</span>
<span>bb_resume.pdf</span>
<span>2.4mb</span>
</span>
<div class="wa-cluster wa-gap-2xs">
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
<wa-divider vertical style="height: 1em"></wa-divider>
<wa-button appearance="plain" variant="danger" size="small">Delete</wa-button>
</div>
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
</div>
</div>
<wa-divider></wa-divider>
@@ -200,11 +198,7 @@ isPro: true
<span>bb_cover_letter.pdf</span>
<span>2.4mb</span>
</span>
<div class="wa-cluster wa-gap-2xs">
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
<wa-divider vertical style="height: 1em"></wa-divider>
<wa-button appearance="plain" variant="danger" size="small">Delete</wa-button>
</div>
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
</div>
</div>
</div>
@@ -214,37 +208,34 @@ isPro: true
</dl>
</div>
```
## Condensed
### Narrow with Invoice Details
```html{.example}
<wa-card appearance="filled" style="max-width: 45ch; margin: auto">
<div class="wa-stack">
<div class="wa-split wa-align-items-start">
<dl class="wa-stack wa-gap-2xs">
<dt class="wa-heading-s">Amount</dt>
<dd class="wa-heading-l">$5,610.00</dd>
</dl>
<wa-badge appearance="filled outlined" variant="success">Paid</wa-badge>
</div>
<wa-divider></wa-divider>
<dl class="wa-stack">
<wa-card with-header with-footer class="wa-callout wa-neutral" style="max-width: 480px; margin: 0 auto;">
<div slot="header" class="wa-split">
<dl class="wa-stack wa-gap-2xs">
<dt class="wa-heading-s">Amount</dt>
<dd class="wa-heading-l">$10,560.00</dd>
</dl>
<wa-badge appearance="filled outlined" variant="success">Paid</wa-badge>
</div>
<div>
<dl class="wa-stack" style="margin: 0;">
<div class="wa-flank wa-align-items-stretch">
<dt><wa-icon name="user" label="Name" fixed-width></wa-icon></dt>
<dd>Sam Wilson</dd>
<dt><wa-icon name="user"></wa-icon></dt>
<dd class="wa-heading-s">Sam Wilson</dd>
</div>
<div class="wa-flank wa-align-items-stretch">
<dt><wa-icon name="calendar-days" label="Date" fixed-width></wa-icon></dt>
<dd><wa-format-date date="2025-03-15"></wa-format-date></dd>
<dt><wa-icon name="calendar-days"></wa-icon></dt>
<dd class="wa-heading-s">June 8, 2015</dd>
</div>
<div class="wa-flank wa-align-items-stretch">
<dt><wa-icon family="brands" name="cc-visa" label="Credit Card" fixed-width></wa-icon></dt>
<dd>Paid with Visa 1234</dd>
<dt><wa-icon family="brands" name="cc-visa"></wa-icon></dt>
<dd class="wa-heading-s">Paid with Visa</dd>
</div>
</dl>
</div>
<div slot="footer">
<a href="" class="wa-cluster wa-gap-2xs">
<a href="#" class="wa-flank wa-align-items-center wa-gap-2xs">
<span>Download Receipt</span>
<wa-icon name="arrow-right"></wa-icon>
</a>

View File

@@ -1,207 +1,113 @@
---
title: Empty State
description: 'Guide users with helpful prompts and visuals when no content is available.'
isPro: true
description: TODO
parent: app
tags: app
---
## Examples
## Simple
```html {.example}
<div class="wa-stack wa-align-items-center">
<wa-icon name="backpack" class="wa-caption-l" style="font-size: var(--wa-font-size-3xl)"></wa-icon>
<span class="wa-heading-m">No Kits</span>
<p class="wa-caption-l">Manage all of your project's icons in a kit.</p>
### Simple
```html{.example}
<div class="wa-stack wa-align-items-center">
<wa-icon name="folder" style="font-size: 60px;"></wa-icon>
<span class="wa-heading-s">No Projects</span>
<p class="wa-caption-m">Get started by creating a new project.</p>
<wa-button>
<wa-icon slot="prefix" name="plus"></wa-icon>
Add Kit
New Project
</wa-button>
</div>
```
## With Interactive Placeholder
### With border
```html {.example}
<a href="" class="wa-stack wa-align-items-center wa-placeholder wa-link-plain" style="max-width: 60ch; margin: auto">
<wa-icon name="ufo-beam" class="wa-caption-l" family="sharp" style="font-size: var(--wa-font-size-3xl)"></wa-icon>
<p class="wa-heading-m">No Custom Icons</p>
<p style="text-align: center">Add your own icon or logo to get started.</p>
</a>
```html{.example}
<a href="#" class="wa-align-items-center wa-callout wa-neutral wa-outlined wa-stack" style="max-width: 480px; margin: 0 auto; text-decoration: none;">
<wa-icon name="database" style="font-size: 64px;"></wa-icon>
<div class="wa-stack wa-align-items-center wa-gap-2xs">
<p class="wa-heading-m">No DBs</p>
<p>Get started by creating a database.</p>
</div>
</a>
```
### With starting points
## With Templates
```html {.example}
<wa-card with-header with-footer style="max-width: 70ch; margin: auto">
```html{.example}
<wa-card with-header with-footer style="max-width: 720px; margin: 0 auto;">
<div slot="header" class="wa-stack wa-gap-xs">
<h2 class="wa-heading-m">Projects</h2>
<p class="wa-caption-m">You havent created a project yet. Get started by selecting a template or start from an empty project.</p>
</div>
<div class="wa-stack wa-gap-xl">
<p class="wa-caption-m">You havent created a project yet. Get started by selecting a template or start with a blank canvas.</p>
<div class="wa-grid wa-gap-xl" style="--min-column-size: 30ch;">
<a href="" class="wa-flank wa-align-items-start wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-yellow-90);color: var(--wa-color-yellow-40);">
<wa-icon slot="icon" name="note-sticky"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Quick Note <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Jot down any idea. Will it make sense later? Who knows.
</p>
</div>
</a>
<a href="" class="wa-flank wa-align-items-start wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-red-90);color: var(--wa-color-red-40);">
<wa-icon slot="icon" name="list-check"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Checklist <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
The ultimate tool for looking busy.
</p>
</div>
</a>
<a href=""class="wa-flank wa-align-items-start wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-purple-90);color: var(--wa-color-purple-40);">
<wa-icon slot="icon" name="table-cells"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Spreadsheet <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Endless rows and columns of tiny, soul-crushing numbers.
</p>
</div>
</a>
<a href="" class="wa-flank wa-align-items-start wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-orange-90);color: var(--wa-color-orange-40);">
<wa-icon slot="icon" name="presentation-screen"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Slideshow <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Dramatic transitions make everything seem more official.
</p>
</div>
</a>
<a href="" class="wa-flank wa-align-items-start wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-green-90);color: var(--wa-color-green-40);">
<wa-icon slot="icon" name="pen-field"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Form <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Collect the deepest personal details and darkest secrets.
</p>
</div>
</a>
<a href="" class="wa-flank wa-align-items-start wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-blue-90);color: var(--wa-color-blue-40);">
<wa-icon slot="icon" name="image"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Photo Album <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Curate your best memories or most basic food pictures.
</p>
</div>
</a>
</div>
</div>
<div slot="footer">
<a href="" class="wa-cluster wa-gap-xs">
<span>Or start with a blank canvas</span>
<wa-icon name="arrow-right"></wa-icon>
<div class="wa-grid" style="--min-column-size: 30ch;">
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="bars" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a List <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Another to-do system youll try but eventually give up on.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="image" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Gallery <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Great for mood boards and inspiration.
</p>
</div>
</a>
<a href="#"class="wa-flank" style="text-decoration: none;">
<wa-icon name="table-cells" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Spreadsheet <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Helps keep up with the numbers.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="calendar" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Calendar <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Stay on top of your deadlines, or dont — its up to you.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="table-columns" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Board <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Track tasks in different stages of your project.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="clock" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Timeline <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Get a birds-eye-view of your procrastination.
</p>
</div>
</a>
</div>
</wa-card>
```
## Add people
```html {.example}
<wa-card style="max-width: 60ch; margin: 0 auto;">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-m">Add team members</h3>
<p>This project is awful lonely. Invite some team members to liven up the joint.</p>
<div class="wa-flank:end wa-gap-xs">
<wa-input></wa-input><wa-button>Invite</wa-button>
</div>
<div class="wa-stack">
<em class="wa-caption-l">Team members previously added to projects</em>
<wa-divider></wa-divider>
<section>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1614807547811-4174d3582092?q=80&w=2932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Earl Upton</span>
<span class="wa-caption-m">DevOps</span>
</div>
<wa-button appearance="plain">
<wa-icon name="user-plus" slot="prefix"></wa-icon>
Invite
</wa-button>
</div>
</div>
<wa-divider></wa-divider>
</section>
<section>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1613428800237-c86372070fab?q=80&w=3017&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" lable="profile image"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Steamboat Willie</span>
<span class="wa-caption-m">Captain</span>
</div>
<wa-button appearance="plain">
<wa-icon name="user-plus" slot="prefix"></wa-icon>
Invite
</wa-button>
</div>
</div>
<wa-divider></wa-divider>
</section>
<section>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1678582967399-bf558533f5eb?q=80&w=3029&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Melissa Eckers</span>
<span class="wa-caption-m">Cloud Engineer</span>
</div>
<wa-button appearance="plain">
<wa-icon name="user-plus" slot="prefix"></wa-icon>
Invite
</wa-button>
</div>
</div>
<wa-divider></wa-divider>
</section><section>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1559188286-a173792c8340?q=80&w=2906&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Devin Shears</span>
<span class="wa-caption-m">UX Writer</span>
</div>
<wa-button appearance="plain">
<wa-icon name="user-plus" slot="prefix"></wa-icon>
Invite
</wa-button>
</div>
</div>
<wa-divider></wa-divider>
</section>
</div>
<div slot="footer">
<a href="#">Or start from an empty project →</a>
</div>
</wa-card>
```

View File

@@ -1,118 +1,91 @@
---
title: FAQ
description: 'Empower users to learn more with a structured list of questions and answers.'
isPro: true
description: TODO
parent: app
tags: app
---
## With Flanked Heading & Description
```html {.example}
<div class="wa-flank wa-align-items-start wa-gap-2xl" style="--flank-size: 35ch">
```html{.example}
<div class="wa-grid">
<div>
<h2>Frequently Asked Questions</h2>
<p>Cant find an answer? Reach out to your local <a href="">Operator</a>, or contact <a href="">the Oracle</a>, and enjoy a cookie. &#127850;</p>
<p>Cant find the answer youre looking for? Reach out to our <a href="#">customer support</a> team.</p>
</div>
<dl class="wa-stack wa-gap-2xl">
<dl class="wa-stack wa-gap-m">
<div class="wa-stack wa-gap-xs">
<dt>Is Zion actually real, or just another Matrix?</dt>
<dd>Ah, the question that keeps redpills up at night. Sure, we escaped the first Matrix, but whos to say Zion isnt just another layer of the simulation?</dd>
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt>Why do the Agents always wear suits?</dt>
<dd>Because nothing says "unstoppable digital enforcer" like a generic business professional aesthetic. Also, intimidation. You ever try fighting someone in sunglasses and a tie? Its terrifying.</dd>
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt>Can I go back into the Matrix once Im out?</dt>
<dd>Technically, yes—via hacking in. Emotionally? That depends on how well you handle the knowledge that nothing around you is real.</dd>
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
</dl>
</div>
```
## With Expandable Answers
```html {.example}
<div class="wa-stack">
```html{.example}
<div style="max-width: 960px; margin: 0 auto;">
<h2>Frequently Asked Questions</h2>
<wa-details appearance="plain">
<h3 slot="summary" class="wa-heading-m" style="margin: 0">Is Zion actually real, or just another Matrix?</h3>
Ah, the question that keeps redpills up at night. Sure, we escaped the first Matrix, but whos to say Zion isnt just another layer of the simulation?
<div class="wa-stack wa-gap-xs">
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
<wa-divider></wa-divider>
<wa-details appearance="plain">
<h3 slot="summary" class="wa-heading-m" style="margin: 0">Why do the Agents always wear suits?</h3>
Because nothing says "unstoppable digital enforcer" like a generic business professional aesthetic. Also, intimidation. You ever try fighting someone in sunglasses and a tie? Its terrifying.
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
<wa-divider></wa-divider>
<wa-details appearance="plain">
<h3 slot="summary" class="wa-heading-m" style="margin: 0">Can I go back into the Matrix once Im out?</h3>
Technically, yes—via hacking in. Emotionally? That depends on how well you handle the knowledge that nothing around you is real.
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
</div>
</div>
```
## Two Column
```html {.example}
<div class="wa-stack wa-gap-2xl">
<h2>Frequently Asked Questions</h2>
<dl class="wa-stack wa-gap-2xl">
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">Is Zion actually real, or just another Matrix?</dt>
<dd>Ah, the question that keeps redpills up at night. Sure, we escaped the first Matrix, but whos to say Zion isnt just another layer of the simulation?</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">Why do the Agents always wear suits?</dt>
<dd>Because nothing says "unstoppable digital enforcer" like a generic business professional aesthetic. Also, intimidation. You ever try fighting someone in sunglasses and a tie? Its terrifying.</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">Can I go back into the Matrix once Im out?</dt>
<dd>Technically, yes—via hacking in. Emotionally? That depends on how well you handle the knowledge that nothing around you is real.</dd>
</div>
</dl>
</div>
```
## Multiple Columns
```html{.example}
<div>
<h2>Frequently Asked Questions</h2>
<dl class="wa-grid wa-gap-m" style="--min-column-size: 30ch;">
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How often do you update your courses?</dt>
<dd>A course is updated once there is a fundamental shift in the language or librarys underlying API. You can check our <a href="#">workshop</a> list to see if a new version of a given course is on the schedule. You may also write to us as <a href="#">support@frontendmasters.com</a> with suggestions for updates.</dd>
<dl class="wa-stack wa-gap-m">
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">Do you offer certificates of completion?</dt>
<dd>You can download certificates of completion from the <a href="#">Completed Courses</a> list in your Learning Library. Click the diploma icon next to the course to download the certificate in light or dark mode. A link to your Public Profile is included on each certificate if youve created one. Public Profiles showcase your learning journey and are a fantastic way to share progress with friends, co-workers, or employers. Public Profiles are available to members with an active Frontend Masters subscription who have watched ten or more hours of content. Visit the <a href="#">Public Profile</a> section in My Account to get started.</dd>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">Do you offer a free trial?</dt>
<dd>
<p>We offer a free trial to first-time subscribers. You can find more about the trial here.</p>
<p>We also have the following opportunities to learn for free:</p>
<ul>
<li>The online bootcamp is a free, two-week curriculum to get you started with web development.</li>
<li>You can create a free account to gain access to five full courses for free.</li>
</ul>
</dd>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">Do you have discounts for students?</dt>
<dd>We are part of the <a href="#">GitHub Student Developer Pack</a>, allowing students six months of free access to the entire platform.</dd>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do I cancel my plan?</dt>
<dd>You can cancel your Frontend Masters subscription by visiting the <a href="#">Subscription tab</a> in your My Account area.</dd>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
</dl>
</div>

View File

@@ -0,0 +1,86 @@
---
title: Feed
description: TODO
parent: app
tags: app
---
```html {.example}
<div class="activity-feed">
<div class="activity-group">
<span class="connector"></span>
<div class="activity">
<wa-icon name="user-circle" class="fa-fw"></wa-icon>
<p>Kicked ass and <strong>chewed bubblegum</strong></p>
<span style="margin-left: auto"><em>Oct. 31st</em></span>
</div>
</div>
<div class="activity-group">
<span class="connector"></span>
<div class="activity">
<wa-icon name="thumbs-up" style="color: blue" class="fa-fw"></wa-icon>
<p>Kicked ass and <strong>chewed bubblegum</strong></p>
<span style="margin-left: auto"><em>Oct. 31st</em></span>
</div>
</div>
<div class="activity-group">
<span class="connector"></span>
<div class="activity">
<wa-icon name="crown" class="fa-fw"></wa-icon>
<p>Kicked ass and <strong>chewed bubblegum</strong></p>
<span style="margin-left: auto"><em>Oct. 31st</em></span>
</div>
</div>
<div class="activity-group">
<span class="connector"></span>
<div class="activity">
<wa-icon name="turtle" style="color: green" class="fa-fw"></wa-icon>
<p>Kicked ass and <strong>chewed bubblegum</strong></p>
<span style="margin-left: auto"><em>Oct. 31st</em></span>
</div>
</div>
</div>
<style>
:root {
--border-color: var(--wa-color-surface-border);
}
.activity-feed {
wa-icon {
margin-right: 1rem;
font-size: 32px;
}
.fa-fw {
text-align: center;
width: 1.25em;
}
.activity {
display: flex;
justify-content: flex-start;
align-items: flex-start;
}
.activity-group:not(:first-child) {
margin-top: .5rem;
}
.activity-group {
position: relative;
}
.connector {
position: absolute;
background-color: var(--border-color);
height: 25%;
width: 0.125rem;
margin-left: -1px;
top: 2.5rem;
left: 1rem;
}
.activity-group:last-of-type .connector {
display: none;
}
}
</style>
```

View File

@@ -1,525 +0,0 @@
---
title: Grid List
description: 'Improve browsing and selection by organizing data in a structured grid layout.'
isPro: true
---
## Cards with Footer Actions
```html {.example}
<div class="wa-grid" style="--min-column-size: 30ch;">
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<div class="wa-cluster wa-gap-xs">
<h3 class="wa-heading-s">Barklia Woofington</h3 class="wa-heading-s">
<wa-badge pill>Admin</wa-badge>
</div>
<span class="wa-caption-m">Canine Executive Officer</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1593270379182-fe1b1f6d67e5?q=80&w=2175&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Avatar of black and white Border Collie"></wa-avatar>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<div class="wa-cluster wa-gap-xs">
<h3 class="wa-heading-s">Maggie Pawsworth</h3 class="wa-heading-s">
<wa-badge pill>Admin</wa-badge>
</div>
<span class="wa-caption-m">Canine Fetch Officer</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1514479425649-0981aca9fe41?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Avatar of black collie mix"></wa-avatar>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Rex Tailwag</h3 class="wa-heading-s">
<span class="wa-caption-m">Head of Security</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1610968755695-d7fcb5fd4b92?q=80&w=2848&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Avatar of black and tan German Shepherd"></wa-avatar>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Luna Sniffington</h3 class="wa-heading-s">
<span class="wa-caption-m">Hound Relations</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1526440847959-4e38e7f00b04?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Avatar of black and tan Yorkshire Terrier"></wa-avatar>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Charlie Drooler</h3 class="wa-heading-s">
<span class="wa-caption-m">Head of Sales</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1554692844-6627ca340264?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Avatar of tan and white corgi"></wa-avatar>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Daisy Zoomley</h3 class="wa-heading-s">
<span class="wa-caption-m">IT Support</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1544378062-0b74cc8b4713?q=80&w=3648&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="Avatar of gray Weimaraner"></wa-avatar>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
</div>
```
## Cards with Footer Actions & Large Image
```html {.example}
<div class="wa-grid" style="--min-column-size: 29ch;">
<wa-card with-footer>
<div class="wa-stack wa-align-items-center wa-gap-xs">
<div class="wa-frame wa-border-radius-circle">
<img src="https://images.unsplash.com/photo-1522075469751-3a6694fb2f61?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<h2 class="wa-heading-m">Scott Summers</h2>
<p class="wa-caption-l">DevOps</p>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-stack wa-align-items-center wa-gap-xs">
<div class="wa-frame wa-border-radius-circle">
<img src="https://images.unsplash.com/photo-1559188286-a173792c8340?q=80&w=2906&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<h2 class="wa-heading-m">Kaitlin Moore</h2>
<p class="wa-caption-l">Systems Engineer</p>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-stack wa-align-items-center wa-gap-xs">
<div class="wa-frame wa-border-radius-circle">
<img src="https://images.unsplash.com/photo-1613428800237-c86372070fab?q=80&w=3017&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<h2 class="wa-heading-m">Nessa Riley</h2>
<p class="wa-caption-l">Cloud Engineer</p>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-stack wa-align-items-center wa-gap-xs">
<div class="wa-frame wa-border-radius-circle">
<img src="https://images.unsplash.com/photo-1645288059073-af3e9eb62a29?q=80&w=2936&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<h2 class="wa-heading-m">Veronica Staley</h2>
<p class="wa-caption-l">Machine Learning Engineer</p>
</div>
<div slot="footer" class="wa-grid wa-gap-xs" style="--min-column-size: 10ch;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="at"></wa-icon>
Email
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="phone"></wa-icon>
Phone
</wa-button>
</div>
</wa-card>
</div>
```
## with Images
```html {.example}
<div class="wa-grid">
<article class="wa-stack">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1522075469751-3a6694fb2f61?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<div class="wa-stack wa-gap-3xs">
<span>Jeff Hanks</span>
<span>Product Designer</span>
</div>
<div class="wa-cluster wa-gap-3xs">
<wa-icon-button name="bluesky" family="brands" label="link to Blusky profile"></wa-icon-button>
<wa-icon-button name="dribbble" family="brands" label="link to Dribbble profile"></wa-icon-button>
</div>
</article>
<article class="wa-stack">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1674044494331-8db2ecf18d46?q=80&w=3019&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<div class="wa-stack wa-gap-3xs">
<span>Allen Bryant</span>
<span>Staff Engineer</span>
</div>
<div class="wa-cluster wa-gap-3xs">
<wa-icon-button name="bluesky" family="brands" label="link to Blusky profile"></wa-icon-button>
<wa-icon-button name="dribbble" family="brands" label="link to Dribbble profile"></wa-icon-button>
</div>
</article>
<article class="wa-stack">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1645288059073-af3e9eb62a29?q=80&w=2936&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<div class="wa-stack wa-gap-3xs">
<span>Mariah Greene</span>
<span>DevOps</span>
</div>
<div class="wa-cluster wa-gap-3xs">
<wa-icon-button name="bluesky" family="brands" label="link to Blusky profile"></wa-icon-button>
<wa-icon-button name="dribbble" family="brands" label="link to Dribbble profile"></wa-icon-button>
</div>
</article>
<article class="wa-stack">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1613428800237-c86372070fab?q=80&w=3017&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<div class="wa-stack wa-gap-3xs">
<span>Beverly Winslow</span>
<span>Design Systems Lead</span>
</div>
<div class="wa-cluster wa-gap-3xs">
<wa-icon-button name="bluesky" family="brands" label="link to Blusky profile"></wa-icon-button>
<wa-icon-button name="dribbble" family="brands" label="link to Dribbble profile"></wa-icon-button>
</div>
</article>
<article class="wa-stack">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1614807547811-4174d3582092?q=80&w=2932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<div class="wa-stack wa-gap-3xs">
<span>Eric Masterson</span>
<span>Copy Writer</span>
</div>
<div class="wa-cluster wa-gap-3xs">
<wa-icon-button name="bluesky" family="brands" label="link to Blusky profile"></wa-icon-button>
<wa-icon-button name="dribbble" family="brands" label="link to Dribbble profile"></wa-icon-button>
</div>
</article>
<article class="wa-stack">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1559188286-a173792c8340?q=80&w=2906&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
<div class="wa-stack wa-gap-3xs">
<span>Stephen Coffee</span>
<span>Visual Designer</span>
</div>
<div class="wa-cluster wa-gap-3xs">
<wa-icon-button name="bluesky" family="brands" label="link to Blusky profile"></wa-icon-button>
<wa-icon-button name="dribbble" family="brands" label="link to Dribbble profile"></wa-icon-button>
</div>
</article>
</div>
```
## Linked Cards with Options Menu
```html{.example}
<div class="wa-grid" style="--min-column-size: 25ch">
<wa-card>
<div class="wa-flank:end">
<a href="" class="wa-flank wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-yellow-80); --text-color: var(--wa-color-yellow-40)">
<wa-icon slot="icon" name="pancakes"></wa-icon>
</wa-avatar>
<div class="wa-gap-2xs wa-stack">
<span class="wa-heading-s">Breakfast</span>
<span class="wa-caption-m">28 Items</span>
</div>
</a>
<wa-dropdown>
<wa-icon-button id="more-actions-1" slot="trigger" name="ellipsis-vertical" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="more-actions-1">More actions</wa-tooltip>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end">
<a href="" class="wa-flank wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-orange-80); --text-color: var(--wa-color-orange-40)">
<wa-icon slot="icon" name="burger-cheese"></wa-icon>
</wa-avatar>
<div class="wa-gap-2xs wa-stack">
<span class="wa-heading-s">Lunch + Dinner</span>
<span class="wa-caption-m">40 Items</span>
</div>
</a>
<wa-dropdown>
<wa-icon-button id="more-actions-2" slot="trigger" name="ellipsis-vertical" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="more-actions-2">More actions</wa-tooltip>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end">
<a href="" class="wa-flank wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-indigo-80); --text-color: var(--wa-color-indigo-40)">
<wa-icon slot="icon" name="martini-glass-citrus"></wa-icon>
</wa-avatar>
<div class="wa-gap-2xs wa-stack">
<span class="wa-heading-s">Beverages</span>
<span class="wa-caption-m">19 Items</span>
</div>
</a>
<wa-dropdown>
<wa-icon-button id="more-actions-3" slot="trigger" name="ellipsis-vertical" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="more-actions-3">More actions</wa-tooltip>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end">
<a href="" class="wa-flank wa-link-plain">
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-pink-80); --text-color: var(--wa-color-pink-40)">
<wa-icon slot="icon" name="cake-slice"></wa-icon>
</wa-avatar>
<div class="wa-gap-2xs wa-stack">
<span class="wa-heading-s">Dessert</span>
<span class="wa-caption-m">11 Items</span>
</div>
</a>
<wa-dropdown>
<wa-icon-button id="more-actions-4" slot="trigger" name="ellipsis-vertical" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="more-actions-4">More actions</wa-tooltip>
</div>
</wa-card>
</div>
```
## Kanban
```html {.example}
<div>
<h2>Project #487</h2>
<div class="wa-grid wa-gap-2xl">
<div class="wa-stack">
<div class="wa-cluster wa-gap-s"><span>Draft</span> <wa-badge appearance="filled outlined" variant="neutral">1</wa-badge></div>
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-2xs">
<div class="wa-cluster wa-gap-2xs">
<span class="wa-heading-s">Unit Testing</span>
<wa-dropdown>
<wa-icon-button id="task-action-4" slot="trigger" name="ellipsis" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="task-action-4">More actions</wa-tooltip>
</div>
<div class="wa-cluster wa-gap-2xs">
<wa-badge appearance="outlined" pill>DevOps</wa-badge> <wa-badge variant="neutral" appearance="outlined" pill>Priority: Low</wa-badge>
</div>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1559188286-a173792c8340?q=80&w=2906&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
label="profile image"></wa-avatar>
</div>
</wa-card>
<wa-button appearance="plain">
<wa-icon name="plus"></wa-icon>
Add Task
</wa-button>
</div>
<div class="wa-stack">
<div class="wa-cluster wa-gap-s"><span>In Progress</span> <wa-badge appearance="filled outlined" variant="neutral">2</wa-badge></div>
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-2xs">
<div class="wa-cluster wa-gap-2xs">
<span class="wa-heading-s">UX Audit</span>
<wa-dropdown>
<wa-icon-button id="task-action-2" slot="trigger" name="ellipsis" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="task-action-2">More actions</wa-tooltip>
</div>
<div class="wa-cluster wa-gap-2xs">
<wa-badge appearance="outlined" pill>Design</wa-badge> <wa-badge variant="warning" appearance="outlined" pill>Priority: Medium</wa-badge>
</div>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1613428800237-c86372070fab?q=80&w=3017&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
label="profile image"></wa-avatar>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-2xs">
<div class="wa-cluster wa-gap-2xs">
<span class="wa-heading-s">Visual Testing</span>
<wa-dropdown>
<wa-icon-button id="task-action-3" slot="trigger" name="ellipsis" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="task-action-3">More actions</wa-tooltip>
</div>
<div class="wa-cluster wa-gap-2xs">
<wa-badge appearance="outlined" pill>Design</wa-badge> <wa-badge variant="danger" appearance="outlined" pill>Priority: High</wa-badge>
</div>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1614807547811-4174d3582092?q=80&w=2932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="profile image"></wa-avatar>
</div>
</wa-card>
<wa-button appearance="plain">
<wa-icon name="plus"></wa-icon>
Add Task
</wa-button>
</div>
<div class="wa-stack">
<div class="wa-cluster wa-gap-s"><span>Ready for Review</span> <wa-badge appearance="filled outlined" variant="neutral">1</wa-badge></div>
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-2xs">
<div class="wa-cluster wa-gap-2xs">
<span class="wa-heading-s">Deploy Bug Fixes</span>
<wa-dropdown>
<wa-icon-button id="task-action-1" slot="trigger" name="ellipsis" label="More actions"></wa-icon-button>
<wa-menu>
<wa-menu-item>Copy link</wa-menu-item>
<wa-menu-item>Rename</wa-menu-item>
<wa-menu-item>Move to trash</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-tooltip for="task-action-1">More actions</wa-tooltip>
</div>
<div class="wa-cluster wa-gap-2xs">
<wa-badge appearance="outlined" pill>Development</wa-badge> <wa-badge variant="warning" appearance="outlined" pill>Priority: Medium</wa-badge>
</div>
</div>
<wa-avatar initials="KK" label="Avatar with initials: KK"></wa-avatar>
</div>
</wa-card>
<wa-button appearance="plain">
<wa-icon name="plus"></wa-icon>
Add Task
</wa-button>
</div>
</div>
</div>
```

View File

@@ -0,0 +1,166 @@
---
title: Grid
description: TODO
parent: app
tags: app
---
```html {.example}
<div class="wa-grid" style="--min-column-size: 30ch;">
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-0">
<span>
<strong>John Carpenter</strong>
<wa-badge pill>Admin</wa-badge>
</span>
<span>Master of Horror</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"label="Avatar of a gray tabby kitten looking down">
</wa-avatar>
</div>
<div slot="footer" class="wa-grid" style="--min-column-size: 16ch;">
<wa-button appearance="outlined"><wa-icon slot="prefix" name="at"></wa-icon>Email</wa-button>
<wa-button appearance="outlined"><wa-icon slot="prefix" name="phone"></wa-icon>Phone</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-0">
<span>
<strong>John Carpenter</strong>
<wa-badge pill>Admin</wa-badge>
</span>
<span>Master of Horror</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"label="Avatar of a gray tabby kitten looking down">
</wa-avatar>
</div>
<div slot="footer" class="wa-grid" style="--min-column-size: 16ch;">
<wa-button appearance="outlined"><wa-icon slot="prefix" name="at"></wa-icon>Email</wa-button>
<wa-button appearance="outlined"><wa-icon slot="prefix" name="phone"></wa-icon>Phone</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-0">
<span>
<strong>John Carpenter</strong>
<wa-badge pill>Admin</wa-badge>
</span>
<span>Master of Horror</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"label="Avatar of a gray tabby kitten looking down">
</wa-avatar>
</div>
<div slot="footer" class="wa-grid" style="--min-column-size: 16ch;">
<wa-button appearance="outlined"><wa-icon slot="prefix" name="at"></wa-icon>Email</wa-button>
<wa-button appearance="outlined"><wa-icon slot="prefix" name="phone"></wa-icon>Phone</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-0">
<span>
<strong>John Carpenter</strong>
<wa-badge pill>Admin</wa-badge>
</span>
<span>Master of Horror</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"label="Avatar of a gray tabby kitten looking down">
</wa-avatar>
</div>
<div slot="footer" class="wa-grid" style="--min-column-size: 16ch;">
<wa-button appearance="outlined"><wa-icon slot="prefix" name="at"></wa-icon>Email</wa-button>
<wa-button appearance="outlined"><wa-icon slot="prefix" name="phone"></wa-icon>Phone</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-0">
<span>
<strong>John Carpenter</strong>
<wa-badge pill>Admin</wa-badge>
</span>
<span>Master of Horror</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"label="Avatar of a gray tabby kitten looking down">
</wa-avatar>
</div>
<div slot="footer" class="wa-grid" style="--min-column-size: 16ch;">
<wa-button appearance="outlined"><wa-icon slot="prefix" name="at"></wa-icon>Email</wa-button>
<wa-button appearance="outlined"><wa-icon slot="prefix" name="phone"></wa-icon>Phone</wa-button>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-flank:end">
<div class="wa-stack wa-gap-0">
<span>
<strong>John Carpenter</strong>
<wa-badge pill>Admin</wa-badge>
</span>
<span>Master of Horror</span>
</div>
<wa-avatar image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"label="Avatar of a gray tabby kitten looking down">
</wa-avatar>
</div>
<div slot="footer" class="wa-grid" style="--min-column-size: 16ch;">
<wa-button appearance="outlined"><wa-icon slot="prefix" name="at"></wa-icon>Email</wa-button>
<wa-button appearance="outlined"><wa-icon slot="prefix" name="phone"></wa-icon>Phone</wa-button>
</div>
</wa-card>
</div>
```
```html{.example}
<div class="wa-grid">
<wa-card>
<div class="wa-flank">
<div class="wa-callout wa-neutral">GA</div>
<div class="wa-split">
<div class="wa-gap-0 wa-stack">
<span class="wa-heading-xs">Graph API</span>
<span class="wa-caption-m">16 Members</span>
</div>
<wa-icon-button name="ellipsis-vertical" label="actions"></wa-icon-button>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<div class="wa-callout wa-success">GA</div>
<div class="wa-split">
<div class="wa-gap-0 wa-stack">
<span class="wa-heading-xs">Graph API</span>
<span class="wa-caption-m">16 Members</span>
</div>
<wa-icon-button name="ellipsis-vertical" label="actions"></wa-icon-button>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<div class="wa-callout wa-danger">GA</div>
<div class="wa-split">
<div class="wa-gap-0 wa-stack">
<span class="wa-heading-xs">Graph API</span>
<span class="wa-caption-m">16 Members</span>
</div>
<wa-icon-button name="ellipsis-vertical" label="actions"></wa-icon-button>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<div class="wa-callout wa-warning">GA</div>
<div class="wa-split">
<div class="wa-gap-0 wa-stack">
<span class="wa-heading-xs">Graph API</span>
<span class="wa-caption-m">16 Members</span>
</div>
<wa-icon-button name="ellipsis-vertical" label="actions"></wa-icon-button>
</div>
</div>
</wa-card>
</div>
```

View File

@@ -1,9 +1,7 @@
---
title: App
description: Pre-built action panels, data displays, and more ready to drop into your web app.
parent: patterns
description: TODO
layout: overview
override:tags: []
categories: ["app"]
listChildren: true
isPro: false
---

View File

@@ -1,266 +1,369 @@
---
title: Leaderboard
description: 'Engage and motivate users by highlighting top performers, scores, and achievements.'
isPro: true
description: TODO
parent: app
tags: app
---
## Simple
```html {.example}
<div class="wa-stack">
<h3>Daily Crossword</h3>
```html{.example}
<div class="wa-stack wa-gap-xs" style="max-width: 960px; margin: 0 auto">
<h2>Collective Activity for Yesterday</h2>
<div class="wa-grid">
<wa-callout variant="warning" appearance="filled">
<wa-icon slot="icon" name="timer"></wa-icon>
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-l">11h 54m 52s</span>
<span class="wa-caption-m">until play ends</span>
</div>
</wa-callout>
<wa-callout variant="neutral" appearance="filled">
<wa-icon slot="icon" name="user-group"></wa-icon>
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-l">304</span>
<span class="wa-caption-m">players on this leaderboard</span>
</div>
</wa-callout>
</div>
<wa-card>
<div class="wa-stack">
<ol class="wa-stack">
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="1" fixed-width></wa-icon>
<wa-avatar>
<wa-icon slot="icon" name="hat-wizard"></wa-icon>
</wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>wordwiz</span>
<small class="wa-caption-l">00:01:41</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="2" fixed-width></wa-icon>
<wa-avatar initials="A"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>acrossNdown</span>
<small class="wa-caption-l">00:01:58</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="3" fixed-width></wa-icon>
<wa-avatar initials="X"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>XwordChamp</span>
<small class="wa-caption-l">00:02:14</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="4" fixed-width></wa-icon>
<wa-avatar>
<wa-icon slot="icon" name="chess-knight"></wa-icon>
</wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>puzzlepoet</span>
<small class="wa-caption-l">00:02:16</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="5" fixed-width></wa-icon>
<wa-avatar initials="R"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>RiddleMeThis</span>
<small class="wa-caption-l">00:02:34</small>
</div>
</li>
</ol>
</div>
<div slot="footer">
<a href="" class="wa-cluster wa-gap-xs wa-caption-m">
<span>View all standings</span>
<wa-icon name="arrow-right"></wa-icon>
</a>
</div>
</wa-card>
</div>
```
## Two Column
```html {.example}
<div class="wa-stack">
<h3>Collective Activity for Yesterday</h3>
<div class="wa-grid">
<wa-callout variant="neutral" appearance="filled">
<wa-callout>
<wa-icon slot="icon" name="book"></wa-icon>
<div class="wa-stack wa-gap-0">
<h4 class="wa-heading-xs">Items Studied</h4>
<div class="wa-heading-xs">Items Studied</div>
<div class="wa-heading-2xl">482,813</div>
</div>
</wa-callout>
<wa-callout variant="brand" appearance="filled">
<wa-icon slot="icon" name="diploma"></wa-icon>
<wa-callout variant="warning">
<wa-icon slot="icon" name="medal"></wa-icon>
<div class="wa-stack wa-gap-0">
<h4 class="wa-heading-xs">Items Mastered</h4>
<div class="wa-heading-xs">Items Mastered</div>
<div class="wa-heading-2xl">67,106</div>
</div>
</wa-callout>
<wa-callout variant="success" appearance="filled">
<wa-icon slot="icon" name="wand-sparkles"></wa-icon>
<wa-callout variant="success">
<wa-icon slot="icon" name="plus"></wa-icon>
<div class="wa-stack wa-gap-0">
<h4 class="wa-heading-xs">Items Created</h4>
<div class="wa-heading-xs">Items Created</div>
<div class="wa-heading-2xl">2,080</div>
</div>
</wa-callout>
</div>
<!-- -->
<div class="wa-grid">
<wa-card>
<div slot="header" class="wa-flank wa-gap-xl">
<wa-icon name="graduation-cap" class="wa-heading-xl"></wa-icon>
<span class="wa-gap-2xs wa-stack">
<h4>Study Leaders</h4>
<span class="wa-caption-m">Items mastered in the last 7 days</span>
</span>
</div>
<div class="wa-stack">
<ol class="wa-stack">
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="1" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=3418&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>mitsuwo</span>
<small class="wa-caption-l">2,753</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="2" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=3348&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>knowledgeninja</span>
<small class="wa-caption-l">2,298</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="3" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=2592&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>NxtLvl</span>
<small class="wa-caption-l">2,008</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="4" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1630549316063-7ae02749d2cc?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>brainiac</span>
<small class="wa-caption-l">1,954</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="5" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1582845512747-e42001c95638?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>eduexplorer</span>
<small class="wa-caption-l">1,897</small>
</div>
</li>
</ol>
</div>
</wa-card>
<wa-card>
<div slot="header" class="wa-flank wa-gap-xl">
<wa-icon name="hat-wizard" class="wa-heading-xl"></wa-icon>
<span class="wa-gap-2xs wa-stack">
<h4>Creation Leaders</h4>
<span class="wa-caption-m">Items created in the last 7 days</span>
</span>
</div>
<div class="wa-stack">
<ol class="wa-stack">
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="1" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1630549316063-7ae02749d2cc?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>brainiac</span>
<small class="wa-caption-l">134</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="2" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1546776230-bb86256870ce?q=80&w=3368&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>LessonLegend</span>
<small class="wa-caption-l">115</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="3" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=3418&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>mitsuwo</span>
<small class="wa-caption-l">98</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="4" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1586374579358-9d19d632b6df?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>wiswiz</span>
<small class="wa-caption-l">79</small>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank">
<div class="wa-cluster">
<wa-icon name="5" fixed-width></wa-icon>
<wa-avatar image="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=3348&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" shape="rounded"></wa-avatar>
</div>
<div class="wa-split wa-gap-xs">
<span>knowledgeninja</span>
<small class="wa-caption-l">77</small>
</div>
</li>
</ol>
</div>
</wa-card>
<wa-card with-header>
<div slot="header" class="wa-flank">
<wa-icon name="trophy"></wa-icon>
<span class="wa-gap-0 wa-stack">
<h4>Study Leaders</h4>
<p>items mastered last 7 days</p>
</span>
</div>
<div>
<ol>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
</li>
</ol>
</div>
</wa-card>
<!-- -->
<wa-card with-header>
<div slot="header" class="wa-flank">
<wa-icon name="trophy"></wa-icon>
<span class="wa-gap-0 wa-stack">
<h4>Creation Leaders</h4>
<p>items created last 7 days</p>
</span>
</div>
<div>
<ol>
<li>
<p>Item 1</p>
<wa-divider></wa-divider>
</li>
<li>
<p>Item 1</p>
<wa-divider></wa-divider>
</li>
<li>
<p>Item 1</p>
<wa-divider></wa-divider>
</li>
</ol>
</div>
</wa-card>
</div>
</div>
```
### Two Column
```html{.example}
<div style="max-width: 960px; margin: 0 auto">
<h2>WTA Rankings</h2>
<div class="wa-grid wa-gap-3xl">
<div class="wa-stack">
<div class="wa-flank">
<div class="wa-border-radius-l wa-frame">
<img src="https://uploads.webawesome.com/serena-2.jpg" />
</div>
<div class="wa-stack wa-gap-s">
<span class="wa-heading-m">Serena Williams</span>
<span class="wa-caption-l">United States</span>
</div>
</div>
<span class="wa-heading-l">SINGLES</span>
<ol class="wa-stack wa-gap-2xs">
<li>
<div class="wa-split">
<span>Williams, Serena</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Williams, Serena</span>
<span>6960</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Li, Na</span>
<span>6785</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Halep, Simona</span>
<span>6070</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Radwanska, Agnieszka</span>
<span>5130</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Sharapova, Maria</span>
<span>4661</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Bouchard, Eugenie</span>
<span>4460</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Kerber, Angelique</span>
<span>4365</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Jankovic, Jelena</span>
<span>3900</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Azarenka, Victoria</span>
<span>3812</span>
</div>
</li>
</ol>
</div>
<!-- -->
<div class="wa-stack">
<div class="wa-cluster">
<div class="wa-border-radius-l wa-frame">
<img src="https://uploads.webawesome.com/roberta.jpg" />
</div>
<div class="wa-border-radius-l wa-frame">
<img src="https://uploads.webawesome.com/sara.jpg" />
</div>
</div>
<span class="wa-heading-l">DOUBLES</span>
<ol class="wa-stack wa-gap-2xs">
<li>
<div class="wa-split">
<span>Errani, Vinci</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Roberts, Paxson</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Smith, Wexler</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Elena, Hisieh</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Pen, Sania</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Makarova, Cara</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Washington, Roosevelt</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>King, Little</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Grier, Brown</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Burkhart, Silverton</span>
<span>9231</span>
</div>
</li>
</ol>
</div>
</div>
```

View File

@@ -1,52 +1,44 @@
---
title: Pagination
description: 'Improve navigation and performance by breaking long lists or content into manageable pages.'
isPro: true
description: TODO
parent: app
tags: app
---
## Simple
## Simple Pagination
```html {.example}
<div class="wa-stack">
<div class="wa-placeholder"></div>
```html{.example}
<div>
<wa-divider></wa-divider>
<div class="wa-split">
<span class="wa-caption-l">Showing 1 to 10 of 50 Results</span>
<div class="wa-cluster wa-gap-xs">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="chevron-left"></wa-icon>
Prev
</wa-button>
<wa-button appearance="outlined">
<wa-icon slot="suffix" name="chevron-right"></wa-icon>
Next
</wa-button>
</div>
<span>
<wa-button><wa-icon slot="prefix" name="gear" variant="solid"></wa-icon> Prev</wa-button>
<wa-button><wa-icon slot="suffix" name="gear" variant="solid"></wa-icon>Next </wa-button>
</span>
</div>
</div>
```
## With Button Group
## Multi Page
```html {.example}
<div class="wa-stack">
<div class="wa-placeholder"></div>
<wa-divider></wa-divider>
<div class="wa-split">
<span class="wa-caption-l">Showing 1 to 10 of 50 Results</span>
<wa-button-group orientation="horizontal">
<wa-button appearance="outlined">
<wa-icon name="chevron-left"></wa-icon>
</wa-button>
<wa-button appearance="accent" variant="brand">1</wa-button>
<wa-button appearance="outlined">2</wa-button>
<wa-button appearance="outlined">3</wa-button>
<wa-button appearance="outlined" disabled>...</wa-button>
<wa-button appearance="outlined">10</wa-button>
<wa-button appearance="outlined">
<wa-icon name="chevron-right"></wa-icon>
</wa-button>
</wa-button-group>
<wa-card with-footer>
<div class="wa-stack" style="opacity: 25%;">
<div>
<div class="wa-flank">
<wa-avatar label="User avatar"></wa-avatar>
<div>
Some stuff
</div>
</div>
<wa-divider></wa-divider>
</div>
</div>
</div>
<div slot="footer" class="wa-split">
<wa-button><wa-icon slot="prefix" name="gear" variant="solid"></wa-icon> Prev</wa-button>
<wa-button><wa-icon slot="suffix" name="gear" variant="solid"></wa-icon>Next </wa-button>
</div>
</wa-card>
```

View File

@@ -1,229 +0,0 @@
---
title: Permissions
description: 'Permission patterns provide or restrict access to users.'
isPro: true
---
## With Form Inputs
```html{.example}
<wa-card with-header style="max-width: 72ch; margin: 0 auto;">
<div slot="header" class="wa-split">
<h2 class="wa-heading-m">Invite Team Members</h2>
<wa-icon name="close"></wa-icon>
</div>
<div class="wa-stack wa-gap-2xl">
<div class="wa-align-items-end wa-flank:end wa-gap-2xs">
<wa-input label="Email" placeholder="contact@example.com"></wa-input>
<wa-button variant="success">Send Invite</wa-button>
</div>
<div class="wa-stack">
<span class="wa-heading-s">Project Members</span>
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1580489944761-15a19d654956?q=80&w=1961&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Jessica Jones</span>
<span class="wa-caption-m" style="word-break: break-word">jessica.jones@example.com</span>
</div>
<wa-select value="owner">
<wa-option value="owner">Owner</wa-option>
<wa-option value="admin">Admin</wa-option>
<wa-option value="can-edit">Can Edit</wa-option>
<wa-option value="view-only">View Only</wa-option>
</wa-select>
</div>
</div>
<div class="wa-flank">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1566492031773-4f4e44671857?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Foggy Nelson</span>
<span class="wa-caption-m" style="word-break: break-word">foggy.nelson@example.com</span>
</div>
<wa-select value="admin">
<wa-option value="owner">Owner</wa-option>
<wa-option value="admin">Admin</wa-option>
<wa-option value="can-edit">Can Edit</wa-option>
<wa-option value="view-only">View Only</wa-option>
</wa-select>
</div>
</div>
<div class="wa-flank">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Karen Page</span>
<span class="wa-caption-m" style="word-break: break-word">karen.page@example.com</span>
</div>
<wa-select value="can-edit">
<wa-option value="owner">Owner</wa-option>
<wa-option value="admin">Admin</wa-option>
<wa-option value="can-edit">Can Edit</wa-option>
<wa-option value="view-only">View Only</wa-option>
</wa-select>
</div>
</div>
<div class="wa-flank">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Matt Murdock</span>
<span class="wa-caption-m" style="word-break: break-word">matt.murdock@example.com</span>
</div>
<wa-select value="view-only">
<wa-option value="owner">Owner</wa-option>
<wa-option value="admin">Admin</wa-option>
<wa-option value="can-edit">Can Edit</wa-option>
<wa-option value="view-only">View Only</wa-option>
</wa-select>
</div>
</div>
</div>
</div>
<div class="wa-align-items-end wa-flank:end wa-gap-2xs">
<wa-input label="Share Link" value="https://sharelink3435re.com" disabled></wa-input>
<wa-button variant="brand" appearance="filled outlined">
<wa-icon slot="prefix" name="link" variant="solid"></wa-icon>
Copy Link
</wa-button>
</div>
</div>
</wa-card>
```
## Link Settings
```html {.example}
<wa-card style="max-width: 45ch; margin: 0 auto;">
<div class="wa-stack">
<h2 class="wa-heading-m">Manage Link</h2>
<wa-input label="Expiration Date" type="date"></wa-input>
<wa-radio-group
label="Share Limit"
orientation="horizontal"
name="share-limit"
value="0"
>
<wa-radio-button value="0">None</wa-radio-button>
<wa-radio-button value="5">5</wa-radio-button>
<wa-radio-button value="10">10</wa-radio-button>
<wa-radio-button value="50">50</wa-radio-button>
<wa-radio-button value="100">100</wa-radio-button>
</wa-radio-group>
<wa-divider></wa-divider>
<wa-switch hint="Members are removed after logging out." checked>Temporary Access</wa-switch>
<div class="wa-cluster wa-gap-xs" style="justify-content: flex-end">
<wa-button size="small" appearance="outlined" pill>Cancel</wa-button>
<wa-button size="small" variant="brand" pill>Generate</wa-button>
</div>
</div>
</wa-card>
```
## Role Settings
```html {.example}
<div style="max-width: 78ch; margin: 0 auto;">
<h2>Settings</h2>
<p>Update settings for this server.</p>
<wa-tab-group>
<wa-tab panel="general">
<div class="wa-cluster">
<wa-icon name="user"></wa-icon>
<span>User Permissions</span>
</div>
</wa-tab>
<wa-tab-panel name="general">
<wa-card>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1741289308283-feba56f857cc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTl8fGJlYXJkfGVufDB8MnwwfHx8Mg%3D%3D" alt="image avatar"></wa-avatar>
<div class="wa-split">
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-s">Kris Kringle</span>
<span class="wa-caption-m">Admin</span>
</div>
<wa-button appearance="plain">
<wa-icon slot="prefix" name="edit"></wa-icon>
Edit Profile
</wa-button>
</div>
</div>
</wa-card>
<table>
<thead>
<tr>
<th>Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1579824894326-77ec5aaf8703?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NDJ8fHJlaW5kZWVyfGVufDB8MnwwfHx8Mg%3D%3D"></wa-avatar>
<span class="wa-caption-m">Dasher</span>
</div>
</td>
<td>
<wa-select value="moderator">
<wa-option value="moderator">Moderator</wa-option>
<wa-option value="contributor">Contributor</wa-option>
<wa-option value="reader">Reader</wa-option>
</wa-select>
</td>
</tr>
<tr>
<td>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1691065686144-916ff29d1b4f?q=80&w=2666&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<span class="wa-caption-m">Dancer</span>
</div>
</td>
<td>
<wa-select value="moderator">
<wa-option value="moderator">Moderator</wa-option>
<wa-option value="contributor">Contributor</wa-option>
<wa-option value="reader">Reader</wa-option>
</wa-select>
</td>
</tr>
<tr>
<td>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1616742618872-9e8a890d90b2?q=80&w=2712&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<span class="wa-caption-m">Prancer</span>
</div>
</td>
<td>
<wa-select value="contributor">
<wa-option value="moderator">Moderator</wa-option>
<wa-option value="contributor">Contributor</wa-option>
<wa-option value="reader">Reader</wa-option>
</wa-select>
</td>
</tr>
<tr>
<td>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1728290403857-1b7909db2baa?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<span class="wa-caption-m">Vixen</span>
</div>
</td>
<td>
<wa-select value="reader">
<wa-option value="moderator">Moderator</wa-option>
<wa-option value="contributor">Contributor</wa-option>
<wa-option value="reader">Reader</wa-option>
</wa-select>
</td>
</tr>
</tbody>
</table>
</wa-tab-panel>
</wa-tab-group>
</div>
```

View File

@@ -1,168 +1,137 @@
---
title: Pricing
description: 'Help users make informed purchasing decisions with clear, structured pricing.'
isPro: true
description: TODO
parent: app
tags: app
---
## Three Tiers
```html{.example}
<div class="wa-grid">
<wa-card>
<div class="wa-stack">
<div class="wa-cluster wa-heading-l">
<wa-icon name="apple-core"></wa-icon>
<h3>Lite</h3>
</div>
<span class="wa-flank wa-align-items-baseline wa-gap-2xs">
<span class="wa-heading-2xl">$60</span>
<span class="wa-caption-l">per year</span>
<wa-card with-header>
<div slot="header">
<span class="wa-split">
<span class="wa-heading-s">Plan</span>
<wa-badge appearance="filled outlined" variant="success" pill>Most Popular</wa-badge>
</span>
<span class="wa-flank wa-gap-2xs">
<span class="wa-heading-2xl">$10</span>
<span class="wa-caption-l">per user/per month</span>
</span>
<p class="wa-caption-l">Basic Features</p>
<span class="wa-grid">
<wa-button>Get Started</wa-button>
<wa-button appearance="outlined">Talk to sales</wa-button>
</span>
<p class="wa-caption-l">An online-only plan for web-based projects.</p>
<wa-button variant="brand" appearance="outlined">Get Lite</wa-button>
</div>
<div slot="footer" class="wa-stack">
<h4 class="wa-heading-s">What You Get</h4>
<div class="wa-stack">
<p class="wa-heading-s">Features</p>
<p class="wa-caption-m">Everything in out free plan plus</p>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="user" fixed-width></wa-icon>
<span class="wa-caption-m">1 user</span>
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Access to basic features</span>
</div>
<div class="wa-flank">
<wa-icon name="suitcase" fixed-width></wa-icon>
<span class="wa-caption-m">2 custom kits</span>
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Basic Reporting and Analytics</span>
</div>
<div class="wa-flank">
<wa-icon name="chart-simple" fixed-width></wa-icon>
<span class="wa-caption-m">Up to 100k pageviews</span>
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">10 Individual users</span>
</div>
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">20GB of data for user</span>
</div>
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Basic Chat and email</span>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster wa-heading-l">
<wa-icon name="apple-whole"></wa-icon>
<h3>Pro</h3>
</div>
<wa-badge>Most Popular</wa-badge>
</div>
<span class="wa-flank wa-align-items-baseline wa-gap-2xs">
<span class="wa-heading-2xl">$120</span>
<span class="wa-caption-l">per year</span>
<wa-card with-header>
<div slot="header">
<span class="wa-split">
<span class="wa-heading-s">Plan</span>
<wa-badge appearance="filled outlined" variant="success" pill>Most Popular</wa-badge>
</span>
<span class="wa-flank wa-gap-2xs">
<span class="wa-heading-2xl">$10</span>
<span class="wa-caption-l">per user/per month</span>
</span>
<p class="wa-caption-l">Basic Features</p>
<span class="wa-grid">
<wa-button>Get Started</wa-button>
<wa-button appearance="outlined">Talk to sales</wa-button>
</span>
<p class="wa-caption-l">A great all-around plan for online or desktop use.</p>
<wa-button variant="brand">Get Pro</wa-button>
</div>
<div slot="footer" class="wa-stack">
<h4 class="wa-heading-s">What You Get</h4>
<div class="wa-stack wa-gap-2xs">
<p class="wa-heading-s">Features</p>
<p class="wa-caption-m">Everything in out free plan plus</p>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="user" fixed-width></wa-icon>
<span class="wa-caption-m">5 users</span>
</div>
<div class="wa-flank">
<wa-icon name="suitcase" fixed-width></wa-icon>
<span class="wa-caption-m">20 custom kits</span>
</div>
<div class="wa-flank">
<wa-icon name="chart-simple" fixed-width></wa-icon>
<span class="wa-caption-m">Up to 1M pageviews</span>
</div>
<div class="wa-flank">
<wa-icon name="arrow-down-to-line" fixed-width></wa-icon>
<span class="wa-caption-m">Kit downloads</span>
</div>
<div class="wa-flank">
<wa-icon name="cloud-plus" fixed-width></wa-icon>
<span class="wa-caption-m">Cloud hosting</span>
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Access to basic features</span>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<div class="wa-cluster wa-heading-l">
<wa-icon name="crate-apple"></wa-icon>
<h3>Max</h3>
</div>
<span class="wa-flank wa-align-items-baseline wa-gap-2xs">
<span class="wa-heading-2xl">$600</span>
<span class="wa-caption-l">per year</span>
<wa-card with-header>
<div slot="header">
<span class="wa-split">
<span class="wa-heading-s">Plan</span>
<wa-badge appearance="filled outlined" variant="success" pill>Most Popular</wa-badge>
</span>
<span class="wa-flank wa-gap-2xs">
<span class="wa-heading-2xl">$10</span>
<span class="wa-caption-l">per user/per month</span>
</span>
<p class="wa-caption-l">Basic Features</p>
<span class="wa-grid">
<wa-button>Get Started</wa-button>
<wa-button appearance="outlined">Talk to sales</wa-button>
</span>
<p class="wa-caption-l">Our biggest plan with more of everything.</p>
<wa-button variant="brand" appearance="outlined">Get Max</wa-button>
</div>
<div slot="footer" class="wa-stack">
<h4 class="wa-heading-s">What You Get</h4>
<div class="wa-stack wa-gap-2xs">
<p class="wa-heading-s">Features</p>
<p class="wa-caption-m">Everything in out free plan plus</p>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="user" fixed-width></wa-icon>
<span class="wa-caption-m">50 users</span>
</div>
<div class="wa-flank">
<wa-icon name="suitcase" fixed-width></wa-icon>
<span class="wa-caption-m">Unlimited custom kits</span>
</div>
<div class="wa-flank">
<wa-icon name="chart-simple" fixed-width></wa-icon>
<span class="wa-caption-m">Up to 10M pageviews</span>
</div>
<div class="wa-flank">
<wa-icon name="arrow-down-to-line" fixed-width></wa-icon>
<span class="wa-caption-m">Kit downloads</span>
</div>
<div class="wa-flank">
<wa-icon name="cloud-plus" fixed-width></wa-icon>
<span class="wa-caption-m">Cloud hosting</span>
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Access to basic features</span>
</div>
</div>
</div>
</wa-card>
</div>
```
## Single Tier
```html {.example}
<wa-card>
<div class="wa-grid">
<div class="wa-stack">
<h3 class="wa-heading-l">Lifetime Membership</h3>
<p>Learn at your own pace with expert-led content, exclusive resources, and a community of like-minded learners.</p>
<wa-divider></wa-divider>
<h4 class="wa-heading-s">Membership Includes:</h4>
<div class="wa-grid">
<div class="wa-flank wa-gap-xs">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Private forum access</span>
</div>
<div class="wa-flank wa-gap-xs">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Priority admission to events</span>
</div>
<div class="wa-flank wa-gap-xs">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Yearly skill assessment</span>
</div>
<div class="wa-flank wa-gap-xs">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Members-only swag</span>
</div>
</div>
```html{.example}
<div class="wa-callout wa-neutral wa-outlined wa-grid">
<div class="wa-stack">
<h2 class="wa-heading-l">Lifetime membership</h2>
<p>Lorem ipsum dolor sit amet consect etur adipisicing elit. Itaque amet indis perferendis blanditiis repellendus etur quidem assumenda.</p>
<wa-divider></wa-divider>
<h3 class="wa-heading-s">What's included</h3>
<div class="wa-grid">
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Private forum access</p></span>
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Entry to annual conference</p></span>
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Member resources</p></span>
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Official member t-shirt</p></span>
</div>
<wa-callout variant="neutral" appearance="filled">
<div class="wa-stack wa-align-items-center" style="justify-content: center">
<h4 class="wa-heading-s">Pay Once, Own it Forever</h4>
<div class="wa-cluster wa-align-items-baseline wa-gap-2xs">
<span class="wa-heading-3xl">$459</span>
<span>USD</span>
</div>
<wa-button variant="brand" style="width: 100%">Get Access</wa-button>
<small class="wa-caption-m">30-day money back guarantee</small>
</div>
</wa-callout>
</div>
</wa-card>
```
<div class="wa-callout wa-neutral wa-stack wa-align-items-center">
<h3 class="wa-heading-s">Pay once, own it forever</h3>
<div>
<span class="wa-heading-3xl">$349</span>
<span>USD</span>
</div>
<wa-button variant="success">Get Access</wa-button>
<p class="wa-caption-s">Invoices and receipts available for easy company reimbursement</p>
</div>
</div>
```
### With templates
### With recommendations grid

View File

@@ -2,7 +2,6 @@
title: Blog
description: TODO
unlisted: true
isPro: true
---
TODO Page Description
@@ -368,4 +367,4 @@ TODO Page Description
}
</style>
```
```

View File

@@ -2,9 +2,8 @@
title: Business
description: TODO
unlisted: true
isPro: true
---
TODO Page Description
## Examples
## Examples

View File

@@ -1,8 +1,9 @@
---
title: Category Filter
description: 'Helps the user find the right products with filters to refine search results by specific attributes.'
parent: ecommerce
tags: e-commerce
icon: checkbox
isPro: true
---
## Sidebar with Checkboxes & Expandable Filters
@@ -41,7 +42,7 @@ isPro: true
<wa-checkbox>XXL</wa-checkbox>
</div>
</wa-details>
</form>
</form>
<div class="wa-placeholder"></div>
</div>
</div>

View File

@@ -1,8 +1,9 @@
---
title: Category Preview
description: 'Help shoppers discover your product offerings with showcases of product categories.'
parent: ecommerce
tags: e-commerce
icon: preview
isPro: true
---
## Split with Image Grid
@@ -16,20 +17,20 @@ isPro: true
</div>
<div class="wa-stack">
<div class="wa-frame:landscape wa-border-radius-s">
<img
<img
src="https://images.unsplash.com/photo-1544441893-675973e31985?q=80&w=2340&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="An analog watch, cotton pants, crew neck tee, and pair of tennis shoes (Photograph by Mnz)"
/>
</div>
<div class="wa-grid">
<div class="wa-frame:landscape wa-border-radius-s">
<img
<img
src="https://images.unsplash.com/photo-1548768041-2fceab4c0b85?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Stack of three folded solid color tees (Photograph by Mnz)"
/>
</div>
<div class="wa-frame:landscape wa-border-radius-s">
<img
<img
src="https://images.unsplash.com/photo-1544441892-794166f1e3be?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Pair of bright white tennis shoes(Photograph by Mnz)"
/>
@@ -47,7 +48,7 @@ isPro: true
<div class="wa-grid">
<a href="" class="wa-stack wa-link-plain">
<div class="wa-frame:portrait wa-border-radius-s">
<img
<img
src="https://uploads.webawesome.com/organization.jpg"
alt="Inside of a closet filled with clothes on wooden hangers and integrated shelving with shoes"
/>
@@ -56,7 +57,7 @@ isPro: true
</a>
<a href="" class="wa-stack wa-link-plain">
<div class="wa-frame:portrait wa-border-radius-s">
<img
<img
src="https://uploads.webawesome.com/bags.jpg"
alt="Young person hugging a small floral patterned book bag between their arms"
/>
@@ -65,7 +66,7 @@ isPro: true
</a>
<a href="" class="wa-stack wa-link-plain">
<div class="wa-frame:portrait wa-border-radius-s">
<img
<img
src="https://uploads.webawesome.com/outdoor-2.jpg"
alt="Person in a mountain clearing wearing a waterproof hooded windbreaker in black and orange"
/>

View File

@@ -1,7 +1,8 @@
---
title: Checkout Form
description: 'Let shoppers checkout with ease with streamlined forms to capture shipping and payment info.'
isPro: true
parent: ecommerce
tags: e-commerce
---

View File

@@ -1,7 +1,8 @@
---
title: Incentives
description: 'Encourage shoppers to buy your products with value propositions, discounts, and promotions.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## 3 Column
@@ -10,29 +11,29 @@ isPro: true
<div class="wa-gap-3xl wa-stack" style="max-width: 960px; margin: 0 auto;">
<div class="wa-align-items-center wa-grid">
<div>
<span class="wa-heading-xl">Unlock your Superpower</span>
<p class="wa-caption-l">Web development is like a superpower—you can turn your ideas into actual products online, and learning it from home means you dont need a fancy degree or expensive tuition to start building your future.</p>
<span class="wa-heading-xl">Get the Best Instruction from our Educators.</span>
<p class="wa-caption-l">At the beginning at least, but then we realized we could make a lot more money if we kinda stopped caring about that. Our new strategy is to write a bunch of things that look really good in the headlines, then clarify in the small print but hope people don't actually read it.</p>
</div>
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1551981878-4c70c3e64135?q=80&w=2960&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
<img src="https://uploads.webawesome.com/online-learning.jpg" />
</div>
</div>
<div class="wa-grid">
<div class="wa-stack wa-gap-xs">
<wa-icon name="briefcase" variant="light" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Career Opportunities</span>
<p class="wa-caption-m">Mastering web development can lead to high-paying jobs, freelancing gigs, or even launching your own business or app.</p>
<wa-icon name="stopwatch" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Learn at your Speed</span>
<p class="wa-caption-m">It's not actually free we just price it into the products. Someone's paying for it, and it's not us.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="laptop-code" variant="light" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Flexibility of Online Learning</span>
<p class="wa-caption-m">Perfect for people balancing school, work, or other responsibilities—no need to attend in-person classes</p>
<wa-icon name="chart-line" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Track Progress</span>
<p class="wa-caption-m">If it breaks in the first 10 years we'll replace it. After that you're on your own though.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="palette" variant="light" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Creative & Practical Skillset</span>
<p class="wa-caption-m">You can build real, functional things like personal portfolios, blogs, or web apps—and immediately see your progress.</p>
<wa-icon name="people-group" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Active Community</span>
<p class="wa-caption-m">If you don't like it, trade it to one of your friends for something of theirs. Don't send it here though.</p>
</div>
</div>
</div>
@@ -40,7 +41,7 @@ isPro: true
## 2 Column with Cards
```html{.example}
<div class="wa-grid" style="--min-column-size: 24ch;">
<div class="wa-grid" style="--min-column-size: 41ch;">
<wa-card>
<div class="wa-flank">
<div>
@@ -98,26 +99,26 @@ isPro: true
```html{.example}
<div>
<div class="wa-grid" style="--min-column-size: 16ch;">
<div class="wa-grid">
<div class="wa-stack wa-gap-xs">
<wa-icon family="duotone" name="magnifying-glass" style="font-size: var(--wa-font-size-2xl);"></wa-icon>
<span class="wa-heading-s">In-Demand Skills</span>
<p class="wa-caption-m">Learn skills that lead to well-paying jobs, freelance work, or remote opportunities.</p>
<wa-icon name="magnifying-glass" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">SEO Consulting</span>
<p class="wa-caption-m">It's not actually free we just price it into the products. Someone's paying for it, and it's not us.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon family="duotone" name="chalkboard-user" style="font-size: var(--wa-font-size-2xl);"></wa-icon>
<span class="wa-heading-s">Learn Anytime, Anywhere</span>
<p class="wa-caption-m">Flexible learning fits into any schedule—perfect for students, parents, or full-time workers.</p>
<wa-icon name="chalkboard-user" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">In Person Training</span>
<p class="wa-caption-m">If it breaks in the first 10 years we'll replace it. After that you're on your own though.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon family="duotone" name="people-arrows" style="font-size: var(--wa-font-size-2xl);"></wa-icon>
<span class="wa-heading-s">Build and Launch Your Own Projects</span>
<p class="wa-caption-m">Youre not just learning theory—youre creating real, functional websites and apps.</p>
<wa-icon name="people-arrows" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">1 on 1 Sessions</span>
<p class="wa-caption-m">If you don't like it, trade it to one of your friends for something of theirs. Don't send it here though.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon family="duotone" name="code" style="font-size: var(--wa-font-size-2xl);"></wa-icon>
<span class="wa-heading-s">Low-Cost Entry</span>
<p class="wa-caption-m">You dont need a tech degree or expensive tools to get started</p>
<wa-icon name="code" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Web Development</span>
<p class="wa-caption-m">If you don't like it, trade it to one of your friends for something of theirs. Don't send it here though.</p>
</div>
</div>
</div>

View File

@@ -1,7 +1,8 @@
---
title: Order History
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## List
@@ -31,7 +32,7 @@ isPro: true
<wa-divider></wa-divider>
<div class="wa-flank" style="--flank-size: 12rem">
<div class="wa-frame wa-border-radius-s" style="aspect-ratio: 3 / 2">
<img
<img
src="https://img.fortawesome.com/cfa83f3c/light-fixtures.jpg"
alt=""
/>
@@ -48,7 +49,7 @@ isPro: true
<wa-button size="small" appearance="plain" variant="neutral">View Product</wa-button>
<wa-button size="small" appearance="accent" variant="brand">Buy Again</wa-button>
</div>
</div>
</div>
</div>
</div>
<wa-divider></wa-divider>
@@ -187,65 +188,3 @@ isPro: true
</table>
</div>
```
## Card separated
```html{.example}
<div class="wa-stack" style="max-width: 60ch; margin: 0 auto;">
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack">
<div class="wa-cluster wa-gap-xs">
<wa-avatar shape="rounded" label="Avatar with an image icon">
<wa-icon slot="icon"family="brands" name="amazon"></wa-icon>
</wa-avatar>
<span class="wa-heading-s">Amazon</span>
</div>
<div class="wa-stack wa-gap-xs">
<span>Expected Tomorrow</span>
<wa-progress-bar value="75" label="delivery progress" style="height: 0.5rem;"></wa-progress-bar>
</div>
</div>
<div class="wa-frame wa-border-radius-m" style="max-width: 6rem;">
<img src="https://images.unsplash.com/photo-1589810635657-232948472d98?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack">
<div class="wa-cluster wa-gap-xs">
<wa-avatar shape="rounded" label="Avatar with an image icon">
<wa-icon slot="icon" family="sharp" variant="light" name="shirt"></wa-icon>
</wa-avatar>
<span class="wa-heading-s">T-shirt Depot</span>
</div>
<div class="wa-stack wa-gap-xs">
<span>Out for Delivery</span>
<wa-progress-bar value="95" label="delivery progress" style="height: 0.5rem;"></wa-progress-bar>
</div>
</div>
<div class="wa-frame wa-border-radius-m" style="max-width: 6rem;">
<img src="https://images.unsplash.com/photo-1576566588028-4147f3842f27?q=80&w=2400&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end">
<div class="wa-stack">
<div class="wa-cluster wa-gap-xs">
<wa-avatar shape="rounded" label="Avatar with an image icon">
<wa-icon slot="icon" variant="duotone" name="gamepad-modern"></wa-icon>
</wa-avatar>
<span class="wa-heading-s">Game Theory</span>
</div>
<div class="wa-stack wa-gap-xs">
<span>Shipping Soon</span>
<wa-progress-bar value="15" label="delivery progress" style="height: 0.5rem;"></wa-progress-bar>
</div>
</div>
<div class="wa-frame wa-border-radius-m" style="max-width: 6rem;">
<img src="https://images.unsplash.com/photo-1627421383054-488d9c9828f5?q=80&w=2960&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</div>
</div>
</wa-card>
</div>
```

View File

@@ -1,7 +1,8 @@
---
title: Order Summary
description: 'Give shoppers confidence in their purchases with summaries of everything included in their order.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## Simple
@@ -25,7 +26,7 @@ isPro: true
<ul class="wa-stack wa-gap-xl">
<li class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
<img
src="https://uploads.webawesome.com/vase-1.jpg"
alt=""
/>
@@ -38,7 +39,7 @@ isPro: true
<wa-divider></wa-divider>
<li class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
<img
src="https://uploads.webawesome.com/decorative-vase.jpg"
alt=""
/>
@@ -218,7 +219,7 @@ isPro: true
<p class="wa-caption-m">Wood fired, salt glaze</p>
<wa-tag variant="success" appearance="filled" size="small">Delivered</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank wa-align-items-start">
@@ -236,7 +237,7 @@ isPro: true
<p class="wa-caption-m">High quality Japanese Kutani-yaki ceramic-ware</p>
<wa-tag variant="neutral" appearance="filled" size="small">Shipping Soon</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank wa-align-items-start">
@@ -254,7 +255,7 @@ isPro: true
<p class="wa-caption-m">Koishiwara-yaki style with crystalline glaze</p>
<wa-tag variant="brand" appearance="filled" size="small">Out for Delivery</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-divider></wa-divider>
<wa-callout variant="neutral" appearance="filled">
@@ -292,4 +293,4 @@ isPro: true
</div>
</wa-callout>
</div>
```
```

View File

@@ -1,7 +1,8 @@
---
title: Product Lists
description: 'Let shoppers browse and compare products with detailed lists of the products in your store.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## Simple Grid with Ratings
@@ -10,7 +11,7 @@ isPro: true
<div class="wa-grid wa-gap-2xl">
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1633933329864-5d4c4423ad54?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Bunch of fresh basil leaves with purple veins (Photograph by Svitlana)"
/>
@@ -22,7 +23,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1662892194342-f95c33cc16e3?q=80&w=3000&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Bunch of cut chamomile blooms (Photograph by Rootnot Creations)"
/>
@@ -34,7 +35,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1636396279461-f875646332d9?q=80&w=3360&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Canvas bundle of cut lavender blooms (Photograph by volant)"
/>
@@ -46,7 +47,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1501085934018-450c8e615dbc?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Blooming marjoram plant (Photograph by Monika Grabkowska)"
/>
@@ -58,7 +59,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1688633767797-455f59c98272?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Group of mature oregano plants (Photograph Nikolett Emmert)"
/>
@@ -70,7 +71,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1603109731710-dba41b1096a7?q=80&w=2259&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Cluster of peppermint plants (Photograph by Josefin)"
/>
@@ -82,7 +83,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1726994803809-0e065bd4b25b?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Mature rosemary stems (Photograph by 360floralflaves)"
/>
@@ -94,7 +95,7 @@ isPro: true
</a>
<a class="wa-stack wa-align-items-center wa-gap-xs wa-link-plain" href="">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1659834742696-44573974981b?q=80&w=3542&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Group of sage plants (Photograph by Susie Burleson)"
/>
@@ -114,7 +115,7 @@ isPro: true
<div class="wa-grid">
<a href="" class="wa-link-plain">
<wa-card>
<img slot="image"
<img slot="image"
src="https://images.unsplash.com/photo-1622445272461-c6580cab8755?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Man in a relaxed fit, white, crew neck t-shirt (Photography by Mediamodifier)"
/>
@@ -130,7 +131,7 @@ isPro: true
</a>
<a href="" class="wa-link-plain">
<wa-card>
<img slot="image"
<img slot="image"
src="https://images.unsplash.com/photo-1554568218-0f1715e72254?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Woman in a light heather t-shirt printed with sharp black ink (Photograph by Christian Bolt)"
/>

View File

@@ -1,7 +1,8 @@
---
title: Product Overview
description: 'Showcase your products with overviews including images, ratings, features, options, and more.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## Split with Image
@@ -76,7 +77,7 @@ isPro: true
</dl>
</div>
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1600396538702-d234dbb79139?q=80&w=3833&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Whole roasted coffee beans (Photograph by Jocelyn Morales)"
/>
@@ -361,7 +362,7 @@ isPro: true
<div class="wa-stack">
<img class="wa-border-radius-l"
src="https://img.fortawesome.com/cfa83f3c/icon-grid-wallpaper.png"
alt="Sample of 48 line-style icons"
alt="Sample of 48 line-style icons"
/>
<wa-tab-group>
<wa-tab panel="license">License</wa-tab>
@@ -427,4 +428,4 @@ isPro: true
</ul>
</div>
</div>
```
```

View File

@@ -1,10 +1,11 @@
---
title: Product Preview
description: 'Give shoppers a quick look at your products as they browse with modal previews.'
parent: ecommerce
tags: e-commerce
icon: preview
isPro: true
---
## With Product Options
```html {.example}
@@ -15,7 +16,7 @@ isPro: true
</div>
<div class="wa-grid wa-gap-xl">
<div class="wa-frame wa-border-radius-l" style="aspect-ratio: auto">
<img
<img
src="https://images.unsplash.com/photo-1660997351262-6c31d8a35b6c?q=80&w=2000&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Stan Smith graphic crew-neck tee in honeydew color"
/>
@@ -127,7 +128,7 @@ isPro: true
<div class="wa-gap-xs wa-stack">
<h4 class="wa-heading-m">About</h4>
<p class="wa-body-s">The Champion® Crossbody Bag is crafted for the trendsetter. Its sleek silhouette, paired with a tonal branded adjustable sling strap, ensures you look effortlessly cool no matter where you go.</p>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-gap-xs wa-stack">
<h4 class="wa-heading-m">Details</h4>
@@ -149,7 +150,7 @@ isPro: true
</div>
<div class="wa-flank:end wa-align-items-end">
<wa-button variant="brand" size="medium">
<wa-icon slot="suffix" name="cart-shopping" variant="solid"></wa-icon>Add to Cart
<wa-icon slot="suffix" name="cart-shopping" variant="solid"></wa-icon>Add to Cart
</wa-button>
<wa-button appearance="outlined" size="medium">
<wa-icon slot="suffix" name="arrow-right" variant="solid"></wa-icon>View Full Details
@@ -158,4 +159,4 @@ isPro: true
</div>
</div>
</wa-card>
```
```

View File

@@ -1,7 +1,8 @@
---
title: Product Reviews
description: 'Help shoppers make informed decisions with ratings, reviews, and testimonials from your customers.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## Multi column
@@ -12,13 +13,13 @@ isPro: true
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Viktor Vaughn</span>
<wa-relative-time date="2020-07-15T09:17:00-04:00" class="wa-caption-m"></wa-relative-time>
<span class="wa-caption-m"><em>September 23rd, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="5"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Solid treadmill for home workouts!</span>
<p>Best treadmill I've ever owned! It has a sleek design, and the features are top-notch. I use it daily for my cardio workouts, and the motor is powerful enough to keep up with my running. Its easy to adjust the speed and incline, and the display is clear and simple to read. Worth every penny!</p>
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">Best treadmill I've ever owned! It has a sleek design, and the features are top-notch. I use it daily for my cardio workouts, and the motor is powerful enough to keep up with my running. Its easy to adjust the speed and incline, and the display is clear and simple to read. Worth every penny!</p>
</div>
</div>
</div>
@@ -26,13 +27,13 @@ isPro: true
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Ben Grimm</span>
<wa-relative-time date="2020-07-15T09:17:00-04:00" class="wa-caption-m"></wa-relative-time>
<span class="wa-caption-m"><em>May 5th, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="4"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Good value, a few minor flaws</span>
<p>Decent treadmill for the price, but I feel like the belt could be a little wider for comfort. The cushioning is good, but sometimes I experience a slight wobble when running at high speeds. For casual walking, it's fine, but Im not sure its built for intense runners.</p>
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">Decent treadmill for the price, but I feel like the belt could be a little wider for comfort. The cushioning is good, but sometimes I experience a slight wobble when running at high speeds. For casual walking, it's fine, but Im not sure its built for intense runners.</p>
</div>
</div>
</div>
@@ -40,13 +41,13 @@ isPro: true
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Johnny Storm</span>
<wa-relative-time date="2020-07-15T09:17:00-04:00" class="wa-caption-m"></wa-relative-time>
<span class="wa-caption-m"><em>March 3rd, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="4"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Decent, but could use upgrades</span>
<p>This treadmill has been a great addition to my home gym. It's sturdy, easy to use, and I like that it tracks my steps and heart rate. The only downside is that it's a bit bulky, so I had to rearrange my space to make room for it. Overall, I'm happy with the performance and would recommend it.</p>
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">This treadmill has been a great addition to my home gym. It's sturdy, easy to use, and I like that it tracks my steps and heart rate. The only downside is that it's a bit bulky, so I had to rearrange my space to make room for it. Overall, I'm happy with the performance and would recommend it.</p>
</div>
</div>
</div>
@@ -54,13 +55,13 @@ isPro: true
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Sue Storm</span>
<wa-relative-time date="2020-07-15T09:17:00-04:00" class="wa-caption-m"></wa-relative-time>
<span class="wa-caption-m"><em>February 26th, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="4"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Perfect for small spaces</span>
<p>I absolutely love my new treadmill! Its perfect for my daily workouts. The setup was quick, and its so quiet that I can use it while watching TV without any interruptions. The different incline levels really help mix up my routine, and the built-in programs keep things interesting. Highly recommend for anyone looking to stay fit at home!</p>
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">I absolutely love my new treadmill! Its perfect for my daily workouts. The setup was quick, and its so quiet that I can use it while watching TV without any interruptions. The different incline levels really help mix up my routine, and the built-in programs keep things interesting. Highly recommend for anyone looking to stay fit at home!</p>
</div>
</div>
</div>
@@ -79,31 +80,31 @@ isPro: true
<span>5</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="63" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<wa-format-number type="percent" value=".63"></wa-format-number>
<span>63%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>4</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="17" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<wa-format-number type="percent" value=".17"></wa-format-number>
<span>17%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>3</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="15" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<wa-format-number type="percent" value=".15"></wa-format-number>
<span>15%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>2</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="3" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<wa-format-number type="percent" value=".03"></wa-format-number>
<span>3%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>1</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="2" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<wa-format-number type="percent" value=".02"></wa-format-number>
<span>2%</span>
</span>
</div>
</div>
@@ -112,44 +113,44 @@ isPro: true
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Michelle Jasper</span>
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p>I bought this grow light for my herbs and succulents, and wow—what a difference. After just a week, my basil perked up, and new leaves started popping up. Super easy to set up and doesnt get too hot. Highly recommend for anyone growing indoors!</p>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
<wa-divider></wa-divider>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Doug Michaels</span>
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p>This light really helps my plants grow during the winter months. The brightness is strong, and I love the adjustable height. The only downside is the timer—it resets if you unplug it. Otherwise, great value for the price!</p>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
<wa-divider></wa-divider>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1580489944761-15a19d654956?q=80&w=2561&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Stephanie Hurst</span>
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p>I dont get much natural light in my apartment, so this grow light has been a game-changer. Im using it for my small tomato plants and some lettuce, and theyre growing faster than expected. Plus, the light isnt too harsh on the eyes</p>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
<wa-divider></wa-divider>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1566492031773-4f4e44671857?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Miles Rogers</span>
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p>Ive tried a few grow lights, and this one is my favorite. It stays cool, uses less power, and my peace lilies and spider plants are growing beautifully. I just wish it came in more color options for the stand, but performance-wise, its excellent.</p>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
</div>
</div>
@@ -165,15 +166,15 @@ isPro: true
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1607746882042-944635dfe10e?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<p>Ripley</p>
<div>
<wa-icon-button name="thumbs-up" label="I don't like this review"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review"></wa-icon-button>
<wa-icon-button name="thumbs-up" label="I don't like this review" style="color: var(--wa-color-success-fill-loud);"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review" style="color: var(--wa-color-danger-fill-loud);"></wa-icon-button>
</div>
</div>
<div>
<wa-rating label="Rating" precision="0.5" value="5" readonly></wa-rating>
<p>I recently purchased the Modern Sofa Couch, and I couldn't be happier with my decision! The process from ordering to delivery was smooth and hassle-free</p>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-align-items-center">
@@ -181,15 +182,15 @@ isPro: true
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<p>Kane</p>
<div>
<wa-icon-button name="thumbs-up" label="I don't like this review"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review"></wa-icon-button>
<wa-icon-button name="thumbs-up" label="I don't like this review" style="color: var(--wa-color-success-fill-loud);"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review" style="color: var(--wa-color-danger-fill-loud);"></wa-icon-button>
</div>
</div>
<div>
<wa-rating label="Rating" precision="0.5" value="3.4" readonly></wa-rating>
<p>The cushions are soft yet supportive, and the sectional layout gives plenty of space to stretch out. Its perfect for movie nights or just lounging with a good book.</p>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-align-items-center">
@@ -197,15 +198,15 @@ isPro: true
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1728577740843-5f29c7586afe?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<p>Parker</p>
<div>
<wa-icon-button name="thumbs-up" label="I don't like this review"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review"></wa-icon-button>
<wa-icon-button name="thumbs-up" label="I don't like this review" style="color: var(--wa-color-success-fill-loud);"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review" style="color: var(--wa-color-danger-fill-loud);"></wa-icon-button>
</div>
</div>
<div>
<wa-rating label="Rating" precision="0.5" value="3.8" readonly></wa-rating>
<p>The leather is high quality, but its a little firmer than I thought. That said, after sitting on it for a while, it does soften up and feels more comfortable. Its perfect if youre looking for a more structured seating experience.</p>
</div>
</div>
<wa-divider></wa-divider>
</div>

View File

@@ -1,7 +1,8 @@
---
title: Shopping Cart
description: 'Give shoppers an overview of selected items with shopping carts that let them edit items and proceed to checkout.'
isPro: true
parent: ecommerce
tags: e-commerce
---
## Two Columns with Summary Card
@@ -13,7 +14,7 @@ isPro: true
<div class="wa-stack wa-gap-xl">
<article class="wa-flank wa-gap-xl" style="--flank-size: 8rem">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1523381294911-8d3cead13475?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDIzNDd8&ixlib=rb-4.0.3&q=80&w=1080"
alt=""
/>
@@ -31,7 +32,7 @@ isPro: true
</article>
<article class="wa-flank wa-gap-xl" style="--flank-size: 8rem">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1564859227552-81fde4a1df0b?q=80&w=2671&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
@@ -49,7 +50,7 @@ isPro: true
</article>
<article class="wa-flank wa-gap-xl" style="--flank-size: 8rem">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1503341733017-1901578f9f1e?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt=""
/>
@@ -204,12 +205,12 @@ isPro: true
<div class="wa-stack">
<article class="wa-flank" style="--flank-size: 6rem">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1704677982224-89cd6d039fa6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDEwOTJ8&ixlib=rb-4.0.3&q=80&w=1080"
alt=""
/>
</div>
<div class="wa-stack wa-gap-2xs">
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>AJ1 Low</strong>
<strong>$170.00</strong>
@@ -229,7 +230,7 @@ isPro: true
alt="(Photograph by Hamed darzi)"
/>
</div>
<div class="wa-stack wa-gap-2xs">
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>The Trails</strong>
<strong>$35.00</strong>
@@ -244,12 +245,12 @@ isPro: true
<wa-divider></wa-divider>
<article class="wa-flank" style="--flank-size: 6rem">
<div class="wa-frame wa-border-radius-m">
<img
<img
src="https://images.unsplash.com/photo-1693443687750-611ad77f3aba?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by tian dayong)"
/>
</div>
<div class="wa-stack wa-gap-2xs">
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>Outcast 2-pack</strong>
<strong>$27.00</strong>

View File

@@ -1,8 +1,8 @@
---
title: Store Navigation
description: 'Help shoppers explore categories and find products with all of the links they need to navigate your store.'
parent: ecommerce
unlisted: true
isPro: true
---
## Popup Menu

View File

@@ -0,0 +1,26 @@
---
title: E-commerce
description: ''
layout: page
---
{% set ecommercePages = collections['e-commerce'] %}
<section class="index-grid">
{%- for page in ecommercePages -%}
<a href="{{ page.url }}"{{ page.data.keywords | attr('data-keywords') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">{{ page.data.title }}</span>
{% if pageSubtitle -%}
<div class="wa-caption-s">{{ pageSubtitle }}</div>
{%- endif %}
</wa-card>
</a>
{%- endfor -%}
</section>

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