Compare commits
2058 Commits
v2.0.0-bet
...
current
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e6e0368a4 | ||
|
|
7e4d4c3c98 | ||
|
|
b5ef3191b7 | ||
|
|
f30481e229 | ||
|
|
ae010c333b | ||
|
|
43d1f9ee7a | ||
|
|
ec17e8736d | ||
|
|
44b27e791e | ||
|
|
02385027db | ||
|
|
b311072d9b | ||
|
|
87ac077b0a | ||
|
|
87837df35c | ||
|
|
5d72bbd162 | ||
|
|
a4fc1c5b44 | ||
|
|
539eaded73 | ||
|
|
93b2e78092 | ||
|
|
402a00dcd3 | ||
|
|
b63368d5f6 | ||
|
|
74c6d3ee36 | ||
|
|
621aa4362b | ||
|
|
c8919ad11f | ||
|
|
fad76dd1a2 | ||
|
|
b2f6499b87 | ||
|
|
9520e850dd | ||
|
|
4ee5271a83 | ||
|
|
d8de7bcc51 | ||
|
|
7ee31be6d6 | ||
|
|
9cb5ba7ac1 | ||
|
|
c380368b61 | ||
|
|
e298f7e5f4 | ||
|
|
c743561c25 | ||
|
|
e73e32fb71 | ||
|
|
b09a48bec4 | ||
|
|
aeef986cf5 | ||
|
|
409ac96ddf | ||
|
|
6f08f50639 | ||
|
|
8fc5f598d0 | ||
|
|
1383ea3fe8 | ||
|
|
f8c37e0d14 | ||
|
|
cf543ef335 | ||
|
|
a3450a7d83 | ||
|
|
e80b2c9fb9 | ||
|
|
8d617fb98c | ||
|
|
a6e225e47c | ||
|
|
e21943f4fb | ||
|
|
c36df5ecc1 | ||
|
|
458def7830 | ||
|
|
b5d800f07a | ||
|
|
6551a6330b | ||
|
|
cb5f670909 | ||
|
|
5b6c1632bd | ||
|
|
bf15f2fb8a | ||
|
|
31ef2f7929 | ||
|
|
8aab94f184 | ||
|
|
b7acb27c98 | ||
|
|
dcbbc55f28 | ||
|
|
81dfcc2eae | ||
|
|
16f3e256b0 | ||
|
|
1bf09f20aa | ||
|
|
75b2da9eab | ||
|
|
9736f053d9 | ||
|
|
d0b710c26d | ||
|
|
5b83d4d1b0 | ||
|
|
89f0f4a02c | ||
|
|
a067ccb9e0 | ||
|
|
1ccea42cca | ||
|
|
0f90dd0f54 | ||
|
|
262cbc9a22 | ||
|
|
3a61d20d93 | ||
|
|
95f4f87eb8 | ||
|
|
5b3cc0d492 | ||
|
|
0de39a8163 | ||
|
|
879fd7a224 | ||
|
|
50af138424 | ||
|
|
9d592f4e08 | ||
|
|
5016d27af7 | ||
|
|
7218a19357 | ||
|
|
33d2d4368f | ||
|
|
cca40ca710 | ||
|
|
c6281859fd | ||
|
|
956271880d | ||
|
|
201ff4efc5 | ||
|
|
f954233bda | ||
|
|
8267968b76 | ||
|
|
1e243e4257 | ||
|
|
0b6c3a46cf | ||
|
|
a2e58b7696 | ||
|
|
119d299657 | ||
|
|
e8634e4178 | ||
|
|
2e2a683d11 | ||
|
|
414197acc9 | ||
|
|
8fd01e1eda | ||
|
|
e1ca7d1f59 | ||
|
|
f84d6939bd | ||
|
|
82446e2114 | ||
|
|
a4f0ae9088 | ||
|
|
fe3906f766 | ||
|
|
c9e644f3fc | ||
|
|
8ffbd02db7 | ||
|
|
e88d57d17d | ||
|
|
5f4de6d9f5 | ||
|
|
2cce87deeb | ||
|
|
630b5b19a0 | ||
|
|
2ce1451a9f | ||
|
|
2d1badba96 | ||
|
|
1b5db078a7 | ||
|
|
91095bd63a | ||
|
|
d9703a64fd | ||
|
|
4c22e72390 | ||
|
|
d05b8fca20 | ||
|
|
afca2ad2e0 | ||
|
|
b2aa854d98 | ||
|
|
ba642a0886 | ||
|
|
287fff7cf1 | ||
|
|
136ecae4a6 | ||
|
|
cac772d5e6 | ||
|
|
e1dedcb1b5 | ||
|
|
c4901eca68 | ||
|
|
a001c2d12b | ||
|
|
c4c622eabd | ||
|
|
1ae018bedd | ||
|
|
c37c71d8fd | ||
|
|
24929e27c1 | ||
|
|
33a8d92aec | ||
|
|
32d21fa560 | ||
|
|
347d8b7f79 | ||
|
|
8f9c15913b | ||
|
|
60d7f688eb | ||
|
|
15f914914c | ||
|
|
2914475821 | ||
|
|
8e831aa3e7 | ||
|
|
985d4585c4 | ||
|
|
05b1212657 | ||
|
|
854db13bd7 | ||
|
|
4ddf80459a | ||
|
|
89fc2ff643 | ||
|
|
d7145f1f84 | ||
|
|
441a957432 | ||
|
|
67cbb85682 | ||
|
|
0005d16a06 | ||
|
|
ca5ab03cd4 | ||
|
|
c9e30022df | ||
|
|
c167bdd80f | ||
|
|
b9f62bb1bc | ||
|
|
a01b2cf8a2 | ||
|
|
f4b2623c8f | ||
|
|
af8426579e | ||
|
|
6b9ba9becf | ||
|
|
c6cc7b6983 | ||
|
|
0e869ec18d | ||
|
|
1b347874ef | ||
|
|
ff5b1e8573 | ||
|
|
73ad76a2fa | ||
|
|
aadcb486a9 | ||
|
|
4c854d64a7 | ||
|
|
c2e02d34ad | ||
|
|
8c8977549c | ||
|
|
24ef154d42 | ||
|
|
b5a3045bae | ||
|
|
7404e496cb | ||
|
|
5ba2c7eeec | ||
|
|
514a7f3d51 | ||
|
|
15474b83b1 | ||
|
|
a5f1bc6c82 | ||
|
|
834d44e0e4 | ||
|
|
c070149ae6 | ||
|
|
b0b6ea943e | ||
|
|
65b72217ea | ||
|
|
c4c2e8e3a9 | ||
|
|
47018d61cd | ||
|
|
d18db9adfa | ||
|
|
41913c8c58 | ||
|
|
68b982a744 | ||
|
|
a582302a79 | ||
|
|
bd3b2c93ee | ||
|
|
4704d63791 | ||
|
|
415a1477bb | ||
|
|
f363d5e187 | ||
|
|
efb0ee9c48 | ||
|
|
96daee5e1a | ||
|
|
d236206cce | ||
|
|
1ef8e1cf73 | ||
|
|
dc63f858b0 | ||
|
|
b8a3952153 | ||
|
|
4b2a62f660 | ||
|
|
08c074e44b | ||
|
|
d1953b0215 | ||
|
|
b268d7dd8e | ||
|
|
90e56e2f07 | ||
|
|
45ddaa4d38 | ||
|
|
0de54b163a | ||
|
|
620b86cddb | ||
|
|
32d0ac4147 | ||
|
|
a16733eb93 | ||
|
|
b67eef484c | ||
|
|
5166964659 | ||
|
|
e72c2df6d2 | ||
|
|
cdafb3870c | ||
|
|
20abf21791 | ||
|
|
482d155af4 | ||
|
|
ece23c727e | ||
|
|
b7726cd514 | ||
|
|
c31fe1ed35 | ||
|
|
9e034810d9 | ||
|
|
217aabe55a | ||
|
|
1dea2f384e | ||
|
|
c24edec6b9 | ||
|
|
add09ca5b8 | ||
|
|
57bd3632e8 | ||
|
|
6f44b6ffa6 | ||
|
|
ca8ba2d16b | ||
|
|
c37e4ba6b5 | ||
|
|
82cc778a0f | ||
|
|
5085ef831b | ||
|
|
4721bd117b | ||
|
|
57b13d848a | ||
|
|
e01a43f01e | ||
|
|
ec92351acf | ||
|
|
8c44eb75d5 | ||
|
|
aa48566aef | ||
|
|
7cbb26cbdb | ||
|
|
b8b6175a64 | ||
|
|
de5ad1b1b9 | ||
|
|
0866785495 | ||
|
|
947b3a9ec4 | ||
|
|
6db27ca51f | ||
|
|
f966ba97d7 | ||
|
|
1af711bc89 | ||
|
|
c71da4a075 | ||
|
|
d609fa87b4 | ||
|
|
dd16b0f65f | ||
|
|
6144e5eff4 | ||
|
|
c4db99f5a3 | ||
|
|
21431b0e56 | ||
|
|
136e6bc915 | ||
|
|
05aeb78b01 | ||
|
|
22010a1f9b | ||
|
|
e0fd6b210e | ||
|
|
be1c38f0e5 | ||
|
|
b1bdedd3a3 | ||
|
|
429b47963b | ||
|
|
466c8a0883 | ||
|
|
3a212030c0 | ||
|
|
7f1ac48f5f | ||
|
|
9c3e344ae0 | ||
|
|
db147e77b0 | ||
|
|
0384b03528 | ||
|
|
fc06de7b11 | ||
|
|
5ada0a7093 | ||
|
|
f136b8eb12 | ||
|
|
56a160464f | ||
|
|
3dc9430932 | ||
|
|
62b4525321 | ||
|
|
afa69b4f9c | ||
|
|
102f46d185 | ||
|
|
9c5e184d82 | ||
|
|
385b5451c8 | ||
|
|
0e7487257b | ||
|
|
eab0e3219f | ||
|
|
cf89c901a2 | ||
|
|
902b08cc0f | ||
|
|
caf9a09efa | ||
|
|
65734dc993 | ||
|
|
0f02fffc3a | ||
|
|
931ecad8c5 | ||
|
|
c137f83df6 | ||
|
|
d3a0a38dce | ||
|
|
b76af1aa21 | ||
|
|
5cf6a37ee2 | ||
|
|
63194abf93 | ||
|
|
e196b0915a | ||
|
|
d2369d1de8 | ||
|
|
a9bbcc5556 | ||
|
|
8d9430e7a2 | ||
|
|
0411754949 | ||
|
|
91ffaa1a2d | ||
|
|
ae9972a91a | ||
|
|
478fa6f2bb | ||
|
|
6a52a04591 | ||
|
|
a8f87e0d5e | ||
|
|
cbc96fdf5c | ||
|
|
b4d24dd9af | ||
|
|
4b66cc2acb | ||
|
|
3766d5ce27 | ||
|
|
4b7d686754 | ||
|
|
b948a07a4d | ||
|
|
6d3505aefa | ||
|
|
b22650ff51 | ||
|
|
23a7f65b49 | ||
|
|
f4fba8eab4 | ||
|
|
1734bf54a7 | ||
|
|
88efec7815 | ||
|
|
e335189bb8 | ||
|
|
d03ca4ab95 | ||
|
|
257407758f | ||
|
|
2443c046aa | ||
|
|
d710eb3947 | ||
|
|
7b2f6f230d | ||
|
|
07cb6070cc | ||
|
|
bd7dc2a7be | ||
|
|
db931c12be | ||
|
|
765b311a08 | ||
|
|
ce198d9c0b | ||
|
|
8f5893931b | ||
|
|
221be48589 | ||
|
|
234ff2619d | ||
|
|
b37be46ba3 | ||
|
|
6e2ea508db | ||
|
|
0e6e2abd28 | ||
|
|
db1bdfbf65 | ||
|
|
7bf0f647b3 | ||
|
|
44628889fe | ||
|
|
df25f8617b | ||
|
|
ad2099a27f | ||
|
|
708127f96d | ||
|
|
9deb51e95a | ||
|
|
67852ea657 | ||
|
|
7240f4f8f4 | ||
|
|
17ee89a5e8 | ||
|
|
f2177dccaf | ||
|
|
6aaf17b81a | ||
|
|
d113d13792 | ||
|
|
ab9cb5f185 | ||
|
|
76fd7aa28d | ||
|
|
8f17bf4e9d | ||
|
|
0f0f71af9b | ||
|
|
e624701022 | ||
|
|
4cedfc3201 | ||
|
|
d88d9fc81a | ||
|
|
051baa4ff5 | ||
|
|
57c3d7009b | ||
|
|
a27fd4d2e9 | ||
|
|
79ac425e2b | ||
|
|
857f318f9c | ||
|
|
c0966bf767 | ||
|
|
86cecc9e30 | ||
|
|
ec036d8e61 | ||
|
|
77b25f4581 | ||
|
|
3168a1acf8 | ||
|
|
a8d59b3329 | ||
|
|
17160e3bed | ||
|
|
5990fbd000 | ||
|
|
954d78dcd1 | ||
|
|
3ea31389dd | ||
|
|
d79799043a | ||
|
|
9f8ce58288 | ||
|
|
2371c5490f | ||
|
|
77abd42d66 | ||
|
|
218e78e947 | ||
|
|
8a1efac9b8 | ||
|
|
f9ae8327f6 | ||
|
|
7f3076d195 | ||
|
|
1fa79e64ae | ||
|
|
dde1010465 | ||
|
|
3a3a7347bc | ||
|
|
77c9750206 | ||
|
|
3d2e618be8 | ||
|
|
79feaae7fc | ||
|
|
b0f7dfb86b | ||
|
|
e1979b8f38 | ||
|
|
7e9ae32b9b | ||
|
|
480a1df246 | ||
|
|
ff798adb49 | ||
|
|
70a64262e9 | ||
|
|
5f65896150 | ||
|
|
c69db4919b | ||
|
|
a526e8a956 | ||
|
|
4970ba065e | ||
|
|
0292ed30c5 | ||
|
|
b64b1c2536 | ||
|
|
8f9eb012ba | ||
|
|
c8fd9f19d2 | ||
|
|
603aa93322 | ||
|
|
74203de094 | ||
|
|
4fa4682a45 | ||
|
|
34e0fb2fc1 | ||
|
|
50972f2b38 | ||
|
|
652ce6c9f1 | ||
|
|
8412b150b2 | ||
|
|
22b8ef4edf | ||
|
|
0865dede6f | ||
|
|
d638d811ad | ||
|
|
bc58472b7b | ||
|
|
226c856b1e | ||
|
|
a127b8722e | ||
|
|
9c573fb454 | ||
|
|
a346d18930 | ||
|
|
a32488baeb | ||
|
|
a4131caeda | ||
|
|
6c62a4f4c0 | ||
|
|
5b12de1edf | ||
|
|
f79a670ca3 | ||
|
|
fe2e2d6df5 | ||
|
|
e1ec60af62 | ||
|
|
dcbcc4c050 | ||
|
|
0eb3375bb9 | ||
|
|
c26a8810c8 | ||
|
|
872227e345 | ||
|
|
f22c529eab | ||
|
|
3430b33c3e | ||
|
|
1bc2a6ef76 | ||
|
|
5a94f5bf5b | ||
|
|
4277377189 | ||
|
|
d818980dea | ||
|
|
636f61006f | ||
|
|
d93e698baf | ||
|
|
f8d8291caa | ||
|
|
21bef1c2ea | ||
|
|
f0efb9253c | ||
|
|
cfd28f2608 | ||
|
|
a3844fe074 | ||
|
|
65e90f12f4 | ||
|
|
4335289d6a | ||
|
|
86cc721e03 | ||
|
|
4a28825ea7 | ||
|
|
19cf823da5 | ||
|
|
737b55d78d | ||
|
|
8493131db5 | ||
|
|
0d86c2af37 | ||
|
|
d6a7820a52 | ||
|
|
39ca1208f5 | ||
|
|
610a06bcb9 | ||
|
|
b8584c0581 | ||
|
|
ab19afeb66 | ||
|
|
41b5cb367f | ||
|
|
e65b09fdec | ||
|
|
15a4049a01 | ||
|
|
ce708fbba8 | ||
|
|
75bd7784fb | ||
|
|
6e092ccf7a | ||
|
|
b7b73ea3a9 | ||
|
|
9dab91e0d1 | ||
|
|
a3a802a37b | ||
|
|
358ad7bb30 | ||
|
|
0a555c53c7 | ||
|
|
b260a4dc29 | ||
|
|
1f1024f4ca | ||
|
|
9e92d92684 | ||
|
|
527bf79973 | ||
|
|
b281c5bbc1 | ||
|
|
f03de8925b | ||
|
|
776ab2c715 | ||
|
|
df967b7e84 | ||
|
|
a539058253 | ||
|
|
af70d88153 | ||
|
|
8dcffe270f | ||
|
|
c958f2e50a | ||
|
|
cedcd65c72 | ||
|
|
12f62075ad | ||
|
|
b8695b70a9 | ||
|
|
a4e371618a | ||
|
|
039ab175c3 | ||
|
|
7549e50fe4 | ||
|
|
3c2cda699e | ||
|
|
8685ddd049 | ||
|
|
c47ad40802 | ||
|
|
ef1f129b22 | ||
|
|
6bb508ef14 | ||
|
|
3596c8144d | ||
|
|
20903bb638 | ||
|
|
f45fb6848f | ||
|
|
400f9b76d5 | ||
|
|
38a9e98d9b | ||
|
|
e8fe783fb4 | ||
|
|
223ef32b70 | ||
|
|
0793a219a2 | ||
|
|
6e2856db5f | ||
|
|
6d1eb71d8e | ||
|
|
a334e53a5d | ||
|
|
3bb92c095f | ||
|
|
deec097267 | ||
|
|
873e280700 | ||
|
|
5d047f7a93 | ||
|
|
f24ab23752 | ||
|
|
44ecc8ce56 | ||
|
|
e758b1d9bb | ||
|
|
5cdbaa873d | ||
|
|
e9aca6cedb | ||
|
|
7c3896ed42 | ||
|
|
93158e8e90 | ||
|
|
5f9bbdfa06 | ||
|
|
3a0f486e98 | ||
|
|
29c671c0f4 | ||
|
|
88c4bef5e7 | ||
|
|
6066bc468b | ||
|
|
efd944d822 | ||
|
|
4a3f2caf59 | ||
|
|
511182b41b | ||
|
|
1088a51ed5 | ||
|
|
e3e0842bdd | ||
|
|
e4c908b08b | ||
|
|
f86578a213 | ||
|
|
3c2f5ec48e | ||
|
|
fec7ef17aa | ||
|
|
29ff99dd76 | ||
|
|
6b9b410bdc | ||
|
|
b45a9d55ca | ||
|
|
7ce079b7a1 | ||
|
|
b0ba9ff14f | ||
|
|
f665bf984b | ||
|
|
ac429a62c0 | ||
|
|
dc909d10b6 | ||
|
|
aa65077b12 | ||
|
|
7e37c51856 | ||
|
|
6e26daf804 | ||
|
|
25c2d2d5bf | ||
|
|
edc9e69f30 | ||
|
|
2e7ac38678 | ||
|
|
1a68c825c0 | ||
|
|
2cbdeeade0 | ||
|
|
79624f63ed | ||
|
|
01a8ec36ec | ||
|
|
60324885ed | ||
|
|
0c2f43b837 | ||
|
|
0df27cf730 | ||
|
|
68ed69292c | ||
|
|
62c58b3a8c | ||
|
|
1fbb809057 | ||
|
|
e2d2f5d670 | ||
|
|
acef0da2c1 | ||
|
|
3c66d2ab99 | ||
|
|
31f16c4680 | ||
|
|
8056379fdd | ||
|
|
9a6b9a7841 | ||
|
|
02fc39ebe0 | ||
|
|
a90b22c05d | ||
|
|
f5dd4f2aca | ||
|
|
d5b3489b22 | ||
|
|
8ee5f19184 | ||
|
|
d0a32d48b1 | ||
|
|
bf527437a0 | ||
|
|
ae3070ac45 | ||
|
|
6af68343a7 | ||
|
|
48ccc95dd9 | ||
|
|
c6a6a77bbd | ||
|
|
e632b51eb8 | ||
|
|
c8e633c4a1 | ||
|
|
724f4a59db | ||
|
|
041364fb7d | ||
|
|
fbcb4d8dbd | ||
|
|
27a6b4a8c9 | ||
|
|
0d50749ec8 | ||
|
|
c814e9e94e | ||
|
|
0e957c0cd4 | ||
|
|
b330657e0a | ||
|
|
a0fce64fd9 | ||
|
|
b183a04fba | ||
|
|
7645b997b2 | ||
|
|
d81e2f1470 | ||
|
|
f50fe72df2 | ||
|
|
dcca64a986 | ||
|
|
c216cfe0fd | ||
|
|
192f15e3b7 | ||
|
|
01be3daf6d | ||
|
|
d36eec5637 | ||
|
|
121464fa2d | ||
|
|
ee0254e822 | ||
|
|
27f634402c | ||
|
|
67fbe3b34e | ||
|
|
164ebce990 | ||
|
|
571ae704e0 | ||
|
|
ad305fb653 | ||
|
|
fc0541ce53 | ||
|
|
c8555f448c | ||
|
|
96e41198ec | ||
|
|
57064aef4d | ||
|
|
cf200aa58a | ||
|
|
388a4f85a4 | ||
|
|
5f8556b1b2 | ||
|
|
e411b57124 | ||
|
|
0120e7429d | ||
|
|
377dbe28eb | ||
|
|
b25b1d5750 | ||
|
|
0e1b792bf7 | ||
|
|
417f0d17c9 | ||
|
|
d9252fe755 | ||
|
|
c5555ab5fe | ||
|
|
eb61dc7d91 | ||
|
|
a4c522f090 | ||
|
|
a8fe8c3e71 | ||
|
|
87000306c0 | ||
|
|
ae07b7d0a8 | ||
|
|
626b76610f | ||
|
|
b4a1e1b0c9 | ||
|
|
913243f8c1 | ||
|
|
563ed81984 | ||
|
|
fcbf339a86 | ||
|
|
70585e1d2a | ||
|
|
479e568296 | ||
|
|
a473e41ab3 | ||
|
|
92f6a2d8e9 | ||
|
|
06dc5740bf | ||
|
|
fe524e0fac | ||
|
|
ea7de2eb70 | ||
|
|
b8d02537a6 | ||
|
|
24744ef8c5 | ||
|
|
69997466be | ||
|
|
f7d7fdf5b1 | ||
|
|
c0013c5639 | ||
|
|
935040204f | ||
|
|
2ffbf9b017 | ||
|
|
0f67b9a9d1 | ||
|
|
c5dee51233 | ||
|
|
b07238d536 | ||
|
|
e2a65c28f4 | ||
|
|
1f457cdde0 | ||
|
|
46fda5f0a6 | ||
|
|
e22c2f839b | ||
|
|
5bff912162 | ||
|
|
f3010cecbe | ||
|
|
2dc275defd | ||
|
|
9f79445292 | ||
|
|
10cb26b81e | ||
|
|
3722e0ad91 | ||
|
|
f28a0ec743 | ||
|
|
a42b393bf1 | ||
|
|
41f50777bd | ||
|
|
6afc3ba12e | ||
|
|
d8b7040a9e | ||
|
|
316d8b52b6 | ||
|
|
59cd70ae6f | ||
|
|
6d9c8561fb | ||
|
|
edb8a92838 | ||
|
|
da3ffe9a60 | ||
|
|
e2b791dee8 | ||
|
|
9178be576b | ||
|
|
752f5cff55 | ||
|
|
3675787ddd | ||
|
|
6284ed0347 | ||
|
|
1ff05c4b3d | ||
|
|
066abe4e52 | ||
|
|
e9134ddcf6 | ||
|
|
0237851aa1 | ||
|
|
b7b2d9265a | ||
|
|
1841251fdf | ||
|
|
b797803a2b | ||
|
|
b1e48406f3 | ||
|
|
bcb4f2267b | ||
|
|
c951661b58 | ||
|
|
4ca51cf11e | ||
|
|
41bd61c3a5 | ||
|
|
c6df057e15 | ||
|
|
1428481a5c | ||
|
|
1c359fbea9 | ||
|
|
0329694760 | ||
|
|
936ec5a23a | ||
|
|
d291506284 | ||
|
|
3877351fdc | ||
|
|
7885572ebd | ||
|
|
2ee926023c | ||
|
|
69e557cd8c | ||
|
|
f2efa73e20 | ||
|
|
2dd57956d5 | ||
|
|
ce86a1c9f2 | ||
|
|
a0f83c3b2b | ||
|
|
80a16ee42a | ||
|
|
31b05fedd3 | ||
|
|
d3a7950483 | ||
|
|
f299621490 | ||
|
|
c62ee3e207 | ||
|
|
a313087937 | ||
|
|
3945571b20 | ||
|
|
c6a044416a | ||
|
|
d2f1b50ad0 | ||
|
|
1f1bae77dd | ||
|
|
829e22dc1e | ||
|
|
8b28ee818f | ||
|
|
afb2e3d5b4 | ||
|
|
fb0adb9ccb | ||
|
|
efea514f5a | ||
|
|
fda9bd52a3 | ||
|
|
01f8ce6b03 | ||
|
|
e10651565f | ||
|
|
35aa56d334 | ||
|
|
31e1f2fc59 | ||
|
|
ee30f7a10b | ||
|
|
a50909d474 | ||
|
|
63115d51e5 | ||
|
|
026036a14b | ||
|
|
22e09a778b | ||
|
|
488088d5f0 | ||
|
|
0c18880e5c | ||
|
|
0b0a571d17 | ||
|
|
ea9e596279 | ||
|
|
fe17c8406b | ||
|
|
e7a4a5135d | ||
|
|
ebf12860be | ||
|
|
4b81778e46 | ||
|
|
28a8a90bb1 | ||
|
|
8dab5a8f04 | ||
|
|
4ac9483213 | ||
|
|
ae3c0d72c0 | ||
|
|
83b73e823d | ||
|
|
da6ae608f1 | ||
|
|
1e39647d7f | ||
|
|
4dc92247d5 | ||
|
|
1b6f982d68 | ||
|
|
81c775ea87 | ||
|
|
09f741e930 | ||
|
|
602a863d89 | ||
|
|
3dd19a7f62 | ||
|
|
bdf890ab0d | ||
|
|
0b7eae0c20 | ||
|
|
f3e273744a | ||
|
|
7f9b0bd5a2 | ||
|
|
6579a95999 | ||
|
|
aaa8e4a01b | ||
|
|
200d4385ec | ||
|
|
50d983a1ab | ||
|
|
1e6d295746 | ||
|
|
5d128c154c | ||
|
|
6c7d7f4b7e | ||
|
|
0cc8fdb8f8 | ||
|
|
4f7d915853 | ||
|
|
61738a3f6a | ||
|
|
9061c1987a | ||
|
|
c40b3a86a9 | ||
|
|
8b2c090bac | ||
|
|
8f2a3bd8bd | ||
|
|
ade05a6262 | ||
|
|
a706e69be6 | ||
|
|
bc6a813c46 | ||
|
|
599373c24a | ||
|
|
daebd08475 | ||
|
|
a3f658938d | ||
|
|
23414fe411 | ||
|
|
c8061fdee9 | ||
|
|
857b21a6a3 | ||
|
|
48be3f46b8 | ||
|
|
66012a57c8 | ||
|
|
0e77d8a459 | ||
|
|
b559c2345a | ||
|
|
d79d7da299 | ||
|
|
b296ac08cf | ||
|
|
36e677dd6b | ||
|
|
6167993941 | ||
|
|
f9d3f0be27 | ||
|
|
7f76cacc10 | ||
|
|
96cac8da85 | ||
|
|
a788e976c9 | ||
|
|
68c1319ed5 | ||
|
|
9db6f256e5 | ||
|
|
33e19c003c | ||
|
|
337d688bd3 | ||
|
|
cc305f8957 | ||
|
|
40cb38e0a0 | ||
|
|
a0d3ac047d | ||
|
|
e399bd19a2 | ||
|
|
f64f144b4b | ||
|
|
197a0c3048 | ||
|
|
e5e6b0d74f | ||
|
|
db1c2ee5cc | ||
|
|
c6a43ba4c2 | ||
|
|
ed45f52433 | ||
|
|
2d478c36fa | ||
|
|
f140007758 | ||
|
|
f03b09a410 | ||
|
|
0d9767596a | ||
|
|
c626706e27 | ||
|
|
58b653f1ae | ||
|
|
5eeb98d39d | ||
|
|
e90b64b463 | ||
|
|
5fd682d83a | ||
|
|
49193c972f | ||
|
|
c027c0a527 | ||
|
|
8160c33aa4 | ||
|
|
7d0226e3c4 | ||
|
|
084c1dc5b5 | ||
|
|
bfa320c5b5 | ||
|
|
4e1cf11461 | ||
|
|
5b4197da2c | ||
|
|
e29b2f12fb | ||
|
|
33a41bb2e4 | ||
|
|
ab754e9409 | ||
|
|
433955acf7 | ||
|
|
55445a80a3 | ||
|
|
9a64ea0670 | ||
|
|
0ff144a787 | ||
|
|
8893045bf1 | ||
|
|
a8de02bd53 | ||
|
|
4db0aec1c2 | ||
|
|
d885087c93 | ||
|
|
065aad2e4c | ||
|
|
9027ce055a | ||
|
|
119b923522 | ||
|
|
3b4d0652c4 | ||
|
|
1301934796 | ||
|
|
a8539bae02 | ||
|
|
8121faa1d4 | ||
|
|
70766b4e68 | ||
|
|
361efd43a2 | ||
|
|
a78b9fe5bd | ||
|
|
0cba4695ba | ||
|
|
22fa81433e | ||
|
|
5458a0e8f5 | ||
|
|
0e67f85995 | ||
|
|
808003f3df | ||
|
|
46c225d50f | ||
|
|
0a3656efc5 | ||
|
|
0aca600063 | ||
|
|
38f05ff010 | ||
|
|
3d4cbbf6ba | ||
|
|
c877e16c14 | ||
|
|
acce8eb146 | ||
|
|
03fe71353a | ||
|
|
8915282082 | ||
|
|
28003ac430 | ||
|
|
f2dcad82a9 | ||
|
|
69ff4f0bbc | ||
|
|
a1c93fd30f | ||
|
|
bdf8c4e669 | ||
|
|
854e576c2c | ||
|
|
cf32064e8c | ||
|
|
1f91d4cb79 | ||
|
|
a7fdb23577 | ||
|
|
39d1bbed2c | ||
|
|
e2e152c373 | ||
|
|
aae74dbaf7 | ||
|
|
6c716db037 | ||
|
|
7c0c0fa244 | ||
|
|
ffd32e52ef | ||
|
|
27868b56e8 | ||
|
|
346f13e5a5 | ||
|
|
69547d4800 | ||
|
|
9fc4185f87 | ||
|
|
08b5da7c56 | ||
|
|
05e026876a | ||
|
|
8d0d0ac4e0 | ||
|
|
972d629883 | ||
|
|
ce12020fca | ||
|
|
29b149cd26 | ||
|
|
7de37b9315 | ||
|
|
237cda3b63 | ||
|
|
51c4abb72b | ||
|
|
3a6890af81 | ||
|
|
7cc2c89f92 | ||
|
|
bb55c93b1a | ||
|
|
a3d00a92a0 | ||
|
|
5eccce625a | ||
|
|
0c3a25d2ad | ||
|
|
d225aaa2ff | ||
|
|
c6b7c24ed7 | ||
|
|
827c36bb1d | ||
|
|
d9f48a5f2a | ||
|
|
ccbdc6c014 | ||
|
|
b6edba912b | ||
|
|
4cc5baaa0b | ||
|
|
c2bbb0e8a4 | ||
|
|
352cade421 | ||
|
|
708977acf7 | ||
|
|
bab5749788 | ||
|
|
c6d0b27f0d | ||
|
|
ee31f3f682 | ||
|
|
105bb08ee1 | ||
|
|
ca64d26d77 | ||
|
|
23b2f9335b | ||
|
|
dfdd7c75c2 | ||
|
|
156a2812ae | ||
|
|
e42beab336 | ||
|
|
098db9c3fa | ||
|
|
81d393fbc1 | ||
|
|
2696b1a9ec | ||
|
|
322f23ba56 | ||
|
|
09224041b8 | ||
|
|
326816e7b7 | ||
|
|
4117b6d219 | ||
|
|
af9905acff | ||
|
|
e0727cc72c | ||
|
|
624297f624 | ||
|
|
1996037acc | ||
|
|
8fa665d3e7 | ||
|
|
f0a3972ef6 | ||
|
|
c8f42c5bde | ||
|
|
7a6144d8c4 | ||
|
|
ea71155b8f | ||
|
|
20e9e3c320 | ||
|
|
bcf2139fe7 | ||
|
|
48f864475e | ||
|
|
32f24a881e | ||
|
|
0163edd8a3 | ||
|
|
81620f0199 | ||
|
|
d850b0f507 | ||
|
|
19b2cde0d9 | ||
|
|
87e252940d | ||
|
|
c6d30ae1b5 | ||
|
|
23bb45b1b6 | ||
|
|
70f59aa4ba | ||
|
|
237230961a | ||
|
|
b669ab7b74 | ||
|
|
040e8ce5e1 | ||
|
|
a74de59687 | ||
|
|
186f57cdde | ||
|
|
c94db27f07 | ||
|
|
578a58042b | ||
|
|
b3b3956ff5 | ||
|
|
ce2abb97e0 | ||
|
|
6fc71601dd | ||
|
|
fd3da7e773 | ||
|
|
70700b1ab5 | ||
|
|
eb9107bf2b | ||
|
|
d0820178c9 | ||
|
|
a8e8325ea7 | ||
|
|
4b9e35313d | ||
|
|
dc1394483a | ||
|
|
4b32b9461c | ||
|
|
308c8228aa | ||
|
|
d74d2dec2e | ||
|
|
c9f3497a8a | ||
|
|
8e57d0075c | ||
|
|
73c8eba269 | ||
|
|
1c0ffa7a24 | ||
|
|
014354efde | ||
|
|
13ec55ba07 | ||
|
|
d6508a1262 | ||
|
|
9ebb5c8ec7 | ||
|
|
2093568981 | ||
|
|
bd5ca9034c | ||
|
|
7ae454f8ca | ||
|
|
b9fcd09209 | ||
|
|
cf2915a591 | ||
|
|
9e625752be | ||
|
|
147d1f048b | ||
|
|
801c4f70ec | ||
|
|
bcc9081247 | ||
|
|
3919ea97e9 | ||
|
|
876078b725 | ||
|
|
c765a1df9b | ||
|
|
a1bc784bc7 | ||
|
|
d14b9e12ed | ||
|
|
ab0fdd66b4 | ||
|
|
bf730f5bd2 | ||
|
|
8c667791fa | ||
|
|
d07a8cfaea | ||
|
|
23deda2253 | ||
|
|
1c6cf769d4 | ||
|
|
2add23d5d2 | ||
|
|
26693b2256 | ||
|
|
f31d13c424 | ||
|
|
59182db564 | ||
|
|
1bae224f80 | ||
|
|
9b3240a14f | ||
|
|
860224c894 | ||
|
|
a8b2eb2bb0 | ||
|
|
cea69beca9 | ||
|
|
4b7da8f510 | ||
|
|
6d31b1d63d | ||
|
|
7b55b38aa4 | ||
|
|
bf1121d126 | ||
|
|
fb2d419ab0 | ||
|
|
7179b60499 | ||
|
|
ad00d8840e | ||
|
|
3d9fd3b889 | ||
|
|
90f4d77ed6 | ||
|
|
36d1e7c52e | ||
|
|
2a1895a125 | ||
|
|
d5a352465e | ||
|
|
088ab99d02 | ||
|
|
42ed7f5cbb | ||
|
|
66e8259421 | ||
|
|
1f34b63a2e | ||
|
|
cf3b4fa501 | ||
|
|
73c190217f | ||
|
|
b2986e89b0 | ||
|
|
2bf68e8a32 | ||
|
|
f392ab4270 | ||
|
|
eefb8f6a6b | ||
|
|
8b2ddc984b | ||
|
|
f5bcd03c3f | ||
|
|
92a73f21eb | ||
|
|
4dbc3d2c8f | ||
|
|
90aac9abe9 | ||
|
|
589021c40f | ||
|
|
1cc65b145a | ||
|
|
f6fbde3c96 | ||
|
|
caf25773f0 | ||
|
|
b904bb0736 | ||
|
|
28ecc90e7f | ||
|
|
72fb9c7293 | ||
|
|
d69712530c | ||
|
|
71a39600f5 | ||
|
|
0291d7c28d | ||
|
|
ed2417d974 | ||
|
|
85fd8a5204 | ||
|
|
6446bb1013 | ||
|
|
2f8852245e | ||
|
|
401b46bad8 | ||
|
|
ae3efaf8ae | ||
|
|
98746c86e4 | ||
|
|
268aef1711 | ||
|
|
d765cef376 | ||
|
|
23ed3d5647 | ||
|
|
1a7fbbfab4 | ||
|
|
47388d4a3f | ||
|
|
ce09869ea2 | ||
|
|
33587f51d3 | ||
|
|
ed76d8aecc | ||
|
|
33d2ec0597 | ||
|
|
b4ae6ed1aa | ||
|
|
b6839254d4 | ||
|
|
8ee811af58 | ||
|
|
f34ffdac55 | ||
|
|
d7e7ff6101 | ||
|
|
1c36a7bcd4 | ||
|
|
7a77be017e | ||
|
|
5b5c6710fe | ||
|
|
04f7d2e182 | ||
|
|
36ee3c8a70 | ||
|
|
98eec84422 | ||
|
|
bc08a4c005 | ||
|
|
41580992f6 | ||
|
|
9b7ce98ec0 | ||
|
|
864d567572 | ||
|
|
cf360b3b3f | ||
|
|
673dc29dfe | ||
|
|
849b643cfc | ||
|
|
c39c4a9e9f | ||
|
|
92c36c65cb | ||
|
|
b6f25e09d2 | ||
|
|
71119c963d | ||
|
|
ecf5ab5aad | ||
|
|
7e581e6ad7 | ||
|
|
36fa84e4b0 | ||
|
|
3fb4cba856 | ||
|
|
00f98cc505 | ||
|
|
d9f719196a | ||
|
|
4b0c7245bd | ||
|
|
ced3a2a45a | ||
|
|
e6838e0a1f | ||
|
|
9e637ce0db | ||
|
|
acbee743a0 | ||
|
|
fa179fa30b | ||
|
|
2376f75f1d | ||
|
|
ca95822bba | ||
|
|
6fbcd2158a | ||
|
|
389b78f748 | ||
|
|
99368b9fdd | ||
|
|
a5a4621e25 | ||
|
|
fe95ebaa95 | ||
|
|
01c7ca27fe | ||
|
|
96ab3146be | ||
|
|
3c920cfed2 | ||
|
|
db7caf1997 | ||
|
|
808815bdab | ||
|
|
8a8fd7f5a9 | ||
|
|
3b3cb6d61d | ||
|
|
30a45f1d14 | ||
|
|
d10f628f1d | ||
|
|
615da18dc9 | ||
|
|
be11c13f67 | ||
|
|
cb7f0aa41e | ||
|
|
b2cf3a5505 | ||
|
|
0d19c46d18 | ||
|
|
c05832db67 | ||
|
|
e76dbef5f5 | ||
|
|
25c00c80b7 | ||
|
|
012206e4d8 | ||
|
|
de9da437f1 | ||
|
|
153fe15ed3 | ||
|
|
b58374aff1 | ||
|
|
31ae084538 | ||
|
|
f980126e81 | ||
|
|
cb1ada1bd7 | ||
|
|
200d340123 | ||
|
|
5c2f4dd84e | ||
|
|
953d175b44 | ||
|
|
f52a463728 | ||
|
|
5f25049abc | ||
|
|
8edaf67197 | ||
|
|
41c1979283 | ||
|
|
9840891cdc | ||
|
|
7d22e18bfb | ||
|
|
07af6f2741 | ||
|
|
60d9819088 | ||
|
|
9549539f5d | ||
|
|
1c23daa3b1 | ||
|
|
4a6c37ae0c | ||
|
|
f1bfd58dd2 | ||
|
|
4446814114 | ||
|
|
1ae6236e90 | ||
|
|
624a8bbe71 | ||
|
|
ca876b291a | ||
|
|
c850a7eae1 | ||
|
|
5613a3cef3 | ||
|
|
d3b161fc25 | ||
|
|
7659e45cc1 | ||
|
|
8a28d66393 | ||
|
|
c8d92e41b2 | ||
|
|
9b39c90849 | ||
|
|
5c8a34696e | ||
|
|
3e5da7c25a | ||
|
|
b1e6770712 | ||
|
|
fd49fd6456 | ||
|
|
d0ff2fef35 | ||
|
|
4c3313e275 | ||
|
|
4e0bc36b02 | ||
|
|
01eb84e3a6 | ||
|
|
70c97e2ae4 | ||
|
|
c165c8e71f | ||
|
|
6dd9773f2c | ||
|
|
15dbb0a634 | ||
|
|
ce09ac2a92 | ||
|
|
425f936254 | ||
|
|
7a9e4b0e8f | ||
|
|
48f10011e1 | ||
|
|
f6d3f799dd | ||
|
|
2157f4a385 | ||
|
|
0f76d05546 | ||
|
|
293f49e178 | ||
|
|
4d2de2dd57 | ||
|
|
46dc965cd0 | ||
|
|
707aeb6d65 | ||
|
|
96c63c60a2 | ||
|
|
9539123fc3 | ||
|
|
ea07346ae6 | ||
|
|
af1e440103 | ||
|
|
0cea7d23f0 | ||
|
|
ea8c88a31a | ||
|
|
b4e5544ff8 | ||
|
|
04d534cd30 | ||
|
|
7cb247976f | ||
|
|
3cbf9e14e6 | ||
|
|
3bd6516440 | ||
|
|
e3f691fbda | ||
|
|
ae76bea220 | ||
|
|
ca81a507b6 | ||
|
|
3f2382cfdc | ||
|
|
c1ccae315f | ||
|
|
92cb4e3d29 | ||
|
|
9dd8c45c57 | ||
|
|
fa84a84a40 | ||
|
|
9e747e7c2e | ||
|
|
79306e0618 | ||
|
|
139073dc3e | ||
|
|
18d441ef2e | ||
|
|
e07058ef5a | ||
|
|
f02941445b | ||
|
|
37b172dbfd | ||
|
|
4b2fc37015 | ||
|
|
ae219c83fb | ||
|
|
e60c5c4546 | ||
|
|
f57adb33eb | ||
|
|
25821c1294 | ||
|
|
8904e9d709 | ||
|
|
35885ef59f | ||
|
|
c19eb5847a | ||
|
|
c591f1d23e | ||
|
|
fd1f76169a | ||
|
|
8814746738 | ||
|
|
7bb6c4f0c1 | ||
|
|
6c14282223 | ||
|
|
7333760ada | ||
|
|
cb0b5feef8 | ||
|
|
01369464fa | ||
|
|
c2ceaa9a3f | ||
|
|
36716508c3 | ||
|
|
d683a76a49 | ||
|
|
4a0f6ef8af | ||
|
|
92b735b7fa | ||
|
|
240db01e75 | ||
|
|
04bacccfea | ||
|
|
25b6e8c2d7 | ||
|
|
1e2ceb8252 | ||
|
|
329a5aec32 | ||
|
|
c86ae623cb | ||
|
|
ce8dbc4302 | ||
|
|
72972c76af | ||
|
|
d55813fffb | ||
|
|
1f92e96079 | ||
|
|
2cb3c1fc9f | ||
|
|
caaf2b0d1e | ||
|
|
a635e4cd30 | ||
|
|
aa336fb525 | ||
|
|
c0dc08116c | ||
|
|
a5b3334222 | ||
|
|
8fd2491b9c | ||
|
|
deea93acad | ||
|
|
ba92feee4a | ||
|
|
e6458c26d6 | ||
|
|
4befbfafc5 | ||
|
|
fc938ea3eb | ||
|
|
5e444a4f7c | ||
|
|
1250627862 | ||
|
|
a588bdc7b3 | ||
|
|
44a4d13bad | ||
|
|
7467806969 | ||
|
|
9f844a8b91 | ||
|
|
83435a47de | ||
|
|
33612590ed | ||
|
|
7475e9576c | ||
|
|
56d114f13d | ||
|
|
50f702e9f1 | ||
|
|
43a361a52d | ||
|
|
85976a1f35 | ||
|
|
167cc6862a | ||
|
|
5ca57e4110 | ||
|
|
988d09ed2a | ||
|
|
bafa5fad54 | ||
|
|
a2e816253f | ||
|
|
68603f9aed | ||
|
|
46ac480713 | ||
|
|
35cad794e9 | ||
|
|
ee1a0c2c59 | ||
|
|
6f2ded4ce8 | ||
|
|
756b86a416 | ||
|
|
4b22fd2095 | ||
|
|
368854ba41 | ||
|
|
af4d25ee37 | ||
|
|
cb460ee7ba | ||
|
|
300cbd090f | ||
|
|
e32c15204c | ||
|
|
b8b68af316 | ||
|
|
0a5fb5e9e7 | ||
|
|
99f475b56f | ||
|
|
0b1ff75f1b | ||
|
|
ca653cd245 | ||
|
|
84563bdcd4 | ||
|
|
49215503a6 | ||
|
|
9a8aafc189 | ||
|
|
347808e86c | ||
|
|
f34960d82a | ||
|
|
c6165ee502 | ||
|
|
f676949460 | ||
|
|
73cfaee5ec | ||
|
|
a6983d2d99 | ||
|
|
43e4a5b250 | ||
|
|
7b2c027c26 | ||
|
|
e2069889b4 | ||
|
|
499b3f1ff4 | ||
|
|
b4713f9bc6 | ||
|
|
5132ee3559 | ||
|
|
2a702d1cb5 | ||
|
|
23a4859e0e | ||
|
|
ae94aecdd7 | ||
|
|
a6edf34a92 | ||
|
|
c26b1335f5 | ||
|
|
fdeb7689d7 | ||
|
|
2d5e765193 | ||
|
|
29d82736a7 | ||
|
|
e493c65b12 | ||
|
|
ada6f533b7 | ||
|
|
5ea578b8c8 | ||
|
|
67cb6abe56 | ||
|
|
3ff6a02391 | ||
|
|
dde83e7f67 | ||
|
|
fe527ff5dd | ||
|
|
4f99bbace9 | ||
|
|
ad0ac34f9d | ||
|
|
ba3306b497 | ||
|
|
7ff8b34e80 | ||
|
|
fc4b1464b9 | ||
|
|
485347e20b | ||
|
|
34676105a1 | ||
|
|
339eacb01f | ||
|
|
27a047976b | ||
|
|
3289129782 | ||
|
|
afa715c860 | ||
|
|
ae0eddfb25 | ||
|
|
13b2f8018d | ||
|
|
eb66ce2d4b | ||
|
|
ad16b0b5a6 | ||
|
|
c81f519b7c | ||
|
|
6450c0bee6 | ||
|
|
87d1db760f | ||
|
|
1c903f4d26 | ||
|
|
b84a8bc76a | ||
|
|
e77f059685 | ||
|
|
4e108d434a | ||
|
|
0f626bebbf | ||
|
|
cff57b6562 | ||
|
|
5cb9212fa4 | ||
|
|
c2910d742a | ||
|
|
e8174f7462 | ||
|
|
f245d97fc0 | ||
|
|
469c03f5e7 | ||
|
|
3144c45688 | ||
|
|
99e746ba81 | ||
|
|
7527b9f9b1 | ||
|
|
5e6add724d | ||
|
|
a5cd9a4968 | ||
|
|
c5fe481c33 | ||
|
|
38b0ace0ca | ||
|
|
1819f38ccb | ||
|
|
4834ecbddb | ||
|
|
3aa5fdba55 | ||
|
|
8ae987ea69 | ||
|
|
d77f543c8f | ||
|
|
517415f743 | ||
|
|
b9770e7e73 | ||
|
|
93cb8a2411 | ||
|
|
4866d2d190 | ||
|
|
80a9d05ff3 | ||
|
|
1db7aa3f26 | ||
|
|
ff1e11022d | ||
|
|
b55bf31fdc | ||
|
|
75c557ec63 | ||
|
|
2116ba19f6 | ||
|
|
8b9375ea68 | ||
|
|
9a024c6146 | ||
|
|
642de684e8 | ||
|
|
eb18d759f1 | ||
|
|
3fa41ea8d9 | ||
|
|
1147d6ba4a | ||
|
|
b0bebcd162 | ||
|
|
12dedf2047 | ||
|
|
9af8184221 | ||
|
|
62eeb06abe | ||
|
|
e60b5f670a | ||
|
|
6b2e64ef96 | ||
|
|
d6bfc773de | ||
|
|
a1e4b50b29 | ||
|
|
38c8762f64 | ||
|
|
ddd5b581fa | ||
|
|
e2afe4b787 | ||
|
|
b24ff33fe0 | ||
|
|
0922ee202a | ||
|
|
946fcf2b25 | ||
|
|
a517a8038f | ||
|
|
faca17ff78 | ||
|
|
d4e6126ec3 | ||
|
|
5c0da06d66 | ||
|
|
0d3bcb0b2c | ||
|
|
e0ab8fc8e2 | ||
|
|
011f12a7e4 | ||
|
|
f7f146df04 | ||
|
|
803a6d8a25 | ||
|
|
fa907a7f2b | ||
|
|
033a3a9db9 | ||
|
|
4a0dbde6b7 | ||
|
|
e41e08f2af | ||
|
|
c738f715a3 | ||
|
|
0d2572d37d | ||
|
|
a0df846493 | ||
|
|
01a6d60890 | ||
|
|
8721999a22 | ||
|
|
2b505466ce | ||
|
|
17627d0775 | ||
|
|
0f87fb86a9 | ||
|
|
f438f5252e | ||
|
|
a7291046a6 | ||
|
|
9e15209161 | ||
|
|
aed26b526a | ||
|
|
da5b7afa58 | ||
|
|
c271b07476 | ||
|
|
6b428c1ea9 | ||
|
|
5641ba4a14 | ||
|
|
461c7099ed | ||
|
|
81871868c4 | ||
|
|
191a835d9f | ||
|
|
0d7aabe920 | ||
|
|
1b8b7823c2 | ||
|
|
75ca306959 | ||
|
|
37994de120 | ||
|
|
3e35b0f7c6 | ||
|
|
f555a3323e | ||
|
|
a57526a0ff | ||
|
|
68001b00f3 | ||
|
|
7fbc248aa7 | ||
|
|
ec63d4c528 | ||
|
|
c368af633c | ||
|
|
486fe1dfc4 | ||
|
|
271ae9a36a | ||
|
|
18513724a0 | ||
|
|
9cfb652b29 | ||
|
|
fbec7bd360 | ||
|
|
401aba407c | ||
|
|
c9f14d7f58 | ||
|
|
aa7e32f81d | ||
|
|
6ab6ac81aa | ||
|
|
f13672776a | ||
|
|
13b299a3aa | ||
|
|
7a764f51ec | ||
|
|
71a93409fe | ||
|
|
f70961e67d | ||
|
|
8194d627ee | ||
|
|
4e9573334a | ||
|
|
74cc1296c8 | ||
|
|
4adcb8c938 | ||
|
|
4fdc5aa55f | ||
|
|
fd43cb4fd7 | ||
|
|
e08236eaff | ||
|
|
27b5e3daa7 | ||
|
|
955d3f9dd5 | ||
|
|
557d973ba4 | ||
|
|
b9bf8887dc | ||
|
|
5995258c5e | ||
|
|
2f46b6f507 | ||
|
|
dbb4be7cfa | ||
|
|
a6a8da5aa4 | ||
|
|
86706f31c6 | ||
|
|
59ba63f875 | ||
|
|
52933a528b | ||
|
|
0330498bbb | ||
|
|
837dac17ea | ||
|
|
9fb3b5cfed | ||
|
|
2ad00deb38 | ||
|
|
8fb8a5002d | ||
|
|
af9ee948ef | ||
|
|
9eb76fe470 | ||
|
|
6d766a8ce9 | ||
|
|
33afecf7da | ||
|
|
938c7d2437 | ||
|
|
c3bee5e725 | ||
|
|
bb46282b91 | ||
|
|
ca346ccbb2 | ||
|
|
46f05224ab | ||
|
|
1e3bac6031 | ||
|
|
3f90a3f49d | ||
|
|
099dea886f | ||
|
|
d4d253284d | ||
|
|
d6e15f985c | ||
|
|
c1b0497624 | ||
|
|
f25e4827a2 | ||
|
|
5d57a51618 | ||
|
|
d803ffcf95 | ||
|
|
4de5f180b6 | ||
|
|
2bad321397 | ||
|
|
ab37cc9661 | ||
|
|
a9a5166da7 | ||
|
|
5723ea3f8b | ||
|
|
2daea0836a | ||
|
|
e05c66a973 | ||
|
|
0295d9c573 | ||
|
|
d60e9f3bc2 | ||
|
|
d71d35b258 | ||
|
|
9988d76c3f | ||
|
|
f55d0a67d9 | ||
|
|
171adf7310 | ||
|
|
03a9890781 | ||
|
|
bf2d7b9d92 | ||
|
|
05da17e9cb | ||
|
|
f653f643f7 | ||
|
|
d742ea6efc | ||
|
|
1fb1103e2d | ||
|
|
baea8b62be | ||
|
|
fe3dd76f68 | ||
|
|
6af6e9c2c0 | ||
|
|
707bfb9c78 | ||
|
|
316087d18c | ||
|
|
46c538dffb | ||
|
|
218f6cb8d1 | ||
|
|
05f6c7656c | ||
|
|
3534ae910e | ||
|
|
dd65778017 | ||
|
|
67f3a4b164 | ||
|
|
fcf1fd9bec | ||
|
|
2ceccd201a | ||
|
|
45edfeee2d | ||
|
|
2a6cf2aea2 | ||
|
|
8bb3e5d9c9 | ||
|
|
d3ad2ec4f8 | ||
|
|
a3ef96a799 | ||
|
|
a5b7f8fd6b | ||
|
|
33accf65ef | ||
|
|
e2012433cb | ||
|
|
d6d05121e4 | ||
|
|
125392ce57 | ||
|
|
fb20155485 | ||
|
|
1d44ee2f45 | ||
|
|
2a6e91477a | ||
|
|
302f3b57c5 | ||
|
|
7d818c0590 | ||
|
|
ab77fca2f5 | ||
|
|
4d33e1388b | ||
|
|
9bac03d2f3 | ||
|
|
68bb155793 | ||
|
|
2be6ec1711 | ||
|
|
27e254ac4d | ||
|
|
a7a1fb45bb | ||
|
|
0732799ecb | ||
|
|
ea22ac6b37 | ||
|
|
aeacf40654 | ||
|
|
f87cb8d940 | ||
|
|
f37907a55a | ||
|
|
0538d5c0db | ||
|
|
9a84e126a1 | ||
|
|
5ec633192f | ||
|
|
7b87dc9d21 | ||
|
|
35df355cc6 | ||
|
|
59830a4793 | ||
|
|
d685ce1e6e | ||
|
|
0eba0d4b4a | ||
|
|
b32d3e5c17 | ||
|
|
d696f19764 | ||
|
|
1645c2103c | ||
|
|
9dfac1dd6f | ||
|
|
2937dbfc3a | ||
|
|
f3a1cf82ac | ||
|
|
84ae7d187b | ||
|
|
49ba670b36 | ||
|
|
78f9dcc68a | ||
|
|
8258d84c23 | ||
|
|
a2a48415f7 | ||
|
|
5539705bf3 | ||
|
|
1061873788 | ||
|
|
a587c9523d | ||
|
|
eed18fba57 | ||
|
|
df2158df0b | ||
|
|
40ec49aeb9 | ||
|
|
4900bbf989 | ||
|
|
3dc92ae8e8 | ||
|
|
7255b0b30f | ||
|
|
b9b01d3816 | ||
|
|
256103b02e | ||
|
|
194c190519 | ||
|
|
8e5c258896 | ||
|
|
fd375788f8 | ||
|
|
d80fe902b3 | ||
|
|
4304d8badd | ||
|
|
ecdf507645 | ||
|
|
c4d271d767 | ||
|
|
2dcd60efc4 | ||
|
|
4251f2a7f7 | ||
|
|
4a58ad861c | ||
|
|
b87bbd569e | ||
|
|
11bad31b5f | ||
|
|
d428ffe937 | ||
|
|
4ff60abb93 | ||
|
|
7a5a476ed1 | ||
|
|
b47f3563de | ||
|
|
a828addd28 | ||
|
|
93ce71acdd | ||
|
|
a15ccfee1b | ||
|
|
e5cbee2770 | ||
|
|
e9f7c5ed5a | ||
|
|
3141590d28 | ||
|
|
cfa800c1cd | ||
|
|
6eb79aacdb | ||
|
|
2ace7d4161 | ||
|
|
b36d2edfde | ||
|
|
3897446cb7 | ||
|
|
d4c41a2b27 | ||
|
|
dfaabeead2 | ||
|
|
989e368fb4 | ||
|
|
0c6060eae7 | ||
|
|
8a766fe100 | ||
|
|
9afb32f526 | ||
|
|
8ea8a20cc9 | ||
|
|
70f0c7d01e | ||
|
|
f214f0f033 | ||
|
|
37425db04d | ||
|
|
357909401d | ||
|
|
87286593cb | ||
|
|
2e1a74f79a | ||
|
|
341ea70dbc | ||
|
|
54e4c57ae5 | ||
|
|
9432ffebad | ||
|
|
c748792f16 | ||
|
|
f1b304304c | ||
|
|
8532f7df26 | ||
|
|
9cb3314494 | ||
|
|
cfc7b2ac93 | ||
|
|
2f2709abc6 | ||
|
|
8fd8087370 | ||
|
|
d140dc2c71 | ||
|
|
1a4f330bd5 | ||
|
|
65a0125035 | ||
|
|
bfe506dbf3 | ||
|
|
da7a177599 | ||
|
|
fe677f133b | ||
|
|
d6e4d2f24b | ||
|
|
a14642b62a | ||
|
|
9d223067ae | ||
|
|
39009a6ee6 | ||
|
|
0ea16b1d97 | ||
|
|
977e9e0019 | ||
|
|
e186db3b8e | ||
|
|
0135a37af8 | ||
|
|
a923d1effc | ||
|
|
11f7bf2bb1 | ||
|
|
b336cdffe5 | ||
|
|
f85b9e1b2b | ||
|
|
1422e3ffb7 | ||
|
|
b1a080cb91 | ||
|
|
59ad01c560 | ||
|
|
a24eaa6693 | ||
|
|
b98b10c580 | ||
|
|
2fca01401b | ||
|
|
f20296cf7c | ||
|
|
fe041c5e10 | ||
|
|
ca44d23031 | ||
|
|
18452f692c | ||
|
|
6aca68824a | ||
|
|
7177b9bf82 | ||
|
|
5b6e24bd13 | ||
|
|
cc93108df0 | ||
|
|
95041b75b0 | ||
|
|
0929799daf | ||
|
|
c771534c43 | ||
|
|
3ffbc09630 | ||
|
|
de4207940c | ||
|
|
3eb7d6337a | ||
|
|
1dd556d6c8 | ||
|
|
a250d9b184 | ||
|
|
bb6cedfce4 | ||
|
|
a4c9b9c8cf | ||
|
|
c88ea6666b | ||
|
|
5ecd73c599 | ||
|
|
84739ba695 | ||
|
|
3bb1e9ff91 | ||
|
|
fbd6691711 | ||
|
|
aec17da6b0 | ||
|
|
639533662d | ||
|
|
a340ce4a68 | ||
|
|
6e5fe64e8b | ||
|
|
84bdbb84b8 | ||
|
|
f91ffb6cb4 | ||
|
|
13815199a3 | ||
|
|
98c20ff551 | ||
|
|
479b6b9081 | ||
|
|
c640d2ea77 | ||
|
|
715547d2fd | ||
|
|
8a914a536b | ||
|
|
f56b6c0648 | ||
|
|
25aa8318d9 | ||
|
|
72f2cbe9e8 | ||
|
|
fc7836084a | ||
|
|
60d9d9202b | ||
|
|
a9df468282 | ||
|
|
0bba773c3e | ||
|
|
7be03ae623 | ||
|
|
d4741532f5 | ||
|
|
10f31efefa | ||
|
|
be662ddf32 | ||
|
|
ff84beaade | ||
|
|
8dba8fa5fb | ||
|
|
3a3f5552a7 | ||
|
|
88cba353c0 | ||
|
|
a2851370bb | ||
|
|
7c0ef7dcf0 | ||
|
|
fb6d5d89b8 | ||
|
|
45ceff4c08 | ||
|
|
6169abc700 | ||
|
|
c09e12d13e | ||
|
|
6152e15e10 | ||
|
|
79910b2ae8 | ||
|
|
c347df7c17 | ||
|
|
e9e2b35c59 | ||
|
|
8ae753c396 | ||
|
|
d2c94321f2 | ||
|
|
4c10f8a537 | ||
|
|
9a19cc2173 | ||
|
|
c4cbc894f5 | ||
|
|
449f5e6c7f | ||
|
|
34447a3f2f | ||
|
|
eee97d7dba | ||
|
|
f16392947a | ||
|
|
c3adf92b49 | ||
|
|
a6580b018d | ||
|
|
00c843c7ce | ||
|
|
5fe55a4db9 | ||
|
|
4ca998c346 | ||
|
|
42b3e2cc11 | ||
|
|
59fb8db6be | ||
|
|
664beafefa | ||
|
|
04443a64e2 | ||
|
|
92dedf3386 | ||
|
|
2ba5fb9820 | ||
|
|
222235159b | ||
|
|
1061bd5e0d | ||
|
|
ccec9a8348 | ||
|
|
bf9e06e67d | ||
|
|
1e03d222c5 | ||
|
|
3722f46b8e | ||
|
|
8d7bf97127 | ||
|
|
d26c1a6407 | ||
|
|
f296ff8476 | ||
|
|
a75a71994a | ||
|
|
7d1373a1d1 | ||
|
|
23abc50015 | ||
|
|
5e28d1131a | ||
|
|
a141e64a69 | ||
|
|
e12ee97bd9 | ||
|
|
ebd84642e1 | ||
|
|
888ac2ea0d | ||
|
|
37068c922c | ||
|
|
eec24d2ed1 | ||
|
|
8fa9d629a3 | ||
|
|
ef22dd7dc4 | ||
|
|
3f12624b78 | ||
|
|
d6fa67374c | ||
|
|
d4183cf718 | ||
|
|
4ad0480039 | ||
|
|
7188425ac0 | ||
|
|
c83581cf47 | ||
|
|
f8fa29f157 | ||
|
|
f2a4db6291 | ||
|
|
a4aff0b1e9 | ||
|
|
f5c2e0b425 | ||
|
|
2f88c55ec0 | ||
|
|
db7075a91a | ||
|
|
8ac007ba9a | ||
|
|
111fa8397c | ||
|
|
0ef4e92a96 | ||
|
|
9123afac18 | ||
|
|
1b5dca52e3 | ||
|
|
bc3e9c43da | ||
|
|
ded01cfd8a | ||
|
|
c737b7494f | ||
|
|
47aff56e71 | ||
|
|
15ce341d81 | ||
|
|
7476204258 | ||
|
|
e083b1a02e | ||
|
|
fa74fc54e3 | ||
|
|
fbbeec6d2f | ||
|
|
b4192364f6 | ||
|
|
c7dc82947f | ||
|
|
c38fd3986c | ||
|
|
35d7926e18 | ||
|
|
86e06ce1e6 | ||
|
|
1a08f063a6 | ||
|
|
740208ed76 | ||
|
|
521f6fe3f1 | ||
|
|
f43d490763 | ||
|
|
898179b645 | ||
|
|
8c3888da02 | ||
|
|
e1471ec9a1 | ||
|
|
eac07a51ba | ||
|
|
753000b56a | ||
|
|
8ab2907c3f | ||
|
|
723ee80c8f | ||
|
|
e1c003c8df | ||
|
|
96c82dc69f | ||
|
|
0dd9483797 | ||
|
|
4da110087d | ||
|
|
7f75a64647 | ||
|
|
71d7f6fd98 | ||
|
|
42595f241f | ||
|
|
c67c84dfda | ||
|
|
2ba6a3b097 | ||
|
|
0456ad96fb | ||
|
|
0ab87b03fa | ||
|
|
54fc41e175 | ||
|
|
261e824290 | ||
|
|
802363e1da | ||
|
|
1054d5bb74 | ||
|
|
f5d143710e | ||
|
|
c025208bf5 | ||
|
|
7306e39f3e | ||
|
|
0d30d183df | ||
|
|
cd504a4127 | ||
|
|
bba41402aa | ||
|
|
e1f129abc5 | ||
|
|
7e6c6924f2 | ||
|
|
185fc4c942 | ||
|
|
5f7c6b307f | ||
|
|
a9f80467c3 | ||
|
|
89fb1a8804 | ||
|
|
54bfce0d5d | ||
|
|
dca1d1b413 | ||
|
|
4b07ee40a7 | ||
|
|
d8644c940b | ||
|
|
7df70abb48 | ||
|
|
6e3c5c0388 | ||
|
|
6cbe2e288b | ||
|
|
1f95c6ca6e | ||
|
|
ac6ae43449 | ||
|
|
ba3117f435 | ||
|
|
fd449f68d9 | ||
|
|
574947656c | ||
|
|
5b1b704d1d | ||
|
|
abbdb207e0 | ||
|
|
2d89fc945f | ||
|
|
25b130ce2c | ||
|
|
ca098eb171 | ||
|
|
f6ccd119e8 | ||
|
|
7b1f99b41a | ||
|
|
4193ee1980 | ||
|
|
c718012c3e | ||
|
|
aca5c8af73 | ||
|
|
2d4a699790 | ||
|
|
fc0475b2c5 | ||
|
|
0f6e13b8c9 | ||
|
|
c60cfae677 | ||
|
|
ded05cf079 | ||
|
|
c360d471cd | ||
|
|
382a39e6ed | ||
|
|
bfa1499889 | ||
|
|
053a5e9bd7 | ||
|
|
3677f6cf0f | ||
|
|
03fb75f030 | ||
|
|
8e209d2767 | ||
|
|
0cf77a4115 | ||
|
|
14368c4ce2 | ||
|
|
e74838fdc1 | ||
|
|
3f64b13d70 | ||
|
|
613f4b6440 | ||
|
|
1bfa4c6ba8 | ||
|
|
9089473cf0 | ||
|
|
687eb7d0dc | ||
|
|
52cb8adf65 | ||
|
|
06f241adb1 | ||
|
|
f5ba173156 | ||
|
|
5bd7bfb4ce | ||
|
|
e4413dceee | ||
|
|
f644454080 | ||
|
|
16f4b485b5 | ||
|
|
679dd4578c | ||
|
|
00bf318ee9 | ||
|
|
da3415d029 | ||
|
|
147a8d2f57 | ||
|
|
a1d354ac15 | ||
|
|
1fb0e41603 | ||
|
|
f121c119f0 | ||
|
|
f4c472e7de | ||
|
|
719d62b670 | ||
|
|
165306f56a | ||
|
|
248bb32977 | ||
|
|
dfb9127052 | ||
|
|
5933e948e1 | ||
|
|
624f6ef5a1 | ||
|
|
2865b546fa | ||
|
|
9d7c3b2af9 | ||
|
|
033896dfc2 | ||
|
|
10d95ba8e6 | ||
|
|
43f74583ea | ||
|
|
36d499f253 | ||
|
|
4c6e61e6dd | ||
|
|
0829af77c0 | ||
|
|
f3281d3985 | ||
|
|
5cd5567292 | ||
|
|
c0102a1658 | ||
|
|
c173d0d76e | ||
|
|
d7dd4b82da | ||
|
|
f9010cf3ca | ||
|
|
a0d2dbf685 | ||
|
|
d679d27043 | ||
|
|
9c0641dcad | ||
|
|
af852a088c | ||
|
|
76f04c0b0e | ||
|
|
27376df5f2 | ||
|
|
fd285dbd6f | ||
|
|
76e1d4b403 | ||
|
|
51dbc1a1ee | ||
|
|
7095236116 | ||
|
|
6014c888c2 | ||
|
|
c41714c6f3 | ||
|
|
a3626e121b | ||
|
|
b7caba8b11 | ||
|
|
0a45f446e2 | ||
|
|
917dbb12da | ||
|
|
767c0b3675 | ||
|
|
30477bb0ad | ||
|
|
1ce4d31503 | ||
|
|
066f7cfa08 | ||
|
|
be8f2bf280 | ||
|
|
e339571ce0 | ||
|
|
3ea89b3956 | ||
|
|
1e65d45844 | ||
|
|
99750b8edb | ||
|
|
2af3831366 | ||
|
|
5d9c65041e | ||
|
|
e789f92db2 | ||
|
|
9a1f7dd3eb | ||
|
|
fb48c4cf0e | ||
|
|
8c5dee529b | ||
|
|
c885b76bbc | ||
|
|
6d03f12e54 | ||
|
|
be5bbe95b6 | ||
|
|
e571c884c1 | ||
|
|
96008539d5 | ||
|
|
8c221f33a8 | ||
|
|
9612af06a8 | ||
|
|
17c1be6dd7 | ||
|
|
6607cdb0bd | ||
|
|
5f33bd312e | ||
|
|
185bc30893 | ||
|
|
b35d5e9914 | ||
|
|
a89eab43c4 | ||
|
|
5eac4ebee8 | ||
|
|
65a3c3a33c | ||
|
|
b0cf35d264 | ||
|
|
f8aff7dcd9 | ||
|
|
b754912990 | ||
|
|
83a01cf0e2 | ||
|
|
d81db3fd4b | ||
|
|
1b383888b8 | ||
|
|
cd76672831 | ||
|
|
94f4d652b4 | ||
|
|
5aab7c34e6 | ||
|
|
72eff3754f | ||
|
|
0d3d9c8233 | ||
|
|
3bb8614143 | ||
|
|
2b12a47915 | ||
|
|
9216e72a3e | ||
|
|
9b99a92dc1 | ||
|
|
ab1a68d0f8 | ||
|
|
4fedf9548f | ||
|
|
a396c86e84 | ||
|
|
75f2da3547 | ||
|
|
6c9a25a0c7 | ||
|
|
34db96822b | ||
|
|
37e60c9dfe | ||
|
|
54b2cbc608 | ||
|
|
7f4169e4e3 | ||
|
|
c356ec40d6 | ||
|
|
23a7268e84 | ||
|
|
35d960c09f | ||
|
|
a7d81993d5 | ||
|
|
e5af3257c9 | ||
|
|
da83581f45 | ||
|
|
5900594562 | ||
|
|
a050832da0 | ||
|
|
fe766dc438 | ||
|
|
c1a5ce4b27 | ||
|
|
64b0e63945 | ||
|
|
95f6841a48 | ||
|
|
3189c6fe98 | ||
|
|
9dbee4c686 | ||
|
|
04a2d45334 | ||
|
|
6766af0f9d | ||
|
|
c7058e7613 | ||
|
|
3d1f858301 | ||
|
|
21de0db790 | ||
|
|
c5d4c532b3 | ||
|
|
3877e89277 | ||
|
|
688ac96faa | ||
|
|
e53f36e5ef | ||
|
|
ad35df2a17 | ||
|
|
fd104ad74f | ||
|
|
bffa9a2ed8 | ||
|
|
dfd18776c6 | ||
|
|
f746ef7954 | ||
|
|
a71b83b4c3 | ||
|
|
cebd206bcc | ||
|
|
d07311cf64 | ||
|
|
7d6390d9bf | ||
|
|
68f40ed779 | ||
|
|
4d56124274 | ||
|
|
6aa31e612a | ||
|
|
6d9018627e | ||
|
|
28b0e74e04 | ||
|
|
246f1155e6 | ||
|
|
a59d29e10c | ||
|
|
b13e2c32ff | ||
|
|
807cba18d1 | ||
|
|
e938f94ffc | ||
|
|
d6e6f2cb25 | ||
|
|
43328b94b7 | ||
|
|
dde15b0881 | ||
|
|
d84fd95f3c | ||
|
|
efed99b890 | ||
|
|
1a6c1ed1c3 | ||
|
|
fa82d31000 | ||
|
|
d11e7fe562 | ||
|
|
e36a49b635 | ||
|
|
17df0e3cd3 | ||
|
|
76df2fd204 | ||
|
|
f9491bb944 | ||
|
|
3541540d84 | ||
|
|
1ae5b9cfcd | ||
|
|
e493bda6df | ||
|
|
7de15e94b2 | ||
|
|
002f847165 | ||
|
|
a654f50c33 | ||
|
|
a2594d4a6b | ||
|
|
b98e1f6b20 | ||
|
|
a48eef2575 | ||
|
|
4aeb804441 | ||
|
|
a30adac959 | ||
|
|
d605de4e07 | ||
|
|
fe49ee0aad | ||
|
|
e47fd3b879 | ||
|
|
383e039297 | ||
|
|
46a206de64 | ||
|
|
f39cb976aa | ||
|
|
ad7c02f745 | ||
|
|
1c98a831d8 | ||
|
|
ffcdf4462b | ||
|
|
22cfc82d35 | ||
|
|
83fbe9eccc | ||
|
|
9a89c14e20 | ||
|
|
6b1d762245 | ||
|
|
0b9da0b049 | ||
|
|
5bcce80b50 | ||
|
|
9f3bf24d06 | ||
|
|
647ab0ab78 | ||
|
|
188a7b661e | ||
|
|
fe4393593a | ||
|
|
6fd5a97fde | ||
|
|
10cd4b8999 | ||
|
|
cb3d76889d | ||
|
|
07504dd149 | ||
|
|
2ea5b65cb8 | ||
|
|
f124c8d81b | ||
|
|
1e7567fb8f | ||
|
|
5f6874edbf | ||
|
|
3558bd5d9b | ||
|
|
8e45f7d785 | ||
|
|
ceb234f0d5 | ||
|
|
1c8a3ea7d2 | ||
|
|
522d6a5fc4 | ||
|
|
21a7df9a84 | ||
|
|
d6eeacbdc1 | ||
|
|
d4d581e4fb | ||
|
|
9c31d148fe | ||
|
|
47c932bd46 | ||
|
|
cc7ab8f7c4 | ||
|
|
6883851866 | ||
|
|
94a5c6244e | ||
|
|
42fb6c7100 | ||
|
|
5e7fcdd105 | ||
|
|
12b0365ce0 | ||
|
|
114dfa3904 | ||
|
|
e31a05beb0 | ||
|
|
a28942f264 | ||
|
|
af61f45ecb | ||
|
|
0da9955403 | ||
|
|
e4f699641a | ||
|
|
23b56b4053 | ||
|
|
0971153a74 | ||
|
|
0b3abfae28 | ||
|
|
d0b9488c1c | ||
|
|
698962e0ea | ||
|
|
1c010ffe5a | ||
|
|
95ba1b5849 | ||
|
|
19dba93cca | ||
|
|
94fe4f1f46 | ||
|
|
de9d43f67a | ||
|
|
301c58d6fb | ||
|
|
227ecc0193 | ||
|
|
ee260e671f | ||
|
|
1a954c5b25 | ||
|
|
a14dd95c21 | ||
|
|
19f7918435 | ||
|
|
1e4de5f821 | ||
|
|
45f4b33eb1 | ||
|
|
16e7287c24 | ||
|
|
3b2b5eed5a | ||
|
|
0521740824 | ||
|
|
1d2033953b | ||
|
|
e20edefc61 | ||
|
|
a9287d9d80 | ||
|
|
ba029db24e | ||
|
|
529c187bc4 | ||
|
|
714914ffe5 | ||
|
|
cd23b9ebfe | ||
|
|
35ce68f4f6 | ||
|
|
f7bcd89b97 | ||
|
|
0b44fba68c | ||
|
|
501869c7aa | ||
|
|
15cb1cb746 | ||
|
|
7454cc12a1 | ||
|
|
52d52810b9 | ||
|
|
936039f7a7 | ||
|
|
ba0e8f7973 | ||
|
|
8449a99418 | ||
|
|
28c9dbab1f | ||
|
|
81753cd44b | ||
|
|
9970bc84ff | ||
|
|
499bc4c4cd | ||
|
|
b0921b5be0 | ||
|
|
afc4dfaf50 | ||
|
|
9dda3a9323 | ||
|
|
115e80dce0 | ||
|
|
9f405686ec | ||
|
|
e7d7469c4e | ||
|
|
0dbb72efe9 | ||
|
|
9b21d5a619 |
@@ -1,4 +1,4 @@
|
||||
# http://editorconfig.org
|
||||
# https://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
10
.eslintignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.cache
|
||||
docs/dist
|
||||
docs/search.json
|
||||
docs/**/*.min.js
|
||||
dist
|
||||
examples
|
||||
node_modules
|
||||
src/react
|
||||
scripts
|
||||
|
||||
211
.eslintrc.cjs
Normal file
@@ -0,0 +1,211 @@
|
||||
/* eslint-env node */
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'wc',
|
||||
'lit',
|
||||
'lit-a11y',
|
||||
'chai-expect',
|
||||
'chai-friendly',
|
||||
'import',
|
||||
'sort-imports-es6-autofix'
|
||||
],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:wc/recommended',
|
||||
'plugin:wc/best-practice',
|
||||
'plugin:lit/recommended',
|
||||
'plugin:lit-a11y/recommended'
|
||||
],
|
||||
env: {
|
||||
es2021: true,
|
||||
browser: true
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking'
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.json',
|
||||
tsconfigRootDir: __dirname
|
||||
},
|
||||
files: ['*.ts'],
|
||||
rules: {
|
||||
'default-param-last': 'off',
|
||||
'@typescript-eslint/default-param-last': 'error',
|
||||
'no-empty-function': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'warn',
|
||||
'no-implied-eval': 'off',
|
||||
'@typescript-eslint/no-implied-eval': 'error',
|
||||
'no-invalid-this': 'off',
|
||||
'@typescript-eslint/no-invalid-this': 'error',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'no-throw-literal': 'off',
|
||||
'@typescript-eslint/no-throw-literal': 'error',
|
||||
'no-unused-expressions': 'off',
|
||||
'@typescript-eslint/prefer-regexp-exec': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'error',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/no-misused-promises': [
|
||||
'error',
|
||||
{
|
||||
checksVoidReturn: false
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/consistent-type-assertions': [
|
||||
'warn',
|
||||
{
|
||||
assertionStyle: 'as',
|
||||
objectLiteralTypeAssertions: 'never'
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/consistent-type-imports': 'warn',
|
||||
'@typescript-eslint/no-base-to-string': 'error',
|
||||
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-invalid-void-type': 'error',
|
||||
'@typescript-eslint/no-require-imports': 'error',
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
'@typescript-eslint/no-unnecessary-qualifier': 'warn',
|
||||
'@typescript-eslint/non-nullable-type-assertion-style': 'warn',
|
||||
'@typescript-eslint/prefer-for-of': 'warn',
|
||||
'@typescript-eslint/prefer-optional-chain': 'warn',
|
||||
'@typescript-eslint/prefer-ts-expect-error': 'warn',
|
||||
'@typescript-eslint/prefer-return-this-type': 'error',
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
|
||||
'@typescript-eslint/require-array-sort-compare': 'error',
|
||||
'@typescript-eslint/unified-signatures': 'warn',
|
||||
'@typescript-eslint/array-type': 'warn',
|
||||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||
'@typescript-eslint/member-delimiter-style': 'warn',
|
||||
'@typescript-eslint/method-signature-style': 'warn',
|
||||
'@typescript-eslint/no-extraneous-class': 'error',
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
||||
'@typescript-eslint/parameter-properties': 'error',
|
||||
'@typescript-eslint/strict-boolean-expressions': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.cjs'],
|
||||
env: {
|
||||
node: true
|
||||
}
|
||||
},
|
||||
{
|
||||
extends: ['plugin:chai-expect/recommended', 'plugin:chai-friendly/recommended'],
|
||||
files: ['*.test.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off'
|
||||
}
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
'no-template-curly-in-string': 'error',
|
||||
'array-callback-return': 'error',
|
||||
'comma-dangle': 'off',
|
||||
'consistent-return': 'error',
|
||||
curly: 'off',
|
||||
'default-param-last': 'error',
|
||||
eqeqeq: 'error',
|
||||
'lit-a11y/click-events-have-key-events': 'off',
|
||||
'no-constructor-return': 'error',
|
||||
'no-empty-function': 'warn',
|
||||
'no-eval': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-extra-bind': 'error',
|
||||
'no-floating-decimal': 'error',
|
||||
'no-implicit-coercion': 'off',
|
||||
'no-implicit-globals': 'error',
|
||||
'no-implied-eval': 'error',
|
||||
'no-invalid-this': 'error',
|
||||
'no-labels': 'error',
|
||||
'no-lone-blocks': 'error',
|
||||
'no-new': 'error',
|
||||
'no-new-func': 'error',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-octal-escape': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-return-assign': 'warn',
|
||||
'no-script-url': 'error',
|
||||
'no-self-compare': 'warn',
|
||||
'no-sequences': 'warn',
|
||||
'no-throw-literal': 'error',
|
||||
'no-unmodified-loop-condition': 'error',
|
||||
'no-unused-expressions': 'warn',
|
||||
'no-useless-call': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'no-useless-return': 'warn',
|
||||
'prefer-promise-reject-errors': 'error',
|
||||
radix: 'off',
|
||||
'require-await': 'error',
|
||||
'wrap-iife': ['warn', 'inside'],
|
||||
'no-shadow': 'error',
|
||||
'no-array-constructor': 'error',
|
||||
'no-bitwise': 'error',
|
||||
'no-multi-assign': 'warn',
|
||||
'no-new-object': 'error',
|
||||
'no-useless-computed-key': 'warn',
|
||||
'no-useless-rename': 'warn',
|
||||
'no-var': 'error',
|
||||
'prefer-const': 'warn',
|
||||
'prefer-numeric-literals': 'warn',
|
||||
'prefer-object-spread': 'warn',
|
||||
'prefer-rest-params': 'warn',
|
||||
'prefer-spread': 'warn',
|
||||
'prefer-template': 'off',
|
||||
'no-else-return': 'off',
|
||||
'func-names': ['warn', 'never'],
|
||||
'one-var': ['warn', 'never'],
|
||||
'operator-assignment': 'warn',
|
||||
'prefer-arrow-callback': 'warn',
|
||||
'no-restricted-imports': [
|
||||
'warn',
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: '.',
|
||||
message: 'Usage of local index imports is not allowed.'
|
||||
},
|
||||
{
|
||||
name: './index',
|
||||
message: 'Import from the source file instead.'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
'import/extensions': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
ignorePackages: true,
|
||||
pattern: {
|
||||
js: 'always',
|
||||
ts: 'never'
|
||||
}
|
||||
}
|
||||
],
|
||||
'import/no-duplicates': 'warn',
|
||||
'sort-imports-es6-autofix/sort-imports-es6': [
|
||||
2,
|
||||
{
|
||||
ignoreCase: true,
|
||||
ignoreMemberSort: false,
|
||||
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single']
|
||||
}
|
||||
],
|
||||
'wc/guard-super-call': 'off'
|
||||
}
|
||||
};
|
||||
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,38 +1,35 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Create a report to help us improve.
|
||||
about: Create a bug report to help us fix a demonstrable problem with code in the library.
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: claviska
|
||||
|
||||
assignees:
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
### Describe the bug
|
||||
A bug is _a demonstrable problem_ caused by code in the library. Please provide a clear and concise description of what the bug is here.
|
||||
|
||||
**To Reproduce**
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
### Demo
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
If the bug isn't obvious, please provide a link to a CodePen or Fiddle with a minimal reproduction. Bugs that have repros get attention faster than those that don't.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
Tip: use the CodePen button on any example in the docs!
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
### Screenshots
|
||||
If applicable, add screenshots to help explain the bug.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
### Browser / OS
|
||||
- OS: [e.g. Mac, Windows]
|
||||
- Browser: [e.g. Chrome, Firefox, Safari]
|
||||
- Browser version: [e.g. 22]
|
||||
|
||||
### Additional information
|
||||
Provide any additional information about the bug here.
|
||||
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -3,18 +3,13 @@ name: Feature Request
|
||||
about: Suggest an idea for this project.
|
||||
title: ''
|
||||
labels: feature
|
||||
assignees: claviska
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
### What issue are you having?
|
||||
Provide a clear and concise description of the problem you're facing.
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
### Describe the solution you'd like
|
||||
How would you like to see the library solve it?
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
### Describe alternatives you've considered
|
||||
In what ways have you tried to solve this with the current version?
|
||||
|
||||
2
.github/SECURITY.md
vendored
@@ -4,4 +4,4 @@ We take security issues in Shoelace very seriously and appreciate your efforts t
|
||||
|
||||
To report a security issue, email [cory@abeautifulsite.net](mailto:cory@abeautifulsite.net) and include "SHOELACE SECURITY" in the subject line.
|
||||
|
||||
Well respond as soon as possible and keep you updated throughout the process.
|
||||
We'll respond as soon as possible and keep you updated throughout the process.
|
||||
|
||||
30
.github/workflows/node.js.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# 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: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [next]
|
||||
pull_request:
|
||||
branches: [next]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npx playwright install-deps
|
||||
- run: npm ci
|
||||
- run: npm run verify
|
||||
17
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# This workflow will create a GitHub release every time a tag is pushed
|
||||
name: Create GitHub Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v2.*"
|
||||
- "v3.*"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: "marvinpinto/action-automatic-releases@v1.2.1"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
prerelease: false
|
||||
9
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
.DS_Store
|
||||
_site
|
||||
.cache
|
||||
docs/dist
|
||||
.DS_Store
|
||||
dist
|
||||
examples
|
||||
docs/assets/images/sprite.svg
|
||||
node_modules
|
||||
src/react
|
||||
cdn
|
||||
web-types.json
|
||||
28
.gitpod.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
tasks:
|
||||
- init: npm install && npm run build
|
||||
command: npm run start
|
||||
|
||||
ports:
|
||||
- port: 3001
|
||||
onOpen: ignore
|
||||
- port: 4000-4999
|
||||
onOpen: open-preview
|
||||
|
||||
github:
|
||||
prebuilds:
|
||||
# enable for the master/default branch (defaults to true)
|
||||
master: true
|
||||
# enable for all branches in this repo (defaults to false)
|
||||
branches: true
|
||||
# enable for pull requests coming from this repo (defaults to true)
|
||||
pullRequests: true
|
||||
# enable for pull requests coming from forks (defaults to false)
|
||||
pullRequestsFromForks: true
|
||||
# add a check to pull requests (defaults to true)
|
||||
addCheck: true
|
||||
# add a "Review in Gitpod" button as a comment to pull requests (defaults to false)
|
||||
addComment: false
|
||||
# add a "Review in Gitpod" button to the pull request's description (defaults to false)
|
||||
addBadge: true
|
||||
# add a label once the prebuild is ready to pull requests (defaults to false)
|
||||
addLabel: true
|
||||
4
.husky/pre-commit
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install lint-staged
|
||||
@@ -1,9 +1,14 @@
|
||||
*.md
|
||||
*.hbs
|
||||
.cache
|
||||
.github
|
||||
cspell.json
|
||||
dist
|
||||
docs/*.md
|
||||
docs/search.json
|
||||
src/components/icon/icons
|
||||
src/react/index.ts
|
||||
node_modules
|
||||
package.json
|
||||
package-lock.json
|
||||
tsconfig.json
|
||||
cdn
|
||||
_site
|
||||
|
||||
5
.vscode/extensions.json
vendored
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"bierner.lit-html",
|
||||
"bashmish.es6-string-css"
|
||||
"bashmish.es6-string-css",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
]
|
||||
}
|
||||
|
||||
5
.vscode/settings.json
vendored
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ Twitter: [@shoelace_style](https://twitter.com/shoelace_style)
|
||||
|
||||
## Shoemakers 🥾
|
||||
|
||||
Shoemakers, or "Shoelace developers," can use this documentation to learn how to build Shoelace from source. You will need Node >= 12.10.0 to build and run the project locally.
|
||||
Shoemakers, or "Shoelace developers," can use this documentation to learn how to build Shoelace from source. You will need Node >= 14.17 to build and run the project locally.
|
||||
|
||||
**You don't need to do any of this to use Shoelace!** This page is for people who want to contribute to the project, tinker with the source, or create a custom build of Shoelace.
|
||||
|
||||
@@ -51,11 +51,7 @@ Once you've cloned the repo, run the following command.
|
||||
npm start
|
||||
```
|
||||
|
||||
This will spin up the Shoelace dev server. After the initial build, a browser will open automatically.
|
||||
|
||||
There is currently no hot module reloading (HMR), as browser's don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically. The exception is component metadata used by the docs, which is generated by TypeDoc. This tool takes a few seconds to run so, to prevent long reload delays, it only runs once at startup.
|
||||
|
||||
The documentation is powered by Docsify, which uses raw markdown files to generate pages. As such, no static files are built for the docs.
|
||||
This will spin up the dev server. After the initial build, a browser will open automatically. There is currently no hot module reloading (HMR), as browser's don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically.
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
184
cspell.json
Normal file
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"words": [
|
||||
"activedescendant",
|
||||
"allowfullscreen",
|
||||
"animationend",
|
||||
"Animista",
|
||||
"apos",
|
||||
"atrule",
|
||||
"autocorrect",
|
||||
"autofix",
|
||||
"autoload",
|
||||
"autoloader",
|
||||
"autoloading",
|
||||
"autoplay",
|
||||
"bezier",
|
||||
"boxicons",
|
||||
"CACHEABLE",
|
||||
"callout",
|
||||
"callouts",
|
||||
"cdndir",
|
||||
"chatbubble",
|
||||
"checkmark",
|
||||
"claviska",
|
||||
"Clippy",
|
||||
"codebases",
|
||||
"codepen",
|
||||
"colocated",
|
||||
"colour",
|
||||
"combobox",
|
||||
"Commonmark",
|
||||
"Composability",
|
||||
"Consolas",
|
||||
"contenteditable",
|
||||
"copydir",
|
||||
"Cotte",
|
||||
"coverpage",
|
||||
"crossorigin",
|
||||
"crutchcorn",
|
||||
"csspart",
|
||||
"cssproperty",
|
||||
"datetime",
|
||||
"describedby",
|
||||
"Docsify",
|
||||
"dogfood",
|
||||
"dropdowns",
|
||||
"easings",
|
||||
"endraw",
|
||||
"enterkeyhint",
|
||||
"eqeqeq",
|
||||
"erroneou",
|
||||
"errormessage",
|
||||
"esbuild",
|
||||
"exportmaps",
|
||||
"exportparts",
|
||||
"fieldsets",
|
||||
"formaction",
|
||||
"formdata",
|
||||
"formenctype",
|
||||
"formmethod",
|
||||
"formnovalidate",
|
||||
"formtarget",
|
||||
"FOUC",
|
||||
"FOUCE",
|
||||
"fullscreen",
|
||||
"gestern",
|
||||
"giga",
|
||||
"globby",
|
||||
"Grayscale",
|
||||
"haspopup",
|
||||
"heroicons",
|
||||
"hexa",
|
||||
"Iconoir",
|
||||
"Iframes",
|
||||
"iife",
|
||||
"inputmode",
|
||||
"ionicon",
|
||||
"ionicons",
|
||||
"jsDelivr",
|
||||
"jsfiddle",
|
||||
"jsonata",
|
||||
"keydown",
|
||||
"keyframes",
|
||||
"Kool",
|
||||
"labelledby",
|
||||
"Laravel",
|
||||
"LaViska",
|
||||
"linkify",
|
||||
"listbox",
|
||||
"listitem",
|
||||
"litelement",
|
||||
"lowercasing",
|
||||
"Lucide",
|
||||
"maxlength",
|
||||
"Menlo",
|
||||
"menuitemcheckbox",
|
||||
"menuitemradio",
|
||||
"middlewares",
|
||||
"minlength",
|
||||
"monospace",
|
||||
"mousedown",
|
||||
"mousemove",
|
||||
"mouseup",
|
||||
"multiselectable",
|
||||
"nextjs",
|
||||
"nocheck",
|
||||
"noopener",
|
||||
"noreferrer",
|
||||
"novalidate",
|
||||
"npmdir",
|
||||
"Numberish",
|
||||
"outdir",
|
||||
"ParamagicDev",
|
||||
"peta",
|
||||
"petabit",
|
||||
"prismjs",
|
||||
"progressbar",
|
||||
"radiogroup",
|
||||
"Railsbyte",
|
||||
"remixicon",
|
||||
"reregister",
|
||||
"resizer",
|
||||
"resizers",
|
||||
"retargeted",
|
||||
"RETRYABLE",
|
||||
"rgba",
|
||||
"roadmap",
|
||||
"Roboto",
|
||||
"roledescription",
|
||||
"Sapan",
|
||||
"saturationl",
|
||||
"Schilp",
|
||||
"scrollbars",
|
||||
"scrollend",
|
||||
"scroller",
|
||||
"Segoe",
|
||||
"semibold",
|
||||
"sitedir",
|
||||
"slotchange",
|
||||
"smartquotes",
|
||||
"spacebar",
|
||||
"stylesheet",
|
||||
"Tabbable",
|
||||
"tabindex",
|
||||
"tabler",
|
||||
"tablist",
|
||||
"tabpanel",
|
||||
"templating",
|
||||
"tera",
|
||||
"testid",
|
||||
"textareas",
|
||||
"textfield",
|
||||
"tinycolor",
|
||||
"transitionend",
|
||||
"treeitem",
|
||||
"treeshaking",
|
||||
"Triaging",
|
||||
"turbolinks",
|
||||
"typeof",
|
||||
"unbundles",
|
||||
"unbundling",
|
||||
"unicons",
|
||||
"unsanitized",
|
||||
"unsupportive",
|
||||
"valpha",
|
||||
"valuenow",
|
||||
"valuetext",
|
||||
"WEBP",
|
||||
"Webpacker",
|
||||
"wordmark"
|
||||
],
|
||||
"ignorePaths": [
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"docs/assets/examples/include.html",
|
||||
".vscode/**",
|
||||
"src/translations/!(en).ts",
|
||||
"**/*.min.js"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"(^|[^a-z])sl[a-z]*(^|[^a-z])"
|
||||
],
|
||||
"useGitignore": true
|
||||
}
|
||||
215
custom-elements-manifest.config.js
Normal file
@@ -0,0 +1,215 @@
|
||||
import * as path from 'path';
|
||||
import { customElementJetBrainsPlugin } from 'custom-element-jet-brains-integration';
|
||||
import { customElementVsCodePlugin } from 'custom-element-vs-code-integration';
|
||||
import { parse } from 'comment-parser';
|
||||
import { pascalCase } from 'pascal-case';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import fs from 'fs';
|
||||
|
||||
const packageData = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
||||
const { name, description, version, author, homepage, license } = packageData;
|
||||
|
||||
const { outdir } = commandLineArgs([
|
||||
{ name: 'litelement', type: String },
|
||||
{ name: 'analyze', defaultOption: true },
|
||||
{ name: 'outdir', type: String }
|
||||
]);
|
||||
|
||||
function noDash(string) {
|
||||
return string.replace(/^\s?-/, '').trim();
|
||||
}
|
||||
|
||||
function replace(string, terms) {
|
||||
terms.forEach(({ from, to }) => {
|
||||
string = string?.replace(from, to);
|
||||
});
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
export default {
|
||||
globs: ['src/components/**/*.component.ts'],
|
||||
exclude: ['**/*.styles.ts', '**/*.test.ts'],
|
||||
plugins: [
|
||||
// Append package data
|
||||
{
|
||||
name: 'shoelace-package-data',
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
customElementsManifest.package = { name, description, version, author, homepage, license };
|
||||
}
|
||||
},
|
||||
// Infer tag names because we no longer use @customElement decorators.
|
||||
{
|
||||
name: 'shoelace-infer-tag-names',
|
||||
analyzePhase({ ts, node, moduleDoc }) {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.ClassDeclaration: {
|
||||
const className = node.name.getText();
|
||||
const classDoc = moduleDoc?.declarations?.find(declaration => declaration.name === className);
|
||||
|
||||
const importPath = moduleDoc.path;
|
||||
|
||||
// This is kind of a best guess at components. "thing.component.ts"
|
||||
if (!importPath.endsWith('.component.ts')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tagNameWithoutPrefix = path.basename(importPath, '.component.ts');
|
||||
const tagName = 'sl-' + tagNameWithoutPrefix;
|
||||
|
||||
classDoc.tagNameWithoutPrefix = tagNameWithoutPrefix;
|
||||
classDoc.tagName = tagName;
|
||||
|
||||
// This used to be set to true by @customElement
|
||||
classDoc.customElement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Parse custom jsDoc tags
|
||||
{
|
||||
name: 'shoelace-custom-tags',
|
||||
analyzePhase({ ts, node, moduleDoc }) {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.ClassDeclaration: {
|
||||
const className = node.name.getText();
|
||||
const classDoc = moduleDoc?.declarations?.find(declaration => declaration.name === className);
|
||||
const customTags = ['animation', 'dependency', 'documentation', 'since', 'status', 'title'];
|
||||
let customComments = '/**';
|
||||
|
||||
node.jsDoc?.forEach(jsDoc => {
|
||||
jsDoc?.tags?.forEach(tag => {
|
||||
const tagName = tag.tagName.getText();
|
||||
|
||||
if (customTags.includes(tagName)) {
|
||||
customComments += `\n * @${tagName} ${tag.comment}`;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// This is what allows us to map JSDOC comments to ReactWrappers.
|
||||
classDoc['jsDoc'] = node.jsDoc?.map(jsDoc => jsDoc.getFullText()).join('\n');
|
||||
|
||||
const parsed = parse(`${customComments}\n */`);
|
||||
parsed[0].tags?.forEach(t => {
|
||||
switch (t.tag) {
|
||||
// Animations
|
||||
case 'animation':
|
||||
if (!Array.isArray(classDoc['animations'])) {
|
||||
classDoc['animations'] = [];
|
||||
}
|
||||
classDoc['animations'].push({
|
||||
name: t.name,
|
||||
description: noDash(t.description)
|
||||
});
|
||||
break;
|
||||
|
||||
// Dependencies
|
||||
case 'dependency':
|
||||
if (!Array.isArray(classDoc['dependencies'])) {
|
||||
classDoc['dependencies'] = [];
|
||||
}
|
||||
classDoc['dependencies'].push(t.name);
|
||||
break;
|
||||
|
||||
// Value-only metadata tags
|
||||
case 'documentation':
|
||||
case 'since':
|
||||
case 'status':
|
||||
case 'title':
|
||||
classDoc[t.tag] = t.name;
|
||||
break;
|
||||
|
||||
// All other tags
|
||||
default:
|
||||
if (!Array.isArray(classDoc[t.tag])) {
|
||||
classDoc[t.tag] = [];
|
||||
}
|
||||
|
||||
classDoc[t.tag].push({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
type: t.type || undefined
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'shoelace-react-event-names',
|
||||
analyzePhase({ ts, node, moduleDoc }) {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.ClassDeclaration: {
|
||||
const className = node.name.getText();
|
||||
const classDoc = moduleDoc?.declarations?.find(declaration => declaration.name === className);
|
||||
|
||||
if (classDoc?.events) {
|
||||
classDoc.events.forEach(event => {
|
||||
event.reactName = `on${pascalCase(event.name)}`;
|
||||
event.eventName = `${pascalCase(event.name)}Event`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'shoelace-translate-module-paths',
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
customElementsManifest?.modules?.forEach(mod => {
|
||||
//
|
||||
// CEM paths look like this:
|
||||
//
|
||||
// src/components/button/button.ts
|
||||
//
|
||||
// But we want them to look like this:
|
||||
//
|
||||
// components/button/button.js
|
||||
//
|
||||
const terms = [
|
||||
{ from: /^src\//, to: '' }, // Strip the src/ prefix
|
||||
{ from: /\.component.(t|j)sx?$/, to: '.js' } // Convert .ts to .js
|
||||
];
|
||||
|
||||
mod.path = replace(mod.path, terms);
|
||||
|
||||
for (const ex of mod.exports ?? []) {
|
||||
ex.declaration.module = replace(ex.declaration.module, terms);
|
||||
}
|
||||
|
||||
for (const dec of mod.declarations ?? []) {
|
||||
if (dec.kind === 'class') {
|
||||
for (const member of dec.members ?? []) {
|
||||
if (member.inheritedFrom) {
|
||||
member.inheritedFrom.module = replace(member.inheritedFrom.module, terms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
// Generate custom VS Code data
|
||||
customElementVsCodePlugin({
|
||||
outdir,
|
||||
cssFileName: null,
|
||||
referencesTemplate: (_, tag) => [
|
||||
{
|
||||
name: 'Documentation',
|
||||
url: `https://shoelace.style/components/${tag.replace('sl-', '')}`
|
||||
}
|
||||
]
|
||||
}),
|
||||
customElementJetBrainsPlugin({
|
||||
excludeCss: true,
|
||||
referencesTemplate: (_, tag) => {
|
||||
return {
|
||||
name: 'Documentation',
|
||||
url: `https://shoelace.style/components/${tag.replace('sl-', '')}`
|
||||
};
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
# Not Found
|
||||
|
||||
Sorry, I couldn't find that page.
|
||||
349
docs/_includes/component.njk
Normal file
@@ -0,0 +1,349 @@
|
||||
{% extends "default.njk" %}
|
||||
|
||||
{# Find the component based on the `tag` front matter #}
|
||||
{% set component = getComponent('sl-' + page.fileSlug) %}
|
||||
|
||||
{% block content %}
|
||||
{# Determine the badge variant #}
|
||||
{% if component.status == 'stable' %}
|
||||
{% set badgeVariant = 'primary' %}
|
||||
{% elseif component.status == 'experimental' %}
|
||||
{% set badgeVariant = 'warning' %}
|
||||
{% elseif component.status == 'planned' %}
|
||||
{% set badgeVariant = 'neutral' %}
|
||||
{% elseif component.status == 'deprecated' %}
|
||||
{% set badgeVariant = 'danger' %}
|
||||
{% else %}
|
||||
{% set badgeVariant = 'neutral' %}
|
||||
{% endif %}
|
||||
|
||||
{# Header #}
|
||||
<header class="component-header">
|
||||
<h1>{{ component.name | classNameToComponentName }}</h1>
|
||||
|
||||
<div class="component-header__tag">
|
||||
<code><{{ component.tagName }}> | {{ component.name }}</code>
|
||||
</div>
|
||||
|
||||
<div class="component-header__info">
|
||||
<sl-badge variant="neutral" pill>
|
||||
Since {{component.since or '?' }}
|
||||
</sl-badge>
|
||||
<sl-badge variant="{{ badgeVariant }}" pill style="text-transform: capitalize;">
|
||||
{{ component.status }}
|
||||
</sl-badge>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<p class="component-summary">
|
||||
{% if component.summary %}
|
||||
{{ component.summary | markdownInline | safe }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{# Markdown content #}
|
||||
{{ content | safe }}
|
||||
|
||||
{# Importing #}
|
||||
<h2>Importing</h2>
|
||||
<p>
|
||||
If you're using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use
|
||||
any of the following snippets to <a href="/getting-started/installation#cherry-picking">cherry pick</a> this component.
|
||||
</p>
|
||||
|
||||
<sl-tab-group>
|
||||
<sl-tab slot="nav" panel="script">Script</sl-tab>
|
||||
<sl-tab slot="nav" panel="import">Import</sl-tab>
|
||||
<sl-tab slot="nav" panel="bundler">Bundler</sl-tab>
|
||||
<sl-tab slot="nav" panel="react">React</sl-tab>
|
||||
|
||||
<sl-tab-panel name="script">
|
||||
<p>
|
||||
To import this component from <a href="https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace">the CDN</a>
|
||||
using a script tag:
|
||||
</p>
|
||||
<pre><code class="language-html"><script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@{{ meta.version }}/{{ meta.cdndir }}/{{ component.path }}"></script></code></pre>
|
||||
</sl-tab-panel>
|
||||
|
||||
<sl-tab-panel name="import">
|
||||
<p>
|
||||
To import this component from <a href="https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace">the CDN</a>
|
||||
using a JavaScript import:
|
||||
</p>
|
||||
<pre><code class="language-js">import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@{{ meta.version }}/{{ meta.cdndir }}/{{ component.path }}';</code></pre>
|
||||
</sl-tab-panel>
|
||||
|
||||
<sl-tab-panel name="bundler">
|
||||
<p>
|
||||
To import this component using <a href="{{ rootUrl('/getting-started/installation#bundling') }}">a bundler</a>:
|
||||
</p>
|
||||
<pre><code class="language-js">import '@shoelace-style/shoelace/{{ meta.npmdir }}/{{ component.path }}';</code></pre>
|
||||
</sl-tab-panel>
|
||||
|
||||
<sl-tab-panel name="react">
|
||||
<p>
|
||||
To import this component as a <a href="/frameworks/react">React component</a>:
|
||||
</p>
|
||||
<pre><code class="language-js">import {{ component.name }} from '@shoelace-style/shoelace/{{ meta.npmdir }}/react/{{ component.tagNameWithoutPrefix }}';</code></pre>
|
||||
</sl-tab-panel>
|
||||
</sl-tab-group>
|
||||
|
||||
{# Slots #}
|
||||
{% if component.slots.length %}
|
||||
<h2>Slots</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for slot in component.slots %}
|
||||
<tr>
|
||||
<td class="nowrap">
|
||||
{% if slot.name %}
|
||||
<code>{{ slot.name }}</code>
|
||||
{% else %}
|
||||
(default)
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ slot.description | markdownInline | safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#slots') }}">using slots</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Properties #}
|
||||
{% if component.properties.length %}
|
||||
<h2>Properties</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-reflects">Reflects</th>
|
||||
<th class="table-type">Type</th>
|
||||
<th class="table-default">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for prop in component.properties %}
|
||||
<tr>
|
||||
<td>
|
||||
<code class="nowrap">{{ prop.name }}</code>
|
||||
{% if prop.attribute | length > 0 %}
|
||||
{% if prop.attribute != prop.name %}
|
||||
<br>
|
||||
<sl-tooltip content="This attribute is different from its property">
|
||||
<small>
|
||||
<code class="nowrap">
|
||||
{{ prop.attribute }}
|
||||
</code>
|
||||
</small>
|
||||
</sl-tooltip>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ prop.description | markdownInline | safe }}
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
{% if prop.reflects %}
|
||||
<sl-icon label="yes" name="check-lg"></sl-icon>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if prop.type.text %}
|
||||
<code>{{ prop.type.text | markdownInline | safe }}</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if prop.default %}
|
||||
<code>{{ prop.default | markdownInline | safe }}</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>updateComplete</code></td>
|
||||
<td>
|
||||
A read-only promise that resolves when the component has
|
||||
<a href="/getting-started/usage?#component-rendering-and-updating">finished updating</a>.
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#attributes-and-properties') }}">attributes and properties</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Events #}
|
||||
{% if component.events.length %}
|
||||
<h2>Events</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name" data-flavor="html">Name</th>
|
||||
<th class="table-name" data-flavor="react">React Event</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-event-detail">Event Detail</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in component.events %}
|
||||
<tr>
|
||||
<td data-flavor="html"><code class="nowrap">{{ event.name }}</code></td>
|
||||
<td data-flavor="react"><code class="nowrap">{{ event.reactName }}</code></td>
|
||||
<td>{{ event.description | markdownInline | safe }}</td>
|
||||
<td>
|
||||
{% if event.type.text %}
|
||||
<code>{{ event.type.text }}</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#events') }}">events</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Methods #}
|
||||
{% if component.methods.length %}
|
||||
<h2>Methods</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-arguments">Arguments</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for method in component.methods %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ method.name }}()</code></td>
|
||||
<td>{{ method.description | markdownInline | safe }}</td>
|
||||
<td>
|
||||
{% if method.parameters.length %}
|
||||
<code>
|
||||
{% for param in method.parameters %}
|
||||
{{ param.name }}: {{ param.type.text }}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#methods') }}">methods</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Custom Properties #}
|
||||
{% if component.cssProperties.length %}
|
||||
<h2>Custom Properties</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-default">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cssProperty in component.cssProperties %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ cssProperty.name }}</code></td>
|
||||
<td>{{ cssProperty.description | markdownInline | safe }}</td>
|
||||
<td>{{ cssProperty.default }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#custom-properties') }}">customizing CSS custom properties</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# CSS Parts #}
|
||||
{% if component.cssParts.length %}
|
||||
<h2>Parts</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cssPart in component.cssParts %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ cssPart.name }}</code></td>
|
||||
<td>{{ cssPart.description | markdownInline | safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/customizing/#css-parts') }}">customizing CSS parts</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Animations #}
|
||||
{% if component.animations.length %}
|
||||
<h2>Animations</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for animation in component.animations %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ animation.name }}</code></td>
|
||||
<td>{{ animation.description | markdownInline | safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/customizing#animations') }}">customizing animations</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Dependencies #}
|
||||
{% if component.dependencies.length %}
|
||||
<h2>Dependencies</h2>
|
||||
|
||||
<p>This component automatically imports the following dependencies.</p>
|
||||
|
||||
<ul>
|
||||
{% for dependency in component.dependencies %}
|
||||
<li><code><{{ dependency }}></code></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
150
docs/_includes/default.njk
Normal file
@@ -0,0 +1,150 @@
|
||||
<!DOCTYPE html>
|
||||
<html
|
||||
lang="en"
|
||||
data-layout="{{ layout }}"
|
||||
data-shoelace-version="{{ meta.version }}"
|
||||
>
|
||||
<head>
|
||||
{# Metadata #}
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="{{ meta.description }}" />
|
||||
<title>{{ meta.title }}</title>
|
||||
|
||||
{# Opt out of Turbo caching #}
|
||||
<meta name="turbo-cache-control">
|
||||
|
||||
{# Stylesheets #}
|
||||
<link rel="stylesheet" href="{{ assetUrl('styles/docs.css') }}" />
|
||||
<link rel="stylesheet" href="{{ assetUrl('styles/code-previews.css') }}" />
|
||||
<link rel="stylesheet" href="{{ assetUrl('styles/search.css') }}" />
|
||||
|
||||
{# Favicons #}
|
||||
<link rel="icon" href="{{ assetUrl('images/logo.svg') }}" type="image/x-icon" />
|
||||
|
||||
{# Twitter Cards #}
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:creator" content="shoelace_style" />
|
||||
<meta name="twitter:image" content="{{ assetUrl(meta.image, true) }}" />
|
||||
|
||||
{# OpenGraph #}
|
||||
<meta property="og:url" content="{{ rootUrl(page.url, true) }}" />
|
||||
<meta property="og:title" content="{{ meta.title }}" />
|
||||
<meta property="og:description" content="{{ meta.description }}" />
|
||||
<meta property="og:image" content="{{ assetUrl(meta.image, true) }}" />
|
||||
|
||||
{# Shoelace #}
|
||||
<link rel="stylesheet" href="/dist/themes/light.css" />
|
||||
<link rel="stylesheet" href="/dist/themes/dark.css" />
|
||||
<script type="module" src="/dist/shoelace-autoloader.js"></script>
|
||||
|
||||
{# Set the initial theme and menu states here to prevent flashing #}
|
||||
<script>
|
||||
(() => {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const theme = localStorage.getItem('theme') || 'auto';
|
||||
document.documentElement.classList.toggle('sl-theme-dark', theme === 'dark' || (theme === 'auto' && prefersDark));
|
||||
})();
|
||||
</script>
|
||||
|
||||
{# Turbo + Scroll positioning #}
|
||||
<script src="{{ assetUrl('scripts/turbo.js') }}" type="module"></script>
|
||||
<script src="{{ assetUrl('scripts/docs.js') }}" defer></script>
|
||||
<script src="{{ assetUrl('scripts/code-previews.js') }}" defer></script>
|
||||
<script src="{{ assetUrl('scripts/lunr.js') }}" defer></script>
|
||||
<script src="{{ assetUrl('scripts/search.js') }}" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<a id="skip-to-main" class="visually-hidden" href="#main-content" data-smooth-link="false">
|
||||
Skip to main content
|
||||
</a>
|
||||
|
||||
{# Menu toggle #}
|
||||
<button id="menu-toggle" type="button" aria-label="Menu">
|
||||
<svg width="148" height="148" viewBox="0 0 148 148" xmlns="http://www.w3.org/2000/svg">
|
||||
<g stroke="currentColor" stroke-width="18" fill="none" fill-rule="evenodd" stroke-linecap="round">
|
||||
<path d="M9.5 125.5h129M9.5 74.5h129M9.5 23.5h129"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{# Icon toolbar #}
|
||||
<div id="icon-toolbar">
|
||||
{# GitHub #}
|
||||
<a href="https://github.com/shoelace-style/shoelace" title="View Shoelace on GitHub">
|
||||
<sl-icon name="github"></sl-icon>
|
||||
</a>
|
||||
|
||||
{# Twitter #}
|
||||
<a href="https://twitter.com/shoelace_style" title="Follow Shoelace on Twitter">
|
||||
<sl-icon name="twitter"></sl-icon>
|
||||
</a>
|
||||
|
||||
{# Theme selector #}
|
||||
<sl-dropdown id="theme-selector" placement="bottom-end" distance="3">
|
||||
<sl-button slot="trigger" size="small" variant="text" caret title="Press \ to toggle">
|
||||
<sl-icon class="only-light" name="sun-fill"></sl-icon>
|
||||
<sl-icon class="only-dark" name="moon-fill"></sl-icon>
|
||||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item type="checkbox" value="light">Light</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" value="dark">Dark</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item type="checkbox" value="auto">System</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<aside id="sidebar" data-preserve-scroll>
|
||||
<header>
|
||||
<a href="/">
|
||||
<img src="{{ assetUrl('images/wordmark.svg') }}" alt="Shoelace" />
|
||||
</a>
|
||||
<div class="sidebar-version">
|
||||
{{ meta.version }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="sidebar-buttons">
|
||||
<sl-button size="small" class="repo-button repo-button--github" href="https://github.com/shoelace-style/shoelace" target="_blank">
|
||||
<sl-icon slot="prefix" name="github"></sl-icon> Code
|
||||
</sl-button>
|
||||
<sl-button size="small" class="repo-button repo-button--star" href="https://github.com/shoelace-style/shoelace/stargazers" target="_blank">
|
||||
<sl-icon slot="prefix" name="star-fill"></sl-icon> Star
|
||||
</sl-button>
|
||||
<sl-button size="small" class="repo-button repo-button--twitter" href="https://twitter.com/shoelace_style" target="_blank">
|
||||
<sl-icon slot="prefix" name="twitter"></sl-icon> Follow
|
||||
</sl-button>
|
||||
</div>
|
||||
|
||||
<button class="search-box" type="button" title="Press / to search" aria-label="Search" data-plugin="search">
|
||||
<sl-icon name="search"></sl-icon>
|
||||
<span>Search</span>
|
||||
</button>
|
||||
|
||||
<nav>
|
||||
{% include 'sidebar.njk' %}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{# Content #}
|
||||
<main>
|
||||
<a id="main-content"></a>
|
||||
<article id="content" class="content{% if toc %} content--with-toc{% endif %}">
|
||||
{% if toc %}
|
||||
<div class="content__toc">
|
||||
<ul>
|
||||
<li class="top"><a href="#">{{ meta.title }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="content__body">
|
||||
{% block content %}
|
||||
{{ content | safe }}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
65
docs/_includes/sidebar.njk
Normal file
@@ -0,0 +1,65 @@
|
||||
<ul>
|
||||
<li>
|
||||
<h2>Getting Started</h2>
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/getting-started/installation">Installation</a></li>
|
||||
<li><a href="/getting-started/usage">Usage</a></li>
|
||||
<li><a href="/getting-started/themes">Themes</a></li>
|
||||
<li><a href="/getting-started/customizing">Customizing</a></li>
|
||||
<li><a href="/getting-started/form-controls">Form Controls</a></li>
|
||||
<li><a href="/getting-started/localization">Localization</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Frameworks</h2>
|
||||
<ul>
|
||||
<li><a href="/frameworks/react">React</a></li>
|
||||
<li><a href="/frameworks/vue">Vue</a></li>
|
||||
<li><a href="/frameworks/angular">Angular</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Resources</h2>
|
||||
<ul>
|
||||
<li><a href="/resources/community">Community</a></li>
|
||||
<li><a href="https://github.com/shoelace-style/shoelace/discussions">Help & Support</a></li>
|
||||
<li><a href="/resources/accessibility">Accessibility</a></li>
|
||||
<li><a href="/resources/contributing">Contributing</a></li>
|
||||
<li><a href="/resources/changelog">Changelog</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Components</h2>
|
||||
<ul>
|
||||
{% for component in meta.components %}
|
||||
<li>
|
||||
<a href="/components/{{ component.tagName | removeSlPrefix }}">
|
||||
{{ component.name | classNameToComponentName }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Design Tokens</h2>
|
||||
<ul>
|
||||
<li><a href="/tokens/typography">Typography</a></li>
|
||||
<li><a href="/tokens/color">Color</a></li>
|
||||
<li><a href="/tokens/spacing">Spacing</a></li>
|
||||
<li><a href="/tokens/elevation">Elevation</a></li>
|
||||
<li><a href="/tokens/border-radius">Border Radius</a></li>
|
||||
<li><a href="/tokens/transition">Transition</a></li>
|
||||
<li><a href="/tokens/z-index">Z-index</a></li>
|
||||
<li><a href="/tokens/more">More Tokens</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Tutorials</h2>
|
||||
<ul>
|
||||
<li><a href="/tutorials/integrating-with-laravel">Integrating with Laravel</a></li>
|
||||
<li><a href="/tutorials/integrating-with-nextjs">Integrating with NextJS</a></li>
|
||||
<li><a href="/tutorials/integrating-with-rails">Integrating with Rails</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1,74 +0,0 @@
|
||||
- Getting Started
|
||||
- [Overview](/)
|
||||
- [Installation](/getting-started/installation)
|
||||
- [Usage](/getting-started/usage)
|
||||
- [Customizing](/getting-started/customizing)
|
||||
- [Themes](/getting-started/themes)
|
||||
|
||||
- Resources
|
||||
- [Community](/resources/community)
|
||||
- [Contributing](/resources/contributing)
|
||||
- [Changelog](/resources/changelog)
|
||||
|
||||
- Components
|
||||
- [Alert](/components/alert)
|
||||
- [Avatar](/components/avatar)
|
||||
- [Badge](/components/badge)
|
||||
- [Button](/components/button)
|
||||
- [Button Group](/components/button-group)
|
||||
- [Card](/components/card)
|
||||
- [Checkbox](/components/checkbox)
|
||||
- [Color Picker](/components/color-picker)
|
||||
- [Details](/components/details)
|
||||
- [Dialog](/components/dialog)
|
||||
- [Drawer](/components/drawer)
|
||||
- [Dropdown](/components/dropdown)
|
||||
- [Form](/components/form)
|
||||
- [Icon](/components/icon)
|
||||
- [Icon Button](/components/icon-button)
|
||||
- [Image Comparer](/components/image-comparer)
|
||||
- [Input](/components/input)
|
||||
- [Menu](/components/menu)
|
||||
- [Menu Divider](/components/menu-divider)
|
||||
- [Menu Item](/components/menu-item)
|
||||
- [Menu Label](/components/menu-label)
|
||||
- [Progress Bar](/components/progress-bar)
|
||||
- [Progress Ring](/components/progress-ring)
|
||||
- [Radio](/components/radio)
|
||||
- [Radio Group](/components/radio-group)
|
||||
- [Range](/components/range)
|
||||
- [Rating](/components/rating)
|
||||
- [Select](/components/select)
|
||||
- [Skeleton](/components/skeleton)
|
||||
- [Spinner](/components/spinner)
|
||||
- [Switch](/components/switch)
|
||||
- [Tab Group](/components/tab-group)
|
||||
- [Tab](/components/tab)
|
||||
- [Tab Panel](/components/tab-panel)
|
||||
- [Tag](/components/tag)
|
||||
- [Textarea](/components/textarea)
|
||||
- [Tooltip](/components/tooltip)
|
||||
|
||||
- Utilities
|
||||
- [Animation](/components/animation)
|
||||
- [Format Bytes](/components/format-bytes)
|
||||
- [Format Date](/components/format-date)
|
||||
- [Format Number](/components/format-number)
|
||||
- [Include](/components/include)
|
||||
- [QR Code](/components/qr-code)
|
||||
- [Relative Time](/components/relative-time)
|
||||
- [Resize Observer](/components/resize-observer)
|
||||
- [Responsive Media](/components/responsive-media)
|
||||
|
||||
- Design Tokens
|
||||
- [Typography](/tokens/typography)
|
||||
- [Color](/tokens/color)
|
||||
- [Spacing](/tokens/spacing)
|
||||
- [Elevation](/tokens/elevation)
|
||||
- [Border Radius](/tokens/border-radius)
|
||||
- [Transition](/tokens/transition)
|
||||
- [Z-index](/tokens/z-index)
|
||||
|
||||
- Tutorials
|
||||
- [Integrating with NextJS](/tutorials/integrating-with-nextjs)
|
||||
- [Integrating with Rails](/tutorials/integrating-with-rails)
|
||||
35
docs/_utilities/active-links.cjs
Normal file
@@ -0,0 +1,35 @@
|
||||
function normalizePathname(pathname) {
|
||||
// Remove /index.html
|
||||
if (pathname.endsWith('/index.html')) {
|
||||
pathname = pathname.replace(/\/index\.html/, '');
|
||||
}
|
||||
|
||||
// Remove trailing slashes
|
||||
return pathname.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a class name to links that are currently active.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
className: 'active-link', // the class to add to active links
|
||||
pathname: undefined, // the current pathname to compare
|
||||
within: 'body', // element containing the target links
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
|
||||
if (!within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll('a').forEach(link => {
|
||||
if (normalizePathname(options.pathname) === normalizePathname(link.pathname)) {
|
||||
link.classList.add(options.className);
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
64
docs/_utilities/anchor-headings.cjs
Normal file
@@ -0,0 +1,64 @@
|
||||
const { createSlug } = require('./strings.cjs');
|
||||
|
||||
/**
|
||||
* Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM.
|
||||
* The same document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
levels: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], // the headings to convert
|
||||
className: 'anchor-heading', // the class name to add
|
||||
within: 'body', // the element containing the target headings
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
|
||||
if (!within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
|
||||
const hasAnchor = heading.querySelector('a');
|
||||
const anchor = doc.createElement('a');
|
||||
let id = heading.textContent ?? '';
|
||||
let suffix = 0;
|
||||
|
||||
// Skip heading levels we don't care about
|
||||
if (!options.levels?.includes(heading.tagName.toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert dots to underscores
|
||||
id = id.replace(/\./g, '_');
|
||||
|
||||
// Turn it into a slug
|
||||
id = createSlug(id);
|
||||
|
||||
// Make sure it starts with a letter
|
||||
if (!/^[a-z]/i.test(id)) {
|
||||
id = `id_${id}`;
|
||||
}
|
||||
|
||||
// Make sure the id is unique
|
||||
const originalId = id;
|
||||
while (doc.getElementById(id) !== null) {
|
||||
id = `${originalId}-${++suffix}`;
|
||||
}
|
||||
|
||||
if (hasAnchor || !id) return;
|
||||
|
||||
heading.setAttribute('id', id);
|
||||
anchor.setAttribute('href', `#${encodeURIComponent(id)}`);
|
||||
anchor.setAttribute('aria-label', `Direct link to "${heading.textContent}"`);
|
||||
|
||||
if (options.className) {
|
||||
heading.classList.add(options.className);
|
||||
}
|
||||
|
||||
// Append the anchor
|
||||
heading.append(anchor);
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
71
docs/_utilities/cem.cjs
Normal file
@@ -0,0 +1,71 @@
|
||||
const customElementsManifest = require('../../dist/custom-elements.json');
|
||||
|
||||
//
|
||||
// Export it here so we can import it elsewhere and use the same version
|
||||
//
|
||||
module.exports.customElementsManifest = customElementsManifest;
|
||||
|
||||
//
|
||||
// Gets all components from custom-elements.json and returns them in a more documentation-friendly format.
|
||||
//
|
||||
module.exports.getAllComponents = function () {
|
||||
const allComponents = [];
|
||||
|
||||
customElementsManifest.modules?.forEach(module => {
|
||||
module.declarations?.forEach(declaration => {
|
||||
if (declaration.customElement) {
|
||||
// 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 members that are private or don't have 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 properties = members?.filter(prop => {
|
||||
// Look for a corresponding attribute
|
||||
const attribute = declaration.attributes?.find(attr => attr.fieldName === prop.name);
|
||||
if (attribute) {
|
||||
prop.attribute = attribute.name || attribute.fieldName;
|
||||
}
|
||||
|
||||
return prop.kind === 'field' && prop.privacy !== 'private';
|
||||
});
|
||||
allComponents.push({
|
||||
...declaration,
|
||||
methods,
|
||||
properties
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Build dependency graphs
|
||||
allComponents.forEach(component => {
|
||||
const dependencies = [];
|
||||
|
||||
// Recursively fetch sub-dependencies
|
||||
function getDependencies(tag) {
|
||||
const cmp = allComponents.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
|
||||
return allComponents.sort((a, b) => {
|
||||
if (a.name < b.name) return -1;
|
||||
if (a.name > b.name) return 1;
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
138
docs/_utilities/code-previews.cjs
Normal file
@@ -0,0 +1,138 @@
|
||||
let count = 1;
|
||||
|
||||
function escapeHtml(str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns code fields with the :preview suffix into interactive code previews.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
within: 'body', // the element containing the code fields to convert
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
if (!within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll('[class*=":preview"]').forEach(code => {
|
||||
const pre = code.closest('pre');
|
||||
if (!pre) {
|
||||
return;
|
||||
}
|
||||
const adjacentPre = pre.nextElementSibling?.tagName.toLowerCase() === 'pre' ? pre.nextElementSibling : null;
|
||||
const reactCode = adjacentPre?.querySelector('code[class$="react"]');
|
||||
const sourceGroupId = `code-preview-source-group-${count}`;
|
||||
const isExpanded = code.getAttribute('class').includes(':expanded');
|
||||
const noCodePen = code.getAttribute('class').includes(':no-codepen');
|
||||
|
||||
count++;
|
||||
|
||||
const htmlButton = `
|
||||
<button type="button"
|
||||
title="Show HTML code"
|
||||
class="code-preview__button code-preview__button--html"
|
||||
>
|
||||
HTML
|
||||
</button>
|
||||
`;
|
||||
|
||||
const reactButton = `
|
||||
<button type="button" title="Show React code" class="code-preview__button code-preview__button--react">
|
||||
React
|
||||
</button>
|
||||
`;
|
||||
|
||||
const codePenButton = `
|
||||
<button type="button" class="code-preview__button code-preview__button--codepen" title="Edit on CodePen">
|
||||
<svg
|
||||
width="138"
|
||||
height="26"
|
||||
viewBox="0 0 138 26"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M80 6h-9v14h9 M114 6h-9 v14h9 M111 13h-6 M77 13h-6 M122 20V6l11 14V6 M22 16.7L33 24l11-7.3V9.3L33 2L22 9.3V16.7z M44 16.7L33 9.3l-11 7.4 M22 9.3l11 7.3 l11-7.3 M33 2v7.3 M33 16.7V24 M88 14h6c2.2 0 4-1.8 4-4s-1.8-4-4-4h-6v14 M15 8c-1.3-1.3-3-2-5-2c-4 0-7 3-7 7s3 7 7 7 c2 0 3.7-0.8 5-2 M64 13c0 4-3 7-7 7h-5V6h5C61 6 64 9 64 13z" />
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
const codePreview = `
|
||||
<div class="code-preview ${isExpanded ? 'code-preview--expanded' : ''}">
|
||||
<div class="code-preview__preview">
|
||||
${code.textContent}
|
||||
<div class="code-preview__resizer">
|
||||
<sl-icon name="grip-vertical"></sl-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="code-preview__source-group" id="${sourceGroupId}">
|
||||
<div class="code-preview__source code-preview__source--html" ${reactCode ? 'data-flavor="html"' : ''}>
|
||||
<pre><code class="language-html">${escapeHtml(code.textContent)}</code></pre>
|
||||
</div>
|
||||
|
||||
${
|
||||
reactCode
|
||||
? `
|
||||
<div class="code-preview__source code-preview__source--react" data-flavor="react">
|
||||
<pre><code class="language-jsx">${escapeHtml(reactCode.textContent)}</code></pre>
|
||||
</div>
|
||||
`
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="code-preview__buttons">
|
||||
<button
|
||||
type="button"
|
||||
class="code-preview__button code-preview__toggle"
|
||||
aria-expanded="${isExpanded ? 'true' : 'false'}"
|
||||
aria-controls="${sourceGroupId}"
|
||||
>
|
||||
Source
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
${reactCode ? ` ${htmlButton} ${reactButton} ` : ''}
|
||||
|
||||
${noCodePen ? '' : codePenButton}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
pre.insertAdjacentHTML('afterend', codePreview);
|
||||
pre.remove();
|
||||
|
||||
if (adjacentPre) {
|
||||
adjacentPre.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Wrap code preview scripts in anonymous functions so they don't run in the global scope
|
||||
doc.querySelectorAll('.code-preview__preview script').forEach(script => {
|
||||
if (script.type === 'module') {
|
||||
// Modules are already scoped
|
||||
script.textContent = script.innerHTML;
|
||||
} else {
|
||||
// Wrap non-modules in an anonymous function so they don't run in the global scope
|
||||
script.textContent = `(() => { ${script.innerHTML} })();`;
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
23
docs/_utilities/copy-code-buttons.cjs
Normal file
@@ -0,0 +1,23 @@
|
||||
let codeBlockId = 0;
|
||||
|
||||
/**
|
||||
* Adds copy code buttons to code fields. The provided doc should be a document object provided by JSDOM. The same
|
||||
* document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc) {
|
||||
doc.querySelectorAll('pre > code').forEach(code => {
|
||||
const pre = code.closest('pre');
|
||||
const button = doc.createElement('sl-copy-button');
|
||||
|
||||
if (!code.id) {
|
||||
code.id = `code-block-${++codeBlockId}`;
|
||||
}
|
||||
|
||||
button.classList.add('copy-code-button');
|
||||
button.setAttribute('from', code.id);
|
||||
|
||||
pre.append(button);
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
41
docs/_utilities/external-links.cjs
Normal file
@@ -0,0 +1,41 @@
|
||||
const { isExternalLink } = require('./strings.cjs');
|
||||
|
||||
/**
|
||||
* Transforms external links to make them safer and optionally add a target. The provided doc should be a document
|
||||
* object provided by JSDOM. The same document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
className: 'external-link', // the class name to add to links
|
||||
noopener: true, // sets rel="noopener"
|
||||
noreferrer: true, // sets rel="noreferrer"
|
||||
ignore: () => false, // callback function to filter links that should be ignored
|
||||
within: 'body', // element that contains the target links
|
||||
target: '', // sets the target attribute
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
|
||||
if (within) {
|
||||
within.querySelectorAll('a').forEach(link => {
|
||||
if (isExternalLink(link) && !options.ignore(link)) {
|
||||
link.classList.add(options.className);
|
||||
|
||||
const rel = [];
|
||||
if (options.noopener) rel.push('noopener');
|
||||
if (options.noreferrer) rel.push('noreferrer');
|
||||
|
||||
if (rel.length) {
|
||||
link.setAttribute('rel', rel.join(' '));
|
||||
}
|
||||
|
||||
if (options.target) {
|
||||
link.setAttribute('target', options.target);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return doc;
|
||||
};
|
||||
63
docs/_utilities/highlight-code.cjs
Normal file
@@ -0,0 +1,63 @@
|
||||
const Prism = require('prismjs');
|
||||
const PrismLoader = require('prismjs/components/index.js');
|
||||
|
||||
PrismLoader('diff');
|
||||
PrismLoader.silent = true;
|
||||
|
||||
/** Highlights a code string. */
|
||||
function highlight(code, language) {
|
||||
const alias = language.replace(/^diff-/, '');
|
||||
const isDiff = /^diff-/i.test(language);
|
||||
|
||||
// Auto-load the target language
|
||||
if (!Prism.languages[alias]) {
|
||||
PrismLoader(alias);
|
||||
|
||||
if (!Prism.languages[alias]) {
|
||||
throw new Error(`Unsupported language for code highlighting: "${language}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Register diff-* languages to use the diff grammar
|
||||
if (isDiff) {
|
||||
Prism.languages[language] = Prism.languages.diff;
|
||||
}
|
||||
|
||||
return Prism.highlight(code, Prism.languages[language], language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights all code fields that have a language parameter. If the language has a colon in its name, the first chunk
|
||||
* will be the language used and additional chunks will be applied as classes to the `<pre>`. For example, a code field
|
||||
* tagged with "html:preview" will be rendered as `<pre class="language-html preview">`.
|
||||
*
|
||||
* The provided doc should be a document object provided by JSDOM. The same document will be returned with the
|
||||
* appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc) {
|
||||
doc.querySelectorAll('pre > code[class]').forEach(code => {
|
||||
// Look for class="language-*" and split colons into separate classes
|
||||
code.classList.forEach(className => {
|
||||
if (className.startsWith('language-')) {
|
||||
//
|
||||
// We use certain suffixes to indicate code previews, expanded states, etc. The class might look something like
|
||||
// this:
|
||||
//
|
||||
// class="language-html:preview:expanded"
|
||||
//
|
||||
// The language will always come first, so we need to drop the "language-" prefix and everything after the first
|
||||
// color to get the highlighter language.
|
||||
//
|
||||
const language = className.replace(/^language-/, '').split(':')[0];
|
||||
|
||||
try {
|
||||
code.innerHTML = highlight(code.textContent ?? '', language);
|
||||
} catch (err) {
|
||||
// Language not found, skip it
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
67
docs/_utilities/markdown.cjs
Normal file
@@ -0,0 +1,67 @@
|
||||
const MarkdownIt = require('markdown-it');
|
||||
const markdownItContainer = require('markdown-it-container');
|
||||
const markdownItIns = require('markdown-it-ins');
|
||||
const markdownItKbd = require('markdown-it-kbd');
|
||||
const markdownItMark = require('markdown-it-mark');
|
||||
const markdownItReplaceIt = require('markdown-it-replace-it');
|
||||
|
||||
const markdown = MarkdownIt({
|
||||
html: true,
|
||||
xhtmlOut: false,
|
||||
breaks: false,
|
||||
langPrefix: 'language-',
|
||||
linkify: false,
|
||||
typographer: false
|
||||
});
|
||||
|
||||
// Third-party plugins
|
||||
markdown.use(markdownItContainer);
|
||||
markdown.use(markdownItIns);
|
||||
markdown.use(markdownItKbd);
|
||||
markdown.use(markdownItMark);
|
||||
markdown.use(markdownItReplaceIt);
|
||||
|
||||
// Callouts
|
||||
['tip', 'warning', 'danger'].forEach(type => {
|
||||
markdown.use(markdownItContainer, type, {
|
||||
render: function (tokens, idx) {
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return `<div role="alert" class="callout callout--${type}">`;
|
||||
}
|
||||
return '</div>\n';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Asides
|
||||
markdown.use(markdownItContainer, 'aside', {
|
||||
render: function (tokens, idx) {
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return `<aside>`;
|
||||
}
|
||||
return '</aside>\n';
|
||||
}
|
||||
});
|
||||
|
||||
// Details
|
||||
markdown.use(markdownItContainer, 'details', {
|
||||
validate: params => params.trim().match(/^details\s+(.*)$/),
|
||||
render: (tokens, idx) => {
|
||||
const m = tokens[idx].info.trim().match(/^details\s+(.*)$/);
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return `<details>\n<summary><span>${markdown.utils.escapeHtml(m[1])}</span></summary>\n`;
|
||||
}
|
||||
return '</details>\n';
|
||||
}
|
||||
});
|
||||
|
||||
// Replace [#1234] with a link to GitHub issues
|
||||
markdownItReplaceIt.replacements.push({
|
||||
name: 'github-issues',
|
||||
re: /\[#([0-9]+)\]/gs,
|
||||
sub: '<a href="https://github.com/shoelace-style/shoelace/issues/$1">#$1</a>',
|
||||
html: true,
|
||||
default: true
|
||||
});
|
||||
|
||||
module.exports = markdown;
|
||||
26
docs/_utilities/prettier.cjs
Normal file
@@ -0,0 +1,26 @@
|
||||
const { format } = require('prettier');
|
||||
|
||||
/** Formats markup using prettier. */
|
||||
module.exports = function (content, options) {
|
||||
options = {
|
||||
arrowParens: 'avoid',
|
||||
bracketSpacing: true,
|
||||
htmlWhitespaceSensitivity: 'css',
|
||||
insertPragma: false,
|
||||
bracketSameLine: false,
|
||||
jsxSingleQuote: false,
|
||||
parser: 'html',
|
||||
printWidth: 120,
|
||||
proseWrap: 'preserve',
|
||||
quoteProps: 'as-needed',
|
||||
requirePragma: false,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'none',
|
||||
useTabs: false,
|
||||
...options
|
||||
};
|
||||
|
||||
return format(content, options);
|
||||
};
|
||||
19
docs/_utilities/replacer.cjs
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @typedef {object} Replacement
|
||||
* @property {string | RegExp} pattern
|
||||
* @property {string} replacement
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Array<Replacement>} Replacements
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Document} content
|
||||
* @param {Replacements} replacements
|
||||
*/
|
||||
module.exports = function (content, replacements) {
|
||||
replacements.forEach(replacement => {
|
||||
content.body.innerHTML = content.body.innerHTML.replaceAll(replacement.pattern, replacement.replacement);
|
||||
});
|
||||
};
|
||||
21
docs/_utilities/scrolling-tables.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM.
|
||||
* The same document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
const tables = [...doc.querySelectorAll('table')];
|
||||
|
||||
options = {
|
||||
className: 'table-scroll', // the class name to add to the table's container
|
||||
...options
|
||||
};
|
||||
|
||||
tables.forEach(table => {
|
||||
const div = doc.createElement('div');
|
||||
div.classList.add(options.className);
|
||||
table.insertAdjacentElement('beforebegin', div);
|
||||
div.append(table);
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
16
docs/_utilities/strings.cjs
Normal file
@@ -0,0 +1,16 @@
|
||||
const slugify = require('slugify');
|
||||
|
||||
/** Creates a slug from an arbitrary string of text. */
|
||||
module.exports.createSlug = function (text) {
|
||||
return slugify(String(text), {
|
||||
remove: /[^\w|\s]/g,
|
||||
lower: true
|
||||
});
|
||||
};
|
||||
|
||||
/** Determines whether or not a link is external. */
|
||||
module.exports.isExternalLink = function (link) {
|
||||
// We use the "internal" hostname when initializing JSDOM so we know that those are local links
|
||||
if (!link.hostname || link.hostname === 'internal') return false;
|
||||
return true;
|
||||
};
|
||||
42
docs/_utilities/table-of-contents.cjs
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Generates an in-page table of contents based on headings.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
levels: ['h2'], // headings to include (they must have an id)
|
||||
container: 'nav', // the container to append links to
|
||||
listItem: true, // if true, links will be wrapped in <li>
|
||||
within: 'body', // the element containing the headings to summarize
|
||||
...options
|
||||
};
|
||||
|
||||
const container = doc.querySelector(options.container);
|
||||
const within = doc.querySelector(options.within);
|
||||
const headingSelector = options.levels.map(h => `${h}[id]`).join(', ');
|
||||
|
||||
if (!container || !within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll(headingSelector).forEach(heading => {
|
||||
const listItem = doc.createElement('li');
|
||||
const link = doc.createElement('a');
|
||||
const level = heading.tagName.slice(1);
|
||||
|
||||
link.href = `#${heading.id}`;
|
||||
link.textContent = heading.textContent;
|
||||
|
||||
if (options.listItem) {
|
||||
// List item + link
|
||||
listItem.setAttribute('data-level', level);
|
||||
listItem.append(link);
|
||||
container.append(listItem);
|
||||
} else {
|
||||
// Link only
|
||||
link.setAttribute('data-level', level);
|
||||
container.append(link);
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
23
docs/_utilities/typography.cjs
Normal file
@@ -0,0 +1,23 @@
|
||||
const smartquotes = require('smartquotes');
|
||||
|
||||
smartquotes.replacements.push([/---/g, '\u2014']); // em dash
|
||||
smartquotes.replacements.push([/--/g, '\u2013']); // en dash
|
||||
smartquotes.replacements.push([/\.\.\./g, '\u2026']); // ellipsis
|
||||
smartquotes.replacements.push([/\(c\)/gi, '\u00A9']); // copyright
|
||||
smartquotes.replacements.push([/\(r\)/gi, '\u00AE']); // registered trademark
|
||||
smartquotes.replacements.push([/\?!/g, '\u2048']); // ?!
|
||||
smartquotes.replacements.push([/!!/g, '\u203C']); // !!
|
||||
smartquotes.replacements.push([/\?\?/g, '\u2047']); // ??
|
||||
smartquotes.replacements.push([/([0-9]\s?)-(\s?[0-9])/g, '$1\u2013$2']); // number ranges use en dash
|
||||
|
||||
/**
|
||||
* Improves typography by adding smart quotes and similar corrections within the specified element(s).
|
||||
*
|
||||
* The provided doc should be a document object provided by JSDOM. The same document will be returned with the
|
||||
* appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, selector = 'body') {
|
||||
const elements = [...doc.querySelectorAll(selector)];
|
||||
elements.forEach(el => smartquotes.element(el));
|
||||
return doc;
|
||||
};
|
||||
BIN
docs/assets/examples/carousel/field.jpg
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
docs/assets/examples/carousel/mountains.jpg
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
docs/assets/examples/carousel/sunset.jpg
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
docs/assets/examples/carousel/valley.jpg
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/assets/examples/carousel/waterfall.jpg
Normal file
|
After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 709 KiB |
11
docs/assets/images/awesome.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="733" xmlns="http://www.w3.org/2000/svg" height="733">
|
||||
<circle cy="366.5" cx="366.5" r="366.5"/>
|
||||
<circle cy="366.5" cx="366.5" r="336.5" fill="#fede58"/>
|
||||
<path d="M325 665c-121-21-194-115-212-233v-8l-25-1-1-18h481c6 13 10 27 13 41 13 94-38 146-114 193-45 23-93 29-142 26z"/>
|
||||
<path d="M372 647c52-6 98-28 138-62 28-25 46-56 51-87 4-20 1-57-5-70l-423-1c-2 56 39 118 74 157 31 34 72 54 116 63 11 2 38 2 49 0z" fill="#871945"/>
|
||||
<path d="M76 342c-13-26-13-57-9-85 6-27 18-52 35-68 21-20 50-23 77-18 15 4 28 12 39 23 18 17 30 40 36 67 4 20 4 41 0 60l-6 21z"/>
|
||||
<path d="M234 323c5-6 6-40 2-58-3-16-4-16-10-10-14 14-38 14-52 0-15-18-12-41 6-55 3-3 5-5 5-6-1-4-22-8-34-7-42 4-57.6 40-66.2 77-3 17-1 53 4 59H234z" fill="#fff"/>
|
||||
<path d="M378 343c-2-3-6-20-7-29-5-28-1-57 11-83 15-30 41-52 72-60 29-7 57 0 82 15 26 17 45 49 50 82 2 12 2 33 0 45-1 10-5 26-8 30z"/>
|
||||
<path d="M565 324c4-5 5-34 4-50-2-14-6-24-8-24-1 0-3 2-6 5-17 17-47 13-58-9-7-16-4-31 8-43 4-4 7-8 7-9 0 0-4-2-8-3-51-17-105 20-115 80-3 15 0 43 3 53z" fill="#fff"/>
|
||||
<path d="M504 590s-46 40-105 53c-66 15-114-7-114-7s14-76 93-95c76-18 126 49 126 49z" fill="#f9bedd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
23
docs/assets/images/gitpod.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<svg width="160" height="45" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d)">
|
||||
<rect x="2" y="2" width="156" height="40" rx="16" fill="#F9F9F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.425 11.174c.604 1.114.233 2.53-.83 3.164l-6.986 4.166a.378.378 0 00-.18.325v6.748c0 .134.069.258.18.325l5.714 3.407c.11.066.244.066.354 0l5.714-3.407a.378.378 0 00.18-.325V21.29l-4.986 2.936c-1.067.628-2.416.231-3.015-.886-.6-1.118-.22-2.532.846-3.16l7.008-4.127c2.048-1.206 4.576.345 4.576 2.806v6.718c0 1.803-.924 3.467-2.42 4.36l-5.713 3.407a4.596 4.596 0 01-4.734 0l-5.714-3.408C18.924 29.044 18 27.38 18 25.576V18.83c0-1.803.924-3.467 2.42-4.36l6.985-4.165c1.063-.634 2.415-.245 3.02.87z" fill="url(#paint0_linear)"/>
|
||||
<path fill="#F9F9F9" d="M47 12.5h95v-1H47z"/>
|
||||
<path d="M52.538 27.752c2.744 0 4.844-1.876 4.844-5.152 0-3.108-2.1-5.152-4.844-5.152s-4.802 2.002-4.802 5.152c0 3.29 2.058 5.152 4.802 5.152zm0-1.554c-1.736 0-2.912-1.316-2.912-3.598 0-2.226 1.162-3.598 2.912-3.598s2.954 1.4 2.954 3.598c0 2.31-1.218 3.598-2.954 3.598zm7.89 4.158V27.22c0-.196-.013-.378-.055-.658.434.7 1.022 1.19 2.17 1.19 1.736 0 3.066-1.414 3.066-3.626 0-2.17-1.19-3.682-2.996-3.682-1.078 0-1.806.476-2.24 1.204.042-.28.056-.462.056-.672v-.308H58.72v9.688h1.708zm1.695-3.948c-1.036 0-1.764-.938-1.764-2.31 0-1.414.742-2.296 1.764-2.296 1.092 0 1.75.952 1.75 2.296 0 1.372-.7 2.31-1.75 2.31zm7.866 1.344c1.848 0 3.052-1.078 3.192-2.478h-1.736c-.112.714-.714 1.134-1.456 1.134-1.036 0-1.722-.826-1.736-1.904h4.97v-.378c0-2.226-1.204-3.682-3.29-3.682-1.988 0-3.43 1.47-3.43 3.626 0 2.366 1.442 3.682 3.486 3.682zm-1.75-4.48c.098-.896.756-1.554 1.68-1.554.924 0 1.526.63 1.554 1.554H68.24zm8.006 4.228v-4.004c0-.952.616-1.694 1.456-1.694.798 0 1.288.63 1.288 1.638v4.06h1.708v-4.312c0-1.68-.896-2.744-2.408-2.744-1.078 0-1.722.518-2.1 1.204.042-.266.056-.476.056-.672v-.308h-1.708V27.5h1.708zm8.911-7.868h1.792V17.84h-1.792v1.792zm.042 1.036V27.5h1.708v-6.832h-1.708zm5.097 6.832v-4.004c0-.952.616-1.694 1.456-1.694.798 0 1.288.63 1.288 1.638v4.06h1.708v-4.312c0-1.68-.896-2.744-2.408-2.744-1.078 0-1.722.518-2.1 1.204.042-.266.056-.476.056-.672v-.308h-1.708V27.5h1.708zm13.238.252c1.526 0 2.52-.658 2.982-1.54-.07.322-.098.644-.098.98v.308h1.68v-5.222h-4.34v1.554h2.66v.07c0 1.4-1.134 2.296-2.59 2.296-1.792 0-3.024-1.372-3.024-3.598s1.26-3.598 3.066-3.598c1.302 0 2.17.756 2.296 1.736h1.89c-.182-1.904-1.764-3.29-4.214-3.29-2.954 0-4.928 2.128-4.928 5.152 0 3.136 1.848 5.152 4.62 5.152zm6.063-8.12h1.792V17.84h-1.792v1.792zm.042 1.036V27.5h1.708v-6.832h-1.708zm6.413 6.958c.434 0 .84-.07 1.008-.126v-1.288c-.168.028-.35.042-.518.042-.728 0-1.008-.42-1.008-1.134v-3.094h1.68v-1.358h-1.68v-2.464h-1.708v2.464h-1.554v1.358h1.554v3.346c0 1.526.77 2.254 2.226 2.254zm3.961 2.73V27.22c0-.196-.014-.378-.056-.658.434.7 1.022 1.19 2.17 1.19 1.736 0 3.066-1.414 3.066-3.626 0-2.17-1.19-3.682-2.996-3.682-1.078 0-1.806.476-2.24 1.204.042-.28.056-.462.056-.672v-.308h-1.708v9.688h1.708zm1.694-3.948c-1.036 0-1.764-.938-1.764-2.31 0-1.414.742-2.296 1.764-2.296 1.092 0 1.75.952 1.75 2.296 0 1.372-.7 2.31-1.75 2.31zm7.88 1.344c2.058 0 3.514-1.372 3.514-3.64 0-2.24-1.456-3.668-3.514-3.668-2.044 0-3.5 1.428-3.5 3.668 0 2.268 1.442 3.64 3.5 3.64zm0-1.344c-1.064 0-1.764-.84-1.764-2.296 0-1.484.728-2.31 1.764-2.31 1.05 0 1.778.826 1.778 2.31 0 1.456-.714 2.296-1.778 2.296zm7.551 1.344c1.26 0 1.876-.686 2.142-1.19-.056.238-.056.42-.056.658v.28h1.708v-9.8h-1.708v3.276c0 .21 0 .42.056.672-.392-.658-1.05-1.204-2.114-1.204-1.596 0-3.15 1.218-3.15 3.668 0 2.408 1.316 3.64 3.122 3.64zm.406-1.344c-1.022 0-1.792-.896-1.792-2.31 0-1.358.77-2.296 1.792-2.296s1.778.896 1.778 2.296c0 1.372-.756 2.31-1.778 2.31z" fill="#12100C"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="33.806" y1="13.629" x2="22.389" y2="30.86" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FFB45B"/>
|
||||
<stop offset="1" stop-color="#FF8A00"/>
|
||||
</linearGradient>
|
||||
<filter id="filter0_d" x="0" y=".5" width="160" height="44" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
||||
<feOffset dy=".5"/>
|
||||
<feGaussianBlur stdDeviation="1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
|
||||
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow"/>
|
||||
<feBlend in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -1,6 +1,6 @@
|
||||
<svg viewBox="0 0 127 141" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g fill-rule="nonzero" fill="#409eff">
|
||||
<g fill-rule="nonzero" fill="#0ea5e9">
|
||||
<path d="M102.375,90.85 C102.979,90.557 103.57,90.215 104.15,89.826 L106.425,88.501 C106.848,88.19 107.64,87.573 108.8,86.65 L108.95,86.501 C109.883,85.567 110.916,85.117 112.05,85.15 C112.55,85.15 113.133,85.284 113.8,85.55 L122.3,78 C122.533,77.8 122.767,77.633 123,77.5 L123.05,77.5 C123.95,76.967 124.7,77 125.3,77.6 C126.367,78.166 126.45,79.133 125.55,80.5 L116.65,88.399 C116.717,88.533 116.75,88.666 116.75,88.799 C116.883,89.399 116.833,89.999 116.6,90.599 C116.4,90.999 116.117,91.382 115.75,91.749 C115.379,92.145 114.996,92.528 114.6,92.898 L109.45,96.648 C108.99,96.97 108.523,97.27 108.05,97.548 C107.46,97.906 106.86,98.232 106.25,98.523 C105.985,98.644 105.718,98.76 105.45,98.874 C103.841,99.559 102.174,100.017 100.45,100.249 C99.65,106.982 97.35,113.183 93.55,118.849 C88.75,125.915 82.183,131.299 73.85,134.999 C65.55,138.699 56.567,140.549 46.9,140.549 C33.567,140.415 22.75,137.415 14.45,131.549 C4.817,124.75 0,115.7 0,104.399 L0,102.849 C0.333,95.149 2.6,87.849 6.8,80.95 C10.933,74.116 16.983,69.5 24.95,67.1 C29.05,65.9 33.166,65.3 37.3,65.3 C41.567,65.3 45.967,66.083 50.5,67.65 C55.033,69.216 60.15,71.916 65.85,75.75 L80.7,85.7 C84.833,88.399 88.6,90.233 92,91.2 C91.3,84.3 88.8,78.399 84.5,73.5 C80.2,68.533 74.717,64.9 68.05,62.6 L61.65,60.4 C55.783,58.333 51.417,56.3 48.55,54.3 C40.817,49.067 36.517,41.883 35.65,32.75 L35.5,30.05 C35.5,21.25 39.067,13.883 46.2,7.95 C52.567,2.65 60.133,0 68.9,0 C75.5,0 81.417,1.9 86.65,5.7 C91.917,9.533 94.9,14.967 95.6,22 L95.75,24.75 C95.75,29.85 94.433,34.216 91.8,37.85 C89.1,41.483 86.717,43.3 84.65,43.3 C84.21,43.269 83.802,43.21 83.425,43.125 L74.1,51.9 C72.6,52.733 71.583,52.583 71.05,51.45 C70.517,50.85 70.567,50.1 71.2,49.2 L71.25,49.15 C71.383,48.95 71.567,48.733 71.8,48.5 L80.475,40.275 C80.376,39.872 80.318,39.431 80.3,38.95 C80.3,37.817 80.75,36.867 81.65,36.1 C85.45,32.7 87.35,28.784 87.35,24.35 C87.35,19.95 85.683,16.25 82.35,13.25 C79.017,10.25 74.467,8.716 68.7,8.65 C61.5,8.65 55.583,10.817 50.95,15.15 C46.317,19.483 44,24.683 44,30.75 C44,35.65 45.883,40.066 49.65,44 C53.383,47.9 59.15,50.966 66.95,53.2 C77.883,56.367 86.233,61.7 92,69.2 C97.133,75.833 100,83.283 100.6,91.55 C101.199,91.365 101.791,91.132 102.375,90.85 Z M71.95,49.05 C71.95,49.35 72.117,49.5 72.45,49.5 C72.483,49.5 75.117,47.066 80.35,42.2 C80.35,41.533 78.95,42.45 76.15,44.95 C73.35,47.483 71.95,48.85 71.95,49.05 Z M74.15,50.8 C74.15,50.533 74.017,50.4 73.75,50.4 C73.45,50.4 73.183,50.55 72.95,50.85 C72.416,50.817 72.033,50.884 71.8,51.05 C71.7,51.117 71.65,51.183 71.65,51.25 C71.65,51.45 71.783,51.6 72.05,51.7 L72.95,51.7 C73.75,51.4 74.15,51.1 74.15,50.8 Z M80.35,45.35 C80.35,44.583 79.9,44.583 79,45.35 C78.567,45.75 78.017,46.317 77.35,47.05 C77.117,47.217 76.633,47.667 75.9,48.4 C75.133,49.2 74.75,49.683 74.75,49.85 L74.8,50.2 C75,50.267 75.133,50.3 75.2,50.3 C75.233,50.3 76.1,49.5 77.8,47.9 C79.5,46.3 80.35,45.45 80.35,45.35 Z M124.2,78.3 L115.8,85.7 C116.3,85.967 116.667,86.349 116.9,86.849 L125.2,79.45 C125.266,79.116 125.217,78.849 125.05,78.649 C124.883,78.517 124.6,78.399 124.2,78.3 Z M123.75,78.05 L123.55,77.85 L116.15,83.85 L116.6,84.4 L123.75,78.05 Z M91.85,99.899 C89.65,99.333 87.617,98.649 85.75,97.849 C81.55,96.149 76.333,93.183 70.1,88.95 L59.85,82 C55.517,79.233 51.567,77.166 48,75.8 C44.4,74.467 40.867,73.8 37.4,73.8 L35.9,73.8 C27.067,74.267 20.2,77.583 15.3,83.75 C10.734,89.45 8.45,96.184 8.45,103.95 C8.45,112.683 11.95,119.516 18.95,124.45 C25.916,129.416 35.467,131.899 47.6,131.899 C57.133,131.899 65.166,130.2 71.7,126.799 C78.2,123.399 83.25,118.899 86.85,113.299 C89.55,109.033 91.217,104.566 91.85,99.899 Z"></path>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
BIN
docs/assets/images/tie.webp
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 55 KiB |
@@ -5,7 +5,7 @@
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="undraw-content-team" transform="translate(-3.000000, 0.000000)">
|
||||
<rect id="Rectangle" fill-opacity="0.25" fill="#FFFFFF" x="180" y="16" width="579" height="343" rx="20"></rect>
|
||||
<rect id="Rectangle" fill-opacity="0.25" fill="#fff" x="180" y="16" width="579" height="343" rx="20"></rect>
|
||||
<path d="M840.86295,552.21468 L98.22937,552.21468 C84.4769827,552.21468 73.32847,541.066167 73.32847,527.31378 L73.32847,527.31378 C342.533003,496.02706 606.678133,496.02706 865.76386,527.31378 L865.76386,527.31378 C865.763854,541.066169 854.615339,552.21468 840.86295,552.21468 Z" id="Path" fill="#CCCCCC" fill-rule="nonzero"></path>
|
||||
<path d="M865.76386,528.77851 L73.32847,527.31375 L165.16896,372.78153 L165.60837,372.04915 L165.60837,31.47769 C165.607672,23.1290737 168.923838,15.1221947 174.827202,9.21883153 C180.730565,3.31546831 188.737444,-0.00069762467 197.08606,2.84217094e-14 L737.61198,2.84217094e-14 C745.960596,-0.00069762467 753.967475,3.31546831 759.870838,9.21883153 C765.774202,15.1221947 769.090368,23.1290737 769.08967,31.47769 L769.08967,374.39269 L865.76386,528.77851 Z M196.36834,21.97141 C190.70822,21.9777587 186.121369,26.5646095 186.11502,32.22473 L186.11502,342.75394 C186.121622,348.413956 190.708324,353.000658 196.36834,353.00726 L742.72398,353.00726 C748.383893,353.000411 752.970451,348.413853 752.9773,342.75394 L752.9773,32.22473 C752.970704,26.5647122 748.383998,21.9780061 742.72398,21.97141 L196.36834,21.97141 Z" id="Combined-Shape" fill="#E6E6E6" fill-rule="nonzero"></path>
|
||||
<path d="M199.95903,394.02055 C198.24391,394.023463 196.686317,395.021305 195.9667,396.57816 L167.66779,458.0981 C167.041726,459.458563 167.151668,461.044211 167.959498,462.305253 C168.767328,463.566295 170.161797,464.32907 171.6594,464.3291 L766.77054,464.3291 C768.293506,464.329083 769.707849,463.540407 770.508355,462.244793 C771.308862,460.949179 771.381351,459.331427 770.69993,457.96941 L739.93993,396.44947 C739.199697,394.957483 737.676056,394.015676 736.01054,394.0206 L199.95903,394.02055 Z" id="Path" fill="#CCCCCC" fill-rule="nonzero"></path>
|
||||
@@ -22,7 +22,7 @@
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(480.586874, 208.953401) rotate(-40.261060) translate(-480.586874, -208.953401) " cx="480.586874" cy="208.953401" rx="10.63605" ry="3.98853"></ellipse>
|
||||
<circle id="Oval" fill="#FFFFFF" fill-rule="nonzero" cx="457.85318" cy="143.08115" r="14.35864"></circle>
|
||||
<circle id="Oval" fill="#3F3D56" fill-rule="nonzero" cx="451.95181" cy="137.93436" r="4.78622"></circle>
|
||||
<path d="M493.93625,107.65269 C494.56802,92.0991 481.16312,78.92509 463.99545,78.22776 C446.82778,77.53043 432.39853,89.57376 431.76672,105.12736 C431.13491,120.68096 443.06863,124.21482 460.23627,124.91221 C477.40391,125.6096 493.30447,123.20627 493.93625,107.65269 Z" id="Path" fill="#009DFF" fill-rule="nonzero"></path>
|
||||
<path d="M493.93625,107.65269 C494.56802,92.0991 481.16312,78.92509 463.99545,78.22776 C446.82778,77.53043 432.39853,89.57376 431.76672,105.12736 C431.13491,120.68096 443.06863,124.21482 460.23627,124.91221 C477.40391,125.6096 493.30447,123.20627 493.93625,107.65269 Z" id="Path" fill="#0ea5e9" fill-rule="nonzero"></path>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(422.001785, 145.703659) rotate(-77.089900) translate(-422.001785, -145.703659) " cx="422.001785" cy="145.703659" rx="6.59448" ry="21.00616"></ellipse>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(504.470422, 159.418119) rotate(-77.089900) translate(-504.470422, -159.418119) " cx="504.470422" cy="159.418119" rx="6.59448" ry="21.00616"></ellipse>
|
||||
<path d="M472.3331,169.91416 C472.9488,173.280144 471.720947,176.718794 469.112518,178.933525 C466.504089,181.148255 462.911834,181.802199 459.690258,180.648779 C456.468682,179.495358 454.107795,176.710012 453.4978,173.34299 L453.49445,173.3245 C452.5527,168.12235 456.57483,166.2815 461.77701,165.33976 C466.97919,164.39802 471.39139,164.71201 472.3331,169.91416 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
@@ -32,7 +32,7 @@
|
||||
<rect id="Rectangle" fill="#2F2E41" fill-rule="nonzero" x="278.92063" y="359.95537" width="13.08374" height="23.44171"></rect>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" cx="263.65629" cy="383.66967" rx="10.90314" ry="4.08868"></ellipse>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" cx="289.82377" cy="383.12453" rx="10.90314" ry="4.08868"></ellipse>
|
||||
<path d="M230.60203,286.10434 C227.12455,270.53055 238.2407,254.79388 255.43064,250.9555 C272.62058,247.11712 289.37486,256.63058 292.85233,272.20438 C296.3298,287.77818 284.93742,293.52203 267.74748,297.36038 C250.55754,301.19873 234.07951,301.67812 230.60203,286.10434 Z" id="Path" fill="#009DFF" fill-rule="nonzero"></path>
|
||||
<path d="M230.60203,286.10434 C227.12455,270.53055 238.2407,254.79388 255.43064,250.9555 C272.62058,247.11712 289.37486,256.63058 292.85233,272.20438 C296.3298,287.77818 284.93742,293.52203 267.74748,297.36038 C250.55754,301.19873 234.07951,301.67812 230.60203,286.10434 Z" id="Path" fill="#0ea5e9" fill-rule="nonzero"></path>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(223.870603, 306.172293) rotate(-64.625740) translate(-223.870603, -306.172293) " cx="223.870603" cy="306.172293" rx="6.76007" ry="21.53368"></ellipse>
|
||||
<circle id="Oval" fill="#2F2E41" fill-rule="nonzero" cx="85.9008" cy="369.76318" r="43.06733"></circle>
|
||||
<rect id="Rectangle" fill="#2F2E41" fill-rule="nonzero" x="66.27519" y="403.56287" width="13.08374" height="23.44171"></rect>
|
||||
@@ -41,7 +41,7 @@
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" cx="103.34581" cy="426.732" rx="10.90314" ry="4.08868"></ellipse>
|
||||
<circle id="Oval" fill="#FFFFFF" fill-rule="nonzero" cx="86.99113" cy="358.86008" r="14.71922"></circle>
|
||||
<circle id="Oval" fill="#3F3D56" fill-rule="nonzero" cx="86.99113" cy="358.86008" r="4.90642"></circle>
|
||||
<path d="M44.12401,329.71183 C40.64653,314.13804 51.76268,298.4014 68.95262,294.56302 C86.14256,290.72464 102.89683,300.23813 106.37431,315.81192 C109.85179,331.38571 98.45939,337.12961 81.26945,340.96792 C64.07951,344.80623 47.60154,345.28568 44.12401,329.71183 Z" id="Path" fill="#E6E6E6" fill-rule="nonzero"></path>
|
||||
<path d="M44.12401,329.71183 C40.64653,314.13804 51.76268,298.4014 68.95262,294.56302 C86.14256,290.72464 102.89683,300.23813 106.37431,315.81192 C109.85179,331.38571 98.45939,337.12961 81.26945,340.96792 C64.07951,344.80623 47.60154,345.28568 44.12401,329.71183 Z" id="Path" fill="#12a5e9" fill-rule="nonzero"></path>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(110.988725, 213.490755) rotate(-69.082170) translate(-110.988725, -213.490755) " cx="110.988725" cy="213.490755" rx="21.53369" ry="6.76007"></ellipse>
|
||||
<circle id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(71.181568, 246.012788) rotate(-80.782520) translate(-71.181568, -246.012788) " cx="71.1815681" cy="246.012788" r="43.06735"></circle>
|
||||
<rect id="Rectangle" fill="#2F2E41" fill-rule="nonzero" x="51.55595" y="279.81244" width="13.08374" height="23.44171"></rect>
|
||||
@@ -50,10 +50,10 @@
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" cx="88.62657" cy="302.9816" rx="10.90314" ry="4.08868"></ellipse>
|
||||
<circle id="Oval" fill="#FFFFFF" fill-rule="nonzero" cx="72.27189" cy="235.10965" r="14.71922"></circle>
|
||||
<circle id="Oval" fill="#3F3D56" fill-rule="nonzero" cx="72.27189" cy="235.10965" r="4.90642"></circle>
|
||||
<path d="M29.40483,205.96134 C25.92735,190.38755 37.0435,174.65088 54.23344,170.8125 C71.42338,166.97412 88.17766,176.48758 91.65513,192.06138 C95.1326,207.63518 83.74022,213.37903 66.55028,217.21738 C49.36034,221.05573 32.88231,221.53519 29.40483,205.96134 Z" id="Path" fill="#009DFF" fill-rule="nonzero"></path>
|
||||
<path d="M29.40483,205.96134 C25.92735,190.38755 37.0435,174.65088 54.23344,170.8125 C71.42338,166.97412 88.17766,176.48758 91.65513,192.06138 C95.1326,207.63518 83.74022,213.37903 66.55028,217.21738 C49.36034,221.05573 32.88231,221.53519 29.40483,205.96134 Z" id="Path" fill="#0ea5e9" fill-rule="nonzero"></path>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(22.673401, 226.029366) rotate(-64.625740) translate(-22.673401, -226.029366) " cx="22.6734006" cy="226.029366" rx="6.76007" ry="21.53368"></ellipse>
|
||||
<path d="M50.02702,261.54972 C50.02702,265.76487 60.88029,274.08829 72.92357,274.08829 C84.96685,274.08829 96.25871,262.22129 96.25871,258.0062 C96.25871,253.79111 84.96678,258.82395 72.92357,258.82395 C60.88036,258.82395 50.02702,257.33457 50.02702,261.54972 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M113.52376,81.56869 C111.867655,81.5704977 110.525568,82.9125851 110.52376,84.56869 L110.52376,208.56869 C110.525568,210.224795 111.867655,211.566882 113.52376,211.56869 L400.52376,211.56869 C402.179865,211.566882 403.521952,210.224795 403.52376,208.56869 L403.52376,84.56869 C403.521952,82.9125851 402.179865,81.5704977 400.52376,81.56869 L113.52376,81.56869 Z" id="Path" fill="#009DFF" fill-rule="nonzero"></path>
|
||||
<path d="M113.52376,81.56869 C111.867655,81.5704977 110.525568,82.9125851 110.52376,84.56869 L110.52376,208.56869 C110.525568,210.224795 111.867655,211.566882 113.52376,211.56869 L400.52376,211.56869 C402.179865,211.566882 403.521952,210.224795 403.52376,208.56869 L403.52376,84.56869 C403.521952,82.9125851 402.179865,81.5704977 400.52376,81.56869 L113.52376,81.56869 Z" id="Path" fill="#fbc024" fill-rule="nonzero"></path>
|
||||
<circle id="Oval" fill="#FFFFFF" fill-rule="nonzero" cx="191.01816" cy="146.56869" r="29.1211"></circle>
|
||||
<path d="M256.7436,142.69417 C254.884983,142.724723 253.39428,144.240132 253.39428,146.099 C253.39428,147.957868 254.884983,149.473277 256.7436,149.50383 L348.68926,149.50383 C349.906316,149.524778 351.042001,148.894505 351.668119,147.850647 C352.294237,146.806789 352.31556,145.508108 351.72405,144.444258 C351.132539,143.380407 350.018157,142.713189 348.80107,142.69417 C348.763797,142.693537 348.726527,142.693537 348.68926,142.69417 L256.7436,142.69417 Z" id="b71acdfd-6a55-428e-917a-53f192cb0203" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M256.7436,122.96697 C254.884983,122.997523 253.39428,124.512932 253.39428,126.3718 C253.39428,128.230668 254.884983,129.746077 256.7436,129.77663 L302.65917,129.77663 C303.876249,129.797613 305.011971,129.167347 305.638111,128.123473 C306.26425,127.0796 306.285572,125.78089 305.694037,124.717025 C305.102503,123.65316 303.988082,122.985951 302.77097,122.96697 C302.733703,122.966337 302.696437,122.966337 302.65917,122.96697 L256.7436,122.96697 Z" id="ad4fbcfa-41b0-45f9-a593-23b6dc3fe165" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
@@ -67,14 +67,14 @@
|
||||
<circle id="Oval" fill="#3F3D56" fill-rule="nonzero" cx="725.31949" cy="403.22896" r="4.90642"></circle>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(771.918005, 384.148727) rotate(-53.549900) translate(-771.918005, -384.148727) " cx="771.918005" cy="384.148727" rx="21.53368" ry="6.76007"></ellipse>
|
||||
<path d="M705.39698,436.33866 C705.39698,432.86466 714.34198,426.00466 724.26778,426.00466 C734.19358,426.00466 743.50006,435.78516 743.50006,439.25914 C743.50006,442.73312 734.19351,438.58514 724.26778,438.58514 C714.34205,438.58514 705.39698,439.81268 705.39698,436.33866 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero" transform="translate(724.448520, 433.325266) rotate(-180.000000) translate(-724.448520, -433.325266) "></path>
|
||||
<path d="M847.1767,378.54172 L611.43117,345.86064 C607.604361,345.32541 604.932725,341.793834 605.45868,337.96574 L631.96057,146.79396 C632.495641,142.967058 636.027329,140.295337 639.85547,140.82147 L875.60098,173.50256 C879.427885,174.037626 882.099609,177.569318 881.57347,181.39746 L855.0716,372.56924 C854.536375,376.396051 851.004794,379.067687 847.1767,378.54172 L847.1767,378.54172 Z" id="Path" fill="#009DFF" fill-rule="nonzero"></path>
|
||||
<path d="M847.1767,378.54172 L611.43117,345.86064 C607.604361,345.32541 604.932725,341.793834 605.45868,337.96574 L631.96057,146.79396 C632.495641,142.967058 636.027329,140.295337 639.85547,140.82147 L875.60098,173.50256 C879.427885,174.037626 882.099609,177.569318 881.57347,181.39746 L855.0716,372.56924 C854.536375,376.396051 851.004794,379.067687 847.1767,378.54172 L847.1767,378.54172 Z" id="Path" fill="#9358ff" fill-rule="nonzero"></path>
|
||||
<path d="M762.72231,318.87957 L642.36784,302.19498 C642.216871,302.176045 642.067969,302.14324 641.92302,302.09698 L712.51355,211.39072 C713.394132,210.238632 714.82651,209.649483 716.262854,209.8486 C717.699198,210.047717 718.917295,211.004295 719.45127,212.35248 L748.48059,283.8148 L749.87186,287.23459 L762.72231,318.87957 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<polygon id="Path" fill="#000000" fill-rule="nonzero" opacity="0.2" points="762.722 318.879 721.63 313.183 745.864 286.679 747.609 284.77 748.481 283.815 749.872 287.235"></polygon>
|
||||
<path d="M829.73481,328.16942 L725.63807,313.73863 L749.87186,287.23463 L751.61612,285.32515 L783.19533,250.78503 C784.29885,249.735613 785.796059,249.204111 787.314261,249.322828 C788.832463,249.441546 790.228856,250.199316 791.15584,251.40751 C791.271244,251.575507 791.375823,251.750689 791.46894,251.93199 L829.73481,328.16942 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<circle id="Oval" fill="#FFFFFF" fill-rule="nonzero" cx="764.18602" cy="224.18353" r="18"></circle>
|
||||
<rect id="Rectangle" fill="#3F3D56" fill-rule="nonzero" transform="translate(653.262165, 167.923576) rotate(7.892770) translate(-653.262165, -167.923576) " x="642.262129" y="156.923541" width="22.0000711" height="22.0000711"></rect>
|
||||
<path d="M768.18655,374.08068 C771.66403,358.50689 760.54788,342.77022 743.35794,338.93184 C726.168,335.09346 709.41373,344.60692 705.93625,360.18071 C702.45877,375.7545 713.85117,381.49837 731.04111,385.33671 C748.23105,389.17505 764.70908,389.6545 768.18655,374.08068 Z" id="Path" fill="#F2F2F2" fill-rule="nonzero"></path>
|
||||
<rect id="Rectangle" fill="#FFFFFF" fill-rule="nonzero" transform="translate(653.262165, 167.923576) rotate(7.892770) translate(-653.262165, -167.923576) " x="642.262129" y="156.923541" width="22.0000711" height="22.0000711"></rect>
|
||||
<path d="M768.18655,374.08068 C771.66403,358.50689 760.54788,342.77022 743.35794,338.93184 C726.168,335.09346 709.41373,344.60692 705.93625,360.18071 C702.45877,375.7545 713.85117,381.49837 731.04111,385.33671 C748.23105,389.17505 764.70908,389.6545 768.18655,374.08068 Z" id="Path" fill="#12a5e9" fill-rule="nonzero"></path>
|
||||
<ellipse id="Oval" fill="#2F2E41" fill-rule="nonzero" transform="translate(735.010556, 473.249892) rotate(-4.181640) translate(-735.010556, -473.249892) " cx="735.010556" cy="473.249892" rx="10.90314" ry="4.08868"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
1
docs/assets/images/undraw-not-found.svg
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
32
docs/assets/images/undraw-taken.svg
Normal file
@@ -0,0 +1,32 @@
|
||||
<svg width="673" height="739" viewBox="0 0 673 739" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill-rule="nonzero" fill="none">
|
||||
<path d="M467 149.805c-46.62-7.44-99.71-11.41-155-11.41-50.6 0-99.35 3.32-142.98 9.58.01-.67.02-1.34.05-2.01C171.475 65.082 237.996.903 318.914 1.398c80.917.494 146.649 65.48 148.066 146.387.01.68.02 1.35.02 2.02Z" fill="#0BA5E9"/>
|
||||
<path d="M337.55 1.342a149.047 149.047 0 0 0-168.93 143.229c-.031.67-.04 1.34-.05 2.01 12.961-1.86 26.384-3.454 40.164-4.784 3.478-71.745 57.64-130.8 128.816-140.455Z" opacity=".1" fill="#FFF"/>
|
||||
<path d="M532.18 161.625a600.121 600.121 0 0 0-65.2-13.84 943.364 943.364 0 0 0-108.74-10.45 1133.608 1133.608 0 0 0-83.01-.34 973.29 973.29 0 0 0-106.16 8.97 624.292 624.292 0 0 0-77.25 15.66C32.61 177.995 0 199.935 0 223.395s32.61 45.4 91.82 61.77c41.64 11.52 92.98 19.37 148.92 22.97 23.09 1.5 46.96 2.26 71.26 2.26 24.38 0 48.33-.77 71.49-2.27 50.91-3.29 98.01-10.1 137.43-20 .21-.06.41-.11.62-.16 2.66-.66 5.28-1.35 7.87-2.04.93-.26 1.85-.51 2.77-.76a.978.978 0 0 1 .16-.05c.88-.24 1.75-.49 2.62-.73 1.74-.5 3.46-.99 5.15-1.5.08-.02.15-.04.22-.06 1.47-.44 2.91-.88 4.34-1.32 1.17-.37 2.33-.73 3.48-1.1.84-.27 1.67-.54 2.49-.81.6-.2 1.19-.39 1.77-.59.79-.26 1.58-.53 2.36-.8.33-.11.66-.22.98-.34.75-.25 1.48-.51 2.21-.77.79-.28 1.58-.57 2.36-.85.65-.23 1.3-.47 1.94-.71.54-.21 1.07-.41 1.61-.61 1.47-.55 2.91-1.12 4.33-1.68.71-.29 1.42-.57 2.12-.86.69-.28 1.39-.57 2.07-.86 1.12-.47 2.22-.94 3.3-1.41.52-.24 1.05-.47 1.56-.69.39-.18.77-.35 1.16-.53.28-.12.56-.25.83-.38 1.01-.46 2.01-.93 2.99-1.4 3.76-1.8 7.27-3.64 10.53-5.52 20.45-11.71 31.24-24.7 31.24-38.2 0-23.46-32.61-45.4-91.82-61.77Zm-.54 121.62c-41.69 11.53-93.17 19.38-149.26 22.95-22.81 1.45-46.39 2.2-70.38 2.2-23.91 0-47.41-.74-70.15-2.19-56.18-3.56-107.74-11.41-149.49-22.96C34.09 267.125 2 245.875 2 223.395c0-1.986.252-3.965.74-5.89 5.1-20.28 36.47-39.26 89.62-53.96a623.806 623.806 0 0 1 76.66-15.57 976.027 976.027 0 0 1 106.8-9c11.92-.39 23.98-.583 36.18-.58 15.41 0 30.65.31 45.63.91a941.367 941.367 0 0 1 109.37 10.5 598.858 598.858 0 0 1 64.64 13.74c53.14 14.7 84.5 33.67 89.61 53.94.496 1.93.75 3.916.75 5.91 0 22.48-32.09 43.73-90.36 59.85Z" fill="#3F3D56"/>
|
||||
<path d="M623.43 224.305c0 13.36-11.01 26-30.67 37.29-3.27 1.88-6.79 3.72-10.53 5.52-.98.47-1.98.94-2.99 1.4-.27.13-.55.26-.83.38-.39.18-.77.35-1.16.53-.51.22-1.04.45-1.56.69-1.08.47-2.18.94-3.3 1.41-.68.29-1.38.58-2.07.86-.7.29-1.41.57-2.12.86-1.42.56-2.86 1.13-4.33 1.68-.54.2-1.07.4-1.61.61-.64.24-1.29.48-1.94.71-.78.28-1.57.57-2.36.85-.73.26-1.46.52-2.21.77-.32.12-.65.23-.98.34-.78.27-1.57.54-2.36.8-.58.2-1.17.39-1.77.59-.82.27-1.65.54-2.49.81-1.15.37-2.31.73-3.48 1.1-1.43.44-2.87.88-4.34 1.32-.07.02-.14.04-.22.06-1.69.51-3.41 1-5.15 1.5-.87.24-1.74.49-2.62.73a.978.978 0 0 0-.16.05c-.92.25-1.84.5-2.77.76-2.58.68-5.21 1.37-7.87 2.04-.21.05-.41.1-.62.16-38.35 9.58-85.4 16.56-137.47 19.93-22.81 1.47-46.59 2.25-71.02 2.25-24.65 0-48.63-.79-71.62-2.29-137.24-8.95-239.38-43.03-239.38-83.71.01-2.475.388-4.936 1.12-7.3.06.17.12.33.19.5 14.27 37.48 115.54 67.77 246.94 75.16 20.13 1.14 40.98 1.73 62.32 1.73 21.43 0 42.36-.6 62.57-1.74 131.29-7.42 232.46-37.72 246.68-75.17.24-.6.45-1.2.63-1.8a25.304 25.304 0 0 1 1.55 8.62ZM91.67 213.54c-16.643 0-34.331-3.58-34.331-10.216 0-6.636 17.688-10.217 34.33-10.217 16.643 0 34.331 3.58 34.331 10.217 0 6.636-17.688 10.217-34.33 10.217Zm0-18.433c-19.054 0-32.331 4.33-32.331 8.217 0 3.886 13.277 8.217 32.33 8.217 19.053 0 32.331-4.33 32.331-8.217 0-3.886-13.278-8.217-32.33-8.217Z" fill="#3F3D56"/>
|
||||
<path d="M162.67 260.54c-16.643 0-34.331-3.58-34.331-10.216 0-6.636 17.688-10.217 34.33-10.217 16.643 0 34.331 3.58 34.331 10.217 0 6.636-17.688 10.217-34.33 10.217Zm0-18.433c-19.054 0-32.331 4.33-32.331 8.217 0 3.886 13.277 8.217 32.33 8.217 19.053 0 32.331-4.33 32.331-8.217 0-3.886-13.278-8.217-32.33-8.217ZM531.67 213.54c-16.643 0-34.331-3.58-34.331-10.216 0-6.636 17.688-10.217 34.33-10.217 16.643 0 34.331 3.58 34.331 10.217 0 6.636-17.688 10.217-34.33 10.217Zm0-18.433c-19.054 0-32.331 4.33-32.331 8.217 0 3.886 13.277 8.217 32.33 8.217 19.053 0 32.331-4.33 32.331-8.217 0-3.886-13.278-8.217-32.33-8.217ZM460.67 260.54c-16.643 0-34.331-3.58-34.331-10.216 0-6.636 17.688-10.217 34.33-10.217 16.643 0 34.331 3.58 34.331 10.217 0 6.636-17.688 10.217-34.33 10.217Zm0-18.433c-19.054 0-32.331 4.33-32.331 8.217 0 3.886 13.277 8.217 32.33 8.217 19.053 0 32.331-4.33 32.331-8.217 0-3.886-13.278-8.217-32.33-8.217ZM311.67 282.54c-16.643 0-34.331-3.58-34.331-10.216 0-6.636 17.688-10.217 34.33-10.217 16.643 0 34.331 3.58 34.331 10.217 0 6.636-17.688 10.217-34.33 10.217Zm0-18.433c-19.054 0-32.331 4.33-32.331 8.217 0 3.886 13.277 8.217 32.33 8.217 19.053 0 32.331-4.33 32.331-8.217 0-3.886-13.278-8.217-32.33-8.217Z" fill="#3F3D56"/>
|
||||
<circle fill="#2F2E41" cx="336.978" cy="450.705" r="42.012"/>
|
||||
<path fill="#2F2E41" d="m300.555 488.547 20.447-10.24 5.715 11.413-20.447 10.24z"/>
|
||||
<ellipse fill="#2F2E41" transform="rotate(-56.601 300.086 492.946)" cx="300.086" cy="492.946" rx="3.989" ry="10.636"/>
|
||||
<path fill="#2F2E41" d="m347.239 489.72 5.715-11.412 20.447 10.24-5.715 11.412z"/>
|
||||
<ellipse fill="#2F2E41" transform="rotate(-33.399 373.87 492.946)" cx="373.87" cy="492.946" rx="10.636" ry="3.989"/>
|
||||
<circle fill="#FFF" cx="334.037" cy="440.429" r="14.359"/>
|
||||
<ellipse fill="#3F3D56" transform="rotate(-45 334.135 434.282)" cx="334.135" cy="434.282" rx="4.766" ry="4.8"/>
|
||||
<path d="M370.12 405c.632-15.553-12.773-28.727-29.941-29.425-17.168-.697-31.597 11.346-32.229 26.9-.632 15.553 11.302 19.087 28.47 19.785 17.167.697 33.068-1.706 33.7-17.26Z" fill="#0BA5E9"/>
|
||||
<ellipse fill="#2F2E41" transform="rotate(-40.645 380.654 456.766)" cx="380.654" cy="456.766" rx="6.594" ry="21.006"/>
|
||||
<ellipse fill="#2F2E41" transform="rotate(-49.355 293.42 456.766)" cx="293.419" cy="456.766" rx="21.006" ry="6.594"/>
|
||||
<path d="M348.517 467.262a9.572 9.572 0 1 1-18.836 3.428l-.003-.018c-.942-5.202 3.08-7.043 8.282-7.985 5.203-.942 9.615-.628 10.557 4.575Z" fill="#FFF"/>
|
||||
<path d="M266 495.395a2 2 0 0 1-2-2v-118a2 2 0 0 1 4 0v118a2 2 0 0 1-2 2ZM236 601.395a2 2 0 0 1-2-2v-86a2 2 0 0 1 4 0v86a2 2 0 0 1-2 2ZM313 530.395a2 2 0 0 1-2-2v-118a2 2 0 0 1 4 0v118a2 2 0 0 1-2 2ZM284 615.395a2 2 0 0 1-2-2v-48a2 2 0 0 1 4 0v48a2 2 0 0 1-2 2ZM325 369.395a2 2 0 0 1-2-2v-48a2 2 0 0 1 4 0v48a2 2 0 0 1-2 2ZM225 390.395a2 2 0 0 1-2-2v-48a2 2 0 0 1 4 0v48a2 2 0 0 1-2 2ZM399 395.395a2 2 0 0 1-2-2v-48a2 2 0 0 1 4 0v48a2 2 0 0 1-2 2ZM395 545.395a2 2 0 0 1-2-2v-58a2 2 0 0 1 4 0v58a2 2 0 0 1-2 2ZM355 596.395a2 2 0 0 1-2-2v-86a2 2 0 0 1 4 0v86a2 2 0 0 1-2 2ZM363 449.395a2 2 0 0 1-2-2v-118a2 2 0 0 1 4 0v118a2 2 0 0 1-2 2Z" fill="#CCC"/>
|
||||
<ellipse fill="#2F2E41" transform="rotate(-39.938 594.37 683.981)" cx="594.369" cy="683.981" rx="6.76" ry="21.534"/>
|
||||
<circle fill="#2F2E41" transform="rotate(-71.565 548.562 676.503)" cx="548.562" cy="676.503" r="43.067"/>
|
||||
<path fill="#2F2E41" d="M553.707 710.303h13.084v23.442h-13.084zM527.54 710.303h13.084v23.442H527.54z"/>
|
||||
<ellipse fill="#2F2E41" cx="555.888" cy="734.017" rx="10.903" ry="4.089"/>
|
||||
<ellipse fill="#2F2E41" cx="529.72" cy="733.472" rx="10.903" ry="4.089"/>
|
||||
<path d="M535.04 622.366c3.845-15.487 20.82-24.6 37.914-20.356 17.094 4.245 27.834 20.24 23.989 35.727-3.846 15.487-16.604 15.537-33.698 11.293-17.094-4.245-32.051-11.177-28.206-26.664Z" fill="#0BA5E9"/>
|
||||
<ellipse fill="#2F2E41" transform="rotate(-64.626 500.054 656.52)" cx="500.054" cy="656.52" rx="6.76" ry="21.534"/>
|
||||
<circle fill="#FFF" cx="542.124" cy="667.416" r="14.359"/>
|
||||
<circle fill="#3F3D56" cx="536.222" cy="662.269" r="4.786"/>
|
||||
<circle fill="#FFF" cx="542" cy="697.395" r="6"/>
|
||||
<path d="M671.531 738.395h-236a1 1 0 1 1 0-2h236a1 1 0 0 1 0 2Z" fill="#3F3D56"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
BIN
docs/assets/images/walk.gif
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@@ -1,167 +0,0 @@
|
||||
.code-block {
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
background: var(--sl-color-gray-50);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.code-block__preview {
|
||||
position: relative;
|
||||
border: solid 1px var(--sl-color-gray-200);
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
background-color: white;
|
||||
min-width: 20rem;
|
||||
max-width: 100%;
|
||||
padding: 1.5rem 3.25rem 1.5rem 1.5rem;
|
||||
}
|
||||
|
||||
/* Block the preview while dragging to prevent iframes from intercepting drag events */
|
||||
.code-block__preview--dragging:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.code-block__resizer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 1.75rem;
|
||||
font-size: 20px;
|
||||
color: var(--sl-color-gray-500);
|
||||
background-color: white;
|
||||
border-left: solid 1px var(--sl-color-gray-200);
|
||||
border-top-right-radius: 3px;
|
||||
cursor: ew-resize;
|
||||
transition: 250ms background-color;
|
||||
}
|
||||
|
||||
.code-block__resizer:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 1px var(--sl-color-primary-400), 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary);
|
||||
background-color: var(--sl-color-primary-50);
|
||||
color: var(--sl-color-primary-500);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.code-block__preview {
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.code-block__resizer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.code-block__source {
|
||||
border: solid 1px var(--sl-color-gray-200);
|
||||
border-bottom: none;
|
||||
border-radius: 0 !important;
|
||||
margin: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.code-block__source .docsify-copy-code-button {
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.code-block--expanded .code-block__source {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.code-block__toggle {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
border: solid 1px var(--sl-color-gray-200);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
background: var(--sl-color-white);
|
||||
font: inherit;
|
||||
font-size: 0.875rem;
|
||||
color: var(--sl-color-gray-600);
|
||||
cursor: pointer;
|
||||
transition: 250ms background-color;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.code-block__toggle:hover,
|
||||
.code-block__toggle:active {
|
||||
border-color: var(--sl-color-primary-400);
|
||||
background-color: var(--sl-color-primary-50);
|
||||
color: var(--sl-color-primary-500);
|
||||
}
|
||||
|
||||
.code-block__toggle:focus {
|
||||
outline: none;
|
||||
border-color: var(--sl-color-primary-400);
|
||||
background-color: var(--sl-color-primary-50);
|
||||
color: var(--sl-color-primary-500);
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary);
|
||||
}
|
||||
|
||||
.code-block__toggle svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-left: 0.25rem;
|
||||
transition: 250ms transform;
|
||||
}
|
||||
|
||||
.code-block--expanded .code-block__toggle svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Dark theme */
|
||||
.sl-theme-dark .code-block {
|
||||
background-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .code-block__preview {
|
||||
background-color: var(--sl-color-gray-900);
|
||||
border-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .code-block__source {
|
||||
border-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .code-block__resizer {
|
||||
border-left-color: var(--sl-color-gray-800);
|
||||
background-color: var(--sl-color-gray-900);
|
||||
color: var(--sl-color-gray-400);
|
||||
}
|
||||
|
||||
.sl-theme-dark .code-block__toggle {
|
||||
background-color: var(--sl-color-gray-900);
|
||||
border-color: var(--sl-color-gray-800);
|
||||
color: var(--sl-color-gray-400);
|
||||
}
|
||||
|
||||
.sl-theme-dark .code-block__toggle:hover,
|
||||
.sl-theme-dark .code-block__toggle:active {
|
||||
background-color: var(--sl-color-gray-900);
|
||||
border-color: var(--sl-color-gray-800);
|
||||
color: var(--sl-color-gray-400);
|
||||
}
|
||||
|
||||
.sl-theme-dark .code-block__toggle:focus {
|
||||
border-color: var(--sl-color-primary-500);
|
||||
background-color: var(--sl-color-primary-900);
|
||||
color: var(--sl-color-primary-500);
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
(() => {
|
||||
let count = 1;
|
||||
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
function runScript(script) {
|
||||
const newScript = document.createElement('script');
|
||||
|
||||
if (script.type === 'module') {
|
||||
newScript.type = 'module';
|
||||
newScript.textContent = script.innerHTML;
|
||||
} else {
|
||||
newScript.appendChild(document.createTextNode(`(() => { ${script.innerHTML} })();`));
|
||||
}
|
||||
|
||||
script.parentNode.replaceChild(newScript, script);
|
||||
}
|
||||
|
||||
function wrap(el, wrapper) {
|
||||
el.parentNode.insertBefore(wrapper, el);
|
||||
wrapper.appendChild(el);
|
||||
}
|
||||
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
// Convert code blocks to previews
|
||||
hook.afterEach(function (html, next) {
|
||||
const domParser = new DOMParser();
|
||||
const doc = domParser.parseFromString(html, 'text/html');
|
||||
|
||||
[...doc.querySelectorAll('code[class^="lang-"]')].map(code => {
|
||||
if (code.classList.contains('preview')) {
|
||||
const pre = code.closest('pre');
|
||||
const preId = `code-block-preview-${count}`;
|
||||
const toggleId = `code-block-toggle-${count}`;
|
||||
|
||||
pre.id = preId;
|
||||
pre.classList.add('code-block__source');
|
||||
pre.setAttribute('data-lang', pre.getAttribute('data-lang').replace(/ preview$/, ''));
|
||||
pre.setAttribute('aria-labelledby', toggleId);
|
||||
|
||||
const codeBlock = `
|
||||
<div class="code-block">
|
||||
<div class="code-block__preview">
|
||||
${code.textContent}
|
||||
<div class="code-block__resizer" role="slider" tabindex="0">
|
||||
<sl-icon name="grip-vertical"></sl-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${pre.outerHTML}
|
||||
|
||||
<div class="code-block__toggle" aria-expanded="false" aria-controls="${preId}">
|
||||
Source
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
pre.replaceWith(domParser.parseFromString(codeBlock, 'text/html').body);
|
||||
|
||||
count++;
|
||||
}
|
||||
});
|
||||
|
||||
next(doc.body.innerHTML);
|
||||
});
|
||||
|
||||
// After the page is done loading, force scripts in previews to execute
|
||||
hook.doneEach(() => {
|
||||
[...document.querySelectorAll('.code-block__preview script')].map(script => runScript(script));
|
||||
});
|
||||
|
||||
// Horizontal resizing
|
||||
hook.doneEach(() => {
|
||||
[...document.querySelectorAll('.code-block__preview')].map(preview => {
|
||||
const resizer = preview.querySelector('.code-block__resizer');
|
||||
let startX;
|
||||
let startWidth;
|
||||
|
||||
const dragStart = event => {
|
||||
startX = event.changedTouches ? event.changedTouches[0].pageX : event.clientX;
|
||||
startWidth = parseInt(document.defaultView.getComputedStyle(preview).width, 10);
|
||||
preview.classList.add('code-block__preview--dragging');
|
||||
event.preventDefault();
|
||||
resizer.focus();
|
||||
document.documentElement.addEventListener('mousemove', dragMove, false);
|
||||
document.documentElement.addEventListener('touchmove', dragMove, false);
|
||||
document.documentElement.addEventListener('mouseup', dragStop, false);
|
||||
document.documentElement.addEventListener('touchend', dragStop, false);
|
||||
};
|
||||
|
||||
const dragMove = event => {
|
||||
setWidth(startWidth + (event.changedTouches ? event.changedTouches[0].pageX : event.pageX) - startX);
|
||||
};
|
||||
|
||||
const dragStop = event => {
|
||||
preview.classList.remove('code-block__preview--dragging');
|
||||
document.documentElement.removeEventListener('mousemove', dragMove, false);
|
||||
document.documentElement.removeEventListener('touchmove', dragMove, false);
|
||||
document.documentElement.removeEventListener('mouseup', dragStop, false);
|
||||
document.documentElement.removeEventListener('touchend', dragStop, false);
|
||||
};
|
||||
|
||||
const handleKeyDown = event => {
|
||||
if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {
|
||||
const currentWidth = preview.clientWidth;
|
||||
const maxWidth = preview.parentElement.clientWidth;
|
||||
const incr = event.shiftKey ? 100 : 10;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if (event.key === 'ArrowLeft') setWidth(currentWidth - incr);
|
||||
if (event.key === 'ArrowRight') setWidth(currentWidth + incr);
|
||||
if (event.key === 'Home') setWidth(0);
|
||||
if (event.key === 'End') setWidth(maxWidth);
|
||||
}
|
||||
};
|
||||
|
||||
const setWidth = width => (preview.style.width = width + 'px');
|
||||
|
||||
resizer.addEventListener('mousedown', dragStart);
|
||||
resizer.addEventListener('touchstart', dragStart);
|
||||
resizer.addEventListener('keydown', handleKeyDown);
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
|
||||
// Expand and collapse code blocks
|
||||
document.addEventListener('click', event => {
|
||||
const toggle = event.target.closest('.code-block__toggle');
|
||||
if (toggle) {
|
||||
const codeBlock = event.target.closest('.code-block');
|
||||
codeBlock.classList.toggle('code-block--expanded');
|
||||
event.target.setAttribute('aria-expanded', codeBlock.classList.contains('code-block--expanded'));
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -1,428 +0,0 @@
|
||||
(() => {
|
||||
let metadataStore;
|
||||
|
||||
function createPropsTable(props) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Description</th>
|
||||
<th>Type</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${props
|
||||
.map(prop => {
|
||||
return `
|
||||
<tr>
|
||||
<td>
|
||||
<code>${escapeHtml(prop.name)}</code>
|
||||
${
|
||||
prop.attribute && prop.name !== prop.attribute
|
||||
? `
|
||||
<br>
|
||||
<small>
|
||||
<sl-tooltip content="This is the corresponding HTML attribute">
|
||||
<code class="attribute-tooltip">${escapeHtml(prop.attribute)}</code>
|
||||
</sl-tooltip>
|
||||
</small>`
|
||||
: ''
|
||||
}
|
||||
</td>
|
||||
<td>${escapeHtml(prop.description)}</td>
|
||||
<td><code style="white-space: normal;">${escapeHtml(prop.type)}</code></td>
|
||||
<td><code style="white-space: normal;">${escapeHtml(prop.defaultValue)}</code></td>
|
||||
</tr>
|
||||
`;
|
||||
})
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createEventsTable(events) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Event</th>
|
||||
<th>Description</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${events
|
||||
.map(
|
||||
event => `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(event.name)}</code></td>
|
||||
<td>${escapeHtml(event.description)}</td>
|
||||
<td><code style="white-space: normal;">${escapeHtml(event.details)}</code></td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createMethodsTable(methods) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
<th>Arguments</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${methods
|
||||
.map(
|
||||
method => `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(method.name)}</code></td>
|
||||
<td>${escapeHtml(method.description)}</td>
|
||||
<td>
|
||||
${
|
||||
method.params.length
|
||||
? `
|
||||
<code style="white-space: normal;">${escapeHtml(
|
||||
method.params.map(param => `${param.name}: ${param.type}`).join(', ')
|
||||
)}</code>
|
||||
`
|
||||
: ''
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createSlotsTable(slots) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Slot</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${slots
|
||||
.map(
|
||||
slot => `
|
||||
<tr>
|
||||
<td><code>${slot.name ? escapeHtml(slot.name) : '(default)'}</code></td>
|
||||
<td>${escapeHtml(slot.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createCustomPropertiesTable(styles) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${styles
|
||||
.map(
|
||||
style => `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(style.name)}</code></td>
|
||||
<td>${escapeHtml(style.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createPartsTable(parts) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${parts
|
||||
.map(
|
||||
part => `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(part.name)}</code></td>
|
||||
<td>${escapeHtml(part.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createAnimationsTable(animations) {
|
||||
const table = document.createElement('table');
|
||||
table.innerHTML = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${animations
|
||||
.map(
|
||||
animation => `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(animation.name)}</code></td>
|
||||
<td>${escapeHtml(animation.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
return table.outerHTML;
|
||||
}
|
||||
|
||||
function createDependenciesList(targetComponent, allComponents) {
|
||||
const ul = document.createElement('ul');
|
||||
const dependencies = [];
|
||||
|
||||
// Recursively fetch subdependencies
|
||||
function getDependencies(tag) {
|
||||
const component = allComponents.find(c => c.tag === tag);
|
||||
if (!component || !Array.isArray(component.dependencies)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
component.dependencies.map(tag => {
|
||||
if (!dependencies.includes(tag)) {
|
||||
dependencies.push(tag);
|
||||
}
|
||||
getDependencies(tag);
|
||||
});
|
||||
}
|
||||
|
||||
getDependencies(targetComponent);
|
||||
dependencies.sort().map(tag => {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = `<code><${tag}></code>`;
|
||||
ul.appendChild(li);
|
||||
});
|
||||
|
||||
return ul.outerHTML;
|
||||
}
|
||||
|
||||
function escapeHtml(html) {
|
||||
return (html + '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/`(.*?)`/g, '<code>$1</code>');
|
||||
}
|
||||
|
||||
function getMetadata() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Simple caching to prevent multiple XHR requests
|
||||
if (metadataStore) {
|
||||
return resolve(metadataStore);
|
||||
}
|
||||
|
||||
fetch('/dist/metadata.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
metadataStore = data;
|
||||
resolve(metadataStore);
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
});
|
||||
}
|
||||
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
hook.mounted(function () {
|
||||
getMetadata().then(metadata => {
|
||||
const target = document.querySelector('.app-name');
|
||||
|
||||
// Add version
|
||||
const version = document.createElement('div');
|
||||
version.classList.add('sidebar-version');
|
||||
version.textContent = metadata.version;
|
||||
target.appendChild(version);
|
||||
|
||||
// Add repo buttons
|
||||
const buttons = document.createElement('div');
|
||||
buttons.classList.add('sidebar-buttons');
|
||||
buttons.innerHTML = `
|
||||
<a class="repo-button repo-button--small repo-button--sponsor" href="https://github.com/sponsors/claviska" rel="noopener" target="_blank">
|
||||
<sl-icon name="heart"></sl-icon> Sponsor
|
||||
</a>
|
||||
<a class="repo-button repo-button--small repo-button--github" href="https://github.com/shoelace-style/shoelace/stargazers" rel="noopener" target="_blank">
|
||||
<sl-icon name="github"></sl-icon> <span class="github-star-count">Star</span>
|
||||
</a>
|
||||
<a class="repo-button repo-button--small repo-button--twitter" href="https://twitter.com/shoelace_style" rel="noopener" target="_blank">
|
||||
<sl-icon name="twitter"></sl-icon> Follow
|
||||
</a>
|
||||
`;
|
||||
target.appendChild(buttons);
|
||||
});
|
||||
});
|
||||
|
||||
hook.beforeEach(async function (content, next) {
|
||||
const metadata = await getMetadata();
|
||||
|
||||
// Replace %VERSION% placeholders
|
||||
content = content.replace(/%VERSION%/g, metadata.version);
|
||||
|
||||
// Handle [component-header] tags
|
||||
content = content.replace(/\[component-header:([a-z-]+)\]/g, (match, tag) => {
|
||||
const component = metadata.components.filter(data => data.tag === tag)[0];
|
||||
let result = '';
|
||||
|
||||
if (!component) {
|
||||
console.error('Component not found in metadata: ' + tag);
|
||||
return next(content);
|
||||
}
|
||||
|
||||
let badgeType = 'info';
|
||||
if (component.status === 'stable') badgeType = 'primary';
|
||||
if (component.status === 'experimental') badgeType = 'warning';
|
||||
if (component.status === 'planned') badgeType = 'info';
|
||||
if (component.status === 'deprecated') badgeType = 'danger';
|
||||
|
||||
result += `
|
||||
<div class="component-header">
|
||||
<div class="component-header__tag">
|
||||
<code>${component.className} | <${component.tag}></code>
|
||||
</div>
|
||||
|
||||
<div class="component-header__info">
|
||||
<sl-badge type="info" pill>
|
||||
Since ${component.since || '?'}
|
||||
</sl-badge>
|
||||
|
||||
<sl-badge type="${badgeType}" pill style="text-transform: capitalize;">
|
||||
${component.status}
|
||||
</sl-badge>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return result.replace(/^ +| +$/gm, '');
|
||||
});
|
||||
|
||||
// Handle [component-metadata] tags
|
||||
content = content.replace(/\[component-metadata:([a-z-]+)\]/g, (match, tag) => {
|
||||
const component = metadata.components.filter(data => data.tag === tag)[0];
|
||||
let result = '';
|
||||
|
||||
if (!component) {
|
||||
console.error('Component not found in metadata: ' + tag);
|
||||
return next(content);
|
||||
}
|
||||
|
||||
if (component.props.length) {
|
||||
result += `
|
||||
## Properties
|
||||
${createPropsTable(component.props)}
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.events.length) {
|
||||
result += `
|
||||
## Events
|
||||
${createEventsTable(component.events)}
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.methods.length) {
|
||||
result += `
|
||||
## Methods
|
||||
${createMethodsTable(component.methods)}
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.slots.length) {
|
||||
result += `
|
||||
## Slots
|
||||
${createSlotsTable(component.slots)}
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.cssCustomProperties.length) {
|
||||
result += `
|
||||
## CSS Custom Properties
|
||||
${createCustomPropertiesTable(component.cssCustomProperties)}
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.parts.length) {
|
||||
result += `
|
||||
## CSS Parts
|
||||
${createPartsTable(component.parts)}
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.animations.length) {
|
||||
result += `
|
||||
## Animations
|
||||
${createAnimationsTable(component.animations)}
|
||||
|
||||
Learn how to [customize animations](/getting-started/customizing#animations).
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.dependencies.length) {
|
||||
result += `
|
||||
## Dependencies
|
||||
|
||||
This component has the following dependencies so, if you're [cherry picking](/getting-started/installation#cherry-picking),
|
||||
be sure to import these components in addition to <code><${tag}></code>.
|
||||
|
||||
${createDependenciesList(component.tag, metadata.components)}
|
||||
`;
|
||||
}
|
||||
|
||||
// Strip whitespace so markdown doesn't process things as code blocks
|
||||
return result.replace(/^ +| +$/gm, '');
|
||||
});
|
||||
|
||||
next(content);
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,24 +0,0 @@
|
||||
(() => {
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
//
|
||||
// Docsify generates pages dynamically and asynchronously, so when a reload happens, the scroll position can't be
|
||||
// be restored immediately. This plugin waits until Docsify loads the page and then restores it.
|
||||
//
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
hook.ready(() => {
|
||||
// Restore
|
||||
const scrollTop = sessionStorage.getItem('bs-scroll');
|
||||
if (scrollTop) {
|
||||
document.documentElement.scrollTop = scrollTop;
|
||||
}
|
||||
|
||||
// Remember
|
||||
document.addEventListener('scroll', event => {
|
||||
sessionStorage.setItem('bs-scroll', document.documentElement.scrollTop);
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,14 +0,0 @@
|
||||
(() => {
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
hook.mounted(function () {
|
||||
// Move search below the app name
|
||||
const appName = document.querySelector('.sidebar .app-name');
|
||||
const search = document.querySelector('.sidebar .search');
|
||||
appName.insertAdjacentElement('afterend', search);
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,13 +0,0 @@
|
||||
.theme-toggle {
|
||||
position: fixed;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.theme-toggle {
|
||||
top: 0.25rem;
|
||||
right: 0.25rem;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
(() => {
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
hook.mounted(function () {
|
||||
let isDark = localStorage.getItem('theme') === 'sl-theme-dark';
|
||||
const sidebarToggle = document.querySelector('.sidebar-toggle');
|
||||
const noTransitions = Object.assign(document.createElement('style'), {
|
||||
textContent: '* { transition: none !important; }'
|
||||
});
|
||||
const toggle = Object.assign(document.createElement('sl-icon-button'), {
|
||||
name: isDark ? 'sun' : 'moon',
|
||||
label: 'Toggle dark mode'
|
||||
});
|
||||
toggle.classList.add('theme-toggle');
|
||||
|
||||
// Set initial theme
|
||||
if (isDark) {
|
||||
document.body.classList.add('sl-theme-dark');
|
||||
}
|
||||
|
||||
// Toggle theme
|
||||
toggle.addEventListener('click', () => {
|
||||
isDark = !isDark;
|
||||
isDark ? localStorage.setItem('theme', 'sl-theme-dark') : localStorage.removeItem('theme');
|
||||
toggle.name = isDark ? 'sun' : 'moon';
|
||||
|
||||
// Disable transitions as the theme changes
|
||||
document.body.appendChild(noTransitions);
|
||||
requestAnimationFrame(() => {
|
||||
document.body.classList.toggle('sl-theme-dark', isDark);
|
||||
requestAnimationFrame(() => document.body.removeChild(noTransitions));
|
||||
});
|
||||
});
|
||||
|
||||
sidebarToggle.insertAdjacentElement('afterend', toggle);
|
||||
});
|
||||
});
|
||||
})();
|
||||
249
docs/assets/scripts/code-previews.js
Normal file
@@ -0,0 +1,249 @@
|
||||
(() => {
|
||||
function convertModuleLinks(html) {
|
||||
html = html
|
||||
.replace(/@shoelace-style\/shoelace/g, `https://esm.sh/@shoelace-style/shoelace@${shoelaceVersion}`)
|
||||
.replace(/from 'react'/g, `from 'https://esm.sh/react@${reactVersion}'`)
|
||||
.replace(/from "react"/g, `from "https://esm.sh/react@${reactVersion}"`);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function getAdjacentExample(name, pre) {
|
||||
let currentPre = pre.nextElementSibling;
|
||||
|
||||
while (currentPre?.tagName.toLowerCase() === 'pre') {
|
||||
if (currentPre?.getAttribute('data-lang').split(' ').includes(name)) {
|
||||
return currentPre;
|
||||
}
|
||||
|
||||
currentPre = currentPre.nextElementSibling;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function runScript(script) {
|
||||
const newScript = document.createElement('script');
|
||||
|
||||
if (script.type === 'module') {
|
||||
newScript.type = 'module';
|
||||
newScript.textContent = script.innerHTML;
|
||||
} else {
|
||||
newScript.appendChild(document.createTextNode(`(() => { ${script.innerHTML} })();`));
|
||||
}
|
||||
|
||||
script.parentNode.replaceChild(newScript, script);
|
||||
}
|
||||
|
||||
function getFlavor() {
|
||||
return sessionStorage.getItem('flavor') || 'html';
|
||||
}
|
||||
|
||||
function setFlavor(newFlavor) {
|
||||
flavor = ['html', 'react'].includes(newFlavor) ? newFlavor : 'html';
|
||||
sessionStorage.setItem('flavor', flavor);
|
||||
|
||||
// Set the flavor class on the body
|
||||
document.documentElement.classList.toggle('flavor-html', flavor === 'html');
|
||||
document.documentElement.classList.toggle('flavor-react', flavor === 'react');
|
||||
}
|
||||
|
||||
function syncFlavor() {
|
||||
setFlavor(getFlavor());
|
||||
|
||||
document.querySelectorAll('.code-preview__button--html').forEach(preview => {
|
||||
if (flavor === 'html') {
|
||||
preview.classList.add('code-preview__button--selected');
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.code-preview__button--react').forEach(preview => {
|
||||
if (flavor === 'react') {
|
||||
preview.classList.add('code-preview__button--selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const shoelaceVersion = document.documentElement.getAttribute('data-shoelace-version');
|
||||
const reactVersion = '18.2.0';
|
||||
const cdndir = 'cdn';
|
||||
const npmdir = 'dist';
|
||||
let flavor = getFlavor();
|
||||
let count = 1;
|
||||
|
||||
// We need the version to open
|
||||
if (!shoelaceVersion) {
|
||||
throw new Error('The data-shoelace-version attribute is missing from <html>.');
|
||||
}
|
||||
|
||||
// Sync flavor UI on page load
|
||||
syncFlavor();
|
||||
|
||||
//
|
||||
// Resizing previews
|
||||
//
|
||||
document.addEventListener('mousedown', handleResizerDrag);
|
||||
document.addEventListener('touchstart', handleResizerDrag, { passive: true });
|
||||
|
||||
function handleResizerDrag(event) {
|
||||
const resizer = event.target.closest('.code-preview__resizer');
|
||||
const preview = event.target.closest('.code-preview__preview');
|
||||
|
||||
if (!resizer || !preview) return;
|
||||
|
||||
let startX = event.changedTouches ? event.changedTouches[0].pageX : event.clientX;
|
||||
let startWidth = parseInt(document.defaultView.getComputedStyle(preview).width, 10);
|
||||
|
||||
event.preventDefault();
|
||||
preview.classList.add('code-preview__preview--dragging');
|
||||
document.documentElement.addEventListener('mousemove', dragMove);
|
||||
document.documentElement.addEventListener('touchmove', dragMove);
|
||||
document.documentElement.addEventListener('mouseup', dragStop);
|
||||
document.documentElement.addEventListener('touchend', dragStop);
|
||||
|
||||
function dragMove(event) {
|
||||
const width = startWidth + (event.changedTouches ? event.changedTouches[0].pageX : event.pageX) - startX;
|
||||
preview.style.width = `${width}px`;
|
||||
}
|
||||
|
||||
function dragStop() {
|
||||
preview.classList.remove('code-preview__preview--dragging');
|
||||
document.documentElement.removeEventListener('mousemove', dragMove);
|
||||
document.documentElement.removeEventListener('touchmove', dragMove);
|
||||
document.documentElement.removeEventListener('mouseup', dragStop);
|
||||
document.documentElement.removeEventListener('touchend', dragStop);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Toggle source mode
|
||||
//
|
||||
document.addEventListener('click', event => {
|
||||
const button = event.target.closest('.code-preview__button');
|
||||
const codeBlock = button?.closest('.code-preview');
|
||||
|
||||
if (button?.classList.contains('code-preview__button--html')) {
|
||||
// Show HTML
|
||||
setFlavor('html');
|
||||
toggleSource(codeBlock, true);
|
||||
} else if (button?.classList.contains('code-preview__button--react')) {
|
||||
// Show React
|
||||
setFlavor('react');
|
||||
toggleSource(codeBlock, true);
|
||||
} else if (button?.classList.contains('code-preview__toggle')) {
|
||||
// Toggle source
|
||||
toggleSource(codeBlock);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update flavor buttons
|
||||
[...document.querySelectorAll('.code-preview')].forEach(cb => {
|
||||
cb.querySelector('.code-preview__button--html')?.classList.toggle(
|
||||
'code-preview__button--selected',
|
||||
flavor === 'html'
|
||||
);
|
||||
cb.querySelector('.code-preview__button--react')?.classList.toggle(
|
||||
'code-preview__button--selected',
|
||||
flavor === 'react'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function toggleSource(codeBlock, force) {
|
||||
codeBlock.classList.toggle('code-preview--expanded', force);
|
||||
event.target.setAttribute('aria-expanded', codeBlock.classList.contains('code-preview--expanded'));
|
||||
}
|
||||
|
||||
//
|
||||
// Open in CodePen
|
||||
//
|
||||
document.addEventListener('click', event => {
|
||||
const button = event.target.closest('button');
|
||||
|
||||
if (button?.classList.contains('code-preview__button--codepen')) {
|
||||
const codeBlock = button.closest('.code-preview');
|
||||
const htmlExample = codeBlock.querySelector('.code-preview__source--html > pre > code')?.textContent;
|
||||
const reactExample = codeBlock.querySelector('.code-preview__source--react > pre > code')?.textContent;
|
||||
const isReact = flavor === 'react' && typeof reactExample === 'string';
|
||||
const theme = document.documentElement.classList.contains('sl-theme-dark') ? 'dark' : 'light';
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const isDark = theme === 'dark' || (theme === 'auto' && prefersDark);
|
||||
const editors = isReact ? '0010' : '1000';
|
||||
let htmlTemplate = '';
|
||||
let jsTemplate = '';
|
||||
let cssTemplate = '';
|
||||
|
||||
const form = document.createElement('form');
|
||||
form.action = 'https://codepen.io/pen/define';
|
||||
form.method = 'POST';
|
||||
form.target = '_blank';
|
||||
|
||||
// HTML templates
|
||||
if (!isReact) {
|
||||
htmlTemplate =
|
||||
`<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@${shoelaceVersion}/${cdndir}/shoelace.js"></script>\n` +
|
||||
`\n${htmlExample}`;
|
||||
jsTemplate = '';
|
||||
}
|
||||
|
||||
// React templates
|
||||
if (isReact) {
|
||||
htmlTemplate = '<div id="root"></div>';
|
||||
jsTemplate =
|
||||
`import React from 'https://esm.sh/react@${reactVersion}';\n` +
|
||||
`import ReactDOM from 'https://esm.sh/react-dom@${reactVersion}';\n` +
|
||||
`import { setBasePath } from 'https://esm.sh/@shoelace-style/shoelace@${shoelaceVersion}/${cdndir}/utilities/base-path';\n` +
|
||||
`\n` +
|
||||
`// Set the base path for Shoelace assets\n` +
|
||||
`setBasePath('https://esm.sh/@shoelace-style/shoelace@${shoelaceVersion}/${npmdir}/')\n` +
|
||||
`\n${convertModuleLinks(reactExample)}\n` +
|
||||
`\n` +
|
||||
`ReactDOM.render(<App />, document.getElementById('root'));`;
|
||||
}
|
||||
|
||||
// CSS templates
|
||||
cssTemplate =
|
||||
`@import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@${shoelaceVersion}/${cdndir}/themes/${
|
||||
isDark ? 'dark' : 'light'
|
||||
}.css';\n` +
|
||||
'\n' +
|
||||
'body {\n' +
|
||||
' font: 16px sans-serif;\n' +
|
||||
' background-color: var(--sl-color-neutral-0);\n' +
|
||||
' color: var(--sl-color-neutral-900);\n' +
|
||||
' padding: 1rem;\n' +
|
||||
'}';
|
||||
|
||||
// Docs: https://blog.codepen.io/documentation/prefill/
|
||||
const data = {
|
||||
title: '',
|
||||
description: '',
|
||||
tags: ['shoelace', 'web components'],
|
||||
editors,
|
||||
head: `<meta name="viewport" content="width=device-width">`,
|
||||
html_classes: `sl-theme-${isDark ? 'dark' : 'light'}`,
|
||||
css_external: ``,
|
||||
js_external: ``,
|
||||
js_module: true,
|
||||
js_pre_processor: isReact ? 'babel' : 'none',
|
||||
html: htmlTemplate,
|
||||
css: cssTemplate,
|
||||
js: jsTemplate
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
// Set the initial flavor
|
||||
window.addEventListener('turbo:load', syncFlavor);
|
||||
})();
|
||||
272
docs/assets/scripts/docs.js
Normal file
@@ -0,0 +1,272 @@
|
||||
//
|
||||
// Sidebar
|
||||
//
|
||||
// When the sidebar is hidden, we apply the inert attribute to prevent focus from reaching it. Due to the many states
|
||||
// the sidebar can have (e.g. static, hidden, expanded), we test for visibility by checking to see if it's placed
|
||||
// offscreen or not. Then, on resize/transition we make sure to update the attribute accordingly.
|
||||
//
|
||||
(() => {
|
||||
function getSidebar() {
|
||||
return document.getElementById('sidebar');
|
||||
}
|
||||
|
||||
function isSidebarOpen() {
|
||||
return document.documentElement.classList.contains('sidebar-open');
|
||||
}
|
||||
|
||||
function isSidebarVisible() {
|
||||
return getSidebar().getBoundingClientRect().x >= 0;
|
||||
}
|
||||
|
||||
function toggleSidebar(force) {
|
||||
const isOpen = typeof force === 'boolean' ? force : !isSidebarOpen();
|
||||
return document.documentElement.classList.toggle('sidebar-open', isOpen);
|
||||
}
|
||||
|
||||
function updateInert() {
|
||||
getSidebar().inert = !isSidebarVisible();
|
||||
}
|
||||
|
||||
// Toggle the menu
|
||||
document.addEventListener('click', event => {
|
||||
const menuToggle = event.target.closest('#menu-toggle');
|
||||
if (!menuToggle) return;
|
||||
toggleSidebar();
|
||||
});
|
||||
|
||||
// Update the sidebar's inert state when the window resizes and when the sidebar transitions
|
||||
window.addEventListener('resize', () => toggleSidebar(false));
|
||||
|
||||
document.addEventListener('transitionend', event => {
|
||||
const sidebar = event.target.closest('#sidebar');
|
||||
if (!sidebar) return;
|
||||
updateInert();
|
||||
});
|
||||
|
||||
// Close when a menu item is selected on mobile
|
||||
document.addEventListener('click', event => {
|
||||
const sidebar = event.target.closest('#sidebar');
|
||||
const link = event.target.closest('a');
|
||||
if (!sidebar || !link) return;
|
||||
|
||||
if (isSidebarOpen()) {
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
// Close when open and escape is pressed
|
||||
document.addEventListener('keydown', event => {
|
||||
if (event.key === 'Escape' && isSidebarOpen()) {
|
||||
event.stopImmediatePropagation();
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
// Close when clicking outside of the sidebar
|
||||
document.addEventListener('mousedown', event => {
|
||||
if (isSidebarOpen() & !event.target?.closest('#sidebar, #menu-toggle')) {
|
||||
event.stopImmediatePropagation();
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
updateInert();
|
||||
})();
|
||||
|
||||
//
|
||||
// Theme selector
|
||||
//
|
||||
(() => {
|
||||
function getTheme() {
|
||||
return localStorage.getItem('theme') || 'auto';
|
||||
}
|
||||
|
||||
function isDark() {
|
||||
if (theme === 'auto') {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
}
|
||||
return theme === 'dark';
|
||||
}
|
||||
|
||||
function setTheme(newTheme) {
|
||||
theme = newTheme;
|
||||
localStorage.setItem('theme', theme);
|
||||
|
||||
// Update the UI
|
||||
updateSelection();
|
||||
|
||||
// Toggle the dark mode class
|
||||
document.documentElement.classList.toggle('sl-theme-dark', isDark());
|
||||
}
|
||||
|
||||
function updateSelection() {
|
||||
const menu = document.querySelector('#theme-selector sl-menu');
|
||||
if (!menu) return;
|
||||
[...menu.querySelectorAll('sl-menu-item')].map(item => (item.checked = item.getAttribute('value') === theme));
|
||||
}
|
||||
|
||||
let theme = getTheme();
|
||||
|
||||
// Selection is not preserved when changing page, so update when opening dropdown
|
||||
document.addEventListener('sl-show', event => {
|
||||
const themeSelector = event.target.closest('#theme-selector');
|
||||
if (!themeSelector) return;
|
||||
updateSelection();
|
||||
});
|
||||
|
||||
// Listen for selections
|
||||
document.addEventListener('sl-select', event => {
|
||||
const menu = event.target.closest('#theme-selector sl-menu');
|
||||
if (!menu) return;
|
||||
setTheme(event.detail.item.value);
|
||||
});
|
||||
|
||||
// Update the theme when the preference changes
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => setTheme(theme));
|
||||
|
||||
// Toggle with backslash
|
||||
document.addEventListener('keydown', event => {
|
||||
if (
|
||||
event.key === '\\' &&
|
||||
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
|
||||
) {
|
||||
event.preventDefault();
|
||||
setTheme(isDark() ? 'light' : 'dark');
|
||||
}
|
||||
});
|
||||
|
||||
// Set the initial theme and sync the UI
|
||||
setTheme(theme);
|
||||
})();
|
||||
|
||||
//
|
||||
// Open details when printing
|
||||
//
|
||||
(() => {
|
||||
const detailsOpenOnPrint = new Set();
|
||||
|
||||
window.addEventListener('beforeprint', () => {
|
||||
detailsOpenOnPrint.clear();
|
||||
document.querySelectorAll('details').forEach(details => {
|
||||
if (details.open) {
|
||||
detailsOpenOnPrint.add(details);
|
||||
}
|
||||
details.open = true;
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('afterprint', () => {
|
||||
document.querySelectorAll('details').forEach(details => {
|
||||
details.open = detailsOpenOnPrint.has(details);
|
||||
});
|
||||
detailsOpenOnPrint.clear();
|
||||
});
|
||||
})();
|
||||
|
||||
//
|
||||
// Smooth links
|
||||
//
|
||||
(() => {
|
||||
document.addEventListener('click', event => {
|
||||
const link = event.target.closest('a');
|
||||
const id = (link?.hash ?? '').substr(1);
|
||||
const isFragment = link?.hasAttribute('href') && link?.getAttribute('href').startsWith('#');
|
||||
|
||||
if (!link || !isFragment || link.getAttribute('data-smooth-link') === 'false') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Scroll to the top
|
||||
if (link.hash === '') {
|
||||
event.preventDefault();
|
||||
window.scroll({ top: 0, behavior: 'smooth' });
|
||||
history.pushState(undefined, undefined, location.pathname);
|
||||
}
|
||||
|
||||
// Scroll to an id
|
||||
if (id) {
|
||||
const target = document.getElementById(id);
|
||||
|
||||
if (target) {
|
||||
event.preventDefault();
|
||||
window.scroll({ top: target.offsetTop, behavior: 'smooth' });
|
||||
history.pushState(undefined, undefined, `#${id}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
//
|
||||
// Table of Contents scrollspy
|
||||
//
|
||||
(() => {
|
||||
// This will be stale if its not a function.
|
||||
const getLinks = () => [...document.querySelectorAll('.content__toc a')];
|
||||
const linkTargets = new WeakMap();
|
||||
const visibleTargets = new WeakSet();
|
||||
const observer = new IntersectionObserver(handleIntersect, { rootMargin: '0px 0px' });
|
||||
let debounce;
|
||||
|
||||
function handleIntersect(entries) {
|
||||
entries.forEach(entry => {
|
||||
// Remember which targets are visible
|
||||
if (entry.isIntersecting) {
|
||||
visibleTargets.add(entry.target);
|
||||
} else {
|
||||
visibleTargets.delete(entry.target);
|
||||
}
|
||||
});
|
||||
|
||||
updateActiveLinks();
|
||||
}
|
||||
|
||||
function updateActiveLinks() {
|
||||
const links = getLinks();
|
||||
// Find the first visible target and activate the respective link
|
||||
links.find(link => {
|
||||
const target = linkTargets.get(link);
|
||||
|
||||
if (target && visibleTargets.has(target)) {
|
||||
links.forEach(el => el.classList.toggle('active', el === link));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Observe link targets
|
||||
function observeLinks() {
|
||||
getLinks().forEach(link => {
|
||||
const hash = link.hash.slice(1);
|
||||
const target = hash ? document.querySelector(`.content__body #${hash}`) : null;
|
||||
|
||||
if (target) {
|
||||
linkTargets.set(link, target);
|
||||
observer.observe(target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
observeLinks();
|
||||
|
||||
document.addEventListener('turbo:load', updateActiveLinks);
|
||||
document.addEventListener('turbo:load', observeLinks);
|
||||
})();
|
||||
|
||||
//
|
||||
// Show custom versions in the sidebar
|
||||
//
|
||||
(() => {
|
||||
function updateVersion() {
|
||||
const el = document.querySelector('.sidebar-version');
|
||||
if (!el) return;
|
||||
|
||||
if (location.hostname === 'next.shoelace.style') el.textContent = 'Next';
|
||||
if (location.hostname === 'localhost') el.textContent = 'Development';
|
||||
}
|
||||
|
||||
updateVersion();
|
||||
|
||||
document.addEventListener('turbo:load', updateVersion);
|
||||
})();
|
||||
376
docs/assets/scripts/search.js
Normal file
@@ -0,0 +1,376 @@
|
||||
(() => {
|
||||
// Append the search dialog to the body
|
||||
const siteSearch = document.createElement('div');
|
||||
const scrollbarWidth = Math.abs(window.innerWidth - document.documentElement.clientWidth);
|
||||
|
||||
siteSearch.classList.add('search');
|
||||
siteSearch.innerHTML = `
|
||||
<div class="search__overlay"></div>
|
||||
<dialog id="search-dialog" class="search__dialog">
|
||||
<div class="search__content">
|
||||
<div class="search__header">
|
||||
<div id="search-combobox" class="search__input-wrapper">
|
||||
<sl-icon name="search"></sl-icon>
|
||||
<input
|
||||
id="search-input"
|
||||
class="search__input"
|
||||
type="search"
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
enterkeyhint="go"
|
||||
spellcheck="false"
|
||||
maxlength="100"
|
||||
role="combobox"
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="true"
|
||||
aria-controls="search-listbox"
|
||||
aria-haspopup="listbox"
|
||||
aria-activedescendant
|
||||
>
|
||||
<button type="button" class="search__clear-button" aria-label="Clear entry" tabindex="-1" hidden>
|
||||
<sl-icon name="x-circle-fill"></sl-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search__body">
|
||||
<ul
|
||||
id="search-listbox"
|
||||
class="search__results"
|
||||
role="listbox"
|
||||
aria-label="Search results"
|
||||
></ul>
|
||||
<div class="search__empty">No matching pages</div>
|
||||
</div>
|
||||
<footer class="search__footer">
|
||||
<small><kbd>↑</kbd> <kbd>↓</kbd> Navigate</small>
|
||||
<small><kbd>↲</kbd> Select</small>
|
||||
<small><kbd>Esc</kbd> Close</small>
|
||||
</footer>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
const overlay = siteSearch.querySelector('.search__overlay');
|
||||
const dialog = siteSearch.querySelector('.search__dialog');
|
||||
const input = siteSearch.querySelector('.search__input');
|
||||
const clearButton = siteSearch.querySelector('.search__clear-button');
|
||||
const results = siteSearch.querySelector('.search__results');
|
||||
const version = document.documentElement.getAttribute('data-shoelace-version');
|
||||
const key = `search_${version}`;
|
||||
const searchDebounce = 50;
|
||||
const animationDuration = 150;
|
||||
let isShowing = false;
|
||||
let searchTimeout;
|
||||
let searchIndex;
|
||||
let map;
|
||||
|
||||
const loadSearchIndex = new Promise(resolve => {
|
||||
const cache = localStorage.getItem(key);
|
||||
const wait = 'requestIdleCallback' in window ? requestIdleCallback : requestAnimationFrame;
|
||||
|
||||
// Cleanup older search indices (everything before this version)
|
||||
try {
|
||||
const items = { ...localStorage };
|
||||
|
||||
Object.keys(items).forEach(k => {
|
||||
if (key > k) {
|
||||
localStorage.removeItem(k);
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
// Look for a cached index
|
||||
try {
|
||||
if (cache) {
|
||||
const data = JSON.parse(cache);
|
||||
|
||||
searchIndex = window.lunr.Index.load(data.searchIndex);
|
||||
map = data.map;
|
||||
|
||||
return resolve();
|
||||
}
|
||||
} catch {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
// Wait until idle to fetch the index
|
||||
wait(() => {
|
||||
fetch('/assets/search.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (!window.lunr) {
|
||||
console.error('The Lunr search client has not yet been loaded.');
|
||||
}
|
||||
|
||||
searchIndex = window.lunr.Index.load(data.searchIndex);
|
||||
map = data.map;
|
||||
|
||||
// Cache the search index for this version
|
||||
if (version) {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(data));
|
||||
} catch (err) {
|
||||
console.warn(`Unable to cache the search index: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function show() {
|
||||
isShowing = true;
|
||||
document.body.append(siteSearch);
|
||||
document.body.classList.add('search-visible');
|
||||
document.body.style.setProperty('--docs-search-scroll-lock-size', `${scrollbarWidth}px`);
|
||||
clearButton.hidden = true;
|
||||
requestAnimationFrame(() => input.focus());
|
||||
updateResults();
|
||||
|
||||
dialog.showModal();
|
||||
|
||||
await Promise.all([
|
||||
dialog.animate(
|
||||
[
|
||||
{ opacity: 0, transform: 'scale(.9)', transformOrigin: 'top' },
|
||||
{ opacity: 1, transform: 'scale(1)', transformOrigin: 'top' }
|
||||
],
|
||||
{ duration: animationDuration }
|
||||
).finished,
|
||||
overlay.animate([{ opacity: 0 }, { opacity: 1 }], { duration: animationDuration }).finished
|
||||
]);
|
||||
|
||||
dialog.addEventListener('mousedown', handleMouseDown);
|
||||
dialog.addEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
async function hide() {
|
||||
isShowing = false;
|
||||
|
||||
await Promise.all([
|
||||
dialog.animate(
|
||||
[
|
||||
{ opacity: 1, transform: 'scale(1)', transformOrigin: 'top' },
|
||||
{ opacity: 0, transform: 'scale(.9)', transformOrigin: 'top' }
|
||||
],
|
||||
{ duration: animationDuration }
|
||||
).finished,
|
||||
overlay.animate([{ opacity: 1 }, { opacity: 0 }], { duration: animationDuration }).finished
|
||||
]);
|
||||
|
||||
dialog.close();
|
||||
|
||||
input.blur(); // otherwise Safari will scroll to the bottom of the page on close
|
||||
input.value = '';
|
||||
document.body.classList.remove('search-visible');
|
||||
document.body.style.removeProperty('--docs-search-scroll-lock-size');
|
||||
siteSearch.remove();
|
||||
updateResults();
|
||||
|
||||
dialog.removeEventListener('mousedown', handleMouseDown);
|
||||
dialog.removeEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
function handleInput() {
|
||||
clearButton.hidden = input.value === '';
|
||||
|
||||
// Debounce search queries
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce);
|
||||
}
|
||||
|
||||
function handleClear() {
|
||||
clearButton.hidden = true;
|
||||
input.value = '';
|
||||
input.focus();
|
||||
updateResults();
|
||||
}
|
||||
|
||||
function handleMouseDown(event) {
|
||||
if (!event.target.closest('.search__content')) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
// Close when pressing escape
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault(); // prevent <dialog> from closing immediately so it can animate
|
||||
event.stopImmediatePropagation();
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle keyboard selections
|
||||
if (['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
|
||||
const currentEl = results.querySelector('[data-selected="true"]');
|
||||
const items = [...results.querySelectorAll('li')];
|
||||
const index = items.indexOf(currentEl);
|
||||
let nextEl;
|
||||
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowUp':
|
||||
nextEl = items[Math.max(0, index - 1)];
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
nextEl = items[Math.min(items.length - 1, index + 1)];
|
||||
break;
|
||||
case 'Home':
|
||||
nextEl = items[0];
|
||||
break;
|
||||
case 'End':
|
||||
nextEl = items[items.length - 1];
|
||||
break;
|
||||
case 'Enter':
|
||||
currentEl?.querySelector('a')?.click();
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the selected item
|
||||
items.forEach(item => {
|
||||
if (item === nextEl) {
|
||||
input.setAttribute('aria-activedescendant', item.id);
|
||||
item.setAttribute('data-selected', 'true');
|
||||
nextEl.scrollIntoView({ block: 'nearest' });
|
||||
} else {
|
||||
item.setAttribute('data-selected', 'false');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function updateResults(query = '') {
|
||||
try {
|
||||
await loadSearchIndex;
|
||||
|
||||
const hasQuery = query.length > 0;
|
||||
const searchTerms = query
|
||||
.split(' ')
|
||||
.map((term, index, arr) => {
|
||||
// Search API: https://lunrjs.com/guides/searching.html
|
||||
if (index === arr.length - 1) {
|
||||
// The last term is not mandatory and 1x fuzzy. We also duplicate it with a wildcard to match partial words
|
||||
// as the user types.
|
||||
return `${term}~1 ${term}*`;
|
||||
} else {
|
||||
// All other terms are mandatory and 1x fuzzy
|
||||
return `+${term}~1`;
|
||||
}
|
||||
})
|
||||
.join(' ');
|
||||
const matches = hasQuery ? searchIndex.search(searchTerms) : [];
|
||||
const hasResults = hasQuery && matches.length > 0;
|
||||
|
||||
siteSearch.classList.toggle('search--has-results', hasQuery && hasResults);
|
||||
siteSearch.classList.toggle('search--no-results', hasQuery && !hasResults);
|
||||
|
||||
input.setAttribute('aria-activedescendant', '');
|
||||
results.innerHTML = '';
|
||||
|
||||
matches.forEach((match, index) => {
|
||||
const page = map[match.ref];
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
const displayTitle = page.title ?? '';
|
||||
const displayDescription = page.description ?? '';
|
||||
const displayUrl = page.url.replace(/^\//, '').replace(/\/$/, '');
|
||||
let icon = 'file-text';
|
||||
|
||||
a.setAttribute('role', 'option');
|
||||
a.setAttribute('id', `search-result-item-${match.ref}`);
|
||||
|
||||
if (page.url.includes('getting-started/')) {
|
||||
icon = 'lightbulb';
|
||||
}
|
||||
if (page.url.includes('resources/')) {
|
||||
icon = 'book';
|
||||
}
|
||||
if (page.url.includes('components/')) {
|
||||
icon = 'puzzle';
|
||||
}
|
||||
if (page.url.includes('tokens/')) {
|
||||
icon = 'palette2';
|
||||
}
|
||||
if (page.url.includes('utilities/')) {
|
||||
icon = 'wrench';
|
||||
}
|
||||
if (page.url.includes('tutorials/')) {
|
||||
icon = 'joystick';
|
||||
}
|
||||
|
||||
li.classList.add('search__result');
|
||||
li.setAttribute('role', 'option');
|
||||
li.setAttribute('id', `search-result-item-${match.ref}`);
|
||||
li.setAttribute('data-selected', index === 0 ? 'true' : 'false');
|
||||
|
||||
a.href = page.url;
|
||||
a.innerHTML = `
|
||||
<div class="search__result-icon" aria-hidden="true">
|
||||
<sl-icon name="${icon}"></sl-icon>
|
||||
</div>
|
||||
<div class="search__result__details">
|
||||
<div class="search__result-title"></div>
|
||||
<div class="search__result-description"></div>
|
||||
<div class="search__result-url"></div>
|
||||
</div>
|
||||
`;
|
||||
a.querySelector('.search__result-title').textContent = displayTitle;
|
||||
a.querySelector('.search__result-description').textContent = displayDescription;
|
||||
a.querySelector('.search__result-url').textContent = displayUrl;
|
||||
|
||||
li.appendChild(a);
|
||||
results.appendChild(li);
|
||||
});
|
||||
} catch {
|
||||
// Ignore query errors as the user types
|
||||
}
|
||||
}
|
||||
|
||||
// Show the search dialog when clicking on data-plugin="search"
|
||||
document.addEventListener('click', event => {
|
||||
const searchButton = event.target.closest('[data-plugin="search"]');
|
||||
if (searchButton) {
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
// Show the search dialog when slash (or CMD+K) is pressed and focus is not inside a form element
|
||||
document.addEventListener('keydown', event => {
|
||||
if (
|
||||
!isShowing &&
|
||||
(event.key === '/' || (event.key === 'k' && (event.metaKey || event.ctrlKey))) &&
|
||||
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
|
||||
) {
|
||||
event.preventDefault();
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
// Purge cache when we press CMD+CTRL+R
|
||||
document.addEventListener('keydown', event => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'r') {
|
||||
localStorage.clear();
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('input', handleInput);
|
||||
clearButton.addEventListener('click', handleClear);
|
||||
|
||||
// Close when a result is selected
|
||||
results.addEventListener('click', event => {
|
||||
if (event.target.closest('a')) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
})();
|
||||
29
docs/assets/scripts/turbo.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as Turbo from 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@7.3.0/+esm';
|
||||
|
||||
(() => {
|
||||
if (!window.scrollPositions) {
|
||||
window.scrollPositions = {};
|
||||
}
|
||||
|
||||
function preserveScroll() {
|
||||
document.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
scrollPositions[element.id] = element.scrollTop;
|
||||
});
|
||||
}
|
||||
|
||||
function restoreScroll(event) {
|
||||
document.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
element.scrollTop = scrollPositions[element.id];
|
||||
});
|
||||
|
||||
if (event.detail && event.detail.newBody) {
|
||||
event.detail.newBody.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
element.scrollTop = scrollPositions[element.id];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('turbo:before-cache', preserveScroll);
|
||||
window.addEventListener('turbo:before-render', restoreScroll);
|
||||
window.addEventListener('turbo:render', restoreScroll);
|
||||
})();
|
||||
173
docs/assets/styles/code-previews.css
Normal file
@@ -0,0 +1,173 @@
|
||||
/* Interactive code blocks */
|
||||
.code-preview {
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
background-color: var(--sl-color-neutral-50);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.code-preview__preview {
|
||||
position: relative;
|
||||
border: solid 1px var(--sl-color-neutral-200);
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
background-color: var(--sl-color-neutral-0);
|
||||
min-width: 20rem;
|
||||
max-width: 100%;
|
||||
padding: 1.5rem 3.25rem 1.5rem 1.5rem;
|
||||
}
|
||||
|
||||
/* Block the preview while dragging to prevent iframes from intercepting drag events */
|
||||
.code-preview__preview--dragging:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.code-preview__resizer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 1.75rem;
|
||||
font-size: 20px;
|
||||
color: var(--sl-color-neutral-600);
|
||||
background-color: var(--sl-color-neutral-0);
|
||||
border-left: solid 1px var(--sl-color-neutral-200);
|
||||
border-top-right-radius: 3px;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.code-preview__preview {
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.code-preview__resizer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.code-preview__source {
|
||||
border: solid 1px var(--sl-color-neutral-200);
|
||||
border-bottom: none;
|
||||
border-radius: 0 !important;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.code-preview--expanded .code-preview__source {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.code-preview__source pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.code-preview__buttons {
|
||||
position: relative;
|
||||
border: solid 1px var(--sl-color-neutral-200);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.code-preview__button {
|
||||
flex: 0 0 auto;
|
||||
height: 2.5rem;
|
||||
min-width: 2.5rem;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: var(--sl-color-neutral-0);
|
||||
font: inherit;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
color: var(--sl-color-neutral-600);
|
||||
padding: 0 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.code-preview__button:not(:last-of-type) {
|
||||
border-right: solid 1px var(--sl-color-neutral-200);
|
||||
}
|
||||
|
||||
.code-preview__button--html,
|
||||
.code-preview__button--react {
|
||||
width: 70px;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.code-preview__button--selected {
|
||||
font-weight: 700;
|
||||
color: var(--sl-color-primary-600);
|
||||
}
|
||||
|
||||
.code-preview__button--codepen {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
width: 6rem;
|
||||
}
|
||||
|
||||
.code-preview__button:first-of-type {
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
.code-preview__button:last-of-type {
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
.code-preview__button:hover,
|
||||
.code-preview__button:active {
|
||||
box-shadow: 0 0 0 1px var(--sl-color-primary-400);
|
||||
border-right-color: transparent;
|
||||
background-color: var(--sl-color-primary-50);
|
||||
color: var(--sl-color-primary-600);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.code-preview__button:focus-visible {
|
||||
outline: none;
|
||||
outline: var(--sl-focus-ring);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.code-preview__toggle {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
color: var(--sl-color-neutral-600);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.code-preview__toggle svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.code-preview--expanded .code-preview__toggle svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* We can apply data-flavor="html|react" to any element on the page to toggle it when the flavor changes */
|
||||
.flavor-html [data-flavor]:not([data-flavor='html']) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flavor-react [data-flavor]:not([data-flavor='react']) {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/* Color demo */
|
||||
.color-demo {
|
||||
width: 4rem;
|
||||
height: 2rem;
|
||||
border-radius: var(--sl-border-radius-small);
|
||||
box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.33);
|
||||
}
|
||||
|
||||
/* Border radius demo */
|
||||
.border-radius-demo {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background: var(--sl-color-primary-500);
|
||||
}
|
||||
|
||||
/* Transition demo */
|
||||
.transition-demo {
|
||||
position: relative;
|
||||
background: var(--sl-color-gray-200);
|
||||
width: 8rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.transition-demo:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: var(--sl-color-primary-500);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
transition-duration: inherit;
|
||||
transition-property: width;
|
||||
}
|
||||
|
||||
.transition-demo:hover:after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sl-theme-dark .transition-demo {
|
||||
background: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
/* Spacing demo */
|
||||
.spacing-demo {
|
||||
width: 100px;
|
||||
background: var(--sl-color-primary-500);
|
||||
}
|
||||
|
||||
/* Elevation dmeo */
|
||||
.elevation-demo {
|
||||
background: var(--sl-color-white);
|
||||
border-radius: 3px;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.sl-theme-dark .elevation-demo {
|
||||
background-color: var(--sl-color-gray-800);
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
/* Elevation tokens */
|
||||
.sl-theme-dark {
|
||||
--sl-shadow-x-small: 0 1px 0 #6b72800d;
|
||||
--sl-shadow-small: 0 1px 2px #6b72801a;
|
||||
--sl-shadow-medium: 0 2px 4px #6b72801a;
|
||||
--sl-shadow-large: 0 2px 8px #6b72801a;
|
||||
--sl-shadow-x-large: 0 4px 16px #6b72801a;
|
||||
}
|
||||
|
||||
.sl-theme-dark {
|
||||
background: var(--sl-color-gray-900);
|
||||
color: var(--sl-color-gray-200);
|
||||
}
|
||||
|
||||
/* Sidebar **/
|
||||
.sl-theme-dark .sidebar {
|
||||
background: var(--sl-color-gray-900);
|
||||
border-right-color: var(--sl-color-gray-900);
|
||||
}
|
||||
|
||||
.sl-theme-dark .sidebar li > p {
|
||||
color: var(--sl-color-white);
|
||||
border-bottom-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .sidebar-toggle {
|
||||
background-color: var(--sl-color-gray-900);
|
||||
}
|
||||
|
||||
.sl-theme-dark .docsify-pagination-container {
|
||||
border-top-color: var(--sl-color-gray-800) !important;
|
||||
}
|
||||
|
||||
/* Search */
|
||||
.sl-theme-dark .sidebar .search input[type='search'] {
|
||||
background: var(--sl-input-background-color);
|
||||
border-color: var(--sl-input-border-color);
|
||||
color: var(--sl-input-color);
|
||||
}
|
||||
|
||||
.sl-theme-dark .sidebar .search input[type='search']:hover {
|
||||
border-color: var(--sl-input-border-color-hover);
|
||||
}
|
||||
|
||||
.sl-theme-dark .sidebar .search input[type='search']:focus {
|
||||
border-color: var(--sl-input-border-color-focus);
|
||||
}
|
||||
|
||||
.sl-theme-dark .sidebar .clear-button {
|
||||
color: var(--sl-color-gray-700);
|
||||
}
|
||||
|
||||
.sl-theme-dark .sidebar .clear-button svg circle {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.sl-theme-dark .component-header {
|
||||
border-bottom-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .anchor span {
|
||||
color: var(--sl-color-white);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section h2 {
|
||||
border-bottom-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section blockquote {
|
||||
border-left-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section kbd {
|
||||
border-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.sl-theme-dark .markdown-section tr:nth-child(2n) {
|
||||
background: var(--sl-color-gray-950);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section td {
|
||||
border-top-color: var(--sl-color-gray-800);
|
||||
border-bottom-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section table .attribute-tooltip {
|
||||
border-bottom-color: var(--sl-color-gray-700);
|
||||
}
|
||||
|
||||
/* Tips & warnings */
|
||||
.sl-theme-dark .markdown-section p.tip,
|
||||
.sl-theme-dark .markdown-section p.warn {
|
||||
background-color: var(--sl-color-gray-950);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section p.tip:before,
|
||||
.sl-theme-dark .markdown-section p.warn:before {
|
||||
color: var(--sl-color-gray-900);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section p.tip code,
|
||||
.sl-theme-dark .markdown-section p.warn code {
|
||||
background-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
/* Code */
|
||||
.sl-theme-dark .markdown-section code {
|
||||
background: var(--sl-color-gray-950);
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
.sl-theme-dark .markdown-section pre,
|
||||
.sl-theme-dark .code-block__source {
|
||||
background-color: var(--sl-color-gray-800);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre > code {
|
||||
color: var(--sl-color-gray-200);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.comment {
|
||||
color: var(--sl-color-gray-600);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.prolog,
|
||||
.sl-theme-dark .markdown-section pre .token.doctype,
|
||||
.sl-theme-dark .markdown-section pre .token.cdata,
|
||||
.sl-theme-dark .markdown-section pre .token.operator {
|
||||
color: var(--sl-color-gray-300);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.property,
|
||||
.sl-theme-dark .markdown-section pre .token.keyword,
|
||||
.sl-theme-dark .markdown-section pre .token.tag,
|
||||
.sl-theme-dark .markdown-section pre .token.url {
|
||||
color: var(--sl-color-primary-400);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.symbol,
|
||||
.sl-theme-dark .markdown-section pre .token.deleted {
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.boolean,
|
||||
.sl-theme-dark .markdown-section pre .token.constant,
|
||||
.sl-theme-dark .markdown-section pre .token.selector,
|
||||
.sl-theme-dark .markdown-section pre .token.attr-name,
|
||||
.sl-theme-dark .markdown-section pre .token.string,
|
||||
.sl-theme-dark .markdown-section pre .token.char,
|
||||
.sl-theme-dark .markdown-section pre .token.builtin,
|
||||
.sl-theme-dark .markdown-section pre .token.inserted {
|
||||
color: var(--sl-color-success-400);
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.atrule,
|
||||
.sl-theme-dark .markdown-section pre .token.attr-value,
|
||||
.sl-theme-dark .markdown-section pre .token.number,
|
||||
.sl-theme-dark .markdown-section pre .token.variable {
|
||||
color: #c380ff;
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.function,
|
||||
.sl-theme-dark .markdown-section pre .token.class-name {
|
||||
color: #ffbb4d;
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.regex {
|
||||
color: #f8bd5b;
|
||||
}
|
||||
|
||||
.sl-theme-dark .markdown-section pre .token.important {
|
||||
color: #fd495f;
|
||||
}
|
||||
|
||||
/* Repo buttons */
|
||||
.sl-theme-dark .repo-button {
|
||||
background-color: var(--sl-color-gray-900);
|
||||
border-color: var(--sl-color-gray-800);
|
||||
color: var(--sl-color-gray-200);
|
||||
}
|
||||
|
||||
.sl-theme-dark .repo-button--github sl-icon {
|
||||
color: var(--sl-color-white);
|
||||
}
|
||||
|
||||
.sl-theme-dark .repo-button:hover {
|
||||
background-color: var(--sl-color-gray-900);
|
||||
border: solid 1px var(--sl-color-gray-700);
|
||||
}
|
||||
|
||||
.sl-theme-dark .repo-button:focus {
|
||||
border-color: var(--sl-color-primary-500);
|
||||
}
|
||||
347
docs/assets/styles/search.css
Normal file
@@ -0,0 +1,347 @@
|
||||
/* Search plugin */
|
||||
:root,
|
||||
:root.sl-theme-dark {
|
||||
--docs-search-box-background: var(--sl-color-neutral-0);
|
||||
--docs-search-box-border-width: 1px;
|
||||
--docs-search-box-border-color: var(--sl-color-neutral-300);
|
||||
--docs-search-box-color: var(--sl-color-neutral-600);
|
||||
--docs-search-dialog-background: var(--sl-color-neutral-0);
|
||||
--docs-search-border-width: var(--docs-border-width);
|
||||
--docs-search-border-color: var(--docs-border-color);
|
||||
--docs-search-text-color: var(--sl-color-neutral-900);
|
||||
--docs-search-text-color-muted: var(--sl-color-neutral-500);
|
||||
--docs-search-font-weight-normal: var(--sl-font-weight-normal);
|
||||
--docs-search-font-weight-semibold: var(--sl-font-weight-semibold);
|
||||
--docs-search-border-radius: calc(2 * var(--docs-border-radius));
|
||||
--docs-search-accent-color: var(--sl-color-primary-600);
|
||||
--docs-search-icon-color: var(--sl-color-neutral-500);
|
||||
--docs-search-icon-color-active: var(--sl-color-neutral-600);
|
||||
--docs-search-shadow: var(--docs-shadow-x-large);
|
||||
--docs-search-result-background-hover: var(--sl-color-neutral-100);
|
||||
--docs-search-result-color-hover: var(--sl-color-neutral-900);
|
||||
--docs-search-result-background-active: var(--sl-color-primary-600);
|
||||
--docs-search-result-color-active: var(--sl-color-neutral-0);
|
||||
--docs-search-focus-ring: var(--sl-focus-ring);
|
||||
--docs-search-overlay-background: rgb(0 0 0 / 0.33);
|
||||
}
|
||||
|
||||
:root.sl-theme-dark {
|
||||
--docs-search-overlay-background: rgb(71 71 71 / 0.33);
|
||||
}
|
||||
|
||||
body.search-visible {
|
||||
padding-right: var(--docs-search-scroll-lock-size) !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* Search box */
|
||||
.search-box {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-radius: 9999px;
|
||||
background: var(--docs-search-box-background);
|
||||
border: solid var(--docs-search-box-border-width) var(--docs-search-box-border-color);
|
||||
font: inherit;
|
||||
color: var(--docs-search-box-color);
|
||||
padding: 0.75rem 1rem;
|
||||
margin: var(--sl-spacing-large) 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.search-box span {
|
||||
flex: 1 1 auto;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
text-align: left;
|
||||
line-height: 1;
|
||||
margin: 0 0.75rem;
|
||||
}
|
||||
|
||||
.search-box:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.search-box:focus-visible {
|
||||
outline: var(--docs-search-focus-ring);
|
||||
}
|
||||
|
||||
/* Site search */
|
||||
.search {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.search[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search__overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: var(--docs-search-overlay-background);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.search__dialog {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search__dialog:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.search__dialog::backdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Fixes an iOS Safari 16.4 bug that draws the parent element's border radius incorrectly when showing/hiding results */
|
||||
.search__header {
|
||||
background-color: var(--docs-search-dialog-background);
|
||||
border-radius: var(--docs-search-border-radius);
|
||||
}
|
||||
|
||||
.search--has-results .search__header {
|
||||
border-top-left-radius: var(--docs-search-border-radius);
|
||||
border-top-right-radius: var(--docs-search-border-radius);
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.search__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-height: calc(100vh - 20rem);
|
||||
background-color: var(--docs-search-dialog-background);
|
||||
border-radius: var(--docs-search-border-radius);
|
||||
box-shadow: var(--docs-search-shadow);
|
||||
padding: 0;
|
||||
margin: 10rem auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
.search__content {
|
||||
max-width: calc(100% - 2rem);
|
||||
max-height: calc(90svh);
|
||||
margin: 4vh 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.search__input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search__input-wrapper sl-icon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
flex: 0 0 auto;
|
||||
color: var(--docs-search-icon-color);
|
||||
margin: 0 1.5rem;
|
||||
}
|
||||
|
||||
.search__clear-button {
|
||||
display: flex;
|
||||
background: none;
|
||||
border: none;
|
||||
font: inherit;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.search__clear-button[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search__clear-button:active sl-icon {
|
||||
color: var(--docs-search-icon-color-active);
|
||||
}
|
||||
|
||||
.search__input {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
font: inherit;
|
||||
font-size: 1.5rem;
|
||||
font-weight: var(--docs-search-font-weight-normal);
|
||||
color: var(--docs-search-text-color);
|
||||
background: transparent;
|
||||
padding: 1rem 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search__input::placeholder {
|
||||
color: var(--docs-search-text-color-muted);
|
||||
}
|
||||
|
||||
.search__input::-webkit-search-decoration,
|
||||
.search__input::-webkit-search-cancel-button,
|
||||
.search__input::-webkit-search-results-button,
|
||||
.search__input::-webkit-search-results-decoration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search__input:focus,
|
||||
.search__input:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.search__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.search--has-results .search__body {
|
||||
border-top: solid var(--docs-search-border-width) var(--docs-search-border-color);
|
||||
}
|
||||
|
||||
.search__results {
|
||||
display: none;
|
||||
line-height: 1.2;
|
||||
list-style: none;
|
||||
padding: 0.5rem 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search--has-results .search__results {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search__results a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 0.5rem 1.5rem;
|
||||
}
|
||||
|
||||
.search__results a:focus-visible {
|
||||
outline: var(--docs-search-focus-ring);
|
||||
}
|
||||
|
||||
.search__results li a:hover,
|
||||
.search__results li a:hover small {
|
||||
background-color: var(--docs-search-result-background-hover);
|
||||
color: var(--docs-search-result-color-hover);
|
||||
}
|
||||
|
||||
.search__results li[data-selected='true'] a,
|
||||
.search__results li[data-selected='true'] a * {
|
||||
outline: none;
|
||||
background-color: var(--docs-search-result-background-active);
|
||||
color: var(--docs-search-result-color-active);
|
||||
}
|
||||
|
||||
.search__results h3 {
|
||||
font-weight: var(--docs-search-font-weight-semibold);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search__results small {
|
||||
display: block;
|
||||
color: var(--docs-search-text-color-muted);
|
||||
}
|
||||
|
||||
.search__result {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search__result a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.search__result-icon {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
color: var(--docs-search-text-color-muted);
|
||||
}
|
||||
|
||||
.search__result-icon sl-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.search__result__details {
|
||||
width: calc(100% - 3rem);
|
||||
}
|
||||
|
||||
.search__result-title,
|
||||
.search__result-description,
|
||||
.search__result-url {
|
||||
max-width: 400px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.search__result-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: var(--docs-search-font-weight-semibold);
|
||||
color: var(--docs-search-accent-color);
|
||||
}
|
||||
|
||||
.search__result-description {
|
||||
font-size: 0.875rem;
|
||||
color: var(--docs-search-text-color);
|
||||
}
|
||||
|
||||
.search__result-url {
|
||||
font-size: 0.875rem;
|
||||
color: var(--docs-search-text-color-muted);
|
||||
}
|
||||
|
||||
.search__empty {
|
||||
display: none;
|
||||
border-top: solid var(--docs-search-border-width) var(--docs-search-border-color);
|
||||
text-align: center;
|
||||
color: var(--docs-search-text-color-muted);
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.search--no-results .search__empty {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search__footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 2rem;
|
||||
border-top: solid var(--docs-search-border-width) var(--docs-search-border-color);
|
||||
border-bottom-left-radius: inherit;
|
||||
border-bottom-right-radius: inherit;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.search__footer small {
|
||||
color: var(--docs-search-text-color-muted);
|
||||
}
|
||||
|
||||
.search__footer small kbd:last-of-type {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
.search__footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
# Alert
|
||||
|
||||
[component-header:sl-alert]
|
||||
|
||||
Alerts are used to display important messages either inline or as toast notifications.
|
||||
|
||||
```html preview
|
||||
<sl-alert open>
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
This is a standard alert. You can customize its content and even the icon.
|
||||
</sl-alert>
|
||||
```
|
||||
|
||||
?> Alerts will not be visible if the `open` attribute is not present.
|
||||
|
||||
## Examples
|
||||
|
||||
### Types
|
||||
|
||||
Set the `type` attribute to change the alert's type.
|
||||
|
||||
```html preview
|
||||
<sl-alert type="primary" open>
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
<strong>This is super informative</strong><br>
|
||||
You can tell by how pretty the alert is.
|
||||
</sl-alert>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-alert type="success" open>
|
||||
<sl-icon slot="icon" name="check2-circle"></sl-icon>
|
||||
<strong>Your changes have been saved</strong><br>
|
||||
You can safely exit the app now.
|
||||
</sl-alert>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-alert type="info" open>
|
||||
<sl-icon slot="icon" name="gear"></sl-icon>
|
||||
<strong>Your settings have been updated</strong><br>
|
||||
Settings will take affect on next login.
|
||||
</sl-alert>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-alert type="warning" open>
|
||||
<sl-icon slot="icon" name="exclamation-triangle"></sl-icon>
|
||||
<strong>Your session has ended</strong><br>
|
||||
Please login again to continue.
|
||||
</sl-alert>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-alert type="danger" open>
|
||||
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||
<strong>Your account has been deleted</strong><br>
|
||||
We're very sorry to see you go!
|
||||
</sl-alert>
|
||||
```
|
||||
|
||||
### Closable
|
||||
|
||||
Add the `closable` attribute to show a close button that will hide the alert.
|
||||
|
||||
```html preview
|
||||
<sl-alert type="primary" open closable class="alert-closable">
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
You can close this alert any time!
|
||||
</sl-alert>
|
||||
|
||||
<script>
|
||||
const alert = document.querySelector('.alert-closable');
|
||||
alert.addEventListener('sl-after-hide', () => {
|
||||
setTimeout(() => alert.open = true, 2000);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Without Icons
|
||||
|
||||
Icons are optional. Simply omit the `icon` slot if you don't want them.
|
||||
|
||||
```html preview
|
||||
<sl-alert type="primary" open>
|
||||
Nothing fancy here, just a simple alert.
|
||||
</sl-alert>
|
||||
```
|
||||
|
||||
### Duration
|
||||
|
||||
Set the `duration` prop to automatically hide an alert after a period of time. This is useful for alerts that don't require acknowledgement.
|
||||
|
||||
```html preview
|
||||
<div class="alert-duration">
|
||||
<sl-button type="primary">Show Alert</sl-button>
|
||||
|
||||
<sl-alert type="primary" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
This alert will automatically hide itself after three seconds, unless you interact with it.
|
||||
</sl-alert>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.alert-duration');
|
||||
const button = container.querySelector('sl-button');
|
||||
const alert = container.querySelector('sl-alert');
|
||||
|
||||
button.addEventListener('click', () => alert.show());
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.alert-duration sl-alert {
|
||||
margin-top: var(--sl-spacing-medium);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Toast Notifications
|
||||
|
||||
To display an alert as a toast notification, or "toast", create the alert and call its `toast()` method. This will move the alert out of its position in the DOM and into [the toast stack](#the-toast-stack) where it will be shown. Once dismissed, it will be removed from the DOM completely. To reuse a toast, store a reference to it and call `toast()` again later on.
|
||||
|
||||
You should always use the `closable` prop so users can dismiss the notification. It's also common to set a reasonable `duration` when the notification doesn't require acknowledgement.
|
||||
|
||||
```html preview
|
||||
<div class="alert-toast">
|
||||
<sl-button type="primary">Primary</sl-button>
|
||||
<sl-button type="success">Success</sl-button>
|
||||
<sl-button type="info">Info</sl-button>
|
||||
<sl-button type="warning">Warning</sl-button>
|
||||
<sl-button type="danger">Danger</sl-button>
|
||||
|
||||
<sl-alert type="primary" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
<strong>This is super informative</strong><br>
|
||||
You can tell by how pretty the alert is.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="success" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="check2-circle"></sl-icon>
|
||||
<strong>Your changes have been saved</strong><br>
|
||||
You can safely exit the app now.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="info" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="gear"></sl-icon>
|
||||
<strong>Your settings have been updated</strong><br>
|
||||
Settings will take affect on next login.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="warning" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="exclamation-triangle"></sl-icon>
|
||||
<strong>Your session has ended</strong><br>
|
||||
Please login again to continue.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="danger" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||
<strong>Your account has been deleted</strong><br>
|
||||
We're very sorry to see you go!
|
||||
</sl-alert>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.alert-toast');
|
||||
|
||||
['primary', 'success', 'info', 'warning', 'danger'].map(type => {
|
||||
const button = container.querySelector(`sl-button[type="${type}"]`);
|
||||
const alert = container.querySelector(`sl-alert[type="${type}"]`);
|
||||
|
||||
button.addEventListener('click', () => alert.toast());
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Creating Toasts Imperatively
|
||||
|
||||
For convenience, you can create a utility that emits toast notifications with a function call rather than composing them in your HTML. To do this, generate the alert with JavaScript, append it to the body, and call the `toast()` method as shown in the example below.
|
||||
|
||||
```html preview
|
||||
<div class="alert-toast-wrapper">
|
||||
<sl-button type="primary">Create Toast</sl-button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.alert-toast-wrapper');
|
||||
const button = container.querySelector('sl-button');
|
||||
let count = 0;
|
||||
|
||||
// Always escape HTML for text arguments!
|
||||
function escapeHtml(html) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = html;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// Custom function to emit toast notifications
|
||||
function notify(message, type = 'primary', icon = 'info-circle', duration = 3000) {
|
||||
const alert = Object.assign(document.createElement('sl-alert'), {
|
||||
type: type,
|
||||
closable: true,
|
||||
duration: duration,
|
||||
innerHTML: `
|
||||
<sl-icon name="${icon}" slot="icon"></sl-icon>
|
||||
${escapeHtml(message)}
|
||||
`
|
||||
});
|
||||
|
||||
document.body.append(alert);
|
||||
return alert.toast();
|
||||
}
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
notify(`This is custom toast #${++count}`);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### The Toast Stack
|
||||
|
||||
The toast stack is a fixed position singleton element created and managed internally by the alert component. It will be added and removed from the DOM as needed when toasts are shown. When more than one toast is visible, they will stack vertically in the toast stack.
|
||||
|
||||
By default, the toast stack is positioned at the top-right of the viewport. You can change its position by targeting `.sl-toast-stack` in your stylesheet. To make toasts appear at the top-left of the viewport, for example, use the following styles.
|
||||
|
||||
```css
|
||||
.sl-toast-stack {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
```
|
||||
|
||||
?> By design, it is not possible to show toasts in more than one stack simultaneously. Such behavior is confusing and makes for a poor user experience.
|
||||
|
||||
[component-metadata:sl-alert]
|
||||
@@ -1,178 +0,0 @@
|
||||
# Animation
|
||||
|
||||
[component-header:sl-animation]
|
||||
|
||||
Animate elements declaratively with nearly 100 baked-in presets, or roll your own with custom keyframes. Powered by the [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API).
|
||||
|
||||
To animate an element, wrap it in `<sl-animation>` and set a `name` and `duration`. Refer to the [properties table](#properties) for additional options.
|
||||
|
||||
```html preview
|
||||
<div class="animation-overview">
|
||||
<sl-animation name="bounce" duration="2000"><div class="box"></div></sl-animation>
|
||||
<sl-animation name="jello" duration="2000"><div class="box"></div></sl-animation>
|
||||
<sl-animation name="heartBeat" duration="2000"><div class="box"></div></sl-animation>
|
||||
<sl-animation name="flip" duration="2000"><div class="box"></div></sl-animation>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.animation-overview .box {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: var(--sl-color-primary-500);
|
||||
margin: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
?> The animation will be applied only to the first child element found in `<sl-animation>`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Animations & Easings
|
||||
|
||||
This example demonstrates all of the baked-in animations and easings. Animations are based on those found in the popular [Animate.css](https://animate.style/) library.
|
||||
|
||||
```html preview
|
||||
<div class="animation-sandbox">
|
||||
<sl-animation name="bounce" easing="ease-in-out" duration="2000">
|
||||
<div class="box"></div>
|
||||
</sl-animation>
|
||||
|
||||
<div class="controls">
|
||||
<sl-select label="Animation" value="bounce"></sl-select>
|
||||
<sl-select label="Easing" value="linear"></sl-select>
|
||||
<sl-range min="0" max="2" step=".5" value="1"></sl-range>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import { getAnimationNames, getEasingNames } from '/dist/shoelace.js';
|
||||
|
||||
const container = document.querySelector('.animation-sandbox');
|
||||
const animation = container.querySelector('sl-animation');
|
||||
const animationName = container.querySelector('.controls sl-select:nth-child(1)');
|
||||
const easingName = container.querySelector('.controls sl-select:nth-child(2)');
|
||||
const playbackRate = container.querySelector('sl-range');
|
||||
const animations = getAnimationNames();
|
||||
const easings = getEasingNames();
|
||||
|
||||
animations.map(name => {
|
||||
const menuItem = Object.assign(document.createElement('sl-menu-item'), {
|
||||
textContent: name,
|
||||
value: name
|
||||
});
|
||||
animationName.appendChild(menuItem);
|
||||
});
|
||||
|
||||
easings.map(name => {
|
||||
const menuItem = Object.assign(document.createElement('sl-menu-item'), {
|
||||
textContent: name,
|
||||
value: name
|
||||
});
|
||||
easingName.appendChild(menuItem);
|
||||
});
|
||||
|
||||
animationName.addEventListener('sl-change', () => animation.name = animationName.value);
|
||||
easingName.addEventListener('sl-change', () => animation.easing = easingName.value);
|
||||
playbackRate.addEventListener('sl-change', () => animation.playbackRate = playbackRate.value);
|
||||
playbackRate.tooltipFormatter = val => `Playback Rate = ${val}`;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.animation-sandbox .box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: var(--sl-color-primary-500);
|
||||
}
|
||||
|
||||
.animation-sandbox .controls {
|
||||
max-width: 300px;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.animation-sandbox .controls sl-select {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Using Intersection Observer
|
||||
|
||||
Use an [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to control the animation when an element enters or exits the viewport. For example, scroll the box below in and out of your screen. The animation stops when the box exits the viewport and restarts each time it enters the viewport.
|
||||
|
||||
```html preview
|
||||
<div class="animation-scroll">
|
||||
<sl-animation name="jackInTheBox" duration="2000" iterations="1"><div class="box"></div></sl-animation>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.animation-scroll');
|
||||
const animation = container.querySelector('sl-animation');
|
||||
const box = animation.querySelector('.box');
|
||||
|
||||
// Watch for the box to enter and exit the viewport. Note that we're observing the box, not the animation element!
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
if (entries[0].isIntersecting) {
|
||||
// Start the animation when the box enters the viewport
|
||||
animation.pause = null;
|
||||
} else {
|
||||
// Reset the animation when the box leaves the viewport
|
||||
animation.pause = true;
|
||||
animation.setCurrentTime(0);
|
||||
}
|
||||
});
|
||||
observer.observe(box);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.animation-scroll .box {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: var(--sl-color-primary-500);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Custom Keyframe Formats
|
||||
|
||||
Supply your own [keyframe formats](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Keyframe_Formats) to build custom animations.
|
||||
|
||||
```html preview
|
||||
<div class="animation-keyframes">
|
||||
<sl-animation easing="ease-in-out" duration="2000">
|
||||
<div class="box"></div>
|
||||
</sl-animation>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const animation = document.querySelector('.animation-keyframes sl-animation');
|
||||
animation.keyframes = [
|
||||
{
|
||||
offset: 0,
|
||||
easing: 'cubic-bezier(0.250, 0.460, 0.450, 0.940)',
|
||||
fillMode: 'both',
|
||||
transformOrigin: 'center center',
|
||||
transform: 'rotate(0)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
easing: 'cubic-bezier(0.250, 0.460, 0.450, 0.940)',
|
||||
fillMode: 'both',
|
||||
transformOrigin: 'center center',
|
||||
transform: 'rotate(90deg)'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.animation-keyframes .box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: var(--sl-color-primary-500);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-animation]
|
||||
@@ -1,86 +0,0 @@
|
||||
# Avatar
|
||||
|
||||
[component-header:sl-avatar]
|
||||
|
||||
Avatars are used to represent a person or object.
|
||||
|
||||
```html preview
|
||||
<sl-avatar></sl-avatar>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Images
|
||||
|
||||
To use an image for the avatar, set the `image` and `alt` attributes. This will take priority and be shown over initials and icons.
|
||||
|
||||
```html preview
|
||||
<sl-avatar
|
||||
image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"
|
||||
alt="Gray tabby kitten looking down"
|
||||
></sl-avatar>
|
||||
```
|
||||
|
||||
### Initials
|
||||
|
||||
When you don't have an image to use, you can set the `initials` attribute to show something more personalized than an icon.
|
||||
|
||||
```html preview
|
||||
<sl-avatar initials="SL"></sl-avatar>
|
||||
```
|
||||
|
||||
### Custom Icons
|
||||
|
||||
When no image or initials are set, an icon will be shown. The default avatar shows a generic "user" icon, but you can customize this with the `icon` slot.
|
||||
|
||||
```html preview
|
||||
<sl-avatar>
|
||||
<sl-icon slot="icon" name="image"></sl-icon>
|
||||
</sl-avatar>
|
||||
|
||||
<sl-avatar>
|
||||
<sl-icon slot="icon" name="archive"></sl-icon>
|
||||
</sl-avatar>
|
||||
|
||||
<sl-avatar>
|
||||
<sl-icon slot="icon" name="briefcase"></sl-icon>
|
||||
</sl-avatar>
|
||||
```
|
||||
|
||||
### Shapes
|
||||
|
||||
Avatars can be shaped using the `shape` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-avatar shape="square"></sl-avatar>
|
||||
|
||||
<sl-avatar shape="rounded"></sl-avatar>
|
||||
|
||||
<sl-avatar shape="circle"></sl-avatar>
|
||||
```
|
||||
|
||||
|
||||
### Avatar Groups
|
||||
|
||||
You can group avatars with a few lines of CSS.
|
||||
|
||||
```html preview
|
||||
<div class="avatar-group">
|
||||
<sl-avatar image="https://images.unsplash.com/photo-1490150028299-bf57d78394e0?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=256&h=256&q=80&crop=right"></sl-avatar>
|
||||
<sl-avatar image="https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=256&h=256&crop=left&q=80"></sl-avatar>
|
||||
<sl-avatar image="https://images.unsplash.com/photo-1456439663599-95b042d50252?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=256&h=256&crop=left&q=80"></sl-avatar>
|
||||
<sl-avatar image="https://images.unsplash.com/flagged/photo-1554078875-e37cb8b0e27d?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=256&h=256&crop=top&q=80"></sl-avatar>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatar-group sl-avatar:not(:first-of-type) {
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
.avatar-group sl-avatar::part(base) {
|
||||
border: solid 2px white;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-avatar]
|
||||
@@ -1,90 +0,0 @@
|
||||
# Badge
|
||||
|
||||
[component-header:sl-badge]
|
||||
|
||||
Badges are used to draw attention and display statuses or counts.
|
||||
|
||||
```html preview
|
||||
<sl-badge>Badge</sl-badge>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Types
|
||||
|
||||
Set the `type` attribute to change the badge's type.
|
||||
|
||||
```html preview
|
||||
<sl-badge type="primary">Primary</sl-badge>
|
||||
<sl-badge type="success">Success</sl-badge>
|
||||
<sl-badge type="info">Info</sl-badge>
|
||||
<sl-badge type="warning">Warning</sl-badge>
|
||||
<sl-badge type="danger">Danger</sl-badge>
|
||||
```
|
||||
|
||||
### Pill Badges
|
||||
|
||||
Use the `pill` attribute to give badges rounded edges.
|
||||
|
||||
```html preview
|
||||
<sl-badge type="primary" pill>Primary</sl-badge>
|
||||
<sl-badge type="success" pill>Success</sl-badge>
|
||||
<sl-badge type="info" pill>Info</sl-badge>
|
||||
<sl-badge type="warning" pill>Warning</sl-badge>
|
||||
<sl-badge type="danger" pill>Danger</sl-badge>
|
||||
```
|
||||
|
||||
### Pulsating Badges
|
||||
|
||||
Use the `pulse` attribute to draw attention to the badge with a subtle animation.
|
||||
|
||||
```html preview
|
||||
<div class="badge-pulse">
|
||||
<sl-badge type="primary" pill pulse>1</sl-badge>
|
||||
<sl-badge type="success" pill pulse>1</sl-badge>
|
||||
<sl-badge type="info" pill pulse>1</sl-badge>
|
||||
<sl-badge type="warning" pill pulse>1</sl-badge>
|
||||
<sl-badge type="danger" pill pulse>1</sl-badge>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.badge-pulse sl-badge:not(:last-of-type) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### With Buttons
|
||||
|
||||
One of the most common use cases for badges is attaching them to buttons. To make this easier, badges will be automatically positioned at the top-right when they're a child of a button.
|
||||
|
||||
```html preview
|
||||
<sl-button>
|
||||
Requests
|
||||
<sl-badge pill>30</sl-badge>
|
||||
</sl-button>
|
||||
|
||||
<sl-button style="margin-left: 1rem;">
|
||||
Warnings
|
||||
<sl-badge type="warning" pill>8</sl-badge>
|
||||
</sl-button>
|
||||
|
||||
<sl-button style="margin-left: 1rem;">
|
||||
Errors
|
||||
<sl-badge type="danger" pill>6</sl-badge>
|
||||
</sl-button>
|
||||
```
|
||||
|
||||
### With Menu Items
|
||||
|
||||
When including badges in menu items, use the `suffix` slot to make sure they're aligned correctly.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 240px; border: solid 1px var(--sl-panel-border-color); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-label>Messages</sl-menu-label>
|
||||
<sl-menu-item>Comments <sl-badge slot="suffix" type="info" pill>4</sl-badge></sl-menu-item>
|
||||
<sl-menu-item>Replies <sl-badge slot="suffix" type="info" pill>12</sl-badge></sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
[component-metadata:sl-badge]
|
||||
@@ -1,221 +0,0 @@
|
||||
# Button Group
|
||||
|
||||
[component-header:sl-button-group]
|
||||
|
||||
Button groups can be used to group related buttons into sections.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-button>Left</sl-button>
|
||||
<sl-button>Center</sl-button>
|
||||
<sl-button>Right</sl-button>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Button Sizes
|
||||
|
||||
All button sizes are supported, but avoid mixing sizes within the same button group.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-button size="small">Left</sl-button>
|
||||
<sl-button size="small">Center</sl-button>
|
||||
<sl-button size="small">Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button size="medium">Left</sl-button>
|
||||
<sl-button size="medium">Center</sl-button>
|
||||
<sl-button size="medium">Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button size="large">Left</sl-button>
|
||||
<sl-button size="large">Center</sl-button>
|
||||
<sl-button size="large">Right</sl-button>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
### Theme Buttons
|
||||
|
||||
Theme buttons are supported through the button's `type` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-button type="primary">Left</sl-button>
|
||||
<sl-button type="primary">Center</sl-button>
|
||||
<sl-button type="primary">Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button type="success">Left</sl-button>
|
||||
<sl-button type="success">Center</sl-button>
|
||||
<sl-button type="success">Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button type="info">Left</sl-button>
|
||||
<sl-button type="info">Center</sl-button>
|
||||
<sl-button type="info">Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button type="warning">Left</sl-button>
|
||||
<sl-button type="warning">Center</sl-button>
|
||||
<sl-button type="warning">Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button type="danger">Left</sl-button>
|
||||
<sl-button type="danger">Center</sl-button>
|
||||
<sl-button type="danger">Right</sl-button>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
### Pill Buttons
|
||||
|
||||
Pill buttons are supported through the button's `pill` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-button size="small" pill>Left</sl-button>
|
||||
<sl-button size="small" pill>Center</sl-button>
|
||||
<sl-button size="small" pill>Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button size="medium" pill>Left</sl-button>
|
||||
<sl-button size="medium" pill>Center</sl-button>
|
||||
<sl-button size="medium" pill>Right</sl-button>
|
||||
</sl-button-group>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button-group>
|
||||
<sl-button size="large" pill>Left</sl-button>
|
||||
<sl-button size="large" pill>Center</sl-button>
|
||||
<sl-button size="large" pill>Right</sl-button>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
### Dropdowns in Button Groups
|
||||
|
||||
Dropdowns can be placed inside button groups as long as the trigger is a `<sl-button>` element.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-button>Button</sl-button>
|
||||
<sl-button>Button</sl-button>
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Dropdown</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Item 1</sl-menu-item>
|
||||
<sl-menu-item>Item 2</sl-menu-item>
|
||||
<sl-menu-item>Item 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
### Split Buttons
|
||||
|
||||
Create a split button using a button and a dropdown.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-button type="primary">Save</sl-button>
|
||||
<sl-dropdown placement="bottom-end">
|
||||
<sl-button slot="trigger" type="primary" caret></sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Save</sl-menu-item>
|
||||
<sl-menu-item>Save as…</sl-menu-item>
|
||||
<sl-menu-item>Save all</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
### Tooltips in Button Groups
|
||||
|
||||
Buttons can be wrapped in tooltips to provide more detail when the user interacts with them.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
<sl-tooltip content="I'm on the left">
|
||||
<sl-button>Left</sl-button>
|
||||
</sl-tooltip>
|
||||
|
||||
<sl-tooltip content="I'm in the middle">
|
||||
<sl-button>Center</sl-button>
|
||||
</sl-tooltip>
|
||||
|
||||
<sl-tooltip content="I'm on the right">
|
||||
<sl-button>Right</sl-button>
|
||||
</sl-tooltip>
|
||||
</sl-button-group>
|
||||
```
|
||||
|
||||
### Toolbar Example
|
||||
|
||||
Create interactive toolbars with button groups.
|
||||
|
||||
```html preview
|
||||
<div class="button-group-toolbar">
|
||||
<sl-button-group label="History">
|
||||
<sl-tooltip content="Undo">
|
||||
<sl-button><sl-icon name="arrow-counterclockwise"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
<sl-tooltip content="Redo">
|
||||
<sl-button><sl-icon name="arrow-clockwise"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
</sl-button-group>
|
||||
|
||||
<sl-button-group label="Formatting">
|
||||
<sl-tooltip content="Bold">
|
||||
<sl-button><sl-icon name="type-bold"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
<sl-tooltip content="Italic">
|
||||
<sl-button><sl-icon name="type-italic"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
<sl-tooltip content="Underline">
|
||||
<sl-button><sl-icon name="type-underline"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
</sl-button-group>
|
||||
|
||||
<sl-button-group label="Alignment">
|
||||
<sl-tooltip content="Align Left">
|
||||
<sl-button><sl-icon name="justify-left"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
<sl-tooltip content="Align Center">
|
||||
<sl-button><sl-icon name="justify"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
<sl-tooltip content="Align Right">
|
||||
<sl-button><sl-icon name="justify-right"></sl-icon></sl-button>
|
||||
</sl-tooltip>
|
||||
</sl-button-group>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.button-group-toolbar sl-button-group:not(:last-of-type) {
|
||||
margin-right: var(--sl-spacing-x-small);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-button-group]
|
||||
@@ -1,227 +0,0 @@
|
||||
# Button
|
||||
|
||||
[component-header:sl-button]
|
||||
|
||||
Buttons represent actions that are available to the user.
|
||||
|
||||
```html preview
|
||||
<sl-button>Button</sl-button>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Types
|
||||
|
||||
Use the `type` attribute to set the button's type.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default">Default</sl-button>
|
||||
<sl-button type="primary">Primary</sl-button>
|
||||
<sl-button type="success">Success</sl-button>
|
||||
<sl-button type="info">Info</sl-button>
|
||||
<sl-button type="warning">Warning</sl-button>
|
||||
<sl-button type="danger">Danger</sl-button>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the `size` prop to change a button's size.
|
||||
|
||||
```html preview
|
||||
<sl-button size="small">Small</sl-button>
|
||||
<sl-button size="medium">Medium</sl-button>
|
||||
<sl-button size="large">Large</sl-button>
|
||||
```
|
||||
|
||||
### Pill Buttons
|
||||
|
||||
Use the `pill` prop to give buttons rounded edges.
|
||||
|
||||
```html preview
|
||||
<sl-button size="small" pill>Small</sl-button>
|
||||
<sl-button size="medium" pill>Medium</sl-button>
|
||||
<sl-button size="large" pill>Large</sl-button>
|
||||
```
|
||||
|
||||
### Circle Buttons
|
||||
|
||||
Use the `circle` prop to create circular icon buttons.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default" size="small" circle><sl-icon name="gear"></sl-icon></sl-button>
|
||||
<sl-button type="default" size="medium" circle><sl-icon name="gear"></sl-icon></sl-button>
|
||||
<sl-button type="default" size="large" circle><sl-icon name="gear"></sl-icon></sl-button>
|
||||
```
|
||||
|
||||
### Text Buttons
|
||||
|
||||
Use the `text` type to create text buttons that share the same size as regular buttons but don't have backgrounds or borders.
|
||||
|
||||
```html preview
|
||||
<sl-button type="text" size="small">Text</sl-button>
|
||||
<sl-button type="text" size="medium">Text</sl-button>
|
||||
<sl-button type="text" size="large">Text</sl-button>
|
||||
```
|
||||
|
||||
### Link Buttons
|
||||
|
||||
It's often helpful to have a button that works like a link. This is possible by setting the `href` attribute, which will make the component render an `<a>` under the hood. This gives you all the default link behavior the browser provides (e.g. <kbd>CMD/CTRL/SHIFT + CLICK</kbd>) and exposes the `target` and `download` attributes.
|
||||
|
||||
```html preview
|
||||
<sl-button href="https://example.com/">Link</sl-button>
|
||||
<sl-button href="https://example.com/" target="_blank">New Window</sl-button>
|
||||
<sl-button href="/assets/images/wordmark.svg" download="shoelace.svg">Download</sl-button>
|
||||
<sl-button href="https://example.com/" disabled>Disabled</sl-button>
|
||||
```
|
||||
|
||||
?> When a `target` is set, the link will receive `rel="noreferrer noopener"` for [security reasons](https://mathiasbynens.github.io/rel-noopener/).
|
||||
|
||||
### Setting a Custom Width
|
||||
|
||||
As expected, buttons can be given a custom width by setting its `width`. This is useful for making buttons span the full width of their container on smaller screens.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default" size="small" style="width: 100%; margin-bottom: 1rem;">Small</sl-button>
|
||||
<sl-button type="default" size="medium" style="width: 100%; margin-bottom: 1rem;">Medium</sl-button>
|
||||
<sl-button type="default" size="large" style="width: 100%;">Large</sl-button>
|
||||
```
|
||||
|
||||
### Prefix and Suffix Icons
|
||||
|
||||
Use the `prefix` and `suffix` slots to add icons.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default" size="small">
|
||||
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||
Settings
|
||||
</sl-button>
|
||||
|
||||
<sl-button type="default" size="small">
|
||||
<sl-icon slot="suffix" name="arrow-counterclockwise"></sl-icon>
|
||||
Refresh
|
||||
</sl-button>
|
||||
|
||||
<sl-button type="default" size="small">
|
||||
<sl-icon slot="prefix" name="link-45deg"></sl-icon>
|
||||
<sl-icon slot="suffix" name="box-arrow-up-right"></sl-icon>
|
||||
Open
|
||||
</sl-button>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button type="default">
|
||||
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||
Settings
|
||||
</sl-button>
|
||||
|
||||
<sl-button type="default">
|
||||
<sl-icon slot="suffix" name="arrow-counterclockwise"></sl-icon>
|
||||
Refresh
|
||||
</sl-button>
|
||||
|
||||
<sl-button type="default">
|
||||
<sl-icon slot="prefix" name="link-45deg"></sl-icon>
|
||||
<sl-icon slot="suffix" name="box-arrow-up-right"></sl-icon>
|
||||
Open
|
||||
</sl-button>
|
||||
|
||||
<br><br>
|
||||
|
||||
<sl-button type="default" size="large">
|
||||
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||
Settings
|
||||
</sl-button>
|
||||
|
||||
<sl-button type="default" size="large">
|
||||
<sl-icon slot="suffix" name="arrow-counterclockwise"></sl-icon>
|
||||
Refresh
|
||||
</sl-button>
|
||||
|
||||
<sl-button type="default" size="large">
|
||||
<sl-icon slot="prefix" name="link-45deg"></sl-icon>
|
||||
<sl-icon slot="suffix" name="box-arrow-up-right"></sl-icon>
|
||||
Open
|
||||
</sl-button>
|
||||
```
|
||||
|
||||
### Caret
|
||||
|
||||
Use the `caret` prop to add a dropdown indicator when a button will trigger a dropdown, menu, or popover.
|
||||
|
||||
```html preview
|
||||
<sl-button size="small" caret>Small</sl-button>
|
||||
<sl-button size="medium" caret>Medium</sl-button>
|
||||
<sl-button size="large" caret>Large</sl-button>
|
||||
```
|
||||
|
||||
### Loading
|
||||
|
||||
Use the `loading` prop to make a button busy. The width will remain the same as before, preventing adjacent elements from moving around. Clicks will be suppressed until the loading state is removed.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default" loading>Default</sl-button>
|
||||
<sl-button type="primary" loading>Primary</sl-button>
|
||||
<sl-button type="success" loading>Success</sl-button>
|
||||
<sl-button type="info" loading>Info</sl-button>
|
||||
<sl-button type="warning" loading>Warning</sl-button>
|
||||
<sl-button type="danger" loading>Danger</sl-button>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` prop to disable a button. Clicks will be suppressed until the disabled state is removed.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default" disabled>Default</sl-button>
|
||||
<sl-button type="primary" disabled>Primary</sl-button>
|
||||
<sl-button type="success" disabled>Success</sl-button>
|
||||
<sl-button type="info" disabled>Info</sl-button>
|
||||
<sl-button type="warning" disabled>Warning</sl-button>
|
||||
<sl-button type="danger" disabled>Danger</sl-button>
|
||||
```
|
||||
|
||||
### Styling Buttons
|
||||
|
||||
This example demonstrates how to style buttons using a custom class. This is the recommended approach if you need to add additional variations. To customize an existing variation, modify the selector to target the button's type attribute instead of a class (e.g. `sl-button[type="primary"]`).
|
||||
|
||||
```html preview
|
||||
<sl-button class="pink">Pink Button</sl-button>
|
||||
|
||||
<style>
|
||||
sl-button.pink::part(base) {
|
||||
/* Set design tokens for height and border width */
|
||||
--sl-input-height-medium: 48px;
|
||||
--sl-input-border-width: 4px;
|
||||
|
||||
border-radius: 0;
|
||||
background-color: #ff1493;
|
||||
border-top-color: #ff7ac1;
|
||||
border-left-color: #ff7ac1;
|
||||
border-bottom-color: #ad005c;
|
||||
border-right-color: #ad005c;
|
||||
color: white;
|
||||
font-size: 1.125rem;
|
||||
box-shadow: 0 2px 10px #0002;
|
||||
transition: var(--sl-transition-medium) transform ease, var(--sl-transition-medium) border ease;
|
||||
}
|
||||
|
||||
sl-button.pink::part(base):hover {
|
||||
transform: scale(1.05) rotate(-1deg);
|
||||
}
|
||||
|
||||
sl-button.pink::part(base):active {
|
||||
border-top-color: #ad005c;
|
||||
border-right-color: #ff7ac1;
|
||||
border-bottom-color: #ff7ac1;
|
||||
border-left-color: #ad005c;
|
||||
transform: scale(1.05) rotate(-1deg) translateY(2px);
|
||||
}
|
||||
|
||||
sl-button.pink::part(base):focus-visible {
|
||||
outline: dashed 2px deeppink;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-button]
|
||||
@@ -1,144 +0,0 @@
|
||||
# Card
|
||||
|
||||
[component-header:sl-card]
|
||||
|
||||
Cards can be used to group related subjects in a container.
|
||||
|
||||
```html preview
|
||||
<sl-card 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">
|
||||
<sl-button type="primary" pill>More Info</sl-button>
|
||||
<sl-rating></sl-rating>
|
||||
</div>
|
||||
</sl-card>
|
||||
|
||||
<style>
|
||||
.card-overview {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.card-overview small {
|
||||
color: var(--sl-color-gray-500);
|
||||
}
|
||||
|
||||
.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 preview
|
||||
<sl-card class="card-basic">
|
||||
This is just a basic card. No image, no header, and no footer. Just your content.
|
||||
</sl-card>
|
||||
|
||||
<style>
|
||||
.card-basic {
|
||||
max-width: 300px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## Card with Header
|
||||
|
||||
Headers can be used to display titles and more.
|
||||
|
||||
```html preview
|
||||
<sl-card class="card-header">
|
||||
<div slot="header">
|
||||
Header Title
|
||||
|
||||
<sl-icon-button name="gear"></sl-icon-button>
|
||||
</div>
|
||||
|
||||
This card has a header. You can put all sorts of things in it!
|
||||
</sl-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 sl-icon-button {
|
||||
font-size: var(--sl-font-size-medium);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## Card with Footer
|
||||
|
||||
Footers can be used to display actions, summaries, or other relevant content.
|
||||
|
||||
```html preview
|
||||
<sl-card class="card-footer">
|
||||
This card has a footer. You can put all sorts of things in it!
|
||||
|
||||
<div slot="footer">
|
||||
<sl-rating></sl-rating>
|
||||
<sl-button slot="footer" type="primary">Preview</sl-button>
|
||||
</div>
|
||||
</sl-card>
|
||||
|
||||
<style>
|
||||
.card-footer {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.card-footer [slot="footer"] {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## Images
|
||||
|
||||
Cards accept an `image` slot. The image is displayed atop the card and stretches to fit.
|
||||
|
||||
```html preview
|
||||
<sl-card 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.
|
||||
</sl-card>
|
||||
|
||||
<style>
|
||||
.card-image {
|
||||
max-width: 300px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-card]
|
||||
@@ -1,39 +0,0 @@
|
||||
# Checkbox
|
||||
|
||||
[component-header:sl-checkbox]
|
||||
|
||||
Checkboxes allow the user to toggle an option on or off.
|
||||
|
||||
```html preview
|
||||
<sl-checkbox>Checkbox</sl-checkbox>
|
||||
```
|
||||
|
||||
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form) instead.
|
||||
|
||||
## Examples
|
||||
|
||||
### Checked
|
||||
|
||||
Use the `checked` attribute to activate the checkbox.
|
||||
|
||||
```html preview
|
||||
<sl-checkbox checked>Checked</sl-checkbox>
|
||||
```
|
||||
|
||||
### Indeterminate
|
||||
|
||||
Use the `indeterminate` attribute to make the checkbox indeterminate.
|
||||
|
||||
```html preview
|
||||
<sl-checkbox indeterminate>Indeterminate</sl-checkbox>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable the checkbox.
|
||||
|
||||
```html preview
|
||||
<sl-checkbox disabled>Disabled</sl-checkbox>
|
||||
```
|
||||
|
||||
[component-metadata:sl-checkbox]
|
||||
@@ -1,52 +0,0 @@
|
||||
# Color Picker
|
||||
|
||||
[component-header:sl-color-picker]
|
||||
|
||||
Color pickers allow the user to select a color.
|
||||
|
||||
```html preview
|
||||
<sl-color-picker></sl-color-picker>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Opacity
|
||||
|
||||
Use the `opacity` attribute to enable the opacity slider. When this is enabled, the value will be displayed as HEXA, RGBA, or HSLA based on `format`.
|
||||
|
||||
```html preview
|
||||
<sl-color-picker opacity></sl-color-picker>
|
||||
```
|
||||
|
||||
### Formats
|
||||
|
||||
Set the color picker's format with the `format` attribute. Valid options include `hex`, `rgb`, and `hsl`. Note that the color picker's input will accept any parsable format (including CSS color names) regardless of this option.
|
||||
|
||||
To prevent users from toggling the format themselves, add the `no-format-toggle` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-color-picker format="hex" value="#4a90e2"></sl-color-picker>
|
||||
<sl-color-picker format="rgb" value="rgb(80, 227, 194)"></sl-color-picker>
|
||||
<sl-color-picker format="hsl" value="hsl(290, 87%, 47%)"></sl-color-picker>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the `size` attribute to change the color picker's trigger size.
|
||||
|
||||
```html preview
|
||||
<sl-color-picker size="small"></sl-color-picker>
|
||||
<sl-color-picker size="medium"></sl-color-picker>
|
||||
<sl-color-picker size="large"></sl-color-picker>
|
||||
```
|
||||
|
||||
|
||||
### Inline
|
||||
|
||||
The color picker can be rendered inline instead of in a dropdown using the `inline` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-color-picker inline></sl-color-picker>
|
||||
```
|
||||
|
||||
[component-metadata:sl-color-picker]
|
||||
@@ -1,65 +0,0 @@
|
||||
# Details
|
||||
|
||||
[component-header:sl-details]
|
||||
|
||||
Details show a brief summary and expand to show additional content.
|
||||
|
||||
```html preview
|
||||
<sl-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.
|
||||
</sl-details>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disable` attribute to prevent the details from expanding.
|
||||
|
||||
```html preview
|
||||
<sl-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.
|
||||
</sl-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 `sl-show` event.
|
||||
|
||||
```html preview
|
||||
<div class="details-group-example">
|
||||
<sl-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.
|
||||
</sl-details>
|
||||
|
||||
<sl-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.
|
||||
</sl-details>
|
||||
|
||||
<sl-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.
|
||||
</sl-details>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.details-group-example');
|
||||
|
||||
// Close all other details when one is shown
|
||||
container.addEventListener('sl-show', event => {
|
||||
[...container.querySelectorAll('sl-details')].map(details => (details.open = event.target === details));
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.details-group-example sl-details:not(:last-of-type) {
|
||||
margin-bottom: var(--sl-spacing-xx-small);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-details]
|
||||
@@ -1,131 +0,0 @@
|
||||
# Dialog
|
||||
|
||||
[component-header:sl-dialog]
|
||||
|
||||
Dialogs, sometimes called "modals", appear above the page and require the user's immediate attention.
|
||||
|
||||
```html preview
|
||||
<sl-dialog label="Dialog" class="dialog-overview">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-dialog>
|
||||
|
||||
<sl-button>Open Dialog</sl-button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('.dialog-overview');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
||||
|
||||
openButton.addEventListener('click', () => dialog.show());
|
||||
closeButton.addEventListener('click', () => dialog.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
## UX Tips
|
||||
|
||||
- Use a dialog when you immediately require the user's attention, e.g. confirming a destructive action.
|
||||
- Always provide an obvious way for the user to dismiss the dialog.
|
||||
- Don't nest dialogs. It almost always leads to a poor experience for the user.
|
||||
|
||||
## Examples
|
||||
|
||||
### Custom Width
|
||||
|
||||
Use the `--width` custom property to set the dialog's width.
|
||||
|
||||
```html preview
|
||||
<sl-dialog label="Dialog" class="dialog-width" style="--width: 50vw;">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-dialog>
|
||||
|
||||
<sl-button>Open Dialog</sl-button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('.dialog-width');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
||||
|
||||
openButton.addEventListener('click', () => dialog.show());
|
||||
closeButton.addEventListener('click', () => dialog.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Scrolling
|
||||
|
||||
By design, a dialog's height will never exceed that of the viewport. As such, dialogs will not scroll with the page ensuring the header and footer are always accessible to the user.
|
||||
|
||||
```html preview
|
||||
<sl-dialog label="Dialog" class="dialog-scrolling">
|
||||
<div style="height: 150vh; border: dashed 2px var(--sl-color-gray-200); padding: 0 1rem;">
|
||||
<p>Scroll down and give it a try! 👇</p>
|
||||
</div>
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-dialog>
|
||||
|
||||
<sl-button>Open Dialog</sl-button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('.dialog-scrolling');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
||||
|
||||
openButton.addEventListener('click', () => dialog.show());
|
||||
closeButton.addEventListener('click', () => dialog.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Ignoring Clicks on the Overlay
|
||||
|
||||
By default, dialogs are closed when the user clicks or taps on the overlay. To prevent this behavior, cancel the `sl-overlay-dismiss` event.
|
||||
|
||||
```html preview
|
||||
<sl-dialog label="Dialog" class="dialog-no-overlay-dismiss">
|
||||
This dialog will not be closed when you click outside of it.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-dialog>
|
||||
|
||||
<sl-button>Open Dialog</sl-button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('.dialog-no-overlay-dismiss');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
||||
|
||||
openButton.addEventListener('click', () => dialog.show());
|
||||
closeButton.addEventListener('click', () => dialog.hide());
|
||||
|
||||
dialog.addEventListener('sl-overlay-dismiss', event => event.preventDefault());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Customizing Initial Focus
|
||||
|
||||
By default, the dialog's panel will gain focus when opened. To set focus on a different element, listen for the `sl-initial-focus` event.
|
||||
|
||||
```html preview
|
||||
<sl-dialog label="Dialog" class="dialog-focus">
|
||||
<sl-input placeholder="I will have focus when the dialog is opened"></sl-input>
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-dialog>
|
||||
|
||||
<sl-button>Open Dialog</sl-button>
|
||||
|
||||
<script>
|
||||
const dialog = document.querySelector('.dialog-focus');
|
||||
const input = dialog.querySelector('sl-input');
|
||||
const openButton = dialog.nextElementSibling;
|
||||
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
||||
|
||||
openButton.addEventListener('click', () => dialog.show());
|
||||
closeButton.addEventListener('click', () => dialog.hide());
|
||||
|
||||
dialog.addEventListener('sl-initial-focus', event => {
|
||||
event.preventDefault();
|
||||
input.focus({ preventScroll: true });
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
[component-metadata:sl-dialog]
|
||||
@@ -1,219 +0,0 @@
|
||||
# Drawer
|
||||
|
||||
[component-header:sl-drawer]
|
||||
|
||||
Drawers slide in from a container to expose additional options and information.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" class="drawer-overview">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-overview');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Slide in From Start
|
||||
|
||||
By default, drawers slide in from the end. To make the drawer slide in from the start, set the `placement` attribute to `start`.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" placement="start" class="drawer-placement-start">
|
||||
This drawer slides in from the start.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-placement-start');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Slide in From Top
|
||||
|
||||
To make the drawer slide in from the top, set the `placement` attribute to `top`.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" placement="top" class="drawer-placement-top">
|
||||
This drawer slides in from the top.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-placement-top');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Slide in From Bottom
|
||||
|
||||
To make the drawer slide in from the bottom, set the `placement` attribute to `bottom`.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" placement="bottom" class="drawer-placement-bottom">
|
||||
This drawer slides in from the bottom.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-placement-bottom');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Contained to an Element
|
||||
|
||||
By default, the drawer slides out of its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport. To make the drawer slide out of its parent element, add the `contained` prop and `position: relative` to the parent.
|
||||
|
||||
```html preview
|
||||
<div
|
||||
style="position: relative; border: solid 2px var(--sl-panel-border-color); height: 300px; padding: 1rem; margin-bottom: 1rem;"
|
||||
>
|
||||
The drawer will be contained to this box. This content won't shift or be affected in any way when the drawer opens.
|
||||
|
||||
<sl-drawer label="Drawer" contained class="drawer-contained" style="--size: 50%;">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
</div>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-contained');
|
||||
const openButton = drawer.parentElement.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Custom Size
|
||||
|
||||
Use the `--size` custom property to set the drawer's size. This will be applied to the drawer's width or height depending on its `placement`.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" class="drawer-custom-size" style="--size: 50vw;">
|
||||
This drawer is always 50% of the viewport.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-custom-size');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Scrolling
|
||||
|
||||
By design, a drawer's height will never exceed 100% of its container. As such, drawers will not scroll with the page to ensure the header and footer are always accessible to the user.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" class="drawer-scrolling">
|
||||
<div style="height: 150vh; border: dashed 2px var(--sl-color-gray-200); padding: 0 1rem;">
|
||||
<p>Scroll down and give it a try! 👇</p>
|
||||
</div>
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-scrolling');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Ignoring Clicks on the Overlay
|
||||
|
||||
By default, drawers are closed when the user clicks or taps on the overlay. To prevent this behavior, cancel the `sl-overlay-dismiss` event.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" class="drawer-no-overlay-dismiss">
|
||||
This drawer will not be closed when you click outside of it.
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-no-overlay-dismiss');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
|
||||
drawer.addEventListener('sl-overlay-dismiss', event => event.preventDefault());
|
||||
</script>
|
||||
```
|
||||
|
||||
### Customizing Initial Focus
|
||||
|
||||
By default, the drawer's panel will gain focus when opened. To set focus on a different element, listen for the `sl-initial-focus` event.
|
||||
|
||||
```html preview
|
||||
<sl-drawer label="Drawer" class="drawer-focus">
|
||||
<sl-input placeholder="I will have focus when the drawer is opened"></sl-input>
|
||||
<sl-button slot="footer" type="primary">Close</sl-button>
|
||||
</sl-drawer>
|
||||
|
||||
<sl-button>Open Drawer</sl-button>
|
||||
|
||||
<script>
|
||||
const drawer = document.querySelector('.drawer-focus');
|
||||
const input = drawer.querySelector('sl-input');
|
||||
const openButton = drawer.nextElementSibling;
|
||||
const closeButton = drawer.querySelector('sl-button[type="primary"]');
|
||||
|
||||
openButton.addEventListener('click', () => drawer.show());
|
||||
closeButton.addEventListener('click', () => drawer.hide());
|
||||
|
||||
drawer.addEventListener('sl-initial-focus', event => {
|
||||
event.preventDefault();
|
||||
input.focus({ preventScroll: true });
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
[component-metadata:sl-drawer]
|
||||
@@ -1,177 +0,0 @@
|
||||
# Dropdown
|
||||
|
||||
[component-header:sl-dropdown]
|
||||
|
||||
Dropdowns expose additional content that "drops down" in a panel.
|
||||
|
||||
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](/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](/components/color-picker) and [select](/components/select)). The API gives you complete control over showing, hiding, and positioning the panel.
|
||||
|
||||
```html preview
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Dropdown</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Dropdown Item 1</sl-menu-item>
|
||||
<sl-menu-item>Dropdown Item 2</sl-menu-item>
|
||||
<sl-menu-item>Dropdown Item 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item checked>Checked</sl-menu-item>
|
||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item>
|
||||
Prefix
|
||||
<sl-icon slot="prefix" name="gift"></sl-icon>
|
||||
</sl-menu-item>
|
||||
<sl-menu-item>
|
||||
Suffix Icon
|
||||
<sl-icon slot="suffix" name="heart"></sl-icon>
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### 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 preview
|
||||
<sl-dropdown placement="top-start">
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Cut</sl-menu-item>
|
||||
<sl-menu-item>Copy</sl-menu-item>
|
||||
<sl-menu-item>Paste</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item>Find</sl-menu-item>
|
||||
<sl-menu-item>Replace</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
```
|
||||
|
||||
### Distance
|
||||
|
||||
The distance from the panel to the trigger can be customized using the `distance` attribute. This value is specified in pixels.
|
||||
|
||||
```html preview
|
||||
<sl-dropdown distance="30">
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Cut</sl-menu-item>
|
||||
<sl-menu-item>Copy</sl-menu-item>
|
||||
<sl-menu-item>Paste</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item>Find</sl-menu-item>
|
||||
<sl-menu-item>Replace</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
```
|
||||
|
||||
### Skidding
|
||||
|
||||
The offset of the panel along the trigger can be customized using the `skidding` attribute. This value is specified in pixels.
|
||||
|
||||
```html preview
|
||||
<sl-dropdown skidding="30">
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Cut</sl-menu-item>
|
||||
<sl-menu-item>Copy</sl-menu-item>
|
||||
<sl-menu-item>Paste</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item>Find</sl-menu-item>
|
||||
<sl-menu-item>Replace</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
```
|
||||
|
||||
### 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, 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 preview
|
||||
<div class="dropdown-hoist">
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>No Hoist</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Item 1</sl-menu-item>
|
||||
<sl-menu-item>Item 2</sl-menu-item>
|
||||
<sl-menu-item>Item 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
|
||||
<sl-dropdown hoist>
|
||||
<sl-button slot="trigger" caret>Hoist</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item>Item 1</sl-menu-item>
|
||||
<sl-menu-item>Item 2</sl-menu-item>
|
||||
<sl-menu-item>Item 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dropdown-hoist {
|
||||
border: solid 2px var(--sl-panel-border-color);
|
||||
padding: var(--sl-spacing-medium);
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Getting the Selected Item
|
||||
|
||||
When dropdowns are used with [menus](/components/menu), you can listen for the `sl-select` 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 preview
|
||||
<div class="dropdown-selection">
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.dropdown-selection');
|
||||
const dropdown = container.querySelector('sl-dropdown');
|
||||
|
||||
dropdown.addEventListener('sl-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 preview
|
||||
<div class="dropdown-selection-alt">
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.dropdown-selection-alt');
|
||||
const cut = container.querySelector('sl-menu-item[value="cut"]');
|
||||
const copy = container.querySelector('sl-menu-item[value="copy"]');
|
||||
const paste = container.querySelector('sl-menu-item[value="paste"]');
|
||||
|
||||
cut.addEventListener('click', () => console.log('cut'));
|
||||
copy.addEventListener('click', () => console.log('copy'));
|
||||
paste.addEventListener('click', () => console.log('paste'));
|
||||
</script>
|
||||
```
|
||||
|
||||
[component-metadata:sl-dropdown]
|
||||
@@ -1,217 +0,0 @@
|
||||
# Form
|
||||
|
||||
[component-header:sl-form]
|
||||
|
||||
Forms collect data that can easily be processed and sent to a server.
|
||||
|
||||
All Shoelace components make use of a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate markup, styles, and behavior. One caveat of this approach is that native `<form>` elements will not recognize Shoelace form controls.
|
||||
|
||||
This component solves that problem by serializing _both_ Shoelace form controls and native form controls when the form is submitted. The resulting form data is exposed in the `sl-submit` event as a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object in `event.detail.formData`. You can also find an array of form controls in `event.detail.formControls`.
|
||||
|
||||
Shoelace forms don't make use of `action` and `method` attributes and they don't submit the same was as native forms. To handle submission, you need to listen for the `sl-submit` event as shown in the example below and make an XHR request with the resulting form data.
|
||||
|
||||
```html preview
|
||||
<sl-form class="form-overview">
|
||||
<sl-input name="name" type="text" label="Name"></sl-input>
|
||||
<br>
|
||||
<sl-select name="favorite" label="Select your favorite">
|
||||
<sl-menu-item value="birds">Birds</sl-menu-item>
|
||||
<sl-menu-item value="cats">Cats</sl-menu-item>
|
||||
<sl-menu-item value="dogs">Dogs</sl-menu-item>
|
||||
</sl-select>
|
||||
<br>
|
||||
<sl-checkbox name="agree" value="yes">
|
||||
I totally agree
|
||||
</sl-checkbox>
|
||||
<br><br>
|
||||
<sl-button submit>Submit</sl-button>
|
||||
</sl-form>
|
||||
|
||||
<script>
|
||||
const form = document.querySelector('.form-overview');
|
||||
|
||||
// Watch for the slSubmit event
|
||||
form.addEventListener('sl-submit', event => {
|
||||
const formData = event.detail.formData;
|
||||
let output = '';
|
||||
|
||||
//
|
||||
// Example 1: Post data to a server and wait for a JSON response
|
||||
//
|
||||
fetch('https://jsonplaceholder.typicode.com/posts', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
console.log('Success:', result);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
|
||||
//
|
||||
// Example 2: Output all form control names + values
|
||||
//
|
||||
for (const entry of formData.entries()) {
|
||||
output += `${entry[0]}: ${entry[1]}\n`;
|
||||
}
|
||||
alert(output);
|
||||
|
||||
//
|
||||
// Example 3: Get all form controls that were serialized as
|
||||
// an array of HTML elements
|
||||
//
|
||||
console.log(event.detail.formControls);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## Form Control Validation
|
||||
|
||||
Client-side validation can be enabled through the browser's [Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) for many form controls. You can enable it using props such as `required`, `pattern`, `minlength`, and `maxlength`. As the user interacts with the form control, the `invalid` attribute will reflect its validity based on its current value and the constraints that have been defined.
|
||||
|
||||
When a form control is invalid, the containing form will not be submitted. Instead, the browser will show the user a relevant error message. If you don't want to use client-side validation, you can suppress this behavior by adding `novalidate` to the `<sl-form>` element.
|
||||
|
||||
All form controls support validation, but not all validation props are available for every component. Refer to a component's documentation to see which validation props it supports.
|
||||
|
||||
Note that validity is not checked until the user interacts with the control or its containing form is submitted. This prevents required controls from being rendered as invalid right away, which can result in a poor user experience. If you need this behavior, set the `invalid` attribute initially.
|
||||
|
||||
!> Client-side validation can be used to improve the UX of forms, but it is not a replacement for server-side validation. **You should always validate and sanitize user input on the server!**
|
||||
|
||||
### Required Fields
|
||||
|
||||
To make a field required, use the `required` prop. The form will not be submitted if a required form control is empty.
|
||||
|
||||
```html preview
|
||||
<sl-form class="input-validation-required">
|
||||
<sl-input name="name" label="Name" required></sl-input>
|
||||
<br>
|
||||
<sl-select label="Favorite Animal" clearable required>
|
||||
<sl-menu-item value="birds">Birds</sl-menu-item>
|
||||
<sl-menu-item value="cats">Cats</sl-menu-item>
|
||||
<sl-menu-item value="dogs">Dogs</sl-menu-item>
|
||||
<sl-menu-item value="other">Other</sl-menu-item>
|
||||
</sl-select>
|
||||
<br>
|
||||
<sl-textarea name="comment" label="Comment" required></sl-textarea>
|
||||
<br>
|
||||
<sl-checkbox required>Check me before submitting</sl-checkbox>
|
||||
<br><br>
|
||||
<sl-button type="primary" submit>Submit</sl-button>
|
||||
</sl-form>
|
||||
|
||||
<script>
|
||||
const form = document.querySelector('.input-validation-required');
|
||||
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
|
||||
</script>
|
||||
```
|
||||
|
||||
### Input Patterns
|
||||
|
||||
To restrict a value to a specific [pattern](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern), use the `pattern` attribute. This example only allows the letters A-Z, so the form will not submit if a number or symbol is entered. This only works with `<sl-input>` elements.
|
||||
|
||||
```html preview
|
||||
<sl-form class="input-validation-pattern">
|
||||
<sl-input name="letters" required label="Letters" pattern="[A-Za-z]+"></sl-input>
|
||||
<br>
|
||||
<sl-button type="primary" submit>Submit</sl-button>
|
||||
</sl-form>
|
||||
|
||||
<script>
|
||||
const form = document.querySelector('.input-validation-pattern');
|
||||
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
|
||||
</script>
|
||||
```
|
||||
|
||||
### Input Types
|
||||
|
||||
Some input types will automatically trigger constraints, such as `email` and `url`.
|
||||
|
||||
```html preview
|
||||
<sl-form class="input-validation-type">
|
||||
<sl-input type="email" label="Email" placeholder="you@example.com" required></sl-input>
|
||||
<br>
|
||||
<sl-input type="url" label="URL" placeholder="https://example.com/" required></sl-input>
|
||||
<br>
|
||||
<sl-button type="primary" submit>Submit</sl-button>
|
||||
</sl-form>
|
||||
|
||||
<script>
|
||||
const form = document.querySelector('.input-validation-type');
|
||||
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
|
||||
</script>
|
||||
```
|
||||
|
||||
### Custom Validation
|
||||
|
||||
To create a custom validation error, use the `setCustomValidity` method. The form will not be submitted when this method is called with anything other than an empty string, and its message will be shown by the browser as the validation error. To make the input valid again, call the method a second time with an empty string as the argument.
|
||||
|
||||
```html preview
|
||||
<sl-form class="input-validation-custom">
|
||||
<sl-input label="Type 'shoelace'" required></sl-input>
|
||||
<br>
|
||||
<sl-button type="primary" submit>Submit</sl-button>
|
||||
</sl-form>
|
||||
|
||||
<script>
|
||||
const form = document.querySelector('.input-validation-custom');
|
||||
const input = form.querySelector('sl-input');
|
||||
|
||||
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
|
||||
input.addEventListener('sl-input', () => {
|
||||
if (input.value === 'shoelace') {
|
||||
input.setCustomValidity('');
|
||||
} else {
|
||||
input.setCustomValidity('Hey, you\'re supposed to type \'shoelace\' before submitting this!');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Custom Validation Styles
|
||||
|
||||
The `invalid` attribute reflects the form control's validity, so you can style invalid fields using the `[invalid]` selector. The example below demonstrates how you can give erroneous fields a different appearance. Type something other than "shoelace" to demonstrate this.
|
||||
|
||||
```html preview
|
||||
<sl-input class="custom-input" required pattern="shoelace">
|
||||
<small slot="help-text">Please enter "shoelace" to continue</small>
|
||||
</sl-input>
|
||||
|
||||
<style>
|
||||
.custom-input[invalid]:not([disabled])::part(label),
|
||||
.custom-input[invalid]:not([disabled])::part(help-text) {
|
||||
color: var(--sl-color-danger-600);
|
||||
}
|
||||
|
||||
.custom-input[invalid]:not([disabled])::part(base) {
|
||||
border-color: var(--sl-color-danger-500);
|
||||
}
|
||||
|
||||
.custom-input[invalid] {
|
||||
--focus-ring: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-danger);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Third-party Validation
|
||||
|
||||
To opt out of the browser's built-in validation and use your own, add the `novalidate` attribute to the form. This will ignore all constraints and prevent the browser from showing its own warnings when form controls are invalid.
|
||||
|
||||
Remember that the `invalid` prop on form controls reflects validity as defined by the [Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation). You can set it initially, but the `invalid` prop will update as the user interacts with the form control. As such, you should not rely on it to set invalid styles using a custom validation library.
|
||||
|
||||
Instead, toggle a class and target it in your stylesheet as shown below.
|
||||
|
||||
```html
|
||||
<sl-form novalidate>
|
||||
<sl-input class="invalid"></sl-input>
|
||||
</sl-form>
|
||||
|
||||
<style>
|
||||
sl-input.invalid {
|
||||
...
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-form]
|
||||
@@ -1,58 +0,0 @@
|
||||
# Format Bytes
|
||||
|
||||
[component-header:sl-format-bytes]
|
||||
|
||||
Formats a number as a human readable bytes value.
|
||||
|
||||
```html preview
|
||||
<div class="format-bytes-overview">
|
||||
The file is <sl-format-bytes value="1000"></sl-format-bytes> in size.
|
||||
<br><br>
|
||||
<sl-input type="number" value="1000" label="Number to Format" style="max-width: 180px;"></sl-input>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.format-bytes-overview');
|
||||
const formatter = container.querySelector('sl-format-bytes');
|
||||
const input = container.querySelector('sl-input');
|
||||
|
||||
input.addEventListener('sl-input', () => formatter.value = input.value || 0);
|
||||
</script>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Formatting Bytes
|
||||
|
||||
Set the `value` attribute to a number to get the value in bytes.
|
||||
|
||||
```html preview
|
||||
<sl-format-bytes value="12"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200000"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200000000"></sl-format-bytes>
|
||||
```
|
||||
|
||||
### Formatting Bits
|
||||
|
||||
To get the value in bits, set the `unit` attribute to `bits`.
|
||||
|
||||
```html preview
|
||||
<sl-format-bytes value="12" unit="bits"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200" unit="bits"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200000" unit="bits"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200000000" unit="bits"></sl-format-bytes>
|
||||
```
|
||||
|
||||
### Localization
|
||||
|
||||
Use the `locale` attribute to set the number formatting locale.
|
||||
|
||||
```html preview
|
||||
<sl-format-bytes value="12" locale="de"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200" locale="de"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200000" locale="de"></sl-format-bytes><br>
|
||||
<sl-format-bytes value="1200000000" locale="de"></sl-format-bytes>
|
||||
```
|
||||
|
||||
[component-metadata:sl-format-bytes]
|
||||
@@ -1,64 +0,0 @@
|
||||
# Format Date
|
||||
|
||||
[component-header:sl-format-date]
|
||||
|
||||
Formats a date/time using the specified locale and options.
|
||||
|
||||
Localization is handled by the browser's [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). No language packs are required.
|
||||
|
||||
```html preview
|
||||
<!-- Shoelace 2 release date 🎉 -->
|
||||
<sl-format-date date="2020-07-15T09:17:00-04:00"></sl-format-date>
|
||||
```
|
||||
|
||||
The `date` prop determines the date/time to use when formatting. It must be a string that [`Date.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) can interpret or a [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object set via JavaScript. If omitted, the current date/time will be assumed.
|
||||
|
||||
?> When using strings, avoid ambiguous dates such as `03/04/2020` which can be interpreted as March 4 or April 3 depending on the user's browser and locale. Instead, always use a valid [ISO 8601 date time string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) to ensure the date will be parsed properly by all clients.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### Date & Time Formatting
|
||||
|
||||
Formatting options are based on those found in the [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). When formatting options are provided, the date/time will be formatted according to those values. When no formatting options are provided, a localized, numeric date will be displayed instead.
|
||||
|
||||
```html preview
|
||||
<!-- Human-readable date -->
|
||||
<sl-format-date month="long" day="numeric" year="numeric"></sl-format-date><br>
|
||||
|
||||
<!-- Time -->
|
||||
<sl-format-date hour="numeric" minute="numeric"></sl-format-date><br>
|
||||
|
||||
<!-- Weekday -->
|
||||
<sl-format-date weekday="long"></sl-format-date><br>
|
||||
|
||||
<!-- Month -->
|
||||
<sl-format-date month="long"></sl-format-date><br>
|
||||
|
||||
<!-- Year -->
|
||||
<sl-format-date year="numeric"></sl-format-date><br>
|
||||
|
||||
<!-- No formatting options -->
|
||||
<sl-format-date></sl-format-date>
|
||||
```
|
||||
|
||||
### Hour Formatting
|
||||
|
||||
By default, the browser will determine whether to use 12-hour or 24-hour time. To force one or the other, set the `hourFormat` prop to `12` or `24`.
|
||||
|
||||
```html preview
|
||||
<sl-format-date hour="numeric" minute="numeric" hour-format="12"></sl-format-date><br>
|
||||
<sl-format-date hour="numeric" minute="numeric" hour-format="24"></sl-format-date>
|
||||
```
|
||||
|
||||
### Localization
|
||||
|
||||
Use the `locale` attribute to set the date/time formatting locale.
|
||||
|
||||
```html preview
|
||||
English: <sl-format-date locale="en"></sl-format-date><br>
|
||||
French: <sl-format-date locale="fr"></sl-format-date><br>
|
||||
Russian: <sl-format-date locale="ru"></sl-format-date><br>
|
||||
```
|
||||
|
||||
[component-metadata:sl-format-date]
|
||||
@@ -1,61 +0,0 @@
|
||||
# Format Number
|
||||
|
||||
[component-header:sl-format-number]
|
||||
|
||||
Formats a number using the specified locale and options.
|
||||
|
||||
Localization is handled by the browser's [`Intl.NumberFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat). No language packs are required.
|
||||
|
||||
```html preview
|
||||
<div class="format-number-overview">
|
||||
<sl-format-number value="1000"></sl-format-number>
|
||||
<br><br>
|
||||
<sl-input type="number" value="1000" label="Number to Format" style="max-width: 180px;"></sl-input>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.format-number-overview');
|
||||
const formatter = container.querySelector('sl-format-number');
|
||||
const input = container.querySelector('sl-input');
|
||||
|
||||
input.addEventListener('sl-input', () => formatter.value = input.value || 0);
|
||||
</script>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Percentages
|
||||
|
||||
To get the value as a percent, set the `type` attribute to `percent`.
|
||||
|
||||
```html preview
|
||||
<sl-format-number type="percent" value="0"></sl-format-number><br>
|
||||
<sl-format-number type="percent" value=".25"></sl-format-number><br>
|
||||
<sl-format-number type="percent" value=".50"></sl-format-number><br>
|
||||
<sl-format-number type="percent" value=".75"></sl-format-number><br>
|
||||
<sl-format-number type="percent" value="1"></sl-format-number>
|
||||
```
|
||||
|
||||
### Localization
|
||||
|
||||
Use the `locale` attribute to set the number formatting locale.
|
||||
|
||||
```html preview
|
||||
English: <sl-format-number value="2000" locale="en" minimum-fraction-digits="2"></sl-format-number><br>
|
||||
German: <sl-format-number value="2000" locale="de" minimum-fraction-digits="2"></sl-format-number><br>
|
||||
Russian: <sl-format-number value="2000" locale="ru" minimum-fraction-digits="2"></sl-format-number>
|
||||
```
|
||||
|
||||
### Currency
|
||||
|
||||
To format a number as a monetary value, set the `type` attribute to `currency` and set the `currency` attribute to the desired ISO 4217 currency code. You should also specify `locale` to ensure the the number is formatted correctly for the target locale.
|
||||
|
||||
```html preview
|
||||
<sl-format-number type="currency" currency="USD" value="2000" locale="en-US"></sl-format-number><br>
|
||||
<sl-format-number type="currency" currency="GBP" value="2000" locale="en-GB"></sl-format-number><br>
|
||||
<sl-format-number type="currency" currency="EUR" value="2000" locale="de"></sl-format-number><br>
|
||||
<sl-format-number type="currency" currency="RUB" value="2000" locale="ru"></sl-format-number><br>
|
||||
<sl-format-number type="currency" currency="CNY" value="2000" locale="zh-cn"></sl-format-number>
|
||||
```
|
||||
|
||||
[component-metadata:sl-format-number]
|
||||
@@ -1,67 +0,0 @@
|
||||
# Icon Button
|
||||
|
||||
[component-header:sl-icon-button]
|
||||
|
||||
Icons buttons are simple, icon-only buttons that can be used for actions and in toolbars.
|
||||
|
||||
For a full list of icons that come bundled with Shoelace, refer to the [icon component](/components/icon).
|
||||
|
||||
```html preview
|
||||
<sl-icon-button name="gear" label="Settings"></sl-icon-button>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Sizes
|
||||
|
||||
Icon buttons inherit their parent element's `font-size`.
|
||||
|
||||
```html preview
|
||||
<sl-icon-button name="pencil" label="Edit" style="font-size: 1.5rem;"></sl-icon-button>
|
||||
<sl-icon-button name="pencil" label="Edit" style="font-size: 2rem;"></sl-icon-button>
|
||||
<sl-icon-button name="pencil" label="Edit" style="font-size: 2.5rem;"></sl-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 preview
|
||||
<div class="icon-button-color">
|
||||
<sl-icon-button name="type-bold" label="Bold"></sl-icon-button>
|
||||
<sl-icon-button name="type-italic" label="Italic"></sl-icon-button>
|
||||
<sl-icon-button name="type-underline" label="Underline"></sl-icon-button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.icon-button-color sl-icon-button::part(base) {
|
||||
color: #b00091;
|
||||
}
|
||||
|
||||
.icon-button-color sl-icon-button::part(base):hover,
|
||||
.icon-button-color sl-icon-button::part(base):focus {
|
||||
color: #c913aa;
|
||||
}
|
||||
|
||||
.icon-button-color sl-icon-button::part(base):active {
|
||||
color: #960077;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Icon Button with Tooltip
|
||||
|
||||
Wrap a tooltip around an icon button to provide contextual information to the user.
|
||||
|
||||
```html preview
|
||||
<sl-tooltip content="Settings">
|
||||
<sl-icon-button name="gear" label="Settings"></sl-icon-button>
|
||||
</sl-tooltip>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
```html preview
|
||||
<sl-icon-button name="gear" label="Settings" disabled></sl-icon-button>
|
||||
```
|
||||
|
||||
[component-metadata:sl-icon-button]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Image Comparer
|
||||
|
||||
[component-header:sl-image-comparer]
|
||||
|
||||
Compare visual differences between similar photos with a sliding panel.
|
||||
|
||||
For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
|
||||
|
||||
```html preview
|
||||
<sl-image-comparer>
|
||||
<img slot="before" src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&sat=-100&bri=-5" alt="Grayscale version of kittens in a basket looking around.">
|
||||
<img slot="after" src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80" alt="Color version of kittens in a basket looking around.">
|
||||
</sl-image-comparer>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Initial Position
|
||||
|
||||
Use the `position` attribute to set the initial position of the slider. This is a percentage from `0` to `100`.
|
||||
|
||||
```html preview
|
||||
<sl-image-comparer position="0">
|
||||
<img slot="before" src="https://images.unsplash.com/photo-1520903074185-8eca362b3dce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1200&q=80" alt="A person sitting on bricks wearing untied boots.">
|
||||
<img slot="after" src="https://images.unsplash.com/photo-1520640023173-50a135e35804?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2250&q=80" alt="A person sitting on a yellow curb tying shoelaces on a boot.">
|
||||
</sl-image-comparer>
|
||||
```
|
||||
|
||||
[component-metadata:sl-image-comparer]
|
||||
@@ -1,121 +0,0 @@
|
||||
# Input
|
||||
|
||||
[component-header:sl-input]
|
||||
|
||||
Inputs collect data from the user.
|
||||
|
||||
```html preview
|
||||
<sl-input></sl-input>
|
||||
```
|
||||
|
||||
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form) instead.
|
||||
|
||||
?> Please refer to the section on [form control validation](/components/form?id=form-control-validation) to learn how to do client-side validation.
|
||||
|
||||
## Examples
|
||||
|
||||
### Placeholders
|
||||
|
||||
Use the `placeholder` attribute to add a placeholder.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Type something"></sl-input>
|
||||
```
|
||||
|
||||
### Clearable
|
||||
|
||||
Add the `clearable` prop to add a clear button when the input has content.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Clearable" clearable></sl-input>
|
||||
```
|
||||
|
||||
### Toggle Password
|
||||
|
||||
Add the `toggle-password` prop to add a toggle button that will show the password when activated.
|
||||
|
||||
```html preview
|
||||
<sl-input type="password" placeholder="Password Toggle" size="small" toggle-password></sl-input>
|
||||
<br>
|
||||
<sl-input type="password" placeholder="Password Toggle" size="medium" toggle-password></sl-input>
|
||||
<br>
|
||||
<sl-input type="password" placeholder="Password Toggle" size="large" toggle-password></sl-input>
|
||||
```
|
||||
|
||||
### Pill
|
||||
|
||||
Use the `pill` prop to give inputs rounded edges.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Small" size="small" pill></sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Medium" size="medium" pill></sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Large" size="large" pill></sl-input>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable an input.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Disabled" size="small" disabled></sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Disabled" size="medium" disabled></sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Disabled" size="large" disabled></sl-input>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the `size` attribute to change an input's size.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Small" size="small"></sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Medium" size="medium"></sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Large" size="large"></sl-input>
|
||||
```
|
||||
|
||||
### Prefix & Suffix Icons
|
||||
|
||||
Use the `prefix` and `suffix` slots to add icons.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Small" size="small">
|
||||
<sl-icon name="tag" slot="prefix"></sl-icon>
|
||||
<sl-icon name="gear" slot="suffix"></sl-icon>
|
||||
</sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Medium" size="medium">
|
||||
<sl-icon name="tag" slot="prefix"></sl-icon>
|
||||
<sl-icon name="gear" slot="suffix"></sl-icon>
|
||||
</sl-input>
|
||||
<br>
|
||||
<sl-input placeholder="Large" size="large">
|
||||
<sl-icon name="tag" slot="prefix"></sl-icon>
|
||||
<sl-icon name="gear" slot="suffix"></sl-icon>
|
||||
</sl-input>
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the `label` attribute to give the input an accessible label. For labels that contain HTML, use the `label` slot instead.
|
||||
|
||||
```html preview
|
||||
<sl-input label="What is your name?"></sl-input>
|
||||
```
|
||||
|
||||
### Help Text
|
||||
|
||||
Add descriptive help text to an input with the `help-text` attribute. For help texts that contain HTML, use the `help-text` slot instead.
|
||||
|
||||
```html preview
|
||||
<sl-input
|
||||
label="Nickname"
|
||||
help-text="What would you like people to call you?"
|
||||
></sl-input>
|
||||
```
|
||||
|
||||
[component-metadata:sl-input]
|
||||
@@ -1,22 +0,0 @@
|
||||
# Menu Divider
|
||||
|
||||
[component-header:sl-menu-divider]
|
||||
|
||||
Menu dividers are used to visually group menu items.
|
||||
|
||||
```html preview
|
||||
<sl-menu
|
||||
style="max-width: 200px; border: solid 1px var(--sl-panel-border-color); border-radius: var(--sl-border-radius-medium);"
|
||||
>
|
||||
<sl-menu-item value="1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="2">Option 2</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item value="3">Option 3</sl-menu-item>
|
||||
<sl-menu-item value="4">Option 4</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item value="5">Option 5</sl-menu-item>
|
||||
<sl-menu-item value="6">Option 6</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
[component-metadata:sl-menu-divider]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Menu Item
|
||||
|
||||
[component-header:sl-menu-item]
|
||||
|
||||
Menu items provide options for the user to pick from in a menu.
|
||||
|
||||
```html preview
|
||||
<sl-menu
|
||||
style="max-width: 200px; border: solid 1px var(--sl-panel-border-color); border-radius: var(--sl-border-radius-medium);"
|
||||
>
|
||||
<sl-menu-item>Option 1</sl-menu-item>
|
||||
<sl-menu-item>Option 2</sl-menu-item>
|
||||
<sl-menu-item>Option 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item checked>Checked</sl-menu-item>
|
||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item>
|
||||
Prefix Icon
|
||||
<sl-icon slot="prefix" name="gift"></sl-icon>
|
||||
</sl-menu-item>
|
||||
<sl-menu-item>
|
||||
Suffix Icon
|
||||
<sl-icon slot="suffix" name="heart"></sl-icon>
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
[component-metadata:sl-menu-item]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Menu Label
|
||||
|
||||
[component-header:sl-menu-label]
|
||||
|
||||
Menu labels are used to describe a group of menu items.
|
||||
|
||||
```html preview
|
||||
<sl-menu
|
||||
style="max-width: 200px; border: solid 1px var(--sl-panel-border-color); border-radius: var(--sl-border-radius-medium);"
|
||||
>
|
||||
<sl-menu-label>Fruits</sl-menu-label>
|
||||
<sl-menu-item value="apple">Apple</sl-menu-item>
|
||||
<sl-menu-item value="banana">Banana</sl-menu-item>
|
||||
<sl-menu-item value="orange">Orange</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-label>Vegetables</sl-menu-label>
|
||||
<sl-menu-item value="broccoli">Broccoli</sl-menu-item>
|
||||
<sl-menu-item value="carrot">Carrot</sl-menu-item>
|
||||
<sl-menu-item value="zucchini">Zucchini</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
[component-metadata:sl-menu-label]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Menu
|
||||
|
||||
[component-header:sl-menu]
|
||||
|
||||
Menus provide a list of options for the user to choose from.
|
||||
|
||||
You can use [menu items](/components/menu-item), [menu dividers](/components/menu-divider), and [menu labels](/components/menu-label) to compose a menu.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px; border: solid 1px var(--sl-panel-border-color); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item value="undo">Undo</sl-menu-item>
|
||||
<sl-menu-item value="redo">Redo</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
<sl-menu-item value="delete">Delete</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
?> 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.
|
||||
|
||||
[component-metadata:sl-menu]
|
||||
@@ -1,60 +0,0 @@
|
||||
# Progress Bar
|
||||
|
||||
[component-header:sl-progress-bar]
|
||||
|
||||
Progress bars are used to show the status of an ongoing operation.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar percentage="50"></sl-progress-bar>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Custom Height
|
||||
|
||||
Use the `--height` custom property to set the progress bar's height.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar percentage="50" style="--height: 6px;"></sl-progress-bar>
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the default slot to show a label.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar percentage="50" class="progress-bar-labels">50%</sl-progress-bar>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-button circle><sl-icon name="dash"></sl-icon></sl-button>
|
||||
<sl-button circle><sl-icon name="plus"></sl-icon></sl-button>
|
||||
|
||||
<script>
|
||||
const progressBar = document.querySelector('.progress-bar-labels');
|
||||
const subtractButton = progressBar.nextElementSibling.nextElementSibling;
|
||||
const addButton = subtractButton.nextElementSibling;
|
||||
|
||||
addButton.addEventListener('click', () => {
|
||||
const percentage = Math.min(100, progressBar.percentage + 10);
|
||||
progressBar.percentage = percentage;
|
||||
progressBar.textContent = `${percentage}%`;
|
||||
});
|
||||
|
||||
subtractButton.addEventListener('click', () => {
|
||||
const percentage = Math.max(0, progressBar.percentage - 10)
|
||||
progressBar.percentage = percentage;
|
||||
progressBar.textContent = `${percentage}%`;
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Indeterminate
|
||||
|
||||
The `indeterminate` attribute can be used to inform the user that the operation is pending, but its status cannot currently be determined. In this state, `percentage` is ignored and the label, if present, will not be shown.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar indeterminate></sl-progress-bar>
|
||||
```
|
||||
|
||||
[component-metadata:sl-progress-bar]
|
||||
@@ -1,71 +0,0 @@
|
||||
# Progress Ring
|
||||
|
||||
[component-header:sl-progress-ring]
|
||||
|
||||
Progress rings are used to show the progress of a determinate operation in a circular fashion.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50"></sl-progress-ring>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Size
|
||||
|
||||
Use the `size` attribute to set the diameter of the progress ring.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50" size="200"></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Stroke Width
|
||||
|
||||
Use the `stroke-width` attribute to set the width of the progress ring's indicator.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50" stroke-width="10"></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Colors
|
||||
|
||||
To change the color, use the `--track-color` and `--indicator-color` custom properties.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring
|
||||
percentage="50"
|
||||
style="--track-color: #ffe2c6; --indicator-color: tomato;"
|
||||
></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the default slot to show a label.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50" size="200" class="progress-ring-labels" style="margin-bottom: .5rem;">50%</sl-progress-ring>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-button circle><sl-icon name="dash"></sl-icon></sl-button>
|
||||
<sl-button circle><sl-icon name="plus"></sl-icon></sl-button>
|
||||
|
||||
<script>
|
||||
const progressRing = document.querySelector('.progress-ring-labels');
|
||||
const subtractButton = progressRing.nextElementSibling.nextElementSibling;
|
||||
const addButton = subtractButton.nextElementSibling;
|
||||
|
||||
addButton.addEventListener('click', () => {
|
||||
const percentage = Math.min(100, progressRing.percentage + 10);
|
||||
progressRing.percentage = percentage;
|
||||
progressRing.textContent = `${percentage}%`;
|
||||
});
|
||||
|
||||
subtractButton.addEventListener('click', () => {
|
||||
const percentage = Math.max(0, progressRing.percentage - 10)
|
||||
progressRing.percentage = percentage;
|
||||
progressRing.textContent = `${percentage}%`;
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
[component-metadata:sl-progress-ring]
|
||||
@@ -1,60 +0,0 @@
|
||||
# QR Code
|
||||
|
||||
[component-header:sl-qr-code]
|
||||
|
||||
Generates a [QR code](https://www.qrcode.com/) and renders it using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API).
|
||||
|
||||
QR codes are useful for providing small pieces of information to users who can quickly scan them with a smartphone. Most smartphones have built-in QR code scanners, so simply pointing the camera at a QR code will decode it and allow the user to visit a website, dial a phone number, read a message, etc.
|
||||
|
||||
```html preview
|
||||
<sl-qr-code value="https://shoelace.style/" label="Scan this code to visit Shoelace on the web!"></sl-qr-code>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Colors
|
||||
|
||||
Use the `fill` and `background` props to modify the QR code's colors. You should always ensure good contrast for optimal compatibility with QR code scanners.
|
||||
|
||||
```html preview
|
||||
<sl-qr-code value="https://shoelace.style/" fill="deeppink" background="white"></sl-qr-code>
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
Use the `size` prop to change the size of the QR code.
|
||||
|
||||
```html preview
|
||||
<sl-qr-code value="https://shoelace.style/" size="64"></sl-qr-code>
|
||||
```
|
||||
|
||||
### Radius
|
||||
|
||||
Create a rounded effect with the `radius` prop.
|
||||
|
||||
```html preview
|
||||
<sl-qr-code value="https://shoelace.style/" radius="0.5"></sl-qr-code>
|
||||
```
|
||||
|
||||
### Error Correction
|
||||
|
||||
QR codes can be rendered with various levels of [error correction](https://www.qrcode.com/en/about/error_correction.html) that can be set using the `error-correction` attribute. This example generates four codes with the same value using different error correction levels.
|
||||
|
||||
```html preview
|
||||
<div class="qr-error-correction">
|
||||
<sl-qr-code value="https://shoelace.style/" error-correction="L"></sl-qr-code>
|
||||
<sl-qr-code value="https://shoelace.style/" error-correction="M"></sl-qr-code>
|
||||
<sl-qr-code value="https://shoelace.style/" error-correction="Q"></sl-qr-code>
|
||||
<sl-qr-code value="https://shoelace.style/" error-correction="H"></sl-qr-code>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.qr-error-correction {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-qr-code]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Radio Group
|
||||
|
||||
[component-header:sl-radio-group]
|
||||
|
||||
Radio Groups are used to group multiple radios so they function as a single control.
|
||||
|
||||
```html preview
|
||||
<sl-radio-group label="Select an item">
|
||||
<sl-radio value="1" checked>Item 1</sl-radio>
|
||||
<sl-radio value="2">Item 2</sl-radio>
|
||||
<sl-radio value="3">Item 3</sl-radio>
|
||||
</sl-radio-group>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Hiding the Fieldset
|
||||
|
||||
You can hide the fieldset and legend that wraps the radio group using the `no-fieldset` attribute. In this case, a label is still required for assistive devices to properly identify the control.
|
||||
|
||||
```html preview
|
||||
<sl-radio-group label="Select an item" no-fieldset>
|
||||
<sl-radio value="1" checked>Item 1</sl-radio>
|
||||
<sl-radio value="2">Item 2</sl-radio>
|
||||
<sl-radio value="3">Item 3</sl-radio>
|
||||
</sl-radio-group>
|
||||
```
|
||||
|
||||
[component-metadata:sl-radio-group]
|
||||
@@ -1,34 +0,0 @@
|
||||
# Radio
|
||||
|
||||
[component-header:sl-radio]
|
||||
|
||||
Radios allow the user to select one option from a group of many.
|
||||
|
||||
Radios are designed to be used with [radio groups](/components/radio-group). As such, all of the examples on this page utilize them to demonstrate their correct usage.
|
||||
|
||||
```html preview
|
||||
<sl-radio-group label="Select an option" no-fieldset>
|
||||
<sl-radio value="1" checked>Option 1</sl-radio>
|
||||
<sl-radio value="2">Option 2</sl-radio>
|
||||
<sl-radio value="3">Option 3</sl-radio>
|
||||
</sl-radio-group>
|
||||
```
|
||||
|
||||
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form) instead.
|
||||
|
||||
## Examples
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable a radio.
|
||||
|
||||
```html preview
|
||||
<sl-radio-group label="Select an option" no-fieldset>
|
||||
<sl-radio value="1" checked>Option 1</sl-radio>
|
||||
<sl-radio value="2">Option 2</sl-radio>
|
||||
<sl-radio value="3">Option 3</sl-radio>
|
||||
<sl-radio value="4" disabled>Disabled</sl-radio>
|
||||
</sl-radio-group>
|
||||
```
|
||||
|
||||
[component-metadata:sl-radio]
|
||||
@@ -1,73 +0,0 @@
|
||||
# Range
|
||||
|
||||
[component-header:sl-range]
|
||||
|
||||
Ranges allow the user to select a single value within a given range using a slider.
|
||||
|
||||
```html preview
|
||||
<sl-range min="0" max="100" step="1"></sl-range>
|
||||
```
|
||||
|
||||
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form) instead.
|
||||
|
||||
## Examples
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` prop to disable a slider.
|
||||
|
||||
```html preview
|
||||
<sl-range min="0" max="100" step="1" disabled></sl-range>
|
||||
```
|
||||
|
||||
### Tooltip Placement
|
||||
|
||||
By default, the tooltip is shown on top. Set `tooltip` to `bottom` to show it below the slider.
|
||||
|
||||
```html preview
|
||||
<sl-range min="0" max="100" step="1" tooltip="bottom"></sl-range>
|
||||
```
|
||||
|
||||
### Disable the Tooltip
|
||||
|
||||
To disable the tooltip, set `tooltip` to `none`.
|
||||
|
||||
```html preview
|
||||
<sl-range min="0" max="100" step="1" tooltip="none"></sl-range>
|
||||
```
|
||||
|
||||
### Custom Tooltip Formatter
|
||||
|
||||
You can change the tooltip's content by setting the `tooltipFormatter` prop to a function that accepts the range's value as an argument.
|
||||
|
||||
```html preview
|
||||
<sl-range min="0" max="100" step="1" class="range-with-custom-formatter"></sl-range>
|
||||
|
||||
<script>
|
||||
const range = document.querySelector('.range-with-custom-formatter');
|
||||
range.tooltipFormatter = value => `Total - ${value}%`;
|
||||
</script>
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the `label` attribute to give the range an accessible label. For labels that contain HTML, use the `label` slot instead.
|
||||
|
||||
```html preview
|
||||
<sl-range label="Volume" min="0" max="100"></sl-input>
|
||||
```
|
||||
|
||||
### Help Text
|
||||
|
||||
Add descriptive help text to a range with the `help-text` attribute. For help texts that contain HTML, use the `help-text` slot instead.
|
||||
|
||||
```html preview
|
||||
<sl-range
|
||||
label="Volume"
|
||||
help-text="Controls the volume of the current song."
|
||||
min="0"
|
||||
max="100"
|
||||
></sl-input>
|
||||
```
|
||||
|
||||
[component-metadata:sl-range]
|
||||