Compare commits

..

359 Commits

Author SHA1 Message Date
Cory LaViska
e019dcbeb0 fix type 2025-10-13 10:58:14 -04:00
Cory LaViska
f398899991 update changelog (#1570) 2025-10-13 10:47:43 -04:00
LX
8fc0ee89ff Fix missing form-control-label part on texarea (#1533) 2025-10-13 10:45:39 -04:00
trent
ed17964f10 remove unsupported tag ‘plain’ appearance visual test (#1519) 2025-10-13 10:43:55 -04:00
Jean-Baptiste Muscat
64ce424c42 Document code completion setup for Web Awesome (#1550)
* Document code completion setup for Web Awesome

Added instructions for enabling code completion in VS Code and JetBrains IDEs for Web Awesome components.

This mirror what already exist for Shoelace: https://shoelace.style/getting-started/usage#code-completion
+ a new line to explain how to setup VS Code completion from the CDN

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-10-13 10:43:16 -04:00
Jason Polete
51253650e1 Fix wa-details accordion behavior in react (#1538)
* fix wa-details accordion in react (#1534)

* Update packages/webawesome/src/components/details/details.test.ts

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>

* Remove unused import

* Fix unintended indent

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-10-13 10:40:35 -04:00
Leon Vogt
0b45173192 Enhance icon button label check (#1543) 2025-10-13 10:39:29 -04:00
Konnor Rogers
0eb8eaea00 add versions.txt (#1546) 2025-10-03 23:42:31 -04:00
Brian Talbot
334e3361b4 Docs: Add Planned Features to Navigation (#1539)
* adding plannedBadge() macro + planned-badge.njk

* adding planned features to sidebar.njk

* adding .icon-shrink utility to utils.css

* using icon-shrink on sidebar's experimental iconography

* revising proBadge macro

* defining params in a more clear manner
* adding shrink param to visually reduce badge size

* setting proBadge to shrink in sidebar.njk

* addressing PR feedback

* reverting proBadge shrink param

* revisiting pro + sidebar wa-badge styling

* removing text-transform from pro badge
* scaling down sidebar-based wa-badges using 1 step below
--wa-font-size-scale
2025-10-03 17:34:52 -04:00
Brian Talbot
5e482739a9 updating Home view to support purchasing Pro (#1528) 2025-10-03 12:56:05 -04:00
Lindsay M
c0b18f6580 Round --content-width-* and use in the docs (#1526)
* use `--content-width-*` properties for docs

* round `--content-width-*` values to prevent rendering bugs
2025-10-02 16:13:05 -04:00
Brian Talbot
c18df17429 Docs: Add Links to Licenses + Supporting Utilities (#1537)
* adding .appearance-plain for lists to utils.css

* adding gitLastModifiedISO filter to .eleventy.js

* adding link to Pro License in sidebar.njk

* adding link to Free License in sidebar.njk

* adding link to Terms of Service in sidebar.njk

* adding "last updated" date to changelog.md
2025-10-02 15:46:32 -04:00
Brian Talbot
2ec957ff76 Docs: Update + Show Social Media Links (#1531)
* adding mastodon social link to docs/index.md
* adding social links to sidebar's colophon
* updating community.md with latest social network details
2025-10-01 12:04:32 -04:00
Lindsay M
1fd68dfb3c Fix focus ring in <wa-scroller>, <wa-dialog>, and <wa-drawer> (#1525)
* visible focus outlines for scrollable containers

* add changelog
2025-09-30 18:09:58 -04:00
randomguy-2650
0b5689de62 remove last smart quote (forgotten in previous PR) (#1523) 2025-09-30 12:26:38 -04:00
Konnor Rogers
8ffd9991db Fix 11ty / server handoff for Brian (#1518)
* update for brian's stuff
* change to top level
2025-09-30 11:29:52 -04:00
Cory LaViska
566f98359c fix name (#1522) 2025-09-30 10:03:40 -04:00
randomguy-2650
6387dffe75 Make the README better (#1494)
* Make the README better

• Replace straight quotes with smart quotes
• Revise Node.js minimum requirement wording (to prevent line breaks)
• Replace old links to LitElement (Polymer) to Lit
• Replace mentions of “NPM” with “npm”, as per https://github.com/npm/cli?tab=readme-ov-file#is-it-npm-or-npm-or-npm
• Fix some grammar and abbreviations
• Made “dependencies” and “devDependencies” mentions unquoted to be consistent
• Correct “MIT license” with “MIT License”, as per https://opensource.org/license/mit

* Make some specific changes to make wording more clear

* add missing dot

* remove smart quotes
2025-09-29 12:32:58 -04:00
randomguy-2650
bb747d50dd Add missing CSS part into JSDoc (Dialog, Drawer) (#1515)
* add missing CSS part into JSDoc

* add missing CSS part into JSDoc
2025-09-29 12:12:08 -04:00
Brian Talbot
2704ef7197 Docs: Polish Pro Badge (#1504)
* updating Pro Badge's appearance
* abstracting Pro Badge into include
* adding nanoid-based uniqueId filter to eleventyConfig
* ensuring Pro Badge instances have unique ids
* using added uniqueId filter + nanoid
* converting Pro Badge to be macro-based
* customizing Pro Badge's associated wa-tooltip size
2025-09-29 11:59:49 -04:00
Brian Talbot
336a3acdd0 Docs: Add Shared Monorepo Utils + DRY Out Styling (#1497)
* adding utils.css
* importing utils.css in docs.css
* removing shared styles now in utils.css
* using hover-icon util in toggle navigation
* updating hover-icon a11y in header
* revising wa-icon embiggening utility
2025-09-26 14:35:19 -04:00
Cory LaViska
e68640b8ca update changelog (#1500) 2025-09-25 16:30:24 -04:00
Adilet
487b629995 Add Kazakh translation (#1496)
* Add Kazakh translation

* Fix kk.ts translation entry
2025-09-25 14:56:45 -04:00
Brian Talbot
255647d2a9 fixing theme.js logic (#1492)
* to adhere to original work in talbs/update-theme-logic
* to also account for work in talbs/update-header
2025-09-25 10:55:40 -04:00
Brian Talbot
53f1b3615d Docs: Update Theme Logic (#1491)
* updating theme.js to handle static site theme
* removing redundant theme logic from base.njk
2025-09-24 17:10:19 -04:00
Brian Talbot
d00d8bac4e Docs: Update Header (#1490)
* updating color-scheme-selectors and theme-selectors
* abstracting repo links into github-icon-buttons
* adjusting responsive logo treatment
* moving version + beta info to sidebar
* removing unused + outdated header styling
* adding brand logo to sidebar
* updating `.brand-logo` styling
* abstracting search-trigger-button
2025-09-24 16:39:01 -04:00
Konnor Rogers
87864924e1 fix auto width typing (#1482) 2025-09-24 13:48:04 -04:00
randomguy-2650
ce3496a621 Improve contributing page (#1443)
* add `@customElement()` decorator

• Hope this doesn’t ping some random user

* replace “->” with “→”
2025-09-24 13:47:45 -04:00
Brian Talbot
cf80b57a79 Update Layouts to Prep for Site Assets (#1470)
* syncing up `<body>` classes on blank.njk
* using `wa_page_attributes` block instead of `pageType`
* using `head` block instead of `pageType`
* removing `pageType` from `<body>` classes
* removing `pageType` from eleventyConfig
* updating color-scheme-selector's icons
* allowing `wa-page` attributes to override those set in base.njk
* allowing pageClass to be used on base.njk's `<body>`
2025-09-22 19:06:54 -04:00
Lindsay M
694a9eccb9 Make sure essential CSS is always imported (#1476)
* import relevant utilities into native styles

* import color variant classes into free palettes

* import the default palette into kitchen sink, not the default theme

* fix palette path

* import each theme's intended palette
2025-09-22 14:12:49 -04:00
Alicia Garcia-Raboso
502df6ee9c Remove duplicated declaration (#1473) 2025-09-19 09:43:57 -04:00
Lindsay M
44142fb56d Fix badge positioning for link buttons (#1463)
* Fix badge positioning for link buttons

* add changelog
2025-09-18 11:53:52 -04:00
Lindsay M
7e00d2b02e Fix incorrect class in color palette instructions (#1462) 2025-09-18 11:16:36 -04:00
Lindsay M
fcf37f83a1 Fix details focus ring (#1464)
* remove duplicate styles, fix focus outline

* update native details focus ring and rounding
2025-09-18 11:15:54 -04:00
Kelsey Jackson
0beceff73f update to the button if it has an icon in it's default slot (#1461) 2025-09-18 08:42:38 -05:00
Brian Talbot
afe60eae69 Docs: Icon Component - Update Default Width (#1466)
* updating default width value in icon component docs
* noting default icon width change in 3.0.0-beta.5's changelog
2025-09-18 09:33:09 -04:00
Bryce A. Glass
b4f45f4ff1 Update align-items.md (#1467)
Fixed some internal links from `/docs/layout/` to `docs/utilities/`
2025-09-18 08:50:37 -04:00
Brian Talbot
fd4cded708 Add Input-Based Visually Hidden Utilities (#1454)
* adding input-based visually hidden utilities
* documenting input-based visually hidden utilities
2025-09-16 09:17:07 -04:00
konnorrogers
4b2b72e822 update package-lock version 2025-09-15 19:13:18 -04:00
konnorrogers
56657ebcfc Bump package.json version 2025-09-15 19:11:14 -04:00
Konnor Rogers
844015df7b pin tinycolor (#1455) 2025-09-15 19:08:05 -04:00
Brian Talbot
d5da2e2db5 simplifying pageHeader/pageFooter overrides in base.njk (#1453) 2025-09-15 16:42:09 -04:00
randomguy-2650
efbc404524 add variant="danger" to Delete dropdown item (#1445) 2025-09-15 09:34:09 -04:00
randomguy-2650
b6afa148ae fix typo (#1442) 2025-09-15 09:29:53 -04:00
randomguy-2650
7c3795897c Fix typo in Textarea docs (#1444)
* fix typo

* Update packages/webawesome/docs/docs/components/textarea.md

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-09-13 09:59:48 -04:00
Cory LaViska
986e52f977 make event cancelable (#1434) 2025-09-11 11:55:35 -04:00
konnorrogers
6dce88429a Bump changelog
Bump package.json version

update lockfile
2025-09-10 12:45:43 -04:00
Kelsey Jackson
04497cfd13 Add horizontal orientation to <wa-card> (#874)
* started horizontal card logic

* a little more work

* remove SSR attributes

These are no longer used since we're not serving up an SSR version of the website anymore.

* more work

* looking for old code

* added actions slot to horizontal card

* troubleshooting linter issue

* fixed liniting error

* responded to feedback

* added jsDoc and updated example

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-09-10 10:27:15 -05:00
randomguy-2650
75116a5b0c Replace invisible BOM marker in Dialog/Drawer with a zero‐width space (#1410)
* replace BOM marker with a zero‐width space

* replace BOM marker with a zero‐width space
2025-09-10 11:06:15 -04:00
Cory LaViska
5e192023b4 reword (#1427) 2025-09-10 11:05:53 -04:00
Brian Talbot
26b29189db fixing GitHub discussion links to point to webawesome project (#1425) 2025-09-10 10:53:38 -04:00
trent
ac20e495d9 allow bundlers access to package.json (#1415) 2025-09-10 10:53:17 -04:00
Cory LaViska
4ac31e06f3 remove whitespace; closes #1417 (#1418) 2025-09-10 10:38:06 -04:00
Konnor Rogers
4993b1034f add notes about skips (#1419)
* add notes about skips

* prettier

* re-add support for 'unpublished: true'

* prettier
2025-09-10 10:32:48 -04:00
Cory LaViska
b3b93091f7 Add intersection observer component (#1406)
* add intersection observer component

* remove prefix

* update description
2025-09-08 17:22:45 -04:00
Brian Talbot
8cf20d9938 Docs: Fix Color Swatch Hover States (#1407)
* removing unused `--background-color-hover` from `docs.css`
* fixing `.swatch` hover-based `background-color`
* linting + formatting `docs/tokens/color.md`
2025-09-05 16:30:15 -04:00
randomguy-2650
63296b7ed5 update FA version from 7.0.0 to 7.0.1 (#1399) 2025-09-03 15:01:35 -04:00
Brian Talbot
0e56ed0cbb Prep for Pro + Product Marketing (#1390)
* adding conditional header + footer includes to `base.njk`

- support for custom headers via `header` front matter variable
- support for custom footers via `footer` front matter variable
- backward compatibility with default header

* revising `base.njk`'s body classes

* adding fileSlug-based class to body
* adding pageType-based class (default `docs`) to body

* adding conditional CSS asset logic to `base.njk`

* to load marketing-based CSS based on pageType
* to load docs-based CSS by default

* disabling wa-page's sticky header for marketing pageType
2025-09-03 12:37:28 -04:00
Cory LaViska
e70cb5c66d add changelog entry (#1398) 2025-09-03 08:13:55 -04:00
Michael Romer
913abd0db1 Reflect icon properties to its attributes (#1395) 2025-09-03 08:12:11 -04:00
Cory LaViska
d2798a96da flip color picker to keep it in the viewport (#1391) 2025-09-02 18:02:48 -04:00
Konnor Rogers
42729153db update vercel sh clone (#1392) 2025-09-02 17:52:25 -04:00
Cory LaViska
c2df5ca1ea fix typo (#1381) 2025-08-29 11:34:48 -04:00
Cory LaViska
c49813c7c1 Update themer to use bunny fonts instead of google fonts (#1378)
* use fonts.bunny.net for web fonts

* use bunny
2025-08-27 19:24:44 +00:00
Cory LaViska
f63dfbfff0 fix var name (#1372) 2025-08-25 16:17:58 -04:00
Cory LaViska
9a7947debd fix radio group styles; closes #1178 (#1360) 2025-08-25 14:30:59 -04:00
Cory LaViska
d2e1653519 fix value assignment; closes #1323 (#1368) 2025-08-25 12:35:34 -04:00
Cory LaViska
5b7004e72d Fix edge case where interactive elements inside <wa-details> would cause it to open/close (#1350)
* fixes #1252

* fixes #1250

* update changelog
2025-08-25 11:08:36 -04:00
Lindsay M
7ccfed9e93 Use FA7 icons in native styles (#1362)
* replace icons with FA7 paths

* replace details icon
2025-08-22 10:47:12 -04:00
Lindsay M
4f1de3918b Fix button positioning for real (#1361) 2025-08-21 18:00:09 -04:00
Konnor Rogers
adaea2fa5f fix wa-page fallback loading in free repo (#1359) 2025-08-21 14:12:39 -04:00
Lindsay M
e016e4bd48 Fix home page icons (#1358) 2025-08-21 13:29:09 -04:00
Cory LaViska
5e0b5f3fe6 update system icon view boxes (#1357) 2025-08-21 11:46:09 -04:00
Cory LaViska
493e1c06b9 Fixes spacing between clear and password toggle icons in <wa-input> (#1351)
* fixes spacing between icons; closes #1325

* use form control padding token

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-08-21 11:35:05 -04:00
Konnor Rogers
8b763d0392 remove page (#1352) 2025-08-20 17:45:28 -04:00
Brian Talbot
9d82749abb 💅 Docs: Sidebar Visual + UI Polish (#1341)
* using layout utilities for sidebar heading link styling
* syncing up sidebar heading + general link styles
* updating sidebar heading text + icon alignment
* updating layout of experimental + pro badge decoratives
* increasing visual padding of `#search-trigger`'s `<kbd>`
* fixing `<li>` indentations
2025-08-20 17:24:36 -04:00
Lindsay M
3e3e5276a6 Apply position: relative only to buttons that contain badges (#1346)
* make relative positioning conditional

* add changelog
2025-08-20 17:07:29 -04:00
Cory LaViska
a0a47b1bdf remove outdated wa-change info (#1348) 2025-08-20 15:38:26 -04:00
Cory LaViska
fa51cff947 Fix icon sizes for FA7 (#1345)
* fix icon sizes for FA7

* update test to reflect new size

* fix icons for real

* update tests
2025-08-20 15:14:07 -04:00
Cory LaViska
fd08d4f227 add --show-duration and --hide-duration to select (#1344) 2025-08-20 14:34:21 -04:00
Cory LaViska
7008c0cef7 Add z-index to scroller's content and shadows (#1338)
* add z-index to content and shadows; fixes #1326

* remove unused property
2025-08-20 14:20:33 -04:00
Cory LaViska
e9ce8659f6 rename icon-position to icon-placement (#1343) 2025-08-20 12:31:55 -04:00
Cory LaViska
325d6f211b Remove the unsupported button group size attribute (#1334)
* remove unsupported example

* remove old/incorrect example

* remove unsupported attribute
2025-08-20 12:20:18 -04:00
Cory LaViska
bd1570ec76 fix paths and imports; closes #1303 (#1336) 2025-08-19 17:10:49 -04:00
Cory LaViska
406f3a0e81 Allow the slider's thumb to receive focus when tapping or dragging (#1337)
* fix paths and imports; closes #1303

* allow slider thumb to receive focus on tap; fixes #1312
2025-08-19 17:10:15 -04:00
Lindsay M
08babbce6d fix search trigger label alignment (#1315) 2025-08-19 16:18:49 -04:00
Cory LaViska
293b86705a update changelog (#1333) 2025-08-19 15:51:35 -04:00
Alan Chambers
fe5ab48c06 Add jsx types to package.json exports (#1295) 2025-08-19 15:50:12 -04:00
Cory LaViska
35e9dfe88d Update <wa-icon> to support Font Awesome 7 (#1301)
* Add FA 7 support

* Add FA 7 support

* Add FA 7 support

* Update the system library to use FA 7 icons

* fix: fix type issues

* Update the SVGs in the system library to be minified/compressed

* add suggestions and more features

* feat: add `swap-opacity` attribute

* fix: remove unrelated stuff in `swap-opacity` attribute styling

* Only scale paths for fixed width icons

* fix: fix Prettier lint issues

* fix: fix more syntax errors

* lint: Fix CSS linting, batch 1 of 3

* lint: fix TS linting issues, batch 2 of 3

* lint: Fix JS linting issues, batch 3 of 3

* lint: fix hopefully last linting issue, batch 3.5 of 3

* lint: fix final linting issues, 3.75 of 3

* lint: the actual last lint fix, batch 3.875 of 3

* chore: centre SVG paths within the SVG for fixed‐width icons

* fix iconoir example

* add comment to clarify

* use a constant for fa version

* remove unsupported features

* update for FA7; improve duotone support

* update changelog

* remove redundant fixed-width attributes

* update kit code

* notdog!

* add support for pro+ icons

* clean up example layouts, use consistent icon sizes

---------

Co-authored-by: randomguy-2650 <150704902+randomguy-2650@users.noreply.github.com>
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-08-19 15:44:22 -04:00
Curtis Keller
44567ec967 remove unimplemented appearance typing (#1319) 2025-08-19 15:37:08 -04:00
Cory LaViska
bfdd0bd6d0 update list (#1309) 2025-08-14 11:37:18 -04:00
Cory LaViska
f3f5d40b7b Update changelog for new translation (#1308)
* prettier

* update changelog
2025-08-14 11:34:05 -04:00
Pratik sharma
3d75d6b59c added translation for Hindi(hi) (#1307) 2025-08-14 11:32:24 -04:00
whjvenyl
f30801ab66 Do not crush labels with nested tags (#1274)
* Adjust label styles for button and checkbox components to not crush space of nested tags

* Adjust label styles for button and checkbox components to not crush space of nested tags

* Update packages/webawesome/src/components/checkbox/checkbox.css

---------

Co-authored-by: Tobias Bannwart <tobias.bannwart@bison-group.com>
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-08-12 11:38:06 -04:00
Cory LaViska
f92ef1f74e Fix dropdown bugs (#1293)
* fix dropdown auto-size; closes #1268

* fix slotted dropdown items; fixes #1271

* fix keyboard selection in dropdowns in shadow roots; fixes #1270
2025-08-12 11:31:40 -04:00
Lindsay M
da27a8dc74 Add native <input type="file"> styles (#1279)
* add `input type="file"` styles

* add `max-inline-size`

* refactor button styles to include `::file-selector-button`

* improve docs

* add changelog

* add region marker
2025-08-11 10:39:47 -04:00
Kelsey Jackson
437e0d9aec updated icon docs (#1283) 2025-08-07 13:35:27 -05:00
Cory LaViska
583d9c0616 add changelog; #1277 (#1282) 2025-08-07 13:40:47 -04:00
LX
cb29033eaf Fix exportparts of tooltip inside wa-slider component (#1277) 2025-08-07 13:33:59 -04:00
Konnor Rogers
c02ac306af Add extra build logging (#1259)
* fix build reloading

* prettier
2025-08-06 16:25:30 -04:00
konnorrogers
56d678b504 Bump package.json version 2025-08-05 12:59:29 -04:00
konnorrogers
b1864eb93d Bump package.json version 2025-08-05 12:58:54 -04:00
konnorrogers
d2b5613e85 bump changelog 2025-08-05 12:58:07 -04:00
konnorrogers
f7ca634822 Bump changelog 2025-08-05 12:57:53 -04:00
Kelsey Jackson
35d33c89b9 updated templates (#1265)
* updated templates

* added conditional

* updated layouts again
2025-08-05 12:32:09 -04:00
randomguy-2650
094bd478ff fix: remove non‐existent Plain appearance in the Badge visual tests (#1260) 2025-08-05 10:58:15 -04:00
Kelsey Jackson
0b619a99f1 Kj/honeyhive patterns sidebar updates (#1258)
* adding to sidebar

* updated sidebar

* updated sidebar navigation

* add header to sidebar nav
2025-08-01 12:57:14 -04:00
Cory LaViska
89cf48c865 Add JSX types for React (#1256)
* add JSX types for React et al

* update changelog
2025-07-31 13:10:07 -04:00
Cory LaViska
b7a6ebd228 add without-arrow to hide arrows without artifacts (#1253) 2025-07-30 14:08:26 -04:00
Cory LaViska
6c8bbd51d1 Add missing dependency for React wrappers (#1242)
* add dep

* remove dev dep
2025-07-28 13:55:12 -04:00
Lindsay M
6085b9698c Add tokens to style tooltip borders (#1234)
* add tooltip border tokens

* target the correct part

* target the correct part (for real)
2025-07-28 12:30:42 -04:00
Tu Nguyen
17ee36175b fixed a typo in dropdown doc (#1235) 2025-07-28 12:29:56 -04:00
Cory LaViska
3c7bb71a59 scope styles to #content (#1217) 2025-07-23 17:10:32 -04:00
randomguy-2650
d66b552962 fix: fix a German translation to make it sound more natural (#1223) 2025-07-23 14:43:13 -04:00
Cory LaViska
6f6e23c78c Fix details animation by preventing overflow during animation (#1214)
* don't overflow content; fixes #1149

* fix details overflow; closes #1149
2025-07-22 18:00:21 +00:00
Cory LaViska
310f7a8c5d fix dialog and drawer header; fixes #1209 (#1213) 2025-07-22 13:57:07 -04:00
Cory LaViska
9a7b258108 remove links to the old alpha repo (#1216) 2025-07-22 13:54:19 -04:00
Lindsay M
e10aba0ed1 Add icon-position to <wa-details> (#1210)
* add `icon-position` to `<wa-details>`

* fix attribute name
2025-07-22 13:38:42 -04:00
Konnor Rogers
1ea5dae9ad fix build reloading (#1211)
* fix build reloading

* prettier

* fix build reloading
2025-07-22 10:51:17 -04:00
Cory LaViska
21310bd367 Link fix and typo (#1208)
* fix typo

* fix broken discord link
2025-07-21 14:20:54 -04:00
Doug Stevenson
c1478e5865 Fix hash link for "cherry picking" (#1207) 2025-07-21 14:14:49 -04:00
randomguy-2650
9b8433c996 Update outdated docs related to A+O appearance (#1204) 2025-07-21 11:37:47 -04:00
konnorrogers
57dac67aab update package-lock 2025-07-18 14:24:04 -04:00
konnorrogers
441bfd7b72 Bump package.json version 2025-07-18 14:02:10 -04:00
konnorrogers
7150c59334 Bump changelog 2025-07-18 14:01:31 -04:00
Konnor Rogers
bd2a3c3b64 add pro setup (#1201) 2025-07-18 13:41:03 -04:00
Lindsay M
11519625ed Use margin for <wa-icon> spacing in native buttons (#1197) 2025-07-18 09:47:24 -04:00
Konnor Rogers
f19848c11e prevent infinite loop in build watcher (#1200)
* prevent infinite loop in build watcher

* prettier
2025-07-18 00:43:29 -04:00
Konnor Rogers
36b21b0be7 introduce before watch and after watch events (#1199)
* add before / after watch events so pro can properly incrementally build

* add events for pro / app

* add extra hooks for non-wa dev

* add old new line

* use package-lock.json from next

* npm install

* prettier
2025-07-18 00:09:47 -04:00
Cory LaViska
fe2c2ab7af improve accessibility; fixes #1177 (#1190) 2025-07-17 11:56:41 -04:00
Cory LaViska
b98b9baba4 add back id="hint" (#1192) 2025-07-17 11:55:53 -04:00
Cory LaViska
7b18be876b fix media rounding; closes #1107 (#1193) 2025-07-17 11:55:26 -04:00
Cory LaViska
c9e6895ef7 fix pill buttons in groups; closes #1165 (#1191) 2025-07-17 11:28:57 -04:00
Konnor Rogers
64c8647dee build speed improvements and add optional incremental builds (#1183)
* build speed improvments

* fix button

* prettier

* move things to plugins / transformers

* final fixes

* build fixes

* fix build issues

* add comment

* build sstuf

* prettier

* fix badge.css

* fix build stuff

* fix eleventy stuff

* prettier
2025-07-16 17:37:47 -04:00
randomguy-2650
9e9a00547a fix: fix incorrect documentation link used in @documentation JSDoc (#1187) 2025-07-16 12:02:35 -04:00
Lindsay M
f747483e32 Add --track-height to <wa-progress-bar> (#1159)
* add `--track-height` to `<wa-progress-bar>`

* fix custom `<wa-progress-bar>` height instances

* add changelog
2025-07-14 18:16:19 -04:00
Lindsay M
8719bbc88b Fix extra whitespace in <wa-textarea> with resize="auto" (#1175)
* fix extra whitespace

* fix the fix

* add changelog
2025-07-14 17:56:53 -04:00
Cory LaViska
0ff5e7fb7a Fix domain in documentation links (#1180)
* fix domain in doc links

* unprettier
2025-07-14 17:19:28 -04:00
Konnor Rogers
2a52b2766f fix badge pulsing (#1173)
* fix badge pulsing

* use and document `--pulse-color`

* Add changelog entry

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-07-14 17:00:35 -04:00
Cory LaViska
1e8bbc3b06 fix domain (#1179) 2025-07-14 16:57:44 -04:00
Cory LaViska
1ef9cb9601 add missing dependency (#1176) 2025-07-14 16:55:43 -04:00
Lindsay M
5b54410212 Revise native styles documentation (#1153) 2025-07-14 16:21:15 -04:00
Joe Marquardt
f621fbb224 fix the build on windows (#1148)
- make-react importPath variable
 - esbuild entryPoints globby usage requires forward slashes
2025-07-14 16:13:11 -04:00
Cory LaViska
f5624fbf4a Slider hint (#1174)
* update example

* show hint in correct position when present

* update example

* update example
2025-07-14 16:05:02 -04:00
randomguy-2650
f65bc3918e fix: fix the language name in it.ts (#1171) 2025-07-14 15:48:18 -04:00
Lindsay M
f49c10b05b Replace old --wa-flow-spacing with --wa-content-spacing (#1157)
* remove old `--wa-flow-spacing`

* add changelog
2025-07-11 15:03:18 -04:00
Konnor Rogers
3b6c018fed Fix react imports to include a class name (#1158) 2025-07-10 15:40:45 -04:00
Lindsay M
c10e1e77c9 Update <wa-select> "Sizes" documentation (#1162) 2025-07-10 15:37:37 -04:00
Lindsay M
a1e879035c Fix code example styles (#1156) 2025-07-10 15:36:03 -04:00
Lindsay M
d2625fccab Remove extra stylesheets from CodePen editing (#1161) 2025-07-10 14:09:50 -04:00
randomguy-2650
29c8ad08bb Fix links pointing to / instead of the current page (#1145) 2025-07-09 13:11:24 -04:00
Mischa
0f68e6f0dd Refactor copy button documentation layout for improved alignment with input (#1141) 2025-07-09 13:09:53 -04:00
Tu Nguyen
4dca2b9541 Fixed a minor doc typo (#1137) 2025-07-09 12:17:20 -04:00
konnorrogers
36ccaa4aaa bump package.json 2025-07-03 18:32:12 -04:00
konnorrogers
c86d7635aa Bump package.json version 2025-07-03 18:31:59 -04:00
Konnor Rogers
d84e842a4e fixing select + tests (#1136)
* fixing select + tests

* fix TS

* prettier

* prettier

* fix CI test

* fix changelog
2025-07-03 18:29:02 -04:00
Lindsay M
fb8c06235f Fix link hover styles (#1135) 2025-07-03 14:20:51 -04:00
Cory LaViska
f6a10e9dda update changelog (#1134) 2025-07-03 12:06:38 -04:00
Lindsay M
5ce34677ed Add GitHub repository links (#1128)
* add repository links

* fix mobile navigation drawer
2025-07-03 11:26:35 -04:00
Lindsay M
8ebc839dfd Fix text colors on accent backgrounds (#1130) 2025-07-03 11:26:28 -04:00
Lindsay M
2779eb1753 Fix :active Awesome button text colors (#1129) 2025-07-03 09:24:47 -04:00
Cory LaViska
341ca809e9 Themes page fix (#1125)
* fix themes + palettes

* fix copy button color

* unimprove code links
2025-07-02 21:39:50 +00:00
Cory LaViska
7232ddee5d Dropdown fix (#1122)
* _blank

* fix dropdown flip/shift/ behavior when the viewport doesn't have space
2025-07-02 15:06:50 -04:00
whjvenyl
f63001f18e remove duplicate property (#1119)
Co-authored-by: Tobias Bannwart <tobias.bannwart@bison-group.com>
2025-07-02 14:10:15 -04:00
Lindsay M
8b831f6ece Improve organization of essential and optional styles (#1113)
* include all essential styles in `styles/themes/default.css` + cleanup

* tweak installation quick start description

* more docs updates
2025-07-02 13:58:55 -04:00
Lindsay M
4dee3d0f2d Add opt-in class to highlight table rows on hover (#1111)
* add `.wa-hover-rows`

* update docs

* update changelog
2025-07-02 09:20:17 -04:00
Cory LaViska
10a78d99af add missing items (#1117) 2025-07-02 08:21:52 -04:00
Lindsay M
99d9024339 Fix filled + outlined appearances (#1112)
* fix filled + outlined appearances

* docs consistency
2025-07-01 16:50:28 -04:00
Alan Chambers
313e31a3f2 Adjust package.json styles exports (#1104) 2025-07-01 16:45:55 -04:00
Konnor Rogers
4eeabc57e5 fix component paths....again (#1098) 2025-06-30 18:52:49 -04:00
Konnor Rogers
c8c0d0f848 disable runaway popup example (#1097) 2025-06-30 18:37:36 -04:00
Konnor Rogers
e8687b895d fix component paths (#1096) 2025-06-30 17:50:59 -04:00
Konnor Rogers
7743b670ed update docs (#1095)
* update docs

* add publish access config

* update package-lock
2025-06-30 15:32:08 -04:00
Konnor Rogers
88e99d7cd3 add placeholder readme.md (#1093) 2025-06-30 13:57:19 -04:00
Konnor Rogers
c0d18ab9f0 add dist-cdn to files (#1092) 2025-06-30 13:40:52 -04:00
Konnor Rogers
6576f67cfa center cta (#1091) 2025-06-30 13:37:22 -04:00
Konnor Rogers
057ff5fb31 change to webawesome (#1089)
* change to webawesome

* change to webawesome

* update index.md

* whitespace

* add thanks for being a webawesome pro subscriber

* add stub for currentUser

* add source code link

* add source code link

* prettier

* fix raw call
2025-06-30 13:29:56 -04:00
Cory LaViska
1dac76a35e fix blurb (#1090) 2025-06-30 13:03:28 -04:00
Konnor Rogers
e7f2962984 Pro fixes (#1088)
* add pro badge to themer

* add isPro flag to palettes

* show based on currentUser.hasPro

* fix logged out user stuff

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-06-30 12:13:21 -04:00
Lindsay M
956dc9bdd9 Fix avatar colors in theme showcase (#1087) 2025-06-30 10:53:23 -04:00
Lindsay M
62020be8c1 add missing changelog entries (#1086) 2025-06-30 09:42:30 -04:00
Lindsay M
429cf68301 Restore docs indices (#1085)
* fix missing indices

* fix search placeholder
2025-06-27 16:27:28 -04:00
konnorrogers
dd77663a75 add script for version tagging 2025-06-27 16:26:05 -04:00
konnorrogers
fa9f18f002 add print-version npm script 2025-06-27 16:14:46 -04:00
konnorrogers
c2e2e1afcc bump package.json 2025-06-27 16:12:02 -04:00
konnorrogers
2628f4ff7c Bump package.json version 2025-06-27 16:11:44 -04:00
Cory LaViska
16722a191d revert fallback (#1083) 2025-06-27 13:19:56 -04:00
Lindsay M
21243729c6 Remove custom properties that are easily styled with CSS parts (#1080)
* progress, components A – C

* left behind tweaks for A – C

* all the rest

* tweaks

* remove 'accent + outlined' appearances and other tweaks

* fix overlooked docs + scouts rule

* re-add `--checked-icon-color` to radio and checkbox

* revert to `--thumb-size`

* fix theme overrides

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-06-27 12:48:40 -04:00
Konnor Rogers
1581b99796 fix custom elements manifest evaluation (#1082)
* fix custom elements manifest evaluation

* prettier
2025-06-27 16:31:32 +00:00
Lindsay M
103cbc439e Replace "alpha" with "beta" in the docs (#1081)
* change alpha messaging -> beta

* switch `webawesome-alpha` links to `webawesome` repo

* update installation disclaimers

* fix broken link
2025-06-27 11:11:46 -04:00
Cory LaViska
3a40ffe58a Themer rework (#1048)
* remove experimental pages

* typo

* untying the knots

* whitespace

* fix input bubbling

* refactor

* reimplement color scheme selector

* rename

* fix comments

* revert premature abstraction

* host vars

* rework theme selector

* feed themes from global data

* add back component headers

* reimplement component index

* make headings optional

* add back color palette page sans instructions

* fix selector

* fix search list with turbo

* always dispatch after update

* add back theme preview page

* fix

* fix errors

* fix theme selector

* fix themes

* improve

* make transition smooth

* revert

* revert

* skip

* fix borders

* fix fade in

* remove unused blocks

* we know this guy

* fix event timing

* remove header

* remove unused styles

* add better nunjucks extension

* update header

* fix layout

* add theme linke

* fix autocomplete bug

* correct description

* consistency between palettes and tokens docs

* better extension

* add colorPalettes data

* typo

* typos

* fix progress bar height

* remove due to errors; works without

* move pro palettes to pro

* consolidate themer data

* themer data

* add font packs

* reorg

* restructure theme data

* add word

* detect the reference slot instead of requiring with-references

* Remove `:root` selector and `@import` rules from themes (#1061)

* remove `:root` selector and imports from themes

* re-add `base.css` to free

* update how themes are assigned

* update showcase location

* update

* fix palettes

* add font href

* fix theme page in turbo

* fix color palettes

* remove rose

* fix shadow

* update docs

* update docs

* rename eyedropper to fix spelling

* rename eyedropper

* disable turbo

* remove unused import

* update themer data

* add get/set icon family

* revert example

* fix color palette data

* add brand color to theme data

* fix sharp duotone name

* fix typo

* update changelog for merged branch

* update changelog

* allow default theme to inherit color scheme when nested

* make font packs more exciting

* update serif typeface

* add examples

* update font weights

* set initial selection instantly

* set brand and palette with theme in theme selector

* add palette stylesheets

* fix icon slot

* fix theme descriptions

* minor style touch up

* tweak example button text

* group callout examples

* add 'create theme' button

* tweak spacing, fix sneaky plain card background

* prettier

* ultra tiny tweak to showcase example

* show usage instructions

* prevent error when theme selector isn't present

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-06-27 10:26:46 -04:00
Cory LaViska
453e8ff501 rename caret => with-caret (#1079) 2025-06-26 13:11:00 -04:00
Cory LaViska
dc556e5379 add disabled to radio group; remove @watch (#1066) 2025-06-23 14:41:54 -04:00
Konnor Rogers
c11d6129a3 Rework setting initial values in <wa-select> (#1063)
* fix select to use selected options

* fix selected stuff

* remove unused prop

* update tests

* fix default value and form reset

* remove demo

* update changelog

* document value prop

* recommend selected in docs

* document props

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-06-23 13:46:05 -04:00
Cory LaViska
dd5c32680a remove redundant examples; closes #1041 (#1064) 2025-06-23 10:38:02 -04:00
Lindsay M
81996cbc63 fix tag sizes (#1062) 2025-06-23 10:30:01 -04:00
Konnor Rogers
d20945d78b increase breakpoint on wa-page (#1060) 2025-06-17 11:45:38 -04:00
Konnor Rogers
07327be95e input / change always bubble now (#1057)
* make sure relayNativeEvent is synchronous

* prettier

* changelog entry

* fix event
2025-06-13 13:19:47 -04:00
Cory LaViska
b99d7771dc move pro themes to pro (#1054) 2025-06-11 12:15:52 -04:00
Lindsay M
10cc9bdc68 Change prefix and suffix to start and end (#1047)
* change `prefix` > `start` and `suffix` > `end` (breadcrumb item)

* fix formatting

* change `prefix` > `start` and `suffix` > `end` (button)

* change `prefix` > `start` and `suffix` > `end` (input)

* change `prefix` > `start` and `suffix` > `end` (select)

* replace leftover `prefix` instances with `start`

* replace leftover `suffix` instances with `end`

* update changelog

* remove `slot="start|end"` examples from unsupported components
2025-06-11 11:36:50 -04:00
Lindsay M
bc598dad92 Consolidate theme files (#1053)
* consolidate theme files

* move dimension to its own layer

* touch up

* fix `.wa-invert`

* fix selectors and missing fonts

* fix selectors (for real this time)
2025-06-11 11:24:40 -04:00
Lindsay M
ff61ac002f Remove clamped color tokens (#1050) 2025-06-10 15:44:33 -04:00
Konnor Rogers
63ec9d5bc1 Try with PAT (#1049)
* Try with PAT

* Try with PAT
2025-06-10 13:59:52 -04:00
Kelsey Jackson
555327b2fc Kj/layout patterns (#1013)
* add button for drawer example

* scaffolding

* building initial page

* loading blank

* committing to pull down changes

* committing to merge

* trying to sync with next

* drawer issue

* added content to drawer

* added checkout page

* added checkout page

* committing to merge

* committing to merge

* made changes to sidebar

* syncing with repo

* syncing with repo

* update sidebar again

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-06-09 12:17:14 -05:00
Cory LaViska
15c6eaec90 Dropdown rework (#1039)
* use wa-popup in color picker

* remove test

* remove old dropdown, menu, menu item, menu label

* remove old dropdown

* rework dropdown + dropdown item

* update examples

* add hide duration

* update jsdoc

* add event

* add size

* add size

* fix docs

* remove old test; fix types

* add submenu to example

* adapt for <wa-popup>

* remove state

* fix dropdown stuff (#1044)

* fix dropdown stuff

* prettier

* get typescript to give a real error

* remove unnecessary checks

* prettier

* remove old tag

* convert old dropdowns to new syntax

* update example

* update styles

---------

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-06-09 11:19:34 -04:00
Lindsay M
6f856fbd89 Native styles cleanup (#1043)
* tidy and touch up content styles

* finish touching up inline text styles

* move styles for docs code blocks from `native.css` to appropriate files

* tidy and touch up list and table styles

* tidy and touch up details styles

* tidy up dialog styles

* fix bloated spacing in dialog and drawer

* add fieldset, refactor radio and checkbox styles

* refactor input, textarea, and select styles

* refactor range styles to match new `<wa-slider>`

* readability improvements

* touch up theme overrides

* fix Matter checkbox and radio hover styles
2025-06-09 11:18:37 -04:00
Konnor Rogers
df46e1db3b remove public alpha cdn (#1042) 2025-06-06 14:04:44 -04:00
Cory LaViska
d21d829c29 Slider rework (#1034)
* initial rework

* improvements

* add size styles

* update changelog

* update changelog

* fix hint aria

* whitespace

* slider test fixes (#1036)

* prettier

* More slider fixes 2 (#1037)

* more fixes

* more fixes

* prettier

* fix theme slider styles

* only add extra space around slider when label is present

---------

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-06-06 10:38:18 -04:00
Cory LaViska
2331e88dcf update jsdoc (#1038) 2025-06-06 08:29:19 -04:00
Cory LaViska
c162983ca2 add hover queries (#1035) 2025-06-05 22:03:51 +00:00
Cory LaViska
0d09037916 Zoomable frame (#1029)
* add zoomable frame component; #986

* remove viewport demo component

* update changelog

* fix code demos

* update zoomable iframes with theme changes
2025-06-05 17:34:25 -04:00
Cory LaViska
d2e32a0a53 Support icon buttons directly in <wa-button> (#1030)
* support icon buttons directly in <wa-button>

* [progress] replace `<wa-icon-button>` instances

* change close buttons to `<wa-button>`

* fix formatting

* change scroll buttons to `<wa-button>`

* update tests

* change tag remove button to `<wa-button>`

* fix tag tests

* remove nonexistent parts from tab docs

* change viewport demo controls to `<wa-button>`

* fix leftover icon button dependencies

* fix icon button usage in palettes and themes

* revert mistakenly committed change to theme preview heights

* fix icon button styles in old themer

* replace icon buttons in style utility examples

* fix import

* handle press on button, not icon-button, in select

* fix stray icon button references in docs

* fix broken home page button

* remove icon button overrides from Matter theme

* add generated directories so they're excluded from search results

* add dire

* remove icon-button component

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-06-05 15:16:03 -04:00
Cory LaViska
71d45eabbd Add data- invokers to dialog and drawer (#1032)
* add data- invokers to dialog and drawer

* rename var
2025-06-05 14:47:29 -04:00
Konnor Rogers
eac60a9022 Fixes for app and prettier (#1028)
* fix for app

* prettier

* fix for app

* prettier

* update prettierignore

* prettier

* prettier

* fix prism vendoring
2025-06-04 10:28:38 -04:00
Cory LaViska
f8dca5d1a8 refactor styles and simplify custom states (#1016) 2025-06-04 08:09:14 -04:00
Lindsay M
5980b5f843 Refactor form control sizing (#1005)
* visual test setup

* fix improper class placement in visual tests

* add `wa-form-control-*-font-size` and `-wa-form-control-hint-*` custom properties

* use new custom properties

* dump of component sizing improvements

* fix native color picker styles

* update menu with relative sizes

* tidy up menu, select, and tag sizing

* use relative sizing across components

* touch up custom properties

* update docs and comments

* update changelog

* revert changes to visual tests to simplify PR

* revert leftover change to visual tests

* tidy up space doc markdown

* fix default card spacing

* fix card docs

* wrap up new `--tag-max-size` for `<wa-select>`

* change default `--tag-max-size`

* prettier

* touch up

* clean up leftovers

* fix native form control margins

* set default toggle size relative to font size

* correct toggle size in docs

* Konnorrogers/lm form control sizing (#1025)

* try a second updateComplete??

* try a second updateComplete??

* more timeouts?

* try logging

* more logging
gp

* maybe now

* radio group test

* add todo note'

* add workflow dispatch for client tests

---------

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
2025-06-03 16:27:24 -04:00
Cory LaViska
9a3ffb04ba remove unused custom props; align styles with wa-slider (#1017) 2025-06-03 15:51:49 -04:00
Cory LaViska
04d37224e0 remove hint from <wa-radio>; fixes #1024 (#1026) 2025-06-03 15:31:53 -04:00
Cory LaViska
f4a63f9e22 Simplify color variants docs (#1023)
* remove

* simplify
2025-06-03 15:28:11 -04:00
Cory LaViska
3ab342ebb6 add support for name attribute (#1022) 2025-06-03 15:10:31 -04:00
Cory LaViska
48fe9389c8 Use outlined appearance for buttons in <wa-color-picker> (#1021)
* use outlined appearance for buttons

* don't override child element's size
2025-06-03 15:10:15 -04:00
Cory LaViska
6b2a081fa0 Improve rating's default a11y (#1019)
* add regular star

* support dual icons; improve default contrast

* support dual icons; improve contrast

* update docs

* Update packages/webawesome/src/components/rating/rating.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

---------

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-06-03 15:09:34 -04:00
Cory LaViska
afb2082c79 add resize-vertical (#1018) 2025-06-03 15:08:52 -04:00
Cory LaViska
7bdc9a2cc4 Add <wa-popover> (#1012)
* remove redundant styles from template

* rotate arrow based on placement so borders show correctly when applied

* use actual placement, not preferred

* add popover

* update changelog

* update changelog

* use <dialog> for popover

* fix arrow border in FF/Safari

* update content

* add sidebar to plop

* add popover
2025-06-02 16:13:24 -04:00
Cory LaViska
dead18d23c Fix scroll on reload (#1015)
* fix scroll on reload

* fix comment
2025-06-02 16:09:49 -04:00
Konnor Rogers
2b37c54d7c fix code blocks (#1009) 2025-06-02 10:23:47 -04:00
Cory LaViska
35b61e5cf3 Fix plop templates (#1007)
* update plop templates

* fix plop template

* don't break react
2025-06-02 09:37:30 -04:00
Konnor Rogers
cc33805d27 add convenience scripts (#1004) 2025-05-30 11:46:43 -04:00
Konnor Rogers
6e548dd85b Turn Web Awesome into a monorepo (#1002)
* finishing touches

* finishing touches

* use bash

* remove pro stuff

* update github actions

* fix head.njk
2025-05-29 19:26:10 -04:00
Cory LaViska
212ca5b0a6 Fix icons (#997)
* remove

* remove style observer from icons

* fix size example

* unbreak the themer

* remove old test

* remove abstraction

* remove createProperty and initial; fix default attribute values

* skip it to ship it

* cleanup and add ? fallback

* update tests

* fix types

* remove default

* update test

* update tests

* update deps

* update deps

* update deps

* update dep

* fix comment

* downgrade 11ty

* revert deps

* add nunjucks

* prettier

* skip tests for now

* fix parsing error

* prettier

* skip

* sigh webkit

* tidy up icon library examples

* change rando `solid` icon to `regular`

* restore tests

* fix radio group size

* fix button group size

* remove size from card

* fix menu item sizes

* remove card `size` from visual tests and docs

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-29 15:59:41 -04:00
Cory LaViska
b96c3f318b Simplify native styles (#993)
* move print styles

* begin native styles split

* unsplit button styles 😓

* unsplit callout; remove .wa-callout

* merge forms

* remove unused

* remove unused

* unsplit checkbox

* remove old astro config

* remove overflow

* unsplit slider

* fix tooltip position in RTL

* unsplit radio

* move required light DOM styles to <wa-page>

* remove unused file

* remove unused import

* remove

* goodbye

* fix examples

* unsplit dialog

* unsplit select

* remove select

* unsplit input

* unsplit details

* update

* update comment

* update textarea

* combine native docs; improvements

* update

* reorg and fix headings

* fix details summary padding; fixes #684

* update

* fix native details summary padding; fixes #684

* #684

* remove passthrough style nonsense

* it's CSS not JS

* fix details in sidebar

* add spacing in native buttons for icons

* whitespace

* update docs

* remove button group util

* remove shadow folder, add component folder

* layerize

* default border radius

* remove color contrast script from dist

* add term

* layerize themes + color folders

* reorder

* remove radio button; #504

* remove visual tests

* remove visual tests

* remove unused stylesheet

* make search smarter

* add radio styles

* Fix filled textareas

* re-introduce visual tests (with adjustments)

* fix button appearances

* fix textarea focus styles

* re-introduce appearance classes

* remove 'native styles' note from component pages

* fix checked radio styles

* touch up callout styles

* remove errant `.wa-tag`

* scope appearance classes to relevant elements

* more visual test cases

* fix details borders

* minor visual tests reorg

* add `--box-shadow` to buttons

* fix Awesome theme

* use same layer for all themes (allows unset properties to inherit from Default theme)

* fix box-shadow in wa-textarea

* set button box shadow to `initial`

* fix Active theme

* fix Brutalist theme

* fix Glossy theme

* fix Matter theme (mostly)

* fix Playful theme

* fix Premium theme

* fix Shoelac theme

* fix Tailspin theme

* fix custom radio button styles

* fix links to native styles doc

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-29 13:10:53 -04:00
Cory LaViska
b0aba7ce07 Viewport demo fixes (#996)
* fix viewports in code demo

* sync color schemes in viewport demos

* add terms

* fix viewport styles in dark mode
2025-05-27 15:33:18 -05:00
Cory LaViska
e39bb856c4 fix code example resizer (#995) 2025-05-27 13:27:07 -04:00
Cory LaViska
23dc884678 Simplify sidebar (#989)
* remove test value

* remove animation to prevent page-to-page blips

* static sidebar

* manage open sections on page load and with turbo

* cleanup unused scripts

* Remove overlap between Style Utilities and Layout

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-23 12:07:34 -04:00
Cory LaViska
4e14f25831 Revert <wa-code-demo> in docs (#981)
* remove code demo

* fix page demos and split into external files
2025-05-23 06:21:09 -04:00
Cory LaViska
b15502a01e Use with- and without- consistently (#977)
* use with- and without- consistently

* fix test

* cleanup

* remove console
2025-05-22 14:33:24 -04:00
Cory LaViska
73f6eeacbd Add help buttons to component pages (#984)
* add help buttons to component pages; fixes #140

* justify start
2025-05-22 13:40:35 -04:00
Cory LaViska
5921f3eeaa Button slot detection (#976)
* reimplement slot detection; remove broken visually hidden logic

* update example now that wa-visually-hidden is not a component

* cleanup
2025-05-22 13:40:19 -04:00
Cory LaViska
35338ef643 Add min-block-size to divider; fixes #675 (#964)
* add min-block-size to divider; fixes #675

* Remove unnecessary divider heights from patterns

* Update src/components/divider/divider.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-05-22 11:05:38 -04:00
Cory LaViska
5c950a7874 Remove old BEM -- convention from classes and fix button group dividers (#967)
* remove old BEM -- convention from classes

* fix button group divider; #375

* Update src/styles/utilities/button-group.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

* Update src/styles/utilities/button-group.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

* fix outlined button groups

* Also overlap borders in vertical button groups

---------

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-22 11:04:11 -04:00
Konnor Rogers
a7ea989170 fix icon spritesheets (#982)
* fix icon spritesheets

* fix icon tests

* prettier
2025-05-22 06:27:08 -04:00
Konnor Rogers
7253ed8ab0 fix menu spacing (#978)
* fix menu spacing

* fix relative links in HTML files

* fix relative links in HTML files
2025-05-21 15:33:59 -04:00
Kelsey Jackson
37e82b70fa updated card slot from image to media (#975)
* updated card slot from  to

* missed a wildcard

* updated changelog
2025-05-21 13:03:11 -05:00
Cory LaViska
39d1b82634 Add data attribute invokers; fixes #246 (#966)
* add data attribute invokers; fixes #246

* Add missing word

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-21 13:47:22 -04:00
Cory LaViska
1259a9b78d use native element for native example; fixes #532 (#969) 2025-05-21 13:46:22 -04:00
Cory LaViska
59077e75d2 improve tag spacing; fixes #677 (#965)
* improve tag spacing; fixes #677

* use spacing token

* use em
2025-05-21 13:35:04 -04:00
Cory LaViska
62ddf13a6a Rename vertical to orientation="vertical"; fixes #674 (#963)
* vertical => orientation="vertical"; fixes #674

* add issue

* Update divider styles and docs to use `orientation='vertical'`

* Update split panel styles and docs to use `orientation='vertical'`

* Update remaining docs and patterns examples to `orientation='vertical'`

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-21 13:34:24 -04:00
Cory LaViska
684bb25244 Add attention attribute to <wa-badge>; fixes #940 (#962)
* add attention attribute; fixes #940

* add bounce

* update changelog

* reword
2025-05-21 13:33:45 -04:00
Cory LaViska
1f2ebf5e7a improve table styles; fixes #953 (#961) 2025-05-21 13:32:34 -04:00
Cory LaViska
2182d3c692 fix radio group when value is a number; fixes #924 (#960) 2025-05-21 13:32:16 -04:00
Cory LaViska
074c7a16d6 Rename the classic theme to shoelace; fixes #909 (#959)
* rename classic => shoelace; fixes #909

* Update Shoelace theme description

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-21 13:31:43 -04:00
Cory LaViska
4130246833 add browser + screen reader support policy; fixes #146 (#958) 2025-05-21 13:31:25 -04:00
Kelsey Jackson
bbda731f56 updated dates in the carousel (#957) 2025-05-20 21:31:26 -05:00
Konnor Rogers
6492ee7728 fix themes for app (#956)
* fix themes for app

* prettier
2025-05-20 13:29:56 -04:00
konnorrogers
73e1c04b37 update publish-alpha-cdn 2025-05-20 12:33:35 -04:00
konnorrogers
49bb6af154 3.0.0-alpha.13 2025-05-20 11:44:47 -04:00
konnorrogers
9b8d73a2ea update changelog / gitignore for 3.0.0-alpha.13 2025-05-20 11:44:42 -04:00
Lea Verou
0b4c1a5934 Themer 2nd slice: Look & Feel (#920)
* Exclude Create link from sidebar, for reals this time

* Fix bug

* Very rough prototype of look & feel

* a11y

* Clean up data files

* Automatically generate theme metadata

* Read look & feel params straight from theme

* First stab at dimensionality icons

* Fix rounding 0 bug

* Add border width slider

* [Image-comparer] Expose wrapper as part

* [Comparer] `pointer-events: none` while dragging

* Dark mode slider

* Adjust increments and ranges for look + feel sliders

* Fix preview

* Fix bug where dark mode was not inverted

* Ability to select panel from URL

* Create mixin for Vue form controls and use it in `<swatch-select>`

* Prototype of slider min/max icon buttons

* Nx tooltip

* Icons

* Prevent failed request

* info-tip: Support passing text as prop

* Clearable

* [Brutalist] Match `--wa-shadow-offset-x-scale` to `--wa-shadow-offset-y-scale`

* Add 'Blocky' dimension (derived from Awesome theme)

* Only show Reset button when `clearable` is set

* Remove `clearable` from Look & Feel sliders

* Add tooltips to min/max buttons

* Remove superfluous `aria-label`

* Do not assume that all hyphens in URLs mean nesting, make it explicit

* Formatting

* Fix bug where styles were not applied on page load

* Update Subtle dimension to maximize compatibility

* `<wa-scoped>`: Do not allow non-template children

* Workaround for card not updating

* Update Glossy dimension to maximize compatibility

* Sync scrolling between regular and inverted preview

* Fix bug

* Make changing the base theme reset customizations

* Fix palette page

* Remove cancel button from editable text

* Don't error in theme pages

* Update Playful dimension to maximize compatibility

* Rename 'Look and Feel' to 'Elements' for better parallel structure

* Hide dimensionality controls

* Make back icon motion more subtle

* Expand spacing slider bounds

* Add `tabindex="-1"` where missing in theme showcase

* Remove extraneous gap from theme headers

* fix edit button bug

* rename comparer => comparison; fix aria-controls

* Always save theme name on blur

* Add changelog for themer and new patterns category

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-05-20 10:16:49 -04:00
Kelsey Jackson
8b17b3d3e0 Kj/blog news patterns (#916)
* initial commit to this pr

* updated patterns

* category lists

* post headers

* WIP

* made some content updates

* deleted rogue file

* updated descriptions

* ran prettier

* updated padding

* updated prettierignore

* updated element

* swtiched to token

* updated with category list feedback

* updated with category list feedback

* updated with feedback for featurd post

* updated with feedback for footer

* updated with newsletter feedback'

* updated with feedback to the paywall

* updated with updates for post footer

* more footer updates

* updated with feedback for the post header

* updated with feedback for post list

* updated social share

* updated sign up and login

* added logic to elements to prevent them from closing on escape

* Fix typo (incomplete `<h2>` tag)

* Add missing input labels, fix capitalization and punctuation

* Add description to Blog & News index

* ran prettier on markdown files

* ignored the post list file

* changed hierarchy

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-19 10:32:13 -05:00
Cory LaViska
f5d1b74e00 Scroller component (#907)
* add term

* add scroller component

* update color in docs

* prettier

* add vertical example

* use CSS

* add word

* rework shadows and add opt outs

* add examples

* update docs

* Add missing closing tag in 'Adding Content' example

* fix jsdoc

* fix safari pixels

* add changelog entry

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-15 20:12:36 +00:00
Cory LaViska
40ea444c48 add slot detection back to drawer; #928 (#931)
* add slot detection back to drawer; #928

* remove unneeded attribute
2025-05-15 12:10:49 -04:00
Cory LaViska
403927687e add slot detection back to dialog; fixes #926 (#927) 2025-05-14 17:53:48 -04:00
lindsaym-fa
6af4e849af Fix issue with button border colors 2025-05-14 10:28:11 -04:00
lindsaym-fa
2c839a4225 Remove Awesome's dimension.css, re-combine with overrides.css 2025-05-14 10:28:11 -04:00
Lea Verou
3703ef26da [Comparer] pointer-events: none while dragging 2025-05-13 17:00:49 -04:00
Lea Verou
3640b4c6e1 [Image-comparer] Expose wrapper as part 2025-05-13 17:00:49 -04:00
Lea Verou
27fc269a94 Have system icons fall back to known families/variants if not found 2025-05-13 14:38:07 -04:00
Konnor Rogers
a5b2fffb7a add unlisted and unpublished support (#919)
* add unlisted and excludeFromSearch filters

* rename unlisted to unreleased, rename excludeFromSearch to unlisted

* add notes for unlisted and unpublished

* prettier

* make unused patterns unpublished

* unreleased -> unpublished

* unreleased -> unpublished

* update contributing
2025-05-12 15:44:25 -04:00
Lea Verou
7de6a676b8 Drop base part from menu-item and menu-label (rel #207) (#884)
* [Menu-item] Drop `base` wrapper (rel #207)

Also add two states: `has-submenu` and `submenu-expanded`

* Add `checked-icon` and `submenu-icon` slots

* [Menu-label] Drop `base` part

* update changelog

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-05-12 11:26:47 -04:00
Lea Verou
3c77d400f8 [breadcrumb-item] Drop base part, move styling to host (#881)
* [breadcrumb-item] Drop `base` part, move styling to host

* update changelog

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-05-12 11:19:52 -04:00
Cory LaViska
6ee10f44f4 Add size example to <wa-badge> (#915)
* add size example

* Update docs/docs/components/badge.md

Co-authored-by: Lea Verou <lea@verou.me>

* Update docs/docs/components/badge.md

Co-authored-by: Lea Verou <lea@verou.me>

* Update docs/docs/components/badge.md

Co-authored-by: Lea Verou <lea@verou.me>

---------

Co-authored-by: Lea Verou <lea@verou.me>
2025-05-12 11:02:28 -04:00
Cory LaViska
6afc6e928c remove ssr attributes since we're not using ssr (#917) 2025-05-12 10:51:49 -04:00
lindsaym-fa
f8fcbd60ec Separate dimension overrides into new files 2025-05-12 09:27:27 -04:00
Lea Verou
bdd25571a8 Themer first slice (#857)
* Basic scaffolding

* Generate theme & palette data.js that other JS can import

* Make it possible to include page-card without links

* WIP

* Add `appearance` to details, closes #569

Except `accent` as that's a) far less useful and b) trickier due to the icon color

* Fix broken link

* WIP

* WIP

* Icons icon

* Unify styles for interactive cards

* Prevent focusing inside theme icons

* Fixes

* Action page cards

* Panel scrollables

* scrollable

* Scroll shadows

* Add renaming UI

* UI

* Move styling of heading icons to `ui.css`

* Support permalinks & CRUD

* Make clickable cards more accessible

* Style cards a little better

* Default to styles panel if theme is selected

* Update theme-icons.css

* Custom themes should be saved under Custom

* Get theme code

* Bigger title

* Fixes

* Use theme Vue app for remixing too

* Fix preview jank and make preview script more flexible

* Make radio groups scrollable

* Add affordance to button cards

* Sticky

* `<color-select>`

* Fix theme remixing

* Improve previewing logic

* Fix preview

* Move `domChange()` to separate module

`theme-picker.js` includes side-effects, which may not always be desirable everywhere we may want to import `domChange()`

* Update preview.js

* Panel animation

* Hide Save button if no changes and not saved

* Do not show blank code when no selection has been made

* Use theme slug in filename

* Remove unused component

* Better UI for editing title (and any other text)

* Tweak UI of renaming

* Better indicate default selection

* Fix preview reverting bug

* Fill out app preview with more examples

* Remove `zoom` from theme showcase (yields unexpected/painful results Safari), improve display in wider viewports

* Pending delete

* Make styles panel cards scrollable

* Fix some of the Safari issues

* Update search.css

* Update panel.css

* Select preview UI

* Fix typo

* Frame colors setting as color contrast

* Show dark mode in color mappings

* Brand color

* Swatch styling

* Fix caret icon

* Move Starting theme to the same level as other controls

* Rename typography to Fonts

* Fix bug: Swatch select should show swatches from the selected palette

* Move capitalize to shared utils

* Add utils for handling nested objects

* Icons panel

* Update code.js

* Move utils around

* Add fit and finish to sidebar panels

* Theme card: Move icons to separate data structure

* Move data to dedicated folder since we now have a lot more of it

* Add default icon families and variants to themes

* Data

* Add `deepEntries()`

* Add Duotone

* Spruce up icons preview

* Use theme's icon family in showcase

* Font cards

* Font cards

* Add `max-inline-size` to preview container

* Remove alternate preview options

* Remove theme subtitle

* Support FA kit codes

* Remove Pro badges from theme cards

* Use panagram preview for Fonts

* Consistent heading and label capitalization

* Classes for different icons-card types

* Update data.js.njk

* Variable style on icon family cards

* Fix Sharp Duotone

* Clean up FA kit code hint

* Hide non-functional Icon Library field

* Fix theme icon heights

* icon variant -> style in theme metadata

* Fix bug with icons defaults not being shown

* More convenient theme defaults

* Fix bug with non updating URL

* Fix bug

* Fix multiplying badges

* Custom docs pages

* Add Duotone icons to Mellow theme

* Fix 404

* Remove "Create" from sidebar

* Fix bug

* Move vue components to `/assets/`, move their CSS with them

* Safari/FF compatibility

* Make panels scrollable again

* Fix extra spacing

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-05-09 17:04:06 -04:00
Lea Verou
38c13640fc [Tiny PR, 8 loc diff] Reduce build process noise (#766)
* Reduce build process noise

- Only run 11ty when something has changed within `docs/`
- Only run esbuild if a JS file has changed within

* Update scripts/build.js

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
2025-05-08 16:05:52 -04:00
Cory LaViska
00a3b1aa8d fix select not opening after disabled (#910) 2025-05-08 14:47:50 -04:00
Cory LaViska
22298781c5 Remove alpha flags (#913)
* remove alpha flags

* revert isPro flag

* update scripts
2025-05-08 13:58:26 -04:00
Lindsay M
fe27710f57 Fix <wa-radio-button> overrides in themes (#914)
* Target `::part()` for `<wa-radio-button>` overrides

* Remove unapplied CSS properties from radio button docs
2025-05-08 13:09:56 -04:00
Cory LaViska
d94589d113 fix radio button validation (#912) 2025-05-07 18:46:24 +00:00
Cory LaViska
3508bf6339 Cloak improvement (#911)
* simplify cloak selector so it's 100% opt-in

* prevent the discovery event from bubbling

* update changelog

* whitespaec
2025-05-07 18:17:26 +00:00
Cory LaViska
61e65ffcb9 Improve native radio alignment (#904)
* show initial checks (feels less broken now)

* improve native radio dot alignment

* Update src/styles/native/radio.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

* Update src/styles/native/radio.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

* Update src/styles/native/radio.css

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>

---------

Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-05-07 16:43:11 +00:00
Lindsay M
aed28adbe4 Update to FA 6.7.2 and add all Duotone styles (#906)
* Update to FA 6.7.2 and add all Duotone styles

* Add changelog
2025-05-02 10:30:51 -04:00
Cory LaViska
15b8bde81b fix matter form control label + focus bug (#897) 2025-05-01 16:20:03 -04:00
Cory LaViska
9ee3fb5d28 Remove old code util; fix color scheme shortcut; fix initial examples (#905)
* fix color scheme shortcut

* remove old unused examples script and styles

* don't open the first example's code _sometimes_
2025-05-01 20:17:27 +00:00
Cory LaViska
47aa376c08 fix width example (#899) 2025-05-01 16:15:21 -04:00
Cory LaViska
69ba974a50 fix select + icon + clear spacing (#903)
* fix select + icon + clear spacing

* update styles

* revert
2025-05-01 18:56:02 +00:00
Lea Verou
8dfb411e5e Add typography metadata to themes 2025-04-30 09:42:27 -04:00
Lea Verou
a35a8fd2ad Theme typography.css fixes
- Add `:where([class^='wa-theme-'], [class*=' wa-theme-'])` to default `typography.css` since we declare mappings that need to be inherited by other themes.
- Remove declarations that redeclare defaults
- Ensure consistent order
- [Awesome] Switch code font to ui-monospace
2025-04-30 09:42:27 -04:00
Cory LaViska
2503005bbd fix radio group margin (#898) 2025-04-29 19:58:08 +00:00
Cory LaViska
78027170ea fix feature request advice (#895) 2025-04-29 14:41:01 -04:00
Konnor Rogers
a20aa48992 fix select (#892)
* fix select

* prettier
2025-04-29 12:33:03 -04:00
Lindsay M
ac8accd664 Fix color contrast in Premium theme, closes #880 (#890)
* Fix `--wa-color-brand-fill-loud` in Premium theme

* jk. *Actually* fix contrast in Premium theme.
2025-04-29 09:52:04 -04:00
Lea Verou
c571573063 [Skeleton] Remove base part, rel #207 (#885) 2025-04-28 17:04:06 -04:00
Lea Verou
e813440315 [Image-comparer] Several fixes + rename to comparer (#883)
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-04-28 16:58:24 -04:00
Lea Verou
cfc3f181a3 Fix broken demo, improve passthrough CSS (#879)
Fixes several issues for components using the `display: contents` technique:
- Introduce `--display` CSS property to make it possible to override internal display value of base part.
- Ensure `display: contents` is always applied with `!important` to avoid rendering glitches like the one here
- Ensure non-inherited custom properties are also inherited
- Ensure the `hidden` attribute still works.
2025-04-23 11:52:23 -04:00
Konnor Rogers
7545f04c46 remove all references to /docs/installation (#872) 2025-04-21 17:01:09 -04:00
Lea Verou
38bd6528fe Only apply wa-button-group-vertical class when <wa-radio-group> is a radio button group, fixes #870 2025-04-15 18:07:57 -04:00
Lea Verou
2202ea9642 CSS custom properties to set certain component attributes (#447) 2025-04-15 17:56:38 -04:00
Konnor Rogers
58fbcede51 update patterns to isPro (#869) 2025-04-14 14:59:27 -04:00
Lea Verou
971200cc88 Move domChange() to separate module (#868) 2025-04-14 12:52:00 -04:00
Konnor Rogers
b75d3b615c fix login media query and leaking variables with Turbo (#867)
* fix media queries to use wa-desktop-only

* fix errors in remix.js when changing pages

* prettier
2025-04-14 11:11:08 -04:00
Kelsey Jackson
9d1c47449e Kj/first pattern launch (#861)
* dividing up e-commerce patterns

* started invoice table

* building out the filter

* Initial Commit

* switching machines

* switching machines

* started split image pattern:

* commiting to merge in next

* commiting to switch machines

* upated the product detail patterns

* updated product list patterns

* updated some patterns

* filter work

* added utilities to order history

* added utilities to order-summary

* updated width of container

* switching machines

* switching machines

* fixing conflicts

* editing descriptions

* updated descriptions

* adding some polish

* more filter work

* updated prouct preview

* Revisions to "Product Features"

* "Category Filters" revisions + `wa-placeholder` utility

* cleaned up product list

* tweaked product overview

* tweaked order history

* tweak category preview

* "Checkout Form" revisions

* Re-add `navigation` to "Product Features" carousel

* cleaned up shopping cart

* tweaked order summary

* Add missing file extension

* Fix typo in file name

* Revert checkout form changes in attempt to improve diff

* Reimplement checkout form revisions

* cleaned up checkout form

* Add "What's a Pattern?" and "Using Patterns" to index

* Update category descriptions and headings

* Add docs layout for patterns with stylesheet

* tweaked customer review

* Add checkout form example

* a little more polish

* more tweaks

* switching branches to merge

* created e-commerce index

* unlisted links

* updtated content

* updated content for category preview

* updated order history

* committing to bring branches up to next

* inital commit

* Reorganize app patterns into separate pages

* switching machines

* Add link style utilities

* Refactor product list patterns

* more polish

* Refactor product overview patterns

* switching machines

* Refactor shopping cart patterns

* committing to pull down changes

* updated product preview

* updated image

* updated incentives

* Clean up utility usage and code formatting for category previews

* started updating with style utilities

* Clean up utilities and formatting, replace placeholder text in order history

* updated incentive images

* updated reviews

* added review variant

* more polish

* some heavy duty updates

* removed store navigation

* switching machines
:

* Clean up utility usage and code formatting for order summaries

* Clean up utility usage and code formatting for product previews

* big switchover

* removed old file

* working on sidebar

* updated sidebar

* created info category

* splitting up the old blog page

* a little cleanup and adding detail

* got three done

* updated social share

* Quick formatting adjustment

* initial paywalls

* Use overviews in pattern subcategories (#826)

* Do not error if no pages

* Automatically set parents and tags for patterns

* Update overview.njk

* [WIP] Use overview pages for pattern listings

* Remove explicit parents

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>

* some newsletter signups

* added login patterns

* reworked feeds'

* a few more

* added a few more

* add more app patterns

* App pattern tweaks (#827)

* Fix `patterns.css` reference

* Tweaks to action panel patterns

* Tweaks to comments patterns

* Progress on data display patterns

* Progress on empty state patterns

* Use email-related data from recent update in `pattern-main` (altered slightly)

* Tweaks to data display patterns

* Tweaks to empty state patterns

* Tweaks to FAQ patterns

* Tweaks to feed patterns

* Tweaks to grid patterns

* Tweaks to pagination patterns

* Tweaks to pricing patterns

* Tweaks to description list patterns

* Tweaks to leaderboard patterns

* Add and update names and descriptions

* Ensure comments fields have labels

* Tweak recent additions

* switching machines

* catching up with next

* added permissions pattern

* switching machines

* added post articles

* having local browset issues

* a few more app patterns

* took out info patterns

* spiffed up the action panels

* gave the action panels a once over

* added content to data display

* updated a few patterns

* clean up a few e-commerce patterns

* added time componen to reviews

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
Co-authored-by: Lea Verou <lea@verou.me>
Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-04-14 11:10:54 -04:00
Lea Verou
003fd28cb0 Mark code-demo and viewport-demo as pro 2025-04-10 10:57:06 -05:00
Lea Verou
2f300d8930 [Popup] Use viewport as default boundary for flip too (#865) 2025-04-10 10:52:15 -05:00
Lea Verou
f13deb87bb Drop hoist from public API, use Popover API where supported (#351)
* First stab at using the Popover API for PE

* fix popup

* First stab at using the Popover API for PE

* fix popup

* Prettier

* Fix TS error

* Remove workaround

* Default to `strategy = fixed` if Popover API is not supported

* Clear out default UA styles for popovers

* Kill `hoist` with fire 🔥

* Refactor

* Update `@floating-ui/dom`

* Fix flipping and shofting

* Fix autosize

* Use `defaultBoundary` for `flip` too

That way we get the previous behavior for it.

* Remove `strategy`, just use `SUPPORTS_POPOVER` check where relevant

* Remove uses of `strategy`

* Use viewport as the default boundary for shifting and autosizing and add `boundary=scroll` to override

---------

Co-authored-by: konnorrogers <konnor5456@gmail.com>
2025-04-09 16:47:40 -05:00
Konnor Rogers
deb9fd70b3 fix pass through copying (#860)
* fix pass through copying

* prettier
2025-04-04 13:46:41 -04:00
Lea Verou
ff3b3d6558 Remove current class from existing sidebar link before adding it to new one 2025-04-02 14:16:03 -04:00
Lea Verou
6b3edb8a56 Tiny fix in saving mixin 2025-04-02 14:16:03 -04:00
Lea Verou
6162b8b115 Move v-content directive to separate file 2025-04-02 11:51:12 -04:00
Lea Verou
cff752b600 Move CRUD logic from palette app to Vue mixin 2025-04-02 11:51:12 -04:00
Lea Verou
7892a94b9b Rewrite and generalize CRUD logic for customizable entities (palettes, themes) (#854)
* Generalize CRUD logic to more easily support themes (and other types of entities)
* Decouple data structures managing saved entities (palettes, themes), sidebar update logic, and palette app (and soon themer) by using events
* Simplify logic (a lot of it carried complexity back from the time we did not use uids and/or was overly general)
* `PersistedArray` class to encapsulate arrays persisted in localStorage
* Remove unused `palette.equals()` function
2025-04-01 16:26:25 -04:00
Lea Verou
40a58ff35f Do not rely on {% raw %}, fixes #851 2025-03-31 17:53:33 -04:00
Lea Verou
0f2950c4cc Import CRUD parts from #828 2025-03-31 17:53:33 -04:00
Cory LaViska
b334884f57 remove unused custom properties (#853) 2025-03-31 17:08:50 +00:00
Cory LaViska
734417d66b fix version 2025-03-28 13:40:28 -04:00
Lea Verou
2cfd651d2f Prevent theme icons from getting focus when tabbing
Looks like `tabindex="-1"` didn't work, need to file a separate issue for that
2025-03-28 13:27:08 -04:00
Lea Verou
3e2d1b98be Changelog fixes
- Moved fixes to bug fixes section
- Linked `allDefined()` and `.wa-cloak` to their docs
- Grouped related bugfixes together
- Moved docs bugfixes to the end (since they are of least interest to users)
2025-03-28 13:27:08 -04:00
Lea Verou
40f332f37c Expand docs on allDefined() 2025-03-28 13:27:08 -04:00
Lea Verou
bfda64f690 Fix wa-cloak docs 2025-03-28 13:27:08 -04:00
Konnor Rogers
883d6df2ef fix z-index issues on sticky-disabled elements. (#848) 2025-03-28 12:26:30 -04:00
Lea Verou
b4240fd321 Move /docs/installation to /docs/, fix parent URL logic, closes #585 (#846)
* Fix: Parent URL should be undefined if parent is falsy

* Document `docs.11tydata.js` better

* Move `docs/installation.md` to `docs/`, fixes #585

* Just in case
2025-03-28 12:12:42 -04:00
Cory LaViska
8755a834f6 3.0.0-alpha.12 2025-03-28 11:07:44 -04:00
Cory LaViska
8d905296b8 update changelog 2025-03-28 11:07:42 -04:00
Cory LaViska
8eba1e5003 Various bug fixes (#839)
* add default icon spacing in tab; fixes #779

* fix radio button pill styles; fixes #759

* remove redundant styles

* fixes #840

* fix focus ring in Safari; fixes #745

* improve details styles; fixes #685

* update examples

* Revert "improve details styles; fixes #685"

This reverts commit 8151872d22.

* revert

* revert

* fix dropdown alignment in button group; closes #374

* fix progress animation in Safari; closes #356

* fix native checkbox indeterminate icon; closes #386

* add comment

* stop running SSR tests locally

* update test

* add FA kit code for codepen 🤞🏻

* remove wa-cloak after components load

* fix whitespace

* update display labels when changed; fixes #702

* fix radio labels (ALPHA-211)

* revert example

* add option as a dep of select

* remove outdated section
2025-03-28 10:57:01 -04:00
Konnor Rogers
21aa85acc0 fix search for webawesome app (#845)
* fix search for webawesome app

* prettier
2025-03-27 16:51:41 -04:00
Lea Verou
404c15b303 Fix race condition, closes #843 2025-03-27 16:14:24 -04:00
Lea Verou
8a26afc334 Fix for theme icons + easier to generate palette icons (#841)
* Make sure components that only appear within page icons are still detected

* Palette icons

* Update theme-icons.css

* Reduce whitespace between swatches

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-03-27 14:25:52 -04:00
Cory LaViska
513a1e35a9 Dialog fixes (#790)
* revert structure and styles to fix WA-A #123

* fix WA-A #201

* update changelog

* fix search dialog position so it doesn't jump around

* remove close watcher; fix dialog/drawer backdrop animations
2025-03-27 12:14:35 -04:00
Lea Verou
09f668fc99 Workaround for dark mode 2025-03-26 18:31:08 -04:00
Lea Verou
d451ba98e5 Fix web fonts in theme icons
Instead of raw DSD, use a component that pulls in a child template and then goes over the CSS and extracts font-related rules into the document, just once per rule.
This also fixes theme icons in Vue.
2025-03-26 18:31:08 -04:00
lindsaym-fa
fd287edd56 Change balance of color swatches 2025-03-26 18:31:08 -04:00
Lea Verou
8424b49646 Theme icons, take 1 2025-03-26 18:31:08 -04:00
Lea Verou
fa24c0f70e Update changelog.md 2025-03-26 13:08:44 -04:00
Cory LaViska
1bba87c66d Improve search lists (#837)
* add debounce to search so it feels more natural

* improve search grid styles
2025-03-26 16:07:09 +00:00
Cory LaViska
0db9ca12e3 Remove unused SSR module and remove first load fade (#835)
* disable SSR module in 11ty

* remove first load fade
2025-03-26 14:45:29 +00:00
Lea Verou
041555fe99 border-radius: 0 on plain details 2025-03-26 10:04:25 -04:00
Lea Verou
b41dbd2de7 Fix: Specify default card background 2025-03-25 16:53:16 -04:00
Lea Verou
7c6f31e0c7 [Card docs] Use style utilities instead of custom CSS 2025-03-25 16:31:40 -04:00
Lea Verou
9e84274a93 [Card] Round all corners of the image for appearance=plain 2025-03-25 16:31:40 -04:00
Lea Verou
2b3803f91e [Card] Support appearance, closes #609 2025-03-25 16:31:40 -04:00
Lea Verou
faed8da3cd Fix broken link 2025-03-25 14:14:53 -04:00
Lea Verou
17cf902f53 Add appearance to details, closes #569
Except `accent` as that's a) far less useful and b) trickier due to the icon color
2025-03-25 14:14:53 -04:00
Lea Verou
8214ff6b2d Several fixes around overviews, outlines etc (#825)
* Fix outline for headings that have links

Previously produced blank items because it assumed any link in a heading is an anchor

* Filter unlisted items from overviews

Previously they were filtered only when the card was rendered, so their heading was still shown

* [Overview] Add id to group headings

* Hide headings from empty groups

Should never happen but you never know

* [Overview] Ensure "Other" is always last even when no sorting
2025-03-25 11:39:04 -04:00
Cory LaViska
c9979e15f8 adds a hard coded delay to drastically reduce theme picker jank (#829) 2025-03-24 20:49:08 +00:00
Cory LaViska
fcfe2bde7d Add FOUCE utilities (#686)
* add fouce utilities

* add comment

* Update docs/docs/installation.md

Co-authored-by: Lea Verou <lea@verou.me>

* commit PR suggestion

* rename wa-reduce-fouce to wa-cloak

* remove class as requested

* add cloak class

* wait a cycle

* move turbo to same file

* reduce fade

* disable SSR and add Turbo FOUCE helper

* disable SSR

* fix test suite

* workflow dispatch

* update fouce util

* no need to remove cloak class

* simplify fouce util

* add allDefined util

* update changelog

---------

Co-authored-by: Lea Verou <lea@verou.me>
Co-authored-by: konnorrogers <konnor5456@gmail.com>
2025-03-24 20:33:24 +00:00
Lea Verou
59dcaaff83 Content hierarchy bugfixes & improvements (#821)
- Sidebar, overview listings, breadcrumbs now based on actual parent-child relationships, rather than increasingly outdated heuristics
- parent properties are now generated automatically from the URL structure, and need only be specified to override that default
- Ability to group by page hierarchy in overview pages, where pages that have >= 2 children become categories

Smaller improvements:
- More flexible syntax for specifying the params of overview pages
- [Overviews] Hide group heading if only one group is present
- parentItem and parentUrl properties that can be used on any page
- Alias a collection as the children of a page (useful for "virtual" parents like Layout)
- Do not error if a page card icon is missing
2025-03-21 16:30:06 -04:00
Cory LaViska
5bad30ec30 fix remove event and return null when empty (#819)
* fix remove event and return null when empty

* use closest
2025-03-21 13:01:49 -04:00
Lea Verou
87c1762146 Scrub :host-context() from everywhere 2025-03-21 12:55:25 -04:00
Konnor Rogers
899edd1d5e Konnorrogers/add a guard for non server deploys (#818)
* add a guard for non-server builds

* add a guard for non-server builds

* add a guard for non-server builds

* prettier
2025-03-20 16:37:22 -04:00
Konnor Rogers
872a110b1e reflect href on buttons (#817) 2025-03-20 14:58:21 -04:00
Lindsay M
07fe6d598e Add curated orange to all palettes, closes #657 (#798)
* Adjust `orange` in Default palette

* Adjust `orange`, `red`, and `yellow` in Classic palette

* Adjust `orange` in Anodized palette

* Adjust `orange` in Bright palette

* Adjust `orange` in Mild palette

* Adjust `orange` in Natural palette

* Adjust `orange` in Vogue palette

* Adjust `orange` in Rudimentary palette

* Adjust `orange` in Elegant palette
2025-03-18 16:08:31 -04:00
Konnor Rogers
79bafc513a 11ty for webawesome-app (#803)
* working on integration

* 11ty for webawesome + app

* add flashes

* additional changes

* prettier

* add note about nunjucks

* prettier
2025-03-18 13:04:24 -04: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
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
1802 changed files with 26576 additions and 37221 deletions

View File

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

View File

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

10
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

6
VERSIONS.txt Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,104 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
{% include 'head.njk' %}
<meta name="theme-color" content="#f36944">
<script type="module" src="/assets/scripts/code-examples.js"></script>
<script type="module" src="/assets/scripts/scroll.js"></script>
<script type="module" src="/assets/scripts/turbo.js"></script>
<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 #}
<link rel="stylesheet" href="/assets/styles/docs.css" />
{% block head %}{% endblock %}
</head>
<body class="layout-{{ layout | stripExtension }}{{ ' page-wide' if wide }}">
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
<wa-page view="desktop" disable-navigation-toggle="">
<header slot="header" class="wa-split">
{# Logo #}
<div id="docs-branding">
{# Nav toggle #}
<wa-button appearance="plain" size="small" data-toggle-nav>
<wa-icon name="bars" label="Toggle navigation"></wa-icon>
</wa-button>
<a href="/" aria-label="Web Awesome">
<span class="wa-desktop-only">{% include "logo.njk" %}</span>
<span class="wa-mobile-only">{% include "logo-simple.njk" %}</span>
</a>
<small id="version-number" class="only-desktop">{{ package.version }}</small>
<wa-badge variant="warning" appearance="filled" class="only-desktop">Alpha</wa-badge>
</div>
<div id="docs-toolbar" class="wa-cluster wa-gap-xs">
{# Desktop selectors #}
<div class="only-desktop wa-cluster wa-gap-xs">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
{# Search #}
<wa-button id="search-trigger" appearance="outlined" size="small" data-search>
<wa-icon slot="prefix" name="magnifying-glass"></wa-icon>
Search
<kbd slot="suffix" class="only-desktop">/</kbd>
</wa-button>
</div>
</header>
{# Sidebar #}
{% if hasSidebar %}
{# Mobile selectors #}
<div class="wa-mobile-only" slot="navigation-header">
<div class="wa-cluster wa-gap-xs">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
</div>
<div slot="navigation" id="sidebar" class="docs-aside" data-remember-scroll>
{% include "sidebar.njk" %}
</div>
{% endif %}
{# Outline #}
{% if hasOutline %}
<aside slot="aside" id="outline" class="docs-aside">
<nav id="outline-standard" class="outline-links">
<h2><a href="#content">{{ title }}</a></h2>
</nav>
</aside>
{% endif %}
{# Main #}
<main id="content">
{# Expandable outline #}
<nav id="outline-expandable">
<details class="outline-links">
<summary>On this page</summary>
</details>
</nav>
{% block header %}
{% include 'breadcrumbs.njk' %}
<h1 class="title">{{ title }}</h1>
{% endblock %}
{% block content %}
{{ content | safe }}
{% endblock %}
{% block afterContent %}{% endblock %}
</main>
{% include 'search.njk' %}
</wa-page>
</body>
</html>

View File

@@ -1,10 +0,0 @@
{% set breadcrumbs = page.url | breadcrumbs %}
{% if breadcrumbs.length > 0 %}
<wa-breadcrumb id="docs-breadcrumbs">
{% for crumb in breadcrumbs %}
<wa-breadcrumb-item href="{{ crumb.url }}">{{ crumb.title }}</wa-breadcrumb-item>
{% endfor %}
<wa-breadcrumb-item>{# Current page #}</wa-breadcrumb-item>
</wa-breadcrumb>
{% else %}
{% endif %}

View File

@@ -1,19 +0,0 @@
{# Color scheme selector #}
<wa-select class="color-scheme-selector" appearance="filled" size="small" value="auto" pill title="Press \ to toggle">
<wa-icon class="only-light" slot="prefix" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="prefix" name="moon" variant="regular"></wa-icon>
<wa-option value="light">
<wa-icon slot="prefix" name="sun" variant="regular"></wa-icon>
Light
</wa-option>
<wa-option value="dark">
<wa-icon slot="prefix" name="moon" variant="regular"></wa-icon>
Dark
</wa-option>
<wa-divider></wa-divider>
<wa-option value="auto">
<wa-icon class="only-light" slot="prefix" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="prefix" name="moon" variant="regular"></wa-icon>
System
</wa-option>
</wa-select>

View File

@@ -1,52 +0,0 @@
<table class="colors wa-palette-{{ paletteId }} contrast-table" data-min-contrast="{{ minContrast }}">
<thead>
<tr>
<th></th>
{% for tint_bg in tints -%}
{% for tint_fg in tints | reverse -%}
{% if (tint_fg - tint_bg) | abs == difference %}
<th>{{ tint_fg }} on {{ tint_bg }}</th>
{% endif %}
{%- endfor -%}
{%- endfor %}
</tr>
</thead>
{% for hue in hues -%}
<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 %}
{% 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 %}
{{ tint_fg }} on {{ tint_bg }}
{% endif %}
</div>
</td>
{% endif %}
{%- endfor -%}
{%- endfor -%}
</tr>
{%- endfor %}
</table>

View File

@@ -1,12 +0,0 @@
{# Cards for pages listed by category #}
<section id="grid" class="index-grid">
{% for category, pages in allPages | groupByTags(categories) -%}
<h2 class="index-category">{{ category | getCategoryTitle(categories) }}</h2>
{%- for page in pages -%}
{%- if not page.data.parent or listChildren -%}
{% include "page-card.njk" %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
</section>

View File

@@ -1,49 +0,0 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description }}">
{% if noindex %}<meta name="robots" content="noindex">{% endif %}
<title>{{ title }}</title>
{# Dark mode #}
<script>
let colorScheme = localStorage.colorScheme;
let isDark = localStorage.colorScheme === "dark";
if (!colorScheme || colorScheme === "auto") {
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
document.documentElement.classList.toggle('wa-dark', isDark);
</script>
<link rel="icon" href="/assets/images/webawesome-logo.svg" />
<link rel="apple-touch-icon" href="/assets/images/app-icon.png">
{# Scripts #}
{# Hydration stuff #}
<script src="/assets/scripts/hydration-errors.js"></script>
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<script type="module" src="/assets/scripts/theme-picker.js"></script>
{# Preset Theme #}
{% if forceTheme %}
<link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/{{ forceTheme }}.css" render="blocking" fetchpriority="high" />
{% else %}
<noscript><link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/default.css" render="blocking" fetchpriority="high" /></noscript>
<script>
{
let preset = localStorage.presetTheme ?? 'default';
let script = document.currentScript;
script.insertAdjacentHTML('beforebegin', `<link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/${ preset }.css" render="blocking" fetchpriority="high" />`);
}
</script>
<script type="module" src="/assets/scripts/preset-theme-picker.js"></script>
{% endif %}
<link rel="stylesheet" href="/dist/styles/webawesome.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />

View File

@@ -1,18 +0,0 @@
<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
<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
@import url('{% cdnUrl stylesheet %}');
```
</wa-tab-panel>
</wa-tab-group>

View File

@@ -1,13 +0,0 @@
{%- if not page.data.unlisted -%}
<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>
{% endif %}

View File

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

View File

@@ -1,9 +0,0 @@
{# Preset theme selector #}
<wa-select appearance="filled" size="small" value="default" pill class="preset-theme-selector">
<wa-icon slot="prefix" name="paintbrush" variant="regular"></wa-icon>
{% for theme in collections.theme | sort %}
<wa-option value="{{ theme.page.fileSlug }}"{{ ' data-alpha="remove"' if theme.noAlpha }}>
{{ theme.data.title }}
</wa-option>
{% endfor %}
</wa-select>

View File

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

View File

@@ -1,16 +0,0 @@
{% if not (isAlpha and page.data.noAlpha) and page.fileSlug != tag and not page.data.unlisted -%}
<li>
<a href="{{ page.url }}">{{ page.data.title }}</a>
{% if page.data.status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
{% if page.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% set children = page.data.children %}
{% if children.length > 0 %}
<ul>
{% for page in children %}
{% include 'sidebar-link.njk' %}
{% endfor %}
</ul>
{% endif %}
</li>
{%- endif %}

View File

@@ -1,33 +0,0 @@
{# Getting started #}
<h2>Getting Started</h2>
<ul>
<li><a href="/docs/installation">Installation</a></li>
<li><a href="/docs/usage">Usage</a></li>
<li><a href="/docs/customizing">Customizing</a></li>
<li><a href="/docs/form-controls">Form Controls</a></li>
<li><a href="/docs/localization">Localization</a></li>
</ul>
{# Resources #}
<h2>Resources</h2>
<ul>
<li><a href="https://github.com/shoelace-style/webawesome-alpha/discussions" target="_blank">Help &amp; Support</a></li>
<li><a href="/docs/resources/community">Community</a></li>
<li><a href="/docs/resources/accessibility">Accessibility</a></li>
<li><a href="/docs/resources/contributing">Contributing</a></li>
<li><a href="/docs/resources/changelog">Changelog</a></li>
<li><a href="/docs/resources/visual-tests">Visual Tests</a></li>
</ul>
{% for tag, title in {
'themes': 'Themes',
'components': 'Components',
'native': 'Native Styles',
'utilities': 'Style Utilities',
'layout': 'Layout',
'patterns': 'Patterns',
'palettes': 'Color Palettes',
'tokens': 'Design Tokens'
} %}
{% include 'sidebar-group.njk' %}
{% endfor %}

View File

@@ -1,25 +0,0 @@
{% if since -%}
<wa-badge variant="neutral">Since {{ since }}</wa-badge>
{% endif -%}
{%- if status %}
{%- if status == "wip" %}
<wa-badge variant="danger">
<wa-icon name="pickaxe"></wa-icon>
Work In Progress
</wa-badge>
{%- elif status == "experimental" %}
<wa-badge variant="warning">
<wa-icon name="flask"></wa-icon>
Experimental
</wa-badge>
{%- elif status == "stable" %}
<wa-badge variant="brand">Stable</wa-badge>
{%- else %}
<wa-badge>{{ status}}</wa-badge>
{%- endif -%}
{%- endif %}
{%- if isPro %}
<wa-badge class="pro">PRO</wa-badge>
{%- endif -%}

View File

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

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

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

View File

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

View File

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

View File

@@ -1,144 +0,0 @@
<div class="showcase-examples-wrapper" aria-hidden="true" data-no-outline>
<div class="showcase-examples">
<wa-card with-header with-footer>
<div slot="header" class="wa-split">
<h3 class="wa-heading-m">Your Cart</h3>
<wa-icon-button name="xmark" tabindex="-1"></wa-icon-button>
</div>
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<wa-avatar shape="rounded" style="--size: 3em; --background-color: var(--wa-color-green-60); --text-color: var(--wa-color-green-95);">
<wa-icon slot="icon" name="sword-laser" family="duotone" style="font-size: 1.5em;"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>Initiate Saber</strong>
<strong>$179.99</strong>
</div>
<div class="wa-split wa-gap-2xs wa-caption-m">
<span>Green</span>
<a href="#" tabindex="-1">Remove</a>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-avatar shape="rounded" style="--size: 3em; --background-color: var(--wa-color-cyan-60); --text-color: var(--wa-color-cyan-95);">
<wa-icon slot="icon" name="robot-astromech" family="duotone" style="font-size: 1.5em;"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>Repair Droid</strong>
<strong>$3,049.99</strong>
</div>
<div class="wa-split wa-gap-2xs wa-caption-m">
<span>R-series</span>
<a href="#" tabindex="-1">Remove</a>
</div>
</div>
</div>
</div>
<div slot="footer" class="wa-stack">
<div class="wa-split">
<strong>Subtotal</strong>
<strong>$3,229.98</strong>
</div>
<span class="wa-caption-m">Shipping and taxes calculated at checkout.</span>
<wa-button tabindex="-1" variant="brand">
<wa-icon slot="prefix" name="shopping-bag"></wa-icon>
Checkout
</wa-button>
</div>
</wa-card>
<wa-card>
<wa-avatar shape="rounded" style="--size: 1.9lh; float: left; margin-right: var(--wa-space-m);">
<wa-icon slot="icon" name="hat-wizard" family="duotone" style="font-size: 1.75em;"></wa-icon>
</wa-avatar>
<p class="wa-body-l" style="margin: 0;">&ldquo;All we have to decide is what to do with the time that is given to us. There are other forces at work in this world, Frodo, besides the will of evil.&rdquo;</p>
</wa-card>
<wa-card>
<div class="wa-stack">
<h3 class="wa-heading-m">Sign In</h3>
<wa-input tabindex="-1" label="Email" placeholder="ddjarin@mandalore.gov">
<wa-icon slot="prefix" name="envelope" variant="regular"></wa-icon>
</wa-input>
<wa-input tabindex="-1" label="Password" type="password">
<wa-icon slot="prefix" name="lock" variant="regular"></wa-icon>
</wa-input>
<wa-button tabindex="-1" variant="brand">Sign In</wa-button>
<a href="#" tabindex="-1" class="wa-body-s">I forgot my password</a>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-stack">
<div class="wa-split">
<h3 class="wa-heading-m">To-Do</h3>
<wa-icon-button tabindex="-1" name="plus" label="Add task"></wa-icon-button>
</div>
<wa-checkbox tabindex="-1" checked>Umbrella for Adelard</wa-checkbox>
<wa-checkbox tabindex="-1" checked>Waste-paper basket for Dora</wa-checkbox>
<wa-checkbox tabindex="-1" checked>Pen and ink for Milo</wa-checkbox>
<wa-checkbox tabindex="-1">Mirror for Angelica</wa-checkbox>
<wa-checkbox tabindex="-1">Silver spoons for Lobelia</wa-checkbox>
</div>
<div slot="footer">
<a href="" tabindex="-1">View all completed</a>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<div class="wa-frame wa-border-radius-m" style="align-self: center; max-inline-size: 25ch;">
<img src="https://images.unsplash.com/photo-1667514627762-521b1c815a89?q=20" alt="Album art">
</div>
<div class="wa-flank:end wa-align-items-start">
<div class="wa-stack wa-gap-3xs">
<div class="wa-cluster wa-gap-xs" style="height: 2.25em;">
<strong>The Stone Troll</strong>
<small><wa-badge variant="neutral" appearance="filled">E</wa-badge></small>
</div>
<span class="wa-caption-m">Samwise G</span>
</div>
<wa-icon-button tabindex="-1" name="ellipsis" label="Options"></wa-icon-button>
</div>
<div class="wa-stack wa-gap-2xs">
<wa-progress-bar value="34" style="height: 0.5em"></wa-progress-bar>
<div class="wa-split">
<span class="wa-caption-xs">1:01</span>
<span class="wa-caption-xs">-1:58</span>
</div>
</div>
<div class="wa-grid wa-align-items-center" style="--min-column-size: 1em; justify-items: center;">
<wa-icon-button tabindex="-1" name="backward" label="Skip backward"></wa-icon-button>
<wa-icon-button tabindex="-1" name="pause" style="font-size: var(--wa-font-size-2xl);" label="Pause"></wa-icon-button>
<wa-icon-button tabindex="-1" name="forward" label="Skip forward"></wa-icon-button>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<h3 class="wa-heading-m">Chalmun's Spaceport Cantina</h3>
<div class="wa-cluster wa-gap-xs">
<wa-rating value="4.6" read-only></wa-rating>
<strong>4.6</strong>
<span>(419 reviews)</span>
</div>
<div class="wa-cluster wa-gap-xs">
<div class="wa-cluster wa-gap-3xs">
<wa-icon name="dollar" style="color: var(--wa-color-green-60);"></wa-icon>
<wa-icon name="dollar" style="color: var(--wa-color-green-60);"></wa-icon>
<wa-icon name="dollar" style="color: var(--wa-color-green-60);"></wa-icon>
</div>
<span class="wa-caption-m">&bull;</span>
<wa-tag size="small">Cocktail Bar</wa-tag>
<wa-tag size="small">Gastropub</wa-tag>
<wa-tag size="small">Local Fare</wa-tag>
<wa-tag size="small">Gluten Free</wa-tag>
</div>
<div class="wa-flank wa-gap-xs">
<wa-icon name="location-dot"></wa-icon>
<a href="#" class="wa-caption-m" tabindex="-1">Mos Eisley, Tatooine</a>
</div>
</div>
</wa-card>
</div>
</div>

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
{% include 'head.njk' %}
</head>
<body class="layout-{{ layout | stripExtension }}">
{% block header %}{% endblock %}
{% block content %}
{{ content | safe }}
{% endblock %}
{% block afterContent %}{% endblock %}
</body>
</html>

View File

@@ -1,38 +0,0 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends '../_includes/base.njk' %}
{# Component header #}
{% block header %}
{% include 'breadcrumbs.njk' %}
<h1 class="title">{{ title }}</h1>
<div class="block-info">
{% set snippets = (elements or element or snippets or snippet) | dict %}
{% for snippet, link in snippets %}
{% if snippet %}
<code class="class">
{%- if link -%}
<a href="{{ link }}">{{ snippet }}</a>
{%- else -%}
{{ snippet }}
{%- endif-%}
</code>
{%- endif %}
{% endfor %}
{% include '../_includes/status.njk' %}
</div>
{% if description %}
<p class="summary">
{{ description | inlineMarkdown | safe }}
</p>
{% endif %}
{% block notes %}{% endblock %}
{% endblock %}
{# Content #}
{% block content %}
{{ content | safe }}
{% endblock %}

View File

@@ -1,32 +0,0 @@
{% extends '../_layouts/block.njk' %}
{# Component header #}
{% block notes %}
{% if component %}
<wa-callout variant="success">
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
Want to do more?
Check out the {% for name in (component | toList) -%}
{{ ' and ' if loop.last and not loop.first }}<a href="/docs/components/{{ name }}"><code>&lt;wa-{{ name }}&gt;</code></a>{{ ', ' if not loop.last }}
{%- endfor %} component{{ 's' if (component | isList) }}</a>!
</wa-callout>
{% endif %}
{% endblock %}
{% block afterContent %}
{% if file %}
{% markdown %}
## Opting In to Native {{ title }} Styles
If you want to use the Native {{ title }} styles **without including the entirety of Web Awesome Native Styles**,
you can include the following CSS files from the Web Awesome CDN.
{% set stylesheet = file %}
{% include 'import-stylesheet-code.md.njk' %}
To use all of Web Awesome Native styles, follow the [instructions on the Native Styles overview page](../).
{% endmarkdown %}
{% endif %}
{% endblock %}

View File

@@ -1,25 +0,0 @@
---
layout: page-outline
tags: ["overview"]
---
{% set forTag = forTag or (page.url | split('/') | last) %}
{% if description %}
<div class="index-summary">{{ description | markdown | safe }}</div>
{% endif %}
<div id="block-filter">
<wa-input type="search" placeholder="Search {{ title }}" clearable autofocus>
<wa-icon slot="prefix" name="search"></wa-icon>
</wa-input>
</div>
{% set allPages = collections[forTag] %}
{% include "grouped-pages.njk" %}
<link href="/assets/styles/filter.css" rel="stylesheet">
<script type="module" src="/assets/scripts/filter.js"></script>
{% if content | trim %}
<wa-divider style="--spacing: var(--wa-space-3xl)"></wa-divider> {# Temp fix for spacing issue #}
{{ content | safe }}
{% endif %}

View File

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

View File

@@ -1,318 +0,0 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% set paletteId = page.fileSlug %}
{% set tints = ["95", "90", "80", "70", "60", "50", "40", "30", "20", "10", "05"] %}
{% 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>
<th class="core-column">Core tint</th>
{% for tint in tints -%}
<th>{{ tint }}</th>
{%- endfor %}
</tr>
</thead>
{# Initialize to last hue before gray #}
{%- set hueBefore = hues[hues|length - 2] -%}
{% for hue in hues -%}
{% 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 -%}
{%- 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>
{%- endfor -%}
</tr>
{%- 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">
{% for page in collections.theme %}
{%- if page.data.palette == paletteId -%}
{% include "page-card.njk" %}
{%- endif -%}
{% endfor %}
</section>
{% markdown %}
## Color Contrast
Web Awesome color scales are designed to guarantee certain contrast ratios,
both per [WCAG 2.1 success criteria](https://www.w3.org/TR/WCAG21/#contrast-minimum)
as well as the emergent APCA specification _(planned)_,
so you can ensure that text is both legible to all users, and legally conformant.
### Level 1
A difference of `40` ensures a minimum **3:1** contrast ratio, suitable for large text and icons (AA).
{% endmarkdown %}
{% set difference = 40 %}
{% set minContrast = 3 %}
{% include "contrast-table.njk" %}
{% markdown %}
This also goes for a difference of `45`:
{% endmarkdown %}
{% set difference = 45 %}
{% include "contrast-table.njk" %}
{% markdown %}
### Level 2
A difference of `50` ensures a minimum **4.5:1** contrast ratio, suitable for normal text (AA) and large text (AAA)
{% endmarkdown %}
{% set difference = 50 %}
{% set minContrast = 4.5 %}
{% include "contrast-table.njk" %}
{% markdown %}
This also goes for a difference of `55`:
{% endmarkdown %}
{% set difference = 55 %}
{% include "contrast-table.njk" %}
{% markdown %}
### Level 3
A difference of `60` ensures a minimum **7:1** contrast ratio, suitable for all text (AAA)
{% endmarkdown %}
{% set difference = 60 %}
{% set minContrast = 7 %}
{% include "contrast-table.njk" %}
{% markdown %}
This also goes for a difference of `65`:
{% endmarkdown %}
{% set difference = 65 %}
{% include "contrast-table.njk" %}
{% markdown %}
## 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' %}
<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

@@ -1,207 +0,0 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{# {% set forceTheme = page.fileSlug %} #}
{% extends '../_includes/base.njk' %}
{% block head %}
<script>
globalThis.wa_data ??= {};
wa_data.baseTheme = "{{ page.fileSlug }}";
wa_data.themes = {
{% for theme in collections.theme -%}
"{{ theme.fileSlug }}": {
"title": "{{ theme.data.title }}",
"palette": "{{ theme.data.palette }}",
"brand": "{{ theme.data.brand }}"
},
{% endfor %}
};
wa_data.palettes = {
{% for palette in collections.palette -%}
"{{ palette.fileSlug }}": {
"title": "{{ palette.data.title }}",
},
{% endfor %}
};
</script>
<link href="{{ page.url }}../remix.css" rel="stylesheet">
<script src="{{ page.url }}../remix.js" type="module"></script>
{% endblock %}
{% block header %}
<iframe src='{{ page.url }}demo.html' id="demo"></iframe>
<wa-details id="mix_and_match" class="wa-gap-m" >
<h4 slot="summary" data-no-anchor data-no-outline id="remix">
<wa-icon name="arrows-rotate"></wa-icon>
Remix this theme
<wa-icon id="what-is-remixing" href="#remixing" name="circle-question" slot="suffix" variant="regular"></wa-icon>
<wa-tooltip for="what-is-remixing">Customize this theme by changing its colors and/or remixing it with design elements from other themes!</wa-tooltip>
</h4>
<wa-select name="colors" label="Colors from…" value="" clearable>
<wa-icon name="palette" slot="prefix" variant="regular"></wa-icon>
{% for theme in collections.theme | sort %}
{% set currentTheme = theme.fileSlug == page.fileSlug %}
<wa-option label="{{ theme.data.title }}" value="{{ theme.fileSlug if not currentTheme }}" {{ (theme.fileSlug if currentTheme) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/theme-color.njk" %}
</div>
<span class="page-name">
{{ theme.data.title }}
{% if theme.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% if currentTheme %}<wa-badge variant="neutral" appearance="outlined">This theme</wa-badge>{% endif %}
</span>
</wa-card>
</wa-option>
{% endfor %}
</wa-select>
<wa-select name="palette" label="Palette" clearable>
<wa-icon name="swatchbook" slot="prefix" variant="regular"></wa-icon>
{% set defaultPalette = palette %}
{% for palette in collections.palette | sort %}
{% set currentPalette = palette.fileSlug == defaultPalette %}
<wa-option label="{{ palette.data.title }}" value="{{ palette.fileSlug if not currentPalette }}" {{ (palette.fileSlug if currentPalette) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/" + (palette.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">
{{ palette.data.title }}
{% if palette.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% if currentPalette %}<wa-badge variant="neutral" appearance="outlined">Theme default</wa-badge>{% endif %}
</span>
</wa-card>
</wa-option>
{% endfor %}
{% set palette = defaultPalette %}
</wa-select>
<wa-select name="brand" label="Brand color" value="" clearable>
<div class="selected-swatch" slot="prefix"></div>
{% for hue in hues %}
{% set currentBrand = hue == brand %}
<wa-option label="{{ hue | capitalize }}" value="{{ hue if not currentBrand }}" {{ (hue if currentBrand) | attr('data-id') }} style="--color: var(--wa-color-{{ hue }})">
{{ hue | capitalize }}
{% if currentBrand %}<wa-badge variant="neutral" appearance="outlined">Theme default</wa-badge>{% endif %}
</wa-option>
{% endfor %}
</wa-select>
<wa-select name="typography" label="Typography from…" clearable>
<wa-icon name="font-case" slot="prefix"></wa-icon>
{% for theme in collections.theme | sort %}
{% set currentTheme = theme.fileSlug == page.fileSlug %}
<wa-option label="{{ theme.data.title }}" value="{{ theme.fileSlug if not currentTheme }}" {{ (theme.fileSlug if currentTheme) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/theme-typography.njk" %}
</div>
<span class="page-name">
{{ theme.data.title }}
{% if theme.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% if currentTheme %}<wa-badge variant="neutral" appearance="outlined">This theme</wa-badge>{% endif %}
</span>
</wa-card>
</wa-option>
{% endfor %}
</wa-select>
</wa-details>
<h2>Color</h2>
{% set paletteURL = '/docs/palettes/' + palette + '/' %}
<div class="index-grid">
{% set themePage = page %}
{% set page = paletteURL | getCollectionItemFromUrl %}
{% set pageSubtitle = "Default color palette" %}
{% include 'page-card.njk' %}
{% set page = themePage %}
<wa-card style="--header-background: var(--wa-color-{{ brand }})" class="wa-palette-{{ palette }}">
<div slot="header"></div>
<div class="page-name">{{ brand | capitalize }}</div>
<div class="wa-caption-s">Default brand color</div>
</wa-card>
</div>
{% endblock %}
{% block afterContent %}
<h2 id="usage">How to use this theme</h2>
{% markdown %}
You can import this theme from the Web Awesome CDN.
{% set stylesheet = 'styles/themes/' + page.fileSlug + '.css' %}
{% include 'import-stylesheet-code.md.njk' %}
## Dark mode
To activate the dark color scheme of the theme on any element and its contents, apply the class `wa-dark` to it.
This means you can use different color schemes throughout the page.
Here, we use the default theme with a dark sidebar:
```html
<html>
<head>
<link rel="stylesheet" href="path/to/web-awesome/dist/styles/themes/default.css" />
</head>
<body>
<nav class="wa-dark">
<!-- dark-themed sidebar -->
</nav>
<!-- light-themed content -->
</body>
</html>
```
You can apply the class to the `<html>` element on your page to activate the dark color scheme for the entire page.
```html
<html class="wa-dark">
<head>
<link rel="stylesheet" href="path/to/web-awesome/dist/styles/themes/{{ page.fileSlug }}.css" />
<!-- other links, scripts, and metadata -->
</head>
<body>
<!-- page content -->
</body>
</html>
```
### Detecting Color Scheme Preference
Web Awesome's themes have both light and dark styles built in.
However, Web Awesome doesn't try to auto-detect the user's light/dark mode preference.
This should be done at the application level.
As a best practice, to provide a dark theme in your app, you should:
- Check for [`prefers-color-scheme`](https://stackoverflow.com/a/57795495/567486) and use its value by default
- Allow the user to override the setting in your app
- Remember the user's preference and restore it on subsequent logins
Web Awesome avoids using the `prefers-color-scheme` media query because not all apps support dark mode, and it would break things for the ones that don't.
Assuming the user's preference is in a variable called `colorScheme` (values: `auto`, `light`, `dark`),
you can use the following JS snippet to apply the `wa-dark` class to the `<html>` element accordingly:
```js
const systemDark = window.matchMedia('(prefers-color-scheme: dark)');
const applyDark = function (event = systemDark) {
const isDark = colorScheme === 'auto' ? event.matches : colorScheme === 'dark';
document.documentElement.classList.toggle('wa-dark', isDark);
};
systemDark.addEventListener('change', applyDark);
applyDark();
```
{% endmarkdown %}
{% endblock %}

View File

@@ -1,19 +0,0 @@
{% extends '../_layouts/block.njk' %}
{% block afterContent %}
{% if file %}
{% markdown %}
## Opting In
If you want to use this utility **only** without [all others](../), you can include the following CSS file from the Web Awesome CDN.
{% set stylesheet = file %}
{% include 'import-stylesheet-code.md.njk' %}
Want them all?
Follow the [instructions on the Utilities overview page](../) to get all Web Awesome utilities.
{% endmarkdown %}
{% endif %}
{% endblock %}

View File

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

View File

@@ -1,190 +0,0 @@
import { parse } from 'node-html-parser';
import { v4 as uuid } from 'uuid';
const templates = {
old(pre, code, { open, buttons, edit }) {
const id = `code-example-${uuid().slice(-12)}`;
let preview = code.textContent;
// Run preview scripts as modules to prevent collisions
const root = parse(preview, { blockTextElements: { script: true } });
root.querySelectorAll('script').forEach(script => script.setAttribute('type', 'module'));
preview = root.toString();
return `
<div class="code-example ${open ? 'open' : ''}">
<div class="code-example-preview">
${preview}
</div>
<div class="code-example-source" id="${id}">
${pre.outerHTML}
</div>
${
buttons
? `
<div class="code-example-buttons">
<button
class="code-example-toggle"
type="button"
aria-expanded="${open ? 'true' : 'false'}"
aria-controls="${id}"
>
Code
<wa-icon name="chevron-down"></wa-icon>
</button>
${
edit
? `
<button class="code-example-pen" type="button">
<wa-icon name="pen-to-square"></wa-icon>
Edit
</button>
`
: ''
}
`
: ''
}
</div>
</div>
`;
},
new(pre, code, { open, first, attributes }) {
attributes = {
open,
include: `link[rel=stylesheet][href^='/dist/']`,
...attributes,
};
const attributesString = Object.entries(attributes)
.map(([key, value]) => {
if (value === true) {
return key;
}
if (value === false || value === null) {
return '';
}
return `${key}="${value}"`;
})
.join(' ');
let includes = '';
if (first) {
includes = `
<template class="wa-code-demo-include-isolated">
<script src="/dist/webawesome.loader.js" type="module"></script>
</template>`;
}
let preview = '';
if (attributes.viewport === undefined) {
// Slot in pre-rendered preview
preview = `<div style="display:contents" slot="preview">${code.textContent}</div>`;
// Run preview scripts as modules to prevent collisions
const root = parse(preview, { blockTextElements: { script: true } });
root.querySelectorAll('script').forEach(script => script.setAttribute('type', 'module'));
preview = root.toString();
}
return `${includes}
<wa-code-demo ${attributesString}>
${preview}
${pre.outerHTML}
</wa-code-demo>
`;
},
};
/**
* Eleventy plugin to turn `<code class="example">` blocks into live examples.
*/
export function codeExamplesPlugin(eleventyConfig, options = {}) {
const defaultOptions = {
container: 'body',
defaultOpen: (code, { outputPathIndex }) => {
return (
outputPathIndex === 1 && // is first
code.textContent.length < 500
); // is short
},
};
options = { ...defaultOptions, ...options };
const stats = {
inputPaths: {},
outputPaths: {},
};
eleventyConfig.addTransform('code-examples', function (content) {
const { inputPath, outputPath } = this.page;
const doc = parse(content, { blockTextElements: { code: true } });
const container = doc.querySelector(options.container);
if (!container) {
return content;
}
// Look for external links
container.querySelectorAll('code.example').forEach(code => {
stats.inputPaths[inputPath] ??= 0;
stats.outputPaths[outputPath] ??= 0;
stats.inputPaths[inputPath]++;
stats.outputPaths[outputPath]++;
const pre = code.closest('pre');
const first = stats.inputPaths[inputPath] === 1;
const localOptions = {
...options,
first,
// Modifier defaults
edit: true,
buttons: true,
new: true, // comment this line to default back to the old demos
attributes: {},
};
for (const prop of ['new', 'open', 'buttons', 'edit']) {
if (code.classList.contains(prop)) {
localOptions[prop] = true;
} else if (code.classList.contains(`no-${prop}`)) {
localOptions[prop] = false;
}
}
for (const attribute of ['viewport', 'include']) {
if (code.hasAttribute(attribute)) {
localOptions.attributes[attribute] = code.getAttribute(attribute);
code.removeAttribute(attribute);
}
}
if (Object.keys(localOptions.attributes).length > 0) {
// attributes only work on the new syntax
localOptions.new = true;
}
if (localOptions.open === undefined) {
if (localOptions.defaultOpen === true) {
localOptions.open = localOptions.defaultOpen;
} else if (typeof localOptions.defaultOpen === 'function') {
localOptions.open = localOptions.defaultOpen(code, {
pre,
inputPathIndex: stats.inputPaths[inputPath],
outputPathIndex: stats.outputPaths[outputPath],
});
}
}
const template = localOptions.new ? 'new' : 'old';
const codeExample = parse(templates[template](pre, code, localOptions));
pre.replaceWith(codeExample);
});
return doc.toString();
});
}

View File

@@ -1,41 +0,0 @@
import { parse } from 'node-html-parser';
/**
* Eleventy plugin to add copy buttons to code blocks.
*/
export function copyCodePlugin(eleventyConfig, options = {}) {
options = {
container: 'body',
...options,
};
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;
}
// 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);
}
// 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,284 +0,0 @@
import { parse } from 'path';
export function stripExtension(string) {
return parse(string).name;
}
export function stripPrefix(content) {
return content.replace(/^wa-/, '');
}
// Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited.
// With Prettier 3, this means a leading pipe will exist be present when the line wraps.
export function trimPipes(content) {
return typeof content === 'string' ? content.replace(/^(\s|\|)/g, '').replace(/(\s|\|)$/g, '') : content;
}
export function keys(obj) {
return Object.keys(obj);
}
export function log(firstArg, ...rest) {
console.log(firstArg, ...rest);
return firstArg;
}
function getCollection(name) {
// From https://github.com/11ty/eleventy/blob/d3d24ccddb804e6e14773501d8c4e07e2c4b9c2b/src/Filters/GetLocaleCollectionItem.js#L39-L43
return this.collections?.[name] || this.ctx?.collections?.[name] || this.context?.environments?.collections?.[name];
}
export function getCollectionItemFromUrl(url, collection) {
collection ??= getCollection.call(this, 'all') || [];
return collection.find(item => item.url === url);
}
export function getTitleFromUrl(url, collection) {
const item = getCollectionItemFromUrl.call(this, url, collection);
return item?.data.title || '';
}
export function split(text, separator) {
return (text + '').split(separator).filter(Boolean);
}
export function breadcrumbs(url, { withCurrent = false } = {}) {
const parts = split(url, '/');
const ret = [];
while (parts.length) {
let partialUrl = '/' + parts.join('/') + '/';
let item = getCollectionItemFromUrl.call(this, partialUrl);
if (item && (partialUrl !== url || withCurrent)) {
let title = item.data.title;
if (title) {
ret.unshift({ url: partialUrl, title });
}
}
parts.pop();
if (item?.data.parent) {
let parentURL = item.data.parent;
if (!item.data.parent.startsWith('/')) {
// Parent is in the same directory
parts.push(item.data.parent);
parentURL = '/' + parts.join('/') + '/';
}
let parentBreadcrumbs = breadcrumbs.call(this, parentURL, { withCurrent: true });
return [...parentBreadcrumbs, ...ret];
}
}
return ret;
}
export function isObject(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
export function isList(value) {
return Array.isArray(value) || value instanceof Set;
}
/** Get an Array or Set */
export function toList(value) {
return isList(value) ? value : [value];
}
/**
* Convert any value to something that can be iterated over with a for key, value loop.
* Arrays and sets will be converted to a Map of value -> undefined
*/
export function dict(value) {
if (value instanceof Map || isObject(value)) {
return value;
}
let list = toList(value);
return new Map([...list].map(item => [item, undefined]));
}
export function deepValue(obj, key) {
key = Array.isArray(key) ? key : key.split('.');
return key.reduce((subObj, property) => subObj?.[property], obj);
}
export function number(value, options) {
if (typeof value !== 'number' && isNaN(value)) {
return value;
}
let lang = options?.lang ?? 'en';
if (options?.lang) {
delete options.lang;
}
if (!options || Object.keys(options).length === 0) {
options = { maximumSignificantDigits: 3 };
}
return Number(value).toLocaleString(lang, options);
}
export function isNumeric(value) {
return typeof value === 'number' || (typeof value === 'string' && !isNaN(value));
}
export function isString(value) {
return typeof value === 'string';
}
export function isEmpty(value) {
return value === null || value === undefined || value === '';
}
function compare(a, b) {
let isEmptyA = isEmpty(a);
let isEmptyB = isEmpty(b);
if (isEmptyA) {
if (isEmptyB) {
return 0;
} else {
return 1;
}
} else if (isEmptyB) {
return -1;
}
// Both strings, and at least one non-numeric
if (isNumeric(a) || isNumeric(b)) {
return a - b;
}
return (a + '').localeCompare(b);
}
/** Sort an array of objects by one or more of their properties */
export function sort(arr, by = { 'data.order': 1, 'data.title': '' }) {
let keys = Array.isArray(by) ? by : Object.keys(by);
return arr.sort((a, b) => {
let aValues = keys.map(key => deepValue(a, key) ?? by[key]);
let bValues = keys.map(key => deepValue(b, key) ?? by[key]);
for (let i = 0; i < aValues.length; i++) {
let aVal = aValues[i];
let bVal = bValues[i];
let result = compare(aVal, bVal);
// They are not equal in terms of comparison OR we're at the last key
if (result !== 0 || i === aValues.length - 1) {
return result;
}
}
});
}
/**
* Group an 11ty collection (or any array of objects with a `data.tags` property) by certain tags.
* @param {object[]} collection
* @param { Object<string, string> | (string | Object<string, string>)[]} [tags] The tags to group by. If not provided/empty, defaults to grouping by all tags.
* @returns { Object.<string, object[]> } An object with keys for each tag, and an array of items for each tag.
*/
export function groupByTags(collection, tags) {
if (!collection) {
console.error(`Empty collection passed to groupByTags() to group by ${JSON.stringify(tags)}`);
}
if (!tags) {
// Default to grouping by union of all tags
tags = Array.from(new Set(collection.flatMap(item => item.data.tags)));
} else if (Array.isArray(tags)) {
// May contain objects of one-off tag -> label mappings
tags = tags.map(tag => (typeof tag === 'object' ? Object.keys(tag)[0] : tag));
} else if (typeof tags === 'object') {
// tags is an object of tags to labels, so we just want the keys
tags = Object.keys(tags);
}
let ret = Object.fromEntries(tags.map(tag => [tag, []]));
ret.other = [];
for (let item of collection) {
let categorized = false;
for (let tag of tags) {
if (item.data.tags.includes(tag)) {
ret[tag].push(item);
categorized = true;
}
}
if (!categorized) {
ret.other.push(item);
}
}
// Remove empty categories
for (let category in ret) {
if (ret[category].length === 0) {
delete ret[category];
}
}
return ret;
}
export function getCategoryTitle(category, categories) {
let title;
if (Array.isArray(categories)) {
// Find relevant entry
// [{id: "Title"}, id2, ...]
title = categories.find(entry => typeof entry === 'object' && entry?.[category])?.[category];
} else if (typeof categories === 'object') {
// {id: "Title", id2: "Title 2", ...}
title = categories[category];
}
if (title) {
return title;
}
// Capitalized
return category.charAt(0).toUpperCase() + category.slice(1);
}
const IDENTITY = x => x;
/**
* Helper to print out one or more HTML attributes, especially conditional ones.
* Usage in 11ty:
* - Single attribute: `<foo{{ value | attr(name) }}>`
* - Multiple attributes: `<foo{{ { name1: value1, name2: value2 } | attr }}>`
*
* @overload
* @param {any} value - The attribute value If falsey, the attribute is not printed. If `true` the attribute is printed without a value.
* @param {string} name - The name of the attribute
*
* @overload
* @param {Object<string, any>} obj - Map of attribute names to values
*
* @returns {string} The attribute string. No `| safe` is needed.
*/
export function attr(value, name) {
const safe = this?.env.filters.safe ?? IDENTITY;
if (arguments.length === 1 && value && typeof value === 'object') {
// Called with a single object argument of names to values
let ret = Object.entries(obj)
.map(([name, value]) => attr(value, name))
.join('');
return safe(ret);
}
if (!value) {
// false, "", null, undefined
return '';
}
let ret = ' ' + name + (value === true ? '' : `="${value}"`);
return safe(ret);
}

View File

@@ -1,69 +0,0 @@
import { parse } from 'node-html-parser';
/**
* Eleventy plugin to add an outline (table of contents) to the page. Headings must have an id, otherwise they won't be
* included in the outline. An unordered list containing links will be appended to the target element.
*
* If no headings are found for the outline, the `ifEmpty()` function will be called with a `node-html-parser` object as
* the first argument. This can be used to toggle classes or remove elements when the outline is empty.
*
* See the `node-html-parser` docs for more details: https://www.npmjs.com/package/node-html-parser
*/
export function outlinePlugin(options = {}) {
options = {
container: 'body',
target: '.outline',
selector: 'h2,h3',
ifEmpty: () => null,
...options,
};
return function (eleventyConfig) {
eleventyConfig.addTransform('outline', content => {
const doc = parse(content);
const container = doc.querySelector(options.container);
const ul = parse('<ul></ul>');
let numLinks = 0;
if (!container) {
return content;
}
container.querySelectorAll(options.selector).forEach(heading => {
const id = heading.getAttribute('id');
const level = heading.tagName.slice(1);
const clone = parse(heading.outerHTML);
if (heading.closest('[data-no-outline]')) {
return;
}
// Create a clone of the heading so we can remove links and [data-no-outline] elements from the text content
clone.querySelectorAll('a').forEach(a => a.remove());
clone.querySelectorAll('[data-no-outline]').forEach(el => el.remove());
// Generate the link
const li = parse(`<li data-level="${level}"><a></a></li>`);
const a = li.querySelector('a');
a.setAttribute('href', `#${encodeURIComponent(id)}`);
a.textContent = clone.textContent.trim().replace(/#$/, '');
// Add it to the list
ul.firstChild.appendChild(li);
numLinks++;
});
if (numLinks > 0) {
// Append the list to all matching targets
doc.querySelectorAll(options.target).forEach(target => {
target.appendChild(parse(ul.outerHTML));
});
} else {
// Remove if empty
options.ifEmpty(doc);
}
return doc.toString();
});
};
}

View File

@@ -1,23 +0,0 @@
import { parse } from 'node-html-parser';
/**
* Eleventy plugin to add remove elements with <div data-alpha="remove"> from the alpha build.
*/
export function removeDataAlphaElements(options = {}) {
options = {
isAlpha: false,
...options,
};
return function (eleventyConfig) {
eleventyConfig.addTransform('remove-data-alpha-elements', content => {
const doc = parse(content, { blockTextElements: { code: true } });
if (options.isAlpha) {
doc.querySelectorAll('[data-alpha="remove"]').forEach(el => el.remove());
}
return doc.toString();
});
};
}

View File

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

View File

@@ -1,25 +0,0 @@
function updateResults(input) {
const filter = input.value.toLowerCase().trim();
let filtered = Boolean(filter);
for (let grid of document.querySelectorAll('.index-grid')) {
grid.classList.toggle('filtered', filtered);
for (let item of grid.querySelectorAll('a:has(> wa-card)')) {
let isMatch = true;
if (filter) {
const content = item.textContent.toLowerCase() + ' ' + (item.getAttribute('data-keywords') + ' ');
isMatch = content.includes(filter);
}
item.hidden = !isMatch;
}
}
}
document.documentElement.addEventListener('input', e => {
if (e.target?.matches('#block-filter wa-input')) {
updateResults(e.target);
}
});

View File

@@ -1,52 +0,0 @@
import { domChange, nextFrame, ThemeAspect } from './theme-picker.js';
const presetTheme = new ThemeAspect({
defaultValue: 'default',
key: 'presetTheme',
picker: 'wa-select.preset-theme-selector',
applyChange(options = {}) {
const oldStylesheets = [...document.querySelectorAll('#theme-stylesheet')];
const oldStylesheet = oldStylesheets.pop();
if (oldStylesheets.length > 0) {
// Remove all but the last one
for (let stylesheet of oldStylesheets) {
stylesheet.remove();
}
}
const href = `/dist/styles/themes/${this.value}.css`;
if (!oldStylesheet || oldStylesheet.getAttribute('href') !== href) {
const newStylesheet = document.createElement('link');
Object.assign(newStylesheet, { href, id: 'theme-stylesheet', rel: 'preload', as: 'style' });
oldStylesheet.after(newStylesheet);
newStylesheet.addEventListener(
'load',
e => {
domChange(
async instant => {
// Swap stylesheets
newStylesheet.rel = 'stylesheet';
if (instant) {
// If no VT, delay by 1 frame to make it smoother
await nextFrame();
}
oldStylesheet.remove();
},
{ behavior: 'smooth', ...options },
);
},
{ once: true },
);
}
},
});
window.addEventListener('turbo:render', e => {
presetTheme.applyChange({ behavior: 'instant' });
});

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +0,0 @@
globalThis.Prism = globalThis.Prism || {};
globalThis.Prism.manual = true;
await import('./prism-downloaded.js');
Prism.plugins.customClass.prefix('code-');
export default Prism;

View File

@@ -1,33 +0,0 @@
// Smooth links
document.addEventListener('click', event => {
const link = event.target.closest('a');
if (!link || link.getAttribute('data-smooth-link') === 'off') {
return;
}
const id = (link.hash ?? '').substr(1);
// Only handle smooth scroll if there's a hash and the link points to the current page
if (id && link.pathname === window.location.pathname) {
const target = document.getElementById(id);
const headerHeight = document.querySelector('wa-page > header').clientHeight;
if (target) {
event.preventDefault();
window.scroll({
top: target.offsetTop - headerHeight,
behavior: 'smooth',
});
history.pushState(undefined, undefined, `#${id}`);
}
}
});
// Scroll classes
function updateScrollClass() {
document.body.classList.toggle('scrolled-down', window.scrollY >= 10);
}
window.addEventListener('scroll', updateScrollClass);
window.addEventListener('turbo:render', updateScrollClass);
updateScrollClass();

View File

@@ -1,254 +0,0 @@
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

@@ -1,37 +0,0 @@
/**
* Sync iframe height with its content page (for same-origin iframes)
* NOT CURRENTLY USED ANYWHERE
*/
for (let iframe of document.querySelectorAll('iframe')) {
if (iframe.contentDocument) {
// Already loaded
syncIframeHeight(iframe);
}
iframe.onload = () => {
console.log('iframe loaded');
if (iframe.contentDocument) {
// Same origin
iframe.contentWindow.iframe = iframe;
syncIframeHeight(iframe);
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target === iframe.contentDocument.body) {
syncIframeHeight(iframe);
}
}
});
resizeObserver.observe(iframe.contentDocument.body);
window.addEventListener('turbo:render', syncIframeHeight(iframe));
}
};
}
function syncIframeHeight(iframe) {
iframe.style.height = '0px';
requestAnimationFrame(() => {
iframe.style.height = iframe.contentDocument.body.scrollHeight + 'px';
});
}

View File

@@ -1,119 +0,0 @@
// Helper for view transitions
export function domChange(fn, { behavior = 'smooth' } = {}) {
const canUseViewTransitions =
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (canUseViewTransitions && behavior === 'smooth') {
document.startViewTransition(fn);
} else {
fn(true);
}
}
export function nextFrame() {
return new Promise(resolve => requestAnimationFrame(resolve));
}
export class ThemeAspect {
constructor(options) {
Object.assign(this, options);
this.set();
// Update when local storage changes.
// That way changes in one window will propagate to others (including iframes).
window.addEventListener('storage', event => {
if (event.key === this.key) {
this.set();
}
});
// Listen for selections
document.addEventListener('change', event => {
const picker = event.target.closest(this.picker);
if (picker) {
this.set(picker.value);
}
});
['turbo:before-render', 'turbo:before-stream-render', 'turbo:before-frame-render'].forEach(eventName => {
document.addEventListener(eventName, e => {
const newElement = e.detail.newBody || e.detail.newFrame || e.detail.newStream;
if (newElement) {
this.syncUI(newElement);
}
});
});
}
get() {
return localStorage.getItem(this.key) ?? this.defaultValue;
}
computed = {};
get computedValue() {
if (this.value in this.computed) {
return this.computed[this.value];
}
return this.value;
}
set(value = this.get()) {
if (value === this.value) {
return;
}
this.value = value;
if (this.value === this.defaultValue) {
localStorage.removeItem(this.key);
} else {
localStorage.setItem(this.key, this.value);
}
this.applyChange();
this.syncUI();
}
syncUI(container = document) {
for (let picker of container.querySelectorAll(this.picker)) {
picker.setAttribute('value', this.value);
picker.value = this.value;
}
}
}
const colorScheme = new ThemeAspect({
defaultValue: 'auto',
key: 'colorScheme',
picker: 'wa-select.color-scheme-selector',
computed: {
get auto() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
},
},
applyChange() {
// Toggle the dark mode class
domChange(() => {
let dark = this.computedValue === 'dark';
document.documentElement.classList.toggle(`wa-dark`, dark);
});
},
});
// Update the color scheme when the preference changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => colorScheme.set());
// Toggle color scheme with backslash
document.addEventListener('keydown', event => {
if (
event.key === '\\' &&
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
) {
event.preventDefault();
colorScheme.set(theming.colorScheme.resolvedValue === 'dark' ? 'light' : 'dark');
}
});

View File

@@ -1,6 +0,0 @@
/**
* 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

@@ -1,54 +0,0 @@
/**
* 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

@@ -1,73 +0,0 @@
/**
* 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

@@ -1,81 +0,0 @@
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

@@ -1,36 +0,0 @@
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

@@ -1,34 +0,0 @@
.theme-color-icon {
display: grid;
gap: var(--wa-space-xs);
grid-template-columns: repeat(4, auto);
div {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
border-radius: var(--wa-border-radius-m);
background-color: var(--background-color);
border: var(--wa-border-width-s) var(--wa-border-style) var(--border-color);
padding: var(--wa-space-2xs) var(--wa-space-xs);
color: var(--text-color);
font-weight: var(--wa-font-weight-semibold);
&.plain {
font-weight: var(--wa-font-weight-bold);
}
}
}
.theme-typography-icon {
display: flex;
flex-direction: column;
gap: var(--wa-space-xs);
h3,
p {
margin-block: 0;
padding: 0;
}
}

View File

@@ -1,21 +0,0 @@
---
title: Breadcrumb Item
description: Breadcrumb Items are used inside breadcrumbs to represent different links.
tags: component
parent: breadcrumb
---
```html {.example}
<wa-breadcrumb>
<wa-breadcrumb-item>
<wa-icon slot="prefix" name="house" variant="solid"></wa-icon>
Home
</wa-breadcrumb-item>
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
<wa-breadcrumb-item>Shirts</wa-breadcrumb-item>
</wa-breadcrumb>
```
:::info
Additional demonstrations can be found in the [breadcrumb examples](/docs/components/breadcrumb).
:::

View File

@@ -1,184 +0,0 @@
---
title: Card
description: Cards can be used to group related subjects in a container.
tags: [organization, layout]
icon: card
---
```html {.example}
<wa-card with-image with-footer class="card-overview">
<img
slot="image"
src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
alt="A kitten sits patiently between a terracotta pot and decorative grasses."
/>
<strong>Mittens</strong><br />
This kitten is as cute as he is playful. Bring him home today!<br />
<small>6 weeks old</small>
<div slot="footer">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</div>
</wa-card>
<style>
.card-overview {
max-width: 300px;
}
.card-overview small {
color: var(--wa-color-text-quiet);
}
.card-overview [slot='footer'] {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
```
## Examples
### Basic Card
Basic cards aren't very exciting, but they can display any content you want them to.
```html {.example}
<wa-card class="card-basic">
This is just a basic card. No image, no header, and no footer. Just your content.
</wa-card>
<style>
.card-basic {
max-width: 300px;
}
</style>
```
### Card with Header
Headers can be used to display titles and more.
If using SSR, you need to also use the `with-header` attribute to add a header to the card (if not, it is added automatically).
```html {.example}
<wa-card with-header class="card-header">
<div slot="header">
Header Title
<wa-icon-button name="gear" variant="solid" label="Settings"></wa-icon-button>
</div>
This card has a header. You can put all sorts of things in it!
</wa-card>
<style>
.card-header {
max-width: 300px;
}
.card-header [slot='header'] {
display: flex;
align-items: center;
justify-content: space-between;
}
.card-header h3 {
margin: 0;
}
.card-header wa-icon-button {
font-size: var(--wa-font-size-m);
}
</style>
```
### Card with Footer
Footers can be used to display actions, summaries, or other relevant content.
If using SSR, you need to also use the `with-footer` attribute to add a footer to the card (if not, it is added automatically).
```html {.example}
<wa-card with-footer class="card-footer">
This card has a footer. You can put all sorts of things in it!
<div slot="footer">
<wa-rating></wa-rating>
<wa-button variant="brand">Preview</wa-button>
</div>
</wa-card>
<style>
.card-footer {
max-width: 300px;
}
.card-footer [slot='footer'] {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
```
### Images
Card images are displayed atop the card and will stretch to fit.
If using SSR, you need to also use the `with-image` attribute to add an image to the card (if not, it is added automatically).
```html {.example}
<wa-card with-image class="card-image">
<img
slot="image"
src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
alt="A kitten walks towards camera on top of pallet."
/>
This is a kitten, but not just any kitten. This kitten likes walking along pallets.
</wa-card>
<style>
.card-image {
max-width: 300px;
}
</style>
```
### Sizing
Use the `size` attribute to change a card's size.
```html {.example}
<div class="wa-stack">
<wa-card with-footer size="small">
This is a small card.
<footer slot="footer" class="wa-flank">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
<wa-card with-footer size="medium">
This is a medium card (default).
<footer slot="footer" class="wa-flank">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
<wa-card with-footer size="large">
This is a large card.
<footer slot="footer" class="wa-flank">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
</div>
```
<style>
</style>

View File

@@ -1,46 +0,0 @@
---
title: Carousel Item
description: A carousel item represent a slide within a carousel.
tags: component
parent: carousel
icon: carousel-item
---
```html {.example}
<wa-carousel pagination>
<wa-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</wa-carousel-item>
<wa-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</wa-carousel-item>
</wa-carousel>
```
:::info
Additional demonstrations can be found in the [carousel examples](/docs/components/carousel).
:::

View File

@@ -1,76 +0,0 @@
let url = new URL(location);
const pushedURL = false;
const matchers = {
default(textContent, query) {
return textContent.includes(query);
},
i(textContent, query) {
return textContent.toLowerCase().includes(query.toLowerCase());
},
regexp(textContent, query) {
query.lastIndex = 0;
return query.test(textContent);
},
};
matchers.iregexp = matchers.regexp; // i is baked into the query
function filterByName(value) {
const previousFilter = url.searchParams.get('name') || '';
url = new URL(location);
if (value) {
const isRegexp = name_search_regexp.checked;
const i = !name_search_i.checked;
const query = isRegexp ? new RegExp(value, 'gmsv' + (i ? 'i' : '')) : value;
const matcherId = (i ? 'i' : '') + (isRegexp ? 'regexp' : '');
const matcher = matchers[matcherId] ?? matchers.default;
for (const th of document.querySelectorAll('table tbody th:first-child')) {
const tr = th.parentNode;
const matches = matcher(th.textContent, query);
tr.toggleAttribute('hidden', !matches);
}
url.searchParams.set('name', value);
if (matcherId) {
url.searchParams.set('match', matcherId);
} else {
url.searchParams.delete('match');
}
} else {
for (const tr of document.querySelectorAll('table tbody tr[hidden]')) {
tr.removeAttribute('hidden');
}
url.searchParams.delete('name');
url.searchParams.delete('match');
}
if (value !== previousFilter) {
history[pushedURL ? 'replaceState' : 'pushState'](null, '', url);
}
// Update heading counts
for (const h2 of document.querySelectorAll('h2:has(+ table)')) {
const count = h2.querySelector('.count');
if (!count) continue;
const table = h2.nextElementSibling;
const visibleRows = table.querySelectorAll('tbody tr:not([hidden])').length;
count.textContent = visibleRows;
const outlineLink = document.querySelector(`#outline-standard a[href="#${h2.id}"]`);
if (outlineLink) {
// Why not just = h2.textContent? To skip the "Jump to heading" link
outlineLink.textContent = '';
outlineLink.append(...[...h2.childNodes].slice(0, 3).map(n => n.cloneNode(true)));
}
}
}
if (name_search.value) {
filterByName(name_search.value);
}
name_search_group.addEventListener('input', e => filterByName(name_search.value));

View File

@@ -1,89 +0,0 @@
---
title: Component Cheatsheet
layout: docs
unlisted: true
---
<style>
table code {
white-space: nowrap;
}
</style>
<p>
This page lists every bit of syntax used by every Web Awesome component and which components share it.
For these times when your memory is failing, or to simply explore the possibilities!
</p>
<fieldset id="name_search_group">
<legend>Filter by name</legend>
<wa-input type=search clearable id="name_search"></wa-input>
<wa-checkbox id="name_search_i" checked>Case sensitive</wa-checkbox>
<wa-checkbox id="name_search_regexp">Regular expression</wa-checkbox>
</fieldset>
<script>
{
let url = new URL(location);
if (url.searchParams.get("name")) {
name_search.value = url.searchParams.get("name");
}
if (url.searchParams.get("match")) {
let matcherId = url.searchParams.get("match");
let caseSensitive = !matcherId.startsWith("i");
let isRegexp = matcherId.endsWith("regexp");
customElements.whenDefined("wa-checkbox").then(async () => {
await Promise.all([
name_search_i.updateComplete,
name_search_regexp.updateComplete,
]);
name_search_i.checked = caseSensitive;
name_search_regexp.checked = isRegexp;
});
}
}
</script>
<script type="module" src="./cheatsheet.js"></script>
{% for type, all in componentsBy -%}
{% set typeTitle = "CSS custom properties" if type == "cssProperty" else ("CSS parts" if type == "cssPart" else (type | title) + "s") %}
<h2 id="{{ typeTitle | slugify }}">
All <span class="count">{{ (all | keys).length }}</span>
{{ typeTitle }}
</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Components</th>
</tr>
</thead>
{% for name, thingComponents in all -%}
<tr>
<th><code>{{ name }}{{ "()" if type == "method" }}</code></th>
<td>
{% set componentLinks = [] %}
{% for component in thingComponents %}
{%- set link -%}
<a href="../{{ component.slug }}"><code>&lt;{{ component.tagName }}&gt;</code></a>
{%- endset -%}
{# https://giuliachiola.dev/posts/add-items-to-an-array-in-nunjucks/ #}
{% set componentLinks = (componentLinks.push(link), componentLinks) %}
{%- endfor -%}
{% if thingComponents.length > 1 %}
<details open>
<summary><strong>{{ thingComponents.length }}</strong> components</summary>
{{ componentLinks | safe }}
</details>
{% else %}
{{ componentLinks | safe }}
{% endif %}
</td>
</tr>
{%- endfor %}
</table>
{%- endfor %}

View File

@@ -1,212 +0,0 @@
---
title: Code Demo
description: Code demos can be used to render code examples as inline live demos.
tags: component
noAlpha: true
---
```html {.example}
<wa-code-demo>
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
&lt;wa-button&gt;Click me!&lt;/wa-button&gt;
</code></pre>
</wa-code-demo>
```
This component is used right here in the docs to render code examples.
:::warning
Do not render untrusted content in a `<wa-code-demo>` element. This component renders the content as HTML, which introduces XSS vulnerabilities if used with untrusted content.
:::
## Examples
### Open by default
```html {.example}
<wa-code-demo open>
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
&lt;wa-button&gt;Click me!&lt;/wa-button&gt;
</code></pre>
</wa-code-demo>
```
### Custom previews
In some cases you may want to preprocess the code displayed, for example to sanitize HTML, remove irrelevant elements or attributes, fix whitespace, or do server-side rendering (SSR).
For these cases, you can slot in a custom preview:
```html {.example}
<wa-code-demo>
<wa-button slot="preview">Click me!</wa-button>
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
</code></pre>
</wa-code-demo>
```
Note that this means the preview will be in the light DOM, and can conflict with other things on the page.
To only render the custom preview within the components shadow DOM, or to display raw text, you can wrap it in a `<template>` element:
```html {.example}
<wa-code-demo>
<template slot="preview">
<wa-button>Click me!</wa-button>
</template>
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
</code></pre>
</wa-code-demo>
```
### Including resources (CSS, scripts, etc.)
Demos are rendered in the shadow DOM of the component, so any resources (stylesheets, scripts, etc.) must be included anew.
The same applies to isolated demos (see below), opening demos in a new tab, or editing them on CodePen.
While you _could_ manually include all of these on every single demo, it would get tedious to write,
and it would add noise for the reader.
Instead, `<wa-code-demo>` provides several better ways to include resources.
The core idea is that rather than specifying these resources over and over on each demo,
you would **point to elements** which would then be cloned into the demo, at the beginning.
There are two ways to point to elements:
- Add a `wa-code-demo-include` class to them
- Specify a CSS selector for which resources to look for in the demos `include` attribute.
There are certain types of elements that are handled specially:
- `<template>`: contents are cloned instead of the element itself.
This is useful for including resources in your demo that you don't want rendered outside the demo.
The following example shows both methods.
It includes all stylesheets on this page whose URLs start with `/dist/styles/themes/`,
plus any other elements with the class `.demo-import`, plus a CSS file with the class `wa-code-demo-include`:
```html {.example}
<template class="wa-code-demo-include-isolated">
<script type="module" src="/dist/webawesome.loader.js"></script>
<style>wa-callout { font-size: var(--wa-font-size-2xl) }</style>
<script>console.log('Hello!')</script>
</template>
<wa-code-demo include="link[rel=stylesheet]">
<pre><code class="language-html">
&lt;wa-callout&gt;Helloooo!&lt;/wa-callout&gt;
</code></pre>
</wa-code-demo>
```
### Isolated viewports
Often you may want to render your demo in a separate viewport, e.g. when its about a whole page.
Or, you may want to sandbox it.
For these cases, you can use the `viewport` attribute, which renders the demo in an iframe:
```html {.example}
<wa-code-demo viewport>
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
</code></pre>
</wa-code-demo>
```
### Viewport Emulation
When you use the `viewport` attribute, `<wa-code-demo>` uses [`<wa-viewport-demo>`](../viewport-demo/) internally, and passes the value of `viewport` to it.
This allows you to also also provide a width value to emulate and it will be scaled accordingly:
```html {.example}
<wa-code-demo viewport="300">
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
</code></pre>
</wa-code-demo>
```
Or both a width and a height value:
```html {.example}
<wa-code-demo viewport="1600 x 1000">
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
&lt;p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed maximus et tortor vel ullamcorper. Fusce tristique et justo quis auctor. In tristique dignissim dignissim. Fusce lacus urna, efficitur vel fringilla sed, hendrerit at ipsum. Donec suscipit ante ac ligula imperdiet varius. Aliquam ullamcorper augue sit amet lectus euismod finibus. Proin semper, diam at rhoncus posuere, diam dui semper turpis, ut faucibus mi ipsum nec ante. Morbi varius nibh ut facilisis varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in blandit velit. Aliquam massa eros, commodo eu vestibulum a, faucibus non risus.
&lt;p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed maximus et tortor vel ullamcorper. Fusce tristique et justo quis auctor. In tristique dignissim dignissim. Fusce lacus urna, efficitur vel fringilla sed, hendrerit at ipsum. Donec suscipit ante ac ligula imperdiet varius. Aliquam ullamcorper augue sit amet lectus euismod finibus. Proin semper, diam at rhoncus posuere, diam dui semper turpis, ut faucibus mi ipsum nec ante. Morbi varius nibh ut facilisis varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in blandit velit. Aliquam massa eros, commodo eu vestibulum a, faucibus non risus.
&lt;p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed maximus et tortor vel ullamcorper. Fusce tristique et justo quis auctor. In tristique dignissim dignissim. Fusce lacus urna, efficitur vel fringilla sed, hendrerit at ipsum. Donec suscipit ante ac ligula imperdiet varius. Aliquam ullamcorper augue sit amet lectus euismod finibus. Proin semper, diam at rhoncus posuere, diam dui semper turpis, ut faucibus mi ipsum nec ante. Morbi varius nibh ut facilisis varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in blandit velit. Aliquam massa eros, commodo eu vestibulum a, faucibus non risus.
</code></pre>
</wa-code-demo>
```
If you only provide a width value, the viewport will be rendered to an initial 16:9 aspect ratio,
which can be changed via resizing.
You can customize this via the `--viewport-initial-aspect-ratio` property.
### Isolated demos with resources
Including resources in isolated demos works the same way.
Any relative URLs are still resolved relative to the host document.
In addition to the `wa-code-demo-include` class, which specifies resources to be included in *every* demo,
you can also use the `wa-code-demo-include-isolated` class which specifies resources to be included in every *isolated* demo,
i.e. the previews of demos using the `viewport` attribute, but also opening demos in a new tab or editing them on CodePen.
```html {.example}
<template class="wa-code-demo-include-isolated">
<script type="module" src="{% cdnUrl 'webawesome.loader.js' %}"></script>
<style>
body {
padding: var(--wa-space-l);
}
wa-callout { font-size: var(--wa-font-size-2xl) }
</style>
<script>console.log('Hello from iframe!')</script>
</template>
<wa-code-demo viewport include="link[rel=stylesheet]">
<pre><code class="language-html">
&lt;wa-callout&gt;Helloooo!&lt;/wa-callout&gt;
</code></pre>
</wa-code-demo>
```
## Styling
Just setting `border-radius` or `border` should work as expected:
```html{.example}
<wa-code-demo style="border: 2px dotted var(--wa-color-blue-50); border-radius: var(--wa-border-radius-m)">
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
&lt;wa-button&gt;Click me!&lt;/wa-button&gt;
</code></pre>
</wa-code-demo>
```
The divider width is controlled separately via `--divider-width`:
```html{.example}
<wa-code-demo open style="border-width: var(--wa-border-width-l); --divider-width: var(--wa-border-width-m);">
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
&lt;wa-button&gt;Click me!&lt;/wa-button&gt;
</code></pre>
</wa-code-demo>
```
## Roadmap
This component is a work in progress.
Some of the things that are not yet implemented are listed below.
It goes without saying that this list is a rough plan and subject to change.
### High priority
- Make the component dynamic so that when the code changes, the demo is updated
### Low priority
- Horizontal layout
- Tabbed layout
- Provide a way to display CSS and JS separately
- Provide a way to customize the playground used (currently it is hardcoded to CodePen)
- Provide a way to customize the buttons shown

View File

@@ -1,11 +0,0 @@
{
"layout": "component.njk",
"tags": ["components"],
"eleventyComputed": {
"component": "{{ components[page.fileSlug] }}",
"description": "{{ components[page.fileSlug].summary }}",
"status": "{{ components[page.fileSlug].status }}",
"since": "{{ components[page.fileSlug].since }}",
"element": "<{{ components[page.fileSlug].tagName }}>"
}
}

View File

@@ -1,118 +0,0 @@
---
title: Details
description: Details show a brief summary and expand to show additional content.
tags: [organization, apps, content, disclosure]
icon: details
native: details
---
<!-- cspell:dictionaries lorem-ipsum -->
```html {.example}
<wa-details summary="Toggle Me">
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>
```
## Examples
### Disabled
Use the `disabled` attribute to prevent the details from expanding.
```html {.example}
<wa-details summary="Disabled" disabled>
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>
```
### Customizing the Summary Icon
Use the `expand-icon` and `collapse-icon` slots to change the expand and collapse icons, respectively. To disable the animation, override the `rotate` property on the `icon` part as shown below.
```html {.example}
<wa-details summary="Toggle Me" class="custom-icons">
<wa-icon name="square-plus" slot="expand-icon" variant="regular"></wa-icon>
<wa-icon name="square-minus" slot="collapse-icon" variant="regular"></wa-icon>
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>
<style>
/* Disable the expand/collapse animation */
wa-details.custom-icons::part(icon) {
rotate: none;
}
</style>
```
### HTML in summary
To use HTML in the summary, use the `summary` slot.
Links and other interactive elements will still retain their behavior:
```html {.example}
<wa-details>
<span slot="summary">
Some text
<a href="https://webawesome.com" target="_blank">a link</a>
more text
</span>
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>
```
### Right-to-Left languages
The details component automatically adapts to right-to-left languages:
```html {.example}
<wa-details summary="تبديلني" lang="ar" dir="rtl">
استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن
</wa-details>
```
### Grouping Details
Details are designed to function independently, but you can simulate a group or "accordion" where only one is shown at a time by listening for the `wa-show` event.
```html {.example}
<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>
<script>
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>
<style>
.details-group-example wa-details:not(:last-of-type) {
margin-bottom: var(--wa-space-2xs);
}
</style>
```

View File

@@ -1,217 +0,0 @@
---
title: Dropdown
description: 'Dropdowns expose additional content that "drops down" in a panel.'
tags: [actions, apps]
icon: dropdown
---
Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it.
Dropdowns are designed to work well with [menus](/docs/components/menu) to provide a list of options the user can select from. However, dropdowns can also be used in lower-level applications (e.g. [color picker](/docs/components/color-picker)). The API gives you complete control over showing, hiding, and positioning the panel.
```html {.example}
<wa-dropdown>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
<wa-menu-item>Dropdown Item 1</wa-menu-item>
<wa-menu-item>Dropdown Item 2</wa-menu-item>
<wa-menu-item>Dropdown Item 3</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item type="checkbox" checked>Checkbox</wa-menu-item>
<wa-menu-item disabled>Disabled</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>
Prefix
<wa-icon slot="prefix" name="gift" variant="solid"></wa-icon>
</wa-menu-item>
<wa-menu-item>
Suffix Icon
<wa-icon slot="suffix" name="heart" variant="solid"></wa-icon>
</wa-menu-item>
</wa-menu>
</wa-dropdown>
```
## Examples
### Getting the Selected Item
When dropdowns are used with [menus](/docs/components/menu), you can listen for the [`wa-select`](/docs/components/menu#events) event to determine which menu item was selected. The menu item element will be exposed in `event.detail.item`. You can set `value` props to make it easier to identify commands.
```html {.example}
<div class="dropdown-selection">
<wa-dropdown>
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu>
<wa-menu-item value="cut">Cut</wa-menu-item>
<wa-menu-item value="copy">Copy</wa-menu-item>
<wa-menu-item value="paste">Paste</wa-menu-item>
</wa-menu>
</wa-dropdown>
</div>
<script>
const container = document.querySelector('.dropdown-selection');
const dropdown = container.querySelector('wa-dropdown');
dropdown.addEventListener('wa-select', event => {
const selectedItem = event.detail.item;
console.log(selectedItem.value);
});
</script>
```
Alternatively, you can listen for the `click` event on individual menu items. Note that, using this approach, disabled menu items will still emit a `click` event.
```html {.example}
<div class="dropdown-selection-alt">
<wa-dropdown>
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu>
<wa-menu-item value="cut">Cut</wa-menu-item>
<wa-menu-item value="copy">Copy</wa-menu-item>
<wa-menu-item value="paste">Paste</wa-menu-item>
</wa-menu>
</wa-dropdown>
</div>
<script>
const container = document.querySelector('.dropdown-selection-alt');
const cut = container.querySelector('wa-menu-item[value="cut"]');
const copy = container.querySelector('wa-menu-item[value="copy"]');
const paste = container.querySelector('wa-menu-item[value="paste"]');
cut.addEventListener('click', () => console.log('cut'));
copy.addEventListener('click', () => console.log('copy'));
paste.addEventListener('click', () => console.log('paste'));
</script>
```
### Placement
The preferred placement of the dropdown can be set with the `placement` attribute. Note that the actual position may vary to ensure the panel remains in the viewport.
```html {.example}
<wa-dropdown placement="top-start">
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu>
<wa-menu-item>Cut</wa-menu-item>
<wa-menu-item>Copy</wa-menu-item>
<wa-menu-item>Paste</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>Find</wa-menu-item>
<wa-menu-item>Replace</wa-menu-item>
</wa-menu>
</wa-dropdown>
```
### Distance
The distance from the panel to the trigger can be customized using the `distance` attribute. This value is specified in pixels.
```html {.example}
<wa-dropdown distance="30">
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu>
<wa-menu-item>Cut</wa-menu-item>
<wa-menu-item>Copy</wa-menu-item>
<wa-menu-item>Paste</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>Find</wa-menu-item>
<wa-menu-item>Replace</wa-menu-item>
</wa-menu>
</wa-dropdown>
```
### Skidding
The offset of the panel along the trigger can be customized using the `skidding` attribute. This value is specified in pixels.
```html {.example}
<wa-dropdown skidding="30">
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu>
<wa-menu-item>Cut</wa-menu-item>
<wa-menu-item>Copy</wa-menu-item>
<wa-menu-item>Paste</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>Find</wa-menu-item>
<wa-menu-item>Replace</wa-menu-item>
</wa-menu>
</wa-dropdown>
```
### Submenus
To create a submenu, nest an `<wa-menu slot="submenu">` element in a [menu item](/docs/components/menu-item).
```html {.example}
<wa-dropdown>
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu style="max-width: 200px;">
<wa-menu-item value="undo">Undo</wa-menu-item>
<wa-menu-item value="redo">Redo</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item value="cut">Cut</wa-menu-item>
<wa-menu-item value="copy">Copy</wa-menu-item>
<wa-menu-item value="paste">Paste</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>
Find
<wa-menu slot="submenu">
<wa-menu-item value="find">Find…</wa-menu-item>
<wa-menu-item value="find-previous">Find Next</wa-menu-item>
<wa-menu-item value="find-next">Find Previous</wa-menu-item>
</wa-menu>
</wa-menu-item>
<wa-menu-item>
Transformations
<wa-menu slot="submenu">
<wa-menu-item value="uppercase">Make uppercase</wa-menu-item>
<wa-menu-item value="lowercase">Make lowercase</wa-menu-item>
<wa-menu-item value="capitalize">Capitalize</wa-menu-item>
</wa-menu>
</wa-menu-item>
</wa-menu>
</wa-dropdown>
```
:::warning
As a UX best practice, avoid using more than one level of submenu when possible.
:::
### Hoisting
Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
```html {.example}
<div class="dropdown-hoist">
<wa-dropdown>
<wa-button slot="trigger" caret>No Hoist</wa-button>
<wa-menu>
<wa-menu-item>Item 1</wa-menu-item>
<wa-menu-item>Item 2</wa-menu-item>
<wa-menu-item>Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-dropdown hoist>
<wa-button slot="trigger" caret>Hoist</wa-button>
<wa-menu>
<wa-menu-item>Item 1</wa-menu-item>
<wa-menu-item>Item 2</wa-menu-item>
<wa-menu-item>Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
</div>
<style>
.dropdown-hoist {
position: relative;
border: solid 2px var(--wa-color-surface-border);
padding: var(--wa-space-m);
overflow: hidden;
}
</style>
```

View File

@@ -1,76 +0,0 @@
---
title: Icon Button
description: Icons buttons are simple, icon-only buttons that can be used for actions and in toolbars.
tags: [actions, apps]
icon: icon-button
---
For a full list of icons that come bundled with Web Awesome, refer to the [icon component](/docs/components/icon).
```html {.example}
<wa-icon-button name="gear" label="Settings"></wa-icon-button>
```
## Examples
### Sizes
Icon buttons inherit their parent element's `font-size`.
```html {.example}
<wa-icon-button name="pen-to-square" variant="solid" label="Edit" style="font-size: 1.5rem;"></wa-icon-button>
<wa-icon-button name="pen-to-square" variant="solid" label="Edit" style="font-size: 2rem;"></wa-icon-button>
<wa-icon-button name="pen-to-square" variant="solid" label="Edit" style="font-size: 2.5rem;"></wa-icon-button>
```
### Colors
Icon buttons are designed to have a uniform appearance, so their color is not inherited. However, you can still customize them by styling the `base` part.
```html {.example}
<div class="icon-button-color">
<wa-icon-button name="bold" variant="solid" label="Bold"></wa-icon-button>
<wa-icon-button name="italic" variant="solid" label="Italic"></wa-icon-button>
<wa-icon-button name="underline" variant="solid" label="Underline"></wa-icon-button>
</div>
<style>
.icon-button-color wa-icon-button::part(base) {
color: #b00091;
}
.icon-button-color wa-icon-button::part(base):hover,
.icon-button-color wa-icon-button::part(base):focus {
color: #c913aa;
}
.icon-button-color wa-icon-button::part(base):active {
color: #960077;
}
</style>
```
### Link Buttons
Use the `href` attribute to convert the button to a link.
```html {.example}
<wa-icon-button name="gear" variant="solid" label="Settings" href="https://example.com" target="_blank"></wa-icon-button>
```
### Icon Button with Tooltip
Add a tooltip that references the `id` of the icon button to provide contextual information.
```html {.example}
<wa-icon-button id="icon-button" name="gear" variant="solid" label="Settings"></wa-icon-button>
<wa-tooltip for="icon-button">Settings</wa-tooltip>
```
### Disabled
Use the `disabled` attribute to disable the icon button.
```html {.example}
<wa-icon-button name="gear" variant="solid" label="Settings" disabled></wa-icon-button>
```

View File

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

View File

@@ -1,125 +0,0 @@
---
title: Menu Item
description: Menu items provide options for the user to pick from in a menu.
tags: component
parent: menu
icon: menu
---
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item>Option 1</wa-menu-item>
<wa-menu-item>Option 2</wa-menu-item>
<wa-menu-item>Option 3</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item type="checkbox" checked>Checkbox</wa-menu-item>
<wa-menu-item disabled>Disabled</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>
Prefix Icon
<wa-icon slot="prefix" name="gift" variant="solid"></wa-icon>
</wa-menu-item>
<wa-menu-item>
Suffix Icon
<wa-icon slot="suffix" name="heart" variant="solid"></wa-icon>
</wa-menu-item>
</wa-menu>
```
## Examples
### Prefix & Suffix
Add content to the start and end of menu items using the `prefix` and `suffix` slots.
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item>
<wa-icon slot="prefix" name="house" variant="solid"></wa-icon>
Home
</wa-menu-item>
<wa-menu-item>
<wa-icon slot="prefix" name="envelope" variant="solid"></wa-icon>
Messages
<wa-badge slot="suffix" variant="brand" pill>12</wa-badge>
</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>
<wa-icon slot="prefix" name="gear" variant="solid"></wa-icon>
Settings
</wa-menu-item>
</wa-menu>
```
### Disabled
Add the `disabled` attribute to disable the menu item so it cannot be selected.
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item>Option 1</wa-menu-item>
<wa-menu-item disabled>Option 2</wa-menu-item>
<wa-menu-item>Option 3</wa-menu-item>
</wa-menu>
```
### Loading
Use the `loading` attribute to indicate that a menu item is busy. Like a disabled menu item, clicks will be suppressed until the loading state is removed.
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item>Option 1</wa-menu-item>
<wa-menu-item loading>Option 2</wa-menu-item>
<wa-menu-item>Option 3</wa-menu-item>
</wa-menu>
```
### Checkbox Menu Items
Set the `type` attribute to `checkbox` to create a menu item that will toggle on and off when selected. You can use the `checked` attribute to set the initial state.
Checkbox menu items are visually indistinguishable from regular menu items. Their ability to be toggled is primarily inferred from context, much like you'd find in the menu of a native app.
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item type="checkbox">Autosave</wa-menu-item>
<wa-menu-item type="checkbox" checked>Check Spelling</wa-menu-item>
<wa-menu-item type="checkbox">Word Wrap</wa-menu-item>
</wa-menu>
```
### Value & Selection
The `value` attribute can be used to assign a hidden value, such as a unique identifier, to a menu item. When an item is selected, the `wa-select` event will be emitted and a reference to the item will be available at `event.detail.item`. You can use this reference to access the selected item's value, its checked state, and more.
```html {.example}
<wa-menu class="menu-value" style="max-width: 200px;">
<wa-menu-item value="opt-1">Option 1</wa-menu-item>
<wa-menu-item value="opt-2">Option 2</wa-menu-item>
<wa-menu-item value="opt-3">Option 3</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item type="checkbox" value="opt-4">Checkbox 4</wa-menu-item>
<wa-menu-item type="checkbox" value="opt-5">Checkbox 5</wa-menu-item>
<wa-menu-item type="checkbox" value="opt-6">Checkbox 6</wa-menu-item>
</wa-menu>
<script>
const menu = document.querySelector('.menu-value');
menu.addEventListener('wa-select', event => {
const item = event.detail.item;
// Log value
if (item.type === 'checkbox') {
console.log(`Selected value: ${item.value} (${item.checked ? 'checked' : 'unchecked'})`);
} else {
console.log(`Selected value: ${item.value}`);
}
});
</script>
```

View File

@@ -1,21 +0,0 @@
---
title: Menu Label
description: Menu labels are used to describe a group of menu items.
tags: component
parent: menu
icon: menu
---
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-label>Fruits</wa-menu-label>
<wa-menu-item value="apple">Apple</wa-menu-item>
<wa-menu-item value="banana">Banana</wa-menu-item>
<wa-menu-item value="orange">Orange</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-label>Vegetables</wa-menu-label>
<wa-menu-item value="broccoli">Broccoli</wa-menu-item>
<wa-menu-item value="carrot">Carrot</wa-menu-item>
<wa-menu-item value="zucchini">Zucchini</wa-menu-item>
</wa-menu>
```

View File

@@ -1,77 +0,0 @@
---
title: Menu
description: Menus provide a list of options for the user to choose from.
tags: [actions, apps]
icon: menu
---
You can use [menu items](/docs/components/menu-item), [menu labels](/docs/components/menu-label), and [dividers](/docs/components/divider) to compose a menu. Menus support keyboard interactions, including type-to-select an option.
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item value="undo">Undo</wa-menu-item>
<wa-menu-item value="redo">Redo</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item value="cut">Cut</wa-menu-item>
<wa-menu-item value="copy">Copy</wa-menu-item>
<wa-menu-item value="paste">Paste</wa-menu-item>
<wa-menu-item value="delete">Delete</wa-menu-item>
</wa-menu>
```
:::info
Menus are intended for system menus (dropdown menus, select menus, context menus, etc.). They should not be mistaken for navigation menus which serve a different purpose and have a different semantic meaning. If you're building navigation, use `<nav>` and `<a>` elements instead.
:::
## Examples
### In Dropdowns
Menus work really well when used inside [dropdowns](/docs/components/dropdown).
```html {.example}
<wa-dropdown>
<wa-button slot="trigger" caret>Edit</wa-button>
<wa-menu>
<wa-menu-item value="cut">Cut</wa-menu-item>
<wa-menu-item value="copy">Copy</wa-menu-item>
<wa-menu-item value="paste">Paste</wa-menu-item>
</wa-menu>
</wa-dropdown>
```
### Submenus
To create a submenu, nest an `<wa-menu slot="submenu">` in any [menu item](/docs/components/menu-item).
```html {.example}
<wa-menu style="max-width: 200px;">
<wa-menu-item value="undo">Undo</wa-menu-item>
<wa-menu-item value="redo">Redo</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item value="cut">Cut</wa-menu-item>
<wa-menu-item value="copy">Copy</wa-menu-item>
<wa-menu-item value="paste">Paste</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item>
Find
<wa-menu slot="submenu">
<wa-menu-item value="find">Find…</wa-menu-item>
<wa-menu-item value="find-previous">Find Next</wa-menu-item>
<wa-menu-item value="find-next">Find Previous</wa-menu-item>
</wa-menu>
</wa-menu-item>
<wa-menu-item>
Transformations
<wa-menu slot="submenu">
<wa-menu-item value="uppercase">Make uppercase</wa-menu-item>
<wa-menu-item value="lowercase">Make lowercase</wa-menu-item>
<wa-menu-item value="capitalize">Capitalize</wa-menu-item>
</wa-menu>
</wa-menu-item>
</wa-menu>
```
:::warning
As a UX best practice, avoid using more than one level of submenus when possible.
:::

View File

@@ -1,55 +0,0 @@
---
title: Option
description: Options define the selectable items within various form controls such as select.
tags: component
parent: select
icon: option
---
```html {.example}
<wa-select label="Select one">
<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>
```
## Examples
### Disabled
Use the `disabled` attribute to disable an option and prevent it from being selected.
```html {.example}
<wa-select label="Select one">
<wa-option value="option-1">Option 1</wa-option>
<wa-option value="option-2" disabled>Option 2</wa-option>
<wa-option value="option-3">Option 3</wa-option>
</wa-select>
```
### Prefix & Suffix
Add icons to the start and end of menu items using the `prefix` and `suffix` slots.
```html {.example}
<wa-select label="Select one">
<wa-option value="option-1">
<wa-icon slot="prefix" name="envelope" variant="solid"></wa-icon>
Email
<wa-icon slot="suffix" name="circle-check" variant="solid"></wa-icon>
</wa-option>
<wa-option value="option-2">
<wa-icon slot="prefix" name="phone" variant="solid"></wa-icon>
Phone
<wa-icon slot="suffix" name="circle-check" variant="solid"></wa-icon>
</wa-option>
<wa-option value="option-3">
<wa-icon slot="prefix" name="comment" variant="solid"></wa-icon>
Chat
<wa-icon slot="suffix" name="circle-check" variant="solid"></wa-icon>
</wa-option>
</wa-select>
```

View File

@@ -1,237 +0,0 @@
---
title: Sample Documentation Page
description: A sample page for a documentation website using Web Awesome's page component.
layout: blank
eleventyExcludeFromCollections: true
---
<style>
wa-page {
--menu-width: 15rem;
--aside-width: 15rem;
}
wa-page[view='mobile'] {
--menu-width: auto;
--aside-width: auto;
}
wa-page[view='mobile'] [slot='aside'] {
display: none;
}
wa-page[view='mobile'] #brand-name {
display: none;
}
wa-page[view='mobile'] #search {
display: none;
}
[slot='banner'] {
--wa-color-text-link: var(--wa-color-neutral-on-loud);
background-color: var(--wa-color-neutral-fill-loud);
}
[slot='header'] {
--wa-link-decoration-default: none;
border-block-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot*='header'] a {
font-weight: var(--wa-font-weight-action);
}
[slot='subheader'] {
background-color: var(--wa-color-surface-lowered);
border-block-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot='navigation-header'] {
border-block-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
wa-page[view='desktop'] [slot*='navigation'] {
border-inline-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot*='navigation'] a {
--wa-color-text-link: var(--wa-color-text-normal);
}
[slot='navigation-footer'] {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot='main-header'],
main,
[slot='main-footer'] {
max-inline-size: 60rem;
margin-inline: auto;
}
[slot='main-footer'] {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot='footer'] {
--wa-color-text-link: var(--wa-color-text-quiet);
background-color: var(--wa-color-surface-lowered);
font-size: var(--wa-font-size-s);
}
</style>
<wa-page mobile-breakpoint="920">
<div slot="banner" class="wa-body-s">
<a href="#" class="wa-cluster wa-align-items-baseline wa-gap-xs" style="flex-wrap: nowrap;">
<wa-icon name="gift"></wa-icon>
<span>Give a Hoot for the Holidays: Donate now and double your impact.</span>
</a>
</div>
<header slot="header" class="wa-split">
<div class="wa-cluster">
<wa-icon name="feather-pointed" style="color: var(--wa-color-brand-fill-loud); font-size: 1.5em;"></wa-icon>
<span id="brand-name" class="wa-heading-s">Audubon Worldwide</span>
<a href="#">Our Work</a>
<a href="#">About Us</a>
<a href="#">Discover</a>
<a href="#">Get Involved</a>
</div>
<div class="wa-cluster wa-gap-xs">
<wa-button size="small" variant="brand" appearance="outlined">Find Your Local Audubon</wa-button>
<wa-button size="small" variant="brand">Donate</wa-button>
</div>
</header>
<nav slot="subheader">
<div class="wa-cluster" style="flex-wrap: nowrap;">
<wa-icon-button data-toggle-nav name="bars" label="Menu"></wa-icon-button>
<wa-breadcrumb style="font-size: var(--wa-font-size-s);">
<wa-breadcrumb-item>Field Guides</wa-breadcrumb-item>
<wa-breadcrumb-item>Owls</wa-breadcrumb-item>
<wa-breadcrumb-item>Great Horned Owl</wa-breadcrumb-item>
</wa-breadcrumb>
</div>
<wa-input id="search" placeholder="Search" size="small" style="max-inline-size: 12rem;">
<wa-icon slot="prefix" name="magnifying-glass"></wa-icon>
</wa-input>
</nav>
<nav slot="navigation-header">
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1544648720-132573cb590d?q=20" label=""></wa-avatar>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Great Horned Owl</span>
<span class="wa-caption-s" lang="la"><em>Bubo virginianus</em></span>
</div>
</div>
</nav>
<nav slot="navigation">
<a href="#identification">Identification</a>
<a href="#range">Range and Habitat</a>
<a href="#behavior">Behavior</a>
<a href="#conservation">Conservation</a>
</nav>
<nav slot="navigation-footer">
<a href="#" class="wa-flank" style="--flank-size: 1.25em;">
<wa-icon name="camera"></wa-icon>
<span>Photo Gallery</span>
</a>
<a href="#" class="wa-flank" style="--flank-size: 1.25em;">
<wa-icon name="map-location-dot"></wa-icon>
<span>Interactive Range Map</span>
</a>
</nav>
<header slot="main-header">
<div class="wa-flank:end wa-border-radius-l wa-dark" style="background-color: var(--wa-color-surface-lowered); --content-percentage: 35%; padding: var(--wa-space-m);">
<div class="wa-stack" style="margin: var(--wa-space-2xl);">
<h1>Great Horned Owl</h1>
<wa-divider></wa-divider>
<div class="wa-cluster wa-gap-xs">
<wa-tag size="small">Owls</wa-tag>
<wa-tag size="small">Birds of Prey</wa-tag>
<wa-tag size="small">Pleistocene Birds</wa-tag>
</div>
<div class="wa-flank">
<wa-icon name="ruler"></wa-icon>
<span class="wa-caption-m">L 21.5" | WS 48.5"</span>
</div>
<div class="wa-flank">
<wa-icon name="earth-americas"></wa-icon>
<span class="wa-caption-m">North America (Widespread), Central America (Limited), South America (Limited)</span>
</div>
<div class="wa-flank">
<wa-icon name="shield-heart"></wa-icon>
<span class="wa-caption-m">Least Concern</span>
</div>
</div>
<div class="wa-frame" style="wa-border-radius-l max-inline-size: 40ch;">
<img src="https://images.unsplash.com/photo-1544648720-132573cb590d?q=20" />
</div>
</div>
</header>
<main class="wa-body-l">
<h2 id="identification">Identification</h2>
<p>Lorem ipsum odor amet, consectetuer adipiscing elit. Eget habitant scelerisque lectus ultrices nascetur aliquet sapien primis. Cursus sapien fusce semper nulla elit sociosqu lectus per sem. Sem ad porttitor dictum nisl pharetra tortor convallis. Sit molestie hendrerit porta dictum tortor posuere euismod magna. Mauris suspendisse pharetra finibus; eleifend etiam ridiculus.</p>
<h2 id="range">Range and Habitat</h2>
<p>Diam sed ipsum pretium porttitor class cubilia elementum. Blandit felis ligula habitant ultricies vulputate rutrum lacus commodo pulvinar. Nostra semper placerat lectus in dis eu. Sagittis ipsum placerat rhoncus lacus id eget. Erat pharetra aptent enim, augue accumsan ultricies inceptos habitasse. Senectus id maximus parturient tellus; fermentum posuere vulputate luctus. Ac tempus dapibus vehicula ligula ullamcorper sit duis.</p>
<h2 id="behavior">Behavior</h2>
<p>Erat vitae luctus arcu taciti malesuada pretium arcu justo primis. Cubilia vitae maecenas congue velit id netus arcu. Dictum vel pellentesque taciti fermentum risus consectetur amet. Faucibus commodo habitasse sem maximus praesent purus, dignissim tristique porta. Platea magna justo ipsum ut metus ac facilisi. Imperdiet laoreet pharetra maximus lacus tortor suscipit. Nam quisque iaculis orci porttitor pellentesque rhoncus. Molestie sagittis tincidunt quisque nisi non urna conubia.</p>
<h2 id="conservation">Conservation</h2>
<p>Nullam magna quam quisque eu varius integer. Inceptos donec facilisi risus himenaeos semper mollis habitasse. Vehicula lacus vivamus euismod pharetra mollis dictum. Ante ex tortor elementum eleifend habitasse orci aliquam. Fames erat senectus fames etiam dapibus cursus.</p>
</main>
<footer slot="main-footer">
<section>
<h2 class="wa-heading-m">Sources</h2>
<ul class="wa-body-s">
<li><cite><a href="https://www.audubon.org/field-guide/bird/great-horned-owl" target="_blank" rel="noopener">Great Horned Owl</a></cite>, National Audubon Society. Retrieved 5 December 2024.</li>
<li><cite><a href="https://www.allaboutbirds.org/guide/Great_Horned_Owl/" target="_blank" rel="noopener">Great Horned Owl</a></cite>, All About Birds by CornellLab. Retrieved 5 December 2024.</li>
<li>Armistead, G. L. (2015). <cite>Field guide to birds of Pennsylvania</cite>. Scott & Nix, Inc.</li>
</ul>
</section>
</footer>
<aside slot="aside">
<h2 class="wa-heading-m">Discover More Birds</h2>
<wa-card with-image>
<div slot="image" class="wa-frame">
<img src="https://images.unsplash.com/photo-1635254859323-65b78408dcca?q=20" alt="" />
</div>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Long-eared Owl</span>
<span class="wa-caption-s" lang="la"><em>Asio otus</em></span>
</div>
</wa-card>
<wa-card with-image>
<div slot="image" class="wa-frame">
<img src="https://images.unsplash.com/photo-1661350356618-f5915c7b6a3c?q=20" alt="" />
</div>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Northen Hawk Owl</span>
<span class="wa-caption-s" lang="la"><em>Surnia ulula</em></span>
</div>
</wa-card>
<wa-card with-image>
<div slot="image" class="wa-frame">
<img src="https://images.unsplash.com/photo-1660307777355-f08bced145d3?q=20" alt="" />
</div>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Golden Eagle</span>
<span class="wa-caption-s" lang="la"><em>Aquila chrysaetos</em></span>
</div>
</wa-card>
</aside>
<footer slot="footer" class="wa-grid wa-gap-xl">
<div class="wa-cluster" style="flex-wrap: nowrap;">
<wa-icon name="feather-pointed" style="font-size: 1.5em;"></wa-icon>
<span class="wa-heading-s">Audubon Worldwide</span>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">Our Work</h3>
<a href="#">Habitat Restoration</a>
<a href="#">Migration Science</a>
<a href="#">Advocacy</a>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">About Us</h3>
<a href="#">Our History</a>
<a href="#">Leadership</a>
<a href="#">Fiscal Reports</a>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">Discover</h3>
<a href="#">Field Guides</a>
<a href="#">Photo Search</a>
<a href="#">Gear and Resources</a>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">Get Involved</h3>
<a href="#">Adopt a Bird</a>
<a href="#">Your Local Audubon</a>
<a href="#">Youth Audubon Camps</a>
</div>
</footer>
</wa-page>

View File

@@ -1,400 +0,0 @@
---
title: Sample Media App Page
description: A sample page for a media app using Web Awesome's page component.
layout: blank
eleventyExcludeFromCollections: true
---
<wa-page class="wa-dark">
<header slot="header">
<div class="wa-cluster">
<wa-icon-button name="bars" label="Menu" data-toggle-nav></wa-icon-button>
<wa-icon name="record-vinyl" family="duotone"></wa-icon>
<span class="wa-heading-m">radiogaga</span>
</div>
<wa-input placeholder="Search" style="max-inline-size: 100%;">
<wa-icon slot="prefix" name="magnifying-glass" ></wa-icon>
</wa-input>
<div class="wa-cluster">
<wa-button appearance="outlined">Log In</wa-button>
<wa-button>Sign Up</wa-button>
</div>
</header>
<div slot="navigation-header" class="wa-split">
<h2 class="wa-heading-s">For You</h2>
<wa-icon-button id="settings" name="gear" label="Settings"></wa-icon-button>
</div>
<nav slot="navigation">
<h3 class="wa-heading-xs">Discover</h3>
<ul class="wa-stack wa-gap-0">
<li>
<a href="#" class="wa-flank">
<wa-icon name="house"></wa-icon>
<span>Home</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="sparkles"></wa-icon>
<span>New</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="tower-broadcast"></wa-icon>
<span>Stations</span>
</a>
</li>
</ul>
<h3 class="wa-heading-xs">Library</h3>
<ul class="wa-stack wa-gap-0">
<li>
<a href="#" class="wa-flank">
<wa-icon name="heart"></wa-icon>
<span>Favorites</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="list-music"></wa-icon>
<span>Playlists</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="microphone-stand"></wa-icon>
<span>Artists</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="grid-2"></wa-icon>
<span>Albums</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="podcast"></wa-icon>
<span>Podcasts</span>
</a>
</li>
</ul>
<h3 class="wa-heading-xs">Recently Played</h3>
<ul id="recent" class="wa-stack wa-gap-0">
<li>
<a href="#" class="wa-flank">
<wa-icon name="cassette-tape" style="background: var(--wa-color-red-90); color: var(--wa-color-red-60);"></wa-icon>
<span>Lo-Fi Station</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="face-awesome" style="background: var(--wa-color-blue-30); color: var(--wa-color-yellow-90);"></wa-icon>
<span>Podcast Awesome</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="seedling" style="background: var(--wa-color-green-70); color: var(--wa-color-green-90);"></wa-icon>
<div class="wa-stack wa-gap-0">
<span>Seasons</span>
<span class="wa-caption-s">Blister Soul</span>
</div>
</a>
</li>
</ul>
</nav>
<div slot="main-header">
<wa-icon-button id="back" name="chevron-left" label="Back"></wa-icon-button>
<wa-tooltip for="back" placement="bottom" distance="2">Back</wa-tooltip>
<div class="wa-cluster">
<wa-icon-button id="favorite" name="heart" variant="regular" label="Favorite"></wa-icon-button>
<wa-tooltip for="favorite" placement="bottom" distance="2">Favorite</wa-tooltip>
<wa-icon-button id="options" name="ellipsis" label="Options"></wa-icon-button>
<wa-tooltip for="options" placement="bottom" distance="2">Options</wa-tooltip>
</div>
</div>
<main>
<div class="wa-stack wa-gap-3xl">
<div class="wa-flank wa-gap-3xl" style="--flank-size: 35%; --content-percentage: 55%;">
<div class="wa-frame wa-border-radius-l" style="max-inline-size: 40ch;">
<img src="https://images.unsplash.com/photo-1732430579016-8d5e5ebd3c99?q=20" alt="Home for the Holidays album artwork" />
</div>
<div class="wa-split:column wa-align-items-start">
<div class="wa-stack" style="margin-block: auto;">
<h1 class="wa-heading-3xl">Home for the Holidays</h1>
<a href="#" class="wa-heading-m">The Shire Choir</a>
<div class="wa-cluster wa-caption-m wa-gap-2xs">
<span>Holiday</span>
<span>&bull;</span>
<span>2024</span>
<span>&bull;</span>
<span>12 songs, 41 minutes 9 seconds</span>
</div>
</div>
<div id="play-controls" class="wa-split wa-gap-xl">
<div class="wa-cluster wa-gap-xl">
<wa-icon-button name="play" label="Play"></wa-icon-button>
<wa-icon-button name="shuffle" label="Shuffle"></wa-icon-button>
</div>
<wa-icon-button name="plus" label="Add to Library"></wa-icon-button>
</div>
</div>
</div>
<ol class="wa-stack wa-gap-0">
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="1"></wa-icon>
<span>Fa-La-La-Fellowship</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:27</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="2"></wa-icon>
<span>Sleigh Ride</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:36</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="3"></wa-icon>
<span>All I Want For Christmas Is Stew</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:51</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="4"></wa-icon>
<span>Rockin' Around the Christmas Ent</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:05</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="5"></wa-icon>
<span>Merry, Did You Know?</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">1:56</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="6"></wa-icon>
<span>Run Run Shadowfax</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:32</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="7"></wa-icon>
<span>You're a Mean One, Mr. Grima</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:46</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="8"></wa-icon>
<span>O Come, All Ye Faithful</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:27</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="9"></wa-icon>
<span>Do You Hear What I Hear</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:13</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<span class="wa-cluster wa-gap-3xs">
<wa-icon name="1"></wa-icon>
<wa-icon name="0"></wa-icon>
</span>
<span>Carol of the Horns</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:55</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<span class="wa-cluster wa-gap-3xs">
<wa-icon name="1"></wa-icon>
<wa-icon name="1"></wa-icon>
</span>
<span>Silent Night</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:10</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<span class="wa-cluster wa-gap-3xs">
<wa-icon name="1"></wa-icon>
<wa-icon name="2"></wa-icon>
</span>
<span>Wizard Wonderland</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:22</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
</ol>
</div>
</main>
<div slot="main-footer" class="wa-grid wa-gap-xl">
<h2 class="wa-heading-2xl">More You Might Like</h2>
<div class="wa-stack wa-gap-xs">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1675219119611-40323b738563?q=20" alt="" />
</div>
<span class="wa-heading-s">Festival of Lights</span>
<span class="wa-caption-s">Station</span>
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1481930916222-5ec4696fc0f2?q=20" alt="" />
</div>
<span class="wa-heading-s">Holiday Cheer</span>
<span class="wa-caption-s">Essential Playlist</span>
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1667514627762-521b1c815a89?q=20" alt="" />
</div>
<span class="wa-heading-s">Nursery Rhymes from the Shire</span>
<span class="wa-caption-s">The Shire Choir</span>
</div>
</div>
</wa-page>
<style>
wa-page {
--menu-width: 18rem;
--wa-tooltip-arrow-size: 0;
background-color: var(--wa-color-surface-lowered);
}
wa-page[view='mobile'] {
--menu-width: auto;
}
wa-page,
[slot='header'],
wa-page[view='desktop'] [slot*='navigation'] {
background-color: var(--wa-color-surface-lowered);
}
wa-page[view='mobile'] [slot*='navigation'] {
padding: 0;
}
wa-page::part(base) {
background-color: var(--wa-color-surface-lowered);
}
[slot='header'] {
background: linear-gradient(to bottom, var(--wa-color-surface-raised), var(--wa-color-surface-lowered));
}
[slot='navigation-header'],
[slot='main-header'] {
padding-block-end: 0;
}
[slot='navigation'] a {
--wa-color-text-link: var(--wa-color-text-normal);
--wa-link-decoration-default: none;
--wa-link-decoration-hover: none;
--flank-size: 2rem;
font-weight: var(--wa-font-weight-action);
gap: 0.5rem;
}
[slot='navigation'] ul {
list-style: none;
margin: 0;
}
[slot='navigation'] ul a {
border-radius: var(--wa-border-radius-m);
padding: var(--wa-space-xs);
}
[slot='navigation'] ul a:hover,
main ol li:hover {
background-color: color-mix(in oklab, var(--wa-color-surface-default), var(--wa-color-brand-fill-quiet));
}
[slot='navigation'] wa-icon {
align-items: center;
aspect-ratio: 1;
color: var(--wa-color-brand-fill-loud);
display: flex;
height: var(--flank-size);
justify-content: center;
}
[slot='navigation'] #recent wa-icon {
border-radius: var(--wa-border-radius-s);
}
[slot='main-header'] {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
border-inline: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
border-radius: var(--wa-border-radius-l) var(--wa-border-radius-l) 0 0
}
main,
[slot*='main'] {
margin-inline: var(--wa-space-m);
}
main ol li {
padding: var(--wa-space-m);
}
main ol li .wa-flank {
--flank-size: 2rem;
}
main ol li:not(:first-child) {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
main,
[slot='main-footer'] {
border-inline: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
main,
[slot='main-header'] {
background-color: var(--wa-color-surface-raised);
}
#play-controls wa-icon-button::part(base) {
border: var(--wa-border-width-l) var(--wa-border-style) currentColor;
border-radius: var(--wa-border-radius-circle);
font-size: 1.5rem;
}
#play-controls wa-icon-button[name="play"]::part(base) {
background-color: var(--wa-color-brand-fill-loud);
border: none;
color: var(--wa-color-brand-on-loud);
font-size: 3rem;
padding: 1.5rem;
}
</style>

View File

@@ -1,888 +0,0 @@
---
title: Page
description: Pages offer an easy way to scaffold entire page layouts using minimal markup.
tags: [pro, organization, layout]
isPro: true
order: 0
# icon: page
---
The page component is designed to power full webpages. It is flexible enough to handle most modern designs and includes a simple mechanism for handling desktop and mobile navigation.
## Layout Anatomy
This image depicts a page's anatomy, including the default positions of each section. The labels represent the [named slots](#slots) you can use to populate them.
Most slots are optional. Slots that have no content will not be shown, allowing you to opt-in to just the sections you actually need.
{% include "page-demo.njk" %}
<!-- ![Screenshot of Layout Anatomy showing various slots](/assets/images/layout-anatomy.svg) -->
## Using `wa-page`
:::info
If you're not familiar with how slots work in HTML, you might want to [learn more about slots](/docs/usage/#slots) before using this component.
:::
A number of sections are available as part of the page component, most of which are optional. Content is populated by [slotting elements](/docs/usage/#slots) into various locations.
This component _does not_ implement any [content sectioning](https://developer.mozilla.org/en-US/docs/Web/HTML/Element#content_sectioning) or "semantic elements" internally (such as `<main>`, `<header>`, `<footer>`, etc.). Instead, we recommended that you slot in content sectioning elements wherever you feel they're appropriate.
When using `<wa-page>`, make sure to zero out all paddings and margins on `<html>` and `<body>`, otherwise you may see unexpected gaps. We highly recommend adding the following styles when using `<wa-page>`:
```css
html,
body {
min-height: 100%;
height: 100%;
padding: 0;
margin: 0;
}
```
::info
If you use [native styles](/docs/native/), this is already taken care of.
:::
## Examples
:::warning
Open demos in a new tab to examine their behavior in different window sizes.
The previews below use simulated zooming which, depending on your browser, may not be accurate.
:::
### Documentation
A sample documentation page using [all available slots](#slots).
The navigation menu collapses into a drawer at a custom `mobile-breakpoint` of 920px.
It can be opened using a button with `[data-toggle-nav]` that appears in the `subheader` slot. The `aside` slot is also hidden below 920px.
```html {.example viewport="1600"}
<wa-page mobile-breakpoint="920">
<div slot="banner" class="wa-body-s">
<a href="#" class="wa-cluster wa-align-items-baseline wa-gap-xs" style="flex-wrap: nowrap;">
<wa-icon name="gift"></wa-icon>
<span>Give a Hoot for the Holidays: Donate now and double your impact.</span>
</a>
</div>
<header slot="header" class="wa-split">
<div class="wa-cluster">
<wa-icon name="feather-pointed" style="color: var(--wa-color-brand-fill-loud); font-size: 1.5em;"></wa-icon>
<span id="brand-name" class="wa-heading-s wa-desktop-only">Audubon Worldwide</span>
<a href="#">Our Work</a>
<a href="#">About Us</a>
<a href="#">Discover</a>
<a href="#">Get Involved</a>
</div>
<div class="wa-cluster wa-gap-xs">
<wa-button size="small" variant="brand" appearance="outlined">Find Your Local Audubon</wa-button>
<wa-button size="small" variant="brand">Donate</wa-button>
</div>
</header>
<nav slot="subheader">
<div class="wa-cluster" style="flex-wrap: nowrap;">
<wa-icon-button data-toggle-nav name="bars" label="Menu"></wa-icon-button>
<wa-breadcrumb style="font-size: var(--wa-font-size-s);">
<wa-breadcrumb-item>Field Guides</wa-breadcrumb-item>
<wa-breadcrumb-item>Owls</wa-breadcrumb-item>
<wa-breadcrumb-item>Great Horned Owl</wa-breadcrumb-item>
</wa-breadcrumb>
</div>
<wa-input id="search" class="wa-desktop-only" placeholder="Search" size="small" style="max-inline-size: 12rem;">
<wa-icon slot="prefix" name="magnifying-glass"></wa-icon>
</wa-input>
</nav>
<nav slot="navigation-header">
<div class="wa-flank">
<wa-avatar image="https://images.unsplash.com/photo-1544648720-132573cb590d?q=20" label=""></wa-avatar>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Great Horned Owl</span>
<span class="wa-caption-s" lang="la"><em>Bubo virginianus</em></span>
</div>
</div>
</nav>
<nav slot="navigation">
<a href="#identification">Identification</a>
<a href="#range">Range and Habitat</a>
<a href="#behavior">Behavior</a>
<a href="#conservation">Conservation</a>
</nav>
<nav slot="navigation-footer">
<a href="#" class="wa-flank">
<wa-icon name="camera"></wa-icon>
<span>Photo Gallery</span>
</a>
<a href="#" class="wa-flank">
<wa-icon name="map-location-dot"></wa-icon>
<span>Interactive Range Map</span>
</a>
</nav>
<header slot="main-header">
<div class="wa-flank:end wa-border-radius-l wa-dark" style="background-color: var(--wa-color-surface-lowered); --content-percentage: 35%; padding: var(--wa-space-m);">
<div class="wa-stack" style="margin: var(--wa-space-2xl);">
<h1>Great Horned Owl</h1>
<wa-divider></wa-divider>
<div class="wa-cluster wa-gap-xs">
<wa-tag size="small">Owls</wa-tag>
<wa-tag size="small">Birds of Prey</wa-tag>
<wa-tag size="small">Pleistocene Birds</wa-tag>
</div>
<div class="wa-flank">
<wa-icon name="ruler"></wa-icon>
<span class="wa-caption-m">L 21.5" | WS 48.5"</span>
</div>
<div class="wa-flank">
<wa-icon name="earth-americas"></wa-icon>
<span class="wa-caption-m">North America (Widespread), Central America (Limited), South America (Limited)</span>
</div>
<div class="wa-flank">
<wa-icon name="shield-heart"></wa-icon>
<span class="wa-caption-m">Least Concern</span>
</div>
</div>
<div class="wa-frame" style="border-radius: var(--wa-border-radius-l); max-inline-size: 40ch;">
<img src="https://images.unsplash.com/photo-1544648720-132573cb590d?q=20" />
</div>
</div>
</header>
<main class="wa-body-l">
<h2 id="identification">Identification</h2>
<p>Lorem ipsum odor amet, consectetuer adipiscing elit. Eget habitant scelerisque lectus ultrices nascetur aliquet sapien primis. Cursus sapien fusce semper nulla elit sociosqu lectus per sem. Sem ad porttitor dictum nisl pharetra tortor convallis. Sit molestie hendrerit porta dictum tortor posuere euismod magna. Mauris suspendisse pharetra finibus; eleifend etiam ridiculus.</p>
<h2 id="range">Range and Habitat</h2>
<p>Diam sed ipsum pretium porttitor class cubilia elementum. Blandit felis ligula habitant ultricies vulputate rutrum lacus commodo pulvinar. Nostra semper placerat lectus in dis eu. Sagittis ipsum placerat rhoncus lacus id eget. Erat pharetra aptent enim, augue accumsan ultricies inceptos habitasse. Senectus id maximus parturient tellus; fermentum posuere vulputate luctus. Ac tempus dapibus vehicula ligula ullamcorper sit duis.</p>
<h2 id="behavior">Behavior</h2>
<p>Erat vitae luctus arcu taciti malesuada pretium arcu justo primis. Cubilia vitae maecenas congue velit id netus arcu. Dictum vel pellentesque taciti fermentum risus consectetur amet. Faucibus commodo habitasse sem maximus praesent purus, dignissim tristique porta. Platea magna justo ipsum ut metus ac facilisi. Imperdiet laoreet pharetra maximus lacus tortor suscipit. Nam quisque iaculis orci porttitor pellentesque rhoncus. Molestie sagittis tincidunt quisque nisi non urna conubia.</p>
<h2 id="conservation">Conservation</h2>
<p>Nullam magna quam quisque eu varius integer. Inceptos donec facilisi risus himenaeos semper mollis habitasse. Vehicula lacus vivamus euismod pharetra mollis dictum. Ante ex tortor elementum eleifend habitasse orci aliquam. Fames erat senectus fames etiam dapibus cursus.</p>
</main>
<footer slot="main-footer">
<section>
<h2 class="wa-heading-m">Sources</h2>
<ul class="wa-body-s">
<li><cite><a href="https://www.audubon.org/field-guide/bird/great-horned-owl" target="_blank" rel="noopener">Great Horned Owl</a></cite>, National Audubon Society. Retrieved 5 December 2024.</li>
<li><cite><a href="https://www.allaboutbirds.org/guide/Great_Horned_Owl/" target="_blank" rel="noopener">Great Horned Owl</a></cite>, All About Birds by CornellLab. Retrieved 5 December 2024.</li>
<li>Armistead, G. L. (2015). <cite>Field guide to birds of Pennsylvania</cite>. Scott & Nix, Inc.</li>
</ul>
</section>
</footer>
<aside slot="aside" class="wa-desktop-only">
<h2 class="wa-heading-m">Discover More Birds</h2>
<wa-card with-image>
<div slot="image" class="wa-frame">
<img src="https://images.unsplash.com/photo-1635254859323-65b78408dcca?q=20" alt="" />
</div>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Long-eared Owl</span>
<span class="wa-caption-s" lang="la"><em>Asio otus</em></span>
</div>
</wa-card>
<wa-card with-image>
<div slot="image" class="wa-frame">
<img src="https://images.unsplash.com/photo-1661350356618-f5915c7b6a3c?q=20" alt="" />
</div>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Northen Hawk Owl</span>
<span class="wa-caption-s" lang="la"><em>Surnia ulula</em></span>
</div>
</wa-card>
<wa-card with-image>
<div slot="image" class="wa-frame">
<img src="https://images.unsplash.com/photo-1660307777355-f08bced145d3?q=20" alt="" />
</div>
<div class="wa-stack wa-gap-3xs">
<span class="wa-heading-s">Golden Eagle</span>
<span class="wa-caption-s" lang="la"><em>Aquila chrysaetos</em></span>
</div>
</wa-card>
</aside>
<footer slot="footer" class="wa-grid wa-gap-xl">
<div class="wa-cluster" style="flex-wrap: nowrap;">
<wa-icon name="feather-pointed" style="font-size: 1.5em;"></wa-icon>
<span class="wa-heading-s">Audubon Worldwide</span>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">Our Work</h3>
<a href="#">Habitat Restoration</a>
<a href="#">Migration Science</a>
<a href="#">Advocacy</a>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">About Us</h3>
<a href="#">Our History</a>
<a href="#">Leadership</a>
<a href="#">Fiscal Reports</a>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">Discover</h3>
<a href="#">Field Guides</a>
<a href="#">Photo Search</a>
<a href="#">Gear and Resources</a>
</div>
<div class="wa-stack">
<h3 class="wa-heading-xs">Get Involved</h3>
<a href="#">Adopt a Bird</a>
<a href="#">Your Local Audubon</a>
<a href="#">Youth Audubon Camps</a>
</div>
</footer>
</wa-page>
<style>
wa-page {
--menu-width: 15rem;
--aside-width: 15rem;
}
wa-page[view='desktop'] {
[slot*='navigation'] {
border-inline-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
}
wa-page[view='mobile'] {
--menu-width: auto;
--aside-width: auto;
}
[slot='banner'] {
--wa-color-text-link: var(--wa-color-neutral-on-loud);
background-color: var(--wa-color-neutral-fill-loud);
}
[slot='header'] {
--wa-link-decoration-default: none;
border-block-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot*='header'] a {
font-weight: var(--wa-font-weight-action);
}
[slot='subheader'] {
background-color: var(--wa-color-surface-lowered);
border-block-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot='navigation-header'] {
border-block-end: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot*='navigation'] a {
--wa-color-text-link: var(--wa-color-text-normal);
}
[slot='navigation-footer'] {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
.wa-flank {
--flank-size: 1.25em;
}
}
[slot='main-header'],
main,
[slot='main-footer'] {
max-inline-size: 60rem;
margin-inline: auto;
}
[slot='main-footer'] {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
[slot='footer'] {
--wa-color-text-link: var(--wa-color-text-quiet);
background-color: var(--wa-color-surface-lowered);
font-size: var(--wa-font-size-s);
}
</style>
<script>
const sectionAnchors = document.querySelectorAll("[slot*='navigation'] a[href*='#']");
sectionAnchors.forEach((sectionAnchor) => sectionAnchor.setAttribute("data-drawer", "close"));
</script>
```
### Media
A sample media app page using `header`, `navigation-header`, `main-header`, and `main-footer` along with the default slot. The navigation menu collapses into a drawer at the default `mobile-breakpoint` and can be opened using a button with `[data-toggle-nav]` that appears in the `header` slot.
```html {.example viewport="1600"}
<wa-page class="wa-dark">
<header slot="header">
<div class="wa-cluster">
<wa-icon-button name="bars" label="Menu" data-toggle-nav></wa-icon-button>
<wa-icon name="record-vinyl"></wa-icon>
<span class="wa-heading-m">radiogaga</span>
</div>
<wa-input id="search-header" placeholder="Search" class="wa-desktop-only" style="max-inline-size: 100%;">
<wa-icon slot="prefix" name="magnifying-glass" ></wa-icon>
</wa-input>
<div class="wa-cluster">
<wa-button appearance="outlined">Log In</wa-button>
<wa-button>Sign Up</wa-button>
</div>
</header>
<div slot="navigation-header" class="wa-split">
<wa-input id="search-nav-drawer" placeholder="Search" style="max-inline-size: 100%;" class="wa-mobile-only">
<wa-icon slot="prefix" name="magnifying-glass" ></wa-icon>
</wa-input>
<div class="wa-split">
<h2 class="wa-heading-s">For You</h2>
<wa-icon-button id="settings" name="gear" label="Settings"></wa-icon-button>
</div>
</div>
<nav slot="navigation">
<h3 class="wa-heading-xs">Discover</h3>
<ul class="wa-stack wa-gap-0">
<li>
<a href="#" class="wa-flank">
<wa-icon name="house"></wa-icon>
<span>Home</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="star"></wa-icon>
<span>New</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="tower-broadcast"></wa-icon>
<span>Stations</span>
</a>
</li>
</ul>
<h3 class="wa-heading-xs">Library</h3>
<ul class="wa-stack wa-gap-0">
<li>
<a href="#" class="wa-flank">
<wa-icon name="heart"></wa-icon>
<span>Favorites</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="bars-staggered"></wa-icon>
<span>Playlists</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="microphone-lines"></wa-icon>
<span>Artists</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="layer-group"></wa-icon>
<span>Albums</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="podcast"></wa-icon>
<span>Podcasts</span>
</a>
</li>
</ul>
<h3 class="wa-heading-xs">Recently Played</h3>
<ul id="recent" class="wa-stack wa-gap-0">
<li>
<a href="#" class="wa-flank">
<wa-icon name="radio" style="background: var(--wa-color-red-90); color: var(--wa-color-red-60);"></wa-icon>
<span>Lo-Fi Station</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="font-awesome" style="background: var(--wa-color-blue-30); color: var(--wa-color-yellow-90);"></wa-icon>
<span>Podcast Awesome</span>
</a>
</li>
<li>
<a href="#" class="wa-flank">
<wa-icon name="seedling" style="background: var(--wa-color-green-70); color: var(--wa-color-green-90);"></wa-icon>
<div class="wa-stack wa-gap-0">
<span>Seasons</span>
<span class="wa-caption-s">Blister Soul</span>
</div>
</a>
</li>
</ul>
</nav>
<div slot="main-header">
<wa-icon-button id="back" name="chevron-left" label="Back"></wa-icon-button>
<wa-tooltip for="back" placement="bottom" distance="2">Back</wa-tooltip>
<div class="wa-cluster">
<wa-icon-button id="favorite" name="heart" variant="regular" label="Favorite"></wa-icon-button>
<wa-tooltip for="favorite" placement="bottom" distance="2">Favorite</wa-tooltip>
<wa-icon-button id="options" name="ellipsis" label="Options"></wa-icon-button>
<wa-tooltip for="options" placement="bottom" distance="2">Options</wa-tooltip>
</div>
</div>
<main>
<div class="wa-stack wa-gap-3xl">
<div class="wa-flank wa-gap-3xl" style="--content-percentage: 40%;">
<div class="wa-frame wa-border-radius-l" style="max-inline-size: 40ch;">
<img src="https://images.unsplash.com/photo-1732430579016-8d5e5ebd3c99?q=20" alt="Home for the Holidays album artwork" />
</div>
<div class="wa-split:column wa-align-items-start">
<div class="wa-stack" style="margin-block: auto;">
<h1 class="wa-heading-3xl">Home for the Holidays</h1>
<a href="#" class="wa-heading-m">The Shire Choir</a>
<div class="wa-cluster wa-caption-m wa-gap-2xs">
<span>Holiday</span>
<span>&bull;</span>
<span>2024</span>
<span>&bull;</span>
<span>12 songs, 41 minutes 9 seconds</span>
</div>
</div>
<div id="play-controls" class="wa-split wa-gap-xl">
<div class="wa-cluster wa-gap-xl">
<wa-icon-button name="play" label="Play"></wa-icon-button>
<wa-icon-button name="shuffle" label="Shuffle"></wa-icon-button>
</div>
<wa-icon-button name="plus" label="Add to Library"></wa-icon-button>
</div>
</div>
</div>
<ol class="wa-stack wa-gap-0">
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="1"></wa-icon>
<span>Fa-La-La-Fellowship</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:27</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="2"></wa-icon>
<span>Sleigh Ride</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:36</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="3"></wa-icon>
<span>All I Want For Christmas Is Stew</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:51</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="4"></wa-icon>
<span>Rockin' Around the Christmas Ent</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:05</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="5"></wa-icon>
<span>Merry, Did You Know?</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">1:56</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="6"></wa-icon>
<span>Run Run Shadowfax</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:32</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="7"></wa-icon>
<span>You're a Mean One, Mr. Grima</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:46</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="8"></wa-icon>
<span>O Come, All Ye Faithful</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:27</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<wa-icon name="9"></wa-icon>
<span>Do You Hear What I Hear</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:13</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<span class="wa-cluster wa-gap-3xs">
<wa-icon name="1"></wa-icon>
<wa-icon name="0"></wa-icon>
</span>
<span>Carol of the Horns</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">2:55</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<span class="wa-cluster wa-gap-3xs">
<wa-icon name="1"></wa-icon>
<wa-icon name="1"></wa-icon>
</span>
<span>Silent Night</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:10</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
<li class="wa-split">
<span class="wa-flank">
<span class="wa-cluster wa-gap-3xs">
<wa-icon name="1"></wa-icon>
<wa-icon name="2"></wa-icon>
</span>
<span>Wizard Wonderland</span>
</span>
<span class="wa-cluster">
<span class="wa-caption-m">3:22</span>
<wa-icon-button name="ellipsis" label="Song Options"></wa-icon-button>
</span>
</li>
</ol>
</div>
</main>
<div slot="main-footer" class="wa-grid wa-gap-xl wa-align-items-center">
<h2 class="wa-heading-2xl">More You Might Like</h2>
<div class="wa-stack wa-gap-xs">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1675219119611-40323b738563?q=20" alt="" />
</div>
<span class="wa-heading-s">Festival of Lights</span>
<span class="wa-caption-s">Station</span>
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1481930916222-5ec4696fc0f2?q=20" alt="" />
</div>
<span class="wa-heading-s">Holiday Cheer</span>
<span class="wa-caption-s">Essential Playlist</span>
</div>
<div class="wa-stack wa-gap-xs">
<div class="wa-frame wa-border-radius-l">
<img src="https://images.unsplash.com/photo-1667514627762-521b1c815a89?q=20" alt="" />
</div>
<span class="wa-heading-s">Nursery Rhymes from the Shire</span>
<span class="wa-caption-s">The Shire Choir</span>
</div>
</div>
</wa-page>
<style>
wa-page {
--menu-width: 30ch;
--wa-tooltip-arrow-size: 0;
background-color: var(--wa-color-surface-lowered);
}
wa-page[view='mobile'] {
--menu-width: auto;
[slot*='main'], main {
padding: var(--wa-space-xl);
}
}
wa-page,
[slot='header'],
wa-page[view='desktop'] [slot*='navigation'] {
background-color: var(--wa-color-surface-lowered);
}
wa-page[view='mobile'] [slot*='navigation'] {
padding: 0;
}
wa-page::part(base) {
background-color: var(--wa-color-surface-lowered);
}
[slot='header'] {
background: linear-gradient(to bottom, var(--wa-color-surface-raised), var(--wa-color-surface-lowered));
}
[slot='navigation-header'],
[slot='main-header'] {
padding-block-end: 0 !important;
padding-block-start: var(--wa-space-3xl);
}
[slot='navigation'] {
a {
--wa-color-text-link: var(--wa-color-text-normal);
--wa-link-decoration-default: none;
--wa-link-decoration-hover: none;
--flank-size: 2rem;
font-weight: var(--wa-font-weight-action);
gap: 0.5rem;
}
ul {
list-style: none;
margin: 0;
a {
border-radius: var(--wa-border-radius-m);
padding: var(--wa-space-xs);
&:hover {
background-color: color-mix(in oklab, var(--wa-color-surface-default), var(--wa-color-brand-fill-quiet));
}
}
}
wa-icon {
align-items: center;
aspect-ratio: 1;
color: var(--wa-color-brand-fill-loud);
display: flex;
height: var(--flank-size);
justify-content: center;
}
#recent wa-icon {
border-radius: var(--wa-border-radius-s);
}
}
[slot='main-header'] {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
border-inline: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
border-radius: var(--wa-border-radius-l) var(--wa-border-radius-l) 0 0
}
main,
[slot*='main'] {
margin-inline: var(--wa-space-m);
}
main ol li {
padding: var(--wa-space-m);
&:hover {
background-color: color-mix(in oklab, var(--wa-color-surface-default), var(--wa-color-brand-fill-quiet));
}
&:not(:first-child) {
border-block-start: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
.wa-flank {
--flank-size: 2rem;
}
}
main,
[slot='main-footer'] {
border-inline: var(--wa-border-width-s) var(--wa-border-style) var(--wa-color-surface-border);
}
main,
[slot='main-header'] {
background-color: var(--wa-color-surface-raised);
}
#play-controls wa-icon-button::part(base) {
border: var(--wa-border-width-l) var(--wa-border-style) currentColor;
border-radius: var(--wa-border-radius-circle);
font-size: 1.5rem;
}
#play-controls wa-icon-button[name="play"]::part(base) {
background-color: var(--wa-color-brand-fill-loud);
border: none;
color: var(--wa-color-brand-on-loud);
font-size: 3rem;
padding: 0.5em 0.45em 0.5em 0.55em;
}
[slot='main-footer'].wa-grid > * {
max-inline-size: 30ch;
}
</style>
<script>
const sectionAnchors = document.querySelectorAll("[slot*='navigation'] a[href*='#']");
sectionAnchors.forEach((sectionAnchor) => sectionAnchor.setAttribute("data-drawer", "close"));
</script>
```
## Customization
### Sticky Sections
The following sections of a page are "sticky" by default, meaning they remain in position as the user scrolls.
- `banner`
- `header`
- `sub-header`
- `menu` (`navigation` itself is not sticky, but its parent `menu` is)
- `aside`
This is often desirable, but you can change this behavior using the `disable-sticky` attribute. Use a space-delimited list of names to tell the page which sections should not be sticky.
```html
<wa-page disable-sticky="header aside"> ... </wa-page>
```
### Skip To Content
The layout provides a "skip to content" link that's visually hidden until the user tabs into it. You don't have to do anything to configure this, unless you want to change the text displayed in the link. In that case, you can slot in your own text using the `skip-to-content` slot.
This example localizes the "skip to content" link for German users.
```html
<wa-page>
...
<span slot="skip-to-content">Zum Inhalt springen</span>
...
</wa-page>
```
### Responsiveness
A page isn't very opinionated when it comes to responsive behaviors, but there are tools in place to help make responsiveness easy.
#### Default Slot Styles
Each slot is a [flex container](https://developer.mozilla.org/en-US/docs/Glossary/Flex_Container) and specifies some flex properties so that your content is reasonably responsive by default.
The following slots specify `justify-content: space-between` and `flex-wrap: wrap` to evenly distribute child elements horizontally and allow them to wrap when space is limited:
- `header`
- `subheader`
- `main-header`
- `main-footer`
- `footer`
The following slots specify `flex-direction: column` to arrange child elements vertically:
- `navigation-header`
- `navigation` (or `menu`)
- `navigation-footer`
- `aside`
And the `banner` slot specifies `justify-content: center` to horizontally center its child elements.
You can override the default display and flex properties for each slot with your own CSS.
#### Responsive Navigation
When you use the `navigation` slot, your slotted content automatically collapses into a drawer on smaller screens.
The breakpoint at which this occurs is `768px` by default, but you can change it using the `mobile-breakpoint` attribute,
which takes either a number or a [CSS length](https://developer.mozilla.org/en-US/docs/Web/CSS/length).
```html
<wa-page mobile-breakpoint="600"> ... </wa-page>
```
```html {.example viewport}
<wa-page mobile-breakpoint="50ch">
<div slot=navigation>Nav</div>
<header slot=header>
<div style="width: 50ch; background: gold">Im 50ch wide</div>
</header>
</wa-page>
<style>
html,
body {
min-height: 100%;
height: 100%;
padding: 0;
margin: 0;
}
</style>
```
By default, a "hamburger" button appears in the `header` slot to toggle the navigation menu on smaller screens.
You can customize what this looks like by slotting your own button in the `toggle-navigation` slot,
or place the `data-toggle-nav` attribute on any button on your page (This _does not_ have to be a Web Awesome element.).
The default button not be shown when using either of these methods — if you want to use multiple navigation toggles on your page, simply add the `data-toggle-nav` attribute to multiple elements.
```html
<wa-page mobile-breakpoint="600">
...
<wa-button data-toggle-nav>Menu</wa-button>
...
</wa-page>
```
Alternatively, you can apply `nav-state="open"` and `nav-state="closed"` to the layout component to show and hide the navigation, respectively.
```html
<wa-page nav-state="open"> ... </wa-page>
```
`<wa-page>` is given the attribute `view="mobile"` or `view="desktop"` when the viewport narrower or wider than the `mobile-breakpoint` value, respectively. You can leverage these attributes to change styles depending on the size of the viewport.
This is especially useful to hide your `data-toggle-nav` button when the viewport is wider:
```css
wa-page[view='desktop'] [data-toggle-nav] {
display: none;
}
```
::info
If you use [native styles](/docs/native/), this is already taken care for you, and the `data-toggle-nav` button is already hidden on wider screens.
:::
#### Custom Widths
You specify widths for some slots on your page with [CSS custom properties](#css-custom-properties) for `--menu-width`, `--main-width`, and `--aside-width`.
If you specify `--menu-width` to apply a specific width to your `navigation` slot, space will still be reserved on the page even below the `mobile-breakpoint`. To collapse this space on smaller screens, add the following code to your styles:
```css
wa-page[view='mobile'] {
--menu-width: auto;
}
```
You can use a similar approach for `--aside-width` to hide the `aside` slot on smaller screens. Be sure to also specify `display: none` for the slot:
```css
wa-page[view='mobile'] {
--aside-width: auto;
[slot='aside'] {
display: none;
}
}
```
### Spacing
A page specifies default `padding` within each slot and a `gap` between the slot's direct children. You can drop elements into any slot, and reasonable spacing is already applied for you.
You can override the default spacing for each slot with your own CSS. In this example, we're setting custom `gap` and `padding` for the `footer` slot:
```css
[slot="footer"] {
gap: var(--wa-space-xl);
padding: var(--wa-space-xl);
}
```
## Utility classes
[Native styles](/docs/native/) define a few useful defaults for `<wa-page>`, as well as
two utility classes you can use for common responsive design tasks:
- `.wa-mobile-only` hides an element on the desktop view
- `.wa-desktop-only` hides an element on the mobile view
If you dont want to use [native styles](/docs/native/), you can include this stylesheet in your project to use these:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/components/page.css' %}" />
```

View File

@@ -1,66 +0,0 @@
body {
padding: 0;
margin: 0;
}
wa-page {
margin: var(--wa-space-xs);
margin-inline-start: 0;
&::part(base),
&::part(main),
&::part(navigation),
&::part(body) {
gap: var(--wa-space-xs);
}
}
:is([slot='banner'], [slot='header'], [slot='subheader'], [slot='footer'], [slot*='navigation']) {
margin-inline-start: var(--wa-space-xs);
}
.slot-content[slot='banner'],
.slot-content[slot='header'],
.slot-content[slot='subheader'] {
outline: 2px solid var(--wa-color-surface-default);
}
.slot-content {
padding: var(--wa-space-m);
border-radius: var(--wa-border-radius-m);
align-content: center;
justify-content: center;
text-align: center;
height: 100%;
box-sizing: border-box;
background: var(--wa-color-blue-80);
color: var(--wa-color-blue-20);
&[slot='banner'] {
background: var(--wa-color-blue-50);
color: white;
}
&[slot='header'] {
background: var(--wa-color-blue-60);
color: var(--wa-color-blue-10);
}
&[slot^='main'],
&[slot=''] {
background: var(--wa-color-gray-80);
color: var(--wa-color-gray-20);
}
&[slot^='navigation'] {
background: var(--wa-color-purple-80);
color: var(--wa-color-purple-20);
}
strong {
display: block;
}
&:not([slot='']) p {
display: none;
}
}

View File

@@ -1,23 +0,0 @@
#page_slots_demo {
display: flex;
flex-flow: column;
gap: 1em;
margin-bottom: var(--wa-space-xl);
fieldset .options {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(9em, 1fr));
gap: 0.2em 1em;
wa-checkbox {
white-space: nowrap;
}
p {
display: contents;
}
}
wa-viewport-demo {
}
}

View File

@@ -1,51 +0,0 @@
let container = document.getElementById('page_slots_demo');
let fieldset = container.querySelector('fieldset');
let iframe = container.querySelector('iframe');
let stylesheets = Array.from(document.querySelectorAll("link[rel=stylesheet][href^='/dist/']"))
.map(i => i.outerHTML)
.join('\n');
let includes = `${stylesheets}
<script src="/dist/webawesome.loader.js" type="module"></script>
<link rel="stylesheet" href="./demo-page.css">`;
async function render() {
await customElements.whenDefined('wa-checkbox');
// Let checkboxes update their "state"
await Promise.allSettled(
Array.from(fieldset.querySelectorAll('wa-checkbox[name=slot]')).map(checkbox => {
return checkbox.updateComplete;
}),
);
let slots = Array.from(fieldset.querySelectorAll('wa-checkbox[name=slot]:state(checked)'));
let slotsHTML = slots
.map(slot => {
let name = slot.getAttribute('value');
let description = slot.getAttribute('data-description');
let tag = 'div';
if (name.endsWith('header')) {
tag = 'header';
}
if (name.endsWith('footer')) {
tag = 'footer';
}
return `<${tag} class="slot-content" slot="${name}">
<strong>${name || 'main <em>(default)</em>'}</strong>
<p>${description}</p>
</${tag}>`;
})
.join('\n');
let page = iframe.contentDocument?.querySelector('wa-page');
if (page) {
page.innerHTML = slotsHTML;
} else {
iframe.srcdoc = `${includes}<wa-page>${slotsHTML}</wa-page>`;
}
}
await render();
fieldset?.addEventListener('input', render);

View File

@@ -1,151 +0,0 @@
---
title: Radio Button
description: Radios buttons allow the user to select a single option from a group using a button-like control.
tags: forms
parent: radio-group
icon: radio-group
---
Radio buttons are designed to be used with [radio groups](/docs/components/radio-group). When a radio button has focus, the arrow keys can be used to change the selected option just like standard radio controls.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" 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>
```
## Examples
### Checked States
To set the initial value and checked state, use the `value` attribute on the containing radio group.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" 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>
```
### Disabled
Use the `disabled` attribute to disable a radio button.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2" disabled>Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
### Sizes
Use the `size` attribute to change a radio button's size.
```html {.example}
<wa-radio-group size="small" label="Select an option" orientation="horizontal" 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>
<br />
<wa-radio-group size="medium" label="Select an option" orientation="horizontal" 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>
<br />
<wa-radio-group size="large" label="Select an option" orientation="horizontal" 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>
```
### Pill Buttons
Use the `pill` attribute to give radio buttons rounded edges.
```html {.example}
<wa-radio-group size="small" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button pill value="1">Option 1</wa-radio-button>
<wa-radio-button pill value="2">Option 2</wa-radio-button>
<wa-radio-button pill value="3">Option 3</wa-radio-button>
</wa-radio-group>
<br />
<wa-radio-group size="medium" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button pill value="1">Option 1</wa-radio-button>
<wa-radio-button pill value="2">Option 2</wa-radio-button>
<wa-radio-button pill value="3">Option 3</wa-radio-button>
</wa-radio-group>
<br />
<wa-radio-group size="large" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button pill value="1">Option 1</wa-radio-button>
<wa-radio-button pill value="2">Option 2</wa-radio-button>
<wa-radio-button pill value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
### Prefix and Suffix Icons
Use the `prefix` and `suffix` slots to add icons.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">
<wa-icon slot="prefix" name="archive" variant="solid"></wa-icon>
Option 1
</wa-radio-button>
<wa-radio-button value="2">
<wa-icon slot="suffix" name="bag-shopping" variant="solid"></wa-icon>
Option 2
</wa-radio-button>
<wa-radio-button value="3">
<wa-icon slot="prefix" name="gift" variant="solid"></wa-icon>
<wa-icon slot="suffix" name="shopping-cart" variant="solid"></wa-icon>
Option 3
</wa-radio-button>
</wa-radio-group>
```
### Buttons with Icons
You can omit button labels and use icons instead. Make sure to set a `label` attribute on each icon so screen readers will announce each option correctly.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="neutral">
<wa-radio-button value="angry">
<wa-icon name="face-angry" variant="solid" label="Angry"></wa-icon>
</wa-radio-button>
<wa-radio-button value="sad">
<wa-icon name="face-frown" variant="solid" label="Sad"></wa-icon>
</wa-radio-button>
<wa-radio-button value="neutral">
<wa-icon name="face-meh" variant="solid" label="Neutral"></wa-icon>
</wa-radio-button>
<wa-radio-button value="happy">
<wa-icon name="face-smile" variant="solid" label="Happy"></wa-icon>
</wa-radio-button>
<wa-radio-button value="laughing">
<wa-icon name="face-laugh" variant="solid" label="Laughing"></wa-icon>
</wa-radio-button>
</wa-radio-group>
```

View File

@@ -1,88 +0,0 @@
---
title: Radio
description: Radios allow the user to select a single option from a group.
tags: component
parent: radio-group
native: radio
icon: radio-group
---
Radios are designed to be used with [radio groups](/docs/components/radio-group).
```html {.example}
<wa-radio-group label="Select an option" name="a" value="1">
<wa-radio value="1">Option 1</wa-radio>
<wa-radio value="2">Option 2</wa-radio>
<wa-radio value="3">Option 3</wa-radio>
</wa-radio-group>
```
:::info
This component works with standard `<form>` elements. Please refer to the section on [form controls](/docs/form-controls) to learn more about form submission and client-side validation.
:::
## Examples
### Initial Value
To set the initial value and checked state, use the `value` attribute on the containing radio group.
```html {.example}
<wa-radio-group label="Select an option" name="a" value="3">
<wa-radio value="1">Option 1</wa-radio>
<wa-radio value="2">Option 2</wa-radio>
<wa-radio value="3">Option 3</wa-radio>
</wa-radio-group>
```
### Disabled
Use the `disabled` attribute to disable a radio.
```html {.example}
<wa-radio-group label="Select an option" name="a" value="1">
<wa-radio value="1">Option 1</wa-radio>
<wa-radio value="2" disabled>Option 2</wa-radio>
<wa-radio value="3">Option 3</wa-radio>
</wa-radio-group>
```
### Sizes
Add the `size` attribute to the [Radio Group](/docs/components/radio-group) to change the radios' size.
```html {.example}
<wa-radio-group size="small" value="1">
<wa-radio value="1">Small 1</wa-radio>
<wa-radio value="2">Small 2</wa-radio>
<wa-radio value="3">Small 3</wa-radio>
</wa-radio-group>
<br />
<wa-radio-group size="medium" value="1">
<wa-radio value="1">Medium 1</wa-radio>
<wa-radio value="2">Medium 2</wa-radio>
<wa-radio value="3">Medium 3</wa-radio>
</wa-radio-group>
<br />
<wa-radio-group size="large" value="1">
<wa-radio value="1">Large 1</wa-radio>
<wa-radio value="2">Large 2</wa-radio>
<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

@@ -1,118 +0,0 @@
---
title: Slider
description: Ranges allow the user to select a single value within a given range using a slider.
tags: [inputs, forms]
native: slider
icon: slider
---
```html {.example}
<wa-slider></wa-slider>
```
:::info
This component works with standard `<form>` elements. Please refer to the section on [form controls](/docs/form-controls) to learn more about form submission and client-side validation.
:::
## Examples
### Labels
Use the `label` attribute to give the range an accessible label. For labels that contain HTML, use the `label` slot instead.
```html {.example}
<wa-slider label="Volume" min="0" max="100"></wa-slider>
```
### Hint
Add descriptive hint to a range with the `hint` attribute. For hints that contain HTML, use the `hint` slot instead.
```html {.example}
<wa-slider label="Volume" hint="Controls the volume of the current song." min="0" max="100"></wa-slider>
```
### Min, Max, and Step
Use the `min` and `max` attributes to set the range's minimum and maximum values, respectively. The `step` attribute determines the value's interval when increasing and decreasing.
```html {.example}
<wa-slider min="0" max="10" step="1"></wa-slider>
```
### Disabled
Use the `disabled` attribute to disable a slider.
```html {.example}
<wa-slider disabled></wa-slider>
```
### Tooltip Placement
By default, the tooltip is shown on top. Set `tooltip` to `bottom` to show it below the slider.
```html {.example}
<wa-slider tooltip="bottom"></wa-slider>
```
### Disable the Tooltip
To disable the tooltip, set `tooltip` to `none`.
```html {.example}
<wa-slider tooltip="none"></wa-slider>
```
### Custom Track Colors
You can customize the active and inactive portions of the track using the `--track-color-active` and `--track-color-inactive` custom properties.
```html {.example}
<wa-slider
style="
--track-color-active: var(--wa-color-brand-fill-loud);
--track-color-inactive: var(--wa-color-brand-fill-normal);
"
></wa-slider>
```
### Custom Track Offset
You can customize the initial offset of the active track using the `--track-active-offset` custom property.
```html {.example}
<wa-slider
min="-100"
max="100"
style="
--track-color-active: var(--wa-color-brand-fill-loud);
--track-color-inactive: var(--wa-color-brand-fill-normal);
--track-active-offset: 50%;
"
></wa-slider>
```
### Custom Tooltip Formatter
You can change the tooltip's content by setting the `tooltipFormatter` property to a function that accepts the range's value as an argument.
```html {.example}
<wa-slider min="0" max="100" step="1" class="range-with-custom-formatter"></wa-slider>
<script>
const range = document.querySelector('.range-with-custom-formatter');
range.tooltipFormatter = value => `Total - ${value}%`;
</script>
```
### Right-to-Left languages
The component adapts to right-to-left (RTL) languages as you would expect.
```html {.example}
<wa-slider dir="rtl"
label="مقدار"
hint="التحكم في مستوى صوت الأغنية الحالية."
style="--track-color-active: var(--wa-color-brand-fill-loud)" value="10"></wa-slider>
```

View File

@@ -1,25 +0,0 @@
---
title: Tab Panel
description: Tab panels are used inside tab groups to display tabbed content.
tags: component
parent: tab-group
icon: tab-panel
---
```html {.example}
<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">This is the general tab panel.</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>
```
:::info
Additional demonstrations can be found in the [tab group examples](/docs/components/tab-group).
:::

View File

@@ -1,11 +0,0 @@
---
title: Tab
description: Tabs are used inside tab groups to represent and activate tab panels.
tags: component
parent: tab-group
icon: tab
---
:::info
Additional demonstrations can be found in the [tab group examples](/docs/components/tab-group).
:::

View File

@@ -1,105 +0,0 @@
---
title: Tag
description: Tags are used as labels to organize things or to indicate a selection.
tags: [feedback, content, apps]
icon: tag
---
```html {.example}
<wa-tag variant="brand">Brand</wa-tag>
<wa-tag variant="success">Success</wa-tag>
<wa-tag variant="neutral">Neutral</wa-tag>
<wa-tag variant="warning">Warning</wa-tag>
<wa-tag variant="danger">Danger</wa-tag>
```
## Examples
### Appearance
Use the `size` attribute to change a tag's visual appearance.
The default appearance is `outlined filled`.
```html {.example}
<div class="wa-stack">
<p>
<wa-tag variant="brand" appearance="outlined accent">Outlined accent</wa-tag>
<wa-tag variant="brand" appearance="accent">Accent</wa-tag>
<wa-tag variant="brand" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="brand" appearance="filled">Filled</wa-tag>
<wa-tag variant="brand" appearance="outlined filled">Outlined Filled</wa-tag>
</p>
<p>
<wa-tag variant="success" appearance="outlined accent">Outlined accent</wa-tag>
<wa-tag variant="success" appearance="accent">Accent</wa-tag>
<wa-tag variant="success" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="success" appearance="filled">Filled</wa-tag>
<wa-tag variant="success" appearance="outlined filled">Outlined Filled</wa-tag>
<p>
<wa-tag variant="neutral" appearance="outlined accent">Outlined accent</wa-tag>
<wa-tag variant="neutral" appearance="accent">Accent</wa-tag>
<wa-tag variant="neutral" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="neutral" appearance="filled">Filled</wa-tag>
<wa-tag variant="neutral" appearance="outlined filled">Outlined Filled</wa-tag>
<p>
<wa-tag variant="warning" appearance="outlined accent">Outlined accent</wa-tag>
<wa-tag variant="warning" appearance="accent">Accent</wa-tag>
<wa-tag variant="warning" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="warning" appearance="filled">Filled</wa-tag>
<wa-tag variant="warning" appearance="outlined filled">Outlined Filled</wa-tag>
<p>
<wa-tag variant="danger" appearance="outlined accent">Outlined accent</wa-tag>
<wa-tag variant="danger" appearance="accent">Accent</wa-tag>
<wa-tag variant="danger" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="danger" appearance="filled">Filled</wa-tag>
<wa-tag variant="danger" appearance="outlined filled">Outlined Filled</wa-tag>
</div>
```
### Sizes
Use the `size` attribute to change a tag's size.
```html {.example}
<wa-tag size="small">Small</wa-tag>
<wa-tag size="medium">Medium</wa-tag>
<wa-tag size="large">Large</wa-tag>
```
### Pill
Use the `pill` attribute to give tabs rounded edges.
```html {.example}
<wa-tag size="small" pill>Small</wa-tag>
<wa-tag size="medium" pill>Medium</wa-tag>
<wa-tag size="large" pill>Large</wa-tag>
```
### Removable
Use the `removable` attribute to add a remove button to the tag.
```html {.example}
<div class="tags-removable">
<wa-tag size="small" removable>Small</wa-tag>
<wa-tag size="medium" removable>Medium</wa-tag>
<wa-tag size="large" removable>Large</wa-tag>
</div>
<script>
const div = document.querySelector('.tags-removable');
div.addEventListener('wa-remove', event => {
const tag = event.target;
tag.style.opacity = '0';
setTimeout(() => (tag.style.opacity = '1'), 2000);
});
</script>
<style>
.tags-removable wa-tag {
transition: opacity var(--wa-transition-normal);
}
</style>
```

View File

@@ -1,82 +0,0 @@
---
title: Tree Item
description: A tree item serves as a hierarchical node that lives inside a tree.
tags: [navigation, disclosure, apps]
icon: tree
---
```html {.example}
<wa-tree>
<wa-tree-item>
Item 1
<wa-tree-item>Item A</wa-tree-item>
<wa-tree-item>Item B</wa-tree-item>
<wa-tree-item>Item C</wa-tree-item>
</wa-tree-item>
<wa-tree-item>Item 2</wa-tree-item>
<wa-tree-item>Item 3</wa-tree-item>
</wa-tree>
```
## Examples
### Nested tree items
A tree item can contain other tree items. This allows the node to be expanded or collapsed by the user.
```html {.example}
<wa-tree>
<wa-tree-item>
Item 1
<wa-tree-item>
Item A
<wa-tree-item>Item Z</wa-tree-item>
<wa-tree-item>Item Y</wa-tree-item>
<wa-tree-item>Item X</wa-tree-item>
</wa-tree-item>
<wa-tree-item>Item B</wa-tree-item>
<wa-tree-item>Item C</wa-tree-item>
</wa-tree-item>
<wa-tree-item>Item 2</wa-tree-item>
<wa-tree-item>Item 3</wa-tree-item>
</wa-tree>
```
### Selected
Use the `selected` attribute to select a tree item initially.
```html {.example}
<wa-tree>
<wa-tree-item selected>
Item 1
<wa-tree-item>Item A</wa-tree-item>
<wa-tree-item>Item B</wa-tree-item>
<wa-tree-item>Item C</wa-tree-item>
</wa-tree-item>
<wa-tree-item>Item 2</wa-tree-item>
<wa-tree-item>Item 3</wa-tree-item>
</wa-tree>
```
### Expanded
Use the `expanded` attribute to expand a tree item initially.
```html {.example}
<wa-tree>
<wa-tree-item expanded>
Item 1
<wa-tree-item expanded>
Item A
<wa-tree-item>Item Z</wa-tree-item>
<wa-tree-item>Item Y</wa-tree-item>
<wa-tree-item>Item X</wa-tree-item>
</wa-tree-item>
<wa-tree-item>Item B</wa-tree-item>
<wa-tree-item>Item C</wa-tree-item>
</wa-tree-item>
<wa-tree-item>Item 2</wa-tree-item>
<wa-tree-item>Item 3</wa-tree-item>
</wa-tree>
```

View File

@@ -1,70 +0,0 @@
---
title: Viewport Demo
description: Viewport demos can be used to display an iframe as a resizable, zoomable preview.
tags: component
noAlpha: true
---
```html {.example}
<wa-viewport-demo viewport="1200">
<iframe src="."></iframe>
</wa-viewport-demo>
```
:::warning
A lot of the functionality of this component will not work on cross-origin iframes.
:::
## Examples
### Arbitrary HTML content
You can render arbitrary HTML content in the iframe by using the `srcdoc` attribute:
```html {.example}
<wa-viewport-demo>
<iframe srcdoc="
&lt;button&gt;Click me!&lt;/button&gt;
"></iframe>
</wa-viewport-demo>
```
### Viewport Emulation
You can also provide a width value to emulate and it will be scaled accordingly:
```html {.example}
<wa-viewport-demo viewport="300">
<iframe srcdoc="
&lt;button&gt;Click me!&lt;/button&gt;
&lt;wa-button&gt;Click me!&lt;/wa-button&gt;
"></iframe>
</wa-viewport-demo>
```
By default, the viewport will be rendered to an initial 16:9 aspect ratio,
which can be changed via resizing.
You can customize this via the `--viewport-initial-aspect-ratio` property.
Or, you could add a height value:
```html {.example}
<wa-viewport-demo viewport="1600 x 1000">
<iframe srcdoc="
&lt;button&gt;Click me!&lt;/button&gt;
&lt;p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed maximus et tortor vel ullamcorper. Fusce tristique et justo quis auctor. In tristique dignissim dignissim. Fusce lacus urna, efficitur vel fringilla sed, hendrerit at ipsum. Donec suscipit ante ac ligula imperdiet varius. Aliquam ullamcorper augue sit amet lectus euismod finibus. Proin semper, diam at rhoncus posuere, diam dui semper turpis, ut faucibus mi ipsum nec ante. Morbi varius nibh ut facilisis varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in blandit velit. Aliquam massa eros, commodo eu vestibulum a, faucibus non risus.
&lt;p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed maximus et tortor vel ullamcorper. Fusce tristique et justo quis auctor. In tristique dignissim dignissim. Fusce lacus urna, efficitur vel fringilla sed, hendrerit at ipsum. Donec suscipit ante ac ligula imperdiet varius. Aliquam ullamcorper augue sit amet lectus euismod finibus. Proin semper, diam at rhoncus posuere, diam dui semper turpis, ut faucibus mi ipsum nec ante. Morbi varius nibh ut facilisis varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in blandit velit. Aliquam massa eros, commodo eu vestibulum a, faucibus non risus.
&lt;p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed maximus et tortor vel ullamcorper. Fusce tristique et justo quis auctor. In tristique dignissim dignissim. Fusce lacus urna, efficitur vel fringilla sed, hendrerit at ipsum. Donec suscipit ante ac ligula imperdiet varius. Aliquam ullamcorper augue sit amet lectus euismod finibus. Proin semper, diam at rhoncus posuere, diam dui semper turpis, ut faucibus mi ipsum nec ante. Morbi varius nibh ut facilisis varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce in blandit velit. Aliquam massa eros, commodo eu vestibulum a, faucibus non risus.
"></iframe>
</wa-viewport-demo>
```
## Roadmap
This component is a work in progress.
Some of the things that are not yet implemented are listed below.
It goes without saying that this list is a rough plan and subject to change.
- Non-linear zoom scale
- Extend to general content, not just iframes
- Styles for mobile and tablet frames and an attribute to switch between them
- Automatic iframe height

View File

@@ -1,10 +0,0 @@
export default {
eleventyComputed: {
children(data) {
let mainTag = data.tags?.[0];
let collection = data.collections[mainTag] ?? [];
return collection.filter(item => item.data.parent === data.page.fileSlug);
},
},
};

View File

@@ -1,47 +0,0 @@
---
title: Clamped brand tokens
layout: block
---
{% set tints = ['40-max', '50-max', '60-max', '40-min', '50-min', '60-min'] %}
{% for hue in hues %}
<link href="/dist/styles/brand/{{ hue }}.css" rel="stylesheet">
{% endfor %}
<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-brand-{{ hue }}">
<th>{{ hue | capitalize }}</th>
<td class="core-column">
<div class="color swatch" style="background-color: var(--wa-color-brand); color: var(--wa-color-brand-on);">
{{ palettes[paletteId][hue].maxChromaTint }}
<wa-copy-button value="--wa-color-brand" copy-label="--wa-color-brand"></wa-copy-button>
</div>
</td>
{% for tint in tints -%}
<td>
<div class="color swatch" style="background-color: var(--wa-color-brand-{{ tint }})">
<wa-copy-button value="--wa-color-brand-{{ tint }}" copy-label="--wa-color-brand-{{ tint }}"></wa-copy-button>
</div>
</td>
{%- endfor -%}
</tr>
{%- endfor %}
</table>
<style>
.core-column .color.swatch::before {
counter-reset: key var(--wa-color-brand-key);
content: counter(key);
}
</style>

View File

@@ -1,100 +0,0 @@
---
title: Default Layout and Spacing
description: TODO
layout: blank
---
<style>
[slot='banner'] {
background-color: pink;
}
[slot='header'] {
background-color: peachpuff;
}
[slot='subheader'] {
background-color: papayawhip;
}
[slot='navigation-header'] {
background-color: lemonchiffon;
}
[slot='navigation'] {
background-color: honeydew;
}
[slot='navigation-footer'] {
background-color: paleturquoise;
}
[slot='main-header'] {
background-color: lavenderblush;
}
main {
background-color: lavender;
height: 100%;
}
[slot='main-footer'] {
background-color: thistle;
}
[slot='aside'] {
background-color: lightcyan;
height: 100%;
}
[slot='footer'] {
background-color: lightsteelblue;
}
</style>
<wa-page>
<section slot="banner">
<strong>Banner</strong>
<span>Banner</span>
<span>Banner</span>
</section>
<header slot="header">
<strong>Header</strong>
<span>Header</span>
<span>Header</span>
</header>
<nav slot="subheader">
<strong>Subheader</strong>
<span>Subheader</span>
<span>Subheader</span>
</nav>
<nav slot="navigation-header">
<strong>Nav Header</strong>
<span>Nav Header</span>
<span>Nav Header</span>
</nav>
<nav slot="navigation">
<strong>Navigation</strong>
<span>Navigation</span>
<span>Navigation</span>
</nav>
<nav slot="navigation-footer">
<strong>Nav Footer</strong>
<span>Nav Footer</span>
<span>Nav Footer</span>
</nav>
<div slot="main-header">
<strong>Main Header</strong>
<span>Main Header</span>
<span>Main Header</span>
</div>
<main>
<h1>Main</h1>
<p>No flex properties here! The author can specify their own preferred content flow and layout in the default slot.</p>
</main>
<div slot="main-footer">
<strong>Main Footer</strong>
<span>Main Footer</span>
<span>Main Footer</span>
</div>
<aside slot="aside">
<strong>Aside</strong>
<span>Aside</span>
<span>Aside</span>
</aside>
<footer slot="footer">
<strong>Footer</strong>
<span>Footer</span>
<span>Footer</span>
</footer>
</wa-page>

View File

@@ -1,50 +0,0 @@
---
title: Form Control Validation
description: TODO
layout: page
---
Adding the `wa-valid` or `wa-invalid` class to a form control will change its appearance. This is useful for applying validation styles to server-rendered form controls.
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem;">
<div>
<h3>Valid</h3>
<wa-input class="wa-valid" label="Name" hint="Just a first name is fine" placeholder="Enter your name"></wa-input><br>
<wa-select class="wa-valid" label="Choose one" hint="Make a choice already">
<wa-option>There can be only one!</wa-option>
<wa-option>Well, maybe two is OK</wa-option>
</wa-select>
<wa-textarea class="wa-valid" label="Bio" hint="Tell us about yourself" placeholder="Enter a bio"></wa-textarea><br>
<wa-slider class="wa-valid" value="50" label="Volume" hint="Crank it up"></wa-slider><br>
<wa-checkbox class="wa-valid" checked>I am awesome</wa-checkbox><br>
<wa-checkbox class="wa-valid">So am I</wa-checkbox><br><br>
<wa-switch class="wa-valid" checked>Still awesome</wa-switch><br>
<wa-switch class="wa-valid">More awesome</wa-switch><br><br>
<wa-radio-group class="wa-valid" label="Select an option" name="a" value="1">
<wa-radio value="1">Option 1</wa-radio>
<wa-radio value="2">Option 2</wa-radio>
<wa-radio value="3">Option 3</wa-radio>
</wa-radio-group><br>
<wa-button variant="brand">Submit Form</wa-button>
</div>
<div>
<h3>Invalid</h3>
<wa-input class="wa-invalid" label="Name" hint="Just a first name is fine" placeholder="Enter your name"></wa-input><br>
<wa-select class="wa-invalid" label="Choose one" hint="Make a choice already">
<wa-option>There can be only one!</wa-option>
<wa-option>Well, maybe two is OK</wa-option>
</wa-select>
<wa-textarea class="wa-invalid" label="Bio" hint="Tell us about yourself" placeholder="Enter a bio"></wa-textarea><br>
<wa-slider class="wa-invalid" value="50" label="Volume" hint="Crank it up"></wa-slider><br>
<wa-checkbox class="wa-invalid" checked>I am awesome</wa-checkbox><br>
<wa-checkbox class="wa-invalid">So am I</wa-checkbox><br><br>
<wa-switch class="wa-invalid" checked>Still awesome</wa-switch><br>
<wa-switch class="wa-invalid">More awesome</wa-switch><br><br>
<wa-radio-group class="wa-invalid" label="Select an option" name="a" value="1">
<wa-radio value="1">Option 1</wa-radio>
<wa-radio value="2">Option 2</wa-radio>
<wa-radio value="3">Option 3</wa-radio>
</wa-radio-group><br>
<wa-button variant="brand">Submit Form</wa-button>
</div>
</div>

View File

@@ -1,84 +0,0 @@
---
title: Inheritance & Default value tests
wide: true
---
## Variant
{%- set variantDefaults = {
button: 'neutral',
tag: 'neutral',
badge: 'brand',
callout: 'brand'
} %}
{%- set variants = ['', 'neutral', 'brand'] %}
### Defaults
```html {.example}
<table>
<thead>
<tr>
<th>Element</th>
<th>Default</th>
<th>Neutral</th>
<th>Brand</th>
</tr>
</thead>
{% for element, default in variantDefaults %}
<tr>
<th>{{ element | capitalize }}</th>
<td><wa-{{ element }}>{{ default | capitalize }}</wa-{{ element }}></td>
<td><wa-{{ element }} variant="neutral">Neutral</wa-{{ element }}></td>
<td><wa-{{ element }} variant="brand">Brand</wa-{{ element }}></td>
</tr>
{% endfor %}
</table>
```
### Nested elements
{% set containers = [
{parent: 'callout', child: 'button'},
{parent: 'callout', child: 'callout'},
{parent: 'button', child: 'badge'}
] %}
{% for container in containers %}
{% set parent = container.parent %}
{% set child = container.child %}
#### {{ child | capitalize }} in {{ parent | capitalize }}
```html {.example}
<table>
<thead>
<tr>
{% if parent == child -%}
<th>👇 Parent / Child 👉</th>
{% else %}
<th>👇 {{ parent | capitalize }} / {{ child | capitalize }} 👉</th>
{%- endif %}
<th>Default</th>
<th>Neutral</th>
<th>Brand</th>
</tr>
</thead>
{% for parentVariant in variants %}
{% set parentContent = (parentVariant | capitalize or 'Default') if parent == 'button' %}
<tr>
<th>{{ parentVariant | capitalize or 'Default' }}</th>
{% for childVariant in variants -%}
{% set childContent = (childVariant or parentVariant or variantDefaults[child]) | capitalize %}
{% set childContent = childContent[0] if child == 'badge' else childContent %}
<td><wa-{{ parent }}{{ parentVariant | attr('variant') }}>
{{ parentContent }}
<wa-{{ child }}{{ childVariant | attr('variant') }}>{{ childContent }}</wa-{{ child }}>
</wa-{{ parent }}></td>
{% endfor %}
</tr>
{% endfor %}
</table>
```
{% endfor %}

View File

@@ -1,75 +0,0 @@
---
title: Size tests
---
Button size should default to `medium`:
```html {.example}
<wa-button size=small>Small</wa-button>
<wa-button>Medium</wa-button>
<wa-button size=medium>Medium</wa-button>
<wa-button size=large>Large</wa-button>
```
If no button size is specified, it should default to that of its ancestor:
```html {.example}
<wa-button-group size="small">
<wa-button>Small 1</wa-button>
<wa-button>Small 2</wa-button>
<wa-button>Small 3</wa-button>
</wa-button-group>
<br><br>
<wa-button-group>
<wa-button>Medium 1</wa-button>
<wa-button>Medium 2</wa-button>
<wa-button>Medium 3</wa-button>
</wa-button-group>
<br><br>
<wa-button-group size="large">
<wa-button>Large 1</wa-button>
<wa-button>Large 2</wa-button>
<wa-button>Large 3</wa-button>
</wa-button-group>
```
Dropdown:
```html {.example}
<p>Small dropdown:
<wa-dropdown size="small">
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
<wa-menu-item>Dropdown Item 1</wa-menu-item>
<wa-menu-item>Dropdown Item 2</wa-menu-item>
<wa-menu-item>Dropdown Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
<p>Small menu:
<wa-dropdown>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu size="small">
<wa-menu-item>Dropdown Item 1</wa-menu-item>
<wa-menu-item>Dropdown Item 2</wa-menu-item>
<wa-menu-item>Dropdown Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
<p>Small menu item:
<wa-dropdown>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
<wa-menu-item size="small">Dropdown Item 1</wa-menu-item>
<wa-menu-item size="small">Dropdown Item 2</wa-menu-item>
<wa-menu-item size="small">Dropdown Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
<p>No size:
<wa-dropdown>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
<wa-menu-item>Dropdown Item 1</wa-menu-item>
<wa-menu-item>Dropdown Item 2</wa-menu-item>
<wa-menu-item>Dropdown Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
```

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +0,0 @@
---
title: Installation
description: Choose the installation method that works best for you.
layout: page-outline
---
Welcome to the Web Awesome alpha release for early backers! 👋
==This is a very early alpha release!== For this preview, we're offering access to Web Awesome through a temporary CDN. Please be aware: Things can change. Things can break. You probably shouldn't be using this software in production yet! But fear not, we're working hard to polish up everything you see here _plus_ all the great stuff we have planned for Web Awesome Pro!
Thank you so much for backing us!
- [Report a bug](https://github.com/shoelace-style/webawesome-alpha/issues)
- [Get help / ask a question](https://github.com/shoelace-style/webawesome-alpha/discussions)
- [See what's new since the last version](/docs/resources/changelog)
:::warning
As a Web Awesome backer, this early alpha release is _just for you_. Please refrain from sharing it for the time being!
:::
---
## Quick Start (Autoloading via CDN)
To get everything included in Web Awesome, add the following code to the `<head>` of your site:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/themes/default.css' %}" />
<link rel="stylesheet" href="{% cdnUrl 'styles/webawesome.css' %}" />
<script type="module" src="{% cdnUrl 'webawesome.loader.js' %}"></script>
```
This snippet includes three parts:
1. **The default theme**, a stylesheet that gives a cohesive look to Web Awesome components with both light and dark modes
2. **Web Awesome styles**, an optional stylesheet that [styles native HTML elements](/docs/native) and includes [utility classes](/docs/utilities) you can use in your project
3. **The autoloader**, a lightweight script watches the DOM for unregistered Web Awesome elements and lazy loads them for you — even if they're added dynamically
Now you can [start using Web Awesome!](/docs/usage)
:::info
While convenient, autoloading may lead to a [Flash of Undefined Custom Elements](https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/). The linked article describes some ways to alleviate it.
:::
---
## Using Font Awesome Kit Codes
Font Awesome users can set their kit code to unlock Font Awesome Pro icons. You can provide it by adding the `data-fa-kit-code` attribute to any element on the page, or by calling the `setKitCode()` method.
```html
<!-- Option 1: the data-fa-kit-code attribute -->
<script src="bundle.js" data-fa-kit-code="abc123"></script>
<!-- Option 2: the setKitCode() method -->
<script type="module">
import { setKitCode } from '{% cdnUrl 'webawesome.loader.js' %}';
setKitCode('YOUR_KIT_CODE_HERE');
</script>
```
---
## Advanced Setup
The autoloader is the easiest way to use Web Awesome, but different projects (or your own preferences!) may require different installation methods.
### Installing via npm
An npm package isn't available in the early backer alpha release, but we'll have one soon! For now, please enjoy [Web Awesome from the CDN](#quick-start-autoloading-via-cdn).
### Cherry Picking
Cherry picking will only load the components you need up front, while limiting the number of files the browser has to download. The disadvantage is that you need to import each individual component on each page it's used. You'll still need to include the default theme (`styles/themes/default.css`) or another theme to style any imported components.
Here's an example that loads only the button component.
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/themes/default.css' %}" />
<script type="module">
import '{% cdnUrl 'components/button/button.js' %}';
// <wa-button> is ready to use!
</script>
```
You can copy and paste the code to import a component from the "Importing" section of the component's documentation. Note that some components have dependencies that are automatically imported when you cherry pick. If a component has dependencies, they will be listed in the "Dependencies" section of its docs.
:::warning
You will see files named `chunk.[hash].js` in the `chunks` directory. Never import these files directly, as they are generated and change from version to version.
:::
### Setting the Base Path
Some components rely on assets (icons, images, etc.) and Web Awesome needs to know where they're located. For convenience, Web Awesome will try to auto-detect the correct location based on the script you've loaded it from. This assumes assets are colocated with `webawesome.loader.js` and will "just work" for most users.
==If you're using the CDN, you can skip this section.== However, if you're [cherry picking](#cherry-picking) or bundling Web Awesome, you'll need to set the base path. You can do this one of two ways.
```html
<!-- Option 1: the data-webawesome attribute -->
<script src="bundle.js" data-webawesome="/path/to/web-awesome/dist"></script>
<!-- Option 2: the setBasePath() method -->
<script type="module">
import { setBasePath } from '/path/to/web-awesome/dist/webawesome.js';
setBasePath('/path/to/web-awesome/dist');
</script>
```
### Referencing Assets
Most of the magic behind assets is handled internally by Web Awesome, but if you need to reference the base path for any reason, the same module exports a function called `getBasePath()`. An optional string argument can be passed, allowing you to get the full path to any asset.
```html
<script type="module">
import { getBasePath, setBasePath } from '/path/to/web-awesome/dist/webawesome.js';
setBasePath('/path/to/assets');
// ...
// Get the base path, e.g. /path/to/assets
const basePath = getBasePath();
// Get the path to an asset, e.g. /path/to/assets/file.ext
const assetPath = getBasePath('file.ext');
</script>
```

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