Compare commits

...

167 Commits

Author SHA1 Message Date
Kelsey Jackson
c3de5a8915 removed old file 2025-03-14 16:02:39 -05:00
Kelsey Jackson
c18aa23d76 merging pattern-maiin 2025-03-14 16:00:32 -05:00
Kelsey Jackson
54e14a20c0 Merge pull request #703 from shoelace-style/kj/e-commerce-patterns
Kj/e commerce patterns
2025-03-14 15:57:58 -05:00
Kelsey Jackson
97b8e96a6e Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-03-14 15:56:08 -05:00
Kelsey Jackson
55a362b741 Merge branch 'pattern-main' into kj/app-pattern 2025-03-14 15:55:45 -05:00
Kelsey Jackson
d9cafdafb7 Merge branch 'next' into pattern-main 2025-03-14 15:55:15 -05:00
Lea Verou
1d03f7bee0 [Icon-button] Make --background-color-hover work + remaining 3 interaction properties (#801)
* [Icon-button] Make `--background-color-hover` work, fixes #800

* [Icon-button] Introduce `--text-color-hover`, `--background-color-active`, `--text-color-active`

* Oops
2025-03-14 09:29:04 -04:00
Kelsey Jackson
81bf6865ec big switchover 2025-03-14 06:10:40 -05:00
Lindsay M
a9bf1bd838 Add --wa-color-{role}-N variables, closes #785 (#797)
* Initial comment, based on #768

* Add `neutral` color variables

* Add `success`, `warning`, and `danger` variables

* Theme touch-ups

* Remove unused clamped tokens

* Re-add clamped tokens test page, refactor to be based on hue instead of `brand`
2025-03-13 17:07:03 -04:00
Lea Verou
c0ca739366 More robust dynamic value / options handling, fixes #789 2025-03-12 16:52:50 -04:00
Cory LaViska
a6745602d6 fix color picker light dismiss (#794)
* fix color picker light dismiss

* update changelog
2025-03-12 15:59:37 -04:00
Cory LaViska
da4f619d95 prevent card example from overflowing (#795) 2025-03-12 14:44:39 -04:00
Cory LaViska
1283a696a5 fix switch + tooltip behavior (#793) 2025-03-12 18:22:23 +00:00
Cory LaViska
d12b97b0b0 fix wa-pill and wa-input[pill] styles (#791) 2025-03-12 16:19:50 +00:00
lindsaym-fa
873eb47d18 Clean up utility usage and code formatting for product previews 2025-03-11 17:20:07 -04:00
lindsaym-fa
a564d3061f Clean up utility usage and code formatting for order summaries 2025-03-11 14:22:04 -04:00
Kelsey Jackson
ef865396f2 switching machines
:
2025-03-11 09:26:58 -05:00
Lea Verou
e5c2884880 [Tooltip] Specify inherited CSS properties on host, fixes #773 (#774)
* [Tooltip] Specify inherited CSS properties on host, fixes #773

* Remove unused `--show-delay` and `--hide-delay`
2025-03-10 15:08:27 -04:00
Lea Verou
1d600a77c4 Fix #566 2025-03-10 14:15:06 -04:00
Kelsey Jackson
903085257d removed store navigation 2025-03-07 11:12:39 -06:00
Kelsey Jackson
27237441a1 some heavy duty updates 2025-03-07 10:59:24 -06:00
Kelsey Jackson
b0291653f8 more polish 2025-03-06 22:43:13 -06:00
Kelsey Jackson
3962c50844 added review variant 2025-03-06 12:59:44 -06:00
lindsaym-fa
db3c568ba2 Add generated orange to Anodized palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
4bb9805ba6 Add generated orange to Bright palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
bd935fa8d5 Add generated orange to Classic palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
c3e582b47b Add generated orange to Natural palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
4d094a4e19 Add generated orange to Rudimentary palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
782c404bdf Add generated orange to Default palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
f1438981b2 Add generated orange to Elegant palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
18b88c2f5c Add generated orange to Mild palette 2025-03-05 22:27:11 -05:00
lindsaym-fa
a2d85f49a3 Add generated orange to Vogue palette 2025-03-05 22:27:11 -05:00
Lea Verou
be00026cd3 Update postprocess.js 2025-03-05 22:27:11 -05:00
Lea Verou
58ed88bc5a Add orange to list of hues 2025-03-05 22:27:11 -05:00
Lea Verou
1d14e186f3 Generate missing hues from neighboring hues 2025-03-05 22:27:11 -05:00
Lea Verou
5f672aabc2 Refactor: variable rename for consistency 2025-03-05 22:27:11 -05:00
Lea Verou
db08e12a32 Pave the way for being able to have core colors that are not mapped to any tint 2025-03-05 22:27:11 -05:00
Lea Verou
e0fc639226 Only use hex when color is within sRGB 2025-03-05 22:27:11 -05:00
Lea Verou
e6c662b543 tintless.js -> postprocess.js 2025-03-05 22:27:11 -05:00
Kelsey Jackson
314801c368 updated reviews 2025-03-05 16:40:36 -06:00
Kelsey Jackson
dc30ed8503 updated incentive images 2025-03-05 16:37:49 -06:00
lindsaym-fa
e12be798b8 Clean up utilities and formatting, replace placeholder text in order history 2025-03-04 14:30:00 -05:00
Kelsey Jackson
7f29f1b4ea started updating with style utilities 2025-03-04 13:09:41 -06:00
lindsaym-fa
3563d6a2dd Clean up utility usage and code formatting for category previews 2025-03-04 12:14:48 -05:00
Kelsey Jackson
007d93077f updated incentives 2025-03-04 11:04:31 -06:00
Kelsey Jackson
80b78aeb16 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-03-04 10:14:31 -06:00
Kelsey Jackson
8bc8ea85a5 Merge branch 'next' into pattern-main 2025-03-04 10:14:14 -06:00
Kelsey Jackson
61a6cd9fb9 updated image 2025-03-03 14:46:54 -06:00
Kelsey Jackson
7fb3fd5982 updated product preview 2025-03-03 14:22:45 -06:00
Kelsey Jackson
dc580b3351 committing to pull down changes 2025-03-03 10:38:10 -06:00
lindsaym-fa
74719d4c06 Refactor shopping cart patterns 2025-02-28 15:46:06 -05:00
Kelsey Jackson
47a7cdedd0 switching machines 2025-02-28 09:37:05 -06:00
lindsaym-fa
d906940726 Refactor product overview patterns 2025-02-27 17:04:10 -05:00
Kelsey Jackson
a782470c6a more polish 2025-02-27 11:47:56 -06:00
lindsaym-fa
de175ed4a1 Refactor product list patterns 2025-02-26 11:39:41 -05:00
lindsaym-fa
3612f8fdfa Add link style utilities 2025-02-26 11:39:11 -05:00
Kelsey Jackson
bc76df4b31 switching machines 2025-02-26 07:31:36 -06:00
lindsaym-fa
d1de9a9a73 Fix incorrect sizing tokens in size utilities 2025-02-26 01:01:39 -05:00
lindsaym-fa
4931de8eb4 Fix text color for filled appearance 2025-02-26 01:01:39 -05:00
lindsaym-fa
9ad7f4a6be Reorganize app patterns into separate pages 2025-02-25 12:02:29 -05:00
Kelsey Jackson
a7457630aa inital commit 2025-02-24 16:45:27 -06:00
Kelsey Jackson
e19928123f Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-02-24 11:05:08 -06:00
Kelsey Jackson
e644862f58 Merge branch 'next' into pattern-main 2025-02-24 11:04:45 -06:00
Kelsey Jackson
76529c628e committing to bring branches up to next 2025-02-24 11:04:07 -06:00
Kelsey Jackson
62ded7b15a updated order history 2025-02-21 15:27:43 -06:00
Lea Verou
71e7227763 Theme remixing fix: Order of params should not matter (#772)
Also renamed the `theme` export to `getThemeCode` since it was being renamed everywhere it was imported.
2025-02-21 14:03:55 -05:00
Lea Verou
dd671e15aa Changelog (#770) 2025-02-21 13:14:19 -05:00
Cory LaViska
2daeea0349 3.0.0-alpha.11 2025-02-21 12:53:05 -05:00
Cory LaViska
3cb6625c1d update changelog 2025-02-21 12:52:51 -05:00
Lea Verou
c4b5446d01 Fix boundingClientRect issue for elements whose host is display: contents 2025-02-21 12:02:20 -05:00
Lindsay M
41affca083 Allow color tweak tags to wrap (#769) 2025-02-21 11:50:13 -05:00
Kelsey Jackson
65af9980f1 updated content for category preview 2025-02-21 10:08:33 -06:00
Kelsey Jackson
db592194fd updtated content 2025-02-21 09:45:19 -06:00
Lea Verou
132dbfabcc Gray tweaks prototype (#761)
Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-02-20 12:10:43 -05:00
lindsaym-fa
4fc6224464 Fix missing listbox border 2025-02-19 14:54:11 -05:00
Kelsey Jackson
0f9ea14033 unlisted links 2025-02-19 11:12:05 -06:00
Kelsey Jackson
057b76a10a created e-commerce index 2025-02-19 10:09:42 -06:00
Lea Verou
4921d1c32e Save palette MVP, fixes #746 (#755) 2025-02-18 16:11:40 -05:00
Kelsey Jackson
b466ba9d0f Merge pull request #748 from shoelace-style/lm/ecommerce-patterns-revisions
Suggested Revisions to E-commerce Patterns
2025-02-18 13:34:45 -06:00
Kelsey Jackson
9c979931da fixed conflicts 2025-02-18 13:33:46 -06:00
Kelsey Jackson
898311590a switching branches to merge 2025-02-18 13:31:53 -06:00
Kelsey Jackson
5f4510f355 more tweaks 2025-02-18 09:56:49 -06:00
Lindsay M
54d71d2319 Use tintless and clamped brand colors in themes (#754)
* Use tintless `brand` colors, cutoffs in themes

* Re-add `40-min`, add `70-max`

* Fix mistakes in Mellow theme

* Revert accidental Premium brand color change

* Add changelog
2025-02-18 10:22:32 -05:00
Cory LaViska
c1ecca0169 fix select hint (#760) 2025-02-18 15:09:52 +00:00
Lea Verou
d6a91919e0 Code block improvements
- Add ids, use ids to link copy button. No need for client-side script or updating the copy button manually for dynamic code snippets.
- Add button to link to code block
- Slight refactor on copy plugin to use the 11ty API properly
2025-02-14 15:09:02 -05:00
Lea Verou
4621094ea1 [Tab] Avoid sprouting attributes in the constructor 2025-02-14 13:04:39 -05:00
Kelsey Jackson
b8eeb3db23 a little more polish 2025-02-14 07:42:36 -06:00
lindsaym-fa
8574270340 Add checkout form example 2025-02-13 23:06:50 -05:00
lindsaym-fa
aa042a0a6e Merge branch 'kj/e-commerce-patterns' into lm/ecommerce-patterns-revisions 2025-02-13 21:53:47 -05:00
Lea Verou
726dc73e2a Hue tweaking & chroma scaling, closes #669 #670 (#747)
- General infrastructure to support palette tweaking
- Hue shifts per color scale (UI, permalinks, dynamic code snippets)
- Scale overall chroma up/down (UI, permalinks, dynamic code snippets)
- Update contrast ratio tables (styling for contrast up/down/fail could use improvement, but it's a starting point)
- Make sure it works with Turbo (i.e. things don't break when we navigate to another page)
2025-02-13 19:28:20 -05:00
Lea Verou
4bfebf3249 Improve color ranges script (#752) 2025-02-13 18:15:47 -05:00
Kelsey Jackson
fe81a41a6b Merge branch 'kj/e-commerce-patterns' of github.com:shoelace-style/webawesome into kj/e-commerce-patterns 2025-02-13 15:09:27 -06:00
Kelsey Jackson
f3628ad2d8 tweaked customer review 2025-02-13 15:08:30 -06:00
lindsaym-fa
169337077d Add docs layout for patterns with stylesheet 2025-02-13 15:49:09 -05:00
lindsaym-fa
406d9a9708 Update category descriptions and headings 2025-02-13 15:47:21 -05:00
lindsaym-fa
faaf75c0a2 Add "What's a Pattern?" and "Using Patterns" to index 2025-02-13 13:22:46 -05:00
Kelsey Jackson
13b67db869 Merge branch 'kj/e-commerce-patterns' of github.com:shoelace-style/webawesome into kj/e-commerce-patterns 2025-02-13 10:35:40 -06:00
Kelsey Jackson
b7fdda4b03 cleaned up checkout form 2025-02-13 10:35:31 -06:00
Lea Verou
99ad0abdd3 Palette icons, take 4 2025-02-13 10:52:40 -05:00
Cory LaViska
902e2b6367 Fix invalid CSS property in <wa-select> (#751)
* remove empty selectors

* fix invalid property

* update changelog
2025-02-13 15:45:57 +00:00
lindsaym-fa
d60e675702 Reimplement checkout form revisions 2025-02-13 10:23:46 -05:00
lindsaym-fa
414a318f0b Revert checkout form changes in attempt to improve diff 2025-02-13 10:00:45 -05:00
lindsaym-fa
ff8ed89645 Merge branch 'kj/e-commerce-patterns' into lm/ecommerce-patterns-revisions 2025-02-13 09:55:45 -05:00
lindsaym-fa
e027ab1291 Fix typo in file name 2025-02-13 09:52:56 -05:00
lindsaym-fa
d8f97b15b4 Add missing file extension 2025-02-13 09:52:00 -05:00
Lea Verou
7f3210b12d Update changelog 2025-02-13 09:44:27 -05:00
Kelsey Jackson
a8ed6f2c19 tweaked order summary 2025-02-12 16:14:21 -06:00
Kelsey Jackson
c7f5dc69ad cleaned up shopping cart 2025-02-12 15:07:03 -06:00
Lea Verou
eee63bdecd Clamped brand color tokens (#741) 2025-02-12 15:13:03 -05:00
lindsaym-fa
42381722c5 Re-add navigation to "Product Features" carousel 2025-02-12 15:10:42 -05:00
lindsaym-fa
b2f9ec573f Merge branch 'kj/e-commerce-patterns' into lm/ecommerce-patterns-revisions 2025-02-12 15:05:33 -05:00
lindsaym-fa
b85e59b8ca "Checkout Form" revisions 2025-02-12 15:01:29 -05:00
Kelsey Jackson
8bd69694ce tweak category preview 2025-02-12 13:28:00 -06:00
Kelsey Jackson
7672923479 tweaked order history 2025-02-12 12:05:43 -06:00
Kelsey Jackson
c94006c6aa tweaked product overview 2025-02-12 11:21:17 -06:00
Kelsey Jackson
91ce2f2271 cleaned up product list 2025-02-12 10:08:51 -06:00
lindsaym-fa
9c609e44de "Category Filters" revisions + wa-placeholder utility 2025-02-11 17:06:40 -05:00
lindsaym-fa
28a8e4250a Revisions to "Product Features" 2025-02-11 17:05:38 -05:00
Kelsey Jackson
656a38cd3d updated prouct preview 2025-02-11 11:58:52 -06:00
Kelsey Jackson
9b90e56b45 more filter work 2025-02-11 10:57:29 -06:00
Lindsay M
a91fd07ed7 Add pink, closes #658 (#742) 2025-02-11 10:52:51 -05:00
Kelsey Jackson
0c84a2ff37 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-02-11 09:11:36 -06:00
Kelsey Jackson
511cca7931 Merge branch 'next' into pattern-main 2025-02-11 09:10:58 -06:00
Kelsey Jackson
2069d223f0 adding some polish 2025-02-11 09:10:18 -06:00
Lindsay M
34aa8917a6 Revisit default palette, closes #706 (#731)
* Adjust  everything  (but not grays)

* Update keys

* Tweak green

* Update lighter `green` tints
2025-02-10 22:37:14 -05:00
Lindsay M
715c2c0def Revisit bright palette, closes #697 (#705)
* Adjust red and yellow

* Update remaining colors

* Correct Awesome theme success colors

* Adjust `red`

* Redefine `indigo` and `purple`

* Tweak `indigo`
2025-02-10 17:11:34 -05:00
Kelsey Jackson
37d2455965 updated descriptions 2025-02-10 14:37:00 -06:00
Lea Verou
13b5385633 Radio improvements
- Drop `base` part (rel #207)
- Add `hint` slot and attribute (it was the only form control that did not support that)
- Refactor `@watch` calls to `updated()` per @claviska's plan for them
2025-02-10 14:19:53 -05:00
Lea Verou
d25f3748c4 Analyze color components (#732)
Also refactored existing color scripts (moved to separate directory, extracted utils to separate file)
2025-02-10 13:54:54 -05:00
Lindsay M
b6620ddf7e Revisit vogue palette, closes #723 (#738) 2025-02-10 13:23:57 -05:00
Lindsay M
d70d4a91b1 Revisit mild palette, closes #720 (#737)
* Adjust `cyan`, `indigo`, and `purple`

* Skew `indigo` more towards blue

* Better matching to Material tonal palettes
2025-02-10 13:20:44 -05:00
Lindsay M
bb1f7b2b7a Adjust everything (#734) 2025-02-10 11:42:31 -05:00
Lindsay M
9921c17d63 Revisit natural palette, closes #721 (#735)
* Adjust `cyan`

* Adjust `blue` and `purple`

* Adjust `red` and `yellow`
2025-02-10 11:42:11 -05:00
Lindsay M
7f964f9b56 Adjust everything (#736) 2025-02-10 11:41:36 -05:00
Lindsay M
31eeea1630 Revisit anodized palette, closes #718 (#733)
* Adjust  everything 

* Shift `red` towards orange in darker tints

* Tweak `green` balance
2025-02-10 11:41:17 -05:00
Kelsey Jackson
85b05fc655 editing descriptions 2025-02-07 15:50:15 -06:00
Kelsey Jackson
52328d9805 fixing conflicts 2025-02-07 14:24:40 -06:00
Kelsey Jackson
2c89c5f510 switching machines 2025-02-07 11:42:00 -06:00
Kelsey Jackson
5ac9e8cff1 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-02-05 12:16:50 -06:00
Kelsey Jackson
e238e35b3b Merge branch 'next' into pattern-main 2025-02-05 12:16:22 -06:00
Kelsey Jackson
c6d8d37871 switching machines 2025-01-31 09:43:40 -06:00
Kelsey Jackson
4dddb183fd updated width of container 2025-01-29 13:39:51 -06:00
Kelsey Jackson
d49ed53e9a added utilities to order-summary 2025-01-29 13:33:48 -06:00
Kelsey Jackson
99e2ffc17b added utilities to order history 2025-01-29 13:06:14 -06:00
Kelsey Jackson
97c79c29b9 Merge branch 'kj/e-commerce-patterns' of github.com:shoelace-style/webawesome into kj/e-commerce-patterns 2025-01-29 12:32:10 -06:00
Kelsey Jackson
7da9f53e27 filter work 2025-01-28 15:04:03 -06:00
Kelsey Jackson
a9cc02193f updated some patterns 2025-01-27 13:30:18 -06:00
Kelsey Jackson
9ad1c8f060 updated product list patterns 2025-01-27 13:17:09 -06:00
Kelsey Jackson
e0eaea2024 upated the product detail patterns 2025-01-27 11:20:40 -06:00
Kelsey Jackson
a8b7b6a93f Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-01-23 08:56:50 -06:00
Kelsey Jackson
581e47043a Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-01-22 18:50:38 -06:00
Kelsey Jackson
9ffe0cfe3c Merge branch 'next' into pattern-main 2025-01-22 18:50:11 -06:00
Kelsey Jackson
45df4a924f commiting to switch machines 2025-01-22 14:08:14 -06:00
Kelsey Jackson
43eed9d15e Merge branch 'next' into kj/e-commerce-patterns 2025-01-22 12:30:32 -06:00
Kelsey Jackson
a0ff411463 commiting to merge in next 2025-01-22 12:27:47 -06:00
Kelsey Jackson
04cd027c7e started split image pattern: 2025-01-17 14:44:14 -06:00
Kelsey Jackson
a68a157ebc switching machines 2025-01-15 16:41:13 -06:00
Kelsey Jackson
b2a24a3b52 Merge branch 'pattern-main' into kj/e-commerce-patterns 2025-01-09 11:31:46 -06:00
Kelsey Jackson
cbb456ffda switching machines 2025-01-09 11:29:32 -06:00
Kelsey Jackson
e0038c3125 Initial Commit 2025-01-09 10:59:33 -06:00
Kelsey Jackson
3e5d3120b1 Merge branch 'next' into kj/e-commerce-patterns 2025-01-08 16:19:29 -06:00
Kelsey Jackson
020f4cbaed building out the filter 2025-01-07 11:26:29 -06:00
Kelsey Jackson
9106bb88cf fixed merge conflicts 2025-01-06 10:34:51 -06:00
Kelsey Jackson
a822ab98c8 Merge branch 'next' into kj/e-commerce-patterns 2025-01-02 11:57:42 -06:00
Kelsey Jackson
026777c085 started invoice table 2024-12-18 09:53:15 -06:00
Kelsey Jackson
6d87b9b24a Merge branch 'next' into kj/e-commerce-patterns 2024-12-17 12:23:27 -06:00
Kelsey Jackson
d5affa01e9 dividing up e-commerce patterns 2024-12-11 15:06:01 -06:00
183 changed files with 10320 additions and 4710 deletions

View File

@@ -13,4 +13,4 @@ package-lock.json
tsconfig.json
cdn
_site
docs/assets/scripts/prism.js
docs/assets/scripts/prism-downloaded.js

View File

@@ -94,7 +94,7 @@ export default function (eleventyConfig) {
eleventyConfig.addPlugin(highlightCodePlugin());
// Add copy code buttons to code blocks
eleventyConfig.addPlugin(copyCodePlugin());
eleventyConfig.addPlugin(copyCodePlugin);
// Various text replacements
eleventyConfig.addPlugin(

1
docs/_data/hueRanges.js Normal file
View File

@@ -0,0 +1 @@
export { hueRanges as default } from '../assets/scripts/tweak/data.js';

View File

@@ -1 +1 @@
["red", "yellow", "green", "cyan", "blue", "indigo", "purple", "gray"]
["red", "orange", "yellow", "green", "cyan", "blue", "indigo", "purple", "pink", "gray"]

View File

@@ -1 +1 @@
export { default as default } from '../../src/styles/color/palettes-analyzed.js';
export { default as default } from '../../src/styles/color/scripts/palettes-analyzed.js';

View File

@@ -5,12 +5,12 @@
<meta name="theme-color" content="#f36944">
<script type="module" src="/assets/scripts/code-examples.js"></script>
<script type="module" src="/assets/scripts/copy-code.js"></script>
<script type="module" src="/assets/scripts/scroll.js"></script>
<script type="module" src="/assets/scripts/turbo.js"></script>
<script type="module" src="/assets/scripts/search.js"></script>
<script type="module" src="/assets/scripts/outline.js"></script>
{% if hasSidebar %}<script type="module" src="/assets/scripts/sidebar-tweaks.js"></script>{% endif %}
<script defer data-domain="backers.webawesome.com" src="https://plausible.io/js/script.js"></script>
{# Docs styles #}

View File

@@ -1,4 +1,4 @@
<table class="colors wa-palette-{{ paletteId }}">
<table class="colors wa-palette-{{ paletteId }} contrast-table" data-min-contrast="{{ minContrast }}">
<thead>
<tr>
<th></th>
@@ -12,19 +12,31 @@
</tr>
</thead>
{% for hue in hues -%}
<tr>
<tr data-hue="{{ hue }}">
<th>{{ hue | capitalize }}</th>
{% for tint_bg in tints -%}
{% set color_bg = palettes[paletteId][hue][tint_bg] %}
{% for tint_fg in tints | reverse -%}
{% set color_fg = palettes[paletteId][hue][tint_fg] %}
{% if (tint_fg - tint_bg) | abs == difference %}
<td>
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}-{{ tint_bg }}); color: var(--wa-color-{{ hue }}-{{ tint_fg }})">
{% set contrast_wcag = '' %}
{% if color_fg and color_bg %}
{% set contrast_wcag = color_bg.contrast(color_fg, 'WCAG21') %}
{% endif %}
{% set contrast_wcag = '' %}
{% if color_fg and color_bg -%}
{% set contrast_wcag = color_bg.contrast(color_fg, 'WCAG21') %}
{%- endif %}
<td v-for="contrast of [contrasts.{{ hue }}['{{ tint_bg }}']['{{ tint_fg }}']]"
data-tint-bg="{{ tint_bg }}" data-tint-fg="{{ tint_fg }}" data-original-contrast="{{ contrast_wcag }}">
<div v-content:number="contrast.value"
class="color swatch" :class="{
'value-up': contrast.value - contrast.original > 0.0001,
'value-down': contrast.original - contrast.value > 0.0001,
'contrast-fail': contrast.value < {{ minContrast }}
}"
style="--color: var(--wa-color-{{ hue }}-{{ tint_bg }}); color: var(--wa-color-{{ hue }}-{{ tint_fg }})"
:style="{
'--color': contrast.bgColor,
color: contrast.fgColor,
}"
>
{% if contrast_wcag %}
{{ contrast_wcag | number({maximumSignificantDigits: 2}) }}
{% else %}

View File

@@ -1,11 +1,14 @@
{% set paletteId = palette.fileSlug or page.fileSlug %}
{% set tints = [80, 60, 40, 20] %}
{% set suffixes = ['-80', '', '-20'] %}
{% set width = 20 %}
{% set height = 13 %}
{% set gap_x = 3 %}
{% set gap_y = 3 %}
{% set height = 12 %}
{% set height_core = 20 %}
{% set gap_x = 4 %}
{% set gap_y = 4 %}
<svg viewBox="0 0 {{ (width + gap_x) * hues|length }} {{ (height + gap_y) * tints|length }}" fill="none" xmlns="http://www.w3.org/2000/svg" class="wa-palette-{{ paletteId }} palette-icon">
{% 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 {
@@ -15,10 +18,14 @@
{% for hue in hues -%}
{% set hueIndex = loop.index0 %}
{% for tint in tints -%}
<rect x="{{ hueIndex * (width + gap_x) }}" y="{{ loop.index0 * (height + gap_y) }}"
width="{{ width }}" height="{{ height }}"
fill="var(--wa-color-{{ hue }}-{{ tint }})" rx="4" />
{% set y = 0 %}
{% for suffix in suffixes -%}
{% set swatch_height = height if suffix else height_core %}
<rect x="{{ hueIndex * (width + gap_x) }}" y="{{ y }}"
width="{{ width }}" height="{{ swatch_height }}"
fill="var(--wa-color-{{ hue }}{{ suffix }})" rx="2" />
{% set y = y + swatch_height + gap_y %}
{%- endfor %}
{% endfor %}
</svg>

View File

@@ -0,0 +1,10 @@
<svg width="120" height="87" viewBox="0 0 240 178" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="39" width="67" height="63" rx="12" fill="#D9D9D9"/>
<rect y="115" width="67" height="63" rx="12" fill="#D9D9D9"/>
<rect width="67" height="19" rx="6" fill="#D9D9D9"/>
<rect x="87" y="39" width="67" height="63" rx="12" fill="#D9D9D9"/>
<rect x="174" y="39" width="67" height="63" rx="12" fill="#D9D9D9"/>
<rect x="174" y="7" width="67" height="4.75" rx="2.375" fill="#D9D9D9"/>
<rect x="87" y="115" width="67" height="63" rx="12" fill="#D9D9D9"/>
<rect x="174" y="115" width="67" height="63" rx="12" fill="#D9D9D9"/>
</svg>

After

Width:  |  Height:  |  Size: 631 B

View File

@@ -1,17 +1,83 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{# {% set forceTheme = page.fileSlug %} #}
{% extends '../_layouts/block.njk' %}
{% set paletteId = page.fileSlug %}
{% block afterContent %}
<style>@import url('/dist/styles/color/{{ paletteId }}.css') layer(palette.{{ paletteId }});</style>
{% set tints = ["95", "90", "80", "70", "60", "50", "40", "30", "20", "10", "05"] %}
<table class="colors wa-palette-{{ paletteId }}">
{% extends '../_includes/base.njk' %}
{% block head %}
<style>@import url('/dist/styles/color/{{ paletteId }}.css') layer(palette.{{ paletteId }});</style>
<link href="{{ page.url }}../tweak.css" rel="stylesheet">
<script type="module" src="{{ page.url }}../tweak.js"></script>
{% endblock %}
{% block header %}
<div id="palette-app" data-palette-id="{{ paletteId }}">
<div
:class="{
tweaking: tweaking.chroma,
'tweaking-chroma': tweaking.chroma,
'tweaking-hue': tweaking.chroma,
'tweaking-gray-chroma': tweaking.grayChroma,
'tweaked-chroma': tweaked?.chroma,
'tweaked-hue': tweaked?.hue,
'tweaked-any': tweaked
}"
:style="{
'--chroma-scale': chromaScale,
'--gray-chroma': tweaked?.grayChroma ? grayChroma : '',
}">
{% 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>
<h1 v-if="!saved" class="title">{{ title }}</h1>
<div class="block-info">
<code class="class">.wa-palette-{{ paletteId }}</code>
{% include '../_includes/status.njk' %}
{% if not isPro %}
<wa-badge class="pro" v-if="tweaked">PRO</wa-badge>
{% endif %}
</div>
{% if description %}
<p class="summary">
{{ description | inlineMarkdown | safe }}
</p>
{% endif %}
{% endblock %}
{% block afterContent %}
{% set maxChroma = 0 %}
<wa-callout size="small" class="tweaked-callout" variant="warning">
<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>
</div>
<wa-button @click="reset()" appearance="outlined" variant="danger">
<span slot="prefix" class="icon-modifier">
<wa-icon name="circle-xmark" variant="regular"></wa-icon>
</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 }}">
<thead>
<tr>
<th></th>
@@ -21,18 +87,100 @@
{%- endfor %}
</tr>
</thead>
{# Initialize to last hue before gray #}
{%- set hueBefore = hues[hues|length - 2] -%}
{% for hue in hues -%}
<tr>
<th>{{ hue | capitalize }}</th>
<td class="core-column">
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}); color: var(--wa-color-{{ hue }}-{{ '05' if palettes[paletteId][hue].maxChromaTint > 60 else '95' }});">
{{ palettes[paletteId][hue].maxChromaTint }}
<wa-copy-button value="--wa-color-{{ hue }}" copy-label="--wa-color-{{ hue }}"></wa-copy-button>
</div>
{% set coreTint = palettes[paletteId][hue].maxChromaTint %}
{%- set coreColor = palettes[paletteId][hue][coreTint] -%}
{%- set maxChroma = coreColor.c if coreColor.c > maxChroma else maxChroma -%}
{% if hue === 'gray' %}
<tr data-hue="{{ hue }}" class="color-scale"
:class="{tweaking: tweaking.grayChroma, tweaked: tweaked.grayChroma || tweaked.grayColor }">
{% else %}
<tr data-hue="{{ hue }}" class="color-scale"
:class="{tweaking: tweaking.{{ hue }}, tweaked: hueShifts.{{ hue }} }"
:style="{ '--hue-shift': hueShifts.{{ hue }} || '' }">
{% endif %}
<th>
{{ hue | capitalize }}
</th>
<td class="core-column"
style="--color: var(--wa-color-{{ hue }})"
:style="{
'--color-tweaked': colors.{{ hue }}[{{ coreTint }}],
'--color-gray-undertone': colors[grayColor][{{coreTint}}],
'--color-tweaked-no-gray-chroma': colorsMinusGrayChroma.{{ hue }}[{{ coreTint }}],
}">
<wa-dropdown>
<div slot="trigger" id="core-{{ hue }}-swatch" data-tint="core" class="color swatch"
style="background-color: var(--wa-color-{{ hue }}); color: var(--wa-color-{{ hue }}-{{ '05' if palettes[paletteId][hue].maxChromaTint > 60 else '95' }});"
>
{{ palettes[paletteId][hue].maxChromaTint }}
<wa-icon name="sliders-simple" class="tweak-icon"></wa-icon>
</div>
<div class="popup">
{% if hue === 'gray' %}
<wa-radio-group class="core-color" orientation="horizontal" v-model="grayColor">
{% for h in hues -%}
{%- if h !== 'gray' -%}
<wa-radio-button id="gray-undertone-{{ h }}" value="{{ h }}" label="{{ h | capitalize }}" style="--color: var(--wa-color-{{ h }})"></wa-radio-button>
<wa-tooltip for="gray-undertone-{{ h }}" hoist>
{{ h | capitalize }}
</wa-tooltip>
{%- endif -%}
{%- endfor -%}
<div slot="label">
Gray undertone
</div>
</wa-radio-group>
<div class="decorated-slider gray-chroma-slider" :style="{'--max': maxGrayChroma}">
<wa-slider name="gray-chroma" v-model="grayChroma" ref="grayChromaSlider"
value="0" min="0" :max="maxGrayChroma" step="0.01"
@input="tweaking.grayChroma = true" @change="tweaking.grayChroma = false">
<div slot="label">
Gray colorfulness
<wa-icon-button @click="grayChroma = originalGrayChroma" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
</div>
</wa-slider>
<div class="label-min">Neutral</div>
<div class="label-max" v-content="moreHue[grayColor]">Warmer/Cooler</div>
</div>
{% else %}
{%- set hueAfter = hues[loop.index0 + 1] -%}
{%- set hueAfter = hues[0] if hueAfter == 'gray' else hueAfter -%}
{%- set minShift = hueRanges[hue].min - coreColor.h | round -%}
{%- set maxShift = hueRanges[hue].max - coreColor.h | round -%}
<div class="decorated-slider hue-shift-slider" style="--min: {{ minShift }}; --max: {{ maxShift }};">
<wa-slider name="{{ hue }}-shift" v-model="hueShifts.{{ hue }}" value="0"
min="{{ minShift }}" max="{{ maxShift }}" step="1"
@input="tweaking.hue = tweaking.{{hue}} = true"
@change="tweaking.hue = tweaking.{{ hue }} = false">
<div slot="label">
Tweak {{ hue }} hue
<wa-icon-button @click="hueShifts.{{ hue }} = 0" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
</div>
</wa-slider>
<div class="label-min">More {{hueBefore}}</div>
<div class="label-max">More {{hueAfter}}</div>
</div>
{%- set hueBefore = hue -%}
{% endif %}
<div class="wa-gap-s">
<code>--wa-color-{{ hue }}</code>
<wa-copy-button value="--wa-color-{{ hue }}" copy-label="--wa-color-{{ hue }}"></wa-copy-button>
</div>
</div>`
</wa-dropdown>
</td>
{% for tint in tints -%}
<td>
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}-{{ tint }})">
{%- set color = palettes[paletteId][hue][tint] -%}
<td data-tint="{{ tint }}" style="--color: var(--wa-color-{{ hue }}-{{ tint }})"
:style="{
'--color-tweaked': colors.{{ hue }}[{{ tint }}],
'--color-tweaked-no-gray-chroma': colorsMinusGrayChroma.{{ hue }}[{{ tint }}],
}">
<div class="color swatch" style="--color: var(--wa-color-{{ hue }}-{{ tint }})">
<wa-copy-button value="--wa-color-{{ hue }}-{{ tint }}" copy-label="--wa-color-{{ hue }}-{{ tint }}"></wa-copy-button>
</div>
</td>
@@ -41,6 +189,26 @@
{%- endfor %}
</table>
{% set chromaScaleBounds = [
(0.08 / maxChroma) | number({maximumFractionDigits: 2}),
(0.3 / maxChroma]) | number({maximumFractionDigits: 2}) -%}
<div class="decorated-slider chroma-scale-slider wa-palette-{{ paletteId }}"
:class="{ tweaked: chromaScale !== 1 }"
style="--min: {{ chromaScaleBounds[0] }}; --max: {{ chromaScaleBounds[1] }};">
<wa-slider name="chroma-scale" ref="chromaScaleSlider"
v-model="chromaScale" value="1" step="0.01"
min="{{ chromaScaleBounds[0] }}" max="{{ chromaScaleBounds[1] }}"
@input="tweaking.chroma = true"
@change="tweaking.chroma = false">
<div slot="label">
Overall colorfulness
<wa-icon-button @click="chromaScale = 1" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
</div>
</wa-slider>
<div class="label-min">More muted</div>
<div class="label-max">More vibrant</div>
</div>
<h2>Used By</h2>
<section class="index-grid">
@@ -65,6 +233,7 @@ A difference of `40` ensures a minimum **3:1** contrast ratio, suitable for larg
{% endmarkdown %}
{% set difference = 40 %}
{% set minContrast = 3 %}
{% include "contrast-table.njk" %}
{% markdown %}
@@ -84,6 +253,7 @@ A difference of `50` ensures a minimum **4.5:1** contrast ratio, suitable for no
{% endmarkdown %}
{% set difference = 50 %}
{% set minContrast = 4.5 %}
{% include "contrast-table.njk" %}
{% markdown %}
@@ -102,6 +272,7 @@ A difference of `60` ensures a minimum **7:1** contrast ratio, suitable for all
{% endmarkdown %}
{% set difference = 60 %}
{% set minContrast = 7 %}
{% include "contrast-table.njk" %}
{% markdown %}
@@ -114,13 +285,34 @@ This also goes for a difference of `65`:
{% include "contrast-table.njk" %}
{% markdown %}
## How to use this palette
## How to use this palette { #usage }
If you are using a Web Awesome theme that uses this palette, it will already be included.
To use a different palette than a theme default, or to use it in a custom theme, you can import this palette directly from the Web Awesome CDN.
{% set stylesheet = 'styles/color/' + page.fileSlug + '.css' %}
{% include 'import-stylesheet-code.md.njk' %}
<wa-tab-group class="import-stylesheet-code">
<wa-tab panel="html">In HTML</wa-tab>
<wa-tab panel="css">In CSS</wa-tab>
<wa-tab-panel name="html">
Add the following code to the `<head>` of your page:
```html { v-content:html="code.html.highlighted" }
<link rel="stylesheet" href="{% cdnUrl stylesheet %}" />
```
</wa-tab-panel>
<wa-tab-panel name="css">
Add the following code at the top of your CSS file:
```css { v-content:html="code.css.highlighted" }
@import url('{% cdnUrl stylesheet %}');
```
</wa-tab-panel>
</wa-tab-group>
{% endmarkdown %}
</div></div> {# end palette app #}
{% endblock %}

View File

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

View File

@@ -3,30 +3,39 @@ import { parse } from 'node-html-parser';
/**
* Eleventy plugin to add copy buttons to code blocks.
*/
export function copyCodePlugin(options = {}) {
export function copyCodePlugin(eleventyConfig, options = {}) {
options = {
container: 'body',
...options,
};
return function (eleventyConfig) {
eleventyConfig.addTransform('copy-code', content => {
const doc = parse(content, { blockTextElements: { code: true } });
const container = doc.querySelector(options.container);
let codeCount = 0;
eleventyConfig.addTransform('copy-code', content => {
const doc = parse(content, { blockTextElements: { code: true } });
const container = doc.querySelector(options.container);
if (!container) {
return content;
if (!container) {
return content;
}
// Look for code blocks
container.querySelectorAll('pre > code').forEach(code => {
const pre = code.closest('pre');
let preId = pre.getAttribute('id') || `code-block-${++codeCount}`;
let codeId = code.getAttribute('id') || `${preId}-inner`;
if (!code.getAttribute('id')) {
code.setAttribute('id', codeId);
}
if (!pre.getAttribute('id')) {
pre.setAttribute('id', preId);
}
// Look for code blocks
container.querySelectorAll('pre > code').forEach(code => {
const pre = code.closest('pre');
// Add a copy button (we set the copy data at runtime to reduce page bloat)
pre.innerHTML = `<wa-copy-button class="copy-button" hoist></wa-copy-button>` + pre.innerHTML;
});
return doc.toString();
// Add a copy button
pre.innerHTML += `<wa-icon-button href="#${preId}" class="block-link-icon" name="link"></wa-icon-button>
<wa-copy-button from="${codeId}" class="copy-button" hoist></wa-copy-button>`;
});
};
return doc.toString();
});
}

View File

@@ -1,15 +0,0 @@
function setCopyValue() {
document.querySelectorAll('.copy-button').forEach(copyButton => {
const pre = copyButton.closest('pre');
const code = pre?.querySelector('code');
if (code) {
copyButton.value = code.textContent;
}
});
}
// Set data for all copy buttons when the page loads
setCopyValue();
document.addEventListener('turbo:load', setCopyValue);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,37 +0,0 @@
/**
* Get import code for remixed themes.
*/
export const urls = {
colors: id => `styles/themes/${id}/color.css`,
palette: id => `styles/color/${id}.css`,
brand: id => `styles/brand/${id}.css`,
typography: id => `styles/themes/${id}/typography.css`,
};
function getImport(url, options = {}) {
let { language = 'html', cdnUrl = '/dist/', attributes } = options;
url = cdnUrl + url;
if (language === 'css') {
return `@import url('${url}');`;
} else {
attributes = attributes ? ` ${attributes}` : '';
return `<link rel="stylesheet" href="${url}"${attributes} />`;
}
}
export function getCode(base, params, options) {
let ret = [];
if (base) {
ret.push(`styles/themes/${base}.css`);
}
ret.push(
...Object.entries(params)
.filter(([aspect, id]) => Boolean(id))
.map(([aspect, id]) => urls[aspect](id)),
);
return ret.map(url => getImport(url, options)).join('\n');
}

View File

@@ -0,0 +1,254 @@
const sidebar = (globalThis.sidebar = {});
sidebar.palettes = {
render() {
if (this.saved.length === 0) {
return;
}
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;
}
}
},
equals(p1, p2) {
if (!p1 || !p2) {
return false;
}
return p1.id === p2.id && p1.uid === p2.uid;
},
delete(palette) {
let savedPalettes = sidebar.palettes.saved;
let count = savedPalettes.length;
if (count === 0) {
return;
}
// TODO improve UX of this
if (!confirm(`Are you sure you want to delete palette “${palette.title}”?`)) {
return;
}
savedPalettes = savedPalettes.filter(p => !sidebar.palette.equals(palette, p));
if (savedPalettes.length === count) {
// Nothing was removed
return;
}
// Update UI
let pathname = `/docs/palettes/${palette.id}/`;
let url = pathname + palette.search;
let uls = new Set();
for (let a of document.querySelectorAll(`#sidebar a[href="${url}"]`)) {
let li = a.closest('li');
let ul = li.closest('ul');
uls.add(ul);
li.remove();
}
// Remove empty lists
for (let ul of uls) {
if (!ul.children.length) {
ul.remove();
}
}
sidebar.updateCurrent();
sidebar.palettes.save(savedPalettes);
if (sidebar.palette.equals(globalThis.paletteApp?.saved, palette)) {
paletteApp.postDelete();
}
},
getSaved(palette, savedPalettes = sidebar.palettes.saved) {
return savedPalettes.find(p => sidebar.palette.equals(p, palette));
},
render(palette) {
// Find existing <a>
let { title, id, search, uid } = palette;
for (let a of document.querySelectorAll(`#sidebar a[href^="/docs/palettes/${id}/"][data-uid="${uid}"]`)) {
// Palette already in sidebar, just update it
a.textContent = palette.title;
a.href = `/docs/palettes/${id}/${search}`;
return;
}
let pathname = `/docs/palettes/${id}/`;
let url = pathname + search;
let parentA = document.querySelector(`a[href="${pathname}"]`);
let parentLi = parentA?.closest('li');
let a;
if (parentLi) {
a = Object.assign(document.createElement('a'), { href: url, textContent: title });
a.dataset.uid = uid;
let badges = [...parentLi.querySelectorAll('wa-badge')].map(badge => badge.cloneNode(true));
let ul = parentLi.querySelector('ul') ?? parentLi.appendChild(document.createElement('ul'));
let li = document.createElement('li');
let deleteButton = Object.assign(document.createElement('wa-icon-button'), {
name: 'trash',
label: 'Delete',
className: 'delete',
});
deleteButton.addEventListener('click', () => {
let palette = { id, uid, title: a.textContent, search: a.search };
sidebar.palette.delete(palette);
});
li.append(a, ' ', ...badges, deleteButton);
ul.appendChild(li);
}
},
save(palette, saved) {
let savedPalettes = sidebar.palettes.saved;
let existing = this.getSaved(saved ?? palette, savedPalettes);
let oldValues;
if (existing) {
// Rename
oldValues = { ...existing };
Object.assign(existing, palette);
} else {
savedPalettes.push(palette);
}
this.render(palette, oldValues);
sidebar.updateCurrent();
sidebar.palettes.save(savedPalettes);
},
};
sidebar.updateCurrent = function () {
// Find the sidebar link with the longest shared prefix with the current URL
let pathParts = location.pathname.split('/').filter(Boolean);
let prefixes = [];
if (pathParts.length === 1) {
// If at /docs/ we just use that, otherwise we want at least two parts (/docs/xxx/)
prefixes.push('/' + pathParts[0] + '/');
} else {
for (let i = 2; i <= pathParts.length; i++) {
prefixes.push('/' + pathParts.slice(0, i).join('/') + '/');
}
}
// Last prefix includes the search too (if any)
if (location.search) {
let params = new URLSearchParams(location.search);
params.sort();
prefixes.push(prefixes.at(-1) + location.search);
}
// We want to start from the longest prefix
prefixes.reverse();
let candidates;
let matchingPrefix;
for (let prefix of prefixes) {
candidates = document.querySelectorAll(`#sidebar a[href^="${prefix}"]`);
if (candidates.length > 0) {
matchingPrefix = prefix;
break;
}
}
if (!matchingPrefix) {
// Abort mission
return;
}
if (matchingPrefix === pathParts.at(-1)) {
// Full path matches, check search
if (location.search) {
candidates = [...candidates];
let searchParams = new URLSearchParams(location.search);
if (searchParams.has('uid')) {
// Only consider candidates with the same uid
candidates = candidates.filter(a => {
let params = new URLSearchParams(a.search);
return params.get('uid') === searchParams.get('uid');
});
} else {
// Sort candidates based on how many params they have in common, in descending order
candidates = candidates.sort((a, b) => {
return countSharedSearchParams(searchParams, b.search) - countSharedSearchParams(searchParams, a.search);
});
}
}
}
if (candidates.length > 0) {
for (let current of document.querySelectorAll('#sidebar a.current')) {
current.classList.remove('current');
}
candidates[0].classList.add('current');
}
};
sidebar.render = function () {
this.palettes.render();
};
sidebar.render();
window.addEventListener('turbo:render', () => sidebar.render());
function countSharedSearchParams(searchParams, search) {
if (!search || search === '?') {
return 0;
}
let params = new URLSearchParams(search);
return [...searchParams.keys()].filter(k => params.get(k) === searchParams.get(k)).length;
}

View File

@@ -0,0 +1,6 @@
/**
* Get import code for remixed themes and tweaked palettes.
*/
export { getThemeCode } from './tweak/code.js';
export { cdnUrl, hueRanges, hues, selectors, tints, urls } from './tweak/data.js';
export { default as Permalink } from './tweak/permalink.js';

View File

@@ -0,0 +1,54 @@
/**
* Get import code for remixed themes and tweaked palettes.
*/
import { urls } from './data.js';
export function cssImport(url, options = {}) {
let { language = 'html', cdnUrl = '/dist/', attributes } = options;
url = cdnUrl + url;
if (language === 'css') {
return `@import url('${url}');`;
} else {
attributes = attributes ? ` ${attributes}` : '';
return `<link rel="stylesheet" href="${url}"${attributes} />`;
}
}
export function cssLiteral(value, options = {}) {
let { language = 'html' } = options;
if (language === 'css') {
return value;
} else {
return `<style>\n${value}\n</style>`;
}
}
// Params in correct order
export const themeParams = ['colors', 'palette', 'brand', 'typography'];
export function getThemeCode(base, params, options) {
let ret = [];
if (base) {
ret.push(urls.theme(base));
}
for (let aspect of themeParams) {
let value = params[aspect];
if (value) {
ret.push(urls[aspect](value));
}
}
return ret.map(url => cssImport(url, options)).join('\n');
}
export function cssRule(selector, declarations, { indent = ' ' } = {}) {
selector = Array.isArray(selector) ? selector.flat().join(',\n') : selector;
declarations = Array.isArray(declarations) ? declarations.flat() : declarations;
declarations = declarations.map(declaration => indent + declaration.trim()).join('\n');
return `${selector} {\n${declarations.trimEnd()}\n}`;
}

View File

@@ -0,0 +1,73 @@
/**
* Data related to theme remixing and palette tweaking
* Must work in both browser and Node.js
*/
export const cdnUrl = globalThis.document ? document.documentElement.dataset.cdnUrl : '/dist/';
export const urls = {
theme: id => `styles/themes/${id}.css`,
colors: id => `styles/themes/${id}/color.css`,
palette: id => `styles/color/${id}.css`,
brand: id => `styles/brand/${id}.css`,
typography: id => `styles/themes/${id}/typography.css`,
};
export const selectors = {
palette: id =>
[':where(:root)', ':host', ":where([class^='wa-theme-'], [class*=' wa-theme-'])", `.wa-palette-${id}`].join(',\n'),
};
export const hueRanges = {
red: { min: 5, max: 35 }, // 30
orange: { min: 35, max: 60 }, // 25
yellow: { min: 60, max: 112 }, // 45
green: { min: 112, max: 170 }, // 55
cyan: { min: 170, max: 220 }, // 50
blue: { min: 220, max: 265 }, // 45
indigo: { min: 265, max: 290 }, // 25
purple: { min: 290, max: 320 }, // 30
pink: { min: 320, max: 365 }, // 45
};
export const moreHue = {
red: 'Redder',
orange: 'More orange', // https://www.reddit.com/r/grammar/comments/u9n0uo/is_it_oranger_or_more_orange/
yellow: 'Yellower',
green: 'Greener',
cyan: 'More cyan',
blue: 'Bluer',
indigo: 'More indigo',
pink: 'Pinker',
};
/**
* Max gray chroma (% of chroma of undertone) per hue
*/
export const maxGrayChroma = {
red: 0.2,
orange: 0.2,
yellow: 0.25,
green: 0.25,
cyan: 0.3,
blue: 0.35,
indigo: 0.35,
purple: 0.3,
pink: 0.25,
};
export const docsURLs = {
colors: '/docs/themes/',
palette: '/docs/palettes/',
typography: '/docs/themes/',
};
export const icons = {
colors: 'palette',
palette: 'swatchbook',
brand: 'droplet',
typography: 'font-case',
};
export const hues = Object.keys(hueRanges);
export const tints = ['05', '10', '20', '30', '40', '50', '60', '70', '80', '90', '95'];

View File

@@ -0,0 +1,81 @@
const IDENTITY = x => x;
export default class Permalink extends URLSearchParams {
/** Params changed since last URL I/O */
changed = false;
constructor(params) {
super(location.search);
this.params = params;
}
toJSON() {
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 (!value || value == defaultValue) {
super.delete(key);
if (oldValue) {
this.changed = true;
}
} else {
super.set(key, value);
if (String(value) !== String(oldValue)) {
this.changed = true;
}
}
this.sort();
}
/**
* Update page URL if it has changed since last time
*/
updateLocation() {
if (this.changed) {
// If theres already a search, replace it.
// We dont want to clog the users history while they iterate
let search = this.toString();
let historyAction = location.search && search ? 'replaceState' : 'pushState';
history[historyAction](null, '', `?${search}`);
this.changed = false;
}
}
}

View File

@@ -0,0 +1,36 @@
export function normalizeAngles(angles) {
// First, normalize
angles = angles.map(h => ((h % 360) + 360) % 360);
// Remove top and bottom 25% and find average
let averageHue =
angles
.toSorted((a, b) => a - b)
.slice(angles.length / 4, -angles.length / 4)
.reduce((a, b) => a + b, 0) / angles.length;
for (let i = 0; i < angles.length; i++) {
let h = angles[i];
let prevHue = angles[i - 1];
let delta = h - prevHue;
if (Math.abs(delta) > 180) {
let equivalent = [h + 360, h - 360];
// Offset hue to minimize difference in the direction that brings it closer to the average
let delta = h - averageHue;
if (Math.abs(equivalent[0] - prevHue) <= Math.abs(equivalent[1] - prevHue)) {
angles[i] = equivalent[0];
} else {
angles[i] = equivalent[1];
}
}
}
return angles;
}
export function subtractAngles(θ1, θ2) {
let [a, b] = normalizeAngles([θ1, θ2]);
return a - b;
}

View File

@@ -27,3 +27,19 @@ wa-copy-button.copy-button {
opacity: 1;
}
}
.block-link-icon {
position: absolute;
inset-block-start: 0;
inset-inline-end: calc(100% + var(--wa-space-s));
transition: var(--wa-transition-slow);
&:not(:hover, :focus) {
opacity: 50%;
}
:not(:hover, :focus-within) > & {
opacity: 0;
}
}

View File

@@ -156,7 +156,7 @@ wa-page > header {
}
/* Pro badges */
wa-badge.pro::part(base) {
wa-badge.pro {
background-color: var(--wa-brand-orange);
border-color: var(--wa-brand-orange);
}
@@ -188,6 +188,29 @@ wa-badge.pro::part(base) {
}
}
}
wa-icon-button.delete {
vertical-align: -0.2em;
margin-inline-start: var(--wa-space-xs);
&:not(li:hover > *, :focus) {
opacity: 0;
}
}
}
wa-icon-button.delete {
&:hover {
color: var(--wa-color-danger-on-quiet);
}
&::part(base):hover {
background: var(--wa-color-danger-fill-quiet);
}
&:not(:hover, :focus) {
opacity: 0.5;
}
}
#sidebar-close-button {
@@ -232,16 +255,32 @@ wa-page > main {
margin-inline: auto;
}
h1.title wa-badge {
vertical-align: middle;
h1.title {
wa-icon-button {
font-size: var(--wa-font-size-l);
color: var(--wa-color-text-quiet);
&::part(base) {
&:not(:hover, :focus) {
opacity: 0.5;
}
}
wa-badge {
vertical-align: middle;
font-size: 1.5rem;
}
}
.block-info {
display: flex;
gap: var(--wa-space-xs);
flex-wrap: wrap;
align-items: center;
margin-block-end: var(--wa-flow-spacing);
code {
line-height: var(--wa-line-height-condensed);
}
}
/* Current link */
@@ -400,9 +439,18 @@ wa-page > main:has(> .index-grid) {
&.color {
border-color: transparent;
transition: background var(--wa-transition-slow);
background: linear-gradient(var(--color-2, transparent) 0% 100%) no-repeat border-box var(--color,);
background-position: var(--color-2-position, bottom);
background-size: var(--color-2-width, 100%) var(--color-2-height, 50%);
&.contrast-fail {
outline: 1px dashed var(--wa-color-red);
outline-offset: calc(-1 * var(--wa-space-2xs));
}
}
wa-copy-button {
> wa-copy-button {
position: absolute;
top: 0;
left: 0;
@@ -463,6 +511,55 @@ table.colors {
}
}
.value-up,
.value-down {
position: relative;
&::after {
content: ' ' var(--icon);
position: absolute;
margin-inline-start: 3em;
scale: 1 0.6;
color: color-mix(in oklch, oklch(from var(--icon-color) none c h) 0%, oklch(from currentColor l none none));
font-size: 90%;
}
}
.value-down {
--icon: '▼';
--icon-color: var(--wa-color-danger-fill-quiet);
&::after {
margin-block-end: -0.2em;
}
}
.value-up {
--icon: '▲';
--icon-color: var(--wa-color-success-fill-quiet);
}
.icon-modifier {
position: relative;
display: inline-flex;
.modifier {
position: absolute;
bottom: -0.1em;
right: -0.3em;
font-size: 60%;
&::part(svg) {
stroke: var(--background-color, var(--wa-color-surface-default));
stroke-width: 100px;
paint-order: stroke;
overflow: visible;
stroke-linecap: round;
stroke-linejoin: round;
}
}
}
/* Layout Examples */
.layout-example-boundary {
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);

View File

@@ -19,13 +19,13 @@ icon: card
<div slot="footer">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
<wa-rating label="Rating"></wa-rating>
</div>
</wa-card>
<style>
.card-overview {
max-width: 300px;
width: 300px;
}
.card-overview small {

View File

@@ -74,3 +74,15 @@ Add the `size` attribute to the [Radio Group](/docs/components/radio-group) to c
<wa-radio value="3">Large 3</wa-radio>
</wa-radio-group>
```
### Hint
Add descriptive hint to a switch with the `hint` attribute. For hints that contain HTML, use the `hint` slot instead.
```html {.example}
<wa-radio-group label="Select an option" name="a" value="1">
<wa-radio value="1" hint="What should the user know about radio 1?">Option 1</wa-radio>
<wa-radio value="2" hint="What should the user know about radio 2?">Option 2</wa-radio>
<wa-radio value="3" hint="What should the user know about radio 3?">Option 3</wa-radio>
</wa-radio-group>
```

View File

@@ -0,0 +1,44 @@
---
title: Clamped Color Tokens
layout: block
---
{% set tints = ['max-50', 'max-60', 'max-70', 'min-50', 'min-60', 'min-70'] %}
{% set hues = ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'indigo', 'purple', 'pink', 'gray'] %}
<table class="colors">
<thead>
<tr>
<th></th>
<th class="core-column">Core tint</th>
{% for tint in tints -%}
<th>{{ tint }}</th>
{%- endfor %}
</tr>
</thead>
{% for hue in hues -%}
<tr class="wa-color-{{ hue }}">
<th>{{ hue | capitalize }}</th>
<td class="core-column">
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}); color: var(--wa-color-{{ hue }}-on); --key: var(--wa-color-{{ hue }}-key);">
{{ palettes[paletteId][hue].maxChromaTint }}
<wa-copy-button value="--wa-color-{{ hue }}" copy-label="--wa-color-{{ hue }}"></wa-copy-button>
</div>
</td>
{% for tint in tints -%}
<td>
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}-{{ tint }})">
<wa-copy-button value="--wa-color-{{ hue }}-{{ tint }}" copy-label="--wa-color-{{ hue }}-{{ tint }}"></wa-copy-button>
</div>
</td>
{%- endfor -%}
</tr>
{%- endfor %}
</table>
<style>
.core-column .color.swatch::before {
counter-reset: key var(--key);
content: counter(key);
}
</style>

View File

@@ -42,6 +42,14 @@ wa-code-demo::part(preview) {
<wa-input label="WA Input (url)" type="url"></wa-input>
```
## Pill shaped text fields
Add the `wa-pill` class to an `<input>` to make it pill-shaped.
```html {.example}
<label>Input <input type="text" placeholder="placeholder" class="wa-pill"></label>
```
## Color Picker
Basic:

View File

@@ -0,0 +1,27 @@
---
layout: null
permalink: "/docs/palettes/data.json"
eleventyExcludeFromCollections: true
---
{
{% for palette in collections.palettes %}
{% set paletteId = palette.fileSlug -%}
{% set colors = palettes[paletteId] -%}
"{{ paletteId }}": {
"title": "{{ palette.data.title }}",
"colors": {
{% for hue, tints in colors -%}
"{{ hue }}": {
{% for tint, value in tints -%}
{% if tint != "05" -%}
{% set value = value.coords or value -%}
{% set key = "05" if tint == "5" else tint -%}
"{{ key }}": {{ value | dump | safe }}{{ ', ' if not loop.last }}
{%- endif %}
{% endfor -%}
}{{ ', ' if not loop.last }}
{% endfor %} {# end of hue #}
}
}{{ ', ' if not loop.last }} {# end of palette #}
{% endfor %}
}

View File

@@ -1,4 +1,5 @@
---
title: Default
description: This is the palette used in the default theme.
order: 0
---

View File

@@ -1,6 +1,7 @@
{
"layout": "palette.njk",
"tags": ["palettes", "palette"],
"wide": true,
"eleventyComputed": {
"snippet": ".wa-palette-{{ page.fileSlug }}",
"icon": "palette",

View File

@@ -0,0 +1,205 @@
:root {
--fa-sliders-simple: '\f1de';
}
.core-column {
position: relative;
> wa-dropdown {
min-width: 100%;
}
}
wa-dropdown > .color.swatch {
cursor: pointer;
}
.decorated-slider {
display: grid;
grid-template-columns: auto 1fr auto;
margin-block-end: var(--wa-space-xl);
wa-slider {
grid-column: 1 / -1;
--track-height: 1em;
--track-color-inactive: transparent;
--track-color-active: transparent;
--thumb-color: var(--color-tweaked, var(--color));
--thumb-shadow: 0 0 0 var(--thumb-gap) var(--wa-color-surface-default),
var(--wa-shadow-offset-x-m) var(--wa-shadow-offset-y-m) var(--wa-shadow-blur-m)
calc(var(--wa-shadow-offset-x-m) * -1 + var(--thumb-gap)) var(--wa-color-shadow);
&:active {
--thumb-size: 2em;
}
&::part(base) {
background: linear-gradient(to right in var(--color-interpolation-space, oklab), var(--color-1), var(--color-2));
}
}
[slot='label'] {
min-height: 1.1lh;
}
.clear-button {
vertical-align: middle;
font-size: var(--wa-font-size-xs);
&:not(.tweaked *) {
display: none;
}
}
.label-min,
.label-max {
font-size: var(--wa-font-size-xs);
}
.label-min {
grid-column: 1;
margin-inline-start: 0.15em;
}
.label-max {
grid-column: 3;
margin-inline-end: 0.1em;
}
}
.hue-shift-slider {
--color-1: oklch(from var(--color) l c calc(h + var(--min, 0)));
--color-2: oklch(from var(--color) l c calc(h + var(--max, 0)));
--color-interpolation-space: oklch;
}
.chroma-scale-slider {
--color: var(--wa-color-brand);
--color-1: oklch(from var(--color) l calc(c * var(--min)) h);
--color-2: oklch(from var(--color) l calc(c * var(--max)) h);
}
.gray-chroma-slider {
--color: var(--wa-color-gray);
--color-1: oklch(from var(--wa-color-gray) l 0 none);
--color-2: oklch(from var(--color-gray-undertone) l calc(c * var(--max)) h);
margin-top: var(--wa-space-m);
}
.popup {
background: var(--wa-color-surface-default);
border: 1px solid var(--wa-color-surface-border);
padding: var(--wa-space-xl);
border-radius: var(--wa-border-radius-m);
code {
white-space: nowrap;
}
}
.color-scale {
th {
white-space: nowrap;
}
td:not([data-hue='gray'] *) {
--tweak-c: calc(c * var(--chroma-scale, 1));
--tweak-h: calc(h + var(--hue-shift, 0));
--color-tweaked-no-chroma-scale: oklch(from var(--color) l c var(--tweak-h));
--color-tweaked-no-hue-shift: oklch(from var(--color) l var(--tweak-c) h);
&:is([data-tint='90'], [data-tint='95']) {
/* Work around https://bugs.webkit.org/show_bug.cgi?id=287637 */
--color-tweaked-no-chroma-scale: lch(from var(--color) l c var(--tweak-h));
--color-tweaked-no-hue-shift: lch(from var(--color) l var(--tweak-c) h);
/* outline: 1px dashed red; */
}
}
.color.swatch {
--color-2: var(--color-tweaked);
--color-2-height: 100%;
&:is(.tweaking *) {
--color-2-height: 70%;
}
&:is(.tweaking-chroma *) {
--color: var(--color-tweaked-no-chroma-scale);
}
&:is(.tweaking-hue *) {
--color: var(--color-tweaked-no-hue-shift);
}
&:is(.tweaking-gray-chroma *) {
--color: var(--color-tweaked-no-gray-chroma);
}
}
.tweak-icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: var(--wa-space-s);
opacity: var(--tweak-icon-opacity, 0%);
}
.core-column:hover {
--tweak-icon-opacity: 40%;
}
&.tweaked .core-column {
--tweak-icon-opacity: 80%;
}
}
.tweaked-callout {
padding: var(--wa-space-xs);
padding-inline-start: var(--wa-space-m);
align-items: center;
&:not(.tweaked-any *) {
visibility: hidden;
}
&::part(message) {
display: flex;
align-items: center;
gap: var(--wa-space-xs);
}
wa-button:first-of-type {
margin-inline-start: auto;
}
}
/* Better UI before Vue initializes */
[v-if='saved'],
[v-if^='tweaked'] {
display: none;
}
.core-color {
wa-radio-button::part(base) {
width: 2em;
height: 2em;
padding: 0;
border-radius: var(--wa-border-radius-circle);
background: var(--color);
background-clip: border-box;
}
wa-radio-button:is([checked], :state(checked))::part(base) {
box-shadow:
inset 0 0 0 var(--indicator-width) var(--indicator-color),
inset 0 0 0 calc(var(--indicator-width) + 1.5px) var(--wa-color-surface-default);
}
&::part(form-control-input) {
gap: var(--wa-space-xs);
}
}

580
docs/docs/palettes/tweak.js Normal file
View File

@@ -0,0 +1,580 @@
// TODO move these to local imports
import Color from 'https://colorjs.io/dist/color.js';
import { createApp, nextTick } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
import { cdnUrl, hueRanges, hues, Permalink, tints } from '../../assets/scripts/tweak.js';
import { cssImport, cssLiteral, cssRule } from '../../assets/scripts/tweak/code.js';
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';
await Promise.all(['wa-slider'].map(tag => customElements.whenDefined(tag)));
// // Detect https://bugs.webkit.org/show_bug.cgi?id=287637
// const SAFARI_OKLCH_BUG = (() => {
// let dummy = document.createElement('div');
// document.body.appendChild(dummy);
// dummy.style.color = 'oklch(from #d5e0e6 l c h)';
// let computedColor = getComputedStyle(dummy).color;
// dummy.remove();
// return computedColor.endsWith(' 0)');
// })();
let allPalettes = await fetch('/docs/palettes/data.json').then(r => r.json());
globalThis.allPalettes = allPalettes;
for (let palette in allPalettes) {
for (let hue in allPalettes[palette].colors) {
let scale = allPalettes[palette].colors[hue];
for (let tint of tints) {
let color = scale[tint];
if (Array.isArray(color)) {
scale[tint] = new Color('oklch', color);
}
}
}
}
const percentFormatter = value => value.toLocaleString(undefined, { style: 'percent' });
let paletteAppSpec = {
data() {
let appRoot = document.querySelector('#palette-app');
let paletteId = appRoot.dataset.paletteId;
let palette = allPalettes[paletteId];
return {
uid: undefined,
paletteId,
paletteTitle: palette.title,
originalColors: palette.colors,
permalink: new Permalink(),
hueRanges,
hueShifts: Object.fromEntries(hues.map(hue => [hue, 0])),
chromaScale: 1,
grayChroma: undefined,
grayColor: undefined,
tweaking: {},
saved: null,
};
},
created() {
// 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);
for (let param of ['chroma-scale', 'gray-color', 'gray-chroma']) {
if (this.permalink.has(param)) {
let value = this.permalink.get(param);
if (!isNaN(value)) {
// Convert numeric values to numbers
value = Number(value);
}
let prop = camelCase(param);
this[prop] = value;
}
}
if (this.permalink.has('uid')) {
this.uid = Number(this.permalink.get('uid'));
}
this.saved = sidebar.palette.getSaved(this.getPalette());
}
},
mounted() {
for (let ref in this.$refs) {
this.$refs[ref].tooltipFormatter = percentFormatter;
}
},
computed: {
tweaks() {
return {
hueShifts: this.hueShifts,
chromaScale: this.chromaScale,
grayColor: this.grayColor,
grayChroma: this.grayChroma,
};
},
isTweaked() {
return Object.values(this.hueShifts).some(Boolean);
},
code() {
let ret = {};
for (let language of ['html', 'css']) {
let code = getPaletteCode(this.paletteId, this.colors, this.tweaked, { language, cdnUrl });
ret[language] = {
raw: code,
highlighted: Prism.highlight(code, Prism.languages[language], language),
};
}
return ret;
},
colors() {
return applyTweaks.call(this, this.originalColors, this.tweaks, this.tweaked);
},
colorsMinusChromaScale() {
let tweaked = { ...this.tweaked, chromaScale: false };
return applyTweaks.call(this, this.originalColors, this.tweaks, tweaked);
},
colorsMinusHueShifts() {
let tweaked = { ...this.tweaked, hue: false };
return applyTweaks.call(this, this.originalColors, this.tweaks, tweaked);
},
colorsMinusGrayChroma() {
let tweaked = { ...this.tweaked, grayChroma: false };
return applyTweaks.call(this, this.originalColors, this.tweaks, tweaked);
},
tweaked() {
let anyHueTweaked = Object.values(this.hueShifts).some(Boolean);
let hue = anyHueTweaked
? Object.fromEntries(Object.entries(this.hueShifts).map(([hue, shift]) => [hue, shift !== 0]))
: false;
let ret = {
chromaScale: this.chromaScale !== 1,
hue,
grayChroma: this.grayChroma !== this.originalGrayChroma,
grayColor: this.grayColor !== this.originalGrayColor,
};
let anyTweaked = Object.values(ret).some(Boolean);
return anyTweaked ? ret : false;
},
tweaksHumanReadable() {
let ret = {};
if (this.chromaScale !== 1) {
ret.chromaScale = 'More ' + (this.chromaScale > 1 ? 'vibrant' : 'muted');
}
for (let hue in this.hueShifts) {
let shift = this.hueShifts[hue];
if (!shift) {
continue;
}
let relHue = shift < 0 ? arrayPrevious(hues, hue) : arrayNext(hues, hue);
let hueTweak = moreHue[relHue] ?? relHue + 'er';
ret[hue] = capitalize(hueTweak + ' ' + hue + 's');
}
if (this.tweaked.grayChroma || this.tweaked.grayColor) {
if (this.tweaked.grayChroma === 0) {
ret.grayChroma = 'Achromatic grays';
} else {
if (this.tweaked.grayColor) {
ret.grayColor = capitalize(this.grayColor) + ' gray undertone';
}
if (this.tweaked.grayChroma) {
let more = this.tweaked.grayChroma > this.originalGrayChroma;
ret.grayChroma = `More ${more ? 'colorful' : 'neutral'} grays`;
}
}
}
return ret;
},
originalContrasts() {
return getContrasts(this.originalColors);
},
contrasts() {
return getContrasts(this.colors, this.originalContrasts);
},
originalCoreColors() {
let ret = {};
for (let hue in this.originalColors) {
let maxChromaTintRaw = this.originalColors[hue].maxChromaTintRaw;
ret[hue] = this.originalColors[hue][maxChromaTintRaw];
}
return ret;
},
coreColors() {
let ret = {};
for (let hue in this.colors) {
let maxChromaTintRaw = this.colors[hue].maxChromaTintRaw;
ret[hue] = this.colors[hue][maxChromaTintRaw];
}
return ret;
},
originalGrayColor() {
let grayHue = this.originalCoreColors.gray.get('h');
let minDistance = Infinity;
let closestHue = null;
for (let name in this.originalCoreColors) {
if (name === 'gray') {
continue;
}
let hue = this.originalCoreColors[name].get('h');
let distance = Math.abs(subtractAngles(hue, grayHue));
if (distance < minDistance) {
minDistance = distance;
closestHue = name;
}
}
return closestHue ?? 'indigo';
},
originalGrayChroma() {
let coreTint = this.originalColors.gray.maxChromaTint;
let grayChroma = this.originalColors.gray[coreTint].get('c');
if (grayChroma === 0 || grayChroma === null) {
return 0;
}
let grayColorChroma = this.originalColors[this.originalGrayColor][coreTint].get('c');
return grayChroma / grayColorChroma;
},
/**
* We want to preserve the original grayChroma selection so that when the user switches to another undertone
* that supports higher chromas, their selection will be there.
* This property is the gray chroma % that is actually applied.
*/
computedGrayChroma() {
return Math.min(this.grayChroma, this.maxGrayChroma);
},
maxGrayChroma() {
return maxGrayChroma[this.grayColor] ?? 0.3;
},
},
watch: {
hueShifts: {
deep: true,
handler() {
this.permalink.readFrom(this.hueShifts);
},
},
chromaScale() {
this.permalink.set('chroma-scale', this.chromaScale, 1);
},
grayColor() {
this.permalink.set('gray-color', this.grayColor, this.originalGrayColor);
},
grayChroma() {
this.permalink.set('gray-chroma', this.grayChroma, this.originalGrayChroma);
},
tweaks: {
deep: true,
async handler(value, oldValue) {
await nextTick(); // must run after individual watchers
// Update page URL
this.permalink.updateLocation();
if (this.saved) {
this.save({ silent: true });
}
},
},
},
methods: {
getPalette() {
return { id: this.paletteId, uid: this.uid, search: location.search };
},
save({ silent } = {}) {
let title = silent
? (this.saved?.title ?? this.paletteTitle)
: prompt('Palette title:', `${this.paletteTitle} (tweaked)`);
if (!title) {
return;
}
let uid = this.uid;
if (!uid) {
// First time saving
this.uid = uid = sidebar.palette.getUid();
this.permalink.set('uid', uid);
this.permalink.updateLocation();
}
let palette = { ...this.getPalette(), uid, title };
sidebar.palette.save(palette, this.saved);
this.saved = palette;
},
rename() {
if (!this.saved) {
return;
}
let newTitle = prompt('New title:', this.saved.title);
if (!newTitle) {
return;
}
this.saved.title = newTitle;
sidebar.palette.save(this.saved);
},
deleteSaved() {
sidebar.palette.delete(this.saved);
},
postDelete() {
this.saved = null;
this.permalink.delete('uid');
this.uid = undefined;
this.permalink.updateLocation();
},
/**
* Remove a specific tweak or all tweaks
* @param {string} [param] - The tweak to remove. If not provided, all tweaks are removed.
*/
reset(param) {
if (!param || param === 'chromaScale') {
this.chromaScale = 1;
}
if (param in this.hueShifts) {
this.hueShifts[param] = 0;
} else if (!param) {
for (let hue in this.hueShifts) {
this.hueShifts[hue] = 0;
}
}
if (!param || param === 'grayColor') {
this.grayColor = this.originalGrayColor;
}
if (!param || param === 'grayChroma') {
this.grayChroma = this.originalGrayChroma;
}
},
},
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;
}
},
},
compilerOptions: {
isCustomElement: tag => tag.startsWith('wa-'),
},
};
function init() {
let paletteAppContainer = document.querySelector('#palette-app');
globalThis.paletteApp?.unmount?.();
if (!paletteAppContainer) {
return;
}
globalThis.paletteApp = createApp(paletteAppSpec).mount(paletteAppContainer);
}
init();
addEventListener('turbo:render', init);
export function getPaletteCode(paletteId, colors, tweaked, options) {
let imports = [];
if (paletteId) {
imports.push(urls.palette(paletteId));
}
let css = '';
let declarations = [];
if (tweaked) {
for (let hue in colors) {
if (hue === 'orange') {
continue;
} else if (hue === 'gray') {
if (!tweaked.grayChroma && !tweaked.grayColor) {
continue;
}
} else if (!tweaked.chromaScale && !tweaked.hue?.[hue]) {
continue;
}
for (let tint of tints) {
let color = colors[hue][tint];
let stringified = color.toString({ format: color.inGamut('srgb') ? 'hex' : undefined });
declarations.push(`--wa-color-${hue}-${tint}: ${stringified};`);
}
declarations.push('');
}
if (declarations.length > 0) {
css += cssRule(selectors.palette(paletteId), declarations);
}
}
let ret = imports.map(url => cssImport(url, options)).join('\n');
if (css) {
ret += `\n\n${cssLiteral(css, options)}`;
}
return ret;
}
function arrayNext(array, element) {
let index = array.indexOf(element);
return array[(index + 1) % array.length];
}
function arrayPrevious(array, element) {
let index = array.indexOf(element);
return array[(index - 1 + array.length) % array.length];
}
function applyTweaks(originalColors, tweaks, tweaked) {
let ret = {};
let { hueShifts, chromaScale = 1, grayColor, grayChroma } = tweaks;
if (!tweaked) {
return originalColors;
}
if (tweaked.grayChroma) {
grayChroma = this.computedGrayChroma;
}
for (let hue in originalColors) {
let originalScale = originalColors[hue];
let scale = (ret[hue] = {});
let descriptors = Object.getOwnPropertyDescriptors(originalScale);
Object.defineProperties(scale, {
maxChromaTint: { ...descriptors.maxChromaTint, enumerable: false },
maxChromaTintRaw: { ...descriptors.maxChromaTintRaw, enumerable: false },
});
for (let tint of tints) {
let color = originalScale[tint].clone();
if (tweaked.hue && hueShifts[hue]) {
color.set({ h: h => h + hueShifts[hue] });
}
if (tweaked.chromaScale && chromaScale !== 1) {
color.set({ c: c => c * chromaScale });
}
if (hue === 'gray' && (tweaked.grayChroma || tweaked.grayColor)) {
let colorUndertone = originalColors[grayColor][tint].clone();
color = colorUndertone.set({ c: c => c * grayChroma });
}
scale[tint] = color;
}
}
return ret;
}
function camelCase(str) {
return (str + '').replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
}
function capitalize(str) {
return str[0].toUpperCase() + str.slice(1);
}
function getContrasts(colors, originalContrasts) {
let ret = {};
for (let hue in colors) {
ret[hue] = {};
for (let tintBg of tints) {
ret[hue][tintBg] = {};
let bgColor = colors[hue][tintBg];
if (!bgColor || !bgColor.contrast) {
continue;
}
for (let tintFg of tints) {
let fgColor = colors[hue][tintFg];
let value = bgColor.contrast(fgColor, 'WCAG21');
if (originalContrasts) {
let original = originalContrasts[hue][tintBg][tintFg];
ret[hue][tintBg][tintFg] = { value, original, bgColor, fgColor };
} else {
ret[hue][tintBg][tintFg] = value;
}
}
}
}
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
---
title: Action Panel
description: 'These patterns help add user actions to dashboards'
parent: app
tags: app
---
## Examples
### Simple
```html {.example}
<wa-card style="max-width: 480px; margin: 0 auto;">
<div class="wa-align-items-start wa-stack wa-gap-xs">
<h3 class="wa-heading-m">New Dashboard</h3>
<p>Arrange your data into a single view.</p>
<wa-button variant="brand">Build Dashboard</wa-button>
</div>
</wa-card>
```
### with right flank
```html {.example}
<wa-card style="max-width: 960px; margin: 0 auto;">
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-m">Query with the SQL Runner</h3>
<p>Access your database to run ad-hoc queries.</p>
</div>
<wa-button appearance="outlined">New Query</wa-button>
</div>
</wa-card>
```
### with switch
```html {.example}
<wa-card style="max-width: 960px; margin: 0 auto;">
<div class="wa-flank:end">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-m">Auto-renew</h3>
<p>We'll send you a reminder 30 days before we draft your account.</p>
</div>
<wa-switch size="large"></wa-switch>
</div>
</wa-card>
```

View File

@@ -0,0 +1,75 @@
---
title: Comments
description: 'For feedback forms and message boxes'
parent: app
tags: app
---
## Examples
### In card with footer
```html{.example}
<form class="comment-box" style="max-width: 960px; margin: 0 auto;">
<wa-card with-footer>
<wa-textarea resize="horizontal"></wa-textarea>
<div slot="footer" class="wa-cluster" style="justify-content: flex-end;">
<wa-button appearance="outlined">
<wa-icon slot="prefix" name="paperclip" variant="solid"></wa-icon>
Attach a file
</wa-button>
<wa-button variant="success">Comment</wa-button>
</div>
</wa-card>
</form>
```
### with avatar and icon buttons
```html{.example}
<div class="wa-callout wa-neutral wa-outlined" style="max-width: 960px; margin: 0 auto;">
<div class="wa-align-items-start wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" label="User avatar"></wa-avatar>
<div class="wa-stack wa-gap-s">
<wa-textarea placeholder="Add to the conversation..." size="medium"></wa-textarea>
<div class="wa-split">
<div>
<wa-icon-button name="link" variant="solid" label="Bold"></wa-icon-button>
<wa-icon-button name="face-smile" variant="solid" label="Italic"></wa-icon-button>
</div>
</wa-button><wa-button>Comment</wa-button>
</div>
</div>
</div>
</div>
```
### With multiple actions
```html{.example}
<wa-card with-header with-footer style="max-width: 640px; margin: 0 auto;">
<div slot="header">
<h2 class="wa-heading-s">I watched...</h2>
</div>
<div class="wa-stack">
<div class="wa-flank">
<div>
<img src="https://a.ltrbxd.com/resized/film-poster/1/0/2/5/3/3/1/1025331-heretic-2024-0-1000-0-1500-crop.jpg?v=c79c5c8121" width="40"/>
</div>
<span class="wa-heading-l">Heretic</span>
</div>
<wa-divider></wa-divider>
<div class="wa-split">
<span class="wa-heading-s">Date</span><span class="wa-caption-m">Thursday, March 13, 2025</span>
</div>
<wa-divider></wa-divider>
<div class="wa-split">
<wa-rating label="Rating"></wa-rating>
<wa-checkbox>Loved it!</wa-checkbox>
</div>
<wa-divider></wa-divider>
<wa-textarea placeholder="Add review..."></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>
```

View File

@@ -0,0 +1,161 @@
---
title: Data Display
description: TODO
parent: app
tags: app
---
## Examples
### With icon
```html{.example}
<div class="wa-grid" style="max-width: 960px; margin: 0 auto">
<wa-card>
<div class="wa-flank">
<wa-avatar shape="square" label="Square avatar" class="wa-callout wa-neutral">
<wa-icon slot="icon" name="user-plus" variant="solid"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Total Subscribers</span>
<div class="wa-cluster">
<span class="wa-heading-l">71,897</span>
<wa-tag size="small" variant="success" appearance="filled outlined" pill><wa-icon fixed-width name="arrow-up"></wa-icon> 122</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<wa-avatar shape="square" label="Square avatar" class="wa-callout wa-neutral">
<wa-icon slot="icon" name="user-plus" variant="solid"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Total Subscribers</span>
<div class="wa-cluster">
<span class="wa-heading-l">71,897</span>
<wa-tag size="small" variant="success" appearance="filled outlined" pill><wa-icon fixed-width name="arrow-up"></wa-icon> 122</wa-tag>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<wa-avatar shape="square" label="Square avatar" class="wa-callout wa-neutral">
<wa-icon slot="icon" name="user-plus" variant="solid"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Total Subscribers</span>
<div class="wa-cluster">
<span class="wa-heading-l">71,897</span>
<wa-tag size="small" variant="success" appearance="filled outlined" pill><wa-icon fixed-width name="arrow-up"></wa-icon> 122</wa-tag>
</div>
</div>
</div>
</wa-card>
</div>
```
### Multi column
```html{.example}
<div style="max-width: 480px; margin: 0 auto">
<wa-card>
<div>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-icon family="brands" name="youtube"></wa-icon>
<div class="wa-align-items-center wa-cluster" style="justify-content: space-between;">
<span>YouTube Premium</span>
<span>5 minutes ago</span>
<wa-tag variant="danger" appearance="outlined filled" pill>-$5.00</wa-tag>
</div>
</div>
<wa-divider></wa-divider>
</div>
</wa-card>
</div>
```
### Card with condensed information
```html{.example}
<wa-card style="max-width: 480px; margin: 0 auto;">
<div class="wa-stack">
<section class="wa-split">
<a href="#" class="wa-cluster wa-gap-xs wa-align-items-center">
<span class="wa-caption-m">query</span>
<span class="wa-heading-m">getUser</span>
<wa-icon fixed-width name="arrow-right"></wa-icon>
</a>
<wa-icon-button fixed-width name="ellipsis" label="actions"></wa-icon-button>
</section>
<section class="wa-cluster">
<span class="wa-caption-l">7.15M request • 9% • 734msP95</span>
</section>
<section class="wa-split">
<div class="wa-stack wa-gap-xs">
<span class="wa-caption-l">Cache Hit Rate</span>
<span class="wa-heading-2xl">12.3%</span>
<wa-badge appearance="filled outlined" variant="danger"><wa-icon name="arrow-down"></wa-icon> down from 19.6%</wa-badge>
</div>
<div class="wa-stack wa-gap-xs">
<span class="wa-caption-l">Max CHR</span>
<span class="wa-heading-2xl">72.6%</span>
<wa-badge appearance="filled outlined" variant="success"><wa-icon name="arrow-up"></wa-icon> CHR Impact +5.4%</wa-badge>
</div>
</section>
<wa-divider></wa-divider>
<section class="wa-stack">
<span class="wa-heading-m">90.5 GB (69.8%)</span>
<div class="wa-split">
<span>Cacheable Bandwidth</span>
<span class="wa-cluster wa-gap-2xs">
<wa-icon fixed-width name="dollar-sign"></wa-icon>
<span>$9.50</span>
<wa-icon fixed-width name="circle-question"></wa-icon>
</span>
</div>
<div class="wa-stack">
<wa-progress-bar value="9.8" label="Upload progress"></wa-progress-bar>
<span class="wa-caption-m">Cached 12.8GB (9.8%)</span>
<span class="wa-caption-m">Non-Cacheable 26.3GB (91.2)</span>
<span class="wa-heading-s">Total 129.6GB</span>
</div>
</section>
</div>
</wa-card>
```

View File

@@ -0,0 +1,244 @@
---
title: Description List
description: 'Shows the user information with labels and values in an easy to read format.'
parent: app
tags: app
---
## Examples
### Simple
```html{.example}
<div style="max-width: 960px; margin: 0 auto">
<h3 class="wa-heading-m">Applicant Info</h3>
<p class="wa-caption-m">Personal details.</p>
<wa-divider></wa-divider>
<dl class="wa-stack wa-gap-2xl">
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Full name</dt>
<dd class="wa-caption-m">Bucky Barnes</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Application for</dt>
<dd class="wa-caption-m">Machine Learning Engineer</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Email address</dt>
<dd class="wa-caption-m">winter_soldier@example.com</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Salary expectation</dt>
<dd class="wa-caption-m">
$240,00
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">About</dt>
<dd class="wa-caption-m">After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I loves, and I'm always striving to atone for those dark days as the Winter Soldier.
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Attachments</dt>
<dd>
<wa-card>
<div>
<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 style="max-width: 960px; margin: 0 auto">
<h2 class="wa-heading-m">Applicant Information</h2>
<p class="wa-caption-m">Personal details and application.</p>
<wa-divider></wa-divider>
<dl class="wa-grid wa-gap-2xl" style="--min-column-size: 40ch;">
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Full name</dt>
<dd class="wa-caption-m">Bucky Barnes</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Application for</dt>
<dd class="wa-caption-m">Machine Learning Engineer</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Email address</dt>
<dd class="wa-caption-m">winter_soldier@example.com</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Salary expectation</dt>
<dd class="wa-caption-m">
$240,00
</dd>
</div>
<div class="wa-align-items-start wa-flank wa-span-grid" style="--flank-size: 15%;">
<dt class="wa-heading-xs">About</dt>
<dd class="wa-caption-m">After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I loves, and I'm always striving to atone for those dark days as the Winter Soldier.
</dd>
</div>
<div class="wa-align-items-start wa-flank wa-span-grid" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Attachments</dt>
<dd>
<wa-card>
<div>
<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>
```
### Multi Column
```html{.example}
<div style="max-width: 960px; margin: 0 auto">
<h2 class="wa-heading-m">Applicant Information</h2>
<p class="wa-caption-m">Personal details and application.</p>
<wa-divider></wa-divider>
<dl class="wa-stack wa-gap-2xl">
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Full name</dt>
<dd class="wa-caption-m wa-split">
<span>Bucky Barnes</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Application for</dt>
<dd class="wa-caption-m wa-split">
<span>Machine Learning Engineer</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Email address</dt>
<dd class="wa-caption-m wa-split">
<span>winter_soldier@example.com</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">Salary expectation</dt>
<dd class="wa-caption-m wa-split">
<span>$240,00</span>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">About</dt>
<dd class="wa-caption-m wa-split">
<p style="max-width: 70ch;">After being lost in action and brainwashed into becoming Hydra's ruthless assassin, my journey is one of redemption, healing, and reclaiming my true self. Though burdened with the weight of the past, I remain a fierce warrior, loyal to those I loves, and I'm always striving to atone for those dark days as the Winter Soldier.</p>
<wa-button appearance="plain" variant="brand" size="small">Update</wa-button>
</dd>
</div>
<div class="wa-align-items-start wa-flank" style="--flank-size: 15%;">
<dt class="wa-heading-xs">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>
```
### Narrow with Invoice Details
```html{.example}
<wa-card with-header with-footer class="wa-callout wa-neutral" style="max-width: 480px; margin: 0 auto;">
<div slot="header" class="wa-split">
<dl class="wa-stack wa-gap-2xs">
<dt class="wa-heading-s">Amount</dt>
<dd class="wa-heading-l">$10,560.00</dd>
</dl>
<wa-badge appearance="filled outlined" variant="success">Paid</wa-badge>
</div>
<div>
<dl class="wa-stack" style="margin: 0;">
<div class="wa-flank wa-align-items-stretch">
<dt><wa-icon name="user"></wa-icon></dt>
<dd class="wa-heading-s">Sam Wilson</dd>
</div>
<div class="wa-flank wa-align-items-stretch">
<dt><wa-icon name="calendar-days"></wa-icon></dt>
<dd class="wa-heading-s">June 8, 2015</dd>
</div>
<div class="wa-flank wa-align-items-stretch">
<dt><wa-icon family="brands" name="cc-visa"></wa-icon></dt>
<dd class="wa-heading-s">Paid with Visa</dd>
</div>
</dl>
</div>
<div slot="footer">
<a href="#" class="wa-flank wa-align-items-center wa-gap-2xs">
<span>Download Receipt</span>
<wa-icon name="arrow-right"></wa-icon>
</a>
</div>
</wa-card>
```

View File

@@ -0,0 +1,113 @@
---
title: Empty State
description: TODO
parent: app
tags: app
---
## Examples
### Simple
```html{.example}
<div class="wa-stack wa-align-items-center">
<wa-icon name="folder" style="font-size: 60px;"></wa-icon>
<span class="wa-heading-s">No Projects</span>
<p class="wa-caption-m">Get started by creating a new project.</p>
<wa-button>
<wa-icon slot="prefix" name="plus"></wa-icon>
New Project
</wa-button>
</div>
```
### With border
```html{.example}
<a href="#" class="wa-align-items-center wa-callout wa-neutral wa-outlined wa-stack" style="max-width: 480px; margin: 0 auto; text-decoration: none;">
<wa-icon name="database" style="font-size: 64px;"></wa-icon>
<div class="wa-stack wa-align-items-center wa-gap-2xs">
<p class="wa-heading-m">No DBs</p>
<p>Get started by creating a database.</p>
</div>
</a>
```
### With starting points
```html{.example}
<wa-card with-header with-footer style="max-width: 720px; margin: 0 auto;">
<div slot="header" class="wa-stack wa-gap-xs">
<h2 class="wa-heading-m">Projects</h2>
<p class="wa-caption-m">You havent created a project yet. Get started by selecting a template or start from an empty project.</p>
</div>
<div class="wa-grid" style="--min-column-size: 30ch;">
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="bars" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a List <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Another to-do system youll try but eventually give up on.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="image" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Gallery <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Great for mood boards and inspiration.
</p>
</div>
</a>
<a href="#"class="wa-flank" style="text-decoration: none;">
<wa-icon name="table-cells" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Spreadsheet <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Helps keep up with the numbers.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="calendar" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Calendar <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Stay on top of your deadlines, or dont — its up to you.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="table-columns" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Board <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Track tasks in different stages of your project.
</p>
</div>
</a>
<a href="#" class="wa-flank" style="text-decoration: none;">
<wa-icon name="clock" class="wa-callout wa-neutral wa-outlined" style="font-size: 16px;"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-align-items-center wa-cluster wa-gap-xs wa-heading-s">
Create a Timeline <wa-icon name="arrow-right"></wa-icon>
</span>
<p class="wa-caption-m">
Get a birds-eye-view of your procrastination.
</p>
</div>
</a>
</div>
<div slot="footer">
<a href="#">Or start from an empty project →</a>
</div>
</wa-card>
```

View File

@@ -0,0 +1,92 @@
---
title: FAQ
description: TODO
parent: app
tags: app
---
```html{.example}
<div class="wa-grid">
<div>
<h2>Frequently Asked Questions</h2>
<p>Cant find the answer youre looking for? Reach out to our <a href="#">customer support</a> team.</p>
</div>
<dl class="wa-stack wa-gap-m">
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<div class="wa-stack wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
</dl>
</div>
```
```html{.example}
<div style="max-width: 960px; margin: 0 auto;">
<h2>Frequently Asked Questions</h2>
<div class="wa-stack wa-gap-xs">
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
<wa-details summary="How do you make holy water?">
You boil the hell out of it.
</wa-details>
</div>
</div>
```
```html{.example}
<div>
<h2>Frequently Asked Questions</h2>
<dl class="wa-stack wa-gap-m">
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-grid wa-gap-xs">
<dt class="wa-heading-m">How do you make holy water?</dt>
<dd class="wa-caption-l">You boil the hell out of it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate laboriosam fugiat.</dd>
</div>
</dl>
</div>
```

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
---
title: App
description: TODO
layout: overview
categories: ["app"]
listChildren: true
---

View File

@@ -0,0 +1,369 @@
---
title: Leaderboard
description: TODO
parent: app
tags: app
---
```html{.example}
<div class="wa-stack wa-gap-xs" style="max-width: 960px; margin: 0 auto">
<h2>Collective Activity for Yesterday</h2>
<div class="wa-grid">
<wa-callout>
<wa-icon slot="icon" name="book"></wa-icon>
<div class="wa-stack wa-gap-0">
<div class="wa-heading-xs">Items Studied</div>
<div class="wa-heading-2xl">482,813</div>
</div>
</wa-callout>
<wa-callout variant="warning">
<wa-icon slot="icon" name="medal"></wa-icon>
<div class="wa-stack wa-gap-0">
<div class="wa-heading-xs">Items Mastered</div>
<div class="wa-heading-2xl">67,106</div>
</div>
</wa-callout>
<wa-callout variant="success">
<wa-icon slot="icon" name="plus"></wa-icon>
<div class="wa-stack wa-gap-0">
<div class="wa-heading-xs">Items Created</div>
<div class="wa-heading-2xl">2,080</div>
</div>
</wa-callout>
</div>
<!-- -->
<div class="wa-grid">
<wa-card with-header>
<div slot="header" class="wa-flank">
<wa-icon name="trophy"></wa-icon>
<span class="wa-gap-0 wa-stack">
<h4>Study Leaders</h4>
<p>items mastered last 7 days</p>
</span>
</div>
<div>
<ol>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1620428268482-cf1851a36764?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1639628735078-ed2f038a193e?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-flank">
<div class="wa-frame wa-border-radius-m">
<img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?q=80&w=40&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" width="40" />
</div>
<div class="wa-stack wa-gap-2xs">
<span>mitsuwo</span>
<span>2,753</span>
</div>
</div>
</li>
</ol>
</div>
</wa-card>
<!-- -->
<wa-card with-header>
<div slot="header" class="wa-flank">
<wa-icon name="trophy"></wa-icon>
<span class="wa-gap-0 wa-stack">
<h4>Creation Leaders</h4>
<p>items created last 7 days</p>
</span>
</div>
<div>
<ol>
<li>
<p>Item 1</p>
<wa-divider></wa-divider>
</li>
<li>
<p>Item 1</p>
<wa-divider></wa-divider>
</li>
<li>
<p>Item 1</p>
<wa-divider></wa-divider>
</li>
</ol>
</div>
</wa-card>
</div>
</div>
```
### Two Column
```html{.example}
<div style="max-width: 960px; margin: 0 auto">
<h2>WTA Rankings</h2>
<div class="wa-grid wa-gap-3xl">
<div class="wa-stack">
<div class="wa-flank">
<div class="wa-border-radius-l wa-frame">
<img src="https://uploads.webawesome.com/serena-2.jpg" />
</div>
<div class="wa-stack wa-gap-s">
<span class="wa-heading-m">Serena Williams</span>
<span class="wa-caption-l">United States</span>
</div>
</div>
<span class="wa-heading-l">SINGLES</span>
<ol class="wa-stack wa-gap-2xs">
<li>
<div class="wa-split">
<span>Williams, Serena</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Williams, Serena</span>
<span>6960</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Li, Na</span>
<span>6785</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Halep, Simona</span>
<span>6070</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Radwanska, Agnieszka</span>
<span>5130</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Sharapova, Maria</span>
<span>4661</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Bouchard, Eugenie</span>
<span>4460</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Kerber, Angelique</span>
<span>4365</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Jankovic, Jelena</span>
<span>3900</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Azarenka, Victoria</span>
<span>3812</span>
</div>
</li>
</ol>
</div>
<!-- -->
<div class="wa-stack">
<div class="wa-cluster">
<div class="wa-border-radius-l wa-frame">
<img src="https://uploads.webawesome.com/roberta.jpg" />
</div>
<div class="wa-border-radius-l wa-frame">
<img src="https://uploads.webawesome.com/sara.jpg" />
</div>
</div>
<span class="wa-heading-l">DOUBLES</span>
<ol class="wa-stack wa-gap-2xs">
<li>
<div class="wa-split">
<span>Errani, Vinci</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Roberts, Paxson</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Smith, Wexler</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Elena, Hisieh</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Pen, Sania</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Makarova, Cara</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Washington, Roosevelt</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>King, Little</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Grier, Brown</span>
<span>9231</span>
</div>
<wa-divider></wa-divider>
</li>
<li>
<div class="wa-split">
<span>Burkhart, Silverton</span>
<span>9231</span>
</div>
</li>
</ol>
</div>
</div>
```

View File

@@ -0,0 +1,44 @@
---
title: Pagination
description: TODO
parent: app
tags: app
---
## Simple Pagination
```html{.example}
<div>
<wa-divider></wa-divider>
<div class="wa-split">
<span class="wa-caption-l">Showing 1 to 10 of 50 Results</span>
<span>
<wa-button><wa-icon slot="prefix" name="gear" variant="solid"></wa-icon> Prev</wa-button>
<wa-button><wa-icon slot="suffix" name="gear" variant="solid"></wa-icon>Next </wa-button>
</span>
</div>
</div>
```
## Multi Page
```html {.example}
<wa-card with-footer>
<div class="wa-stack" style="opacity: 25%;">
<div>
<div class="wa-flank">
<wa-avatar label="User avatar"></wa-avatar>
<div>
Some stuff
</div>
</div>
<wa-divider></wa-divider>
</div>
</div>
<div slot="footer" class="wa-split">
<wa-button><wa-icon slot="prefix" name="gear" variant="solid"></wa-icon> Prev</wa-button>
<wa-button><wa-icon slot="suffix" name="gear" variant="solid"></wa-icon>Next </wa-button>
</div>
</wa-card>
```

View File

@@ -0,0 +1,137 @@
---
title: Pricing
description: TODO
parent: app
tags: app
---
```html{.example}
<div class="wa-grid">
<wa-card with-header>
<div slot="header">
<span class="wa-split">
<span class="wa-heading-s">Plan</span>
<wa-badge appearance="filled outlined" variant="success" pill>Most Popular</wa-badge>
</span>
<span class="wa-flank wa-gap-2xs">
<span class="wa-heading-2xl">$10</span>
<span class="wa-caption-l">per user/per month</span>
</span>
<p class="wa-caption-l">Basic Features</p>
<span class="wa-grid">
<wa-button>Get Started</wa-button>
<wa-button appearance="outlined">Talk to sales</wa-button>
</span>
</div>
<div class="wa-stack">
<p class="wa-heading-s">Features</p>
<p class="wa-caption-m">Everything in out free plan plus</p>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Access to basic features</span>
</div>
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Basic Reporting and Analytics</span>
</div>
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">10 Individual users</span>
</div>
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">20GB of data for user</span>
</div>
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Basic Chat and email</span>
</div>
</div>
</div>
</wa-card>
<wa-card with-header>
<div slot="header">
<span class="wa-split">
<span class="wa-heading-s">Plan</span>
<wa-badge appearance="filled outlined" variant="success" pill>Most Popular</wa-badge>
</span>
<span class="wa-flank wa-gap-2xs">
<span class="wa-heading-2xl">$10</span>
<span class="wa-caption-l">per user/per month</span>
</span>
<p class="wa-caption-l">Basic Features</p>
<span class="wa-grid">
<wa-button>Get Started</wa-button>
<wa-button appearance="outlined">Talk to sales</wa-button>
</span>
</div>
<div class="wa-stack wa-gap-2xs">
<p class="wa-heading-s">Features</p>
<p class="wa-caption-m">Everything in out free plan plus</p>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Access to basic features</span>
</div>
</div>
</div>
</wa-card>
<wa-card with-header>
<div slot="header">
<span class="wa-split">
<span class="wa-heading-s">Plan</span>
<wa-badge appearance="filled outlined" variant="success" pill>Most Popular</wa-badge>
</span>
<span class="wa-flank wa-gap-2xs">
<span class="wa-heading-2xl">$10</span>
<span class="wa-caption-l">per user/per month</span>
</span>
<p class="wa-caption-l">Basic Features</p>
<span class="wa-grid">
<wa-button>Get Started</wa-button>
<wa-button appearance="outlined">Talk to sales</wa-button>
</span>
</div>
<div class="wa-stack wa-gap-2xs">
<p class="wa-heading-s">Features</p>
<p class="wa-caption-m">Everything in out free plan plus</p>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="check"></wa-icon>
<span class="wa-caption-m">Access to basic features</span>
</div>
</div>
</div>
</wa-card>
</div>
```
```html{.example}
<div class="wa-callout wa-neutral wa-outlined wa-grid">
<div class="wa-stack">
<h2 class="wa-heading-l">Lifetime membership</h2>
<p>Lorem ipsum dolor sit amet consect etur adipisicing elit. Itaque amet indis perferendis blanditiis repellendus etur quidem assumenda.</p>
<wa-divider></wa-divider>
<h3 class="wa-heading-s">What's included</h3>
<div class="wa-grid">
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Private forum access</p></span>
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Entry to annual conference</p></span>
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Member resources</p></span>
<span class="wa-flank wa-gap-xs"><wa-icon name="check"></wa-icon><p class="wa-caption-m">Official member t-shirt</p></span>
</div>
</div>
<div class="wa-callout wa-neutral wa-stack wa-align-items-center">
<h3 class="wa-heading-s">Pay once, own it forever</h3>
<div>
<span class="wa-heading-3xl">$349</span>
<span>USD</span>
</div>
<wa-button variant="success">Get Access</wa-button>
<p class="wa-caption-s">Invoices and receipts available for easy company reimbursement</p>
</div>
</div>
```
### With templates
### With recommendations grid

View File

@@ -1,6 +1,7 @@
---
title: Blog
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,6 +1,7 @@
---
title: Business
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,13 +1,85 @@
---
title: Category Filter
description: TODO
description: 'Helps the user find the right products with filters to refine search results by specific attributes.'
parent: ecommerce
tags: e-commerce
icon: checkbox
---
TODO Page Description
## Sidebar with Checkboxes & Expandable Filters
## With inline actions and expandable sidebar filters
```html{.example}
<h1>New Arrivals</h1>
<div class="wa-flank wa-align-items-start" style="--flank-size: 200px;">
<form class="wa-stack">
<wa-checkbox checked>All Products</wa-checkbox>
<wa-checkbox>Sale</wa-checkbox>
<wa-checkbox>Travel</wa-checkbox>
<wa-checkbox>Organization</wa-checkbox>
<wa-checkbox>Accessories</wa-checkbox>
<wa-details summary="Color" open>
<div class="wa-stack">
<wa-checkbox>White</wa-checkbox>
<wa-checkbox>Beige</wa-checkbox>
<wa-checkbox>Blue</wa-checkbox>
<wa-checkbox>Brown</wa-checkbox>
<wa-checkbox>Green</wa-checkbox>
</div>
</wa-details>
<wa-details summary="Category">
<div class="wa-stack">
<wa-checkbox>Outdoor</wa-checkbox>
<wa-checkbox>Indoor</wa-checkbox>
<wa-checkbox>All Weather</wa-checkbox>
</div>
</wa-details>
<wa-details summary="Size">
<div class="wa-stack">
<wa-checkbox>Small</wa-checkbox>
<wa-checkbox>Medium</wa-checkbox>
<wa-checkbox>Large</wa-checkbox>
<wa-checkbox>XL</wa-checkbox>
<wa-checkbox>XXL</wa-checkbox>
</div>
</wa-details>
</form>
<div class="wa-placeholder"></div>
</div>
</div>
```
## Sidebar with Dropdowns
```html{.example}
<h1>New Arrivals</h1>
<div class="wa-flank wa-align-items-start">
<div class="wa-stack">
<wa-select label="Product Type" placeholder="Products" value="all-products">
<wa-option value="all-products">All Products</wa-option>
<wa-option value="sale">Sale</wa-option>
<wa-option value="travel">Travel</wa-option>
<wa-option value="organization">Organization</wa-option>
<wa-option value="accessories">Accessories</wa-option>
</wa-select>
<wa-divider></wa-divider>
<wa-select label="Color" placeholder="Color" value="black" multiple>
<wa-option value="black">Black</wa-option>
<wa-option value="white">White</wa-option>
<wa-option value="gray">Gray</wa-option>
</wa-select>
<wa-select label="Category" placeholder="Category" value="outdoor" multiple>
<wa-option value="outdoor">Outdoor</wa-option>
<wa-option value="indoor">Indoor</wa-option>
<wa-option value="all-weather">All Weather</wa-option>
</wa-select>
<wa-select label="Size" placeholder="Size" value="xl xxl" multiple>
<wa-option value="s">Small</wa-option>
<wa-option value="m">Medium</wa-option>
<wa-option value="l">Large</wa-option>
<wa-option value="xl">XL</wa-option>
<wa-option value="xxl">XXL</wa-option>
</wa-select>
</div>
<div class="wa-placeholder"></div>
</div>
```

View File

@@ -1,12 +1,164 @@
---
title: Category Preview
description: TODO
description: 'Help shoppers discover your product offerings with showcases of product categories.'
parent: ecommerce
tags: e-commerce
icon: preview
---
TODO Page Description
## Three Column (WIP)
## Split with Image Grid
```html {.example}
<div class="wa-flank wa-align-items-start" style="--flank-size: 20rem;">
<div class="wa-stack wa-gap-2xl">
<h2 class="wa-heading-xl">Casual Collection</h2>
<p class="wa-body-s">Look good &mdash; without looking like you're trying too hard. Our casual collection includes laid back styles that work in <em>almost</em> any situation.</p>
<wa-button>View the Collection</wa-button>
</div>
<div class="wa-stack">
<div class="wa-frame:landscape wa-border-radius-s">
<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
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
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)"
/>
</div>
</div>
</div>
</div>
```
## Columns with Tall Images
```html {.example}
<div class="wa-stack">
<h2 class="wa-heading-xl">Shop by Category</h2>
<div class="wa-grid">
<a href="" class="wa-stack wa-link-plain">
<div class="wa-frame:portrait wa-border-radius-s">
<img
src="https://uploads.webawesome.com/organization.jpg"
alt="Inside of a closet filled with clothes on wooden hangers and integrated shelving with shoes"
/>
</div>
<span class="wa-caption-xl">Organization</span>
</a>
<a href="" class="wa-stack wa-link-plain">
<div class="wa-frame:portrait wa-border-radius-s">
<img
src="https://uploads.webawesome.com/bags.jpg"
alt="Young person hugging a small floral patterned book bag between their arms"
/>
</div>
<span class="wa-caption-xl">Bags</span>
</a>
<a href="" class="wa-stack wa-link-plain">
<div class="wa-frame:portrait wa-border-radius-s">
<img
src="https://uploads.webawesome.com/outdoor-2.jpg"
alt="Person in a mountain clearing wearing a waterproof hooded windbreaker in black and orange"
/>
</div>
<span class="wa-caption-xl">Outdoor</span>
</a>
</div>
</div>
```
## Columns with Cards
```html {.example}
<div class="wa-stack">
<div class="wa-split">
<h2 class="wa-heading-xl">Shop by Category</h2>
<a href="" class="wa-cluster">
<span>Browse All Categories</span>
<wa-icon name="arrow-right"></wa-icon>
</a>
</div>
<div class="wa-grid">
<a href="" class="wa-link-plain">
<wa-card style="height: 100%">
<img
slot="image"
src="https://img.fortawesome.com/cfa83f3c/outdoor-3x.jpg"
alt="Two hikers wearing long canvas pants, weatherproof jackets, and backpacks"
/>
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-m">Outdoor</span>
<p class="wa-caption-m">Durable canvas gear for all conditions.</p>
</div>
</wa-card>
</a>
<a href="" class="wa-link-plain">
<wa-card style="height: 100%">
<img
slot="image"
src="https://img.fortawesome.com/cfa83f3c/home.jpg"
alt="Woman sitting on a couch in a bright home, wearing a thick knit sweater"
/>
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-m">Home</span>
<p class="wa-caption-m">Cozy up on the couch and relax in soft cotton.</p>
</div>
</wa-card>
</a>
<a href="" class="wa-link-plain">
<wa-card style="height: 100%">
<img
slot="image"
src="https://img.fortawesome.com/cfa83f3c/fitness.jpg"
alt="Athlete training in fitted active wear tee and shorts"
/>
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-m">Active</span>
<p class="wa-caption-m">Get fit in style with breathable poly blends.</p>
</div>
</wa-card>
</a>
</div>
</div>
```
## Square Image Grid
```html {.example}
<div class="wa-stack wa-gap-2xl">
<div class="wa-stack wa-gap-xs wa-align-items-center">
<h2 class="wa-heading-xl">New Arrivals</h2>
<p class="wa-caption-l">Explore brand new furniture to accentuate your home aesthetic &mdash; just for you.</p>
</div>
<div class="wa-grid">
<div class="wa-stack">
<div class="wa-frame wa-border-radius-m">
<img
src="https://uploads.webawesome.com/indoor-furniture.jpg"
alt="Sunny room with a mid-century modern couch, accent chair, and elegant lamp"
/>
</div>
<wa-button appearance="outlined">View Indoor Furniture</wa-button>
</div>
<div class="wa-stack">
<div class="wa-frame wa-border-radius-m">
<img
src="https://uploads.webawesome.com/outdoor-furniture.jpg"
alt="Covered patio with rustic wooden cabinets, writing desk, and stool"
/>
</div>
<wa-button appearance="outlined">View Outdoor Furniture</wa-button>
</div>
</div>
</div>
```

View File

@@ -0,0 +1,246 @@
---
title: Checkout Form
description: 'Let shoppers checkout with ease with streamlined forms to capture shipping and payment info.'
parent: ecommerce
tags: e-commerce
---
## Full Form with Order Summary Card
```html {.example}
<div class="wa-grid wa-gap-3xl">
<div class="wa-stack">
<h4>Contact</h4>
<wa-input type="email" label="Email Address"></wa-input>
<wa-divider></wa-divider>
<h4>Shipping</h4>
<wa-select label="Country" value="us">
<wa-option value="ca">Canada</wa-option>
<wa-option value="mx">Mexico</wa-option>
<wa-option value="us">United States</wa-option>
</wa-select>
<div class="wa-grid">
<wa-input label="First Name"></wa-input>
<wa-input label="Last Name"></wa-input>
</div>
<wa-input label="Company"></wa-input>
<wa-input label="Address"></wa-input>
<div class="wa-grid" style="--min-column-size: 10ch;">
<wa-input label="City"></wa-input>
<wa-input label="State"></wa-input>
<wa-input label="Postal Code"></wa-input>
</div>
<wa-input label="Phone"></wa-input>
<wa-divider></wa-divider>
<wa-radio-group label="Shipping Method" name="shipping-method" value="standard" orientation="horizontal">
<wa-radio value="standard" hint="7-10 business days">Standard</wa-radio>
<wa-radio value="express" hint="2-5 business days">Express</wa-radio>
</wa-radio-group>
<wa-divider></wa-divider>
<h4>Payment</h4>
<wa-radio-group label="Payment Method" name="payment-method" value="credit" orientation="horizontal">
<wa-radio value="credit">Credit Card</wa-radio>
<wa-radio value="paypal">Paypal</wa-radio>
</wa-radio-group>
<wa-input label="Card Number"></wa-input>
<wa-input label="Name on Card"></wa-input>
<div class="wa-grid">
<wa-input label="Expiration Date" placeholder="MM/YY"></wa-input>
<wa-input label="CVC"></wa-input>
</div>
</div>
<div class="wa-stack">
<h4>Order Summary</h4>
<wa-card>
<div class="wa-stack">
<div class="wa-flank wa-align-items-start" style="--flank-size: 7rem">
<div class="wa-frame wa-border-radius-s">
<img src="https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDM1MzB8&ixlib=rb-4.0.3&q=80&w=1080" alt="">
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-split">
<span class="wa-heading-s">Dolce Runners</span>
<wa-icon-button name="trash" label="Remove from cart"></wa-icon-button>
</div>
<span class="wa-caption-m">Cream/Seafoam</span>
<span class="wa-caption-m">12.5</span>
<div class="wa-split">
<span>$135.00</span>
<wa-select value="1" size="small" style="max-width: 8ch">
<wa-option value="1">1</wa-option>
<wa-option value="2">2</wa-option>
<wa-option value="3">3</wa-option>
</wa-select>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-align-items-start" style="--flank-size: 7rem">
<div class="wa-frame wa-border-radius-s">
<img src="https://images.unsplash.com/photo-1514989940723-e8e51635b782?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDM1Njh8&ixlib=rb-4.0.3&q=80&w=1080" alt="">
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-split">
<span class="wa-heading-s">Dunk High</span>
<wa-icon-button name="trash" label="Remove from cart"></wa-icon-button>
</div>
<span class="wa-caption-m">Sand/Amber/Black</span>
<span class="wa-caption-m">12.5</span>
<div class="wa-split">
<span>$180.00</span>
<wa-select value="1" size="small" style="max-width: 8ch">
<wa-option value="1">1</wa-option>
<wa-option value="2">2</wa-option>
<wa-option value="3">3</wa-option>
</wa-select>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-align-items-start" style="--flank-size: 7rem">
<div class="wa-frame wa-border-radius-s">
<img src="https://images.unsplash.com/photo-1606107557195-0e29a4b5b4aa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDM2MTF8&ixlib=rb-4.0.3&q=80&w=1080" alt="">
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-split">
<span class="wa-heading-s">NB Runner</span>
<wa-icon-button name="trash" label="Remove from cart"></wa-icon-button>
</div>
<span class="wa-caption-m">Forrest Green</span>
<span class="wa-caption-m">12.5</span>
<div class="wa-split">
<span>$48.99</span>
<wa-select value="1" size="small" style="max-width: 8ch">
<wa-option value="1">1</wa-option>
<wa-option value="2">2</wa-option>
<wa-option value="3">3</wa-option>
</wa-select>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-stack">
<div class="wa-split wa-caption-m">
<span>Subtotal</span>
<span>$363.99</span>
</div>
<div class="wa-split wa-caption-m">
<span>Shipping</span>
<span>FREE</span>
</div>
<div class="wa-split wa-heading-m">
<span>Total</span>
<span>$363.99</span>
</div>
</div>
<wa-divider></wa-divider>
<wa-button variant="brand">Confirm Order</wa-button>
</div>
</wa-card>
</div>
</div>
```
## Short Form with Order Summary
```html {.example}
<div class="wa-grid wa-gap-3xl">
<div class="wa-stack wa-gap-xl">
<h2>Payment</h2>
<wa-input type="email" label="Email" placeholder="ex. tanderson@metacortex.com">
<wa-icon slot="prefix" name="envelope"></wa-icon>
</wa-input>
<wa-input label="Card Number" placeholder="1234 1234 1234 1234">
<wa-icon slot="prefix" name="credit-card"></wa-icon>
</wa-input>
<div class="wa-grid" style="--min-column-size: 12ch">
<wa-input label="Expiration" placeholder="MM/YY">
<wa-icon slot="prefix" name="calendar"></wa-icon>
</wa-input>
<wa-input label="CVC" placeholder="CVC">
<wa-icon slot="prefix" name="lock"></wa-icon>
</wa-input>
</div>
<wa-input label="Cardholder Name" placeholder="Thomas Anderson">
<wa-icon slot="prefix" name="user"></wa-icon>
</wa-input>
<div class="wa-grid" style="--min-column-size: 12ch">
<wa-select label="Country" value="us">
<wa-icon slot="prefix" name="globe"></wa-icon>
<wa-option value="ca">Canada</wa-option>
<wa-option value="us">United States</wa-option>
<wa-option value="mx">Mexico</wa-option>
</wa-select>
<wa-input label="ZIP" placeholder="12345">
<wa-icon slot="prefix" name="location-dot"></wa-icon>
</wa-input>
</div>
<wa-switch checked>Sign me up for more offers from this store</wa-switch>
<wa-button variant="brand">Pay Now</wa-button>
</div>
<div class="wa-stack wa-gap-xl">
<h2>Order Summary</h2>
<div class="wa-split">
<div class="wa-cluster">
<div class="wa-frame wa-border-radius-m" style="max-width: 4rem">
<img src="https://images.unsplash.com/photo-1618677366787-9727aacca7ea?q=80&w=3255&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Glasses with black wire frames and dark tinted, circular lenses (Photograph by Colin Lloyd)">
</div>
<strong>Morpheus</strong>
</div>
<div class="wa-cluster">
<wa-input type="number" value="1" style="max-width: 5rem"></wa-input>
<span>$120.00</span>
</div>
</div>
<div class="wa-split">
<div class="wa-cluster">
<div class="wa-frame wa-border-radius-m" style="max-width: 4rem">
<img src="https://images.unsplash.com/photo-1511499767150-a48a237f0083?q=80&w=3558&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Glasses with rose gold wire frames and green tinted, circular lenses (Photograph by Charles Deluvio)">
</div>
<div class="wa-stack wa-gap-3xs">
<strong>Seraph</strong>
<em class="wa-caption-m">Tinted</em>
</div>
</div>
<div class="wa-cluster">
<wa-input type="number" value="1" style="max-width: 5rem"></wa-input>
<span>$180.00</span>
</div>
</div>
<div class="wa-split">
<div class="wa-cluster">
<div class="wa-frame wa-border-radius-m" style="max-width: 4rem">
<img src="https://images.unsplash.com/photo-1547104442-a40f335740cb?q=80&w=3348&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Glasses with tortoise shell half frames and large, rounded lenses (Photograph by Sincerely Media)">
</div>
<div class="wa-stack wa-gap-3xs">
<strong>Keymaker</strong>
<em class="wa-caption-m">Glossy</em>
</div>
</div>
<div class="wa-cluster">
<wa-input type="number" value="1" style="max-width: 5rem"></wa-input>
<span>$50.00</span>
</div>
</div>
<div class="wa-flank:end">
<wa-input placeholder="Discount code or gift card"></wa-input>
<wa-button appearance="filled">Apply</wa-button>
</div>
<div class="wa-stack wa-gap-s">
<div class="wa-split">
<span>Subtotal</span>
<strong>$530.00</strong>
</div>
<div class="wa-split">
<span>Shipping</span>
<span>$8.00</span>
</div>
<div class="wa-split">
<strong>Total</strong>
<strong>$538.00</strong>
</div>
</div>
</div>
</div>
```

View File

@@ -0,0 +1,125 @@
---
title: Incentives
description: 'Encourage shoppers to buy your products with value propositions, discounts, and promotions.'
parent: ecommerce
tags: e-commerce
---
## 3 Column
```html{.example}
<div class="wa-gap-3xl wa-stack" style="max-width: 960px; margin: 0 auto;">
<div class="wa-align-items-center wa-grid">
<div>
<span class="wa-heading-xl">Get the Best Instruction from our Educators.</span>
<p class="wa-caption-l">At the beginning at least, but then we realized we could make a lot more money if we kinda stopped caring about that. Our new strategy is to write a bunch of things that look really good in the headlines, then clarify in the small print but hope people don't actually read it.</p>
</div>
<div class="wa-frame wa-border-radius-l">
<img src="https://uploads.webawesome.com/online-learning.jpg" />
</div>
</div>
<div class="wa-grid">
<div class="wa-stack wa-gap-xs">
<wa-icon name="stopwatch" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Learn at your Speed</span>
<p class="wa-caption-m">It's not actually free we just price it into the products. Someone's paying for it, and it's not us.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="chart-line" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Track Progress</span>
<p class="wa-caption-m">If it breaks in the first 10 years we'll replace it. After that you're on your own though.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="people-group" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Active Community</span>
<p class="wa-caption-m">If you don't like it, trade it to one of your friends for something of theirs. Don't send it here though.</p>
</div>
</div>
</div>
```
## 2 Column with Cards
```html{.example}
<div class="wa-grid" style="--min-column-size: 41ch;">
<wa-card>
<div class="wa-flank">
<div>
<wa-icon name="hands" style="font-size: 2.5rem;"></wa-icon>
</div>
<div class="wa-gap-s wa-stack">
<span class="wa-heading-m">Hands-on training</span>
<p class="wa-caption-l">Upskill effectively with AI-powered coding exercises, practice tests, and quizzes.</p>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<div>
<wa-icon name="medal" style="font-size: 2.5rem;"></wa-icon>
</div>
<div class="wa-gap-s wa-stack">
<span class="wa-heading-m">Certification prep</span>
<p class="wa-caption-l">Prep for industry-recognized certifications by solving real-world challenges and earn badges along the way</p>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<div>
<wa-icon name="chart-line" style="font-size: 2.5rem;"></wa-icon>
</div>
<div class="wa-gap-s wa-stack">
<div class="wa-split wa-gap-2xs">
<span class="wa-heading-m">Insights and analytics</span>
<wa-badge appearance="filled outlined" variant="warning">Pro Plan</wa-badge>
</div>
<p class="wa-caption-l">Fast-track goals with advanced insights plus a dedicated customer success team to help drive effective learning.</p>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank">
<div>
<wa-icon name="puzzle-piece" style="font-size: 2.5rem;"></wa-icon>
</div>
<div class="wa-gap-s wa-stack">
<div class="wa-split wa-gap-2xs">
<span class="wa-heading-m">Customizable content</span>
<wa-badge appearance="filled outlined" variant="warning">Pro Plan</wa-badge>
</div>
<p class="wa-caption-l">Create tailored learning paths for team and organization goals and even host your own content and resources.</p>
</div>
</div>
</wa-card>
</div>
```
## 4 Column
```html{.example}
<div>
<div class="wa-grid">
<div class="wa-stack wa-gap-xs">
<wa-icon name="magnifying-glass" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">SEO Consulting</span>
<p class="wa-caption-m">It's not actually free we just price it into the products. Someone's paying for it, and it's not us.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="chalkboard-user" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">In Person Training</span>
<p class="wa-caption-m">If it breaks in the first 10 years we'll replace it. After that you're on your own though.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="people-arrows" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">1 on 1 Sessions</span>
<p class="wa-caption-m">If you don't like it, trade it to one of your friends for something of theirs. Don't send it here though.</p>
</div>
<div class="wa-stack wa-gap-xs">
<wa-icon name="code" style="font-size: 32px;"></wa-icon>
<span class="wa-heading-s">Web Development</span>
<p class="wa-caption-m">If you don't like it, trade it to one of your friends for something of theirs. Don't send it here though.</p>
</div>
</div>
</div>
```

View File

@@ -1,14 +1,190 @@
---
title: Order History
description: TODO
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
parent: ecommerce
tags: e-commerce
---
TODO Page Description
## Invoice panels
```html{.example}
## List
```html {.example}
<div class="wa-stack wa-gap-2xl">
<h2>Order History</h2>
<p class="wa-caption-m">Check the status of recent orders, manage returns, and download invoices.</p>
<dl class="wa-split">
<span class="wa-stack wa-gap-0">
<dt>Order number</dt>
<dd>WU88191111</dd>
</span>
<span class="wa-stack wa-gap-0">
<dt>Date placed</dt>
<dd>January 22, 2021</dd>
</span>
<span class="wa-stack wa-gap-0">
<dt>Total amount</dt>
<dd>$590.00</dd>
</span>
<span class="wa-cluster">
<wa-button variant="neutral" appearance="outlined">View Order</wa-button>
<wa-button variant="neutral" appearance="outlined">View Invoice</wa-button>
</span>
</dl>
<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
src="https://img.fortawesome.com/cfa83f3c/light-fixtures.jpg"
alt=""
/>
</div>
<div class="wa-stack">
<div class="wa-split">
<span><strong>Dome Light Fixtures</strong></span>
<span><strong>$215.00</strong></span>
</div>
<p class="wa-caption-m">Illuminate your space with elegance and style with stunning Dome Light Fixtures. The shape of these lights complements both modern and traditional interiors.</p>
<div class="wa-split">
<wa-badge appearance="filled" variant="success">Delivered</wa-badge>
<div class="wa-cluster">
<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>
<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
src="https://img.fortawesome.com/cfa83f3c/modern-chair.jpg"
alt=""
/>
</div>
<div class="wa-stack">
<div class="wa-split">
<span><strong>Reading Chair</strong></span>
<span><strong>$115.00</strong></span>
</div>
<p class="wa-caption-m">Add a pop of color and a touch of elegance to any room with our Reading Chair featuring vibrant yellow fabric upholstery.</p>
<div class="wa-split">
<wa-badge appearance="filled" variant="brand">Out for delivery</wa-badge>
<div class="wa-cluster">
<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>
<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
src="https://img.fortawesome.com/cfa83f3c/sofa.jpg"
alt=""
/>
</div>
<div class="wa-stack">
<div class="wa-split">
<span><strong>Custom Sofa</strong></span>
<span><strong>$260.00</strong></span>
</div>
<p class="wa-caption-m">Experience luxury and comfort like never before with our Custom Sofa, designed to elevate any living space. This sofa features exquisite velvet upholstery for an air of sophistication.</p>
<div class="wa-split">
<wa-badge appearance="filled" variant="neutral">Preparing to ship</wa-badge>
<div class="wa-cluster">
<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>
```
## Invoice Table
```html {.example}
<div class="wa-stack wa-gap-2xl">
<wa-callout appearance="filled" variant="neutral">
<div class="wa-flank:end wa-align-items-center">
<dl class="wa-grid">
<div class="wa-stack wa-gap-0">
<dt>Date Placed</dt>
<dd>
<wa-format-date date="2021-01-22" month="long" day="numeric" year="numeric"></wa-format-date>
</dd>
</div>
<div class="wa-stack wa-gap-0">
<dt>Order Number</dt>
<dd>WU88191111</dd>
</div>
<div class="wa-stack wa-gap-0">
<dt>Total Amount</dt>
<dd>$590.00</dd>
</div>
</dl>
<wa-button>View Invoice</wa-button>
</div>
</wa-callout>
<table>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Status</th>
<th>Info</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="wa-cluster wa-align-items-start">
<div class="wa-frame:landscape wa-border-radius-s" style="max-width: 8rem">
<img
src="https://img.fortawesome.com/cfa83f3c/light-fixtures.jpg"
alt=""
/>
</div>
<span>Dome Light Fixtures</span>
</div>
</td>
<td>$215.00</td>
<td>Delivered Jan 25, 2021</td>
<td><a href="">View</a></td>
</tr>
<tr>
<td>
<div class="wa-cluster wa-align-items-start">
<div class="wa-frame:landscape wa-border-radius-s" style="max-width: 8rem">
<img
src="https://img.fortawesome.com/cfa83f3c/modern-chair.jpg"
alt=""
/>
</div>
<span>Reading Chair</span>
</div>
</td>
<td>$115.00</td>
<td>Delivered Jan 25, 2021</td>
<td><a href="">View</a></td>
</tr>
<tr>
<td>
<div class="wa-cluster wa-align-items-start">
<div class="wa-frame:landscape wa-border-radius-s" style="max-width: 8rem">
<img
src="https://img.fortawesome.com/cfa83f3c/sofa.jpg"
alt=""
/>
</div>
<span>Custom Sofa</span>
</div>
</td>
<td>$260.00</td>
<td>Delivered Jan 25, 2021</td>
<td><a href="">View</a></td>
</tr>
</tbody>
</table>
</div>
```

View File

@@ -1,13 +1,296 @@
---
title: Product List
description: TODO
title: Order Summary
description: 'Give shoppers confidence in their purchases with summaries of everything included in their order.'
parent: ecommerce
tags: e-commerce
---
TODO Page Description
## With split image
```html{.example}
## Simple
```html {.example}
<div class="wa-stack wa-gap-xl">
<wa-callout variant="success">
<em>Payment Successful</em>
<wa-icon slot="icon" name="circle-check"></wa-icon>
</wa-callout>
<wa-card>
<div class="wa-stack wa-gap-xl">
<h2>Thank you for ordering from us!</h2>
<p class="wa-caption-l">We're processing your order now. A confirmation email will be sent to you momentarily!</p>
<dl class="wa-cluster">
<dt>Order #</dt>
<dd>49548790-24545</dd>
</dl>
<wa-divider></wa-divider>
<div class="wa-flank:end wa-align-items-start wa-gap-xl" style="--flank-size: 14em">
<div class="wa-stack wa-gap-xl">
<ul class="wa-stack wa-gap-xl">
<li class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
src="https://uploads.webawesome.com/vase-1.jpg"
alt=""
/>
</div>
<div class="wa-split">
<span class="wa-heading-s">Spotted Flower Pot</span>
<span>$75.00</span>
</div>
</li>
<wa-divider></wa-divider>
<li class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
src="https://uploads.webawesome.com/decorative-vase.jpg"
alt=""
/>
</div>
<div class="wa-split">
<span class="wa-heading-s">Decorative Vase</span>
<span>$51.00</span>
</div>
</li>
</ul>
<wa-divider></wa-divider>
<dl class="wa-stack wap-gap-2xs wa-caption-l">
<div class="wa-split">
<dt>Subtotal</dt>
<dd>$126.00</dd>
</div>
<div class="wa-split">
<dt>Shipping</dt>
<dd>$8.00</dd>
</div>
<div class="wa-split">
<dt>Taxes</dt>
<dd>$6.40</dd>
</div>
<div class="wa-split">
<dt>Total</dt>
<dd>$140.40</dd>
</div>
</dl>
</div>
<wa-callout variant="neutral" appearance="filled">
<dl class="wa-stack" style="margin: 0">
<dt>Shipping Address</dt>
<dd>
<address class="wa-stack wa-gap-2xs">
<span>Donna Noble</span>
<span>56 Front Street</span>
<span>Las Cruces, NM 56929</span>
</address>
</dd>
<dt>Payment Information</dt>
<dd class="wa-flank wa-gap-s">
<wa-icon label="Visa" class="wa-body-xl" family="brands" name="cc-visa" style="color: #224DBA;"></wa-icon>
<span>Ending with 9065</span>
</dd>
</dl>
</wa-callout>
</div>
</div>
</wa-card>
<wa-button size="large" variant="brand" appearance="plain">
<wa-icon slot="suffix" name="arrow-right" variant="solid"></wa-icon>
Continue Shopping
</wa-button>
</div>
```
## With Details
```html {.example}
<div class="wa-stack">
<h2>Order Details</h2>
<div class="wa-split">
<div class="wa-cluster">
<span>Order placed <wa-format-date date="2025-02-26T09:00:00-04:00" month="long" day="numeric" year="numeric"></wa-format-date></span>
<wa-divider vertical style="height: 2em"></wa-divider>
<span>Order # 45646456-4656-4542</span>
</div>
<wa-button size="small" appearance="outlined" pill>View Invoice</wa-button>
</div>
<wa-card>
<div class="wa-split wa-align-items-start">
<div class="wa-stack">
<h3 class="wa-heading-s">Shipping Address</h3>
<address class="wa-stack wa-gap-xs wa-caption-m">
<span>Johnny Blaze</span>
<span>200 Park Avenue</span>
<span>Manhattan, NY 45789-3412</span>
<span>United States</span>
</address>
<wa-button size="small" appearance="outlined" pill>Change</wa-button>
</div>
<div class="wa-stack">
<h3 class="wa-heading-s">Payment Method</h3>
<div class="wa-flank wa-gap-s">
<wa-icon class="wa-body-xl" family="brands" name="cc-visa" style="color: #224DBA;"></wa-icon>
<span class="wa-caption-m">Visa ending in 9542</span>
</div>
</div>
<div class="wa-stack">
<h3 class="wa-heading-s">Order Summary</h3>
<dl class="wa-stack wa-gap-xs wa-caption-m">
<div class="wa-split">
<dt>Item(s) Subtotal</dt>
<dd>$39.00</dd>
</div>
<div class="wa-split">
<dt>Shipping & Handling</dt>
<dd>$0.00</dd>
</div>
<div class="wa-split">
<dt>Pre-tax Total</dt>
<dd>$39.00</dd>
</div>
<div class="wa-split">
<dt>Tax</dt>
<dd>$39.00</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-split wa-body-m">
<dt>Grand Total</dt>
<dd>$39.00</dd>
</div>
</dl>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank:end wa-align-items-start" style="--flank-size: 12rem">
<div class="wa-stack">
<h3 class="wa-heading-s">Arriving Saturday</h3>
<div class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
src="https://uploads.webawesome.com/sparkling-water.jpg"
alt=""
/>
</div>
<div class="wa-stack">
<a href="" class="wa-caption-m">Mineragua Sparkling Water 12 Count</a>
<span class="wa-caption-s">Sold by: <a href="">Mineragua</a></span>
<div class="wa-cluster">
<span class="wa-heading-s">$39.00</span>
<wa-button appearance="outlined" size="small" pill>
<wa-icon slot="prefix" name="rotate" variant="solid"></wa-icon>
Buy Again
</wa-button>
</div>
</div>
</div>
</div>
<div class="wa-stack wa-gap-xs">
<wa-button size="small" variant="brand" pill>Track Package</wa-button>
<wa-button size="small" appearance="outlined" variant="neutral" pill>Cancel Item(s)</wa-button>
<wa-button size="small" appearance="outlined" variant="neutral" pill>Ask Question</wa-button>
<wa-button size="small" appearance="outlined" variant="neutral" pill>Write Review</wa-button>
</div>
</div>
</wa-card>
</div>
```
## With Status & Description
```html {.example}
<div class="wa-stack wa-gap-xl">
<div class="wa-split">
<div class="wa-cluster">
<h2>Order #7093</h2>
<a href="">View Invoice</a>
</div>
<p class="wa-caption-m">Order placed <wa-format-date date="2025-06-12T09:00:00-04:00" month="long" day="numeric" year="numeric"></wa-format-date></p>
</div>
<wa-card>
<div class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
src="https://uploads.webawesome.com/vase-1.jpg"
alt=""
/>
</div>
<div class="wa-stack wa-align-items-start wa-gap-s">
<div class="wa-split wa-gap-s">
<h3 class="wa-heading-m">Spotted Flower Pot</h3>
<span>$75.00</span>
</div>
<p class="wa-caption-m">Wood fired, salt glaze</p>
<wa-tag variant="success" appearance="filled" size="small">Delivered</wa-tag>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
src="https://uploads.webawesome.com/decorative-vase.jpg"
alt=""
/>
</div>
<div class="wa-stack wa-align-items-start wa-gap-s">
<div class="wa-split wa-gap-s">
<h3 class="wa-heading-m">Decorative Vase</h3>
<span>$51.00</span>
</div>
<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>
</wa-card>
<wa-card>
<div class="wa-flank wa-align-items-start">
<div class="wa-frame wa-border-radius-s">
<img
src="https://uploads.webawesome.com/cuong-duyen-ceramic.jpg"
alt=""
/>
</div>
<div class="wa-stack wa-align-items-start wa-gap-s">
<div class="wa-split wa-gap-s">
<h3 class="wa-heading-m">Cuong Duyen Ceramic</h3>
<span>$48.00</span>
</div>
<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>
</wa-card>
<wa-divider></wa-divider>
<wa-callout variant="neutral" appearance="filled">
<div class="wa-grid">
<div class="wa-stack">
<h3 class="wa-heading-s">Shipping Address</h3>
<address class="wa-stack wa-gap-xs wa-caption-m">
<span>Donna Noble</span>
<span>56 Front Street</span>
<span>Las Cruces, NM 56929</span>
</address>
</div>
<div class="wa-stack">
<h3 class="wa-heading-s">Order Summary</h3>
<dl class="wa-stack wa-gap-xs wa-caption-m">
<div class="wa-split">
<dt>Item(s) Subtotal</dt>
<dd>$174.00</dd>
</div>
<div class="wa-split">
<dt>Shipping & Handling</dt>
<dd>$0.00</dd>
</div>
<div class="wa-split">
<dt>Tax</dt>
<dd>$17.40</dd>
</div>
<wa-divider></wa-divider>
<div class="wa-split wa-body-m">
<dt>Total</dt>
<dd>$191.40</dd>
</div>
</dl>
</div>
</div>
</wa-callout>
</div>
```

View File

@@ -1,129 +0,0 @@
---
title: Product Detail
description: TODO
parent: ecommerce
tags: e-commerce
---
TODO Page Description
## With color and size selector
```html{.example}
<div class="with-inline-price">
<wa-card with-header>
<div class="card-header" slot="header">
<span class="card-title">Graphic Tank</span>
<wa-icon-button name="close" label="close-modal"></wa-icon-button>
</div>
<div class="card-body">
<img style="border-radius: var(--border-radius)" src="/assets/images/patterns/gervyn-louis-IS03ajI00Fc-unsplash.jpg" />
<form class="detail">
<span class="price">$32</span>
<span class="rating"><wa-rating></wa-rating><a style="margin-left: .5rem; " href="*">36 Reviews</a></span>
<wa-radio-group style="margin-bottom: 1rem;" label="Select an option" name="a" value="1">
<wa-radio-button value="Black">Black</wa-radio-button>
<wa-radio-button value="White">White</wa-radio-button>
<wa-radio-button value="Gray">Gray</wa-radio-button>
</wa-radio-group>
<wa-select label="Sizes" placeholder="select size">
<wa-option value="option-1">Option 1</wa-option>
<wa-option value="option-2">Option 2</wa-option>
<wa-option value="option-3">Option 3</wa-option>
</wa-select>
<wa-button size="medium" style="width: 100%; margin-top: auto;">Medium</wa-button>
</form>
</div>
</wa-card>
</div>
<style>
.with-inline-price {
wa-card {
width: 100%;
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
.card-title {
font-size: large;
font-weight: 600;
}
}
.card-body {
display: grid;
grid-template-columns: 35% 1fr;
gap: 1rem;
.detail {
display: flex;
flex-direction: column;
.price {
font-size: xx-large;
font-weight: 600;
}
.rating {
margin-bottom: 1rem;
}
}
}
}
}
</style>
```
## with large selector
```html{.example}
<wa-card class="large-selector">
<div class="card-body">
<div style="grid-column: 1/6">
<img style="border-radius: var(--border-radius); height: 100%; object-fit: cover;" src="/assets/images/patterns/gervyn-louis-IS03ajI00Fc-unsplash.jpg" />
</div>
<div style="grid-column: 6/-1" class="info">
<h2>Basic Tank</h2>
<wa-icon-button name="close" label="close-modal"></wa-icon-button>
<section>
<p style="font-size: x-large;font-weight: 600;">$32</p>
<div style="display: flex; align-items: flex-start">
<p>3.9</p>
<wa-rating></wa-rating>
<a href="*" style="margin-left: auto;">See all 512 Reviews</a>
</div>
</section>
<section>
<form>
<wa-radio-group label="Color" hint="Choose the most appropriate option." name="a" value="black" style="margin-bottom: 1rem;">
<wa-radio value="black">Black</wa-radio>
<wa-radio value="gray">Gray</wa-radio>
</wa-radio-group>
<wa-radio-group label="Size" hint="Select an option that makes you proud." name="a" value="medium" style="margin-bottom: 1rem;">
<wa-radio-button value="small">S</wa-radio-button>
<wa-radio-button value="medium">M</wa-radio-button>
<wa-radio-button value="large">L</wa-radio-button>
<wa-radio-button value="extra-large">XL</wa-radio-button>
</wa-radio-group>
<wa-button size="medium" style="width: 100%; margin-top: auto;margin-bottom: 1rem;">Medium</wa-button>
<a href="*" style="display: inline-block;width: 100%;text-align: center;">View full details</a>
</form>
</section>
</div>
</div>
</wa-card>
<style>
.large-selector .card-body {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
.info {
position: relative;
wa-icon-button {
position: absolute;
top: 0;
right: 0;
}
}
}
</style>
```

View File

@@ -1,166 +1,184 @@
---
title: Product Lists
description: TODO
description: 'Let shoppers browse and compare products with detailed lists of the products in your store.'
parent: ecommerce
tags: e-commerce
---
TODO Page Description
## With Product Grid
## Simple Grid with Ratings
```html{.example}
<div class="with-product-grid">
<div class="grid-item">
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div class="grid-item-name">Shirt</div>
<wa-rating label="Rating" readonly value="3"></wa-rating>
<a class="grid-item-reviews" href="#">38 Reviews</a>
<div class="grid-item-price">$170</div>
```html {.example}
<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
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)"
/>
</div>
<div class="grid-item">
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div class="grid-item-name">Shirt</div>
<wa-rating label="Rating" readonly value="3"></wa-rating>
<a class="grid-item-reviews" href="#">38 Reviews</a>
<div class="grid-item-price">$170</div>
<strong>Basil</strong>
<wa-rating label="Rating" size="small" readonly value="5"></wa-rating>
<span class="wa-caption-m">41 Reviews</span>
<strong>$8.59</strong>
</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
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)"
/>
</div>
<div class="grid-item">
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div class="grid-item-name">Shirt</div>
<wa-rating label="Rating" readonly value="3"></wa-rating>
<a class="grid-item-reviews" href="#">38 Reviews</a>
<div class="grid-item-price">$170</div>
<strong>Chamomile</strong>
<wa-rating label="Rating" size="small" readonly value="3"></wa-rating>
<span class="wa-caption-m">17 Reviews</span>
<strong>$10.29</strong>
</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
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)"
/>
</div>
<div class="grid-item">
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div class="grid-item-name">Shirt</div>
<wa-rating label="Rating" readonly value="3"></wa-rating>
<a class="grid-item-reviews" href="#">38 Reviews</a>
<div class="grid-item-price">$170</div>
<strong>Lavender</strong>
<wa-rating label="Rating" size="small" readonly value="4"></wa-rating>
<span class="wa-caption-m">29 Reviews</span>
<strong>$9.99</strong>
</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
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)"
/>
</div>
<strong>Marjoram</strong>
<wa-rating label="Rating" size="small" readonly value="4"></wa-rating>
<span class="wa-caption-m">11 Reviews</span>
<strong>$8.59</strong>
</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
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)"
/>
</div>
<strong>Oregano</strong>
<wa-rating label="Rating" size="small" readonly value="5"></wa-rating>
<span class="wa-caption-m">38 Reviews</span>
<strong>$8.59</strong>
</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
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)"
/>
</div>
<strong>Peppermint</strong>
<wa-rating label="Rating" size="small" readonly value="5"></wa-rating>
<span class="wa-caption-m">26 Reviews</span>
<strong>$9.99</strong>
</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
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)"
/>
</div>
<strong>Rosemary</strong>
<wa-rating label="Rating" size="small" readonly value="4"></wa-rating>
<span class="wa-caption-m">34 Reviews</span>
<strong>$8.59</strong>
</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
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)"
/>
</div>
<strong>Sage</strong>
<wa-rating label="Rating" size="small" readonly value="5"></wa-rating>
<span class="wa-caption-m">24 Reviews</span>
<strong>$9.29</strong>
</a>
</div>
```
## Even Card Grid with Details
```html {.example}
<div class="wa-grid" style="--min-column-size: 50ch">
<div class="wa-grid">
<a href="" class="wa-link-plain">
<wa-card>
<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)"
/>
<div class="wa-stack">
<div class="wa-flank:end wa-align-items-start wa-heading-m">
<span>Plain Classic Tee</span>
<span>$24</span>
</div>
<p class="wa-caption-m">Keep it casual or dress it up. Soft, 100% cotton with a crew neckline, perfect for any occasion.</p>
<em class="wa-caption-m">8 colors</em>
</div>
</wa-card>
</a>
<a href="" class="wa-link-plain">
<wa-card>
<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)"
/>
<div class="wa-stack">
<div class="wa-flank:end wa-align-items-start wa-heading-m">
<span>One-color Graphic Tee</span>
<span>$32</span>
</div>
<p class="wa-caption-m">Your own spin on our classic tee. Hand screen printed for the ultimate accuracy and quality.</p>
<em class="wa-caption-m">6 colors</em>
</div>
</wa-card>
</a>
</div>
<style>
.with-product-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
border: var(--wa-panel-border-width) var(--wa-border-style) var(--wa-color-neutral-border-quiet);
.grid-item {
padding: 1.5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.grid-item:nth-of-type(odd) {
border-right: var(--wa-panel-border-width) var(--wa-border-style) var(--wa-color-neutral-border-quiet);
}
.grid-item:not(:nth-last-child(-n + 2)) {
border-bottom: var(--wa-panel-border-width) var(--wa-border-style) var(--wa-color-neutral-border-quiet);
}
.grid-item-image {
width: 100%;
object-fit: cover;
}
.grid-item-name {
margin-top: 1rem;
font-weight: var(--wa-font-weight-bold);
}
.grid-item wa-rating {
--symbol-size: var(--wa-font-size-m);
margin-top: .5rem;
}
.grid-item-reviews {
--wa-link-decoration-default: none;
--wa-color-text-link: var(--wa-color-gray-50);
font-size: var(--wa-font-size-m);
}
.grid-item-price {
font-size: var(--wa-font-size-2xl);
font-weight: var(--wa-font-weight-bold);
}
}
</style>
```
## Card with full details
```html{.example}
<div class="card-with-details">
<wa-card with-footer>
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div slot="footer" class="card-footer details">
<span class="detail-name">Basic Tee 8-pack</span>
<p class="detail-description">Get the full lineup of our Basic Tees. Have a fresh shirt all week, and an extra for laundry day.</p>
<span class="detail-color">8 colors</span>
<span class="detail-price">$256</span>
</div>
</wa-card>
<wa-card with-footer>
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div slot="footer" class="card-footer details">
<span class="detail-name">Basic Tee 8-pack</span>
<p class="detail-description">Get the full lineup of our Basic Tees. Have a fresh shirt all week, and an extra for laundry day.</p>
<span class="detail-color">8 colors</span>
<span class="detail-price">$256</span>
</div>
</wa-card>
<wa-card with-footer>
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div slot="footer" class="card-footer details">
<span class="detail-name">Basic Tee 8-pack</span>
<p class="detail-description">Get the full lineup of our Basic Tees. Have a fresh shirt all week, and an extra for laundry day.</p>
<span class="detail-color">8 colors</span>
<span class="detail-price">$256</span>
</div>
</wa-card>
<wa-card with-footer>
<img class="grid-item-image" src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
<div slot="footer" class="card-footer details">
<span class="detail-name">Basic Tee 8-pack</span>
<p class="detail-description">Get the full lineup of our Basic Tees. Have a fresh shirt all week, and an extra for laundry day.</p>
<span class="detail-color">8 colors</span>
<span class="detail-price">$256</span>
</div>
</wa-card>
<div class="wa-grid">
<a href="" class="wa-link-plain">
<wa-card>
<img slot="image"
src="https://images.unsplash.com/photo-1567098260939-5d9cee055592?q=80&w=2832&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Man in a black t-shirt printed with many-colored gradients (Photograph by Marcel)"
/>
<div class="wa-stack">
<div class="wa-flank:end wa-align-items-start wa-heading-m">
<span>Multi-color Graphic Tee</span>
<span>$36</span>
</div>
<p class="wa-caption-m">Make a statement. Screen printed with vibrant, quality inks to last wash after wash.</p>
<em class="wa-caption-m">4 colors</em>
</div>
</wa-card>
</a>
<a href="" class="wa-link-plain">
<wa-card>
<img slot="image"
src="https://images.unsplash.com/photo-1709185727063-c3caae752a64?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Woman in a black t-shirt with a bright white logo printed on the pocket (Photograph by SASI)"
/>
<div class="wa-stack">
<div class="wa-flank:end wa-align-items-start wa-heading-m">
<span>Pocket Graphic Tee</span>
<span>$29</span>
</div>
<p class="wa-caption-m">Go classic with a bit of your own flair. Screen printed, eye-catching detail on the pocket.</p>
<em class="wa-caption-m">6 colors</em>
</div>
</wa-card>
</a>
</div>
<style>
.card-with-details {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.card-with-details wa-card::part(body) {
padding: 0;
}
.card-with-details .card-footer {
display: flex;
flex-direction: column;
}
.details {
.detail-description {
color: var(--wa-color-gray-50);
}
.detail-name {
font-size: var(--wa-font-size-l);
font-weight: var(--wa-font-weight-action);
}
.detail-color {
color: var(--wa-color-gray-50);
font-style: italic;
}
.detail-price {
font-size: var(--wa-font-size-xl);
font-weight: var(--wa-font-weight-action);
}
}
</style>
```
## With color swatches (WIP)
```html{.example}
```
</div>
```

View File

@@ -0,0 +1,431 @@
---
title: Product Overview
description: 'Showcase your products with overviews including images, ratings, features, options, and more.'
parent: ecommerce
tags: e-commerce
---
## Split with Image
```html {.example}
<div class="wa-grid wa-gap-2xl">
<div class="wa-stack wa-gap-2xl">
<h2>San Ignacio Pache</h2>
<p>A smooth, balanced Arabica varietal, grown and roasted on the Guerrero family's farm. Rich caramel and malt flavors blend with bright citrus for a complex brew suitable for drip, pour over, espresso, or however you take your coffee.</p>
<div class="wa-stack">
<wa-select label="Bag Size" value="12oz">
<wa-option value="12oz">12 oz &ndash; $19.95</wa-option>
<wa-option value="3lb">3 lb &ndash; $72.00</wa-option>
<wa-option value="5lb">5 lb &ndash; $99.75</wa-option>
</wa-select>
<wa-select label="Bean Type" value="whole">
<wa-option value="whole">Whole</wa-option>
<wa-option value="drip">Drip Grind</wa-option>
<wa-option value="espresso">Espresso Grind</wa-option>
</wa-select>
</div>
<div class="wa-stack">
<div class="wa-flank">
<wa-input type="number" aria-label="Quantity" value="1" min="1" style="max-width: 8ch"></wa-input>
<wa-button variant="brand">
<wa-icon slot="prefix" name="basket-shopping"></wa-icon>
Add to Basket
</wa-button>
</div>
<div class="wa-flank wa-caption-m">
<wa-icon name="truck"></wa-icon>
<span>Free shipping on orders over $60</span>
</div>
</div>
<dl class="wa-grid">
<div class="wa-flank">
<wa-avatar>
<wa-icon slot="icon" name="coffee-bean"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-0">
<dt>Roast</dt>
<dd>Medium</dd>
</div>
</div>
<div class="wa-flank">
<wa-avatar>
<wa-icon slot="icon" name="earth-americas"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-0">
<dt>Origin</dt>
<dd>San Ignacio, Peru</dd>
</div>
</div>
<div class="wa-flank">
<wa-avatar>
<wa-icon slot="icon" name="sun-haze"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-0">
<dt>Process</dt>
<dd>Washed</dd>
</div>
</div>
<div class="wa-flank">
<wa-avatar>
<wa-icon slot="icon" name="mug-hot"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-0">
<dt>Tasting Notes</dt>
<dd>Caramel, malt, orange</dd>
</div>
</div>
</dl>
</div>
<div class="wa-frame wa-border-radius-m">
<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)"
/>
</div>
</div>
```
## With Image Grid
```html {.example}
<div class="wa-stack wa-gap-2xl">
<wa-breadcrumb>
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
<wa-breadcrumb-item>Women's</wa-breadcrumb-item>
<wa-breadcrumb-item>Shirts &amp; Tops</wa-breadcrumb-item>
</wa-breadcrumb>
<div class="wa-grid wa-gap-xs" style="--min-column-size: 10ch">
<div class="wa-frame" style="height: 100%; width: 100%">
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1614792568992-ded1c487c1dd?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Patrick Perkins)"
/>
</div>
<div class="wa-grid wa-gap-xs">
<div class="wa-frame" style="aspect-ratio: 3 / 2">
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1614725078749-29c421fd0e51?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Patrick Perkins)"
/>
</div>
<div class="wa-frame" style="aspect-ratio: 3 / 2">
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1614725808713-e6bbe418fc5d?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Patrick Perkins)"
/>
</div>
</div>
<div class="wa-frame" style="height: 100%; width: 100%">
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1614725078379-9d1330a08c95?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Patrick Perkins)"
/>
</div>
</div>
<div class="wa-grid wa-gap-xl" style="--min-column-size: 30ch">
<h2 class="wa-heading-l">Cropped Fitted Tank Top</h2>
<span class="wa-body-xl">$59</span>
</div>
<div class="wa-grid wa-gap-xl" style="--min-column-size: 30ch">
<div class="wa-stack wa-gap-xl">
<div class="wa-cluster">
<wa-rating label="Rating" readonly value="3.5"></wa-rating>
<a href="">117 Reviews</a>
</div>
<p>Made with a breathable, stretchy fabric blend for unparalleled comfort and flattering style. Pairs perfectly with your favorite high-waisted jeans for lazy summer weekends or lively nights out.</p>
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-xs">Good to Know</h3>
<p class="wa-body-xs">95% cotton, 5% elastane. Our tops are pre-shrunk to ensure a consistent fit with no surprises. Machine wash cold. Tumble dry low.</p>
</div>
</div>
<div class="wa-stack">
<wa-radio-group label="Color" name="color" value="black" orientation="horizontal">
<wa-radio-button id="radio-black" value="black">
<wa-icon name="square" label="Black" style="color: black;"></wa-icon>
<wa-tooltip for="radio-black">Black</wa-tooltip>
</wa-radio-button>
<wa-radio-button id="radio-gray" value="gray">
<wa-icon name="square" label="Gray" style="color: gray;"></wa-icon>
<wa-tooltip for="radio-gray">Gray</wa-tooltip>
</wa-radio-button>
<wa-radio-button id="radio-indigo" value="indigo">
<wa-icon name="square" label="Indigo" style="color: indigo;"></wa-icon>
<wa-tooltip for="radio-indigo">Indigo</wa-tooltip>
</wa-radio-button>
<wa-radio-button id="radio-olive" value="olive">
<wa-icon name="square" label="Olive" style="color: olive;"></wa-icon>
<wa-tooltip for="radio-olive">Olive</wa-tooltip>
</wa-radio-button>
</wa-radio-group>
<wa-radio-group label="Size" name="size" value="s" orientation="horizontal">
<wa-radio-button value="xs">XS</wa-radio-button>
<wa-radio-button value="s">S</wa-radio-button>
<wa-radio-button value="m">M</wa-radio-button>
<wa-radio-button value="l">L</wa-radio-button>
<wa-radio-button value="xl">XL</wa-radio-button>
</wa-radio-group>
<wa-button variant="brand">
<wa-icon slot="prefix" name="cart-plus" variant="solid"></wa-icon>
Add to Cart
</wa-button>
</div>
</div>
</div>
```
## With Tiered Images
```html {.example}
<div class="wa-stack wa-gap-2xl">
<wa-breadcrumb>
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
<wa-breadcrumb-item>Men's</wa-breadcrumb-item>
<wa-breadcrumb-item>Shirts &amp; Tops</wa-breadcrumb-item>
</wa-breadcrumb>
<div class="wa-grid wa-gap-2xl" style="--min-column-size: 35ch">
<div class="wa-stack wa-gap-xs">
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1630643583573-c68623718072?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Gervyn Louis)"
/>
<div class="wa-grid wa-gap-xs" style="--min-column-size: 0ch">
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1571666274590-f8cc87006500?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Gervyn Louis)"
/>
<img class="wa-border-radius-s"
src="https://images.unsplash.com/photo-1630643591760-a6ed60ef499f?q=80&w=3387&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Gervyn Louis)"
/>
</div>
</div>
<div class="wa-stack">
<div class="wa-split">
<h2 class="wa-heading-l">Graphic Cutoff Tee</h2>
<span class="wa-body-xl">$65</span>
</div>
<div class="wa-split">
<div class="wa-cluster">
<wa-rating label="Rating" readonly value="4.2"></wa-rating>
<span>4.2</span>
</div>
<a href="#">144 Reviews</a>
</div>
<wa-radio-group label="Color" name="color" value="black" orientation="horizontal">
<wa-radio-button value="black">
<wa-icon slot="prefix" name="shirt" style="color: black;"></wa-icon>
Vintage Black
</wa-radio-button>
<wa-radio-button value="gray">
<wa-icon slot="prefix" name="shirt" style="color: gray;"></wa-icon>
Faded Gray
</wa-radio-button>
</wa-radio-group>
<wa-radio-group label="Size" name="size" value="s" orientation="horizontal">
<wa-radio-button value="xs">XS</wa-radio-button>
<wa-radio-button value="s">S</wa-radio-button>
<wa-radio-button value="m">M</wa-radio-button>
<wa-radio-button value="l">L</wa-radio-button>
<wa-radio-button value="xl">XL</wa-radio-button>
</wa-radio-group>
<wa-button variant="brand">
<wa-icon slot="prefix" name="bag-shopping" variant="solid"></wa-icon>
Add to Bag
</wa-button>
<wa-divider></wa-divider>
<h3 class="wa-heading-s">Description</h3>
<p>Stay cool, <em>slay</em> cool. Train hard and recover in style with this ultra-breathable cutoff tee. Made from 100% organic, quick-drying cotton to keep the air flowing whether you're lifting, sprinting, or crushing HIIT sessions.</p>
<wa-divider></wa-divider>
<h3 class="wa-heading-s">Highlights</h3>
<div class="wa-grid">
<wa-card class="wa-span-grid">
<div class="wa-stack">
<wa-icon name="hand-holding-heart"></wa-icon>
<h4 class="wa-heading-s">People and Planet First</h4>
<p class="wa-caption-m">Ethical production, fair wages, and sustainable materials empower every part of our supply chain.</p>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<wa-icon name="earth-americas"></wa-icon>
<h4 class="wa-heading-s">International Shipping</h4>
<p class="wa-caption-m">Wherever you are, your order will meet you there.</p>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<wa-icon name="arrow-right-arrow-left"></wa-icon>
<h4 class="wa-heading-s">90-day Returns</h4>
<p class="wa-caption-m">Not happy? Return your item and get a full refund.</p>
</div>
</wa-card>
</div>
</div>
</div>
</div>
```
## With Carousel and Collapsible Details
```html {.example}
<div class="wa-stack wa-gap-2xl">
<wa-carousel pagination navigation loop style="--aspect-ratio: 3 / 2;">
<wa-carousel-item>
<img
src="https://images.unsplash.com/photo-1601379327928-bedfaf9da2d0?q=80&w=3456&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Four folded and stacked knit sweaters in three colors (Photograph by Tijana Drndarski)"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
src="https://images.unsplash.com/photo-1519804270019-39e929a7afb5?q=80&w=3774&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Knit sweater in sand color full view, showing waffle knit pattern, relaxed fit, and crew neckline (Photograph by Jonathan Zerger)"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
src="https://images.unsplash.com/photo-1519805614447-6f49142e6697?q=80&w=3633&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Knit sweater in sand color shoulder detail, showing relaxed fit on broader shoulders (Photograph by Jonathan Zerger)"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
src="https://images.unsplash.com/photo-1522230130022-498e355165c5?q=80&w=3774&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Knit sweater in sand color sleeve detail, showing loose fit around the arms (Photograph by Jonathan Zerger)"
/>
</wa-carousel-item>
</wa-carousel>
<div class="wa-grid wa-gap-2xl" style="--min-column-size: 30ch;">
<div class="wa-stack">
<div class="wa-split">
<h3>Pullover Sweater</h3>
<span class="wa-body-xl">$140</span>
</div>
<wa-rating label="Rating" precision="0.5" value="4.5" readonly></wa-rating>
<p>Wrap yourself in warmth and effortless style with this wool knit Pullover Sweater. Designed for unparalleled comfort. The relaxed fit and classic crew neckline make it a versatile staple for layering or wearing solo.</p>
<wa-radio-group label="Color" name="color" value="sand" orientation="horizontal">
<wa-radio-button value="sand">
<wa-icon slot="prefix" name="circle" style="color: burlywood;"></wa-icon>
Sand
</wa-radio-button>
<wa-radio-button value="shale">
<wa-icon slot="prefix" name="circle" style="color: silver;"></wa-icon>
Shale
</wa-radio-button>
<wa-radio-button value="slate">
<wa-icon slot="prefix" name="circle" style="color: dimgray;"></wa-icon>
Slate
</wa-radio-button>
</wa-radio-group>
<wa-radio-group label="Size" name="size" value="s" orientation="horizontal">
<wa-radio-button value="xs">XS</wa-radio-button>
<wa-radio-button value="s">S</wa-radio-button>
<wa-radio-button value="m">M</wa-radio-button>
<wa-radio-button value="l">L</wa-radio-button>
<wa-radio-button value="xl">XL</wa-radio-button>
</wa-radio-group>
<wa-button variant="brand">Add to Cart</wa-button>
</div>
<div class="wa-stack">
<wa-details summary="Size and Fit" open>
<ul class="wa-body-s">
<li>True to size with a relaxed fit</li>
<li>Fits all shoulder shapes, broad to narrow</li>
<li>No pinching in the arms or irritating seams</li>
<li>Ribbed cuffs and hem</li>
</ul>
</wa-details>
<wa-details summary="Materials and Care">
<ul class="wa-body-s">
<li>Durable Merino and Yak wool blend</li>
<li>Machine wash cold on delicate cycle</li>
<li>Lay flat to dry</li>
<li>Made with <wa-icon name="heart" label="love"></wa-icon> in Bentonville, USA</li>
</ul>
</wa-details>
<wa-details summary="Shipping">
<ul class="wa-body-s">
<li>Flat $9 shipping free for orders under $200.</li>
<li>Free shipping on orders over $200, anywhere in the world.</li>
</ul>
</wa-details>
</div>
</div>
</div>
```
## With Tabs
```html {.example}
<div class="wa-flank:end wa-align-items-start wa-gap-2xl" style="--flank-size: 30ch">
<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"
/>
<wa-tab-group>
<wa-tab panel="license">License</wa-tab>
<wa-tab panel="faq">FAQ</wa-tab>
<wa-tab-panel name="license">
<p class="wa-body-s">Your purchase includes a perpetual Font Awesome Pro License to use Classic Light icons on unlimited projects. <a href="">Read the full license terms.</a></p>
</wa-tab-panel>
<wa-tab-panel name="faq">
<dl class="wa-stack wa-body-s">
<dt>Do I need to renew my subscription to receive fixes?</dt>
<dd>We split up Font Awesome releases into regular updates and bug-fix updates. With a Font Awesome Pro plan that has a perpetual license, you'll always be entitled to bug-fix updates for your last version, even after your subscription has expired.</dd>
<dt>Can I use Font Awesome Pro in themes, plug-ins, or open source projects?</dt>
<dd>For themes and open source projects, right now it's best to just use Font Awesome Free. We are working a better solution, so feel free to get in touch if you have thoughts.</dd>
<dt>Do you offer enterprise licenses for Font Awesome Pro?</dt>
<dd>We don't currently offer Enterprise-level licenses, but we may do so in the future. Get in touch if interested.</dd>
</dl>
</wa-tab-panel>
</wa-tab-group>
</div>
<div class="wa-stack wa-gap-l">
<wa-badge appearance="filled">Sale</wa-badge>
<h2>Icon Pack: Classic Light</h2>
<p class="wa-body-l">Easy, readable icons with a lighter touch.</p>
<div class="wa-cluster wa-gap-xs wa-body-l">
<s>$60</s>
<strong>$49</strong>
</div>
<wa-button variant="brand" size="large">
<wa-icon slot="prefix" name="arrow-down-to-line" variant="solid"></wa-icon>
Get Icons
</wa-button>
<wa-divider></wa-divider>
<h3 class="wa-heading-m">What's in the Pack</h3>
<ul class="wa-stack wa-gap-xs">
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>3,323 icons</span>
</li>
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>Pre-bundled Font Awesome kit</span>
</li>
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>Ligature-based desktop font files</span>
</li>
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>Individual SVGs + SVG sprites</span>
</li>
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>Web fonts + SVG framework</span>
</li>
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>SCSS/LESS CSS preprocessor files</span>
</li>
<li class="wa-flank">
<wa-icon name="badge-check"></wa-icon>
<span>Perpetual Pro license</span>
</li>
</ul>
</div>
</div>
```

View File

@@ -0,0 +1,162 @@
---
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}
<wa-card with-header>
<div class="wa-split" slot="header">
<h3 class="wa-heading-l">Stan Smith® Camo Tongue Tee</h3>
<wa-icon-button name="close" label="Close Preview"></wa-icon-button>
</div>
<div class="wa-grid wa-gap-xl">
<div class="wa-frame wa-border-radius-l" style="aspect-ratio: auto">
<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"
/>
</div>
<div class="wa-split:column wa-align-items-stretch wa-gap-xl">
<div class="wa-stack wa-gap-xl">
<div class="wa-cluster">
<span class="wa-heading-2xl">$32</span>
<wa-divider vertical style="height: 2em"></wa-divider>
<wa-rating label="Rating" value="3.75" readonly></wa-rating>
<a href="" class="wa-caption-m">36 Reviews</a>
</div>
<p>An ode to the “Sneaker that go with everything” …even this tee.</p>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-s">
<h4 class="wa-heading-s">Categories</h4>
<div class="wa-cluster wa-gap-2xs">
<a href=""><wa-tag appearance="outlined" size="small" pill>Men's</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Sneakers</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Tees</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Lifestyle</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Fashion</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Casual</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Stan Smith</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Tennis</wa-tag></a>
<a href=""><wa-tag appearance="outlined" size="small" pill>Sports</wa-tag></a>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-s">
<wa-select label="Color" value="honeydew">
<wa-option value="hotpink">
<wa-icon slot="prefix" name="circle" style="color: hotpink;"></wa-icon>
Hot Pink
</wa-option>
<wa-option value="honeydew">
<wa-icon slot="prefix" name="circle" style="color: honeydew;"></wa-icon>
Honeydew
</wa-option>
<wa-option value="coral">
<wa-icon slot="prefix" name="circle" style="color: lightcoral;"></wa-icon>
Coral
</wa-option>
<wa-option value="wheat">
<wa-icon slot="prefix" name="circle" style="color: wheat;"></wa-icon>
Wheat
</wa-option>
<wa-option value="lilac">
<wa-icon slot="prefix" name="circle" style="color: #C8A2C8;"></wa-icon>
Lilac
</wa-option>
<wa-option value="burnt-orange">
<wa-icon slot="prefix" name="circle" style="color: #FF5733"></wa-icon>
Burnt Orange
</wa-option>
</wa-select>
<wa-select label="Size" value="large">
<wa-option value="small">Small</wa-option>
<wa-option value="medium">Medium</wa-option>
<wa-option value="large">Large</wa-option>
<wa-option value="xl">XL</wa-option>
<wa-option value="xxl">XXL</wa-option>
</wa-select>
</div>
</div>
<wa-button variant="brand">
Add to Cart
<wa-icon slot="suffix" name="cart-shopping" variant="solid"></wa-icon>
</wa-button>
</div>
</div>
</wa-card>
```
## With Description & Details
```html{.example}
<wa-card>
<div class="wa-split" slot="header">
<h3 class="wa-heading-l">Champion® Crossbody Bag</h3>
<wa-icon-button name="close" label="Close Preview"></wa-icon-button>
</div>
<div class="wa-grid wa-gap-xl">
<div class="wa-frame wa-border-radius-l" style="aspect-ratio: auto">
<img
src="https://images.unsplash.com/photo-1643467358005-899641cab7b5?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Black weatherproof crossbody bag with two large zipper pockets"
/>
</div>
<div class="wa-split:column wa-align-items-stretch wa-gap-xl">
<div class="wa-stack wa-gap-xl">
<div class="wa-split wa-align-items-start">
<span class="wa-heading-2xl">$40</span>
<wa-icon-button id="favorite" label="Favorite" name="heart" variant="regular"></wa-icon-button>
<wa-tooltip for="favorite">Add to Favorites</wa-tooltip>
</div>
<div class="wa-split">
<div class="wa-cluster wa-gap-xs">
<span>3.9</span>
<wa-rating value="3.9" readonly></wa-rating>
</div>
<a href="">See 512 Reviews</a>
</div>
<wa-divider></wa-divider>
<wa-callout size="small">
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
You purchased this item on <wa-format-date date="2023-02-20T09:00:00-04:00" month="long" day="numeric" year="numeric"></wa-format-date>
</wa-callout>
<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>
<wa-divider></wa-divider>
<div class="wa-gap-xs wa-stack">
<h4 class="wa-heading-m">Details</h4>
<dl class="wa-grid" style="--min-column-size: 15ch">
<div class="wa-gap-2xs wa-stack">
<dt class="wa-body-s">Care Instructions</dt>
<dd class="wa-caption-m">Hand Wash Only</dd>
</div>
<div class="wa-gap-2xs wa-stack">
<dt class="wa-body-s">Origin</dt>
<dd class="wa-caption-m">Imported</dd>
</div>
<div class="wa-gap-2xs wa-stack">
<dt class="wa-body-s">Country of Origin</dt>
<dd class="wa-caption-m">China</dd>
</div>
</dl>
</div>
</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-button>
<wa-button appearance="outlined" size="medium">
<wa-icon slot="suffix" name="arrow-right" variant="solid"></wa-icon>View Full Details
</wa-button>
</div>
</div>
</div>
</wa-card>
```

View File

@@ -1,465 +0,0 @@
---
title: Product Reviews
description: TODO
parent: ecommerce
tags: e-commerce
---
TODO Page Description
## With images grid
```html{.example}
<div class="with-image-grid">
<wa-breadcrumb>
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
<wa-breadcrumb-item>Men's</wa-breadcrumb-item>
<wa-breadcrumb-item>Shirts &amp; Tops</wa-breadcrumb-item>
</wa-breadcrumb>
<div class="image-grid">
<img src="/assets/images/patterns/gervyn-louis-IS03ajI00Fc-unsplash.jpg" />
<img src="/assets/images/patterns/gervyn-louis-KXvd7y7AU6Q-unsplash.jpg" />
<img src="/assets/images/patterns/gervyn-louis-semwwyXFQho-unsplash.jpg" />
<img src="/assets/images/patterns/mad-rabbit-tattoo-7N4FMowSGek-unsplash.jpg" />
</div>
<div>
<h2>Tank top</h2>
<p>The Basic Tee 6-Pack allows you to fully express your vibrant personality with three grayscale options. Feeling adventurous? Put on a heather gray tee. Want to be a trendsetter? Try our exclusive colorway: "Black". Need to add an extra pop of color to your outfit? Our white tee has you covered.</p>
<h3>Highlights</h3>
<ul>
<li>Hand cut and sewn locally</li>
</ul>
<h3>Highlights</h3>
<p>The 6-Pack includes two black, two white, and two heather gray Basic Tees. Sign up for our subscription service and be the first to get new, exciting colors, like our upcoming "Charcoal Gray" limited release.</p>
<span>$192</span>
<div>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
<a href="#">117 Reviews</a>
</div>
<wa-radio-group label="Select an option" hint="Select an option that makes you proud." name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
<wa-radio-group label="Select an option" hint="Select an option that makes you proud." name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
<wa-button>Add to Cart</wa-button>
</div>
</div>
<style>
.with-image-grid {
wa-breadcrumb::part(base) {
margin-bottom: 1rem;
}
.image-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
}
.image-grid img:nth-of-type(1) {
grid-column: 1/-1;
}
.image-grid img:nth-of-type(2) {
grid-column: 1/7;
}
.image-grid img:nth-of-type(3) {
grid-column: 7/-1;
}
.image-grid img:nth-of-type(4) {
grid-column: 1/-1;
}
}
</style>
```
## With Tiered Images
```html{.example}
<div class="with-tiered-images">
<wa-breadcrumb>
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
<wa-breadcrumb-item>Men's</wa-breadcrumb-item>
<wa-breadcrumb-item>Shirts &amp; Tops</wa-breadcrumb-item>
</wa-breadcrumb>
<div>
<div class="heading">
<h2>Basic Tee</h2>
<span style="font-size: var(--wa-font-size-2xl)">$35</span>
</div>
<div class="rating">
<span>3.9</span>
<wa-rating label="Rating" precision="0.5" value="3.9"></wa-rating>
<a href="#">117 Reviews</a>
</div>
<div class="tiered-images">
<img src="/assets/images/patterns/gervyn-louis-IS03ajI00Fc-unsplash.jpg" />
<img src="/assets/images/patterns/gervyn-louis-KXvd7y7AU6Q-unsplash.jpg" />
<img src="/assets/images/patterns/gervyn-louis-semwwyXFQho-unsplash.jpg" />
</div>
</div>
<wa-radio-group label="Select an option" hint="Select an option that makes you proud." name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
<wa-radio-group label="Select an option" hint="Select an option that makes you proud." name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
<wa-button>Add to Cart</wa-button>
<h3>Description</h3>
<p>The Basic tee is an honest new take on a classic. The tee uses super soft, pre-shrunk cotton for true comfort and a dependable fit. They are hand cut and sewn locally, with a special dye technique that gives each tee it's own look.</p>
<p>Looking to stock your closet? The Basic tee also comes in a 3-pack or 5-pack at a bundle discount.</p>
<hr />
<h3>Highlights</h3>
<ul>
<li>Hand cut and sewn locally</li>
</ul>
<div>
<wa-card>
<wa-icon family="solid" name="earth-americas"></wa-icon>
<h3>International delivery</h3>
<p>Get your order in 2 years</p>
</wa-card>
<wa-card>
<wa-icon family="solid" name="earth-americas"></wa-icon>
<h3>International delivery</h3>
<p>Get your order in 2 years</p>
</wa-card>
</div>
</div>
<style>
.with-tiered-images {
wa-breadcrumb::part(base) {
margin-bottom: 1rem;
}
.heading {
display: flex;
justify-content: space-between;
align-items: center;
}
.rating {
display: flex;
span {
display: inline-block;
margin-right: 1rem;
}
wa-rating {
margin-right: 1rem;
}
}
.tiered-images {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
}
.tiered-images img:nth-of-type(1) {
grid-column: 1/-1;
}
.tiered-images img:nth-of-type(2) {
grid-column: 1/7;
}
.tiered-images img:nth-of-type(3) {
grid-column: 7/-1;
}
</style>
```
## with images and expandable details
```html {.example}
<wa-carousel class="carousel-thumbnails" navigation loop>
<wa-carousel-item>
<img
alt="The sun shines on the mountains and trees (by Adam Kool on Unsplash)"
src="/assets/examples/carousel/pullover-1.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="A waterfall in the middle of a forest (by Thomas Kelly on Unsplash)"
src="/assets/examples/carousel/pullover-2.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="The sun is setting over a lavender field (by Leonard Cotte on Unsplash)"
src="/assets/examples/carousel/pullover-3.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="A field of grass with the sun setting in the background (by Sapan Patel on Unsplash)"
src="/assets/examples/carousel/pullover-4.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in (by V2osk on Unsplash)"
src="/assets/examples/carousel/pullover-5.jpg"
/>
</wa-carousel-item>
</wa-carousel>
<div class="thumbnails">
<div class="thumbnails__scroller">
<img alt="Thumbnail by 1" class="thumbnails__image active" src="/assets/examples/carousel/pullover-1.jpg" />
<img alt="Thumbnail by 2" class="thumbnails__image" src="/assets/examples/carousel/pullover-2.jpg" />
<img alt="Thumbnail by 3" class="thumbnails__image" src="/assets/examples/carousel/pullover-3.jpg" />
<img alt="Thumbnail by 4" class="thumbnails__image" src="/assets/examples/carousel/pullover-4.jpg" />
<img alt="Thumbnail by 5" class="thumbnails__image" src="/assets/examples/carousel/pullover-5.jpg" />
</div>
</div>
<div>
<h3 style="--wa-space-xl: 0;">Pullover Sweater</h3>
<span class="price-big">$140</span>
<wa-rating class="sweater-rating" label="Rating" precision="0.5" value="2.5"></wa-rating>
<p>The Zip Tote Basket is the perfect midpoint between shopping tote and comfy backpack. With convertible straps, you can hand carry, should sling, or backpack this convenient and spacious bag. The zip top and durable canvas construction keeps your goods protected for all-day use.</p>
<wa-radio-group label="Select Color" hint="Select an option that makes you proud." name="a" value="1">
<wa-radio-button value="1"></wa-radio-button>
<wa-radio-button value="2"></wa-radio-button>
<wa-radio-button value="3"></wa-radio-button>
</wa-radio-group>
<div>
<wa-button>Add to cart</wa-button>
<wa-icon-button name="gear" label="Settings"></wa-icon-button>
</div>
<div class="details-group-example">
<wa-details summary="First" open>
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="Second">
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="Third">
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>
</div>
<style>
.carousel-thumbnails {
--slide-aspect-ratio: 3 / 2;
}
wa-radio-button #shadow-root div .button--medium {
padding: var(--wa-space-xs) var(--wa-space-xs);
}
.color-circle {
--background: #000;
background: var(--background);
width: 50px;
height: 100%;
}
.sweater-rating {
margin-bottom: 1rem;
}
.price-big {
display: block;
font-size: 32px;
}
.thumbnails {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.thumbnails__scroller {
display: flex;
gap: var(--wa-space-s);
overflow-x: auto;
scrollbar-width: none;
scroll-behavior: smooth;
scroll-padding: var(--wa-space-s);
}
.thumbnails__scroller::-webkit-scrollbar {
display: none;
}
.thumbnails__image {
width: 64px;
height: 64px;
object-fit: cover;
opacity: 0.3;
will-change: opacity;
transition: 250ms opacity;
cursor: pointer;
}
.thumbnails__image.active {
opacity: 1;
}
.details-group-example wa-details:not(:last-of-type) {
margin-bottom: var(--wa-space-2xs);
}
</style>
<script>
{
const carousel = document.querySelector('.carousel-thumbnails');
const scroller = document.querySelector('.thumbnails__scroller');
const thumbnails = document.querySelectorAll('.thumbnails__image');
scroller.addEventListener('click', e => {
const target = e.target;
if (target.matches('.thumbnails__image')) {
const index = [...thumbnails].indexOf(target);
carousel.goToSlide(index);
}
});
carousel.addEventListener('wa-slide-change', e => {
const slideIndex = e.detail.index;
[...thumbnails].forEach((thumb, i) => {
thumb.classList.toggle('active', i === slideIndex);
if (i === slideIndex) {
thumb.scrollIntoView({
block: 'nearest'
});
}
});
});
}
const container = document.querySelector('.details-group-example');
// Close all other details when one is shown
container.addEventListener('wa-show', event => {
if (event.target.localName === 'wa-details') {
[...container.querySelectorAll('wa-details')].map(details => (details.open = event.target === details));
}
});
</script>
```
## Split with image
```html {.example}
<div class="split-with-image">
<div class="div-1">
<wa-breadcrumb>
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
<wa-breadcrumb-item>Men's</wa-breadcrumb-item>
<wa-breadcrumb-item>Shirts &amp; Tops</wa-breadcrumb-item>
</wa-breadcrumb>
<h2>Everyday Ruck Snack</h2>
<span>
<span>$220</span> |
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
<span>1624 reviews</span>
</span>
<p>Don't compromise on snack-carrying capacity with this lightweight and spacious bag. The drawstring top keeps all your favorite chips, crisps, fries, biscuits, crackers, and cookies secure.</p>
<span><wa-icon family="solid" name="check"></wa-icon> In stock and ready to ship</span>
</div>
<div class="div-2">
<img src="/assets/images/patterns/gervyn-louis-IS03ajI00Fc-unsplash.jpg" />
</div>
<div class="div-3">
<wa-radio-group label="Select an option" hint="Select an option that makes you proud." name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
</div>
</div>
<style>
.split-with-image {
display: grid;
/* grid-template-columns: repeat(2, 1fr); */
/* height: 1000px; */
/* gap: 1rem; */
.div-1 {
}
.div-2 {
/* background-color: black;
grid-column-start: 2;
grid-row: span 2 / span 2; */
}
.div-3 {
}
}
</style>
```
## With tabs
```html{.example}
<div>
<wa-rating class="sweater-rating" label="Rating" precision="0.5" value="2.5"></wa-rating>
<h2>Application UI Icon Pack</h2>
<img alt="Sample of 30 icons with friendly and fun details in outline, filled, and brand color styles." src="https://tailwindui.com/img/ecommerce-images/product-page-05-product-01.jpg" class="aqk aql">
<p>The Application UI Icon Pack comes with over 200 icons in 3 styles: outline, filled, and branded. This playful icon pack is tailored for complex application user interfaces with a friendly and legible look.</p>
<wa-button variant="brand">Brand</wa-button>
<wa-button variant="success">Success</wa-button>
<hr />
<h3>Highlights</h3>
<ul>
<li>200+ SVG icons in 3 unique styles</li>
<li>Compatible with Figma, Sketch, and Adobe XD</li>
<li>Drawn on 24 x 24 pixel grid</li>
</ul>
<hr />
<h3>License</h3>
<p>For personal and professional use. You cannot resell or redistribute these icons in their original or modified state. <a href="#">Read full license</a></p>
<hr />
<h3>Share</h3>
<wa-icon family="brands" name="facebook"></wa-icon>
<wa-icon family="brands" name="instagram"></wa-icon>
<wa-icon family="brands" name="x-twitter"></wa-icon>
<wa-tab-group>
<wa-tab panel="general">General</wa-tab>
<wa-tab panel="custom">Custom</wa-tab>
<wa-tab panel="advanced">Advanced</wa-tab>
<wa-tab panel="disabled" disabled>Disabled</wa-tab>
<wa-tab-panel name="general">
<div></div>
<div>
<h3>Hector Gibbons</h3>
<p>July 12, 2021</p>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
<p>Blown away by how polished this icon pack is. Everything looks so consistent and each SVG is optimized out of the box so I can use it directly with confidence. It would take me several hours to create a single icon this good, so it's a steal at this price.</p>
</div>
</wa-tab-panel>
<wa-tab-panel name="custom">This is the custom tab panel.</wa-tab-panel>
<wa-tab-panel name="advanced">This is the advanced tab panel.</wa-tab-panel>
<wa-tab-panel name="disabled">This is a disabled tab panel.</wa-tab-panel>
</wa-tab-group>
</div>
```

View File

@@ -0,0 +1,213 @@
---
title: Product Reviews
description: 'Help shoppers make informed decisions with ratings, reviews, and testimonials from your customers.'
parent: ecommerce
tags: e-commerce
---
## Multi column
```html{.example}
<div style="max-width: 960px; margin: 0 auto;">
<span class="wa-heading-m">Recent Reviews</span>
<wa-divider></wa-divider>
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Viktor Vaughn</span>
<span class="wa-caption-m"><em>September 23rd, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="5"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">Best treadmill I've ever owned! It has a sleek design, and the features are top-notch. I use it daily for my cardio workouts, and the motor is powerful enough to keep up with my running. Its easy to adjust the speed and incline, and the display is clear and simple to read. Worth every penny!</p>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Ben Grimm</span>
<span class="wa-caption-m"><em>May 5th, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="4"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">Decent treadmill for the price, but I feel like the belt could be a little wider for comfort. The cushioning is good, but sometimes I experience a slight wobble when running at high speeds. For casual walking, it's fine, but Im not sure its built for intense runners.</p>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Johnny Storm</span>
<span class="wa-caption-m"><em>March 3rd, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="4"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">This treadmill has been a great addition to my home gym. It's sturdy, easy to use, and I like that it tracks my steps and heart rate. The only downside is that it's a bit bulky, so I had to rearrange my space to make room for it. Overall, I'm happy with the performance and would recommend it.</p>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-gap-s" style="--flank-size: 20%">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Sue Storm</span>
<span class="wa-caption-m"><em>February 26th, 2023</em></span>
</div>
<div class="wa-flank">
<wa-rating label="Rating" readonly value="4"></wa-rating>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Rating Title</span>
<p class="wa-caption-m">I absolutely love my new treadmill! Its perfect for my daily workouts. The setup was quick, and its so quiet that I can use it while watching TV without any interruptions. The different incline levels really help mix up my routine, and the built-in programs keep things interesting. Highly recommend for anyone looking to stay fit at home!</p>
</div>
</div>
</div>
</div>
```
## With Ratings Distribution
```html {.example}
<div style="max-width: 960px; margin: 0 auto;">
<div class="wa-align-items-start wa-flank wa-gap-2xl">
<div class="wa-gap-s wa-stack">
<span class="wa-heading-m">Customer Reviews</span>
<div class="wa-stack wa-gap-xs"><wa-rating label="Rating" precision="0.5" value="4.6" size="small"></wa-rating> <span class="wa-caption-m">Based on 1624 reviews</span></div>
<div class="wa-stack">
<span class="wa-cluster wa-gap-2xs">
<span>5</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="63" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<span>63%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>4</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="17" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<span>17%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>3</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="15" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<span>15%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>2</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="3" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<span>3%</span>
</span>
<span class="wa-cluster wa-gap-2xs">
<span>1</span>
<wa-icon name="star" style="font-size: 12px;"></wa-icon>
<wa-progress-bar value="2" label="Upload progress" style="height: 6px; width: 50%"></wa-progress-bar>
<span>2%</span>
</span>
</div>
</div>
<div>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
<wa-divider></wa-divider>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
<wa-divider></wa-divider>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1580489944761-15a19d654956?q=80&w=2561&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
<wa-divider></wa-divider>
<div>
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1566492031773-4f4e44671857?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-s">Emily Selman</span>
<wa-rating label="Rating" precision="0.5" value="2.5"></wa-rating>
</div>
</div>
<p class="wa-caption-l"><em>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</em></p>
</div>
</div>
</div>
</div>
```
## Two Column
```html{.example}
<div class="wa-stack" style="max-width: 960px; margin: 0 auto;">
<div class="wa-flank wa-align-items-center">
<div class="wa-stack wa-align-items-center wa-gap-xs">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1607746882042-944635dfe10e?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<p>Ripley</p>
<div>
<wa-icon-button name="thumbs-up" label="I don't like this review" style="color: var(--wa-color-success-fill-loud);"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review" style="color: var(--wa-color-danger-fill-loud);"></wa-icon-button>
</div>
</div>
<div>
<wa-rating label="Rating" precision="0.5" value="5" readonly></wa-rating>
<p>I recently purchased the Modern Sofa Couch, and I couldn't be happier with my decision! The process from ordering to delivery was smooth and hassle-free</p>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-align-items-center">
<div class="wa-stack wa-align-items-center wa-gap-xs">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?q=80&w=2574&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<p>Kane</p>
<div>
<wa-icon-button name="thumbs-up" label="I don't like this review" style="color: var(--wa-color-success-fill-loud);"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review" style="color: var(--wa-color-danger-fill-loud);"></wa-icon-button>
</div>
</div>
<div>
<wa-rating label="Rating" precision="0.5" value="3.4" readonly></wa-rating>
<p>The cushions are soft yet supportive, and the sectional layout gives plenty of space to stretch out. Its perfect for movie nights or just lounging with a good book.</p>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank wa-align-items-center">
<div class="wa-stack wa-align-items-center wa-gap-xs">
<wa-avatar label="User avatar" image="https://images.unsplash.com/photo-1728577740843-5f29c7586afe?q=80&w=2680&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></wa-avatar>
<p>Parker</p>
<div>
<wa-icon-button name="thumbs-up" label="I don't like this review" style="color: var(--wa-color-success-fill-loud);"></wa-icon-button>
<wa-icon-button name="thumbs-down" label="I like this review" style="color: var(--wa-color-danger-fill-loud);"></wa-icon-button>
</div>
</div>
<div>
<wa-rating label="Rating" precision="0.5" value="3.8" readonly></wa-rating>
<p>The leather is high quality, but its a little firmer than I thought. That said, after sitting on it for a while, it does soften up and feels more comfortable. Its perfect if youre looking for a more structured seating experience.</p>
</div>
</div>
<wa-divider></wa-divider>
</div>
```

View File

@@ -1,10 +1,279 @@
---
title: Shopping Cart
description: TODO
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
---
TODO Page Description
## Two Columns with Summary Card
## Examples
```html {.example}
<div class="wa-stack wa-gap-2xl">
<h2>Shopping Cart</h2>
<div class="wa-grid wa-align-items-start wa-gap-2xl">
<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
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=""
/>
</div>
<div class="wa-flank:end wa-align-items-baseline">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Classic Tee</h3>
<span class="wa-caption-m">Sage Green</span>
<span class="wa-caption-m">Large</span>
<span>$20.00</span>
</div>
<wa-icon-button name="xmark" label="Remove" id="remove-1"></wa-icon-button>
<wa-tooltip for="remove-1">Remove</wa-tooltip>
</div>
</article>
<article class="wa-flank wa-gap-xl" style="--flank-size: 8rem">
<div class="wa-frame wa-border-radius-m">
<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=""
/>
</div>
<div class="wa-flank:end wa-align-items-baseline">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">RVCA Graphic</h3>
<span class="wa-caption-m">White</span>
<span class="wa-caption-m">Large</span>
<span>$25.00</span>
</div>
<wa-icon-button name="xmark" label="Remove" id="remove-2"></wa-icon-button>
<wa-tooltip for="remove-2">Remove</wa-tooltip>
</div>
</article>
<article class="wa-flank wa-gap-xl" style="--flank-size: 8rem">
<div class="wa-frame wa-border-radius-m">
<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=""
/>
</div>
<div class="wa-flank:end wa-align-items-baseline">
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Stay Wild Graphic</h3>
<span class="wa-caption-m">Black</span>
<span class="wa-caption-m">Large</span>
<span>$18.00</span>
</div>
<wa-icon-button name="xmark" label="Remove" id="remove-3"></wa-icon-button>
<wa-tooltip for="remove-3">Remove</wa-tooltip>
</div>
</article>
</div>
<wa-card>
<div slot="header">
<h3 class="wa-heading-m">Order Summary</h3>
</div>
<div class="wa-stack">
<div class="wa-split">
<span class="wa-caption-l">Subtotal</span>
<strong>$63.00</strong>
</div>
<wa-divider></wa-divider>
<div class="wa-split">
<span class="wa-caption-l">Shipping</span>
<strong>$5.00</strong>
</div>
<wa-divider></wa-divider>
<div class="wa-split">
<span class="wa-caption-l">Tax</span>
<strong>$5.50</strong>
</div>
<wa-divider></wa-divider>
<div class="wa-split wa-body-l">
<span>Total</span>
<strong>$73.50</strong>
</div>
<wa-button variant="brand">Checkout</wa-button>
</div>
</wa-card>
</div>
</div>
</div>
```
## Single Column
```html {.example}
<div class="wa-stack wa-gap-2xl" style="max-width: 60ch; margin: auto">
<h2>Your Cart</h2>
<wa-divider></wa-divider>
<article class="wa-flank" style="--flank-size: 12rem">
<div class="wa-frame wa-border-radius-m" style="aspect-ratio: 3 / 2">
<img
src="https://images.unsplash.com/photo-1594787317357-dcda50fd1d78?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDI4MDd8&ixlib=rb-4.0.3&q=80&w=1080"
alt=""
/>
</div>
<div class="wa-split:column wa-align-items-stretch wa-gap-xs">
<div class="wa-stack wa-gap-xs">
<span class="wa-split wa-gap-xs">
<h3 class="wa-heading-m">Convertible</h3>
<span>$32.00</span>
</span>
<wa-tag size="small" variant="neutral" appearance="filled" pill style="width: fit-content">Cherry Red</wa-tag>
</div>
<div class="wa-split">
<wa-badge appearance="filled" variant="success">In Stock</wa-badge>
<wa-button appearance="plain" size="small" variant="danger">
<wa-icon slot="suffix" name="trash"></wa-icon>
Remove
</wa-button>
</div>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank" style="--flank-size: 12rem">
<div class="wa-frame wa-border-radius-m" style="aspect-ratio: 3 / 2">
<img
src="https://images.unsplash.com/photo-1597670250484-0e9aff7f8804?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDI4NTB8&ixlib=rb-4.0.3&q=80&w=1080"
alt=""
/>
</div>
<div class="wa-split:column wa-align-items-stretch wa-gap-xs">
<div class="wa-stack wa-gap-xs">
<span class="wa-split wa-gap-xs">
<h3 class="wa-heading-m">Racers (3 Pack)</h3>
<span>$80.00</span>
</span>
<wa-tag size="small" variant="neutral" appearance="filled" pill style="width: fit-content">Assorted Colors</wa-tag>
</div>
<div class="wa-split">
<wa-badge appearance="filled" variant="success">In Stock</wa-badge>
<wa-button appearance="plain" size="small" variant="danger">
<wa-icon slot="suffix" name="trash"></wa-icon>
Remove
</wa-button>
</div>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank" style="--flank-size: 12rem">
<div class="wa-frame wa-border-radius-m" style="aspect-ratio: 3 / 2">
<img
src="https://images.unsplash.com/photo-1594787826350-19386fdb2363?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDI4ODV8&ixlib=rb-4.0.3&q=80&w=1080"
alt=""
/>
</div>
<div class="wa-split:column wa-align-items-stretch wa-gap-xs">
<div class="wa-stack wa-gap-xs">
<span class="wa-split wa-gap-xs">
<h3 class="wa-heading-m">Volkswagen T2</h3>
<span>$60.00</span>
</span>
<wa-tag size="small" variant="neutral" appearance="filled" pill style="width: fit-content">Red/White</wa-tag>
</div>
<div class="wa-split">
<wa-badge appearance="filled" variant="warning">Low Stock</wa-badge>
<wa-button appearance="plain" size="small" variant="danger">
<wa-icon slot="suffix" name="trash"></wa-icon>
Remove
</wa-button>
</div>
</div>
</article>
<wa-divider></wa-divider>
<div class="wa-stack">
<div class="wa-split">
<h3 class="wa-heading-m">Subtotal</h3>
<span class="wa-body-l">$172.00</span>
</div>
<span class="wa-caption-m">Shipping and taxes calculated at checkout</span>
<wa-button size="large" variant="brand">Checkout</wa-button>
<div class="cluster">
<span class="wa-caption-m">Not quite ready?</span>
<wa-button appearance="plain" size="small" variant="brand">
Continue Shopping
<wa-icon name="arrow-right"></wa-icon>
</wa-button>
</div>
</div>
</div>
```
## Drawer
```html {.example viewport}
<wa-drawer label="Shopping Cart" with-header with-footer open>
<div class="wa-stack">
<article class="wa-flank" style="--flank-size: 6rem">
<div class="wa-frame wa-border-radius-m">
<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-split wa-gap-2xs">
<strong>AJ1 Low</strong>
<strong>$170.00</strong>
</div>
<span class="wa-caption-m">Multi-color</span>
<div class="wa-split wa-gap-2xs">
<span class="wa-body-s">Qty: 1</span>
<wa-button appearance="plain" size="small">Remove</wa-button>
</div>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank" style="--flank-size: 6rem">
<div class="wa-frame wa-border-radius-m">
<img
src="https://images.unsplash.com/photo-1672908615254-71a0b373eaba?q=80&w=3560&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="(Photograph by Hamed darzi)"
/>
</div>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>The Trails</strong>
<strong>$35.00</strong>
</div>
<span class="wa-caption-m">Twilight Blue</span>
<div class="wa-split wa-gap-2xs">
<span class="wa-body-s">Qty: 1</span>
<wa-button appearance="plain" size="small">Remove</wa-button>
</div>
</div>
</article>
<wa-divider></wa-divider>
<article class="wa-flank" style="--flank-size: 6rem">
<div class="wa-frame wa-border-radius-m">
<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-split wa-gap-2xs">
<strong>Outcast 2-pack</strong>
<strong>$27.00</strong>
</div>
<span class="wa-caption-m">Black / White</span>
<div class="wa-split wa-gap-2xs">
<span class="wa-body-s">Qty: 1</span>
<wa-button appearance="plain" size="small">Remove</wa-button>
</div>
</div>
</article>
</div>
<div slot="footer" class="wa-stack" style="width: 100%">
<div class="wa-split">
<strong>Subtotal</strong>
<strong>$232.00</strong>
</div>
<span class="wa-caption-m">Shipping and taxes calculated at checkout.</span>
<wa-button variant="brand">Checkout</wa-button>
<wa-button appearance="plain" size="small" variant="brand">
Continue Shopping
<wa-icon name="arrow-right"></wa-icon>
</wa-button>
</div>
</wa-drawer>
```

View File

@@ -0,0 +1,85 @@
---
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
---
## Popup Menu
```html{.example}
<wa-dropdown>
<wa-button slot="trigger" caret>Shop</wa-button>
<wa-menu class="mm-grid">
<div>
<wa-menu-label>Shop by Department</wa-menu-label>
<wa-menu-item value="apple">Mens</wa-menu-item>
<wa-menu-item value="banana">Womens</wa-menu-item>
<wa-menu-item value="orange">Kids</wa-menu-item>
<wa-menu-item value="orange">
Infants
<wa-menu slot="submenu">
<wa-menu-item value="uppercase">Newborns</wa-menu-item>
<wa-menu-item value="lowercase">6 Months</wa-menu-item>
<wa-menu-item value="capitalize">12 Months</wa-menu-item>
</wa-menu>
</wa-menu-item>
<wa-menu-item value="orange">Big & Tall</wa-menu-item>
</div>
<div>
<wa-menu-label>Shop by Category</wa-menu-label>
<wa-menu-item value="apple">Shirts</wa-menu-item>
<wa-menu-item value="banana">Pants</wa-menu-item>
<wa-menu-item value="orange">Shoes</wa-menu-item>
</div>
<div>
<wa-menu-label>Just Arrived</wa-menu-label>
<wa-menu-item>
<a href="#">
<img style="width: 100%; max-width: 200px;" 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" />
</a>
</wa-menu-item>
</div>
<wa-menu-item style="grid-column: 1/-1;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<p style="margin:0;">footer with something cool in it</p>
<wa-button variant="brand" size="small">Signup now</wa-button>
</div>
</wa-menu-item>
</wa-menu>
</wa-dropdown>
<style>
.mm-grid {
display: grid;
grid-template-columns: repeat(3, auto);
gap: 1rem;
.card-overview small {
color: var(--wa-color-text-quiet);
}
.card-overview [slot='footer'] {
display: flex;
justify-content: space-between;
align-items: center;
}
}
</style>
```

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,6 +1,7 @@
---
title: Business
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,6 +1,7 @@
---
title: Entertainment
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,8 +1,29 @@
---
title: Patterns
description: Patterns are reusable solutions to common design problems.
description: Patterns are reusable UI solutions to common design problems, ready to copy and paste into any project.
layout: overview
categories: ["e-commerce"]
categories: ["app", "e-commerce"]
listChildren: true
override:tags: []
---
<div class="max-line-length">
{% markdown %}
## 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.
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.
Patterns are written as standard HTML, so you can use them just as you would any ol' HTML and customize them to fit your specific needs.
## Using Patterns
To use a pattern in your project, refer to each pattern's docs for a copyable code snippet. Paste the snippet wherever you'd like the pattern to appear in your project.
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>

View File

@@ -1,6 +1,7 @@
---
title: Membership
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,6 +1,7 @@
---
title: News
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,6 +1,7 @@
---
title: Non-profit
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -0,0 +1,7 @@
.anchor-heading:has(+ wa-code-demo, + template + wa-code-demo) {
font-size: var(--wa-font-size-l);
}
wa-code-demo:has(+ .anchor-heading) {
margin-block-end: var(--wa-space-3xl);
}

View File

@@ -1,5 +1,5 @@
{
"layout": "block.njk",
"layout": "patterns.njk",
"tags": ["patterns"],
"wide": true,
"noAlpha": true

View File

@@ -1,6 +1,7 @@
---
title: Portfolio
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,6 +1,7 @@
---
title: Product Landing
description: TODO
unlisted: true
---
TODO Page Description

View File

@@ -1,7 +1,7 @@
---
title: Changelog
description: Changes to each version of the project are documented here.
layout: page
layout: page-outline
---
Web Awesome follows [Semantic Versioning](https://semver.org/). Breaking changes in components with the <wa-badge variant="brand" pill>Stable</wa-badge> badge will not be accepted until the next major version. As such, all contributions must consider the project's roadmap and take this into consideration. Features that are deemed no longer necessary will be deprecated but not removed.
@@ -14,11 +14,74 @@ During the alpha period, things might break! We take breaking changes very serio
## Next
- Added an orientation example to the native radio docs
- Fixed `wa-pill` class for text fields
- Fixed `pill` style for `<wa-input>` elements
- Fixed a bug in `<wa-color-picker>` that prevented light dismiss from working when clicking immediately above the color picker dropdown
## 3.0.0-alpha.11
### Color Palettes
- Color palette tweaking UI. Tweak hue, grays, overall colorfulness, save or share the results.
- Added a `pink` scale to all color palettes
- Tweaked hues of all color palettes to make them more distinct and make their hues more intentional
- Dropped `violet` and `teal`, instead using `purple` and `cyan` (this is not just a renaming, the colors have been adjusted too).
- Fixed a bug in `<wa-switch>` that caused tooltips to work incorrectly when toggling the switch
### Design Tokens
- Added `--wa-color-[hue]` tokens with the "core" color of each scale, regardless of which tint it lives on.
You can find them in the first column of each color palette.
### Themes
- Improved UI for theme remixing:
- You can now override the brand color of any theme with any of the 9 hues supported.
- Rich previews
- Generated copyable code snippets.
- Permalinks
- Updated Active, Glossy, Playful, and Premium themes so that `--wa-color-brand-fill-loud` uses the core color of the chosen brand color, regardless of tint.
### Components
#### `<wa-radio>`
- Dropped the `base` part. It can now be styled by directly applying CSS to the element itself.
- Added `hint` attribute and corresponding slot.
#### `<wa-select>`
- Added the `tag` part (and associated exported parts) to `<wa-select>` to allow targeting the tag that shows when more than the max number of visible items have been selected
- Fixed a bug that prevented the placeholder color from being customized with the `--wa-form-control-placeholder-color` token
- Fixed an incorrect CSS value in the expand icon
- Fixed a bug that prevented the description from being read by screen readers
#### `<wa-option>`
- `label` attribute to override the generated label (useful for rich content)
- `defaultLabel` property
- Dropped `getTextLabel()` method (if you need dynamic labels, just set the `label` attribute dynamically)
- Dropped `base` part for easier styling. CSS can now be applied directly to the element itself.
#### `<wa-menu-item>`
- `label` attribute to override the generated label (useful for rich content)
- `defaultLabel` property
- Dropped `getTextLabel()` method (if you need dynamic labels, just set the `label` attribute dynamically)
#### `<wa-card>`
- Fixed a bug where child elements did not have correct rounding when headers and footers were absent.
- Re-introduced `--border-color` so that the card itself can have a different border color than its inner borders.
- Fixed a bug that prevented slots from showing automatically without `with-` attributes
#### `<wa-tab>`
- Fixed a bug that caused `document.createElement('wa-tab')` to fail (which also meant it could not be used in VueJS and other frameworks)
### Docs
- Added an orientation example to the native radio docs
- Fixed a number of broken event listeners throughout the docs
- Fixed a bug in `<wa-card>` that prevented slots from showing automatically without `with-` attributes
- Fixed a bug in `<wa-select>` that prevented the placeholder color from being customized with the `--wa-form-control-placeholder-color` token
## 3.0.0-alpha.10

View File

@@ -10,15 +10,17 @@ override:tags: []
eleventyComputed:
forceTheme: "{{ theme.fileSlug }}"
---
{% set isPro = theme.data.isPro %}
{% set status = theme.data.status %}
{% set since = theme.data.since %}
<link rel="stylesheet" href="/docs/themes/showcase.css" />
{% set content %}
<header>
{% include 'breadcrumbs.njk' %}
<h1 class="title">{{ theme.data.title }}</h1>
<p id="mix_and_match" hidden class="wa-size-s"></p>
<p>{% include 'status.njk' %}</p>
<p id="mix_and_match" class="wa-size-s"></p>
<p id="theme-status">{% include 'status.njk' %}</p>
<p id="theme-showcase-description">{{ theme.data.description | inlineMarkdown | safe }}</p>
</header>
{% include 'theme-showcase.njk' %}
@@ -34,30 +36,19 @@ eleventyComputed:
</wa-image-comparer>
<script type="module">
import { getCode, urls as stylesheetURLs } from "/assets/scripts/remix.js";
import { urls as stylesheetURLs, docsURLs, icons } from "/assets/scripts/tweak/data.js";
import { getThemeCode } from "/assets/scripts/tweak/code.js";
function updateTheme() {
let params = new URLSearchParams(window.location.search);
params = Object.fromEntries(params.entries());
const docsURLs = {
colors: '/docs/themes/',
palette: '/docs/palettes/',
typography: '/docs/themes/'
};
const icons = {
colors: 'palette',
palette: 'swatchbook',
brand: 'droplet',
typography: 'font-case'
};
for (let link of document.querySelectorAll('link.mix-and-match')) {
link.remove();
}
let msgs = [];
let code = getCode("{{ theme.fileSlug }}", params, {attributes: 'class="mix-and-match"'});
let tweaks = [];
let code = getThemeCode("{{ theme.fileSlug }}", params, {attributes: 'class="mix-and-match"'});
document.head.insertAdjacentHTML('beforeend', code);
for (let name in stylesheetURLs) {
@@ -71,18 +62,29 @@ function updateTheme() {
}
let icon = icons[name];
msgs.push(`<wa-icon name="${icon}" variant="regular"></wa-icon> ${ title }`);
tweaks.push(`<wa-icon name="${icon}" variant="regular"></wa-icon> ${ title }`);
}
}
for (let p of mix_and_match) {
p.hidden = msgs.length === 0;
if (msgs.length) {
let icon =
p.innerHTML = `<strong><wa-icon name="arrows-rotate"></wa-icon> Remixed</strong> ` + msgs.map(msg => `<wa-badge appearance=outlined>
${ msg }</wa-badge>`).join(' ');
let isRemixed = tweaks.length > 0;
document.documentElement.classList.toggle('is-remixed', isRemixed);
if (isRemixed) {
for (let p of document.querySelectorAll("#theme-status")) {
let proBadge = p.querySelector(".pro");
if (!proBadge) {
p.insertAdjacentHTML('beforeend', '<wa-badge class="pro">PRO</wa-badge>');
}
}
for (let p of mix_and_match) {
if (tweaks.length) {
p.innerHTML = `<strong><wa-icon name="arrows-rotate"></wa-icon> Remixed</strong> ` + tweaks.map(msg => `<wa-badge appearance=outlined>
${ msg }</wa-badge>`).join(' ');
}
}
}
}
updateTheme();
</script>

View File

@@ -1,12 +1,6 @@
import { getCode } from '/assets/scripts/remix.js';
import Prism from '/assets/scripts/prism.js';
import { cdnUrl, getThemeCode, Permalink } from '/assets/scripts/tweak.js';
await Promise.all(['wa-select', 'wa-option', 'wa-details'].map(tag => customElements.whenDefined(tag)));
globalThis.Prism = globalThis.Prism || {};
globalThis.Prism.manual = true;
await import('/assets/scripts/prism.js');
Prism.plugins.customClass.prefix('code-');
const cdnUrl = document.documentElement.dataset.cdnUrl;
const domChange = document.startViewTransition ? document.startViewTransition.bind(document) : fn => fn();
@@ -57,17 +51,11 @@ function init() {
typography: '',
},
params: { colors: '', palette: '', brand: '', typography: '' },
urlParams: new URLSearchParams(location.search),
urlParams: new Permalink(),
};
// Read URL params and apply them. This facilitates permalinks.
if (location.search) {
for (let aspect in data.params) {
if (data.urlParams.has(aspect)) {
data.params[aspect] = data.urlParams.get(aspect);
}
}
}
data.urlParams.mapObject(data.params);
data.urlParams.writeTo(data.params);
if (computed.isRemixed) {
// Start with the remixing UI open if the theme has been remixed
@@ -119,6 +107,10 @@ function setDefault(select, value) {
}
function render(changedAspect) {
if (!globalThis.demo) {
return;
}
let url = new URL(demo.src);
if (!changedAspect || changedAspect === 'colors') {
@@ -133,16 +125,11 @@ function render(changedAspect) {
for (let aspect in data.params) {
let value = data.params[aspect];
if (value) {
data.urlParams.set(aspect, value);
} else {
data.urlParams.delete(aspect);
}
selects[aspect].value = value;
}
data.urlParams.readFrom(data.params);
// Update demo URL
domChange(() => {
url.search = data.urlParams;
@@ -150,18 +137,14 @@ function render(changedAspect) {
return new Promise(resolve => (demo.onload = resolve));
});
// Update page URL. If theres already a search, replace it.
// We dont want to clog the users history while they iterate
let historyAction = location.search ? 'replaceState' : 'pushState';
history[historyAction](null, '', `?${data.urlParams}`);
// Update page URL
data.urlParams.updateLocation();
// Update code snippets
for (let language in codeSnippets) {
let codeSnippet = codeSnippets[language];
let copyButton = codeSnippet.previousElementSibling;
let code = getCode(data.baseTheme, data.params, { language, cdnUrl });
let code = getThemeCode(data.baseTheme, data.params, { language, cdnUrl });
codeSnippet.textContent = code;
copyButton.value = code;
Prism.highlightElement(codeSnippet);
}
}

View File

@@ -12,6 +12,11 @@ body,
#mix_and_match {
font-weight: var(--wa-font-weight-semibold);
color: var(--wa-color-text-quiet);
margin-block-end: var(--wa-space-xs);
html:not(.is-remixed) {
display: none;
}
wa-icon {
vertical-align: -0.15em;

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@shoelace-style/webawesome",
"version": "3.0.0-alpha.10",
"version": "3.0.0-alpha.11",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@shoelace-style/webawesome",
"version": "3.0.0-alpha.10",
"version": "3.0.0-alpha.11",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",

View File

@@ -1,7 +1,7 @@
{
"name": "@shoelace-style/webawesome",
"description": "A forward-thinking library of web components.",
"version": "3.0.0-alpha.10",
"version": "3.0.0-alpha.11",
"homepage": "https://webawesome.com/",
"author": "Web Awesome",
"license": "MIT",

View File

@@ -52,6 +52,7 @@ import styles from './button.css';
@customElement('wa-button')
export default class WaButton extends WebAwesomeFormAssociatedElement {
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
static rectProxy = 'button';
static get validators() {
return [...super.validators, MirrorValidator()];
@@ -224,17 +225,6 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
this.button.blur();
}
getBoundingClientRect(): DOMRect {
let rect = super.getBoundingClientRect();
let buttonRect = this.button.getBoundingClientRect();
if (rect.width === 0 && buttonRect.width > 0) {
return buttonRect;
}
return rect;
}
render() {
const isLink = this.isLink();
const tag = isLink ? literal`a` : literal`button`;

View File

@@ -127,7 +127,7 @@ export default class WaCheckbox extends WebAwesomeFormAssociatedElement {
@property({ type: Boolean, reflect: true }) required = false;
/** The checkbox's hint. If you need to display HTML, use the `hint` slot instead. */
@property({ attribute: 'hint' }) hint = '';
@property() hint = '';
private handleClick() {
this.hasInteracted = true;

View File

@@ -278,11 +278,11 @@
}
/*
* Color dropdown
*/
* Color dropdown
*/
.color-dropdown {
display: flex;
display: contents;
}
.color-dropdown::part(panel) {

View File

@@ -55,12 +55,6 @@ details {
padding-block-start: var(--spacing);
}
.show {
}
.hide {
}
@keyframes show {
from {
}

View File

@@ -1,5 +1,8 @@
:host {
--background-color-hover: var(--wa-color-neutral-fill-quiet);
--text-color-hover: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
--background-color-active: transparent;
--text-color-active: color-mix(in oklab, currentColor, var(--wa-color-mix-active));
display: inline-block;
color: var(--wa-color-text-quiet);
@@ -22,12 +25,13 @@
:host(:not([disabled])) .icon-button:hover,
:host(:not([disabled])) .icon-button:focus-visible {
background-color: var(--wa-color-neutral-fill-quiet);
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
background-color: var(--background-color-hover);
color: var(--text-color-hover);
}
:host(:not([disabled])) .icon-button:active {
color: color-mix(in oklab, currentColor, var(--wa-color-mix-active));
background-color: var(--background-color-active);
color: var(--text-color-active);
}
.icon-button:focus {

View File

@@ -17,7 +17,10 @@ import styles from './icon-button.css';
* @event blur - Emitted when the icon button loses focus.
* @event focus - Emitted when the icon button gains focus.
*
* @cssproperty --background-color-hover - The color of the button's background on hover.
* @cssproperty [--background-color-hover=var(--wa-color-neutral-fill-quiet)] - The color of the button's background on hover.
* @cssproperty [--background-color-active=var(--wa-color-neutral-fill-quiet)] - The color of the button's background on `:active`.
* @cssproperty --text-color-hover - The color of the button's background on hover.
* @cssproperty --text-color-active - The color of the button's background on `:active`.
*
* @csspart base - The component's base wrapper.
*/

View File

@@ -9,7 +9,7 @@
--banner-height: 0px;
--header-height: 0px;
--subheader-height: 0px;
--scroll-margin-top: calc(var(--header-height, 0px) + var(--subheader-height, 0px));
--scroll-margin-top: calc(var(--header-height, 0px) + var(--subheader-height, 0px) + 0.5em);
}
slot[name]:not([name='skip-to-content'], [name='navigation-toggle'])::slotted(*) {

View File

@@ -50,6 +50,7 @@ import styles from './radio-button.css';
@customElement('wa-radio-button')
export default class WaRadioButton extends WebAwesomeFormAssociatedElement {
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, buttonStyles, styles];
static rectProxy = 'input';
private readonly hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix');

View File

@@ -1,15 +1,15 @@
:host(:focus-visible) {
outline: none;
}
.radio {
display: flex;
:host {
display: grid;
grid-template-columns: auto 1fr;
align-items: top;
font: inherit;
vertical-align: middle;
cursor: pointer;
}
:host(:focus-visible) {
outline: none;
}
.checked-icon {
display: flex;
fill: currentColor;
@@ -19,6 +19,11 @@
}
/* When the control isn't checked, hide the circle for Windows High Contrast mode a11y */
.radio:not(.radio--checked) svg circle {
:host(:not(:state(checked))) svg circle {
opacity: 0;
}
[part~='hint'] {
grid-column: 2;
margin-block-start: var(--wa-space-3xs);
}

View File

@@ -1,9 +1,11 @@
import type { PropertyValues } from 'lit';
import { html, isServer } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { watch } from '../../internal/watch.js';
import { HasSlotController } from '../../internal/slot.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import nativeStyles from '../../styles/native/radio.css';
import formControlStyles from '../../styles/shadow/form-control.css';
import sizeStyles from '../../styles/utilities/size.css';
import '../icon/icon.js';
import styles from './radio.css';
@@ -17,14 +19,15 @@ import styles from './radio.css';
* @dependency wa-icon
*
* @slot - The radio's label.
* @slot hint - Text that describes how to use the checkbox. Alternatively, you can use the `hint` attribute.
*
* @event blur - Emitted when the control loses focus.
* @event focus - Emitted when the control gains focus.
*
* @csspart base - The component's base wrapper.
* @csspart control - The circular container that wraps the radio's checked state.
* @csspart checked-icon - The checked icon.
* @csspart label - The container that wraps the radio's label.
* @csspart hint - The hint's wrapper.
*
* @cssproperty --background-color - The radio's background color.
* @cssproperty --background-color-checked - The radio's background color when checked.
@@ -42,7 +45,7 @@ import styles from './radio.css';
*/
@customElement('wa-radio')
export default class WaRadio extends WebAwesomeFormAssociatedElement {
static shadowStyle = [sizeStyles, nativeStyles, styles];
static shadowStyle = [formControlStyles, sizeStyles, nativeStyles, styles];
@state() checked = false;
@@ -63,6 +66,11 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement {
/** Disables the radio. */
@property({ type: Boolean }) disabled = false;
/** The radio's hint. If you need to display HTML, use the `hint` slot instead. */
@property() hint = '';
private readonly hasSlotController = new HasSlotController(this, 'hint');
constructor() {
super();
if (!isServer) {
@@ -81,11 +89,19 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement {
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
@watch('checked')
handleCheckedChange() {
this.toggleCustomState('checked', this.checked);
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
this.tabIndex = this.checked ? 0 : -1;
updated(changedProperties: PropertyValues<this>) {
super.updated(changedProperties);
if (changedProperties.has('checked')) {
this.toggleCustomState('checked', this.checked);
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
this.tabIndex = this.checked ? 0 : -1;
}
if (changedProperties.has('disabled')) {
this.toggleCustomState('disabled', this.disabled);
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
}
/**
@@ -95,12 +111,6 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement {
// We override `setValue` because we don't want to set form values from here. We want to do that in "RadioGroup" itself.
}
@watch('disabled', { waitUntilFirstUpdate: true })
handleDisabledChange() {
this.toggleCustomState('disabled', this.disabled);
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
private handleClick = () => {
if (!this.disabled) {
this.checked = true;
@@ -108,26 +118,30 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement {
};
render() {
return html`
<span
part="base"
class=${classMap({
radio: true,
'radio--checked': this.checked,
})}
>
<span part="control" class="control">
${this.checked
? html`
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" part="checked-icon" class="checked-icon">
<circle cx="8" cy="8" r="8" />
</svg>
`
: ''}
</span>
const hasHintSlot = isServer ? true : this.hasSlotController.test('hint');
const hasHint = this.hint ? true : !!hasHintSlot;
<slot part="label" class="label"></slot>
return html`
<span part="control" class="control">
${this.checked
? html`
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" part="checked-icon" class="checked-icon">
<circle cx="8" cy="8" r="8" />
</svg>
`
: ''}
</span>
<slot part="label" class="label"></slot>
<slot
name="hint"
aria-hidden=${hasHint ? 'false' : 'true'}
class="${classMap({ 'has-slotted': hasHint })}"
id="hint"
part="hint"
>${this.hint}</slot
>
`;
}
}

View File

@@ -177,7 +177,7 @@
align-items: center;
color: var(--wa-color-neutral-on-quiet);
transition: rotate var(--wa-transition-slow) ease;
rotate: 0;
rotate: 0deg;
margin-inline-start: var(--wa-space-s);
.open & {
@@ -194,7 +194,7 @@
background: var(--wa-color-surface-raised);
border-color: var(--wa-color-surface-border);
border-radius: var(--wa-border-radius-m);
border-style: var(--border-style);
border-style: var(--wa-border-style);
border-width: var(--border-width);
padding-block: var(--wa-space-xs);
padding-inline: 0;
@@ -208,13 +208,13 @@
&::slotted(wa-divider) {
--spacing: var(--wa-space-xs);
}
&::slotted(small) {
display: block;
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-semibold);
color: var(--wa-color-text-quiet);
padding-block: var(--wa-space-xs);
padding-inline: var(--wa-space-xl);
}
}
slot:not([name])::slotted(small) {
display: block;
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-semibold);
color: var(--wa-color-text-quiet);
padding-block: var(--wa-space-xs);
padding-inline: var(--wa-space-xl);
}

View File

@@ -647,6 +647,7 @@ describe('<wa-select>', () => {
);
const el = form.querySelector<WaSelect>('wa-select')!;
expect(el.defaultValue).to.equal('option-1');
expect(el.value).to.equal('');
expect(new FormData(form).get('select')).equal('');
@@ -657,6 +658,7 @@ describe('<wa-select>', () => {
await aTimeout(10);
await el.updateComplete;
expect(el.optionValues ? [...el.optionValues] : []).to.have.members(['option-1']);
expect(el.value).to.equal('option-1');
expect(new FormData(form).get('select')).equal('option-1');
});
@@ -745,6 +747,8 @@ describe('<wa-select>', () => {
);
const el = form.querySelector<WaSelect>('wa-select')!;
expect(el.optionValues ? [...el.optionValues] : []).to.have.members(['bar', 'baz']);
expect(el.optionValues?.size).to.equal(2);
expect(el.value).to.have.members(['bar', 'baz']);
expect(el.value!.length).to.equal(2);
expect(new FormData(form).getAll('select')).to.have.members(['bar', 'baz']);
@@ -760,6 +764,36 @@ describe('<wa-select>', () => {
expect(new FormData(form).getAll('select')).to.have.members(['foo', 'bar', 'baz']);
});
});
describe('With setting the value via JS', () => {
it('Should preserve value even if not returned', async () => {
const form = await fixture<HTMLFormElement>(
html` <form>
<wa-select name="select">
<wa-option value="bar">Bar</wa-option>
<wa-option value="baz">Baz</wa-option>
</wa-select>
</form>`,
);
const el = form.querySelector<WaSelect>('wa-select')!;
expect(el.value).to.equal('');
el.value = 'foo';
await aTimeout(10);
await el.updateComplete;
expect(el.value).to.equal('');
const option = document.createElement('wa-option');
option.value = 'foo';
option.innerText = 'Foo';
el.append(option);
await aTimeout(10);
await el.updateComplete;
expect(el.value).to.equal('foo');
});
});
});
});
}

View File

@@ -118,6 +118,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
@state() displayLabel = '';
@state() currentOption: WaOption;
@state() selectedOptions: WaOption[] = [];
@state() optionValues: Set<string> | undefined;
/** The name of the select, submitted as a name/value pair with form data. */
@property() name = '';
@@ -158,7 +159,47 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
return val;
}
@property({ attribute: false }) value: string | string[] | null = null;
private _value: string[] | undefined;
@property({ attribute: false })
set value(val: string | string[]) {
let oldValue = this.value;
if (!Array.isArray(val)) {
val = val.split(' ');
}
if (!this._value || this._value.join(' ') !== val.join(' ')) {
this._value = val;
let newValue = this.value;
if (newValue != oldValue) {
this.requestUpdate('value', oldValue);
}
}
}
get value() {
let value = this._value ?? this.defaultValue;
value = Array.isArray(value) ? value : [value];
let optionsChanged = !this.optionValues;
if (optionsChanged) {
this.optionValues = new Set(
this.getAllOptions()
.filter(option => !option.disabled)
.map(option => option.value),
);
}
// Drop values not in the DOM
let ret: string | string[] = value.filter(v => this.optionValues!.has(v));
ret = this.multiple ? ret : (ret[0] ?? '');
if (optionsChanged) {
this.requestUpdate('value');
}
return ret;
}
/** The select's size. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@@ -538,12 +579,9 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
}
const allOptions = this.getAllOptions();
const val = this.valueHasChanged ? this.value : this.defaultValue;
const value = Array.isArray(val) ? val : [val];
const values: string[] = [];
this.optionValues = undefined; // dirty the value so it gets recalculated
// Check for duplicate values in menu items
allOptions.forEach(option => values.push(option.value));
const value = this.value;
// Select only the options that match the new value
this.setSelectedOptions(allOptions.filter(el => value.includes(el.value)));
@@ -565,6 +603,9 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
// Gets an array of all `<wa-option>` elements
private getAllOptions() {
if (!this?.querySelectorAll) {
return [];
}
return [...this.querySelectorAll<WaOption>('wa-option')];
}
@@ -628,11 +669,24 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
// Update selected options cache
this.selectedOptions = options.filter(el => el.selected);
let selectedValues = new Set(this.selectedOptions.map(el => el.value));
// Toggle values present in the DOM from this.value, while preserving options NOT present in the DOM (for lazy loading)
// Note that options NOT present in the DOM will be moved to the end after this
if (selectedValues.size > 0 || this._value) {
if (!this._value) {
// First time it's set
let value = this.defaultValue ?? [];
this._value = Array.isArray(value) ? value : [value];
}
// Filter out values that are in the DOM
this._value = this._value.filter(value => !this.optionValues?.has(value));
this._value.unshift(...selectedValues);
}
// Update the value and display label
if (this.multiple) {
this.value = this.selectedOptions.map(el => el.value);
if (this.placeholder && this.value.length === 0) {
// When no items are selected, keep the value empty so the placeholder shows
this.displayLabel = '';
@@ -641,7 +695,6 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
}
} else {
const selectedOption = this.selectedOptions[0];
this.value = selectedOption?.value ?? '';
this.displayLabel = selectedOption?.label ?? '';
}
@@ -927,6 +980,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
</div>
<slot
id="hint"
name="hint"
part="hint"
class=${classMap({

View File

@@ -49,6 +49,7 @@ import styles from './switch.css';
*/
@customElement('wa-switch')
export default class WaSwitch extends WebAwesomeFormAssociatedElement {
static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true };
static shadowStyle = [formControlStyles, sizeStyles, styles];
static get validators() {

View File

@@ -24,7 +24,6 @@ let id = 0;
@customElement('wa-tab')
export default class WaTab extends WebAwesomeElement {
static shadowStyle = styles;
public slot = 'nav'; // Auto-slot into nav slot
private readonly attrId = ++id;
private readonly componentId = `wa-tab-${this.attrId}`;
@@ -47,6 +46,9 @@ export default class WaTab extends WebAwesomeElement {
@property({ type: Number, reflect: true }) tabIndex = 0;
connectedCallback() {
// Auto-slot into nav slot
this.slot ||= 'nav';
super.connectedCallback();
this.setAttribute('role', 'tab');
}

View File

@@ -4,10 +4,16 @@
--max-width: 30ch;
--padding: var(--wa-space-2xs) var(--wa-space-xs);
/** These styles are added so we don't interfere in the DOM. */
display: inline-block;
position: absolute;
/** These styles are added so we dont interfere in the DOM. */
/** Defaults for inherited CSS properties */
color: var(--wa-tooltip-content-color);
font-size: var(--wa-tooltip-font-size);
line-height: var(--wa-tooltip-line-height);
text-align: start;
white-space: normal;
}
.tooltip {
@@ -41,12 +47,6 @@
max-width: var(--max-width);
border-radius: var(--border-radius);
background-color: var(--background-color);
font: inherit;
color: var(--wa-tooltip-content-color);
font-size: var(--wa-tooltip-font-size);
line-height: var(--wa-tooltip-line-height);
text-align: start;
white-space: normal;
padding: var(--padding);
user-select: none;
-webkit-user-select: none;

View File

@@ -35,11 +35,8 @@ import styles from './tooltip.css';
*
* @cssproperty --background-color - The tooltip's background color.
* @cssproperty --border-radius - The radius of the tooltip's corners.
* @cssproperty --text-color - The color of the tooltip's content.
* @cssproperty --max-width - The maximum width of the tooltip before its content will wrap.
* @cssproperty --padding - The padding within the tooltip.
* @cssproperty --hide-delay - The amount of time to wait before hiding the tooltip when hovering.
* @cssproperty --show-delay - The amount of time to wait before showing the tooltip when hovering.
*/
@customElement('wa-tooltip')
export default class WaTooltip extends WebAwesomeElement {

View File

@@ -204,6 +204,32 @@ export default class WebAwesomeElement extends LitElement {
);
}
getBoundingClientRect(): DOMRect {
let rect = super.getBoundingClientRect();
if (rect.width === 0 && rect.height === 0) {
let Self = this.constructor as typeof WebAwesomeElement;
if (Self.rectProxy) {
let element = this[Self.rectProxy as keyof this];
if (element instanceof Element) {
let childRect = element.getBoundingClientRect();
if (childRect.width > 0 || childRect.height > 0) {
return childRect;
}
}
}
}
return rect;
}
/**
* If getBoundingClientRect() returns an empty rect,
* should we check another element?
*/
static rectProxy: undefined | string;
static createProperty(name: PropertyKey, options?: PropertyDeclaration): void {
if (options) {
if (options.initial !== undefined && options.default === undefined) {

View File

@@ -1,7 +1,8 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
:where([class^='wa-palette-'], [class*=' wa-palette-']),
.wa-brand-blue {
--wa-color-brand-95: var(--wa-color-blue-95);
--wa-color-brand-90: var(--wa-color-blue-90);
--wa-color-brand-80: var(--wa-color-blue-80);
@@ -14,5 +15,22 @@
--wa-color-brand-10: var(--wa-color-blue-10);
--wa-color-brand-05: var(--wa-color-blue-05);
--wa-color-brand: var(--wa-color-blue);
--wa-color-brand-key: var(--wa-color-blue-key);
--wa-color-brand-lt-50: var(--wa-color-blue-lt-50);
--wa-color-brand-gte-50: var(--wa-color-blue-gte-50);
--wa-color-brand-lt-60: var(--wa-color-blue-lt-60);
--wa-color-brand-gte-60: var(--wa-color-blue-gte-60);
--wa-color-brand-lt-70: var(--wa-color-blue-lt-70);
--wa-color-brand-gte-70: var(--wa-color-blue-gte-70);
--wa-color-brand-max-50: var(--wa-color-blue-max-50);
--wa-color-brand-min-50: var(--wa-color-blue-min-50);
--wa-color-brand-max-60: var(--wa-color-blue-max-60);
--wa-color-brand-min-60: var(--wa-color-blue-min-60);
--wa-color-brand-max-70: var(--wa-color-blue-max-70);
--wa-color-brand-min-70: var(--wa-color-blue-min-70);
--wa-color-brand-on: var(--wa-color-blue-on);
}

View File

@@ -1,7 +1,8 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
:where([class^='wa-palette-'], [class*=' wa-palette-']),
.wa-brand-cyan {
--wa-color-brand-95: var(--wa-color-cyan-95);
--wa-color-brand-90: var(--wa-color-cyan-90);
--wa-color-brand-80: var(--wa-color-cyan-80);
@@ -14,5 +15,22 @@
--wa-color-brand-10: var(--wa-color-cyan-10);
--wa-color-brand-05: var(--wa-color-cyan-05);
--wa-color-brand: var(--wa-color-cyan);
--wa-color-brand-key: var(--wa-color-cyan-key);
--wa-color-brand-lt-50: var(--wa-color-cyan-lt-50);
--wa-color-brand-gte-50: var(--wa-color-cyan-gte-50);
--wa-color-brand-lt-60: var(--wa-color-cyan-lt-60);
--wa-color-brand-gte-60: var(--wa-color-cyan-gte-60);
--wa-color-brand-lt-70: var(--wa-color-cyan-lt-70);
--wa-color-brand-gte-70: var(--wa-color-cyan-gte-70);
--wa-color-brand-max-50: var(--wa-color-cyan-max-50);
--wa-color-brand-min-50: var(--wa-color-cyan-min-50);
--wa-color-brand-max-60: var(--wa-color-cyan-max-60);
--wa-color-brand-min-60: var(--wa-color-cyan-min-60);
--wa-color-brand-max-70: var(--wa-color-cyan-max-70);
--wa-color-brand-min-70: var(--wa-color-cyan-min-70);
--wa-color-brand-on: var(--wa-color-cyan-on);
}

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