mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-13 12:39:14 +00:00
Compare commits
443 Commits
styling-at
...
select-eve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c4974e95 | ||
|
|
7ccfed9e93 | ||
|
|
4f1de3918b | ||
|
|
adaea2fa5f | ||
|
|
e016e4bd48 | ||
|
|
5e0b5f3fe6 | ||
|
|
493e1c06b9 | ||
|
|
8b763d0392 | ||
|
|
9d82749abb | ||
|
|
d1acd6ad68 | ||
|
|
1fa25dc4f0 | ||
|
|
fe31121c15 | ||
|
|
3e3e5276a6 | ||
|
|
a0a47b1bdf | ||
|
|
fa51cff947 | ||
|
|
fd08d4f227 | ||
|
|
7008c0cef7 | ||
|
|
e9ce8659f6 | ||
|
|
325d6f211b | ||
|
|
bd1570ec76 | ||
|
|
406f3a0e81 | ||
|
|
08babbce6d | ||
|
|
293b86705a | ||
|
|
fe5ab48c06 | ||
|
|
35e9dfe88d | ||
|
|
44567ec967 | ||
|
|
bfdd0bd6d0 | ||
|
|
f3f5d40b7b | ||
|
|
3d75d6b59c | ||
|
|
f30801ab66 | ||
|
|
f92ef1f74e | ||
|
|
da27a8dc74 | ||
|
|
437e0d9aec | ||
|
|
583d9c0616 | ||
|
|
cb29033eaf | ||
|
|
c02ac306af | ||
|
|
56d678b504 | ||
|
|
b1864eb93d | ||
|
|
d2b5613e85 | ||
|
|
f7ca634822 | ||
|
|
35d33c89b9 | ||
|
|
094bd478ff | ||
|
|
0b619a99f1 | ||
|
|
89cf48c865 | ||
|
|
b7a6ebd228 | ||
|
|
6c8bbd51d1 | ||
|
|
6085b9698c | ||
|
|
17ee36175b | ||
|
|
3c7bb71a59 | ||
|
|
d66b552962 | ||
|
|
6f6e23c78c | ||
|
|
310f7a8c5d | ||
|
|
9a7b258108 | ||
|
|
e10aba0ed1 | ||
|
|
1ea5dae9ad | ||
|
|
21310bd367 | ||
|
|
c1478e5865 | ||
|
|
9b8433c996 | ||
|
|
57dac67aab | ||
|
|
441bfd7b72 | ||
|
|
7150c59334 | ||
|
|
bd2a3c3b64 | ||
|
|
11519625ed | ||
|
|
f19848c11e | ||
|
|
36b21b0be7 | ||
|
|
fe2c2ab7af | ||
|
|
b98b9baba4 | ||
|
|
7b18be876b | ||
|
|
c9e6895ef7 | ||
|
|
64c8647dee | ||
|
|
9e9a00547a | ||
|
|
f747483e32 | ||
|
|
8719bbc88b | ||
|
|
0ff5e7fb7a | ||
|
|
2a52b2766f | ||
|
|
1e8bbc3b06 | ||
|
|
1ef9cb9601 | ||
|
|
5b54410212 | ||
|
|
f621fbb224 | ||
|
|
f5624fbf4a | ||
|
|
f65bc3918e | ||
|
|
f49c10b05b | ||
|
|
3b6c018fed | ||
|
|
c10e1e77c9 | ||
|
|
a1e879035c | ||
|
|
d2625fccab | ||
|
|
29c8ad08bb | ||
|
|
0f68e6f0dd | ||
|
|
4dca2b9541 | ||
|
|
36ccaa4aaa | ||
|
|
c86d7635aa | ||
|
|
d84e842a4e | ||
|
|
fb8c06235f | ||
|
|
f6a10e9dda | ||
|
|
5ce34677ed | ||
|
|
8ebc839dfd | ||
|
|
2779eb1753 | ||
|
|
341ca809e9 | ||
|
|
7232ddee5d | ||
|
|
f63001f18e | ||
|
|
8b831f6ece | ||
|
|
4dee3d0f2d | ||
|
|
10a78d99af | ||
|
|
99d9024339 | ||
|
|
313e31a3f2 | ||
|
|
4eeabc57e5 | ||
|
|
c8c0d0f848 | ||
|
|
e8687b895d | ||
|
|
7743b670ed | ||
|
|
88e99d7cd3 | ||
|
|
c0d18ab9f0 | ||
|
|
6576f67cfa | ||
|
|
057ff5fb31 | ||
|
|
1dac76a35e | ||
|
|
e7f2962984 | ||
|
|
956dc9bdd9 | ||
|
|
62020be8c1 | ||
|
|
429cf68301 | ||
|
|
dd77663a75 | ||
|
|
fa9f18f002 | ||
|
|
c2e2e1afcc | ||
|
|
2628f4ff7c | ||
|
|
16722a191d | ||
|
|
21243729c6 | ||
|
|
1581b99796 | ||
|
|
103cbc439e | ||
|
|
3a40ffe58a | ||
|
|
453e8ff501 | ||
|
|
dc556e5379 | ||
|
|
c11d6129a3 | ||
|
|
dd5c32680a | ||
|
|
81996cbc63 | ||
|
|
d20945d78b | ||
|
|
07327be95e | ||
|
|
b99d7771dc | ||
|
|
10cc9bdc68 | ||
|
|
bc598dad92 | ||
|
|
ff61ac002f | ||
|
|
63ec9d5bc1 | ||
|
|
555327b2fc | ||
|
|
15c6eaec90 | ||
|
|
6f856fbd89 | ||
|
|
df46e1db3b | ||
|
|
d21d829c29 | ||
|
|
2331e88dcf | ||
|
|
c162983ca2 | ||
|
|
0d09037916 | ||
|
|
d2e32a0a53 | ||
|
|
71d45eabbd | ||
|
|
eac60a9022 | ||
|
|
f8dca5d1a8 | ||
|
|
5980b5f843 | ||
|
|
9a3ffb04ba | ||
|
|
04d37224e0 | ||
|
|
f4a63f9e22 | ||
|
|
3ab342ebb6 | ||
|
|
48fe9389c8 | ||
|
|
6b2a081fa0 | ||
|
|
afb2082c79 | ||
|
|
7bdc9a2cc4 | ||
|
|
dead18d23c | ||
|
|
2b37c54d7c | ||
|
|
35b61e5cf3 | ||
|
|
cc33805d27 | ||
|
|
6e548dd85b | ||
|
|
212ca5b0a6 | ||
|
|
b96c3f318b | ||
|
|
b0aba7ce07 | ||
|
|
e39bb856c4 | ||
|
|
23dc884678 | ||
|
|
4e14f25831 | ||
|
|
b15502a01e | ||
|
|
73f6eeacbd | ||
|
|
5921f3eeaa | ||
|
|
35338ef643 | ||
|
|
5c950a7874 | ||
|
|
a7ea989170 | ||
|
|
7253ed8ab0 | ||
|
|
37e82b70fa | ||
|
|
39d1b82634 | ||
|
|
1259a9b78d | ||
|
|
59077e75d2 | ||
|
|
62ddf13a6a | ||
|
|
684bb25244 | ||
|
|
1f2ebf5e7a | ||
|
|
2182d3c692 | ||
|
|
074c7a16d6 | ||
|
|
4130246833 | ||
|
|
bbda731f56 | ||
|
|
6492ee7728 | ||
|
|
73e1c04b37 | ||
|
|
49bb6af154 | ||
|
|
9b8d73a2ea | ||
|
|
0b4c1a5934 | ||
|
|
8b17b3d3e0 | ||
|
|
f5d1b74e00 | ||
|
|
40ea444c48 | ||
|
|
403927687e | ||
|
|
6af4e849af | ||
|
|
2c839a4225 | ||
|
|
3703ef26da | ||
|
|
3640b4c6e1 | ||
|
|
27fc269a94 | ||
|
|
a5b2fffb7a | ||
|
|
7de6a676b8 | ||
|
|
3c77d400f8 | ||
|
|
6ee10f44f4 | ||
|
|
6afc6e928c | ||
|
|
f8fcbd60ec | ||
|
|
bdd25571a8 | ||
|
|
38c13640fc | ||
|
|
00a3b1aa8d | ||
|
|
22298781c5 | ||
|
|
fe27710f57 | ||
|
|
d94589d113 | ||
|
|
3508bf6339 | ||
|
|
61e65ffcb9 | ||
|
|
aed28adbe4 | ||
|
|
15b8bde81b | ||
|
|
9ee3fb5d28 | ||
|
|
47aa376c08 | ||
|
|
69ba974a50 | ||
|
|
8dfb411e5e | ||
|
|
a35a8fd2ad | ||
|
|
2503005bbd | ||
|
|
78027170ea | ||
|
|
a20aa48992 | ||
|
|
ac8accd664 | ||
|
|
c571573063 | ||
|
|
e813440315 | ||
|
|
cfc3f181a3 | ||
|
|
7545f04c46 | ||
|
|
38bd6528fe | ||
|
|
2202ea9642 | ||
|
|
58fbcede51 | ||
|
|
971200cc88 | ||
|
|
b75d3b615c | ||
|
|
9d1c47449e | ||
|
|
003fd28cb0 | ||
|
|
2f300d8930 | ||
|
|
f13deb87bb | ||
|
|
deb9fd70b3 | ||
|
|
ff3b3d6558 | ||
|
|
6b3edb8a56 | ||
|
|
6162b8b115 | ||
|
|
cff752b600 | ||
|
|
7892a94b9b | ||
|
|
40a58ff35f | ||
|
|
0f2950c4cc | ||
|
|
b334884f57 | ||
|
|
734417d66b | ||
|
|
2cfd651d2f | ||
|
|
3e2d1b98be | ||
|
|
40f332f37c | ||
|
|
bfda64f690 | ||
|
|
883d6df2ef | ||
|
|
b4240fd321 | ||
|
|
8755a834f6 | ||
|
|
8d905296b8 | ||
|
|
8eba1e5003 | ||
|
|
21aa85acc0 | ||
|
|
404c15b303 | ||
|
|
8a26afc334 | ||
|
|
513a1e35a9 | ||
|
|
09f668fc99 | ||
|
|
d451ba98e5 | ||
|
|
fd287edd56 | ||
|
|
8424b49646 | ||
|
|
fa24c0f70e | ||
|
|
1bba87c66d | ||
|
|
0db9ca12e3 | ||
|
|
041555fe99 | ||
|
|
b41dbd2de7 | ||
|
|
7c6f31e0c7 | ||
|
|
9e84274a93 | ||
|
|
2b3803f91e | ||
|
|
faed8da3cd | ||
|
|
17cf902f53 | ||
|
|
8214ff6b2d | ||
|
|
c9979e15f8 | ||
|
|
fcfe2bde7d | ||
|
|
59dcaaff83 | ||
|
|
5bad30ec30 | ||
|
|
87c1762146 | ||
|
|
899edd1d5e | ||
|
|
872a110b1e | ||
|
|
07fe6d598e | ||
|
|
79bafc513a | ||
|
|
1d03f7bee0 | ||
|
|
a9bf1bd838 | ||
|
|
c0ca739366 | ||
|
|
a6745602d6 | ||
|
|
da4f619d95 | ||
|
|
1283a696a5 | ||
|
|
d12b97b0b0 | ||
|
|
e5c2884880 | ||
|
|
1d600a77c4 | ||
|
|
db3c568ba2 | ||
|
|
4bb9805ba6 | ||
|
|
bd935fa8d5 | ||
|
|
c3e582b47b | ||
|
|
4d094a4e19 | ||
|
|
782c404bdf | ||
|
|
f1438981b2 | ||
|
|
18b88c2f5c | ||
|
|
a2d85f49a3 | ||
|
|
be00026cd3 | ||
|
|
58ed88bc5a | ||
|
|
1d14e186f3 | ||
|
|
5f672aabc2 | ||
|
|
db08e12a32 | ||
|
|
e0fc639226 | ||
|
|
e6c662b543 | ||
|
|
d1de9a9a73 | ||
|
|
4931de8eb4 | ||
|
|
71e7227763 | ||
|
|
dd671e15aa | ||
|
|
2daeea0349 | ||
|
|
3cb6625c1d | ||
|
|
c4b5446d01 | ||
|
|
41affca083 | ||
|
|
132dbfabcc | ||
|
|
4fc6224464 | ||
|
|
4921d1c32e | ||
|
|
54d71d2319 | ||
|
|
c1ecca0169 | ||
|
|
d6a91919e0 | ||
|
|
4621094ea1 | ||
|
|
726dc73e2a | ||
|
|
4bfebf3249 | ||
|
|
99ad0abdd3 | ||
|
|
902e2b6367 | ||
|
|
7f3210b12d | ||
|
|
eee63bdecd | ||
|
|
a91fd07ed7 | ||
|
|
34aa8917a6 | ||
|
|
715c2c0def | ||
|
|
13b5385633 | ||
|
|
d25f3748c4 | ||
|
|
b6620ddf7e | ||
|
|
d70d4a91b1 | ||
|
|
bb1f7b2b7a | ||
|
|
9921c17d63 | ||
|
|
7f964f9b56 | ||
|
|
31eeea1630 | ||
|
|
ffda52a7cf | ||
|
|
9be7919c60 | ||
|
|
c30f3c4b09 | ||
|
|
7e8f13b5cb | ||
|
|
97ab986425 | ||
|
|
f1fa7f713e | ||
|
|
3394a95057 | ||
|
|
eed9ddb9b3 | ||
|
|
daf5e7734d | ||
|
|
63133d0e33 | ||
|
|
b2d74145b8 | ||
|
|
17eeccbc5d | ||
|
|
68f645e776 | ||
|
|
b3e4c59197 | ||
|
|
6080a85035 | ||
|
|
f7e088c8df | ||
|
|
80e1c05b37 | ||
|
|
99f0273783 | ||
|
|
8e13683a30 | ||
|
|
fd73542d2c | ||
|
|
bde0ed7403 | ||
|
|
8dc49f7119 | ||
|
|
25cb96aa30 | ||
|
|
360273ac27 | ||
|
|
404d59d9d6 | ||
|
|
ce1ce6caca | ||
|
|
74ecc52a15 | ||
|
|
a64cc60ad5 | ||
|
|
c5f91ec2f7 | ||
|
|
4f9af1e871 | ||
|
|
aeb25f3a7d | ||
|
|
b89ee673e6 | ||
|
|
3c70c44b8a | ||
|
|
d8881c0b1e | ||
|
|
88b6fe2fbe | ||
|
|
6a0725cf00 | ||
|
|
3ff8745910 | ||
|
|
0cb72adb28 | ||
|
|
3d35f5d4e0 | ||
|
|
815cc4220b | ||
|
|
a7caf19b34 | ||
|
|
71c054d6e4 | ||
|
|
e1bf5471bf | ||
|
|
099edc5186 | ||
|
|
e3560dcf98 | ||
|
|
f2bb2c84a0 | ||
|
|
13b3342017 | ||
|
|
d1c1d689ce | ||
|
|
44e5e37a2b | ||
|
|
566aae927d | ||
|
|
7258c001a7 | ||
|
|
7a70940c6a | ||
|
|
45f4edc426 | ||
|
|
da32015f27 | ||
|
|
03d8238edb | ||
|
|
34f8744493 | ||
|
|
fa3fe5f753 | ||
|
|
fc6c7de1fd | ||
|
|
0037712549 | ||
|
|
5301945bfa | ||
|
|
1298651dd8 | ||
|
|
5f9695fde1 | ||
|
|
2eb2597efe | ||
|
|
431e82261b | ||
|
|
df51149d0a | ||
|
|
fba0b11343 | ||
|
|
3618e93490 | ||
|
|
cfa95307d1 | ||
|
|
15344c2a2a | ||
|
|
3974aa5130 | ||
|
|
a6702ad6d2 | ||
|
|
ecf21adddc | ||
|
|
52c24fc3b7 | ||
|
|
d464714d7b | ||
|
|
7d089bbe2f | ||
|
|
71914afc91 | ||
|
|
9d139e3fa0 | ||
|
|
db3039e9fe | ||
|
|
9494b9bb67 | ||
|
|
7e1f4f0351 | ||
|
|
5ebe4f4d3e | ||
|
|
dfb9d53a25 | ||
|
|
c2c1a2ff5b | ||
|
|
ac86c037a1 | ||
|
|
6b07c9a040 | ||
|
|
24a76f6a7c | ||
|
|
89c0667e9c | ||
|
|
434084ea4e | ||
|
|
1738c6345b | ||
|
|
0ac7916a1b | ||
|
|
e7979991e3 | ||
|
|
07f70098f8 | ||
|
|
17146698db | ||
|
|
bf852b1296 | ||
|
|
e367c0ef29 | ||
|
|
01210ef364 | ||
|
|
40648e15fb | ||
|
|
ab67ecfad3 |
@@ -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
|
||||
@@ -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
10
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -1,15 +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
|
||||
|
||||
packages/**/*/_site
|
||||
packages/webawesome/docs/assets/scripts/prism-downloaded.js
|
||||
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -3,6 +3,7 @@
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"bierner.lit-html",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"ronnidc.nunjucks"
|
||||
]
|
||||
}
|
||||
|
||||
39
README.md
39
README.md
@@ -31,6 +31,30 @@ If that's not what you're trying to do, the [documentation website](https://weba
|
||||
|
||||
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/).
|
||||
|
||||
### 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 a 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 (IE: `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 do install a package specific to a package, change your working directory to that package's root
|
||||
|
||||
IE: `cd packages/webawesome && npm install <package-name>`
|
||||
|
||||
### Forking the Repo
|
||||
|
||||
Start by [forking the repo](https://github.com/shoelace-style/webawesome/fork) on GitHub, then clone it locally and install dependencies.
|
||||
@@ -43,9 +67,10 @@ 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
|
||||
```
|
||||
|
||||
@@ -56,6 +81,7 @@ This will spin up the dev server. After the initial build, a browser will open a
|
||||
To generate a production build, run the following command.
|
||||
|
||||
```bash
|
||||
cd packages/webawesome
|
||||
npm run build
|
||||
```
|
||||
|
||||
@@ -66,15 +92,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.
|
||||
27
cspell.json
27
cspell.json
@@ -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,11 +81,13 @@
|
||||
"formtarget",
|
||||
"FOUC",
|
||||
"FOUCE",
|
||||
"Frontmatter",
|
||||
"fullscreen",
|
||||
"gestern",
|
||||
"giga",
|
||||
"globby",
|
||||
"Grayscale",
|
||||
"groupby",
|
||||
"haspopup",
|
||||
"heroicons",
|
||||
"hexa",
|
||||
@@ -82,6 +98,7 @@
|
||||
"inputmode",
|
||||
"ionicon",
|
||||
"ionicons",
|
||||
"jank",
|
||||
"jsDelivr",
|
||||
"jsfiddle",
|
||||
"keydown",
|
||||
@@ -117,8 +134,12 @@
|
||||
"noindex",
|
||||
"noopener",
|
||||
"noreferrer",
|
||||
"noscript",
|
||||
"Notdog",
|
||||
"novalidate",
|
||||
"nowrap",
|
||||
"Numberish",
|
||||
"nums",
|
||||
"oklab",
|
||||
"oklch",
|
||||
"onscrollend",
|
||||
@@ -128,10 +149,12 @@
|
||||
"petabit",
|
||||
"Preact",
|
||||
"preconnect",
|
||||
"prerendered",
|
||||
"prismjs",
|
||||
"progressbar",
|
||||
"radiogroup",
|
||||
"Railsbyte",
|
||||
"referrerpolicy",
|
||||
"remixicon",
|
||||
"reregister",
|
||||
"resizer",
|
||||
@@ -148,7 +171,9 @@
|
||||
"scrollbars",
|
||||
"scrollend",
|
||||
"scroller",
|
||||
"Scrollers",
|
||||
"Segoe",
|
||||
"selectattr",
|
||||
"semibold",
|
||||
"shadowrootmode",
|
||||
"Shortcode",
|
||||
@@ -157,6 +182,7 @@
|
||||
"slotchange",
|
||||
"smartquotes",
|
||||
"spacebar",
|
||||
"srcdoc",
|
||||
"stylesheet",
|
||||
"svgs",
|
||||
"Tabbable",
|
||||
@@ -181,6 +207,7 @@
|
||||
"typeof",
|
||||
"unbundles",
|
||||
"unbundling",
|
||||
"Uncategorized",
|
||||
"unicons",
|
||||
"unsanitized",
|
||||
"unsupportive",
|
||||
|
||||
@@ -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'],
|
||||
};
|
||||
}
|
||||
@@ -1,87 +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';
|
||||
});
|
||||
|
||||
let ret = {
|
||||
...declaration,
|
||||
slug: declaration.tagName.replace(/^wa-/, ''),
|
||||
methods,
|
||||
attributes,
|
||||
properties,
|
||||
};
|
||||
|
||||
// Add named keys to these arrays
|
||||
for (let thing of ['methods', 'attributes', 'properties', 'cssProperties', 'cssParts', 'cssStates', 'events']) {
|
||||
if (ret[thing]) {
|
||||
ret[thing] = ret[thing].reduce((acc, item) => {
|
||||
acc[item.name] = item;
|
||||
return acc;
|
||||
}, ret[thing]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
});
|
||||
|
||||
// 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;
|
||||
@@ -1,3 +0,0 @@
|
||||
import componentList from './componentList.js';
|
||||
|
||||
export default Object.fromEntries(componentList.map(component => [component.slug, component]));
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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/copy-code.js"></script>
|
||||
|
||||
<script type="module" src="/assets/scripts/scroll.js"></script>
|
||||
<script type="module" src="/assets/scripts/turbo.js"></script>
|
||||
<script type="module" src="/assets/scripts/search.js"></script>
|
||||
<script type="module" src="/assets/scripts/outline.js"></script>
|
||||
<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" />
|
||||
</head>
|
||||
<body class="layout-{{ layout | stripExtension }}">
|
||||
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
|
||||
<wa-page view="desktop" disable-navigation-toggle="">
|
||||
<header slot="header" 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>
|
||||
@@ -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 %}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,53 +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 #}
|
||||
<link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/{{ forceTheme or 'default' }}.css" render="blocking" fetchpriority="high" />
|
||||
{% if not forceTheme %}
|
||||
<script>
|
||||
if (localStorage.presetTheme) {
|
||||
let preset = localStorage.presetTheme;
|
||||
let script = document.currentScript;
|
||||
let link = script.previousElementSibling;
|
||||
let newLink = link.cloneNode();
|
||||
newLink.href = link.href.replace("/default.css", `/${preset}.css`);
|
||||
newLink.addEventListener('load', () => {
|
||||
link.remove();
|
||||
});
|
||||
link.after(newLink);
|
||||
}
|
||||
</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" />
|
||||
@@ -1,10 +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>
|
||||
</wa-card>
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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] -%}
|
||||
<wa-details {{ (tag in (tags or [])) | attr('open') }}>
|
||||
<h2 slot="summary">
|
||||
{% set groupUrl %}/docs/{{ tag }}/{% endset %}
|
||||
{% 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 %}
|
||||
@@ -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 %}
|
||||
@@ -1,31 +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 & Support</a></li>
|
||||
<li><a href="/docs/resources/community">Community</a></li>
|
||||
<li><a href="/docs/resources/accessibility">Accessibility</a></li>
|
||||
<li><a href="/docs/resources/contributing">Contributing</a></li>
|
||||
<li><a href="/docs/resources/changelog">Changelog</a></li>
|
||||
</ul>
|
||||
|
||||
{% for tag, title in {
|
||||
'themes': 'Themes',
|
||||
'components': 'Components',
|
||||
'native': 'Native Styles',
|
||||
'utilities': 'Style Utilities',
|
||||
'layout': 'Layout',
|
||||
'patterns': 'Patterns',
|
||||
'theming': 'Theming'
|
||||
} %}
|
||||
{% include 'sidebar-group.njk' %}
|
||||
{% endfor %}
|
||||
@@ -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 -%}
|
||||
@@ -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 |
@@ -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-teal-60); --text-color: var(--wa-color-teal-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;">“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.”</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">•</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>
|
||||
@@ -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>
|
||||
@@ -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 %}
|
||||
@@ -1,24 +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><wa-{{ name }}></code></a>{{ ', ' if not loop.last }}
|
||||
{%- endfor %} component{{ 's' if (component | isList) }}</a>!
|
||||
</wa-callout>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block afterContent %}
|
||||
{# Slots #}
|
||||
{% if css_file %}
|
||||
<h2>Using these styles</h2>
|
||||
<p>If you want to use these styles without using the entirety of Web Awesome Native Styles, you can include the following CSS files:</p>
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -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 %}
|
||||
<br> {# Temp fix for spacing issue #}
|
||||
{{ content | safe }}
|
||||
{% endif %}
|
||||
@@ -1,4 +0,0 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = false %}
|
||||
|
||||
{% extends "../_includes/base.njk" %}
|
||||
@@ -1,85 +0,0 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = true %}
|
||||
{# {% set forceTheme = page.fileSlug %} #}
|
||||
|
||||
{% extends '../_includes/base.njk' %}
|
||||
|
||||
{% block header %}
|
||||
<iframe src='{{ page.url }}demo.html'></iframe>
|
||||
{% endblock %}
|
||||
|
||||
{% block afterContent %}
|
||||
{% markdown %}
|
||||
## How to use this theme
|
||||
|
||||
You can import this theme from the Web Awesome CDN.
|
||||
|
||||
<wa-tab-group>
|
||||
<wa-tab panel="html">In HTML</wa-tab>
|
||||
<wa-tab panel="css">In CSS</wa-tab>
|
||||
<wa-tab-panel name="html">
|
||||
|
||||
Simply add the following code to the `<head>` of your page:
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/themes/' + page.fileSlug + '.css' %}" />
|
||||
```
|
||||
</wa-tab-panel>
|
||||
<wa-tab-panel name="css">
|
||||
|
||||
Simply add the following code at the top of your CSS file:
|
||||
```css
|
||||
@import url('{% cdnUrl 'styles/themes/' + page.fileSlug + '.css' %}');
|
||||
```
|
||||
</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
|
||||
## 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.
|
||||
|
||||
{% endmarkdown %}
|
||||
{% endblock %}
|
||||
@@ -1,84 +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
|
||||
container.querySelectorAll(options.headingSelector).forEach(heading => {
|
||||
const hasAnchor = heading.querySelector('a');
|
||||
const existingId = heading.getAttribute('id');
|
||||
const clone = parse(heading.outerHTML);
|
||||
|
||||
// Create a clone of the heading so we can remove [data-no-anchor] elements from the text content
|
||||
clone.querySelectorAll('[data-no-anchor]').forEach(el => el.remove());
|
||||
|
||||
if (hasAnchor) {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = existingId;
|
||||
if (!id) {
|
||||
const slug = createId(clone.textContent ?? '') ?? uuid().slice(-12);
|
||||
id = slug;
|
||||
let suffix = 1;
|
||||
|
||||
// Make sure the slug is unique in the document
|
||||
while (doc.getElementById(id) !== null) {
|
||||
id = `${slug}-${++suffix}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the anchor
|
||||
const anchor = parse(`
|
||||
<a href="#${encodeURIComponent(id)}">
|
||||
<span class="wa-visually-hidden"></span>
|
||||
<span aria-hidden="true">#</span>
|
||||
</a>
|
||||
`);
|
||||
anchor.querySelector('.wa-visually-hidden').textContent = options.anchorLabel;
|
||||
|
||||
// Update the heading
|
||||
if (!existingId) {
|
||||
heading.setAttribute('id', id);
|
||||
}
|
||||
heading.classList.add('anchor-heading');
|
||||
heading.appendChild(anchor);
|
||||
});
|
||||
|
||||
return doc.toString();
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { parse } from 'node-html-parser';
|
||||
|
||||
/**
|
||||
* Eleventy plugin to add copy buttons to code blocks.
|
||||
*/
|
||||
export function copyCodePlugin(options = {}) {
|
||||
options = {
|
||||
container: 'body',
|
||||
...options,
|
||||
};
|
||||
|
||||
return function (eleventyConfig) {
|
||||
eleventyConfig.addTransform('copy-code', content => {
|
||||
const doc = parse(content, { blockTextElements: { code: true } });
|
||||
const container = doc.querySelector(options.container);
|
||||
|
||||
if (!container) {
|
||||
return content;
|
||||
}
|
||||
|
||||
// Look for code blocks
|
||||
container.querySelectorAll('pre > code').forEach(code => {
|
||||
const pre = code.closest('pre');
|
||||
|
||||
// Add a copy button (we set the copy data at runtime to reduce page bloat)
|
||||
pre.innerHTML = `<wa-copy-button class="copy-button" hoist></wa-copy-button>` + pre.innerHTML;
|
||||
});
|
||||
|
||||
return doc.toString();
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,279 +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 stripQuotes(content) {
|
||||
return content.replace(/^(['"])(.+)\1$/g, '$2');
|
||||
}
|
||||
|
||||
export function getEnumValues(type) {
|
||||
return type
|
||||
.split('|')
|
||||
.map(value => value.trim())
|
||||
.filter(Boolean)
|
||||
.map(stripQuotes);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
function setCopyValue() {
|
||||
document.querySelectorAll('.copy-button').forEach(copyButton => {
|
||||
const pre = copyButton.closest('pre');
|
||||
const code = pre?.querySelector('code');
|
||||
|
||||
if (code) {
|
||||
copyButton.value = code.textContent;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set data for all copy buttons when the page loads
|
||||
setCopyValue();
|
||||
|
||||
document.addEventListener('turbo:load', setCopyValue);
|
||||
@@ -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('wa-input', e => {
|
||||
if (e.target?.matches('#block-filter wa-input')) {
|
||||
updateResults(e.target);
|
||||
}
|
||||
});
|
||||
@@ -1,64 +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() {
|
||||
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' },
|
||||
);
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Without this, there's a flash of the incorrect preset theme.
|
||||
*/
|
||||
function updateSelectionBeforeTurboLoad(e) {
|
||||
const newElement = e.detail.newBody || e.detail.newFrame || e.detail.newStream;
|
||||
if (newElement) {
|
||||
presetTheme.syncUI(newElement);
|
||||
}
|
||||
}
|
||||
|
||||
['turbo:before-render', 'turbo:before-stream-render', 'turbo:before-frame-render'].forEach(eventName => {
|
||||
document.addEventListener(eventName, updateSelectionBeforeTurboLoad);
|
||||
});
|
||||
|
||||
window.presetTheme = presetTheme;
|
||||
@@ -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();
|
||||
@@ -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';
|
||||
});
|
||||
}
|
||||
@@ -1,115 +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('wa-change', event => {
|
||||
const picker = event.target.closest(this.picker);
|
||||
if (picker) {
|
||||
this.set(picker.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
for (let el of document.querySelectorAll('.wa-invert')) {
|
||||
el.classList.toggle('wa-dark', !dark);
|
||||
el.classList.toggle('wa-light', 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');
|
||||
}
|
||||
});
|
||||
@@ -1,474 +0,0 @@
|
||||
@import 'code-examples.css';
|
||||
@import 'code-highlighter.css';
|
||||
@import 'copy-code.css';
|
||||
@import 'outline.css';
|
||||
@import 'search.css';
|
||||
@import 'cera_typeface.css';
|
||||
|
||||
:root {
|
||||
--wa-brand-orange: #f36944;
|
||||
--wa-brand-grey: #30323b;
|
||||
}
|
||||
|
||||
.wa-dark .only-light,
|
||||
.only-dark:not(.wa-dark, .wa-dark *) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
wa-page {
|
||||
--wa-flow-spacing: var(--wa-space-xl);
|
||||
}
|
||||
|
||||
/* Header */
|
||||
wa-page::part(header) {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
wa-page::part(body) {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
wa-page::part(header-actions) {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
wa-page > header {
|
||||
padding-inline: var(--wa-space-xl);
|
||||
|
||||
a[href='/'] {
|
||||
color: var(--wa-color-text-normal);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
wa-button[data-toggle-nav] {
|
||||
--text-color: currentColor;
|
||||
font-size: 1rem;
|
||||
margin-inline-start: -0.875rem;
|
||||
margin-inline-end: 0;
|
||||
|
||||
&::part(base) {
|
||||
padding: 0;
|
||||
padding-inline: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
width: auto;
|
||||
height: 1.75rem;
|
||||
}
|
||||
|
||||
#docs-branding,
|
||||
#docs-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
#version-number {
|
||||
color: var(--wa-color-text-quiet);
|
||||
font-size: var(--wa-font-size-xs);
|
||||
line-height: 1;
|
||||
margin-block-start: var(--wa-space-2xs);
|
||||
}
|
||||
#version-number + wa-badge {
|
||||
font-size: var(--wa-font-size-2xs);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
wa-button#search-trigger {
|
||||
--background-color: var(--wa-form-control-background-color);
|
||||
--border-color: var(--wa-form-control-border-color);
|
||||
}
|
||||
#search-trigger kbd {
|
||||
font-size: var(--wa-font-size-2xs);
|
||||
line-height: var(--wa-form-control-value-line-height);
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar,
|
||||
#outline {
|
||||
h2 {
|
||||
font-size: var(--wa-font-size-m);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2:not(:first-child),
|
||||
wa-details:not(:first-child) {
|
||||
margin-block-start: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
wa-details {
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
border-inline-start: var(--wa-border-width-s) solid var(--wa-color-surface-border);
|
||||
font-size: var(--wa-font-size-s);
|
||||
line-height: var(--wa-line-height-condensed);
|
||||
margin: 0;
|
||||
padding-inline-start: var(--wa-space-m);
|
||||
}
|
||||
|
||||
ul ul {
|
||||
margin-block-start: var(--wa-space-m);
|
||||
}
|
||||
|
||||
ul:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
|
||||
+ li {
|
||||
margin-block-start: var(--wa-space-m);
|
||||
}
|
||||
}
|
||||
|
||||
li a {
|
||||
color: var(--wa-color-text-normal);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
li wa-badge::part(base) {
|
||||
font-size: var(--wa-font-size-2xs);
|
||||
font-weight: var(--wa-font-weight-bold);
|
||||
}
|
||||
|
||||
li wa-icon {
|
||||
color: var(--wa-color-text-quiet);
|
||||
vertical-align: middle;
|
||||
|
||||
&[name='flask'] {
|
||||
margin-inline: 0.125em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#outline-standard h2 {
|
||||
margin-block-end: var(--wa-space-m);
|
||||
}
|
||||
|
||||
/* Pro badges */
|
||||
wa-badge.pro::part(base) {
|
||||
background-color: var(--wa-brand-orange);
|
||||
border-color: var(--wa-brand-orange);
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
h2 {
|
||||
color: var(--wa-color-text-quiet);
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4em;
|
||||
color: var(--wa-color-text-normal);
|
||||
text-decoration: none;
|
||||
|
||||
wa-icon {
|
||||
margin-block-end: -0.15em;
|
||||
font-size: var(--wa-font-size-s);
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
color: var(--wa-color-gray-70);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--wa-color-brand-on-normal);
|
||||
|
||||
wa-icon {
|
||||
color: var(--wa-color-brand-on-quiet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar-close-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
#sidebar-close-button {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar nav {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
wa-page::part(menu) {
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
wa-page[view='mobile'] :is([slot='navigation-header'], [slot='navigation']) {
|
||||
padding: 0;
|
||||
|
||||
& wa-details::part(icon) {
|
||||
padding-inline: var(--wa-space-xs); /* aligns details icons with drawer close icon */
|
||||
}
|
||||
}
|
||||
|
||||
[slot='navigation-header'] wa-menu {
|
||||
font-family: var(--wa-font-family-body);
|
||||
font-size: var(--wa-font-size-m);
|
||||
font-weight: var(--wa-font-weight-normal);
|
||||
}
|
||||
|
||||
/* Main content */
|
||||
wa-page > main {
|
||||
max-width: 80ch;
|
||||
padding: var(--wa-space-xl);
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
h1.title wa-badge {
|
||||
vertical-align: middle;
|
||||
|
||||
&::part(base) {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.block-info {
|
||||
margin-block-end: var(--wa-flow-spacing);
|
||||
}
|
||||
|
||||
/* Current link */
|
||||
#sidebar,
|
||||
#outline {
|
||||
.current {
|
||||
font-weight: var(--wa-font-weight-bold);
|
||||
text-decoration-style: solid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Anchor headings */
|
||||
.anchor-heading a {
|
||||
visibility: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.anchor-heading:hover a {
|
||||
visibility: visible;
|
||||
padding: 0 0.125em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Callouts */
|
||||
.callout {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
border: var(--wa-border-style) var(--wa-border-width-s);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: 1rem;
|
||||
margin-block-end: var(--wa-flow-spacing);
|
||||
|
||||
:first-child {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
:last-child {
|
||||
margin-block-end: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.callout-icon {
|
||||
flex: 0 0 auto;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.callout-content {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.callout-info {
|
||||
background-color: var(--wa-color-brand-fill-quiet);
|
||||
border-color: var(--wa-color-brand-border-quiet);
|
||||
|
||||
.callout-icon {
|
||||
color: var(--wa-color-brand-on-normal);
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--wa-color-brand-fill-normal);
|
||||
}
|
||||
}
|
||||
|
||||
.callout-warning {
|
||||
background-color: var(--wa-color-warning-fill-quiet);
|
||||
border-color: var(--wa-color-warning-border-quiet);
|
||||
|
||||
.callout-icon {
|
||||
color: var(--wa-color-warning-on-normal);
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--wa-color-warning-fill-normal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Index Pages */
|
||||
wa-page > main:has(> .index-grid) {
|
||||
max-width: 120ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.index-summary {
|
||||
max-inline-size: 80ch;
|
||||
}
|
||||
|
||||
.index-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(22ch, 100%), 1fr));
|
||||
gap: var(--wa-space-2xl);
|
||||
|
||||
a {
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
wa-card {
|
||||
box-shadow: none;
|
||||
--spacing: var(--wa-space-m);
|
||||
inline-size: 100%;
|
||||
|
||||
&:hover {
|
||||
--border-color: var(--wa-color-brand-border-loud);
|
||||
border-color: var(--border-color);
|
||||
box-shadow: 0 0 0 var(--wa-border-width-s) var(--border-color);
|
||||
|
||||
.page-name {
|
||||
color: var(--wa-color-brand-on-quiet);
|
||||
}
|
||||
}
|
||||
|
||||
[slot='header'] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&::part(header) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-bottom: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-block-size: calc(6rem + var(--spacing));
|
||||
}
|
||||
}
|
||||
|
||||
.page-name {
|
||||
font-size: var(--wa-font-size-s);
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
}
|
||||
}
|
||||
|
||||
.index-category {
|
||||
grid-column: 1 / -1;
|
||||
margin-block-end: 0;
|
||||
margin-block-start: var(--wa-space-2xl);
|
||||
}
|
||||
|
||||
/* Swatches */
|
||||
.swatch {
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-neutral-border-normal);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
box-sizing: border-box;
|
||||
line-height: 2.5;
|
||||
height: 2.5em;
|
||||
padding-inline: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
/* Layout Examples */
|
||||
.layout-example-boundary {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: var(--wa-space-s);
|
||||
}
|
||||
|
||||
.layout-example-block {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
.layout-example-mixed-sizing .layout-example-block:nth-child(3n) {
|
||||
min-inline-size: 6rem;
|
||||
}
|
||||
.layout-example-mixed-sizing .layout-example-block:nth-child(3n + 2) {
|
||||
min-inline-size: 8rem;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
.two-columns {
|
||||
columns: 2;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.component-table td > * + * {
|
||||
margin-block-start: var(--wa-space-s);
|
||||
}
|
||||
|
||||
.table-scroll {
|
||||
overflow-x: auto;
|
||||
margin-block-end: var(--wa-flow-spacing);
|
||||
}
|
||||
|
||||
/** mobile */
|
||||
@media screen and (max-width: 768px) {
|
||||
wa-page .only-desktop {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/** desktop */
|
||||
@media screen and not (max-width: 768px) {
|
||||
/* Navigation sidebar */
|
||||
wa-page::part(navigation) {
|
||||
border-right: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
wa-page > #sidebar {
|
||||
overflow: auto;
|
||||
max-height: 100%;
|
||||
min-width: 300px;
|
||||
padding: var(--wa-space-xl);
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
wa-page > main {
|
||||
padding: var(--wa-space-3xl);
|
||||
}
|
||||
}
|
||||
|
||||
.layout-theme {
|
||||
wa-page > main {
|
||||
max-width: 140ch;
|
||||
|
||||
.max-line-length {
|
||||
max-width: 80ch;
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
min-height: 16lh;
|
||||
height: 65vh;
|
||||
max-height: 21lh;
|
||||
}
|
||||
}
|
||||
@@ -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).
|
||||
:::
|
||||
@@ -1,145 +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>
|
||||
```
|
||||
@@ -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).
|
||||
:::
|
||||
@@ -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('wa-input', e => filterByName(name_search.value));
|
||||
@@ -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><{{ component.tagName }}></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 %}
|
||||
@@ -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">
|
||||
<button>Click me!</button>
|
||||
<wa-button>Click me!</wa-button>
|
||||
</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">
|
||||
<button>Click me!</button>
|
||||
<wa-button>Click me!</wa-button>
|
||||
</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">
|
||||
<button>Click me!</button>
|
||||
</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 component’s 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">
|
||||
<button>Click me!</button>
|
||||
</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 demo’s `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">
|
||||
<wa-callout>Helloooo!</wa-callout>
|
||||
</code></pre>
|
||||
</wa-code-demo>
|
||||
```
|
||||
|
||||
|
||||
### Isolated viewports
|
||||
|
||||
Often you may want to render your demo in a separate viewport, e.g. when it’s 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">
|
||||
<button>Click me!</button>
|
||||
</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">
|
||||
<button>Click me!</button>
|
||||
</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">
|
||||
<button>Click me!</button>
|
||||
<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.
|
||||
<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.
|
||||
<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">
|
||||
<wa-callout>Helloooo!</wa-callout>
|
||||
</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">
|
||||
<button>Click me!</button>
|
||||
<wa-button>Click me!</wa-button>
|
||||
</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">
|
||||
<button>Click me!</button>
|
||||
<wa-button>Click me!</wa-button>
|
||||
</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
|
||||
@@ -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 }}>"
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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: []
|
||||
---
|
||||
@@ -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>
|
||||
```
|
||||
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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.
|
||||
:::
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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>
|
||||
@@ -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>•</span>
|
||||
<span>2024</span>
|
||||
<span>•</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>
|
||||
@@ -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" %}
|
||||
|
||||
<!--  -->
|
||||
|
||||
## 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>•</span>
|
||||
<span>2024</span>
|
||||
<span>•</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">I’m 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 don’t 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' %}" />
|
||||
```
|
||||
@@ -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-violet-80);
|
||||
color: var(--wa-color-violet-20);
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:not([slot='']) p {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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" 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" 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" 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" 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" 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" 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" 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" 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" 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" 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" 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>
|
||||
```
|
||||
@@ -1,76 +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><br>
|
||||
<wa-radio value="2">Option 2</wa-radio><br>
|
||||
<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><br>
|
||||
<wa-radio value="2">Option 2</wa-radio><br>
|
||||
<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><br>
|
||||
<wa-radio value="2" disabled>Option 2</wa-radio><br>
|
||||
<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><br>
|
||||
<wa-radio value="2">Small 2</wa-radio><br>
|
||||
<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><br>
|
||||
<wa-radio value="2">Medium 2</wa-radio><br>
|
||||
<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><br>
|
||||
<wa-radio value="2">Large 2</wa-radio><br>
|
||||
<wa-radio value="3">Large 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
```
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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).
|
||||
:::
|
||||
@@ -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).
|
||||
:::
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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="
|
||||
<button>Click me!</button>
|
||||
"></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="
|
||||
<button>Click me!</button>
|
||||
<wa-button>Click me!</wa-button>
|
||||
"></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="
|
||||
<button>Click me!</button>
|
||||
<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.
|
||||
<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.
|
||||
<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
|
||||
@@ -1,124 +0,0 @@
|
||||
---
|
||||
title: Customizing
|
||||
description: Learn how to customize Web Awesome through parts and custom properties.
|
||||
layout: page-outline
|
||||
---
|
||||
|
||||
Web Awesome components can be customized at a high level through a theming API. This gives you control over theme colors and general styling. For more advanced customizations, you can make use of CSS parts and custom properties to target individual components.
|
||||
|
||||
## Themes
|
||||
|
||||
Web Awesome uses numerous CSS custom properties that make up a high-level theming API and provide a consistent look and feel across the entire library. You can customize them and use them in your own application just with CSS — no preprocessor required.
|
||||
|
||||
Because these custom properties live at the page level, they're prefixed with `--wa-` to avoid collisions with other libraries or your own custom properties.
|
||||
|
||||
To customize a theme, simply override any of these custom properties in your own stylesheet by scoping your styles to `:root`, `:host`, and, if needed, the class for the specific theme you want to override. Here's an example that changes the default brand color (blue) to violet in the light theme using existing [literal colors](/docs/theming/color/#literal-colors).
|
||||
|
||||
```css
|
||||
:where(:root),
|
||||
:host,
|
||||
.wa-theme-default {
|
||||
/* Changes the brand color to violet across the library */
|
||||
--wa-color-brand-fill-quiet: var(--wa-color-violet-95);
|
||||
--wa-color-brand-fill-normal: var(--wa-color-violet-90);
|
||||
--wa-color-brand-fill-loud: var(--wa-color-violet-50);
|
||||
--wa-color-brand-border-quiet: var(--wa-color-violet-90);
|
||||
--wa-color-brand-border-normal: var(--wa-color-violet-80);
|
||||
--wa-color-brand-border-loud: var(--wa-color-violet-60);
|
||||
--wa-color-brand-on-quiet: var(--wa-color-violet-40);
|
||||
--wa-color-brand-on-normal: var(--wa-color-violet-30);
|
||||
--wa-color-brand-on-loud: white;
|
||||
}
|
||||
```
|
||||
|
||||
For more examples and further guidance, refer to [Themes](/docs/themes) and the Theming section of this documentation. For a complete list of all custom properties used for theming, refer to `src/styles/themes/default.css` in the project's source code.
|
||||
|
||||
## Components
|
||||
|
||||
Whereas a theme offers a high-level way to customize the library, components offer different hooks as a low-level way to customize them individually.
|
||||
|
||||
Web Awesome components use a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate their styles and behaviors. As a result, you can't simply target their internals with the usual CSS selectors. Instead, components expose a set of custom properties and CSS parts that can be targeted to customize their appearance.
|
||||
|
||||
### Custom Properties
|
||||
|
||||
Components expose custom properties that are scoped to the component, not global, so they do not have the same `--wa-` prefix as a theme's custom properties. These custom properties reflect common qualities of a component, such as `--background-color`, `--border-style`, `--size`, etc.
|
||||
|
||||
You can set custom properties on a component in your stylesheet.
|
||||
|
||||
```css
|
||||
wa-avatar {
|
||||
--size: 6rem;
|
||||
}
|
||||
```
|
||||
|
||||
This will also work if you need to target a subset of components with a specific class.
|
||||
|
||||
```css
|
||||
wa-avatar.your-class {
|
||||
--size: 6rem;
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you can set them inline directly on the element.
|
||||
|
||||
```html
|
||||
<wa-avatar style="--size: 6rem;"></wa-avatar>
|
||||
```
|
||||
|
||||
The custom properties exposed by each component can be found in the component's API documentation.
|
||||
|
||||
### Custom States
|
||||
|
||||
Components can expose custom states that allow you to style them based on their current condition using the `:state()` selector. Custom states provide a way to target specific component states that aren't covered by standard pseudo-classes like `:hover` or `:focus`.
|
||||
Here's an example that styles a checkbox that's checked.
|
||||
|
||||
```css
|
||||
wa-checkbox:state(checked) {
|
||||
outline: dotted 2px tomato;
|
||||
}
|
||||
```
|
||||
|
||||
Custom states can be combined with CSS parts and custom properties to create sophisticated customizations. The custom states exposed by each component can be found in the component's API documentation under the "Custom States" section.
|
||||
|
||||
### CSS Parts
|
||||
|
||||
CSS parts offer further flexibility to customize individual components. The "parts" exposed by each component can be targeted with the [CSS part selector](https://developer.mozilla.org/en-US/docs/Web/CSS/::part), or `::part()`.
|
||||
|
||||
Parts allow you to style *any* standard CSS property, not just those exposed through custom properties. Here's an example that modifies buttons with the `gradient-button` class.
|
||||
|
||||
```html {.example}
|
||||
<wa-button class="gradient-button"> Gradient Button </wa-button>
|
||||
|
||||
<style>
|
||||
.gradient-button::part(base) {
|
||||
background: linear-gradient(217deg, var(--wa-color-indigo-50), var(--wa-color-violet-50), var(--wa-color-red-50));
|
||||
border: solid 1px var(--wa-color-violet-50);
|
||||
transition: transform 100ms, box-shadow 100ms;
|
||||
}
|
||||
|
||||
.gradient-button::part(base):hover {
|
||||
box-shadow: var(--wa-shadow-m);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.gradient-button::part(base):active {
|
||||
box-shadow: inset var(--wa-shadow-s);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.gradient-button::part(label) {
|
||||
color: white;
|
||||
text-shadow: rgb(0 0 0 / 0.3) 0 -1px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
CSS parts have a few important advantages:
|
||||
|
||||
- Customizations can be made to components with explicit selectors, such as `::part(icon)`, rather than implicit selectors, such as `.button > div > span + .icon`, that are much more fragile.
|
||||
|
||||
- The internal structure of a component will likely change as it evolves. By exposing CSS parts through an API, the internals can be reworked without fear of breaking customizations as long as its parts remain intact.
|
||||
|
||||
- It encourages us to think more about how components are designed and how customizations should be allowed before users can take advantage of them. Once we opt a part into the component's API, it's guaranteed to be supported and can't be removed until a major version of the library is released.
|
||||
|
||||
Most (but not all) components expose parts. You can find them in each component's API documentation under the "CSS Parts" section.
|
||||
@@ -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);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,352 +0,0 @@
|
||||
---
|
||||
title: Theming Sandbox
|
||||
description: TODO
|
||||
layout: page-outline
|
||||
---
|
||||
|
||||
## 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>
|
||||
```
|
||||
|
||||
## Alerts
|
||||
|
||||
```html {.example}
|
||||
<wa-callout variant="brand">
|
||||
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
|
||||
<strong>This is super informative</strong><br />
|
||||
You can tell by how pretty the alert is.
|
||||
</wa-callout>
|
||||
<br />
|
||||
<wa-callout variant="success">
|
||||
<wa-icon slot="icon" name="circle-check" variant="regular"></wa-icon>
|
||||
<strong>Your changes have been saved</strong><br />
|
||||
You can safely exit the app now.
|
||||
</wa-callout>
|
||||
<br />
|
||||
<wa-callout variant="neutral">
|
||||
<wa-icon slot="icon" name="gear" variant="regular"></wa-icon>
|
||||
<strong>Your settings have been updated</strong><br />
|
||||
Settings will take affect on next login.
|
||||
</wa-callout>
|
||||
<br />
|
||||
<wa-callout variant="warning">
|
||||
<wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon>
|
||||
<strong>Your session has ended</strong><br />
|
||||
Please login again to continue.
|
||||
</wa-callout>
|
||||
<br />
|
||||
<wa-callout variant="danger">
|
||||
<wa-icon slot="icon" name="circle-exclamation" variant="regular"></wa-icon>
|
||||
<strong>Your account has been deleted</strong><br />
|
||||
We're very sorry to see you go!
|
||||
</wa-callout>
|
||||
```
|
||||
|
||||
## Badges and Tags
|
||||
|
||||
```html {.example}
|
||||
<wa-badge variant="brand">Brand</wa-badge>
|
||||
<wa-badge variant="success">Success</wa-badge>
|
||||
<wa-badge variant="neutral">Neutral</wa-badge>
|
||||
<wa-badge variant="warning">Warning</wa-badge>
|
||||
<wa-badge variant="danger">Danger</wa-badge>
|
||||
<br />
|
||||
<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>
|
||||
```
|
||||
|
||||
## Buttons
|
||||
|
||||
```html {.example}
|
||||
<wa-button variant="brand">Brand</wa-button>
|
||||
<wa-button variant="success">Success</wa-button>
|
||||
<wa-button variant="neutral">Neutral</wa-button>
|
||||
<wa-button variant="warning">Warning</wa-button>
|
||||
<wa-button variant="danger">Danger</wa-button>
|
||||
<br /><br />
|
||||
<wa-button variant="brand" appearance="outlined">Brand</wa-button>
|
||||
<wa-button variant="success" appearance="outlined">Success</wa-button>
|
||||
<wa-button variant="neutral" appearance="outlined">Neutral</wa-button>
|
||||
<wa-button variant="warning" appearance="outlined">Warning</wa-button>
|
||||
<wa-button variant="danger" appearance="outlined">Danger</wa-button>
|
||||
<br /><br />
|
||||
<wa-button appearance="plain">Text</wa-button>
|
||||
<br /><br />
|
||||
<wa-radio-group label="Radio button group" 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>
|
||||
```
|
||||
|
||||
## Form controls
|
||||
|
||||
```html {.example}
|
||||
<wa-checkbox>Unchecked</wa-checkbox>
|
||||
<br />
|
||||
<wa-checkbox checked>Checked</wa-checkbox>
|
||||
<br /><br />
|
||||
<wa-radio-group label="Radio" 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-switch>Switch off</wa-switch>
|
||||
<br />
|
||||
<wa-switch checked>Switch on</wa-switch>
|
||||
<br /><br />
|
||||
<wa-slider label="Range" hint="Here's a bit of handy content." min="0" max="100"></wa-slider>
|
||||
<br /><br />
|
||||
<wa-input label="Label" hint="Super helpful and/or contextual content" placeholder="Placeholder"></wa-input>
|
||||
<br />
|
||||
<wa-select label="Select" multiple value="option-1 option-2">
|
||||
<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-option value="option-4">Option 4</wa-option>
|
||||
<wa-option value="option-5">Option 5</wa-option>
|
||||
<wa-option value="option-6">Option 6</wa-option>
|
||||
</wa-select>
|
||||
```
|
||||
|
||||
## Progress
|
||||
|
||||
```html {.example}
|
||||
<wa-progress-ring value="25" style="--indicator-width: 4px;"></wa-progress-ring>
|
||||
<wa-progress-bar value="60"></wa-progress-bar>
|
||||
<wa-spinner></wa-spinner>
|
||||
```
|
||||
|
||||
## Shadows
|
||||
|
||||
```html {.example}
|
||||
<style>
|
||||
div.shadow {
|
||||
border: var(--wa-border-width-s) solid var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
display: inline-block;
|
||||
height: 4rem;
|
||||
margin-right: 2rem;
|
||||
width: 4rem;
|
||||
}
|
||||
</style>
|
||||
<div class="shadow" style="box-shadow: var(--wa-shadow-s);"></div>
|
||||
<div class="shadow" style="box-shadow: var(--wa-shadow-m);"></div>
|
||||
<div class="shadow" style="box-shadow: var(--wa-shadow-l);"></div>
|
||||
```
|
||||
|
||||
## Alignment Tests
|
||||
|
||||
```html {.example}
|
||||
<style>
|
||||
div.test-cases > * + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
div.alignment {
|
||||
background: linear-gradient(to bottom, lightblue, lightblue 1px, transparent 1px, transparent), linear-gradient(to top, lightblue, lightblue 1px, transparent 1px, transparent);
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
div.alignment::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: calc(50% - 0.5px);
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
<div class="test-cases">
|
||||
<div class="alignment">
|
||||
<wa-switch size="small">OCBS</wa-switch>
|
||||
<wa-checkbox size="small">OCBS</wa-checkbox>
|
||||
<wa-radio value="1" size="small">OCBS</wa-radio>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-switch>OCBS</wa-switch>
|
||||
<wa-checkbox>OCBS</wa-checkbox>
|
||||
<wa-radio value="1">OCBS</wa-radio>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-switch size="large">OCBS</wa-switch>
|
||||
<wa-checkbox size="large">OCBS</wa-checkbox>
|
||||
<wa-radio value="1" size="large">OCBS</wa-radio>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-input size="small"></wa-input>
|
||||
<wa-select size="small" value="ocbs" multiple>
|
||||
<wa-option value="ocbs">OCBS</wa-option>
|
||||
</wa-select>
|
||||
<wa-color-picker size="small"></wa-color-picker>
|
||||
<wa-button size="small">OCBS</wa-button>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-input size="medium"></wa-input>
|
||||
<wa-select size="medium" value="ocbs" multiple>
|
||||
<wa-option value="ocbs">OCBS</wa-option>
|
||||
</wa-select>
|
||||
<wa-color-picker size="medium"></wa-color-picker>
|
||||
<wa-button size="medium">OCBS</wa-button>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-input size="large"></wa-input>
|
||||
<wa-select size="large" value="ocbs" multiple>
|
||||
<wa-option value="ocbs">OCBS</wa-option>
|
||||
</wa-select>
|
||||
<wa-color-picker size="large"></wa-color-picker>
|
||||
<wa-button size="large">OCBS</wa-button>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-badge>OCBS</wa-badge>
|
||||
<wa-avatar></wa-avatar>
|
||||
<wa-rating></wa-rating>
|
||||
<wa-slider></wa-slider>
|
||||
<wa-icon-button name="gear" label="Settings"></wa-icon-button>
|
||||
<wa-progress-bar value="50" style="width: 8rem;"></wa-progress-bar>
|
||||
<wa-spinner></wa-spinner>
|
||||
</div>
|
||||
<div class="alignment">
|
||||
<wa-input label="AaBbCc" hint="Ipsum"></wa-input>
|
||||
<wa-select label="AaBbCc" value="ocbs" multiple hint="Ipsum">
|
||||
<wa-option value="ocbs">OCBS</wa-option>
|
||||
</wa-select>
|
||||
<wa-color-picker label="AaBbCc" hint="Ipsum"></wa-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Custom Property Tests
|
||||
|
||||
```html {.example}
|
||||
<style>
|
||||
.wa-theme-test {
|
||||
--wa-form-control-background-color: mistyrose;
|
||||
|
||||
--wa-form-control-border-style: dotted;
|
||||
--wa-form-control-border-width: 3px;
|
||||
--wa-form-control-border-radius: 12px;
|
||||
|
||||
--wa-form-control-activated-color: mediumvioletred;
|
||||
--wa-form-control-border-color: palevioletred;
|
||||
|
||||
--wa-form-control-label-color: rosybrown;
|
||||
--wa-form-control-label-font-weight: 900;
|
||||
--wa-form-control-label-line-height: 1;
|
||||
|
||||
--wa-form-control-value-color: brown;
|
||||
--wa-form-control-value-font-weight: 900;
|
||||
--wa-form-control-value-line-height: 2;
|
||||
|
||||
--wa-form-control-placeholder-color: lightpink;
|
||||
}
|
||||
</style>
|
||||
<div class="wa-theme-test" style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem;">
|
||||
<label>Native Input <input type="text" placeholder="placeholder"></label>
|
||||
<wa-input label="WA Input" type="text" placeholder="placeholder"></wa-input>
|
||||
|
||||
<label>Native Input <input type="text" value="value"></label>
|
||||
<wa-input label="WA Input" type="text" value="value"></wa-input>
|
||||
|
||||
<label>Native Textarea <textarea placeholder="placeholder"></textarea></label>
|
||||
<wa-textarea label="WA Textarea" placeholder="placeholder"></wa-textarea>
|
||||
|
||||
<label>Native Textarea <textarea>value</textarea></label>
|
||||
<wa-textarea label="WA Textarea" value="value"></wa-textarea>
|
||||
|
||||
<label><input type="checkbox" checked> Native Checkbox</label>
|
||||
<wa-checkbox checked>WA Checkbox</wa-checkbox>
|
||||
|
||||
<label><input type="checkbox"> Native Checkbox</label>
|
||||
<wa-checkbox>WA Checkbox</wa-checkbox>
|
||||
|
||||
<label><input type="radio" checked> Native Radio</label>
|
||||
<wa-radio checked>WA Radio</wa-radio>
|
||||
|
||||
<label><input type="radio"> Native Radio</label>
|
||||
<wa-radio>WA Radio</wa-radio>
|
||||
|
||||
<label>
|
||||
Native Select
|
||||
<select value="option-1">
|
||||
<option value="option-1">Option 1</option>
|
||||
<option value="option-2">Option 2</option>
|
||||
<option value="option-3">Option 3</option>
|
||||
<option value="option-4">Option 4</option>
|
||||
</select>
|
||||
</label>
|
||||
<wa-select label="WA Select" value="option-1">
|
||||
<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-option value="option-4">Option 4</wa-option>
|
||||
</wa-select>
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||
## Text Controls Tests
|
||||
|
||||
```html {.example}
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem;">
|
||||
<label>Native Input <input type="text" value="value"></label>
|
||||
<wa-input label="WA Input" type="text" value="value"></wa-input>
|
||||
|
||||
<label>
|
||||
Native Select
|
||||
<select value="option-1">
|
||||
<option value="option-1">Option 1</option>
|
||||
<option value="option-2">Option 2</option>
|
||||
<option value="option-3">Option 3</option>
|
||||
<option value="option-4">Option 4</option>
|
||||
</select>
|
||||
</label>
|
||||
<wa-select label="WA Select" value="option-1">
|
||||
<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-option value="option-4">Option 4</wa-option>
|
||||
</wa-select>
|
||||
|
||||
<label>Native Textarea <textarea>value</textarea></label>
|
||||
<wa-textarea label="WA Textarea" value="value"></wa-textarea>
|
||||
</div>
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,114 +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 only offering access to the free components 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 the free stuff 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!
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Autoloading via CDN (Easiest)
|
||||
|
||||
The autoloader is the easiest way to use Web Awesome. A lightweight script watches the DOM for unregistered Web Awesome elements and lazy loads them for you — even if they're added dynamically.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/themes/default.css' %}" />
|
||||
<script type="module" src="{% cdnUrl 'webawesome.loader.js' %}"></script>
|
||||
```
|
||||
|
||||
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.
|
||||
:::
|
||||
|
||||
## 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>
|
||||
```
|
||||
|
||||
## 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 '/path/to/web-awesome/dist/webawesome.js';
|
||||
setKitCode('YOUR_KIT_CODE_HERE');
|
||||
</script>
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
Here's an example that loads only the button component.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="/path/to/web-awesome/dist/styles/themes/default.css" />
|
||||
|
||||
<script type="module" data-webawesome="/path/to/web-awesome/dist">
|
||||
import '/path/to/web-awesome/dist/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.
|
||||
:::
|
||||
|
||||
## Using Web Awesome with 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 as shown above.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Layout
|
||||
description: Layout components and utility classes help you organize content that can adapt to any device or screen size. Browse the collection of responsive layout tools included in Web Awesome Pro.
|
||||
layout: overview
|
||||
categories: ["components", "utilities"]
|
||||
override:tags: []
|
||||
---
|
||||
@@ -1,133 +0,0 @@
|
||||
---
|
||||
title: Button
|
||||
description: 'Button styles apply your Web Awesome theme to native HTML buttons. Buttons are activated by users to perform actions, such as submitting a form.'
|
||||
tags: forms
|
||||
component: button
|
||||
icon: button
|
||||
snippets:
|
||||
'<button>': https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button
|
||||
'.wa-button': false
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<button>Button</button>
|
||||
<input type="button" value="Input (button)">
|
||||
<input type="reset" value="Input (reset)">
|
||||
<input type="submit" value="Input (submit)">
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Use the variant utility classes to set the button's semantic variant.
|
||||
|
||||
```html {.example}
|
||||
<button class="wa-neutral">Neutral</button>
|
||||
<button class="wa-brand">Brand</button>
|
||||
<button class="wa-success">Success</button>
|
||||
<button class="wa-warning">Warning</button>
|
||||
<button class="wa-danger">Danger</button>
|
||||
```
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the appearance utility classes to change the button's visual appearance:
|
||||
|
||||
```html {.example}
|
||||
<div style="margin-block-end: 1rem;">
|
||||
<button class="wa-accent wa-neutral">Accent</button>
|
||||
<button class="wa-filled wa-neutral">Filled</button>
|
||||
<button class="wa-outlined wa-neutral">Outlined</button>
|
||||
<button class="wa-plain wa-neutral">Text</button>
|
||||
</div>
|
||||
<div style="margin-block-end: 1rem;">
|
||||
<button class="wa-accent wa-brand">Accent</button>
|
||||
<button class="wa-filled wa-brand">Filled</button>
|
||||
<button class="wa-outlined wa-brand">Outlined</button>
|
||||
<button class="wa-plain wa-brand">Text</button>
|
||||
</div>
|
||||
<div style="margin-block-end: 1rem;">
|
||||
<button class="wa-accent wa-success">Accent</button>
|
||||
<button class="wa-filled wa-success">Filled</button>
|
||||
<button class="wa-outlined wa-success">Outlined</button>
|
||||
<button class="wa-plain wa-success">Text</button>
|
||||
</div>
|
||||
<div style="margin-block-end: 1rem;">
|
||||
<button class="wa-accent wa-warning">Accent</button>
|
||||
<button class="wa-filled wa-warning">Filled</button>
|
||||
<button class="wa-outlined wa-warning">Outlined</button>
|
||||
<button class="wa-plain wa-warning">Text</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="wa-accent wa-danger">Accent</button>
|
||||
<button class="wa-filled wa-danger">Filled</button>
|
||||
<button class="wa-outlined wa-danger">Outlined</button>
|
||||
<button class="wa-plain wa-danger">Text</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use `wa-size-*` classes to change a button's size.
|
||||
|
||||
```html {.example}
|
||||
<button class="wa-size-s">Small</button>
|
||||
<button class="wa-size-m">Medium</button>
|
||||
<button class="wa-size-l">Large</button>
|
||||
```
|
||||
|
||||
### Pill Buttons
|
||||
|
||||
Use the `wa-pill` class to give buttons rounded edges.
|
||||
|
||||
```html {.example}
|
||||
<button class="wa-size-s wa-pill">Small</button>
|
||||
<button class="wa-size-m wa-pill">Medium</button>
|
||||
<button class="wa-size-l wa-pill">Large</button>
|
||||
```
|
||||
|
||||
### Link Buttons
|
||||
|
||||
It's often helpful to have a link that looks like a button.
|
||||
This is possible by adding a `wa-button` class to your link.
|
||||
|
||||
```html {.example}
|
||||
<a href="https://example.com/" class="wa-button">Link</a>
|
||||
<a href="https://example.com/" target="_blank" class="wa-button">New Window</a>
|
||||
<a href="/assets/images/logo.svg" download="shoelace.svg" class="wa-button">Download</a>
|
||||
```
|
||||
|
||||
### Setting a Custom Width
|
||||
|
||||
As expected, buttons can be given a custom width by setting the `width` CSS property. This is useful for making buttons span the full width of their container on smaller screens.
|
||||
|
||||
```html {.example}
|
||||
<button class="wa-size-s" style="width: 100%; margin-bottom: 1rem;">Small</button>
|
||||
<button class="wa-size-m" style="width: 100%; margin-bottom: 1rem;">Medium</button>
|
||||
<button class="wa-size-l" style="width: 100%;">Large</button>
|
||||
```
|
||||
<!--
|
||||
|
||||
### Loading
|
||||
|
||||
Use the `loading` attribute to make a button busy. The width will remain the same as before, preventing adjacent elements from moving around.
|
||||
|
||||
```html {.example}
|
||||
<button class="wa-brand" loading>Brand</button>
|
||||
<button class="wa-success" loading>Success</button>
|
||||
<button class="wa-neutral" loading>Neutral</button>
|
||||
<button class="wa-warning" loading>Warning</button>
|
||||
<button class="wa-danger" loading>Danger</button>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable a button.
|
||||
|
||||
```html {.example}
|
||||
<button class="wa-brand" disabled>Brand</button>
|
||||
<button class="wa-success" disabled>Success</button>
|
||||
<button class="wa-neutral" disabled>Neutral</button>
|
||||
<button class="wa-warning" disabled>Warning</button>
|
||||
``` -->
|
||||
@@ -1,89 +0,0 @@
|
||||
---
|
||||
title: Checkbox
|
||||
description: Checkboxes allow the user to toggle an option on or off.
|
||||
tags: forms
|
||||
component: checkbox
|
||||
icon: checkbox
|
||||
elements:
|
||||
"<input type=checkbox>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<label><input type="checkbox"> Checkbox</label>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Checked
|
||||
|
||||
Use the `checked` attribute to activate the checkbox.
|
||||
|
||||
```html {.example}
|
||||
<label><input type="checkbox" checked> Checked</label>
|
||||
```
|
||||
|
||||
<!--
|
||||
### Indeterminate
|
||||
|
||||
Use the `indeterminate` JS property to make the checkbox indeterminate.
|
||||
|
||||
```html {.example}
|
||||
<label><input type="checkbox" class="indeterminate"> Indeterminate</label>
|
||||
<script>
|
||||
document.querySelector(".indeterminate").indeterminate = true;
|
||||
</script>
|
||||
```
|
||||
-->
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable the checkbox.
|
||||
|
||||
```html {.example}
|
||||
<label><input type="checkbox" disabled> Disabled</label>
|
||||
```
|
||||
|
||||
<!--
|
||||
### Sizes
|
||||
|
||||
Use the [size utilities](/docs/utilities/size) to change a checkbox's size.
|
||||
|
||||
```html {.example}
|
||||
<label><input type="checkbox" class="wa-size-s"> Small</label>
|
||||
<br />
|
||||
<label><input type="checkbox" class="wa-size-m"> Medium</label>
|
||||
<br />
|
||||
<label><input type="checkbox" class="wa-size-l"> Large</label>
|
||||
```
|
||||
-->
|
||||
|
||||
### Custom Validity
|
||||
|
||||
Use the `setCustomValidity()` method to set a custom validation message. This will prevent the form from submitting and make the browser display the error message you provide. To clear the error, call this function with an empty string.
|
||||
|
||||
```html {.example}
|
||||
<form class="custom-validity">
|
||||
<label><input type="checkbox"> Check me</label>
|
||||
<br />
|
||||
<button type="submit" variant="brand" style="margin-top: 1rem;">Submit</button>
|
||||
</form>
|
||||
<script>
|
||||
const form = document.querySelector('.custom-validity');
|
||||
const checkbox = form.querySelector('input[type=checkbox]');
|
||||
const errorMessage = `Don't forget to check me!`;
|
||||
|
||||
// Set initial validity
|
||||
checkbox.setCustomValidity(errorMessage);
|
||||
|
||||
// Update validity on change
|
||||
checkbox.addEventListener('change', () => {
|
||||
checkbox.setCustomValidity(checkbox.checked ? '' : errorMessage);
|
||||
});
|
||||
|
||||
// Handle submit
|
||||
form.addEventListener('submit', event => {
|
||||
event.preventDefault();
|
||||
alert('All fields are valid!');
|
||||
});
|
||||
</script>
|
||||
```
|
||||
@@ -1,73 +0,0 @@
|
||||
---
|
||||
title: Content
|
||||
description: 'Content styles apply your Web Awesome theme to HTML text content, code, and images.'
|
||||
tags: content
|
||||
layout: element
|
||||
icon: skeleton
|
||||
---
|
||||
|
||||
|
||||
## Typography
|
||||
|
||||
Vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat. Amet mauris commodo quis imperdiet. Bibendum ut tristique et egestas quis ipsum suspendisse. Sit amet nulla facilisi morbi tempus iaculis urna id volutpat.
|
||||
|
||||
Cras pulvinar mattis nunc sed blandit libero. Facilisis magna etiam tempor orci. Scelerisque eleifend donec pretium vulputate sapien nec. Donec et odio pellentesque diam volutpat commodo sed egestas egestas. Mauris rhoncus aenean vel elit scelerisque mauris pellentesque.
|
||||
|
||||
> What is a Web year now, about three months? And when people can browse around, discover new things, and download them fast, when we all have agents - then Web years could slip by before human beings can notice.
|
||||
>
|
||||
> — Tim Berners-Lee
|
||||
|
||||
## Inline Text
|
||||
|
||||
```html
|
||||
Feugiat nisl pretium fusce id. Ipsum dolor sit amet consectetur adipiscing elit. Eget nunc lobortis mattis aliquam faucibus purus. Metus dictum at tempor commodo ullamcorper a lacus vestibulum. Urna condimentum mattis pellentesque id nibh tortor id.
|
||||
```
|
||||
|
||||
<div class="two-columns">
|
||||
<p><strong>Bold</strong></p>
|
||||
<p><em>Italics</em></p>
|
||||
<p><u>Underline</u></p>
|
||||
<p><del>Deleted</del></p>
|
||||
<p><ins>Inserted</ins></p>
|
||||
<p><s>Strike-through</s></p>
|
||||
<p><small>Small</small></p>
|
||||
<p><span>Text <sub>Sub</sub></span></p>
|
||||
<p><span>Text <sup>Sup</sup></span></p>
|
||||
<p><abbr title="Abbreviation">Abbr.</abbr></p>
|
||||
<p><kbd>Keyboard</kbd></p>
|
||||
<p><mark>Highlighted</mark></p>
|
||||
<p><a href="#">Link text</a></p>
|
||||
<p><code>Inline code</code></p>
|
||||
</div>
|
||||
|
||||
## Headings
|
||||
|
||||
### Heading 3
|
||||
|
||||
Feugiat nisl pretium fusce id. Ipsum dolor sit amet consectetur adipiscing elit. Eget nunc lobortis mattis aliquam faucibus purus. Metus dictum at tempor commodo ullamcorper a lacus vestibulum. Urna condimentum mattis pellentesque id nibh tortor id.
|
||||
|
||||
#### Heading 4
|
||||
|
||||
Gravida arcu ac tortor dignissim convallis aenean. Pellentesque pulvinar pellentesque habitant morbi tristique senectus et. Ipsum nunc aliquet bibendum enim facilisis gravida neque. Donec adipiscing tristique risus nec feugiat in.
|
||||
|
||||
##### Heading 5
|
||||
|
||||
Enim diam vulputate ut pharetra sit. Enim facilisis gravida neque convallis a cras. Enim neque volutpat ac tincidunt vitae semper. Sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec pretium.
|
||||
|
||||
###### Heading 6
|
||||
|
||||
Tincidunt ornare massa eget egestas purus viverra accumsan in nisl. Facilisis mauris sit amet massa vitae. Nunc faucibus a pellentesque sit amet porttitor. Adipiscing tristique risus nec feugiat in fermentum.
|
||||
|
||||
|
||||
## Code Blocks
|
||||
|
||||
```
|
||||
// do a thing
|
||||
export function thing() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## Images
|
||||
|
||||

|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
title: Details
|
||||
description: 'Details styles apply your Web Awesome theme to the HTML `<details>` element. Details show a brief summary and expand to show additional content.'
|
||||
tags: apps
|
||||
layout: element
|
||||
component: details
|
||||
icon: details
|
||||
elements:
|
||||
"<details>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<details>
|
||||
<summary>Tincidunt nunc pulvinar</summary>
|
||||
<p>Ut lectus arcu bibendum at varius. Convallis a cras semper auctor neque vitae. Odio pellentesque diam volutpat commodo sed egestas. Amet dictum sit amet justo donec enim diam vulputate ut.</p>
|
||||
</details>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Right-to-Left Languages
|
||||
|
||||
The details styling automatically adapts to right-to-left languages:
|
||||
|
||||
```html {.example}
|
||||
<details lang="ar" dir="rtl">
|
||||
<summary>تبديلني</summary>
|
||||
استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن
|
||||
</details>
|
||||
```
|
||||
|
||||
## Accordions
|
||||
|
||||
In [modern browsers](https://caniuse.com/mdn-html_elements_details_name),
|
||||
grouping `<details>` elements via the `name` attribute provides accordion-style functionality:
|
||||
|
||||
```html {.example}
|
||||
<details name="details-accordion">
|
||||
<summary>Enim diam</summary>
|
||||
<p>Nunc faucibus a pellentesque sit amet porttitor. Adipiscing tristique risus nec feugiat in fermentum. Leo duis ut diam quam nulla porttitor massa id. Mauris nunc congue nisi vitae.</p>
|
||||
</details>
|
||||
|
||||
<details name="details-accordion">
|
||||
<summary>Arcu non odio</summary>
|
||||
<p>Sed libero enim sed faucibus turpis in eu mi bibendum. Nunc mi ipsum faucibus vitae aliquet nec. Ultricies tristique nulla aliquet enim tortor. Tellus at urna condimentum mattis pellentesque.</p>
|
||||
</details>
|
||||
|
||||
<details name="details-accordion">
|
||||
<summary>Ut porttitor</summary>
|
||||
<p>Eu facilisis sed odio morbi quis commodo odio aenean sed. Sit amet purus gravida quis blandit turpis cursus. Eu consequat ac felis donec et odio pellentesque diam volutpat.</p>
|
||||
</details>
|
||||
```
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
title: Dialog
|
||||
description: 'Dialog styles apply your Web Awesome theme to the HTML `<dialog>` element. Dialogs, also called "modals", appear above the page and interrupt a user''s focus.'
|
||||
tags: apps
|
||||
icon: dialog
|
||||
elements:
|
||||
"<dialog>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog
|
||||
component: dialog
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<dialog id="dialog-overview">
|
||||
<header>
|
||||
<h2>Dialog</h2>
|
||||
<button data-dialog="close" class="wa-plain">✖️</button>
|
||||
</header>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
||||
<footer>
|
||||
<button class="wa-brand" data-dialog="close">Close</button>
|
||||
</footer>
|
||||
</dialog>
|
||||
|
||||
<button>Open Dialog</button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('#dialog-overview');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
|
||||
openButton.addEventListener('click', () => dialog.showModal());
|
||||
dialog.addEventListener('click', event => {
|
||||
if (event.target.closest('[data-dialog="close"]')) {
|
||||
dialog.close();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
@@ -1,85 +0,0 @@
|
||||
---
|
||||
title: Native Styles
|
||||
description: Native Styles use your theme to style native HTML elements to match the look and feel of Web Awesome components.
|
||||
layout: overview
|
||||
categories: ['forms', 'apps', 'content']
|
||||
override:tags: []
|
||||
---
|
||||
|
||||
{% markdown %}
|
||||
Web Awesome works _with_ the platform, rather than trying to reinvent it.
|
||||
If all you need is styles, you don’t need to use new `<wa-*>` elements!
|
||||
We also provide styles that make native HTML elements look good so you can continue using what you know and gradually adopt Web Awesome as you see fit.
|
||||
|
||||
## Installation
|
||||
|
||||
To use all Web Awesome page styles (including [utilities](/docs/utilities/)), include the following stylesheet in your project:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/webawesome.css' %}" />
|
||||
```
|
||||
|
||||
Or, to _only_ include styles for built-in elements:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/native.css' %}" />
|
||||
```
|
||||
|
||||
## Opting Out of Native Styles
|
||||
|
||||
So you've decided to use Native Styles and now you need to style an element or a part of a page completely differently, what to do?
|
||||
You can create an opt-out with the power of [CSS Cascade Layers](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers)!
|
||||
|
||||
Instead of including Native Styles with a `<link>` element, you can include it like this:
|
||||
|
||||
```html
|
||||
<style>
|
||||
@import url('{% cdnUrl 'styles/webawesome.css' %}') layer(wa);
|
||||
|
||||
@layer wa {
|
||||
.wa-off,
|
||||
.wa-off-deep,
|
||||
.wa-off-deep * {
|
||||
all: revert-layer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
Then you can opt-out of Native Styles styling by using a `wa-off` class on individual elements or `wa-off-deep` for entire subtrees:
|
||||
|
||||
```html
|
||||
<p>
|
||||
<button>I’m Awesome</button>
|
||||
<button class="wa-off">I’m not</button>
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p>Lorem Ipsum dolor sit amet</p>
|
||||
<button>I’m also awesome</button>
|
||||
</blockquote>
|
||||
<blockquote class="wa-off">
|
||||
<p>Lorem Ipsum dolor sit amet</p>
|
||||
<button >I’m also not</button>
|
||||
</blockquote>
|
||||
<blockquote class="wa-off-deep">
|
||||
<p>Lorem Ipsum dolor sit amet</p>
|
||||
<button>I’m also not</button>
|
||||
</blockquote>
|
||||
```
|
||||
|
||||
You could even design opt-outs for specific elements!
|
||||
E.g. to opt-out of `<details>` styling:
|
||||
|
||||
```css
|
||||
@layer wa {
|
||||
details.wa-details-off,
|
||||
.wa-details-off details,{
|
||||
all: revert-layer;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you find yourself opting out of entire element types too much, you could consider only including the parts of Native Styles you need instead of the whole thing.
|
||||
You can find instructions for how to do that on the individual Native Styles pages.
|
||||
{% endmarkdown %}
|
||||
@@ -1,84 +0,0 @@
|
||||
---
|
||||
title: Input
|
||||
description: Inputs collect data from the user.
|
||||
tags: forms
|
||||
icon: input
|
||||
component: input
|
||||
elements:
|
||||
"<input>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
|
||||
---
|
||||
|
||||
<style>
|
||||
wa-code-demo::part(preview) {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(150px, 1fr) minmax(150px, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
## Text Fields
|
||||
|
||||
```html {.example}
|
||||
<label>Input (text) <input type="text" placeholder="placeholder"></label>
|
||||
<wa-input label="WA Input (text)" type="text" placeholder="placeholder"></wa-input>
|
||||
|
||||
<label>Input (number) <input type="number"></label>
|
||||
<wa-input label="WA Input (number)" type="number"></wa-input>
|
||||
|
||||
<label>Input (password) <input type="password" required></label>
|
||||
<wa-input label="WA Input (password)" type="password" required></wa-input>
|
||||
|
||||
<label>Input (email) <input type="email"></label>
|
||||
<wa-input label="WA Input (email)" type="email"></wa-input>
|
||||
|
||||
<label>Input (search) <input type="search"></label>
|
||||
<wa-input label="WA Input (search)" type="search"></wa-input>
|
||||
|
||||
<label>Input (tel) <input type="tel"></label>
|
||||
<wa-input label="WA Input (tel)" type="tel"></wa-input>
|
||||
|
||||
<label>Input (url) <input type="url"></label>
|
||||
<wa-input label="WA Input (url)" type="url"></wa-input>
|
||||
```
|
||||
|
||||
## Color Picker
|
||||
|
||||
Basic:
|
||||
|
||||
```html {.example}
|
||||
<label>Input (color) <input type="color" value="#ff0066"></label>
|
||||
<wa-color-picker label="WA Color Picker" value="#ff0066"></wa-color-picker>
|
||||
```
|
||||
|
||||
With swatches:
|
||||
|
||||
```html {.example}
|
||||
<label>Input (color) <input type="color" value="#ff0066" list="swatches"></label>
|
||||
<datalist id="swatches">
|
||||
<option value="#0070ef">Web Awesome Blue</option>
|
||||
<option>#f5a623</option>
|
||||
<option>#f8e71c</option>
|
||||
<option>#8b572a</option>
|
||||
<option>#7ed321</option>
|
||||
<option>#417505</option>
|
||||
<option>#bd10e0</option>
|
||||
<option>#9013fe</option>
|
||||
</datalist>
|
||||
|
||||
<wa-color-picker label="WA Color Picker" value="#ff0066"
|
||||
swatches="#0070ef; #f5a623; #f8e71c; #8b572a; #7ed321; #417505; #bd10e0; #9013fe;"></wa-color-picker>
|
||||
```
|
||||
|
||||
## Time and Date Pickers
|
||||
|
||||
```html {.example}
|
||||
<label>Input (datetime-local) <input type="datetime-local"></label>
|
||||
<wa-input label="WA Input (datetime-local)" type="datetime-local"></wa-input>
|
||||
|
||||
<label>Input (date) <input type="date"></label>
|
||||
<wa-input label="WA Input (date)" type="date"></wa-input>
|
||||
|
||||
<label>Input (time) <input type="time"></label>
|
||||
<wa-input label="WA Input (time)" type="time"></wa-input>
|
||||
```
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
title: Lists
|
||||
description: 'List styles apply your Web Awesome theme to HTML lists, such as bulleted, numbered, or description lists.'
|
||||
tags: content
|
||||
layout: element
|
||||
elements:
|
||||
"<ul>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul
|
||||
"<ol>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol
|
||||
"<dl>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl
|
||||
---
|
||||
|
||||
## Unordered Lists
|
||||
|
||||
- List item 1
|
||||
- List item 2
|
||||
- List item 3
|
||||
- Subitem a
|
||||
- Subitem b
|
||||
|
||||
## Ordered Lists
|
||||
|
||||
1. List item 1
|
||||
2. List item 2
|
||||
3. List item 3
|
||||
- Subitem a
|
||||
- Subitem b
|
||||
|
||||
## Definition Lists
|
||||
|
||||
<dl>
|
||||
<dt>Definition 1</dt>
|
||||
<dd>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.</dd>
|
||||
<dt>Definition 2</dt>
|
||||
<dd>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</dd>
|
||||
<dt>Definition 3</dt>
|
||||
<dd>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</dd>
|
||||
</dl>
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"layout": "element.njk",
|
||||
"tags": ["native"]
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
title: Progress Bar
|
||||
description: Progress bars are used to show the status of an ongoing operation.
|
||||
tags: apps
|
||||
icon: progress-bar
|
||||
status: experimental
|
||||
component: progress-bar
|
||||
elements:
|
||||
"<progress>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress
|
||||
---
|
||||
|
||||
|
||||
```html {.example}
|
||||
<progress value="40" max="100"></progress>
|
||||
```
|
||||
|
||||
Indeterminate:
|
||||
|
||||
|
||||
```html {.example}
|
||||
<progress></progress>
|
||||
```
|
||||
|
||||
### Custom Height
|
||||
|
||||
Use the `height` CSS property to set the progress bar's height.
|
||||
|
||||
```html {.example}
|
||||
<wa-progress-bar value="50" style="height: 6px;"></wa-progress-bar>
|
||||
```
|
||||
@@ -1,76 +0,0 @@
|
||||
---
|
||||
title: Radio
|
||||
description: Radios allow the user to select a single option from a group.
|
||||
tags: forms
|
||||
icon: radio-group
|
||||
component: radio
|
||||
elements:
|
||||
"<input type=radio>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio
|
||||
---
|
||||
|
||||
<style>
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
label + label {
|
||||
margin-inline-start: var(--wa-space);
|
||||
}
|
||||
</style>
|
||||
|
||||
```html {.example}
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Initial Value
|
||||
|
||||
To set the initial value and checked state, use the `checked` attribute on the corresponding radio.
|
||||
|
||||
```html {.example}
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable a radio.
|
||||
|
||||
```html {.example}
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2" disabled> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the [size utilities](/docs/utilities/size) to change the radios' size.
|
||||
|
||||
```html {.example}
|
||||
<fieldset class="wa-size-s">
|
||||
<legend>Small</legend>
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
</fieldset>
|
||||
|
||||
<br />
|
||||
<fieldset class="wa-size-m">
|
||||
<legend>Medium</legend>
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
</fieldset>
|
||||
|
||||
<br />
|
||||
|
||||
<fieldset class="wa-size-l">
|
||||
<legend>Large</legend>
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
</fieldset>
|
||||
```
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
title: Select
|
||||
description: Selects allow you to choose items from a menu of predefined options.
|
||||
tags: forms
|
||||
icon: select
|
||||
component: select
|
||||
elements:
|
||||
"<select>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<label>Select
|
||||
<select id="select">
|
||||
<option value="option-1">Option 1</option>
|
||||
<option value="option-2">Option 2</option>
|
||||
<option value="option-3">Option 3</option>
|
||||
</select>
|
||||
</label>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the [appearance utilities](/docs/utilities/appearance/) to change the select's visual appearance.
|
||||
|
||||
```html {.example}
|
||||
<label>Select
|
||||
<select id="select" class="wa-filled">
|
||||
<option value="option-1">Option 1</option>
|
||||
<option value="option-2">Option 2</option>
|
||||
<option value="option-3">Option 3</option>
|
||||
</select>
|
||||
</label>
|
||||
```
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: Slider
|
||||
description: Sliders allow the user to select a single value within a given range using a slider.
|
||||
tags: forms
|
||||
layout: element
|
||||
icon: slider
|
||||
component: slider
|
||||
elements:
|
||||
"<input type=range>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<label>Select a value: <input type="range"></label>
|
||||
```
|
||||
|
||||
### 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}
|
||||
<input type="range" min="0" max="10" step="1">
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable a slider.
|
||||
|
||||
```html {.example}
|
||||
<input type="range" disabled>
|
||||
```
|
||||
|
||||
<!--
|
||||
### 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}
|
||||
<input type="range"
|
||||
style="
|
||||
--track-color-active: var(--wa-color-brand-fill-loud);
|
||||
--track-color-inactive: var(--wa-color-brand-fill-normal);
|
||||
"
|
||||
>
|
||||
```
|
||||
|
||||
### Right-to-Left languages
|
||||
|
||||
The styles adapt to right-to-left (RTL) languages as you would expect.
|
||||
|
||||
```html {.example}
|
||||
<input type="range" dir=rtl>
|
||||
```
|
||||
-->
|
||||
@@ -1,135 +0,0 @@
|
||||
---
|
||||
title: Table
|
||||
description: 'Table styles apply your Web Awesome theme to the HTML table content. Tables structure data in rows and columns, making it easy to look up information in a complex data set.'
|
||||
tags: content
|
||||
elements:
|
||||
"<table>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<table>
|
||||
<caption>I'm just a table</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column 1</th>
|
||||
<th>Column 2</th>
|
||||
<th>Column 3</th>
|
||||
<th>Column 4</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
## Alternating Rows
|
||||
|
||||
You can use the `wa-zebra-rows` class to add alternating row colors to your table:
|
||||
|
||||
```html {.example}
|
||||
<table class="wa-zebra-rows">
|
||||
<caption>I'm just a table</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column 1</th>
|
||||
<th>Column 2</th>
|
||||
<th>Column 3</th>
|
||||
<th>Column 4</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
You can use [color utility classes](/docs/utilities/colors) to apply different colors to your table:
|
||||
|
||||
```html {.example}
|
||||
<table class="wa-zebra-rows wa-brand">
|
||||
<caption>I'm just a table</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column 1</th>
|
||||
<th>Column 2</th>
|
||||
<th>Column 3</th>
|
||||
<th>Column 4</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
<td>Cell</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
title: Textarea
|
||||
description: Textareas collect data from the user and allow multiple lines of text.
|
||||
tags: forms
|
||||
icon: textarea
|
||||
component: textarea
|
||||
elements:
|
||||
"<textarea>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<label>Textarea <textarea></textarea></label>
|
||||
```
|
||||
|
||||
### Placeholders
|
||||
|
||||
Use the `placeholder` attribute to add a placeholder.
|
||||
|
||||
```html {.example}
|
||||
<textarea placeholder="Type something"></textarea>
|
||||
```
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the [appearence utilities](/docs/utilities/appearance/) to change the textarea's visual appearance.
|
||||
|
||||
```html {.example}
|
||||
<textarea placeholder="Type something" class="wa-filled"></textarea>
|
||||
```
|
||||
|
||||
### Expand with Content
|
||||
|
||||
You can use `field-sizing: content` in [browsers that support it](https://caniuse.com/mdn-css_properties_field-sizing) to make the textarea grow as the user types:
|
||||
|
||||
```html {.example}
|
||||
<textarea placeholder="Type something" style="field-sizing: content"></textarea>
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,369 +0,0 @@
|
||||
---
|
||||
title: Blog
|
||||
description: TODO
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
|
||||
### Hero
|
||||
```html{.example}
|
||||
<wa-carousel pagination>
|
||||
<wa-carousel-item>
|
||||
<a href="#" class="hero-link">
|
||||
<div style="background: #fe53a0;">
|
||||
|
||||
</div>
|
||||
<div style="background: gray;">
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest (by Thomas Kelly on Unsplash)"
|
||||
src="/assets/examples/carousel/blog-carousel-5.jpg"
|
||||
/>
|
||||
</div>
|
||||
<h2><span>Do you see any Teletubbies in here?</span></h2>
|
||||
</a>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<a href="#" class="hero-link">
|
||||
<div style="background: #5a90f3;">
|
||||
|
||||
</div>
|
||||
<div style="background: gray;">
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest (by Thomas Kelly on Unsplash)"
|
||||
src="/assets/examples/carousel/blog-carousel-1.jpg"
|
||||
/>
|
||||
</div>
|
||||
<h2><span>The path of the righteous man is beset on all sides</span></h2>
|
||||
</a>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<a href="#" class="hero-link">
|
||||
<div style="background: #8c431e;">
|
||||
|
||||
</div>
|
||||
<div style="background: gray;">
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest (by Thomas Kelly on Unsplash)"
|
||||
src="/assets/examples/carousel/blog-carousel-2.jpg"
|
||||
/>
|
||||
</div>
|
||||
<h2><span>Article Title</span></h2>
|
||||
</a>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<a href="#" class="hero-link">
|
||||
<div style="background: #37b3e6;">
|
||||
|
||||
</div>
|
||||
<div style="background: gray;">
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest (by Thomas Kelly on Unsplash)"
|
||||
src="/assets/examples/carousel/blog-carousel-3.jpg"
|
||||
/>
|
||||
</div>
|
||||
<h2><span>Article Title</span></h2>
|
||||
</a>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<a href="#" class="hero-link">
|
||||
<div style="background: #f993d6;">
|
||||
|
||||
</div>
|
||||
<div style="background: gray;">
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest (by Thomas Kelly on Unsplash)"
|
||||
src="/assets/examples/carousel/blog-carousel-4.jpg"
|
||||
/>
|
||||
</div>
|
||||
<h2><span>Article Title</span></h2>
|
||||
</a>
|
||||
</wa-carousel-item>
|
||||
|
||||
</wa-carousel>
|
||||
<style>
|
||||
.hero-link {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
h2 {
|
||||
position: absolute;
|
||||
color: white;
|
||||
top: 25%;
|
||||
left: 15%;
|
||||
width: 200px;
|
||||
padding: .5rem;
|
||||
line-height: 1.15;
|
||||
|
||||
span {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
div:first-of-type {
|
||||
width: 30%;
|
||||
}
|
||||
div:last-of-type {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Newsletter signup
|
||||
```html{.example}
|
||||
<wa-card class="news-letter-signup">
|
||||
<h2>Subscribe to our Newsletter</h2>
|
||||
<p>To get the latest and most quality design resources</p>
|
||||
<div class="subscribe-input"> <wa-input></wa-input><wa-button>Subscribe</wa-button></div>
|
||||
</wa-card>
|
||||
<style>
|
||||
.news-letter-signup {
|
||||
display: block;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.subscribe-input {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
wa-input {
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
wa-button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Posts List
|
||||
```html{.example}
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
Recent Articles
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="post-list">
|
||||
<div class="post-list-item" style="display: flex; align-items: center;">
|
||||
<img src="/assets/images/patterns/flower-crop-1.jpg" />
|
||||
<div class="post-list-item-info" style="display: flex;flex-direction: column;">
|
||||
<span style="font-size: small;"> <wa-icon fixed-width name="mug-hot"></wa-icon> Lifestyle</span>
|
||||
<span style="font-size: larger;font-weight: 600;">Your bones don't break</span>
|
||||
<span style="font-size: small;font-style: italic; font-weight: 600; color: var(--wa-color-text-quiet)">Jules</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-list-item" style="display: flex; align-items: center; flex-direction: row-reverse;justify-content: flex-end">
|
||||
<img class="last" src="/assets/images/patterns/flower-crop-2.jpg" />
|
||||
<div class="post-list-item-info" style="display: flex;flex-direction: column; margin-right: 1rem;">
|
||||
<span style="font-size: small;"><wa-icon fixed-width name="user-nurse"> </wa-icon>Health</span>
|
||||
<span style="font-size: larger;font-weight: 600;">That's clear. Your cells react to bacteria</span>
|
||||
<span style="font-size: small;font-style: italic; font-weight: 600; color: var(--wa-color-text-quiet)">Mr. Glass</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-list-item" style="display: flex; align-items: center; flex-direction: row-reverse;justify-content: flex-end">
|
||||
<img style="display:none;" src="#"/>
|
||||
<div class="post-list-item-info" style="display: flex;flex-direction: column;">
|
||||
<span style="font-size: small;"><wa-icon fixed-width name="football"></wa-icon> Sports</span>
|
||||
<span style="font-size: larger;font-weight: 600;">Do you see any Teletubbies in here?</span>
|
||||
<span style="font-size: small;font-style: italic; font-weight: 600; color: var(--wa-color-text-quiet)">Nick Fury</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-list-item" style="display: flex; align-items: center;">
|
||||
<img src="/assets/images/patterns/flower-crop-3.jpg" />
|
||||
<div class="post-list-item-info" style="display: flex;flex-direction: column;">
|
||||
<span style="font-size: small;">Lifestyle</span>
|
||||
<span style="font-size: larger;font-weight: 600;">Your bones don't break</span>
|
||||
<span style="font-size: small;font-style: italic; font-weight: 600; color: var(--wa-color-text-quiet)">Jules</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-list-item" style="display: flex; align-items: center;">
|
||||
<img src="/assets/images/patterns/flower-crop-1.jpg" />
|
||||
<div class="post-list-item-info" style="display: flex;flex-direction: column;">
|
||||
<span style="font-size: small;">Lifestyle</span>
|
||||
<span style="font-size: larger;font-weight: 600;">Your bones don't break</span>
|
||||
<span style="font-size: small;font-style: italic; font-weight: 600; color: var(--wa-color-text-quiet)">Jules</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
<style>
|
||||
.post-list {
|
||||
.post-list-item {
|
||||
border-bottom: 1px solid var(--wa-color-surface-border);
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
img {
|
||||
margin-right: 1rem;
|
||||
object-fit: cover;
|
||||
min-width: 50px;
|
||||
min-height: 50px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
}
|
||||
img.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.post-list-item-info span:first-of-type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.post-list-item-info span wa-icon {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
.post-list-item:last-of-type {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Related Posts
|
||||
```html{.example}
|
||||
<wa-card with-image with-footer class="card-overview">
|
||||
<img
|
||||
slot="image"
|
||||
src="https://plus.unsplash.com/premium_photo-1661382011487-cd3d6b1d9dff?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w1OTAyOTl8MHwxfGFsbHx8fHx8fHx8fDE3MTg2NDc0ODd8&ixlib=rb-4.0.3&q=80&w=1080"
|
||||
alt="A kitten sits patiently between a terracotta pot and decorative grasses."
|
||||
/>
|
||||
|
||||
<strong>Color Advancements</strong><br />
|
||||
Lot of new and exciting features in web colors<br />
|
||||
<small>2d ago</small>
|
||||
|
||||
<div slot="footer">
|
||||
<wa-button variant="brand" pill>Read More</wa-button>
|
||||
|
||||
</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>
|
||||
|
||||
```
|
||||
### Article footer
|
||||
```html{.example}
|
||||
<div class="article-footer">
|
||||
<div class="article-tags">
|
||||
<a href="#"><wa-tag size="medium" pill>UX</wa-tag></a>
|
||||
<a href="#"><wa-tag size="medium" pill>Product Design</wa-tag></a>
|
||||
<a href="#"><wa-tag size="medium" pill>Design</wa-tag></a>
|
||||
<a href="#"><wa-tag size="medium" pill>Prototyping</wa-tag></a>
|
||||
</div>
|
||||
<div class="article-actions">
|
||||
<wa-icon-button name="hands-clapping"></wa-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Social Share
|
||||
|
||||
### Vertical
|
||||
```html{.example}
|
||||
<wa-card class="social-share-vertical" style="--border-radius: 4rem;">
|
||||
<wa-icon-button name="facebook" family="brands" variant="solid" label="Edit" href="https://example.com/"></wa-icon-button>
|
||||
<wa-icon-button name="x-twitter" family="brands" variant="solid" label="Edit" href="https://example.com/"></wa-icon-button>
|
||||
<wa-icon-button name="threads" family="brands" variant="solid" label="Edit" href="https://example.com/"></wa-icon-button>
|
||||
<wa-icon-button name="mastodon" family="brands" variant="solid" label="Edit" href="https://example.com/"></wa-icon-button>
|
||||
<wa-icon-button name="paper-plane" family="solid" variant="solid" label="Edit" href="https://example.com/"></wa-icon-button>
|
||||
</wa-card>
|
||||
<style>
|
||||
.social-share-vertical {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
|
||||
wa-icon-button {
|
||||
font-size: 2.5rem;
|
||||
display: block;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
wa-icon-button:last-of-type {
|
||||
margin-bottom: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Horizontal
|
||||
```html{.example}
|
||||
<wa-card with-header with-footer class="social-share-horizontal">
|
||||
<div slot="header">
|
||||
Share this Article
|
||||
</div>
|
||||
<wa-icon-button name="facebook" family="brands" variant="solid" label="Edit" style="--background: #1877f225; --color: #1877f2"></wa-icon-button>
|
||||
<wa-icon-button name="x-twitter" family="brands" variant="solid" label="Edit" style="--background: #00000025; --color: #000000"></wa-icon-button>
|
||||
<wa-icon-button name="threads" family="brands" variant="solid" label="Edit" style="--background: #c32aa325; --color: #c32aa3"></wa-icon-button>
|
||||
<wa-icon-button name="mastodon" family="brands" variant="solid" label="Edit" style="--background: #6364ff25; --color: #6364ff"></wa-icon-button>
|
||||
|
||||
<wa-icon-button name="instagram" family="brands" variant="solid" label="Edit" style="--background: #c32aa325; --color: #c32aa3"></wa-icon-button>
|
||||
|
||||
<wa-icon-button name="pinterest" family="brands" variant="solid" label="Edit" style="--background: #bd081c25; --color: #bd081c"></wa-icon-button>
|
||||
<wa-icon-button name="linkedin" family="brands" variant="solid" label="Edit" style="--background: #0a66c225; --color: #0a66c2"></wa-icon-button>
|
||||
<div slot="footer">
|
||||
<div class="share-input">
|
||||
<wa-input value="https://fontawesome.com"></wa-input>
|
||||
<wa-button variant="brand"> <wa-icon slot="prefix" name="link" variant="solid"></wa-icon>Copy</wa-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</wa-card>
|
||||
<style>
|
||||
.social-share-horizontal {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
width: fit-content;
|
||||
|
||||
wa-icon-button {
|
||||
--background: transparent;
|
||||
--color: initial;
|
||||
font-size: 1.5rem;
|
||||
border-radius: .25rem;
|
||||
background: var(--background);
|
||||
}
|
||||
wa-icon-button::part(base) {
|
||||
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
.share-input {
|
||||
display: flex;
|
||||
|
||||
wa-input {
|
||||
--border-radius: var(--wa-form-control-border-radius) 0 0 var(--wa-form-control-border-radius);
|
||||
}
|
||||
wa-button {
|
||||
--border-radius: 0 var(--wa-form-control-border-radius) var(--wa-form-control-border-radius) 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
```
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
title: Business
|
||||
description: TODO
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user