mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-14 13:09:14 +00:00
Compare commits
93 Commits
kj/e-comme
...
pattern-ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b30f9f39e | ||
|
|
1999b65591 | ||
|
|
444e0d3e46 | ||
|
|
5aeedceb2d | ||
|
|
1e1cd2406e | ||
|
|
e72f2c1847 | ||
|
|
910c6cb3fb | ||
|
|
55edcd2470 | ||
|
|
952a44b5eb | ||
|
|
2ca8422bc8 | ||
|
|
ff3b3d6558 | ||
|
|
6b3edb8a56 | ||
|
|
6162b8b115 | ||
|
|
cff752b600 | ||
|
|
7892a94b9b | ||
|
|
beb88fac56 | ||
|
|
a588194b95 | ||
|
|
a1ba80fe8d | ||
|
|
40a58ff35f | ||
|
|
0f2950c4cc | ||
|
|
b334884f57 | ||
|
|
a3edcaf27d | ||
|
|
734417d66b | ||
|
|
2cfd651d2f | ||
|
|
3e2d1b98be | ||
|
|
40f332f37c | ||
|
|
bfda64f690 | ||
|
|
883d6df2ef | ||
|
|
b4240fd321 | ||
|
|
8755a834f6 | ||
|
|
8d905296b8 | ||
|
|
8eba1e5003 | ||
|
|
595c40c0fa | ||
|
|
7e2f32a965 | ||
|
|
7b3bd8e027 | ||
|
|
5711819e9c | ||
|
|
760c09781d | ||
|
|
5b59bee2ff | ||
|
|
21aa85acc0 | ||
|
|
ec1ffcefdc | ||
|
|
404c15b303 | ||
|
|
8a26afc334 | ||
|
|
513a1e35a9 | ||
|
|
09f668fc99 | ||
|
|
d451ba98e5 | ||
|
|
fd287edd56 | ||
|
|
8424b49646 | ||
|
|
d828dd3600 | ||
|
|
0984cde1c5 | ||
|
|
5edad481f0 | ||
|
|
aab221dcb1 | ||
|
|
fa24c0f70e | ||
|
|
1bba87c66d | ||
|
|
0db9ca12e3 | ||
|
|
041555fe99 | ||
|
|
b41dbd2de7 | ||
|
|
7c6f31e0c7 | ||
|
|
9e84274a93 | ||
|
|
2b3803f91e | ||
|
|
faed8da3cd | ||
|
|
17cf902f53 | ||
|
|
8214ff6b2d | ||
|
|
c9979e15f8 | ||
|
|
bbe6b4c6b3 | ||
|
|
fcfe2bde7d | ||
|
|
6ee5c27b9d | ||
|
|
c3af1174ca | ||
|
|
59dcaaff83 | ||
|
|
5bad30ec30 | ||
|
|
87c1762146 | ||
|
|
db5b967390 | ||
|
|
8e3ffc4abe | ||
|
|
899edd1d5e | ||
|
|
872a110b1e | ||
|
|
b5523c33b7 | ||
|
|
f031cab138 | ||
|
|
67c46a21dd | ||
|
|
07fe6d598e | ||
|
|
c310ee1072 | ||
|
|
8fff50d3d8 | ||
|
|
79bafc513a | ||
|
|
944f9002c7 | ||
|
|
eba2a75ffb | ||
|
|
c3de5a8915 | ||
|
|
c18aa23d76 | ||
|
|
54e14a20c0 | ||
|
|
55a362b741 | ||
|
|
81bf6865ec | ||
|
|
27237441a1 | ||
|
|
b0291653f8 | ||
|
|
7f29f1b4ea | ||
|
|
9ad7f4a6be | ||
|
|
a7457630aa |
9
.github/workflows/ssr_tests.js.yml
vendored
9
.github/workflows/ssr_tests.js.yml
vendored
@@ -1,11 +1,12 @@
|
||||
# # 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]
|
||||
# push:
|
||||
# branches: [next]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
ssr_test:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
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';
|
||||
@@ -6,9 +7,10 @@ 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 componentList from './_data/componentList.js';
|
||||
import nunjucks from 'nunjucks';
|
||||
// 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';
|
||||
@@ -16,7 +18,10 @@ import { searchPlugin } from './_utils/search.js';
|
||||
|
||||
import process from 'process';
|
||||
|
||||
const packageData = JSON.parse(await readFile('./package.json', 'utf-8'));
|
||||
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 isAlpha = process.argv.includes('--alpha');
|
||||
const isDev = process.argv.includes('--develop');
|
||||
|
||||
@@ -24,12 +29,22 @@ 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) {
|
||||
/**
|
||||
* 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/**');
|
||||
@@ -55,7 +70,38 @@ export default function (eleventyConfig) {
|
||||
|
||||
// Shortcodes - {% shortCode arg1, arg2 %}
|
||||
eleventyConfig.addShortcode('cdnUrl', location => {
|
||||
return `https://early.webawesome.com/webawesome@${packageData.version}/dist/` + location.replace(/^\//, '');
|
||||
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: '',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Paired shortcodes - {% shortCode %}content{% endShortCode %}
|
||||
@@ -117,29 +163,6 @@ 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({
|
||||
@@ -166,6 +189,31 @@ 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: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
|
||||
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}" class="wa-cloak">
|
||||
<head>
|
||||
{% include 'head.njk' %}
|
||||
<meta name="theme-color" content="#f36944">
|
||||
@@ -50,6 +50,9 @@
|
||||
Search
|
||||
<kbd slot="suffix" class="only-desktop">/</kbd>
|
||||
</wa-button>
|
||||
|
||||
{# Login #}
|
||||
{% server "loginOrAvatar" %}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -76,14 +79,19 @@
|
||||
</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' %}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{% set breadcrumbs = page.url | breadcrumbs %}
|
||||
{% if breadcrumbs.length > 0 %}
|
||||
{% set ancestors = page.url | ancestors %}
|
||||
|
||||
{% if ancestors.length > 0 %}
|
||||
<wa-breadcrumb id="docs-breadcrumbs">
|
||||
{% for crumb in breadcrumbs %}
|
||||
<wa-breadcrumb-item href="{{ crumb.url }}">{{ crumb.title }}</wa-breadcrumb-item>
|
||||
{% for ancestor in ancestors %}
|
||||
{% if ancestor.page.url != "/" %}
|
||||
<wa-breadcrumb-item href="{{ ancestor.page.url }}">{{ ancestor.data.title }}</wa-breadcrumb-item>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<wa-breadcrumb-item>{# Current page #}</wa-breadcrumb-item>
|
||||
</wa-breadcrumb>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
{# Cards for pages listed by category #}
|
||||
|
||||
<section id="grid" class="index-grid">
|
||||
{% 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 -%}
|
||||
{% 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 -%}
|
||||
{%- endfor -%}
|
||||
</section>
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
<script src="/assets/scripts/hydration-errors.js"></script>
|
||||
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
|
||||
<link rel="preconnect" href="https://cdn.jsdelivr.net">
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
|
||||
|
||||
{# Internal components #}
|
||||
<script type="module" src="/assets/components/scoped.js"></script>
|
||||
|
||||
{# Web Awesome #}
|
||||
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
|
||||
<script type="module" src="/dist/webawesome.loader.js"></script>
|
||||
|
||||
<script type="module" src="/assets/scripts/theme-picker.js"></script>
|
||||
{# Preset Theme #}
|
||||
@@ -47,3 +49,6 @@
|
||||
<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" %}
|
||||
|
||||
@@ -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" %}
|
||||
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" ignore missing %}
|
||||
</div>
|
||||
<span class="page-name">{{ page.data.title }}</span>
|
||||
{% if pageSubtitle -%}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
{# 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 groupUrl | getCollectionItemFromUrl %}
|
||||
{% if groupItem %}
|
||||
<a href="{{ groupUrl }}" title="Overview">{{ title or (tag | capitalize) }}
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
@@ -12,10 +15,8 @@
|
||||
{% endif %}
|
||||
</h2>
|
||||
<ul>
|
||||
{% for page in collections[tag] | sort %}
|
||||
{% if not page.data.parent -%}
|
||||
{% for page in children %}
|
||||
{% include 'sidebar-link.njk' %}
|
||||
{%- endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</wa-details>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% if not (isAlpha and page.data.noAlpha) and page.fileSlug != tag and not page.data.unlisted -%}
|
||||
{% if page | show -%}
|
||||
<li>
|
||||
<a href="{{ page.url }}">{{ page.data.title }}</a>
|
||||
{% if page.data.status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{# Getting started #}
|
||||
<h2>Getting Started</h2>
|
||||
<ul>
|
||||
<li><a href="/docs/installation">Installation</a></li>
|
||||
<li><a href="/docs/">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>
|
||||
|
||||
8
docs/_includes/svgs/action-panel.njk
Normal file
8
docs/_includes/svgs/action-panel.njk
Normal file
@@ -0,0 +1,8 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 587 B |
@@ -1,31 +1,20 @@
|
||||
{% 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 %}
|
||||
|
||||
{% 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>
|
||||
<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">
|
||||
|
||||
{% 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>
|
||||
<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 }}"> </div>
|
||||
{%- endfor %}
|
||||
{%- endfor %}
|
||||
</div>
|
||||
</template>
|
||||
</wa-scoped>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{% set themeId = theme.fileSlug %}
|
||||
|
||||
<div>
|
||||
<template shadowrootmode="open">
|
||||
<wa-scoped class="theme-icon-host theme-color-icon-host">
|
||||
<template>
|
||||
<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-color-icon wa-theme-{{ themeId }}">
|
||||
<div class="theme-icon 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>
|
||||
</div>
|
||||
</wa-scoped>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{% set themeId = theme.fileSlug %}
|
||||
{% set themeId = theme.fileSlug or page.fileSlug %}
|
||||
|
||||
<div>
|
||||
<template shadowrootmode="open">
|
||||
<wa-scoped class="theme-icon-host theme-typography-icon-host">
|
||||
<template>
|
||||
<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-typography-icon wa-theme-{{ themeId }}" data-no-outline data-no-anchor role="presentation">
|
||||
<div class="theme-icon theme-typography-icon wa-theme-{{ themeId }}" data-no-outline data-no-anchor role="presentation">
|
||||
<h3>Title</h3>
|
||||
<p>Body text</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</wa-scoped>
|
||||
|
||||
29
docs/_includes/svgs/theme.njk
Normal file
29
docs/_includes/svgs/theme.njk
Normal file
@@ -0,0 +1,29 @@
|
||||
{% 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>
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
layout: page-outline
|
||||
tags: ["overview"]
|
||||
---
|
||||
{% set forTag = forTag or (page.url | split('/') | last) %}
|
||||
{% if description %}
|
||||
@@ -13,8 +12,10 @@ tags: ["overview"]
|
||||
</wa-input>
|
||||
</div>
|
||||
|
||||
{% set allPages = collections[forTag] %}
|
||||
{% set allPages = allPages or collections[forTag] %}
|
||||
{% if allPages and allPages.length > 0 %}
|
||||
{% include "grouped-pages.njk" %}
|
||||
{% endif %}
|
||||
|
||||
<link href="/assets/styles/filter.css" rel="stylesheet">
|
||||
<script type="module" src="/assets/scripts/filter.js"></script>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = false %}
|
||||
{% if hasSidebar == undefined %}
|
||||
{% set hasSidebar = true %}
|
||||
{% endif %}
|
||||
|
||||
{% if hasOutline == undefined %}
|
||||
{% set hasOutline = false %}
|
||||
{% endif %}
|
||||
|
||||
{% extends "../_includes/base.njk" %}
|
||||
|
||||
@@ -30,12 +30,21 @@
|
||||
|
||||
{% include 'breadcrumbs.njk' %}
|
||||
|
||||
<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 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>
|
||||
<h1 v-if="!saved" class="title">{{ title }}</h1>
|
||||
|
||||
<div class="block-info">
|
||||
<code class="class">.wa-palette-{{ paletteId }}</code>
|
||||
@@ -59,7 +68,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)">{% raw %}{{ tweakHumanReadable }}{% endraw %}</wa-tag>
|
||||
<wa-tag v-for="tweakHumanReadable, param in tweaksHumanReadable" removable @wa-remove="reset(param)" v-content="tweakHumanReadable"></wa-tag>
|
||||
</div>
|
||||
|
||||
<wa-button @click="reset()" appearance="outlined" variant="danger">
|
||||
@@ -68,13 +77,6 @@
|
||||
</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 }}">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends '../_layouts/block.njk' %}
|
||||
|
||||
{% block head %}
|
||||
<link href="{{ page.url }}../patterns.css" rel="stylesheet">
|
||||
<link href="/docs/patterns/patterns.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
@@ -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" %}
|
||||
{% include "svgs/" + (palette.data.icon or "thumbnail-placeholder") + ".njk" ignore missing %}
|
||||
</div>
|
||||
<span class="page-name">
|
||||
{{ palette.data.title }}
|
||||
|
||||
@@ -29,6 +29,9 @@ function getCollection(name) {
|
||||
}
|
||||
|
||||
export function getCollectionItemFromUrl(url, collection) {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
collection ??= getCollection.call(this, 'all') || [];
|
||||
return collection.find(item => item.url === url);
|
||||
}
|
||||
@@ -42,35 +45,33 @@ export function split(text, separator) {
|
||||
return (text + '').split(separator).filter(Boolean);
|
||||
}
|
||||
|
||||
export function breadcrumbs(url, { withCurrent = false } = {}) {
|
||||
const parts = split(url, '/');
|
||||
const ret = [];
|
||||
export function ancestors(url, { withCurrent = false, withRoot = false } = {}) {
|
||||
let ret = [];
|
||||
let currentUrl = url;
|
||||
let currentItem = getCollectionItemFromUrl.call(this, url);
|
||||
|
||||
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];
|
||||
if (!currentItem) {
|
||||
// Might have eleventyExcludeFromCollections, jump to parent
|
||||
let parentUrl = this.ctx.parentUrl;
|
||||
if (parentUrl) {
|
||||
url = parentUrl;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -177,72 +178,196 @@ 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 | 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.
|
||||
* @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.
|
||||
*/
|
||||
export function groupByTags(collection, tags) {
|
||||
export function groupPages(collection, options = {}, page) {
|
||||
if (!collection) {
|
||||
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);
|
||||
console.error(`Empty collection passed to groupPages() to group by ${JSON.stringify(options)}`);
|
||||
}
|
||||
|
||||
let ret = Object.fromEntries(tags.map(tag => [tag, []]));
|
||||
ret.other = [];
|
||||
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);
|
||||
}
|
||||
|
||||
for (let item of collection) {
|
||||
let categorized = false;
|
||||
let url = item.page.url;
|
||||
let parentUrl = item.data.parentUrl;
|
||||
|
||||
for (let tag of tags) {
|
||||
if (item.data.tags.includes(tag)) {
|
||||
ret[tag].push(item);
|
||||
categorized = true;
|
||||
}
|
||||
}
|
||||
byUrl[url] = item;
|
||||
|
||||
if (!categorized) {
|
||||
ret.other.push(item);
|
||||
if (parentUrl) {
|
||||
byParentUrl[parentUrl] ??= [];
|
||||
byParentUrl[parentUrl].push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty categories
|
||||
for (let category in ret) {
|
||||
if (ret[category].length === 0) {
|
||||
delete ret[category];
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
function capitalize(str) {
|
||||
str += '';
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
const IDENTITY = x => x;
|
||||
|
||||
@@ -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('a').forEach(a => a.remove());
|
||||
clone.querySelectorAll('.wa-visually-hidden, [hidden], [aria-hidden="true"]').forEach(el => el.remove());
|
||||
clone.querySelectorAll('[data-no-outline]').forEach(el => el.remove());
|
||||
|
||||
// Generate the link
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
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) {
|
||||
@@ -52,8 +53,9 @@ export function searchPlugin(options = {}) {
|
||||
return content;
|
||||
});
|
||||
|
||||
eleventyConfig.on('eleventy.after', ({ dir }) => {
|
||||
const outputFilename = join(dir.output, 'search.json');
|
||||
eleventyConfig.on('eleventy.after', ({ directories }) => {
|
||||
const { output } = directories;
|
||||
const outputFilename = path.resolve(join(output, 'search.json'));
|
||||
const map = [];
|
||||
const searchIndex = lunr(async function () {
|
||||
let index = 0;
|
||||
|
||||
171
docs/assets/components/scoped.js
Normal file
171
docs/assets/components/scoped.js
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ document.addEventListener('click', event => {
|
||||
const code = codeExample.querySelector('code');
|
||||
const cdnUrl = document.documentElement.dataset.cdnUrl;
|
||||
const html =
|
||||
`<script type="module" src="${cdnUrl}webawesome.loader.js"></script>\n` +
|
||||
`<script data-fa-kit-code="b10bfbde90" 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` +
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
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);
|
||||
@@ -18,8 +26,10 @@ function updateResults(input) {
|
||||
}
|
||||
}
|
||||
|
||||
const debouncedUpdateResults = debounce(updateResults, 300);
|
||||
|
||||
document.documentElement.addEventListener('input', e => {
|
||||
if (e.target?.matches('#block-filter wa-input')) {
|
||||
updateResults(e.target);
|
||||
debouncedUpdateResults(e.target);
|
||||
}
|
||||
});
|
||||
|
||||
167
docs/assets/scripts/my.js
Normal file
167
docs/assets/scripts/my.js
Normal file
@@ -0,0 +1,167 @@
|
||||
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',
|
||||
});
|
||||
@@ -1,254 +1,119 @@
|
||||
const sidebar = (globalThis.sidebar = {});
|
||||
import my from '/assets/scripts/my.js';
|
||||
|
||||
sidebar.palettes = {
|
||||
render() {
|
||||
if (this.saved.length === 0) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
|
||||
for (let palette of this.saved) {
|
||||
sidebar.palette.render(palette);
|
||||
}
|
||||
|
||||
sidebar.updateCurrent();
|
||||
},
|
||||
|
||||
updateSaved() {
|
||||
this.saved = localStorage.savedPalettes ? JSON.parse(localStorage.savedPalettes) : [];
|
||||
},
|
||||
|
||||
save(saved = this.saved) {
|
||||
this.saved = saved ?? [];
|
||||
|
||||
if (saved.length > 0) {
|
||||
localStorage.savedPalettes = JSON.stringify(saved);
|
||||
} else {
|
||||
delete localStorage.savedPalettes;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
sidebar.palettes.updateSaved();
|
||||
addEventListener('storage', event => sidebar.palettes.updateSaved());
|
||||
|
||||
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;
|
||||
// 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');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
equals(p1, p2) {
|
||||
if (!p1 || !p2) {
|
||||
return false;
|
||||
a.classList.add('current');
|
||||
}
|
||||
|
||||
return p1.id === p2.id && p1.uid === p2.uid;
|
||||
return a;
|
||||
},
|
||||
|
||||
delete(palette) {
|
||||
let savedPalettes = sidebar.palettes.saved;
|
||||
let count = savedPalettes.length;
|
||||
if (count === 0) {
|
||||
removeLink(a) {
|
||||
if (!a || !a.isConnected) {
|
||||
// Link doesn't exist or is already removed
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO improve UX of this
|
||||
if (!confirm(`Are you sure you want to delete palette “${palette.title}”?`)) {
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
if (a.classList.contains('current')) {
|
||||
// If the deleted palette was the current one, the current one is now the parent
|
||||
parentA.classList.add('current');
|
||||
}
|
||||
},
|
||||
|
||||
getSaved(palette, savedPalettes = sidebar.palettes.saved) {
|
||||
return savedPalettes.find(p => sidebar.palette.equals(p, palette));
|
||||
findEntity(entity) {
|
||||
return document.querySelector(`#sidebar a[href^="${entity.baseUrl}"][data-uid="${entity.uid}"]`);
|
||||
},
|
||||
|
||||
render(palette) {
|
||||
// Find existing <a>
|
||||
let { title, id, search, uid } = palette;
|
||||
renderEntity(entity) {
|
||||
let { url, parentUrl } = entity;
|
||||
|
||||
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}"]`);
|
||||
// Find parent
|
||||
let parentA = document.querySelector(`#sidebar a[href="${parentUrl}"]`);
|
||||
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);
|
||||
if (!parentLi) {
|
||||
throw new Error(`Cannot find parent url ${parentUrl}`);
|
||||
}
|
||||
|
||||
this.render(palette, oldValues);
|
||||
sidebar.updateCurrent();
|
||||
// Find existing
|
||||
let a = this.findEntity(entity);
|
||||
let alreadyExisted = !!a;
|
||||
|
||||
sidebar.palettes.save(savedPalettes);
|
||||
},
|
||||
};
|
||||
a ??= document.createElement('a');
|
||||
|
||||
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 = [];
|
||||
a.textContent = entity.title;
|
||||
a.href = url;
|
||||
|
||||
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('/') + '/');
|
||||
}
|
||||
}
|
||||
if (!alreadyExisted) {
|
||||
a.dataset.uid = entity.uid;
|
||||
|
||||
// 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);
|
||||
}
|
||||
a = sidebar.addChild(a, parentA);
|
||||
|
||||
// We want to start from the longest prefix
|
||||
prefixes.reverse();
|
||||
let candidates;
|
||||
let matchingPrefix;
|
||||
// This is mainly to port Pro badges
|
||||
let badges = Array.from(parentLi.querySelectorAll('wa-badge'), badge => badge.cloneNode(true));
|
||||
let append = [...badges];
|
||||
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
if (candidates.length > 0) {
|
||||
for (let current of document.querySelectorAll('#sidebar a.current')) {
|
||||
current.classList.remove('current');
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
candidates[0].classList.add('current');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
sidebar.render = function () {
|
||||
this.palettes.render();
|
||||
};
|
||||
globalThis.sidebar = sidebar;
|
||||
|
||||
// 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.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;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
let initialPageLoadComplete = document.readyState === 'complete';
|
||||
|
||||
if (!initialPageLoadComplete) {
|
||||
window.addEventListener('load', () => {
|
||||
initialPageLoadComplete = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper for view transitions
|
||||
export function domChange(fn, { behavior = 'smooth' } = {}) {
|
||||
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') {
|
||||
document.startViewTransition(fn);
|
||||
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(true);
|
||||
fn(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +120,7 @@ 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 } }));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm';
|
||||
import { preventTurboFouce } from '/dist/webawesome.js';
|
||||
|
||||
if (!window.___turboScrollPositions___) {
|
||||
window.___turboScrollPositions___ = {};
|
||||
}
|
||||
@@ -70,3 +73,4 @@ function fixDSD(e) {
|
||||
window.addEventListener('turbo:before-cache', saveScrollPosition);
|
||||
window.addEventListener('turbo:before-render', restoreScrollPosition);
|
||||
window.addEventListener('turbo:render', restoreScrollPosition);
|
||||
preventTurboFouce();
|
||||
|
||||
@@ -13,56 +13,42 @@ export default class Permalink extends URLSearchParams {
|
||||
return Object.fromEntries(this.entries());
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
writeTo(obj) {
|
||||
let mapping = this.#mappings.get(obj) ?? {};
|
||||
let { keyTo = IDENTITY, valueTo = IDENTITY, canExtend = false } = mapping;
|
||||
|
||||
for (let [key, value] of this) {
|
||||
let mappedKey = keyTo(key);
|
||||
let mappedValue = valueTo(value);
|
||||
|
||||
if (canExtend || mappedKey in obj) {
|
||||
obj[mappedKey] = mappedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(key, value, defaultValue) {
|
||||
let oldValue = this.get(key);
|
||||
if (equals(value, defaultValue) || equals(value, '')) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (!value || value == defaultValue) {
|
||||
value ??= null; // undefined -> null
|
||||
|
||||
let oldValue = Array.isArray(value) ? this.getAll(key) : this.get(key);
|
||||
let changed = !equals(value, oldValue);
|
||||
|
||||
if (!changed) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
super.delete(key);
|
||||
value = value.slice();
|
||||
|
||||
if (oldValue) {
|
||||
this.changed = true;
|
||||
for (let v of value) {
|
||||
if (v || v === 0) {
|
||||
if (typeof v === 'object') {
|
||||
super.append(key, JSON.stringify(v));
|
||||
} else {
|
||||
super.append(key, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (value === null) {
|
||||
super.delete(key);
|
||||
} else {
|
||||
super.set(key, value);
|
||||
|
||||
if (String(value) !== String(oldValue)) {
|
||||
this.changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.sort();
|
||||
this.changed ||= changed;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,3 +65,40 @@ 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];
|
||||
}
|
||||
|
||||
22
docs/assets/scripts/vue/directives/content.js
Normal file
22
docs/assets/scripts/vue/directives/content.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
110
docs/assets/scripts/vue/mixins/saved.js
Normal file
110
docs/assets/scripts/vue/mixins/saved.js
Normal file
@@ -0,0 +1,110 @@
|
||||
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();
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -4,6 +4,7 @@
|
||||
@import 'outline.css';
|
||||
@import 'search.css';
|
||||
@import 'cera_typeface.css';
|
||||
@import 'theme-icons.css';
|
||||
|
||||
:root {
|
||||
--wa-brand-orange: #f36944;
|
||||
@@ -370,10 +371,22 @@ wa-page > main:has(> .index-grid) {
|
||||
|
||||
.index-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(22ch, 100%), 1fr));
|
||||
grid-template-columns: repeat(4, 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;
|
||||
@@ -400,7 +413,6 @@ 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;
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
&::part(base) {
|
||||
margin-block: 10rem;
|
||||
&::part(dialog) {
|
||||
margin-block-start: 10vh;
|
||||
margin-block-end: 0;
|
||||
}
|
||||
|
||||
&::part(body) {
|
||||
@@ -23,20 +24,20 @@
|
||||
@media screen and (max-width: 900px) {
|
||||
max-width: calc(100% - 2rem);
|
||||
|
||||
&::part(base) {
|
||||
&::part(dialog) {
|
||||
margin-block: 1rem;
|
||||
}
|
||||
|
||||
#site-search-container {
|
||||
max-height: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#site-search-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: calc(100vh - 20rem);
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
max-height: calc(100dvh - 2rem);
|
||||
}
|
||||
max-height: calc(100vh - 18rem);
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
@@ -1,3 +1,61 @@
|
||||
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);
|
||||
@@ -25,10 +83,50 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
h3,
|
||||
p {
|
||||
margin-block: 0;
|
||||
padding: 0;
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>6 weeks old</small>
|
||||
<small class="wa-caption-m">6 weeks old</small>
|
||||
|
||||
<div slot="footer">
|
||||
<div slot="footer" class="wa-split">
|
||||
<wa-button variant="brand" pill>More Info</wa-button>
|
||||
<wa-rating label="Rating"></wa-rating>
|
||||
</div>
|
||||
@@ -27,16 +27,6 @@ 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>
|
||||
```
|
||||
|
||||
@@ -65,9 +55,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">
|
||||
<div slot="header" class="wa-split">
|
||||
Header Title
|
||||
<wa-icon-button name="gear" variant="solid" label="Settings"></wa-icon-button>
|
||||
<wa-icon-button name="gear" variant="solid" label="Settings" class="wa-size-m"></wa-icon-button>
|
||||
</div>
|
||||
|
||||
This card has a header. You can put all sorts of things in it!
|
||||
@@ -78,19 +68,9 @@ 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>
|
||||
```
|
||||
|
||||
@@ -103,7 +83,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">
|
||||
<div slot="footer" class="wa-split">
|
||||
<wa-rating></wa-rating>
|
||||
<wa-button variant="brand">Preview</wa-button>
|
||||
</div>
|
||||
@@ -113,12 +93,6 @@ 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>
|
||||
```
|
||||
|
||||
@@ -153,7 +127,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-flank">
|
||||
<footer slot="footer" class="wa-split">
|
||||
<wa-button variant="brand" pill>More Info</wa-button>
|
||||
<wa-rating></wa-rating>
|
||||
</footer>
|
||||
@@ -162,7 +136,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-flank">
|
||||
<footer slot="footer" class="wa-split">
|
||||
<wa-button variant="brand" pill>More Info</wa-button>
|
||||
<wa-rating></wa-rating>
|
||||
</footer>
|
||||
@@ -171,14 +145,39 @@ 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-flank">
|
||||
<footer slot="footer" class="wa-split">
|
||||
<wa-button variant="brand" pill>More Info</wa-button>
|
||||
<wa-rating></wa-rating>
|
||||
</footer>
|
||||
</wa-card>
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||
<style>
|
||||
</style>
|
||||
### 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>
|
||||
```
|
||||
|
||||
@@ -77,6 +77,31 @@ The details component automatically adapts to right-to-left languages:
|
||||
</wa-details>
|
||||
```
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the `appearance` attribute to change the element’s 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.
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
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
|
||||
categories:
|
||||
- actions
|
||||
- feedback: 'Feedback & Status'
|
||||
- imagery
|
||||
- inputs
|
||||
- navigation
|
||||
- organization
|
||||
- helpers: 'Utilities'
|
||||
override:tags: []
|
||||
categories:
|
||||
tags: [actions, feedback, imagery, inputs, navigation, organization, helpers]
|
||||
titles:
|
||||
feedback: 'Feedback & Status'
|
||||
helpers: 'Utilities'
|
||||
---
|
||||
|
||||
@@ -885,4 +885,4 @@ If you don’t want to use [native styles](/docs/native/), you can include this
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/components/page.css' %}" />
|
||||
```
|
||||
```
|
||||
@@ -1,10 +1,108 @@
|
||||
/**
|
||||
* Global data for all pages
|
||||
*/
|
||||
import { sort } from '../_utils/filters.js';
|
||||
|
||||
export default {
|
||||
eleventyComputed: {
|
||||
children(data) {
|
||||
let mainTag = data.tags?.[0];
|
||||
let collection = data.collections[mainTag] ?? [];
|
||||
/**
|
||||
* 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;
|
||||
|
||||
return collection.filter(item => item.data.parent === data.page.fileSlug);
|
||||
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;
|
||||
|
||||
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;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -32,15 +32,11 @@ 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
|
||||
@@ -62,7 +58,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
|
||||
|
||||
@@ -126,4 +122,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>
|
||||
```
|
||||
```
|
||||
@@ -2,6 +2,7 @@
|
||||
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: []
|
||||
---
|
||||
@@ -22,4 +23,4 @@ Or, you can choose to import _only_ the utilities:
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/utilities.css' %}" />
|
||||
```
|
||||
{% endmarkdown %}
|
||||
{% endmarkdown %}
|
||||
|
||||
@@ -33,7 +33,7 @@ Use the [variant utility classes](../utilities/color.md) to set the button's sem
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the [appearance utility classes](../utilities/appearance.md) to change the button's visual appearance:
|
||||
Use the [appearance utility classes](/docs/utilities/appearance) to change the button's visual appearance:
|
||||
|
||||
```html {.example}
|
||||
<div style="margin-block-end: 1rem;">
|
||||
|
||||
@@ -57,7 +57,7 @@ Use the [variant utility classes](../utilities/color.md) to set the callout's co
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the [appearance utility classes](../utilities/appearance.md) to change the callout's visual appearance (the default is `outlined filled`).
|
||||
Use the [appearance utility classes](/docs/utilities/appearance) to change the callout's visual appearance (the default is `outlined filled`).
|
||||
|
||||
```html {.example}
|
||||
<article class="wa-callout wa-brand wa-outlined wa-accent">
|
||||
|
||||
@@ -19,6 +19,35 @@ 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:
|
||||
|
||||
@@ -5,6 +5,6 @@ layout: overview
|
||||
override:tags: []
|
||||
forTag: palette
|
||||
categories:
|
||||
tags: [other, pro]
|
||||
other: Free
|
||||
pro: Pro
|
||||
---
|
||||
|
||||
@@ -6,6 +6,8 @@ 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)));
|
||||
|
||||
@@ -38,24 +40,25 @@ 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 paletteId = appRoot.dataset.paletteId;
|
||||
let palette = allPalettes[paletteId];
|
||||
let id = appRoot.dataset.paletteId;
|
||||
let palette = allPalettes[id];
|
||||
|
||||
return {
|
||||
uid: undefined,
|
||||
paletteId,
|
||||
paletteTitle: palette.title,
|
||||
id,
|
||||
originalTitle: palette.title,
|
||||
originalColors: palette.colors,
|
||||
permalink: new Permalink(),
|
||||
hueRanges,
|
||||
hueShifts: Object.fromEntries(hues.map(hue => [hue, 0])),
|
||||
chromaScale: 1,
|
||||
grayChroma: undefined,
|
||||
grayColor: undefined,
|
||||
tweaking: {},
|
||||
saved: null,
|
||||
type: 'palette',
|
||||
collection: 'palettes',
|
||||
};
|
||||
},
|
||||
|
||||
@@ -63,20 +66,16 @@ 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) {
|
||||
// Update from URL
|
||||
this.permalink.writeTo(this.hueShifts);
|
||||
// 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'));
|
||||
}
|
||||
}
|
||||
|
||||
for (let param of ['chroma-scale', 'gray-color', 'gray-chroma']) {
|
||||
if (this.permalink.has(param)) {
|
||||
@@ -91,12 +90,6 @@ let paletteAppSpec = {
|
||||
this[prop] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.permalink.has('uid')) {
|
||||
this.uid = Number(this.permalink.get('uid'));
|
||||
}
|
||||
|
||||
this.saved = sidebar.palette.getSaved(this.getPalette());
|
||||
}
|
||||
},
|
||||
|
||||
@@ -107,6 +100,11 @@ let paletteAppSpec = {
|
||||
},
|
||||
|
||||
computed: {
|
||||
/** Default palette title for saving */
|
||||
defaultTitle() {
|
||||
return this.originalTitle + ' (tweaked)';
|
||||
},
|
||||
|
||||
tweaks() {
|
||||
return {
|
||||
hueShifts: this.hueShifts,
|
||||
@@ -123,7 +121,7 @@ let paletteAppSpec = {
|
||||
code() {
|
||||
let ret = {};
|
||||
for (let language of ['html', 'css']) {
|
||||
let code = getPaletteCode(this.paletteId, this.colors, this.tweaked, { language, cdnUrl });
|
||||
let code = getPaletteCode(this.id, this.colors, this.tweaked, { language, cdnUrl });
|
||||
ret[language] = {
|
||||
raw: code,
|
||||
highlighted: Prism.highlight(code, Prism.languages[language], language),
|
||||
@@ -284,7 +282,9 @@ let paletteAppSpec = {
|
||||
hueShifts: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.permalink.readFrom(this.hueShifts);
|
||||
for (let hue in this.hueShifts) {
|
||||
this.permalink.set(hue + '-shift', this.hueShifts[hue], 0);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -308,69 +308,12 @@ let paletteAppSpec = {
|
||||
// Update page URL
|
||||
this.permalink.updateLocation();
|
||||
|
||||
if (this.saved) {
|
||||
this.save({ silent: true });
|
||||
}
|
||||
this.unsavedChanges = 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.
|
||||
@@ -399,28 +342,7 @@ let paletteAppSpec = {
|
||||
},
|
||||
|
||||
directives: {
|
||||
// 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;
|
||||
}
|
||||
},
|
||||
content,
|
||||
},
|
||||
|
||||
compilerOptions: {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
66
docs/docs/patterns/app/action-panel.md
Normal file
66
docs/docs/patterns/app/action-panel.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Action Panel
|
||||
description: 'Help users complete tasks efficiently with quick access to key actions.'
|
||||
icon: action-panel
|
||||
---
|
||||
|
||||
## Simple
|
||||
|
||||
```html {.example}
|
||||
<wa-card style="max-width: 60ch; margin: auto">
|
||||
<div class="wa-stack wa-align-items-start">
|
||||
<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>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
## With Flanked Button
|
||||
|
||||
```html {.example}
|
||||
<wa-card style="max-width: 60ch; margin: 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>
|
||||
</div>
|
||||
<wa-button variant="brand">New Query</wa-button>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
## 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-0">
|
||||
<span class="wa-heading-s">Super Dog</span>
|
||||
<span class="wa-caption-m">Online</span>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
206
docs/docs/patterns/app/activity-log.md
Normal file
206
docs/docs/patterns/app/activity-log.md
Normal file
@@ -0,0 +1,206 @@
|
||||
---
|
||||
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-l">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-xl)" 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-xl)" 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-xl)" 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-xl)" 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-xl)" 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-xl)" 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>
|
||||
```
|
||||
3
docs/docs/patterns/app/app.json
Normal file
3
docs/docs/patterns/app/app.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tags": ["app"]
|
||||
}
|
||||
164
docs/docs/patterns/app/comments.md
Normal file
164
docs/docs/patterns/app/comments.md
Normal file
@@ -0,0 +1,164 @@
|
||||
---
|
||||
title: Comments
|
||||
description: 'Enable users to engage in discussions, provide feedback, or record their thoughts.'
|
||||
---
|
||||
|
||||
## 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">
|
||||
<wa-icon slot="prefix" name="paperclip" variant="solid"></wa-icon>
|
||||
Attach a file
|
||||
</wa-button>
|
||||
<wa-button variant="brand">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>
|
||||
</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>
|
||||
</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
|
||||
|
||||
```html {.example}
|
||||
<wa-card with-header with-footer style="max-width: 60ch; margin: auto">
|
||||
<div slot="header">
|
||||
<h3 class="wa-heading-s">I watched...</h3>
|
||||
</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=""
|
||||
/>
|
||||
</div>
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
```
|
||||
152
docs/docs/patterns/app/data-display.md
Normal file
152
docs/docs/patterns/app/data-display.md
Normal file
@@ -0,0 +1,152 @@
|
||||
---
|
||||
title: Data Display
|
||||
description: 'Convey insights, metrics, and aggregate data at a glance.'
|
||||
---
|
||||
|
||||
|
||||
## Simple
|
||||
```html {.example}
|
||||
<wa-card>
|
||||
<div class="wa-grid wa-gap-3xl">
|
||||
<div class="wa-stack">
|
||||
<div class="wa-split">
|
||||
<span>Revenue</span>
|
||||
<span>+4.75%</span>
|
||||
</div>
|
||||
<div class="wa-heading-2xl">$400,000</div>
|
||||
</div>
|
||||
<div class="wa-stack">
|
||||
<div class="wa-split">
|
||||
<span>Revenue</span>
|
||||
<span>+4.75%</span>
|
||||
</div>
|
||||
<div class="wa-heading-2xl">$400,000</div>
|
||||
</div>
|
||||
<div class="wa-stack">
|
||||
<div class="wa-split">
|
||||
<span>Revenue</span>
|
||||
<span>+4.75%</span>
|
||||
</div>
|
||||
<div class="wa-heading-2xl">$400,000</div>
|
||||
</div>
|
||||
<div class="wa-stack">
|
||||
<div class="wa-split">
|
||||
<span>Revenue</span>
|
||||
<span>+4.75%</span>
|
||||
</div>
|
||||
<div class="wa-heading-2xl">$400,000</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
## Cards with Avatars
|
||||
```html {.example}
|
||||
<div class="wa-grid" style="--min-column-size: 30ch">
|
||||
<wa-card>
|
||||
<div class="wa-flank wa-align-items-start">
|
||||
<wa-avatar shape="rounded">
|
||||
<wa-icon slot="icon" name="user-group"></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>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Condensed Card
|
||||
|
||||
```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>
|
||||
</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>
|
||||
<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-card>
|
||||
```
|
||||
252
docs/docs/patterns/app/description-list.md
Normal file
252
docs/docs/patterns/app/description-list.md
Normal file
@@ -0,0 +1,252 @@
|
||||
---
|
||||
title: Description List
|
||||
description: 'Help users digest detailed information in a structured, easy-to-scan format.'
|
||||
---
|
||||
|
||||
## Left Aligned
|
||||
|
||||
```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>
|
||||
<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>
|
||||
<div class="wa-flank" style="--flank-size: 20ch;">
|
||||
<dt>Application for</dt>
|
||||
<dd>Machine Learning Engineer</dd>
|
||||
</div>
|
||||
<div class="wa-flank" style="--flank-size: 20ch;">
|
||||
<dt>Email address</dt>
|
||||
<dd>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.
|
||||
</dd>
|
||||
</div>
|
||||
<div class="wa-flank wa-align-items-start" style="--flank-size: 20ch;">
|
||||
<dt>Attachments</dt>
|
||||
<dd>
|
||||
<wa-card>
|
||||
<div class="wa-stack">
|
||||
<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>2.4mb</span>
|
||||
</span>
|
||||
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa-flank">
|
||||
<wa-icon name="paperclip"></wa-icon>
|
||||
<div class="wa-split">
|
||||
<span class="wa-caption-m wa-cluster">
|
||||
<span>bb_cover_letter.pdf</span>
|
||||
<span>2.4mb</span>
|
||||
</span>
|
||||
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 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>
|
||||
<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>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<dt>Application for</dt>
|
||||
<dd>Machine Learning Engineer</dd>
|
||||
</div>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<dt>Email address</dt>
|
||||
<dd>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.
|
||||
</dd>
|
||||
</div>
|
||||
<div class="wa-stack wa-gap-xs wa-span-grid">
|
||||
<dt>Attachments</dt>
|
||||
<dd>
|
||||
<wa-card>
|
||||
<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>2.4mb</span>
|
||||
</span>
|
||||
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa-flank">
|
||||
<wa-icon name="paperclip"></wa-icon>
|
||||
<div class="wa-split">
|
||||
<span class="wa-caption-m wa-cluster">
|
||||
<span>bb_cover_letter.pdf</span>
|
||||
<span>2.4mb</span>
|
||||
</span>
|
||||
<wa-button appearance="plain" variant="brand" size="small">Download</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</dd>
|
||||
</div>
|
||||
</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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<div class="wa-flank" style="--flank-size: 20ch;">
|
||||
<dt>Attachments</dt>
|
||||
<dd>
|
||||
<wa-card>
|
||||
<div class="wa-stack">
|
||||
<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>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>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa-flank">
|
||||
<wa-icon name="paperclip"></wa-icon>
|
||||
<div class="wa-split">
|
||||
<span class="wa-caption-m wa-cluster">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Condensed
|
||||
|
||||
```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">
|
||||
<div class="wa-flank wa-align-items-stretch">
|
||||
<dt><wa-icon name="user" label="Name" fixed-width></wa-icon></dt>
|
||||
<dd>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>
|
||||
</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>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<a href="" class="wa-cluster wa-gap-2xs">
|
||||
<span>Download Receipt</span>
|
||||
<wa-icon name="arrow-right"></wa-icon>
|
||||
</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
207
docs/docs/patterns/app/empty-state.md
Normal file
207
docs/docs/patterns/app/empty-state.md
Normal file
@@ -0,0 +1,207 @@
|
||||
---
|
||||
title: Empty State
|
||||
description: 'Guide users with helpful prompts and visuals when no content is available.'
|
||||
---
|
||||
|
||||
## 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>
|
||||
<wa-button>
|
||||
<wa-icon slot="prefix" name="plus"></wa-icon>
|
||||
Add Kit
|
||||
</wa-button>
|
||||
</div>
|
||||
```
|
||||
|
||||
## With Interactive Placeholder
|
||||
|
||||
```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" 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>
|
||||
```
|
||||
|
||||
## With Templates
|
||||
|
||||
```html {.example}
|
||||
<wa-card with-header with-footer style="max-width: 70ch; margin: auto">
|
||||
<div slot="header" class="wa-stack wa-gap-xs">
|
||||
<h2 class="wa-heading-m">Projects</h2>
|
||||
</div>
|
||||
<div class="wa-stack wa-gap-xl">
|
||||
<p class="wa-caption-m">You haven’t 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">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<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>
|
||||
</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## Add people
|
||||
```html{.example}
|
||||
<wa-card style="max-width: 60ch; margin: 0 auto;">
|
||||
<div class="wa-stack">
|
||||
<wa-icon></wa-icon>
|
||||
<h1>Add team members</h1>
|
||||
<p>You haven’t added any team members to your project yet. As the owner of this project, you can manage team member permissions.</p>
|
||||
<div class="wa-flank:end">
|
||||
<wa-input></wa-input><wa-button>Invite</wa-button>
|
||||
</div>
|
||||
<div class="wa-stack">
|
||||
<span>Team members previously added to projects</span>
|
||||
<wa-divider></wa-divider>
|
||||
<section>
|
||||
<div class="wa-flank">
|
||||
<wa-avatar></wa-avatar>
|
||||
<div class="wa-split">
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<span>lindsey Walton</span>
|
||||
<span>Front end Developer</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</section>
|
||||
<section>
|
||||
<div class="wa-flank">
|
||||
<wa-avatar></wa-avatar>
|
||||
<div class="wa-split">
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<span>lindsey Walton</span>
|
||||
<span>Front end Developer</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</section>
|
||||
<section>
|
||||
<div class="wa-flank">
|
||||
<wa-avatar></wa-avatar>
|
||||
<div class="wa-split">
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<span>lindsey Walton</span>
|
||||
<span>Front end Developer</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</section><section>
|
||||
<div class="wa-flank">
|
||||
<wa-avatar></wa-avatar>
|
||||
<div class="wa-split">
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<span>lindsey Walton</span>
|
||||
<span>Front end Developer</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
118
docs/docs/patterns/app/faq.md
Normal file
118
docs/docs/patterns/app/faq.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: FAQ
|
||||
description: 'Empower users to learn more with a structured list of questions and answers.'
|
||||
---
|
||||
|
||||
## With Flanked Heading & Description
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-flank wa-align-items-start wa-gap-2xl" style="--flank-size: 35ch">
|
||||
<div>
|
||||
<h2>Frequently Asked Questions</h2>
|
||||
<p>Can’t find an answer? Reach out to your local <a href="">Operator</a>, or contact <a href="">the Oracle</a>, and enjoy a cookie. 🍪</p>
|
||||
</div>
|
||||
<dl class="wa-stack wa-gap-2xl">
|
||||
<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 who’s to say Zion isn’t just another layer of the simulation?</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? It’s terrifying.</dd>
|
||||
</div>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<dt>Can I go back into the Matrix once I’m 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>
|
||||
```
|
||||
|
||||
## With Expandable Answers
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-stack">
|
||||
<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 who’s to say Zion isn’t just another layer of the simulation?
|
||||
</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? It’s terrifying.
|
||||
</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 I’m 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>
|
||||
</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 who’s to say Zion isn’t 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? It’s 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 I’m 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>
|
||||
```
|
||||
|
||||
## 3 Column
|
||||
```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 library’s 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>
|
||||
</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 you’ve 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>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
```
|
||||
287
docs/docs/patterns/app/feed.md
Normal file
287
docs/docs/patterns/app/feed.md
Normal file
@@ -0,0 +1,287 @@
|
||||
---
|
||||
title: Feed
|
||||
description: TODO
|
||||
---
|
||||
|
||||
## Comment Section
|
||||
```html{.example}
|
||||
<wa-card style="max-width: 60ch; margin: 0 auto;">
|
||||
<div class="wa-stack">
|
||||
<h1 class="wa-heading-m">Activity</h1>
|
||||
<wa-textarea></wa-textarea>
|
||||
<wa-divider></wa-divider>
|
||||
<section class="wa-stack">
|
||||
<div class="wa-flank">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<div>
|
||||
<span class="wa-heading-s">Robert Fox</span>
|
||||
<span class="wa-caption-m">commented 32 min ago</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="wa-stack wa-gap-xl" style="list-style-type: none; margin-inline-start: 1em;">
|
||||
<li>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.</li>
|
||||
<li class="wa-stack wa-gap-2xs">
|
||||
<div class="wa-flank">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<div>
|
||||
<span>Robert Fox</span>
|
||||
<span class="wa-caption-m">commented 32 min ago</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 label="User avatar"></wa-avatar>
|
||||
<div>
|
||||
<span>Robert Fox</span>
|
||||
<span class="wa-caption-m">commented 32 min ago</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-icon name="reply"></wa-icon>
|
||||
<a href="#">Leave Comment</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## With Summary Components
|
||||
```html{.example}
|
||||
<wa-card style="max-width: 68ch; margin: 0 auto;">
|
||||
<h1 class="wa-heading-l">Monthly Activity</h1>
|
||||
<div class="wa-stack">
|
||||
<wa-details>
|
||||
<span class="wa-heading-m" slot="summary">
|
||||
February
|
||||
</span>
|
||||
<div class="wa-stack">
|
||||
<section class="wa-flank wa-gap-xs">
|
||||
<wa-icon style="font-size: var(--wa-font-size-xl)" name="envelope"></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>
|
||||
<span class="wa-caption-m">Feb 28th</span>
|
||||
</div>
|
||||
</section>
|
||||
<wa-divider></wa-divider>
|
||||
<section class="wa-flank wa-gap-xs">
|
||||
<wa-icon style="font-size: var(--wa-font-size-xl)" name="phone"></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>
|
||||
<span class="wa-caption-m">Feb 23rd</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</wa-details>
|
||||
<wa-details>
|
||||
<span class="wa-heading-m" slot="summary">
|
||||
March
|
||||
</span>
|
||||
<div class="wa-stack">
|
||||
<section class="wa-flank wa-gap-xs">
|
||||
<wa-icon style="font-size: var(--wa-font-size-xl)" name="video"></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>
|
||||
<span class="wa-caption-m">Mar 15th</span>
|
||||
</div>
|
||||
</section>
|
||||
<wa-divider></wa-divider>
|
||||
<section class="wa-flank wa-gap-s">
|
||||
<wa-icon style="font-size: var(--wa-font-size-xl)" name="calendar"></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>
|
||||
<span class="wa-caption-m">Mar 3rd</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</wa-details>
|
||||
<wa-details>
|
||||
<span class="wa-heading-m" slot="summary">
|
||||
April
|
||||
</span>
|
||||
<div class="wa-stack">
|
||||
<section class="wa-flank wa-gap-s">
|
||||
<wa-icon style="font-size: var(--wa-font-size-xl)" family="brands" name="intercom"></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>
|
||||
<span class="wa-caption-m">Apr 18th</span>
|
||||
</div>
|
||||
</section>
|
||||
<wa-divider></wa-divider>
|
||||
<section class="wa-flank wa-gap-s">
|
||||
<wa-icon style="font-size: var(--wa-font-size-xl)" name="list-check"></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>
|
||||
<span class="wa-caption-m">Apr 2nd</span>
|
||||
</div>
|
||||
</section>
|
||||
</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></wa-avatar>
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<div class="wa-split">
|
||||
<span class="wa-heading-s">Charlotte Parker</span>
|
||||
<span class="wa-caption-s">4h</span>
|
||||
</div>
|
||||
<p>Who's on first?</p>
|
||||
<a href="#" class="wa-cluster wa-gap-2xs">
|
||||
<wa-icon name="reply"></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></wa-avatar>
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<div class="wa-split">
|
||||
<span class="wa-heading-s">Charlotte Parker</span>
|
||||
<span class="wa-caption-s">1h</span>
|
||||
</div>
|
||||
<p>What's on second?</p>
|
||||
<a href="#" class="wa-cluster wa-gap-2xs">
|
||||
<wa-icon name="reply"></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></wa-avatar>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<div class="wa-split">
|
||||
<span class="wa-heading-s">Charlotte Parker</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></wa-avatar>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<div class="wa-split">
|
||||
<span><strong>Happy</strong> commented in <a href="#">Reporting Dashboard</a></span>
|
||||
<wa-icon name="circle-dot" style="color: var(--wa-color-green-50);"></wa-icon>
|
||||
</div>
|
||||
<div class="wa-split">
|
||||
<span class="wa-caption-m">Friday 3:12PM</span>
|
||||
<span class="wa-caption-m">2 hours ago</span>
|
||||
</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></wa-avatar>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<div class="wa-split">
|
||||
<span><strong>Charlotte</strong> followed you</span>
|
||||
<wa-icon name="circle-dot" style="color: var(--wa-color-green-50);"></wa-icon>
|
||||
</div>
|
||||
<div class="wa-split">
|
||||
<span class="wa-caption-m">Friday 3:04PM</span>
|
||||
<span class="wa-caption-m">2 hours ago</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</article>
|
||||
<article>
|
||||
<div class="wa-flank wa-align-items-start">
|
||||
<wa-avatar></wa-avatar>
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<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>
|
||||
<span class="wa-caption-m">3 hours ago</span>
|
||||
</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>
|
||||
```
|
||||
525
docs/docs/patterns/app/grid-list.md
Normal file
525
docs/docs/patterns/app/grid-list.md
Normal file
@@ -0,0 +1,525 @@
|
||||
---
|
||||
title: Grid List
|
||||
description: 'Improve browsing and selection by organizing data in a structured grid layout.'
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-grid" style="--min-column-size: 29ch;">
|
||||
<wa-card with-footer>
|
||||
<div class="wa-stack wa-align-items-center">
|
||||
<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">Product Designer</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">
|
||||
<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">Product Designer</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">
|
||||
<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">Product Designer</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">
|
||||
<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">Product Designer</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">
|
||||
<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">
|
||||
<span>Lindsay Walton</span>
|
||||
<span>Developer</span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-icon-button name="bluesky" family="brands"></wa-icon-button>
|
||||
<wa-icon-button name="dribbble" family="brands"></wa-icon-button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="wa-stack">
|
||||
<div class="wa-frame">
|
||||
<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">
|
||||
<span>Lindsay Walton</span>
|
||||
<span>Developer</span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-icon-button name="bluesky" family="brands"></wa-icon-button>
|
||||
<wa-icon-button name="dribbble" family="brands"></wa-icon-button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="wa-stack">
|
||||
<div class="wa-frame">
|
||||
<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">
|
||||
<span>Lindsay Walton</span>
|
||||
<span>Developer</span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-icon-button name="bluesky" family="brands"></wa-icon-button>
|
||||
<wa-icon-button name="dribbble" family="brands"></wa-icon-button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="wa-stack">
|
||||
<div class="wa-frame">
|
||||
<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">
|
||||
<span>Lindsay Walton</span>
|
||||
<span>Developer</span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-icon-button name="bluesky" family="brands"></wa-icon-button>
|
||||
<wa-icon-button name="dribbble" family="brands"></wa-icon-button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="wa-stack">
|
||||
<div class="wa-frame">
|
||||
<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">
|
||||
<span>Lindsay Walton</span>
|
||||
<span>Developer</span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-icon-button name="bluesky" family="brands"></wa-icon-button>
|
||||
<wa-icon-button name="dribbble" family="brands"></wa-icon-button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="wa-stack">
|
||||
<div class="wa-frame">
|
||||
<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">
|
||||
<span>Lindsay Walton</span>
|
||||
<span>Developer</span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-icon-button name="bluesky" family="brands"></wa-icon-button>
|
||||
<wa-icon-button name="dribbble" family="brands"></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-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>
|
||||
</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-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>
|
||||
</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></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>
|
||||
```
|
||||
|
||||
8
docs/docs/patterns/app/index.njk
Normal file
8
docs/docs/patterns/app/index.njk
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: App
|
||||
description: Pre-built action panels, data displays, and more ready to drop into your web app.
|
||||
parent: patterns
|
||||
layout: overview
|
||||
override:tags: []
|
||||
listChildren: true
|
||||
---
|
||||
265
docs/docs/patterns/app/leaderboard.md
Normal file
265
docs/docs/patterns/app/leaderboard.md
Normal file
@@ -0,0 +1,265 @@
|
||||
---
|
||||
title: Leaderboard
|
||||
description: 'Engage and motivate users by highlighting top performers, scores, and achievements.'
|
||||
---
|
||||
|
||||
## Simple
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-stack">
|
||||
<h3>Daily Crossword</h3>
|
||||
<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-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-2xl">482,813</div>
|
||||
</div>
|
||||
</wa-callout>
|
||||
<wa-callout variant="brand" appearance="filled">
|
||||
<wa-icon slot="icon" name="diploma"></wa-icon>
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<h4 class="wa-heading-xs">Items Mastered</h4>
|
||||
<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>
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<h4 class="wa-heading-xs">Items Created</h4>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
51
docs/docs/patterns/app/pagination.md
Normal file
51
docs/docs/patterns/app/pagination.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: Pagination
|
||||
description: 'Improve navigation and performance by breaking long lists or content into manageable pages.'
|
||||
---
|
||||
|
||||
## Simple
|
||||
|
||||
```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>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## With Button Group
|
||||
|
||||
```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>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
228
docs/docs/patterns/app/permissions.md
Normal file
228
docs/docs/patterns/app/permissions.md
Normal file
@@ -0,0 +1,228 @@
|
||||
---
|
||||
title: Permissions
|
||||
description: 'Permission patterns provide or restrict access to users.'
|
||||
---
|
||||
|
||||
## 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>
|
||||
```
|
||||
167
docs/docs/patterns/app/pricing.md
Normal file
167
docs/docs/patterns/app/pricing.md
Normal file
@@ -0,0 +1,167 @@
|
||||
---
|
||||
title: Pricing
|
||||
description: 'Help users make informed purchasing decisions with clear, structured pricing.'
|
||||
---
|
||||
|
||||
## 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>
|
||||
</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">
|
||||
<div class="wa-flank">
|
||||
<wa-icon name="user" fixed-width></wa-icon>
|
||||
<span class="wa-caption-m">1 user</span>
|
||||
</div>
|
||||
<div class="wa-flank">
|
||||
<wa-icon name="suitcase" fixed-width></wa-icon>
|
||||
<span class="wa-caption-m">2 custom kits</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>
|
||||
</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>
|
||||
</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">
|
||||
<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>
|
||||
</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>
|
||||
</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">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
```
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
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>
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
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
|
||||
---
|
||||
|
||||
@@ -42,7 +40,7 @@ icon: checkbox
|
||||
<wa-checkbox>XXL</wa-checkbox>
|
||||
</div>
|
||||
</wa-details>
|
||||
</form>
|
||||
</form>
|
||||
<div class="wa-placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,4 +80,4 @@ icon: checkbox
|
||||
</div>
|
||||
<div class="wa-placeholder"></div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Category Preview
|
||||
description: 'Help shoppers discover your product offerings with showcases of product categories.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
icon: preview
|
||||
---
|
||||
|
||||
@@ -17,20 +15,20 @@ icon: preview
|
||||
</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)"
|
||||
/>
|
||||
@@ -48,7 +46,7 @@ icon: preview
|
||||
<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"
|
||||
/>
|
||||
@@ -57,7 +55,7 @@ icon: preview
|
||||
</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"
|
||||
/>
|
||||
@@ -66,7 +64,7 @@ icon: preview
|
||||
</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"
|
||||
/>
|
||||
@@ -161,4 +159,4 @@ icon: preview
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Checkout Form
|
||||
description: 'Let shoppers checkout with ease with streamlined forms to capture shipping and payment info.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
|
||||
@@ -243,4 +241,4 @@ tags: e-commerce
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
3
docs/docs/patterns/ecommerce/ecommerce.json
Normal file
3
docs/docs/patterns/ecommerce/ecommerce.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tags": ["ecommerce"]
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Incentives
|
||||
description: 'Encourage shoppers to buy your products with value propositions, discounts, and promotions.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
## 3 Column
|
||||
@@ -17,7 +15,7 @@ tags: e-commerce
|
||||
<div class="wa-frame wa-border-radius-l">
|
||||
<img src="https://uploads.webawesome.com/online-learning.jpg" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="wa-grid">
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
@@ -122,4 +120,4 @@ tags: e-commerce
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
7
docs/docs/patterns/ecommerce/index.njk
Normal file
7
docs/docs/patterns/ecommerce/index.njk
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Ecommerce
|
||||
description: Pre-built product overviews, shopping carts, and more to help you build high-converting storefronts.
|
||||
parent: patterns
|
||||
layout: overview
|
||||
override:tags: []
|
||||
---
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Order History
|
||||
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
## List
|
||||
@@ -32,7 +30,7 @@ tags: e-commerce
|
||||
<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=""
|
||||
/>
|
||||
@@ -49,7 +47,7 @@ tags: e-commerce
|
||||
<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>
|
||||
@@ -188,3 +186,59 @@ tags: e-commerce
|
||||
</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-icon family="brands" name="amazon"></wa-icon>
|
||||
<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: 1rem;"></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-icon family="brands" name="amazon"></wa-icon>
|
||||
<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: 1rem;"></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-icon family="brands" name="amazon"></wa-icon>
|
||||
<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: 1rem;"></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>
|
||||
</div>
|
||||
```
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Order Summary
|
||||
description: 'Give shoppers confidence in their purchases with summaries of everything included in their order.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
## Simple
|
||||
@@ -26,7 +24,7 @@ tags: e-commerce
|
||||
<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=""
|
||||
/>
|
||||
@@ -39,7 +37,7 @@ tags: e-commerce
|
||||
<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=""
|
||||
/>
|
||||
@@ -219,7 +217,7 @@ tags: e-commerce
|
||||
<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">
|
||||
@@ -237,7 +235,7 @@ tags: e-commerce
|
||||
<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">
|
||||
@@ -255,7 +253,7 @@ tags: e-commerce
|
||||
<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">
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Product Lists
|
||||
description: 'Let shoppers browse and compare products with detailed lists of the products in your store.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
## Simple Grid with Ratings
|
||||
@@ -11,7 +9,7 @@ tags: e-commerce
|
||||
<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)"
|
||||
/>
|
||||
@@ -23,7 +21,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -35,7 +33,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -47,7 +45,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -59,7 +57,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -71,7 +69,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -83,7 +81,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -95,7 +93,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -115,7 +113,7 @@ tags: e-commerce
|
||||
<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)"
|
||||
/>
|
||||
@@ -131,7 +129,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -181,4 +179,4 @@ tags: e-commerce
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Product Overview
|
||||
description: 'Showcase your products with overviews including images, ratings, features, options, and more.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
## Split with Image
|
||||
@@ -77,7 +75,7 @@ tags: e-commerce
|
||||
</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)"
|
||||
/>
|
||||
@@ -362,7 +360,7 @@ tags: e-commerce
|
||||
<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>
|
||||
@@ -1,11 +1,9 @@
|
||||
---
|
||||
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
|
||||
---
|
||||
|
||||
|
||||
## With Product Options
|
||||
|
||||
```html {.example}
|
||||
@@ -16,7 +14,7 @@ icon: preview
|
||||
</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"
|
||||
/>
|
||||
@@ -128,7 +126,7 @@ icon: preview
|
||||
<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>
|
||||
@@ -150,7 +148,7 @@ icon: preview
|
||||
</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
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Product Reviews
|
||||
description: 'Help shoppers make informed decisions with ratings, reviews, and testimonials from your customers.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
## Multi column
|
||||
|
||||
@@ -174,7 +172,7 @@ tags: e-commerce
|
||||
<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">
|
||||
@@ -190,7 +188,7 @@ tags: e-commerce
|
||||
<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. It’s 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">
|
||||
@@ -206,8 +204,8 @@ tags: e-commerce
|
||||
<wa-rating label="Rating" precision="0.5" value="3.8" readonly></wa-rating>
|
||||
<p>The leather is high quality, but it’s a little firmer than I thought. That said, after sitting on it for a while, it does soften up and feels more comfortable. It’s perfect if you’re looking for a more structured seating experience.</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Shopping Cart
|
||||
description: 'Give shoppers an overview of selected items with shopping carts that let them edit items and proceed to checkout.'
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
## Two Columns with Summary Card
|
||||
@@ -14,7 +12,7 @@ tags: e-commerce
|
||||
<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=""
|
||||
/>
|
||||
@@ -32,7 +30,7 @@ tags: e-commerce
|
||||
</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=""
|
||||
/>
|
||||
@@ -50,7 +48,7 @@ tags: e-commerce
|
||||
</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=""
|
||||
/>
|
||||
@@ -205,12 +203,12 @@ tags: e-commerce
|
||||
<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>
|
||||
@@ -230,7 +228,7 @@ tags: e-commerce
|
||||
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>
|
||||
@@ -245,12 +243,12 @@ tags: e-commerce
|
||||
<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>
|
||||
@@ -276,4 +274,4 @@ tags: e-commerce
|
||||
</wa-button>
|
||||
</div>
|
||||
</wa-drawer>
|
||||
```
|
||||
```
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
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
|
||||
---
|
||||
|
||||
@@ -82,4 +81,4 @@ unlisted: true
|
||||
|
||||
|
||||
</style>
|
||||
```
|
||||
```
|
||||
@@ -2,8 +2,6 @@
|
||||
title: Patterns
|
||||
description: Patterns are reusable UI solutions to common design problems, ready to copy and paste into any project.
|
||||
layout: overview
|
||||
categories: ["e-commerce"]
|
||||
listChildren: true
|
||||
override:tags: []
|
||||
---
|
||||
|
||||
@@ -12,7 +10,7 @@ override:tags: []
|
||||
|
||||
## What's a Pattern?
|
||||
|
||||
A pattern is a code snippet composed of components, style utilities, and native HTML that you can copy and paste into any project that uses Web Awesome.
|
||||
A pattern is a code snippet composed of components, style utilities, and native HTML that you can copy and paste into any project that uses Web Awesome.
|
||||
It's a chunk of a user interface, rather than a single component, that allows you to implement UI solutions without designing something from scratch.
|
||||
|
||||
Patterns are designed according to proven usability practices so they're responsive, accessible, and cohesive out-of-the-box. Importantly, patterns don't handle business logic or functionality like form submissions, data processing, encryption, etc. It's up to you to implement the logic you need for your project.
|
||||
@@ -26,4 +24,4 @@ To use a pattern in your project, refer to each pattern's docs for a copyable co
|
||||
Because patterns use a combination of Web Awesome features, they work best when you have [native styles](/docs/native), [style utilities](/docs/utilities), and a [theme](/docs/themes) installed in addition to Web Awesome [components](/docs/components). Refer to the [Installation page](/docs/installation) to set up all of these features in your project.
|
||||
|
||||
{% endmarkdown %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
47
docs/docs/patterns/information/call-to-action.md
Normal file
47
docs/docs/patterns/information/call-to-action.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Call To Action
|
||||
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
|
||||
## Simple
|
||||
```html {.example}
|
||||
<div style="margin-block: 5rem;">
|
||||
<h2 style="font-size: 3rem;">Unlock Your Future: <br/>Start Learning Web Development Today!</h2>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<wa-button>Get Started</wa-button>
|
||||
<wa-button appearance="plain">Find out more <wa-icon slot="suffix" name="arrow-right"></wa-icon></wa-button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Centered
|
||||
```html {.example}
|
||||
<div class="wa-stack wa-align-items-center wa-gap-xl" style="margin-block: 5rem;">
|
||||
<h2 style="font-size: 3rem; text-align: center">Unlock Your Future: <br/>Start Learning Web Development Today!</h2>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<wa-button>Get Started</wa-button>
|
||||
<wa-button appearance="plain">Find out more <wa-icon slot="suffix" name="arrow-right"></wa-icon></wa-button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 2 Column
|
||||
```html {.example}
|
||||
<div style="margin-block: 5rem;">
|
||||
<div class="wa-grid wa-align-items-center">
|
||||
<div class="wa-stack wa-align-items-center wa-gap-3xl">
|
||||
<h2 style="font-size: 3rem; text-align: center">Unlock Your Future: <br/>Start Learning Web Development Today!</h2>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<wa-button>Get Started</wa-button>
|
||||
<wa-button appearance="plain">Find out more <wa-icon slot="suffix" name="arrow-right"></wa-icon></wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa-frame wa-border-radius-l">
|
||||
<img src="https://images.unsplash.com/photo-1586864387634-2f33030dab41?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
```
|
||||
87
docs/docs/patterns/information/footer.md
Normal file
87
docs/docs/patterns/information/footer.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: Footer
|
||||
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
## Simple
|
||||
```html {.example}
|
||||
<div class="wa-stack wa-gap-xl" style="max-width: 102ch; margin: 0 auto;">
|
||||
<div class="wa-split">
|
||||
<div class="wa-cluster wa-gap-xs wa-heading-xl">
|
||||
<wa-icon name="gears"></wa-icon>
|
||||
<span>Widget UI</span>
|
||||
</div>
|
||||
<form class="wa-flank:end wa-gap-xs">
|
||||
<wa-input placeholder="Enter your email" type="email"></wa-input>
|
||||
<wa-button>Subscribe</wa-button>
|
||||
</form>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa-cluster" style="justify-content: flex-end">
|
||||
<p>© 2025 All Rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
## Centered
|
||||
```html {.example}
|
||||
<div class="wa-stack wa-align-items-center">
|
||||
<div class="wa-cluster wa-gap-xl">
|
||||
<a href="#">Home</a>
|
||||
<a href="#">Get Started</a>
|
||||
<a href="#">Services</a>
|
||||
<a href="#">Portfolio</a>
|
||||
</div>
|
||||
<div class="wa-cluster wa-gap-s">
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="facebook" family="brands" label="Share on Facebook" href="#" target="_blank"></wa-icon-button></a>
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="bluesky" family="brands" label="Share on Bluesky" href="#" target="_blank"></wa-icon-button></a>
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="linkedin" family="brands" label="Share on LinkedIn" href="#" target="_blank"></wa-icon-button></a>
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="envelope-open" label="Share with email" href="#" target="_blank"></wa-icon-button></a>
|
||||
</div>
|
||||
<p>© 2025 All Rights reserved.</p>
|
||||
</div>
|
||||
```
|
||||
## Corporate
|
||||
```html{.example}
|
||||
<div>
|
||||
<div class="wa-flank wa-align-items-baseline wa-gap-3xl" style="--flank-size: 36ch;">
|
||||
<div>
|
||||
<p>We are committed to providing you with the best products and services. If you have any questions or need assistance, feel free to reach out to our team. Stay connected with us through our social media channels for updates, news, and more. Your satisfaction is our top priority, and we look forward to serving you again soon!</p>
|
||||
</div>
|
||||
<div class="wa-grid">
|
||||
<section class="wa-stack wa-gap-xs">
|
||||
<h2 class="wa-heading-s">Links</h2>
|
||||
<a href="#">Home</a>
|
||||
<a href="#">Get Started</a>
|
||||
<a href="#">Services</a>
|
||||
<a href="#">Portfolio</a>
|
||||
</section>
|
||||
<section class="wa-stack wa-gap-xs">
|
||||
<h2 class="wa-heading-s">Others</h2>
|
||||
<a href="#">Corporate</a>
|
||||
<a href="#">Terms of Service</a>
|
||||
<a href="#">Privacy Policy</a>
|
||||
</section>
|
||||
<section class="wa-stack">
|
||||
<h2 class="wa-heading-s">Social</h2>
|
||||
<div class="wa-cluster">
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="facebook" family="brands" label="Share on Facebook" href="#" target="_blank"></wa-icon-button></a>
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="bluesky" family="brands" label="Share on Bluesky" href="#" target="_blank"></wa-icon-button></a>
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="linkedin" family="brands" label="Share on LinkedIn" href="#" target="_blank"></wa-icon-button></a>
|
||||
<a href="#"><wa-icon-button style="font-size: var(--wa-font-size-l);" name="envelope-open" label="Share with email" href="#" target="_blank"></wa-icon-button></a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa-split">
|
||||
<p>© 2025 All Rights reserved.</p>
|
||||
<wa-select label="Language" value="english">
|
||||
<wa-option value="english">English</wa-option>
|
||||
<wa-option value="spanish">Spanish</wa-option>
|
||||
<wa-option value="french">French</wa-option>
|
||||
</wa-select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
8
docs/docs/patterns/information/index.njk
Normal file
8
docs/docs/patterns/information/index.njk
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Information
|
||||
description: ''
|
||||
parent: patterns
|
||||
layout: overview
|
||||
override:tags: []
|
||||
listChildren: true
|
||||
---
|
||||
3
docs/docs/patterns/information/information.json
Normal file
3
docs/docs/patterns/information/information.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tags": ["information"]
|
||||
}
|
||||
76
docs/docs/patterns/information/login.md
Normal file
76
docs/docs/patterns/information/login.md
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: Login
|
||||
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
|
||||
## Login/ Sign Up
|
||||
```html{.example}
|
||||
<wa-card style="max-width: 45ch; margin: 0 auto">
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">Agent Login</h2>
|
||||
<wa-input placeholder="email" type="email"></wa-input>
|
||||
<wa-input placeholder="password" type="password"></wa-input>
|
||||
<a href="#">Having trouble signing in?</a>
|
||||
<wa-button>Sign in</wa-button>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
<p>Or sign in with:</p>
|
||||
<div class="wa-grid" style="--min-column-size: 12ch;">
|
||||
<wa-button appearance="outlined">
|
||||
<wa-icon slot="prefix" name="google" family="brands"></wa-icon>
|
||||
Google
|
||||
</wa-button>
|
||||
<wa-button appearance="outlined">
|
||||
<wa-icon slot="prefix" name="apple" family="brands"></wa-icon>
|
||||
Apple ID
|
||||
</wa-button>
|
||||
<wa-button appearance="outlined">
|
||||
<wa-icon slot="prefix" name="facebook" family="brands"></wa-icon>
|
||||
Facebook
|
||||
</wa-button>
|
||||
</div>
|
||||
<p>Don't have an account? <a href="#">Request Now</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## Password Recovery
|
||||
```html{.example}
|
||||
<wa-card style="max-width: 45ch; margin: 0 auto">
|
||||
<div class="wa-stack wa-gap-l">
|
||||
<h2 class="wa-heading-m">Password Recovery</h2>
|
||||
<wa-radio-group
|
||||
label="Choose your recovery method"
|
||||
orientation="horizontal"
|
||||
name="recovery-method"
|
||||
value="crypto-keys"
|
||||
>
|
||||
<wa-radio-button value="qr-code">QR Code</wa-radio-button>
|
||||
<wa-radio-button value="crypto-keys">Crypto Keys</wa-radio-button>
|
||||
</wa-radio-group>
|
||||
<p class="wa-caption-m">Store your keys in a password manager to back them up in case you need to restore your account.</p>
|
||||
<div class="wa-stack">
|
||||
<wa-input label="Public Key" value="dsjfaklsjfkwejrl4wj5646uotue789f7ew8rtuewfsd" disabled></wa-input>
|
||||
<wa-input label="Secret Key" value="dfkdfkdfdsofkdsofjs" disabled></wa-input>
|
||||
</div>
|
||||
<wa-button>Submit</wa-button>
|
||||
<wa-button appearance="outlined">Or try to login again</wa-button>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## Two Factor Authentication
|
||||
```html{.example}
|
||||
<wa-card style="max-width: 45ch; margin: 0 auto">
|
||||
<div class="wa-stack wa-gap-l wa-align-items-center">
|
||||
<h2 class="wa-heading-m">Set up using an Authenticator app</h2>
|
||||
<p class="wa-caption-m">Use an authenticator app to get the authentication codes</p>
|
||||
<wa-qr-code value="https://shoelace.style/" label="Scan this code to visit Web Awesome on the web!"></wa-qr-code>
|
||||
<p class="wa-caption-m">If you can't scan the QR Code above, enter this text instead</p>
|
||||
<wa-input value="dsjfaklsjfkwejrl4wj5646uotue789f7ew8rtuewfsd" disabled></wa-input>
|
||||
<h3 class="wa-heading-s">Set up using an Authenticator app</h3>
|
||||
<p class="wa-caption-m">After scanning the QR Code image, the app will display a code that you can enter.</p>
|
||||
<span class="wa-heading-3xl">123466</span>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
110
docs/docs/patterns/information/newsletter.md
Normal file
110
docs/docs/patterns/information/newsletter.md
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: Newsletter
|
||||
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
|
||||
## Simple
|
||||
```html{.example}
|
||||
<wa-card style="margin: 0 auto; max-width: 45ch;">
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">Subscribe to our Newsletter</h2>
|
||||
<p>To get the latest and most quality design resources</p>
|
||||
<form class="wa-flank:end wa-gap-2xs">
|
||||
<wa-input placeholder="email@example.com"></wa-input>
|
||||
<wa-button>Subscribe</wa-button>
|
||||
</form>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
## 2 Column
|
||||
```html{.example}
|
||||
<wa-card style="margin: 0 auto; max-width: 75ch;">
|
||||
<div class="wa-grid">
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<h2 class="wa-heading-m">Subscribe to our Newsletter</h2>
|
||||
<p>To get the latest and most quality design resources</p>
|
||||
</div>
|
||||
<form class="wa-flank:end wa-gap-2xs">
|
||||
<wa-input placeholder="email@example.com"></wa-input>
|
||||
<wa-button>Subscribe</wa-button>
|
||||
</form>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## With Incentives
|
||||
```html {.example}
|
||||
<wa-card style="margin: 0 auto; max-width: 75ch;">
|
||||
<div class="wa-grid">
|
||||
<dl class="wa-stack">
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<dt><wa-icon name="calendar"></wa-icon></dt><dd>Daily News in your Inbox</dd>
|
||||
</div>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<dt><wa-icon name="shield-halved"></wa-icon></dt><dd>Spam Free</dd>
|
||||
</div>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<dt><wa-icon name="shield-halved"></wa-icon></dt><dd>The Most trusted source in the industry.</dd>
|
||||
</div>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<dt><wa-icon name="shield-halved"></wa-icon></dt><dd>Easy to Unsubscribe</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">Subscribe to our Newsletter</h2>
|
||||
<p>To get the latest and most quality design resources</p>
|
||||
<form class="wa-flank:end wa-gap-2xs">
|
||||
<wa-input placeholder="email@example.com"></wa-input>
|
||||
<wa-button>Subscribe</wa-button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## With Image card
|
||||
```html{.example}
|
||||
<wa-card with-image style="max-width: 45ch; margin: 0 auto">
|
||||
<img slot="image" src="https://images.unsplash.com/photo-1595087012935-124877078142?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="mailbox" />
|
||||
<div class="wa-stack wa-align-items-center wa-gap-2xl">
|
||||
<div class="wa-stack wa-align-items-center wa-gap-xs">
|
||||
<h2 class="wa-heading-l">Subscribe!</h2>
|
||||
<p class="wa-caption-l" style="text-align: center; word-break: break-word">Get the best new products in your inbox, everyday. Get the latest content first.</p>
|
||||
</div>
|
||||
<form class="wa-flank:end wa-gap-2xs">
|
||||
<wa-input placeholder="email@example.com"></wa-input>
|
||||
<wa-button appearance="outlined">Signup</wa-button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
## 2 column
|
||||
```html{.example}
|
||||
<wa-card style="margin: 0 auto; max-width: 84ch;">
|
||||
<div class="wa-grid wa-align-items-center">
|
||||
<form class="wa-stack wa-align-items-center wa-gap-2xl">
|
||||
<h2 class="wa-heading-xl" style="text-align: center;">Be the first to know</h2>
|
||||
<p class="wa-caption-xl" style="text-align: center;">Don't miss out on exclusive savings, new arrivals, and more.</p>
|
||||
<div class="wa-stack">
|
||||
<wa-input placeholder="email address (required)"></wa-input>
|
||||
<wa-input type="tel" placeholder="phone number (optional)"></wa-input>
|
||||
<wa-checkbox>
|
||||
<p class="wa-caption-s" style="margin: 0"> Enter your mobile number and select to receive automated marketing text messages about new items, great savings and more. You understand that consent is not required to make a purchase. Message and data rates may apply. Message frequency varies. Wireless Carriers are not liable for delayed or undelivered messages. Text HELP for help and STOP to cancel.
|
||||
For questions, Please <a href="#">contact us</a>. <a href="#">Terms</a></div>
|
||||
</wa-checkbox>
|
||||
</div>
|
||||
<div class="wa-stack wa-align-items-center wa-gap-s">
|
||||
<wa-button appearance="outlined">Sign up now</wa-button>
|
||||
<a href="#">no, thanks</a>
|
||||
</div>
|
||||
</form>
|
||||
<div class="wa-frame:portrait wa-border-radius-l">
|
||||
<img src="https://images.unsplash.com/photo-1552558636-f6a8f071c2b3?q=80&w=2268&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
122
docs/docs/patterns/information/paywall.md
Normal file
122
docs/docs/patterns/information/paywall.md
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
title: Paywall
|
||||
description: ''
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
|
||||
## Meter
|
||||
```html {.example}
|
||||
<div style="max-width: 45ch; margin: 0 auto;">
|
||||
<wa-card>
|
||||
<div class="wa-flank">
|
||||
<wa-avatar shape="rounded" style="--background-color: var(--wa-color-purple-80); --text-color: var(--wa-color-purple-40)">
|
||||
<wa-icon slot="icon" name="newspaper" family="regular"></wa-icon>
|
||||
</wa-avatar>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<p class="wa-caption-m">You've read <span style="font-weight: var(--wa-font-weight-bold);">9 out of 10 articles</span> this month.</p>
|
||||
<p>Already a subscriber? <a href="#">Log in here</a>.</p>
|
||||
<a href="#">Get Unlimited access for just 99¢</a>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
```
|
||||
## Modal
|
||||
|
||||
```html {.example viewport}
|
||||
<div style="position: relative;">
|
||||
|
||||
<div style="max-width: 90ch; margin: 0 auto; filter: blur(5px); padding: var(--wa-size)">
|
||||
<h2>The Great Gatsby</h2>
|
||||
<p>In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since.</p>
|
||||
<p>‘Whenever you feel like criticizing any one,’ he told me, ‘just remember that all the people in this world haven’t had the advantages that you’ve had.’</p>
|
||||
<p>He didn’t say any more but we’ve always been unusually
|
||||
communicative in a reserved way, and I understood that he meant a great deal more than that. In consequence I’m inclined to reserve all judgments, a habit that has opened up many curious natures to me and also made me the victim of not a few veteran bores. The abnormal mind is quick to detect and attach itself to this quality when it appears in a normal person, and so it came about that in college I was unjustly accused of being a politician, because I was privy to the secret griefs of wild, unknown men. Most of the confidences were unsought—frequently I have feigned sleep, preoccupation, or a hostile levity when I realized by some unmistakable sign that an intimate revelation was quivering on the horizon—for the intimate revelations of young men or at least the terms in which they express them are usually plagiaristic and marred by obvious suppressions. Reserving judgments is a matter of infinite hope. I am still a little afraid of missing something if I forget that, as my father snobbishly suggested, and I snobbishly repeat a sense of the fundamental decencies is parcelled out unequally at birth.</p>
|
||||
<p>And, after boasting this way of my tolerance, I come to the admission that it has a limit. Conduct may be founded on the hard rock or the wet marshes but after a certain point I don’t care what it’s founded on. When I came back from the East last autumn I felt that I wanted the world to be in uniform and at a sort of moral attention forever; I wanted no more riotous excursions with privileged glimpses into the human heart. Only Gatsby, the man who gives his name to this book, was exempt from my reaction—Gatsby who represented everything for which I have an unaffected scorn. If personality is an unbroken series of successful gestures, then there was something gorgeous about him, some heightened sensitivity to the promises of life, as if he were related to one of those intricate machines that register earthquakes ten thousand miles away. This responsiveness had nothing to do with that flabby impressionability which is dignified under the name of the ‘creative temperament’— it was an extraordinary gift for hope, a romantic readiness such as I have never found in any other person and which it is not likely I shall ever find again. No—Gatsby turned out all right at the end; it is what preyed on Gatsby, what foul dust floated in the wake of his dreams that temporarily closed out my interest in the abortive sorrows and shortwinded elations of men.</p>
|
||||
</div>
|
||||
<div style="background:rgba(24, 49, 83, 0.5);position: fixed; top: 0; right: 0; width: 100%; height: 100%;z-index: 1;">
|
||||
<wa-card style="max-width: 84ch;margin: 10% auto 0;">
|
||||
<div class="wa-stack wa-gap-xl">
|
||||
<h2 class="wa-heading-m">Want to subscribe or continue using our Products for free with ads?</h2>
|
||||
<p>Laws are changing in your region, so we're introducing a new choice about how we use your info for ads. You'll learn more about what each option means for you before you confirm your choice.</p>
|
||||
<p>Your choice will apply to the <a href="#">accounts in this Accounts Center</a>.</p>
|
||||
<div class="wa-grid">
|
||||
<article class="wa-stack wa-gap-s">
|
||||
<span class="wa-heading-s">Subscribe without ads</span>
|
||||
<p>Subscribe to our accounts without ads, starting at 5.99/month (inclusive of applicable taxes). Your info won't be use for ads.</p>
|
||||
<wa-button variant="success">Subscribe</wa-button>
|
||||
</article>
|
||||
<article class="wa-stack wa-gap-s">
|
||||
<span class="wa-heading-s">Free with ads</span>
|
||||
|
||||
<p>Discover products and brands through personalized ads, while using your accounts for free. Your info will be used for ads</p>
|
||||
<wa-button appearance="outlined">Use for Free</wa-button>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Footer
|
||||
|
||||
```html {.example viewport}
|
||||
<div style="position: relative;">
|
||||
<div style="max-width: 90ch; margin: 0 auto; filter: blur(5px); padding: var(--wa-size)">
|
||||
<h2>The Great Gatsby</h2>
|
||||
<p>In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since.</p>
|
||||
<p>‘Whenever you feel like criticizing any one,’ he told me, ‘just remember that all the people in this world haven’t had the advantages that you’ve had.’</p>
|
||||
<p>He didn’t say any more but we’ve always been unusually
|
||||
communicative in a reserved way, and I understood that he meant a great deal more than that. In consequence I’m inclined to reserve all judgments, a habit that has opened up many curious natures to me and also made me the victim of not a few veteran bores. The abnormal mind is quick to detect and attach itself to this quality when it appears in a normal person, and so it came about that in college I was unjustly accused of being a politician, because I was privy to the secret griefs of wild, unknown men. Most of the confidences were unsought—frequently I have feigned sleep, preoccupation, or a hostile levity when I realized by some unmistakable sign that an intimate revelation was quivering on the horizon—for the intimate revelations of young men or at least the terms in which they express them are usually plagiaristic and marred by obvious suppressions. Reserving judgments is a matter of infinite hope. I am still a little afraid of missing something if I forget that, as my father snobbishly suggested, and I snobbishly repeat a sense of the fundamental decencies is parcelled out unequally at birth.</p>
|
||||
<p>And, after boasting this way of my tolerance, I come to the admission that it has a limit. Conduct may be founded on the hard rock or the wet marshes but after a certain point I don’t care what it’s founded on. When I came back from the East last autumn I felt that I wanted the world to be in uniform and at a sort of moral attention forever; I wanted no more riotous excursions with privileged glimpses into the human heart. Only Gatsby, the man who gives his name to this book, was exempt from my reaction—Gatsby who represented everything for which I have an unaffected scorn. If personality is an unbroken series of successful gestures, then there was something gorgeous about him, some heightened sensitivity to the promises of life, as if he were related to one of those intricate machines that register earthquakes ten thousand miles away. This responsiveness had nothing to do with that flabby impressionability which is dignified under the name of the ‘creative temperament’— it was an extraordinary gift for hope, a romantic readiness such as I have never found in any other person and which it is not likely I shall ever find again. No—Gatsby turned out all right at the end; it is what preyed on Gatsby, what foul dust floated in the wake of his dreams that temporarily closed out my interest in the abortive sorrows and shortwinded elations of men.</p>
|
||||
</div>
|
||||
<div style="background:rgba(24, 49, 83, 0.5);position: fixed; top: 0; right: 0; width: 100%; height: 100%;z-index: 1;">
|
||||
<wa-card class="wa-border-radius-square" style="width: 75%;position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);">
|
||||
<div>
|
||||
<h2 class="wa-heading-m">You've hit your free article limit.</h2>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa-grid">
|
||||
<div class="wa-stack wa-gap-s wa-align-items-start">
|
||||
<span class="wa-heading-s">Standard Digital</span>
|
||||
<span class="wa-heading-xl">$45/month</span>
|
||||
<p>Essential digital access to quality journalism on any device. Makes a great gift.</p>
|
||||
<wa-button size="small" variant="brand">Select</wa-button>
|
||||
<a href="#">What's Included?</a>
|
||||
</div>
|
||||
<div class="wa-stack wa-gap-s wa-align-items-start">
|
||||
<span class="wa-heading-s">Premium Digital</span>
|
||||
<span class="wa-heading-xl">$75/month</span>
|
||||
<p>Complete digital access to quality journalism with expert analysis from industry leaders.</p>
|
||||
<wa-button size="small" variant="brand">Select</wa-button>
|
||||
<a href="#">What's Included?</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
<!-- ### Paywall
|
||||
|
||||
```html {.example viewport}
|
||||
<div>
|
||||
<wa-dialog label="You've run out of free articles... loser" with-header class="dialog-header">
|
||||
<wa-button href="#">Register</wa-button>
|
||||
Already a subscriber? <a href="#">Login</a>
|
||||
</wa-dialog>
|
||||
|
||||
<wa-button>Open Paywall</wa-button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('.dialog-header');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
|
||||
openButton.addEventListener('click', () => dialog.open = true);
|
||||
</script>
|
||||
|
||||
</div>
|
||||
``` -->
|
||||
198
docs/docs/patterns/information/post-list.md
Normal file
198
docs/docs/patterns/information/post-list.md
Normal file
@@ -0,0 +1,198 @@
|
||||
---
|
||||
title: Post List
|
||||
description: ''
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
|
||||
## Text Based
|
||||
```html {.example}
|
||||
<div class="wa-stack wa-gap-2xl" style="max-width: 60ch; margin: 0 auto;">
|
||||
<div class="wa-split">
|
||||
<h2 class="wa-heading-l">Trending Articles</h2>
|
||||
<span class="wa-cluster">
|
||||
<wa-icon name="search"></wa-icon>
|
||||
<a href="#">See all</a>
|
||||
</span>
|
||||
</div>
|
||||
<article class="wa-stack wa-gap-s">
|
||||
<section class="wa-stack wa-gap-xs">
|
||||
<h3 class="wa-heading-m"><a href="#" style="text-decoration: none;">Worst Idioms</a></h3>
|
||||
<span class="wa-caption-m">by <strong><em><a href="#">Paisley Darts</a></em></strong> • 4 min</span>
|
||||
</section>
|
||||
<p>"You can't have your cake and eat it too"... This on needs to be buried in a shallow grave.</p>
|
||||
<a href="#" class="wa-cluster wa-gap-2xs"><span>Read More</span><wa-icon name="angle-right"></wa-icon></a>
|
||||
<wa-divider></wa-divider>
|
||||
</article>
|
||||
<article class="wa-stack wa-gap-s">
|
||||
<section class="wa-stack wa-gap-xs">
|
||||
<h3 class="wa-heading-m"><a href="#" style="text-decoration: none;">Boost Your Productivity with These 5 Simple Habits</a></h3>
|
||||
<span class="wa-caption-m">by <strong><em><a href="#">Michael Sur</a></em></strong> • 3 min</span>
|
||||
</section>
|
||||
<p>Small changes, big results—master the art of productivity in your daily routine.</p>
|
||||
<a href="#" class="wa-cluster wa-gap-2xs"><span>Read More</span><wa-icon name="angle-right"></wa-icon></a>
|
||||
<wa-divider></wa-divider>
|
||||
</article>
|
||||
<article class="wa-stack wa-gap-s">
|
||||
<section class="wa-stack wa-gap-xs">
|
||||
<h3 class="wa-heading-m"><a href="#" style="text-decoration: none;">Why Sustainable Fashion Is the Future of the Industry</a></h3>
|
||||
<span class="wa-caption-m">by <strong><em><a href="#">Stacy Magnolia</a></em></strong> • 7 min</span>
|
||||
</section>
|
||||
<p>From eco-friendly materials to ethical brands, sustainability is shaping the way we dress.</p>
|
||||
<a href="#" class="wa-cluster wa-gap-2xs"><span>Read More</span><wa-icon name="angle-right"></wa-icon></a>
|
||||
<wa-divider></wa-divider>
|
||||
</article>
|
||||
</div>
|
||||
```
|
||||
## Single Column with Images
|
||||
```html {.example}
|
||||
<div class="wa-stack" style="max-width: 78ch; margin: 0 auto;">
|
||||
<div class="wa-split">
|
||||
<h2 class="wa-heading-l">Trending Articles</h2>
|
||||
<span class="wa-cluster">
|
||||
<wa-icon name="search"></wa-icon>
|
||||
<a href="#">See all</a>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<article class="wa-flank:end wa-align-items-center">
|
||||
<div class="wa-stack wa-gap-s wa-align-items-start">
|
||||
<h3 class="wa-heading-m">Worst Idioms <span class="wa-caption-s">4 min</span></h3>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<p class="wa-caption-l">"You can't have your cake and eat it too"... This on needs to be buried in a shallow grave.</p>
|
||||
<span class="wa-caption-m">by <a href="#"><strong><em>Paisley Darts</em></strong></a></span>
|
||||
</div>
|
||||
<wa-tag size="small" appearance="filled">Opinion</wa-tag>
|
||||
</div>
|
||||
<div class="wa-frame wa-border-radius-m" style="width: 10ch;">
|
||||
<img src="https://images.unsplash.com/photo-1720170060678-7c30a36937cd?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
|
||||
</div>
|
||||
</article>
|
||||
<wa-divider></wa-divider>
|
||||
<article class="wa-flank:end wa-align-items-center">
|
||||
<div class="wa-stack wa-gap-s wa-align-items-start">
|
||||
<h3 class="wa-heading-m">Boost Your Productivity with These 5 Simple Habits <span class="wa-caption-s">3 min</span></h3>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<p class="wa-caption-l">"Small changes, big results—master the art of productivity in your daily routine.</p>
|
||||
<span class="wa-caption-m">by <a href="#"><strong><em>Michael Sur</em></strong></a></span>
|
||||
</div>
|
||||
<div class="wa-cluster">
|
||||
<wa-tag size="small" appearance="filled">Self Improvement</wa-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa-frame wa-border-radius-m" style="width: 10ch;">
|
||||
<img src="https://images.unsplash.com/photo-1507099985932-87a4520ed1d5?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
|
||||
</div>
|
||||
</article>
|
||||
<wa-divider></wa-divider>
|
||||
<article class="wa-flank:end wa-align-items-center">
|
||||
<div class="wa-stack wa-gap-s wa-align-items-start">
|
||||
<h3 class="wa-heading-m">Sustainable Fashion Is the Future of the Industry <span class="wa-caption-s">7 min</span></h3>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<p class="wa-caption-l">From eco-friendly materials to ethical brands, sustainability is shaping the way we dress.</p>
|
||||
<span class="wa-caption-m">by <a href="#"><strong><em>Stacy Magnolia</em></strong></a></span>
|
||||
</div>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<wa-tag size="small" appearance="filled">Style</wa-tag><wa-tag size="small" appearance="filled">Environmental</wa-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa-frame wa-border-radius-m" style="width: 10ch;">
|
||||
<img src="https://images.unsplash.com/photo-1631775512414-160ae648c209?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
|
||||
</div>
|
||||
</article>
|
||||
<wa-divider></wa-divider>
|
||||
<article class="wa-flank:end wa-align-items-center">
|
||||
<div class="wa-stack wa-gap-s wa-align-items-start">
|
||||
<h3 class="wa-heading-m">The Power of Mindfulness <span class="wa-caption-s">5 min</span></h3>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<p class="wa-caption-l">Discover how being present in the moment can lead to lasting mental well being.</p>
|
||||
<span class="wa-caption-m">by <a href="#"><strong><em>Desean Ivy</em></strong></a></span>
|
||||
</div>
|
||||
<div class="wa-cluster wa-gap-xs">
|
||||
<wa-tag size="small" appearance="filled">Meditation</wa-tag><wa-tag size="small" appearance="filled">Self Care</wa-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa-frame wa-border-radius-m" style="width: 10ch;">
|
||||
<img src="https://images.unsplash.com/photo-1591228127791-8e2eaef098d3?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
|
||||
</div>
|
||||
</article>
|
||||
<wa-divider></wa-divider>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
## With Image Card
|
||||
```html {.example}
|
||||
<div class="wa-stack wa-align-items-center" style="max-width: 105ch; margin: 0 auto;">
|
||||
<h2 class="wa-heading-l">Trending Articles</h2>
|
||||
<wa-input placeholder="Search Articles">
|
||||
<wa-icon name="search" slot="suffix"></wa-icon>
|
||||
</wa-input>
|
||||
<div class="wa-grid" style="--min-column-size: 40ch;">
|
||||
<a href="#" style="text-decoration: none;">
|
||||
<wa-card with-image>
|
||||
<img slot="image" src="https://images.unsplash.com/photo-1720170060678-7c30a36937cd?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="">
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">Worst Idioms</h2>
|
||||
<p class="wa-caption-l">"You can't have your cake and eat it too"... This on needs to be buried in a shallow grave.</p>
|
||||
<div class="wa-cluster wa-gap-s">
|
||||
<wa-avatar image="https://images.unsplash.com/photo-1522075469751-3a6694fb2f61?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="author avatar"></wa-avatar>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<span class="wa-heading-s">Paisley Darts</span>
|
||||
<span class="wa-caption-s">March 12th 2023</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="#" style="text-decoration: none;">
|
||||
<wa-card with-image>
|
||||
<img slot="image" src="https://images.unsplash.com/photo-1507099985932-87a4520ed1d5?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="">
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">Boost Your Productivity with These 5 Simple Habits</h2>
|
||||
<p class="wa-caption-l">Small changes, big results—master the art of productivity in your daily routine.</p>
|
||||
<div class="wa-cluster wa-gap-s">
|
||||
<wa-avatar image="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="author avatar"></wa-avatar>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<span class="wa-heading-s">Michael Sur</span>
|
||||
<span class="wa-caption-s">March 13th 2023</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="#" style="text-decoration: none;">
|
||||
<wa-card with-image>
|
||||
<img slot="image" src="https://images.unsplash.com/photo-1631775512414-160ae648c209?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="">
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">Sustainable Fashion Is the Future of the Industry</h2>
|
||||
<p class="wa-caption-l">From eco-friendly materials to ethical brands, sustainability is shaping the way we dress.</p>
|
||||
<div class="wa-cluster wa-gap-s">
|
||||
<wa-avatar image="https://images.unsplash.com/photo-1586297135537-94bc9ba060aa?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="author avatar"></wa-avatar>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<span class="wa-heading-s">Stacy Magnolia</span>
|
||||
<span class="wa-caption-s">March 14th 2023</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="#" style="text-decoration: none;">
|
||||
<wa-card with-image>
|
||||
<img slot="image" src="https://images.unsplash.com/photo-1591228127791-8e2eaef098d3?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="">
|
||||
<div class="wa-stack">
|
||||
<h2 class="wa-heading-m">The Power of Mindfulness</h2>
|
||||
<p class="wa-caption-l">Discover how being present in the moment can lead to lasting mental well being.</p>
|
||||
<div class="wa-cluster wa-gap-s">
|
||||
<wa-avatar image="https://images.unsplash.com/photo-1633332755192-727a05c4013d?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="author avatar"></wa-avatar>
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
<span class="wa-heading-s">Desean Ivy</span>
|
||||
<span class="wa-caption-s">March 12th 2023</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</a>
|
||||
</div>
|
||||
<a href="#" style="text-align: center;">See All</a>
|
||||
</div>
|
||||
```
|
||||
101
docs/docs/patterns/information/social-share.md
Normal file
101
docs/docs/patterns/information/social-share.md
Normal file
@@ -0,0 +1,101 @@
|
||||
---
|
||||
title: Social Share
|
||||
description: 'Allow users to easily share content with social networks and platform.'
|
||||
parent: information
|
||||
tags: information
|
||||
---
|
||||
|
||||
## Horizontal
|
||||
```html{.example}
|
||||
<wa-card style="max-width: fit-content; margin: 0 auto;">
|
||||
<div class="wa-stack">
|
||||
<span class="wa-heading-s">Share Video</span>
|
||||
<div class="wa-cluster">
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="code" label="Embed video" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Embed</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="facebook" family="brands" label="Share on Facebook" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Facebook</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="bluesky" family="brands" label="Share on Bluesky" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Bluesky</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="linkedin" family="brands" label="Share on LinkedIn" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">LinkedIn</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="envelope-open" label="Share with email" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Email</span>
|
||||
</span>
|
||||
</div>
|
||||
<wa-button appearance="outlined">
|
||||
<wa-icon slot="prefix" name="link"></wa-icon>
|
||||
Copy Link
|
||||
</wa-button>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
## Vertical
|
||||
```html{.example}
|
||||
<wa-card class="wa-border-radius-pill" style="max-width: 8ch; margin: 0 auto;">
|
||||
<div class="wa-stack">
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="code" label="Embed video" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Embed</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="facebook" family="brands" label="facebook" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Facebook</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="bluesky" family="brands" label="bluesky" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Bluesky</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="linkedin" family="brands" label="LinkedIn" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">LinkedIn</span>
|
||||
</span>
|
||||
<span class="wa-align-items-center wa-stack wa-gap-2xs">
|
||||
<wa-icon-button style="font-size: var(--wa-font-size-2xl);" name="envelope-open" label="email" href="#" target="_blank"></wa-icon-button>
|
||||
<span class="wa-caption-s">Email</span>
|
||||
</span>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## With Image Card
|
||||
```html {.example}
|
||||
<wa-card with-image style="max-width: 45ch; margin: 0 auto;">
|
||||
<img
|
||||
slot="image"
|
||||
src="https://images.unsplash.com/photo-1578269174936-2709b6aeb913?q=80&w=2671&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
alt="Super special awesome trophy"
|
||||
/>
|
||||
<div class="wa-stack wa-align-items-center">
|
||||
<div class="wa-stack wa-gap-2xs wa-align-items-center">
|
||||
<h2 class="wa-heading-l">Flawless!</h2>
|
||||
<span class="wa-caption-l">
|
||||
10 of 10</span>
|
||||
</div>
|
||||
<p style="text-align: center;">You got a perfect score in this section. Tell your friends, family, really... just anyone who will listen.</p>
|
||||
<div class="wa-cluster" style="margin-top: var(--wa-font-size-xl);">
|
||||
<wa-avatar label="Avatar with an image icon">
|
||||
<wa-icon-button slot="icon" style="font-size: var(--wa-font-size-2xl);" name="facebook" family="brands" label="Share on Facebook" href="#" target="_blank"></wa-icon-button>
|
||||
</wa-avatar>
|
||||
<wa-avatar label="Avatar with an image icon">
|
||||
<wa-icon-button slot="icon" style="font-size: var(--wa-font-size-2xl);" name="bluesky" family="brands" label="Share on Bluesky" href="#" target="_blank"></wa-icon-button>
|
||||
</wa-avatar>
|
||||
<wa-avatar label="Avatar with an image icon">
|
||||
<wa-icon-button slot="icon" style="font-size: var(--wa-font-size-2xl);" name="instagram" family="brands" label="Share on Instagram" href="#" target="_blank"></wa-icon-button>
|
||||
</wa-avatar>
|
||||
<wa-avatar label="Avatar with an image icon">
|
||||
<wa-icon-button slot="icon" style="font-size: var(--wa-font-size-2xl);" name="linkedin" family="brands" label="Share on LinkedIn" href="#" target="_blank"></wa-icon-button>
|
||||
</wa-avatar>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
@@ -12,11 +12,37 @@ Components with the <wa-badge variant="warning" pill>Experimental</wa-badge> bad
|
||||
During the alpha period, things might break! We take breaking changes very seriously, but sometimes they're necessary to make the final product that much better. We appreciate your patience!
|
||||
:::
|
||||
|
||||
## Next
|
||||
## 3.0.0-alpha.12
|
||||
|
||||
- Fixed `wa-pill` class for text fields
|
||||
- Fixed `pill` style for `<wa-input>` elements
|
||||
### Enhancements
|
||||
|
||||
- Added `appearance` to [`<wa-details>`](/docs/components/details) and [`<wa-card>`](/docs/components/card) and support for the [appearance utilities](/docs/utilities/appearance/) in the [`<details>` native styles](/docs/native/details).
|
||||
- Added an `orange` scale to all color palettes
|
||||
- Added the [`.wa-cloak` utility](/docs/utilities/fouce) to prevent FOUCE
|
||||
- Added the [`allDefined()` utility](/docs/usage/#all-defined) for awaiting component registration
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Specifying inherited CSS properties on `<wa-tooltip>` now works as expected ([thanks Dennis!](https://github.com/shoelace-style/webawesome-alpha/discussions/203))
|
||||
- Fixed a bug in `<wa-select>` that made it hard to use with VueJS, Svelte, and many other frameworks
|
||||
- Fixed a bug in `<wa-select multiple>` that sometimes resulted in empty `<div>` elements being output
|
||||
- Fixed a bug where changing a `<wa-option>` label wouldn't update the display label in `<wa-select>`
|
||||
- Added default spacing to icons slotted into `<wa-tab>`
|
||||
- Lots of fixes around pill-shaped elements:
|
||||
- Fixed the `wa-pill` class for text fields
|
||||
- Fixed `pill` style for `<wa-input>` and `<wa-radio-button>` elements
|
||||
- Fixed a bug in `<wa-radio-button>` that prevented active buttons from receiving the correct styles
|
||||
- Fixed a bug in `<wa-button>` that prevented the focus ring from showing in Safari
|
||||
- Fixed alignment of `<wa-dropdown>` inside button groups
|
||||
- Removed close watcher logic to backdrop hide animation bugs in `<wa-dialog>` and `<wa-drawer>`; this logic is already handled and we'll revisit `CloseWatcher` when browser support is better and behaviors are consistent
|
||||
- Revert `<wa-dialog>` structure and CSS to fix clipped content in dialogs (WA-A #123) and light dismiss in iOS Safari (WA-A #201)
|
||||
- Fixed a bug in `<wa-color-picker>` that prevented light dismiss from working when clicking immediately above the color picker dropdown
|
||||
- Fixed a bug in `<wa-progress>` that prevented Safari from animation progress changes
|
||||
- Fixed the missing indeterminate icon in [native checkbox styles](/docs/native/checkbox)
|
||||
- Fixed a bug in `<wa-radio>` where elements would stack instead of display inline
|
||||
- Docs fixes:
|
||||
- Fixed the search dialog's styles so it doesn't jump around as you search
|
||||
- Theme cards now have icons
|
||||
|
||||
## 3.0.0-alpha.11
|
||||
|
||||
|
||||
3
docs/docs/themes/creating.md
vendored
3
docs/docs/themes/creating.md
vendored
@@ -31,8 +31,7 @@ If you're customizing the default dark styles, scope your styles to the followin
|
||||
|
||||
```css
|
||||
.wa-dark,
|
||||
.wa-invert,
|
||||
:is(:host-context(.wa-dark)) {
|
||||
.wa-invert {
|
||||
/* your custom styles here */
|
||||
}
|
||||
```
|
||||
|
||||
9
docs/docs/themes/index.njk
vendored
9
docs/docs/themes/index.njk
vendored
@@ -1,13 +1,13 @@
|
||||
---
|
||||
title: Themes
|
||||
description: Themes are collections of design tokens that thread through every Web Awesome component and pattern.
|
||||
description: Themes are collections of design tokens that thread through every Web Awesome component and pattern.
|
||||
Themes play a crucial role in [customizing Web Awesome](/docs/customizing).
|
||||
layout: overview
|
||||
override:tags: []
|
||||
forTag: theme
|
||||
categories:
|
||||
tags: [other, pro]
|
||||
other: Free
|
||||
pro: Pro
|
||||
---
|
||||
|
||||
<div class="max-line-length">
|
||||
@@ -30,7 +30,7 @@ In pre-made themes, we use a light color scheme by default.
|
||||
Additionally, styles may be scoped to the `:root` selector to be activated automatically.
|
||||
For pre-made themes, *all* custom properties are scoped to `:root`, the theme class, and `wa-light`.
|
||||
|
||||
Finally, we scope themes to `:host` and `:host-context()` to ensure the styles are applied to the shadow roots of custom elements.
|
||||
Finally, we scope themes to `:host` to ensure the styles are applied to the shadow roots of custom elements.
|
||||
|
||||
For example, the default theme is set up like this:
|
||||
|
||||
@@ -44,8 +44,7 @@ For example, the default theme is set up like this:
|
||||
}
|
||||
|
||||
.wa-dark,
|
||||
.wa-invert,
|
||||
:host-context(.wa-dark) {
|
||||
.wa-invert {
|
||||
/* subset of CSS custom properties for a dark color scheme */
|
||||
}
|
||||
```
|
||||
|
||||
14
docs/docs/themes/remix.js
vendored
14
docs/docs/themes/remix.js
vendored
@@ -54,8 +54,12 @@ function init() {
|
||||
urlParams: new Permalink(),
|
||||
};
|
||||
|
||||
data.urlParams.mapObject(data.params);
|
||||
data.urlParams.writeTo(data.params);
|
||||
// Apply params from permalink
|
||||
for (let key in data.params) {
|
||||
if (data.urlParams.has(key)) {
|
||||
data.params[key] = data.urlParams.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (computed.isRemixed) {
|
||||
// Start with the remixing UI open if the theme has been remixed
|
||||
@@ -128,7 +132,11 @@ function render(changedAspect) {
|
||||
selects[aspect].value = value;
|
||||
}
|
||||
|
||||
data.urlParams.readFrom(data.params);
|
||||
for (let key in data.params) {
|
||||
if (data.params[key]) {
|
||||
data.urlParams.set(key, data.params[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update demo URL
|
||||
domChange(() => {
|
||||
|
||||
1
docs/docs/themes/themes.json
vendored
1
docs/docs/themes/themes.json
vendored
@@ -3,6 +3,7 @@
|
||||
"wide": true,
|
||||
"tags": ["themes", "theme"],
|
||||
"brand": "blue",
|
||||
"icon": "theme",
|
||||
"eleventyComputed": {
|
||||
"file": "styles/themes/{{ page.fileSlug }}.css"
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ title: Design Tokens
|
||||
description: A theme is a collection of predefined CSS custom properties that control global styles from color to shadows. These custom properties thread through all Web Awesome components for a consistent look and feel.
|
||||
layout: overview
|
||||
override:tags: []
|
||||
categories: {tags: true}
|
||||
---
|
||||
|
||||
@@ -8,6 +8,61 @@ Web Awesome components are just regular HTML elements, or [custom elements](http
|
||||
|
||||
If you're new to custom elements, often referred to as "web components," this section will familiarize you with how to use them.
|
||||
|
||||
## Awaiting Registration
|
||||
|
||||
Unlike traditional frameworks, custom elements don't have a centralized initialization phase. This means you need to verify that a custom element has been properly registered before attempting to interact with its properties or methods.
|
||||
|
||||
### Individual components: `customElements.whenDefined()` { #when-defined}
|
||||
|
||||
You can use the [`customElements.whenDefined()`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined) method to ensure a specific component is ready:
|
||||
|
||||
```ts
|
||||
await customElements.whenDefined('wa-button');
|
||||
|
||||
// <wa-button> is ready to use!
|
||||
const button = document.querySelector('wa-button');
|
||||
```
|
||||
|
||||
### All Web Awesome components: `allDefined()` { #all-defined }
|
||||
|
||||
When working with multiple components, checking each one individually can become tedious. For convenience, Web Awesome provides the `allDefined()` function which automatically detects and waits for all Web Awesome components in the DOM to be initialized before resolving.
|
||||
|
||||
```ts
|
||||
import { allDefined } from '/dist/webawesome.js';
|
||||
|
||||
// Waits for all Web Awesome components in the DOM to be registered
|
||||
await allDefined();
|
||||
|
||||
// All Web Awesome components on the page are ready!
|
||||
```
|
||||
|
||||
#### Advanced Usage
|
||||
|
||||
By default, `allDefined()` will wait for all `wa-` prefixed custom elements within the current `document` to be registered.
|
||||
You can customize this behavior by passing in options:
|
||||
- `root` allows you to pass in a different element to search within, or a different document entirely (defaults to `document`).
|
||||
- `match` allows you to specify a custom function to determine which elements to wait for. This function should return `true` for elements you want to wait for and `false` for those you don't.
|
||||
- `additionalElements` allows you to wait for custom elements to be defined that may not be present in the DOM at the time `allDefined()` is called. This can be useful for elements that are loaded dynamically via JS.
|
||||
|
||||
Here is an example of using `match` and `root` to await registration of Web Awesome components inside an element with an id of `sidebar`, plus a `<my-component>` element if present in the DOM, and `<wa-slider>` and `<other-slider>` elements whether present in the DOM or not:
|
||||
|
||||
```js
|
||||
import { allDefined } from '/dist/webawesome.js';
|
||||
|
||||
await allDefined({
|
||||
match: tagName => tagName.startsWith('wa-') || tagName === 'my-component',
|
||||
root: document.getElementById('sidebar'),
|
||||
additionalElements: ['wa-slider', 'other-slider']
|
||||
});
|
||||
```
|
||||
|
||||
:::warning
|
||||
`additionalElements` will only wait for elements to be registered — it will not load them.
|
||||
If you're using the autoloader plus custom JS to inject HTML dynamically, **you need to make sure your JS runs _before_ the `await allDefined()` call**,
|
||||
otherwise you could run into a chicken and egg issue:
|
||||
since the autoloader will not load elements until they are present in the DOM, the promise will never resolve and your JS to inject them will not run.
|
||||
:::
|
||||
|
||||
## Attributes & Properties
|
||||
|
||||
Many components have properties that can be set using attributes. For example, buttons accept a `size` attribute that maps to the `size` property which dictates the button's size.
|
||||
@@ -88,49 +143,6 @@ For example, `<button>` and `<wa-button>` both have a `type` attribute, but the
|
||||
**Don't make assumptions about a component's API!** To prevent unexpected behaviors, please take the time to review the documentation and make sure you understand what each attribute, property, method, and event is intended to do.
|
||||
:::
|
||||
|
||||
## Waiting for Components to Load
|
||||
|
||||
Web components are registered with JavaScript, so depending on how and when you load Web Awesome, you may notice a [Flash of Undefined Custom Elements (FOUCE)](https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/) when the page loads. There are a couple ways to prevent this, both of which are described in the linked article.
|
||||
|
||||
One option is to use the [`:defined`](https://developer.mozilla.org/en-US/docs/Web/CSS/:defined) CSS pseudo-class to "hide" custom elements that haven't been registered yet. You can scope it to specific tags or you can hide all undefined custom elements as shown below.
|
||||
|
||||
```css
|
||||
:not(:defined) {
|
||||
visibility: hidden;
|
||||
}
|
||||
```
|
||||
|
||||
As soon as a custom element is registered, it will immediately appear with all of its styles, effectively eliminating FOUCE. Note the use of `visibility: hidden` instead of `display: none` to reduce shifting as elements are registered. The drawback to this approach is that custom elements can potentially appear one by one instead of all at the same time.
|
||||
|
||||
Another option is to use [`customElements.whenDefined()`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined), which returns a promise that resolves when the specified element gets registered. You'll probably want to use it with [`Promise.allSettled()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) in case an element fails to load for some reason.
|
||||
|
||||
A clever way to use this method is to hide the `<body>` with `opacity: 0` and add a class that fades it in as soon as all your custom elements are defined.
|
||||
|
||||
```html
|
||||
<style>
|
||||
body {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
body.ready {
|
||||
opacity: 1;
|
||||
transition: 0.25s opacity;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="module">
|
||||
await Promise.allSettled([
|
||||
customElements.whenDefined('wa-button'),
|
||||
customElements.whenDefined('wa-card'),
|
||||
customElements.whenDefined('wa-rating')
|
||||
]);
|
||||
|
||||
// Button, card, and rating are registered now! Add
|
||||
// the `ready` class so the UI fades in.
|
||||
document.body.classList.add('ready');
|
||||
</script>
|
||||
```
|
||||
|
||||
## Component Rendering and Updating
|
||||
|
||||
Web Awesome components are built with [Lit](https://lit.dev/), a tiny library that makes authoring custom elements easier, more maintainable, and a lot of fun! As a Web Awesome user, here is some helpful information about rendering and updating you should probably be aware of.
|
||||
|
||||
34
docs/docs/utilities/fouce.md
Normal file
34
docs/docs/utilities/fouce.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Reduce FOUCE
|
||||
description: Utility to improve the loading experience by hiding non-prerendered custom elements until they are registered.
|
||||
file: styles/utilities/fouce.css
|
||||
icon: spinner
|
||||
snippet: .wa-cloak
|
||||
---
|
||||
|
||||
Often, components are shown before their logic and styles have had a chance to load, also known as a [Flash of Undefined Custom Elements](https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/).
|
||||
The FOUCE style utility (which is automatically applied if you use our [style utilities](/docs/utilities/)) automatically takes care of hiding custom elements until **both they and their contents** have been registered, up to a maximum of two seconds.
|
||||
|
||||
In many cases, this is not enough, and you may wish to hide a broader wrapper element or even the entire page until all WA elements within it have loaded.
|
||||
To do that, you can add the `wa-cloak` class to any element on the page or even apply it to the whole page by placing the class on the `<html>` element:
|
||||
|
||||
```html
|
||||
<html class="wa-cloak">
|
||||
...
|
||||
</html>
|
||||
```
|
||||
|
||||
As soon as all elements are registered _or_ after two seconds have elapsed, the autoloader will show the page. The two-second timeout prevents blank screens from persisting on slow networks and pages that have errors.
|
||||
|
||||
:::details Are you using Turbo in your app?
|
||||
|
||||
If you're using [Turbo](https://turbo.hotwired.dev/) to serve a multi-page application (MPA) as a single page application (SPA), you might notice FOUCE when navigating from page to page. This is because Turbo renders the new page's content before the autoloader has a change to register new components.
|
||||
|
||||
The following function acts as a middleware to ensure components are registered _before_ the page shows, eliminating FOUCE for page-to-page navigation with Turbo.
|
||||
|
||||
```js
|
||||
import { preventTurboFouce } from '/dist/webawesome.js';
|
||||
|
||||
preventTurboFouce();
|
||||
```
|
||||
:::
|
||||
@@ -1,131 +0,0 @@
|
||||
---
|
||||
title: Reduce FOUCE
|
||||
description: Utility to improve the loading experience by hiding non-prerendered custom elements until they are registered.
|
||||
file: styles/utilities/fouce.css
|
||||
icon: spinner
|
||||
---
|
||||
{% markdown %}
|
||||
No class is needed to use this utility, it will be applied automatically as long as it its CSS is included.
|
||||
|
||||
Here is a comparison of the loading experience with and without this utility,
|
||||
with a simulated slow loading time:
|
||||
|
||||
{% endmarkdown %}
|
||||
|
||||
|
||||
<div class="wa-split wa-align-items-end">
|
||||
<strong>Normal loading</strong>
|
||||
<wa-button onclick="document.querySelectorAll('iframe').forEach(iframe => iframe.srcdoc = iframe.srcdoc)">
|
||||
<wa-icon name="refresh"></wa-icon>
|
||||
Refresh
|
||||
</wa-button>
|
||||
<strong>With FOUCE reduction</strong>
|
||||
</div>
|
||||
|
||||
|
||||
{% set sample_card %}
|
||||
<link id="theme-stylesheet" rel="stylesheet" href="/dist/styles/themes/default.css" render="blocking" fetchpriority="high">
|
||||
<link rel="stylesheet" href="/dist/styles/webawesome.css">
|
||||
<link rel="stylesheet" href="/dist/styles/forms.css">
|
||||
<script type=module>
|
||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
const loadScript = src => new Promise((resolve, reject) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
script.type = "module";
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
|
||||
await delay(500);
|
||||
await loadScript("/dist/components/button/button.js");
|
||||
await delay(500);
|
||||
await loadScript("/dist/components/card/card.js");
|
||||
await delay(500);
|
||||
await loadScript("/dist/components/rating/rating.js");
|
||||
</script>
|
||||
|
||||
<wa-card with-footer with-image class="card-overview">
|
||||
<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."
|
||||
/>
|
||||
|
||||
<strong>Mittens</strong><br />
|
||||
This kitten is as cute as he is playful. Bring him home today!<br />
|
||||
<small>6 weeks old</small>
|
||||
|
||||
<div slot="footer">
|
||||
<wa-button variant="brand" pill>More Info</wa-button>
|
||||
<wa-rating></wa-rating>
|
||||
</div>
|
||||
</wa-card>
|
||||
|
||||
<style>
|
||||
.card-overview small {
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
.card-overview [slot=footer] {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
{% endset %}
|
||||
|
||||
|
||||
<div class="iframes">
|
||||
<iframe srcdoc='<body class="wa-fouce-off">{{ sample_card }}</body>'></iframe>
|
||||
<iframe srcdoc='{{ sample_card }}'></iframe>
|
||||
</div>
|
||||
<style>
|
||||
.iframes {
|
||||
display: flex;
|
||||
gap: var(--wa-space-m);
|
||||
margin-top: var(--wa-space-l);
|
||||
|
||||
iframe {
|
||||
flex: 1;
|
||||
height: 60ch;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{% markdown %}
|
||||
## How does it work?
|
||||
|
||||
The utility consists of a timeout (`2s` by default) and a fade duration (`200ms` by default).
|
||||
- If the element is _ready_ before the timeout, it will appear immediately.
|
||||
- If it takes longer than _timeout_ + _fade_, it will fade in over the fade duration.
|
||||
- If it takes somewhere between _timeout_ and _timeout_ + _fade_, you will get an interrupted fade.
|
||||
|
||||
An element is considered ready when both of these are true:
|
||||
1. Either It has been registered or has a `did-ssr` attribute (indicating it was pre-rendered)
|
||||
2. If it’s a Web Awesome component, its contents are also ready
|
||||
|
||||
## Customization
|
||||
|
||||
You can use the following CSS variables to customize the behavior:
|
||||
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `--wa-fouce-fade` | The transition duration for the fade effect. | `200ms` |
|
||||
| `--wa-fouce-timeout` | The timeout after which elements will appear even if not registered | `2s` |
|
||||
|
||||
The fade duration cannot be longer than the timeout.
|
||||
This means that you can disable FOUCE reduction on an element by setting `--wa-fouce-timeout: 0s`.
|
||||
|
||||
For example, if instead of `did-ssr` you used an `ssr` attribute to mark elements that were pre-rendered, you can do this to get them to appear immediately:
|
||||
|
||||
```css
|
||||
[ssr] {
|
||||
--wa-fouce-timeout: 0s;
|
||||
}
|
||||
```
|
||||
|
||||
You can also opt-out from FOUCE reduction for an element and its contents by adding the `.wa-fouce-off` class to it.
|
||||
Applying this class to the root element will disable the utility for the entire page.
|
||||
{% endmarkdown %}
|
||||
@@ -4,8 +4,6 @@ description: Build better with Web Awesome, the open source library of web compo
|
||||
layout: page
|
||||
---
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
.title,
|
||||
.anchor-heading a,
|
||||
@@ -387,4 +385,4 @@ layout: page
|
||||
© Fonticons, Inc.
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@shoelace-style/webawesome",
|
||||
"version": "3.0.0-alpha.11",
|
||||
"version": "3.0.0-alpha.12",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@shoelace-style/webawesome",
|
||||
"version": "3.0.0-alpha.11",
|
||||
"version": "3.0.0-alpha.12",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^4.1.0",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user