Compare commits
339 commits
Author | SHA1 | Date | |
---|---|---|---|
358288c03c | |||
![]() |
97b3342cf9 | ||
c4e15708d2 | |||
0aeb2b7ec3 | |||
9268f33ab6 | |||
d5f5ce808e | |||
ac0a61d0ea | |||
a9782bb50d | |||
![]() |
1efa01f4e3 | ||
![]() |
680e8c906b | ||
![]() |
e7ec98b178 | ||
![]() |
14f7760ff3 | ||
![]() |
5c8517266c | ||
![]() |
7ef5a41ec0 | ||
![]() |
4c67ac0e8c | ||
![]() |
a1cc4b006b | ||
![]() |
6298cadce2 | ||
![]() |
591b4eafe6 | ||
![]() |
4f745b59b1 | ||
![]() |
118f5cfa60 | ||
![]() |
bf745dd7ce | ||
![]() |
643b1ff1e6 | ||
![]() |
4bd37804a9 | ||
![]() |
929f3a1e69 | ||
![]() |
392eebd7d1 | ||
![]() |
29c25dde87 | ||
![]() |
5ad276cbf9 | ||
![]() |
6f608e470e | ||
![]() |
e85bf59b0f | ||
![]() |
633f94ce25 | ||
![]() |
81c1e1d1a9 | ||
![]() |
af4c6e3253 | ||
![]() |
78b9ae07cf | ||
![]() |
c0f3ca1fa3 | ||
![]() |
4d2a577b0e | ||
![]() |
92b11031c3 | ||
![]() |
6e27739d7e | ||
![]() |
c2384944fb | ||
![]() |
334a4c552b | ||
![]() |
06d4ce1126 | ||
![]() |
b07d926e02 | ||
![]() |
fb11b738f4 | ||
![]() |
d50d8c1329 | ||
![]() |
e50aa4c5e9 | ||
![]() |
30de5161f2 | ||
![]() |
b4901e87f9 | ||
![]() |
414a0bd854 | ||
![]() |
f3420f9272 | ||
![]() |
9bd2bde88c | ||
![]() |
1cba4be635 | ||
![]() |
aa14ddd8dc | ||
![]() |
4d16865561 | ||
![]() |
b1a6b11486 | ||
09d154575c | |||
![]() |
d6cf10f9fd | ||
![]() |
13f96a4fe9 | ||
![]() |
a4db6e4680 | ||
![]() |
d0ff3fecea | ||
![]() |
c0c0f941eb | ||
![]() |
f79ce72a1c | ||
![]() |
0abe83aea9 | ||
![]() |
b3d765f96f | ||
![]() |
d1844bad55 | ||
![]() |
944548dc63 | ||
![]() |
ad65225131 | ||
![]() |
986151fe3e | ||
![]() |
dd285e72a4 | ||
![]() |
814692d9c9 | ||
![]() |
8ed98ad1f1 | ||
![]() |
9bdff22174 | ||
![]() |
234ffaf38c | ||
![]() |
5256243858 | ||
![]() |
e502d1d9cf | ||
![]() |
c73675710f | ||
![]() |
5aa7c19874 | ||
![]() |
25ce684d23 | ||
![]() |
5b539c809c | ||
![]() |
4b5b81a2b5 | ||
![]() |
e6dd753196 | ||
![]() |
1a19aea1fd | ||
![]() |
4c46aa1518 | ||
![]() |
7e4c05a2c7 | ||
![]() |
29c8c870b7 | ||
![]() |
26e099e2cf | ||
![]() |
924edc017a | ||
![]() |
975b2e821a | ||
![]() |
a4ea634b5c | ||
![]() |
bcbb517828 | ||
![]() |
03565d1f78 | ||
![]() |
1d77e18f31 | ||
![]() |
033d0322bb | ||
![]() |
965a16aaec | ||
![]() |
2f2c28b13f | ||
![]() |
21cd3f1775 | ||
![]() |
0853ca3b8f | ||
![]() |
7d05ecc580 | ||
![]() |
89d1fde3d2 | ||
![]() |
59d76181db | ||
![]() |
fcde7eb14f | ||
![]() |
31884a1757 | ||
![]() |
3faabb2348 | ||
![]() |
1ea41f658a | ||
![]() |
a0a20c33b2 | ||
![]() |
061cec876e | ||
![]() |
fb4bc0c6c1 | ||
![]() |
b054f29e74 | ||
![]() |
6b96cd1e34 | ||
![]() |
d407f0e379 | ||
![]() |
b3ec749aaf | ||
![]() |
661ea9039c | ||
![]() |
7bf0df9ec9 | ||
![]() |
f86253d66f | ||
![]() |
ce1d4df9e8 | ||
![]() |
3aab9b640e | ||
![]() |
93a8d49f0a | ||
![]() |
d02c1e4081 | ||
![]() |
6bab48f485 | ||
![]() |
ab410926af | ||
![]() |
205d1f27b2 | ||
![]() |
47c0b5e90e | ||
![]() |
0158fd636a | ||
![]() |
29ce2fe3b1 | ||
![]() |
80d92ae81f | ||
![]() |
251c7681d5 | ||
![]() |
007f56c1b9 | ||
![]() |
7dc741e3b3 | ||
![]() |
0775cf571f | ||
![]() |
e6ca1f85bd | ||
![]() |
0ff115fdfb | ||
![]() |
31b95cbe2b | ||
![]() |
cec0a02c46 | ||
![]() |
ec19766202 | ||
![]() |
6ae1bec42f | ||
![]() |
5635c5461e | ||
![]() |
380e88c72f | ||
![]() |
e089626f81 | ||
![]() |
2888c766b7 | ||
![]() |
1eca8f2e27 | ||
![]() |
9e54d2b0a9 | ||
![]() |
a868e4f550 | ||
![]() |
0a0b8ae809 | ||
![]() |
e9de68fe49 | ||
![]() |
89e0353c47 | ||
![]() |
fcf32cb21b | ||
![]() |
56f597708c | ||
![]() |
b42c0de131 | ||
![]() |
f27f96c9dc | ||
![]() |
c28b117fd1 | ||
![]() |
33e421fffb | ||
![]() |
b01d829819 | ||
![]() |
b4c33eec66 | ||
![]() |
f93f8b6484 | ||
![]() |
c38e5dfbe3 | ||
![]() |
f502e6ca24 | ||
![]() |
640e945959 | ||
![]() |
d5c2b7786d | ||
![]() |
6d9907a06c | ||
![]() |
a37b6c80df | ||
![]() |
b9a3e5a8fc | ||
![]() |
f341a23414 | ||
![]() |
0f0ec230d0 | ||
![]() |
e49791fe55 | ||
![]() |
ba31f1b046 | ||
![]() |
d2a4cb1635 | ||
![]() |
5677222258 | ||
![]() |
4b3e4c9f50 | ||
![]() |
304cad0151 | ||
![]() |
5a96395280 | ||
![]() |
4180f78d95 | ||
![]() |
539c701cd7 | ||
![]() |
796fb962ae | ||
![]() |
42a53522db | ||
![]() |
9513ef2134 | ||
![]() |
606e455e6e | ||
![]() |
30fc4f48c9 | ||
![]() |
54e4287b5f | ||
![]() |
3cba6e8e9c | ||
![]() |
79882fd9b1 | ||
![]() |
40dba08c6a | ||
![]() |
426c5ab303 | ||
![]() |
ebff4940f2 | ||
![]() |
c8ace159da | ||
![]() |
facefc4da5 | ||
![]() |
b2eeed0663 | ||
![]() |
5147cd982f | ||
![]() |
6ac9100a2f | ||
![]() |
819d6e4526 | ||
![]() |
715eaaa408 | ||
![]() |
66ba7fa292 | ||
![]() |
3d361fcb5b | ||
![]() |
b9995b8a63 | ||
![]() |
a396969513 | ||
![]() |
21486e1baa | ||
![]() |
f081304d6f | ||
![]() |
d235fb7552 | ||
![]() |
052ab3bdb3 | ||
![]() |
70ae327f02 | ||
![]() |
d128747240 | ||
![]() |
82c121a85d | ||
![]() |
304100fa5f | ||
![]() |
ddccd5cf80 | ||
![]() |
4fd6f33fe9 | ||
![]() |
b96e3383dc | ||
![]() |
0cb3167a04 | ||
![]() |
97a5edd746 | ||
![]() |
030752b4cc | ||
![]() |
8d7ef9e879 | ||
![]() |
6e39c882ae | ||
![]() |
964e800dae | ||
![]() |
31a8e8c77d | ||
![]() |
17d1487913 | ||
![]() |
065b84f93c | ||
![]() |
a90ceec55e | ||
![]() |
98c4b77648 | ||
![]() |
685ba32d82 | ||
![]() |
0aa0deac32 | ||
![]() |
5e1a44c79e | ||
![]() |
36742b7239 | ||
![]() |
4f1578aa72 | ||
![]() |
4dc020027f | ||
![]() |
e5d4e90805 | ||
![]() |
d6a7f98e3f | ||
![]() |
8fe968fbc6 | ||
![]() |
7db1be51e6 | ||
![]() |
1b27b1553c | ||
![]() |
d8577871b4 | ||
![]() |
a18fc82c89 | ||
![]() |
14cb33854e | ||
![]() |
2c2c8d19f7 | ||
![]() |
ddbd910981 | ||
![]() |
d41738776d | ||
![]() |
9a35744142 | ||
![]() |
06f53bc78f | ||
![]() |
0acc1968c1 | ||
![]() |
1491135302 | ||
![]() |
ef779de6d4 | ||
![]() |
4e2d1562e6 | ||
![]() |
a359349086 | ||
![]() |
e924e56d38 | ||
![]() |
3605a76037 | ||
![]() |
798753ab77 | ||
![]() |
2fd25b7d93 | ||
![]() |
f164bdfb6a | ||
![]() |
a002593b02 | ||
![]() |
2da037944b | ||
![]() |
96657a9c38 | ||
![]() |
7c31381d76 | ||
![]() |
be195e93e6 | ||
![]() |
a5d5b35376 | ||
![]() |
97128a0816 | ||
![]() |
f1485808c9 | ||
![]() |
955b9ca27c | ||
![]() |
a8bfaaa964 | ||
![]() |
3c1ab5c40e | ||
![]() |
29abefd605 | ||
![]() |
66d782bdf0 | ||
![]() |
ca9cd27b0d | ||
![]() |
d4ac8dbec0 | ||
![]() |
49d2e17ca1 | ||
![]() |
3f0b3b106d | ||
![]() |
599db41b00 | ||
![]() |
cb7d8cfa26 | ||
![]() |
6e96ce5b52 | ||
![]() |
b3dd15b781 | ||
![]() |
bc676af5e7 | ||
![]() |
bbfccc00f3 | ||
![]() |
da3ceb901d | ||
![]() |
d2a9c77724 | ||
![]() |
509cece7d5 | ||
![]() |
b386cbb006 | ||
![]() |
fd11d674ea | ||
![]() |
abf7c33b20 | ||
![]() |
8514727e1d | ||
![]() |
9fe00b3ac7 | ||
![]() |
7d222239ed | ||
![]() |
5d6936bff1 | ||
![]() |
cb83cd3386 | ||
![]() |
32b37ea9f9 | ||
![]() |
47accdf654 | ||
![]() |
00a453fe47 | ||
![]() |
b21c746d91 | ||
![]() |
9f4c840c87 | ||
![]() |
7809a2728d | ||
![]() |
ea594da817 | ||
![]() |
315e28bc39 | ||
![]() |
373e018c66 | ||
![]() |
0368417e32 | ||
![]() |
55feb87027 | ||
![]() |
3658257bd0 | ||
![]() |
2393186c43 | ||
![]() |
5fb10d9b8c | ||
![]() |
24b571f440 | ||
![]() |
eaaade22d2 | ||
![]() |
ead1ee2aba | ||
![]() |
9009c013b2 | ||
![]() |
fd118e2c41 | ||
![]() |
a3c09c8bca | ||
![]() |
cee89447db | ||
![]() |
30826e6180 | ||
![]() |
cf6fa87f0d | ||
![]() |
4eaa35394f | ||
![]() |
e6f5248dcc | ||
![]() |
1238356ebf | ||
![]() |
48892f31d3 | ||
![]() |
c1dfdb8a8d | ||
![]() |
431493cb16 | ||
![]() |
32dd989fdf | ||
![]() |
8a9f70a254 | ||
![]() |
43bef7ab36 | ||
![]() |
56806e8225 | ||
![]() |
63868e4587 | ||
![]() |
d85810621b | ||
![]() |
a348c7a4ed | ||
![]() |
a38a003553 | ||
![]() |
e811da3860 | ||
![]() |
a3da67c90c | ||
![]() |
d00c7bc5d5 | ||
![]() |
4c841b67a2 | ||
![]() |
019b0523ec | ||
![]() |
1805c235ed | ||
![]() |
6984787040 | ||
![]() |
d265e31d29 | ||
![]() |
de4bc4e3b0 | ||
![]() |
0556f69a62 | ||
![]() |
96beb00422 | ||
![]() |
21536ded4b | ||
![]() |
eddf262add | ||
![]() |
c6dc470b07 | ||
![]() |
fdd1f7cf50 | ||
![]() |
76e57c5fd5 | ||
![]() |
c1f9716d8b | ||
![]() |
5caf3d9cde | ||
![]() |
e91c060c9e | ||
![]() |
f2dfe8aa8a | ||
![]() |
158f817d5a | ||
![]() |
1927b14b66 | ||
![]() |
2cde19237e | ||
![]() |
677c68d706 | ||
![]() |
994a903342 |
11
.build.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
image: alpine/edge
|
||||||
|
secrets:
|
||||||
|
- bbfcb6dc-7c4a-42ee-a11a-022f0339a133
|
||||||
|
environment:
|
||||||
|
REPO: astro-reactive
|
||||||
|
GH_USER: ayoayco
|
||||||
|
tasks:
|
||||||
|
- push-mirror: |
|
||||||
|
cd ~/"${REPO}"
|
||||||
|
git config --global credential.helper store
|
||||||
|
git push --mirror "https://github.com/${GH_USER}/${REPO}"
|
8
.changeset/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Changesets
|
||||||
|
|
||||||
|
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||||
|
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||||
|
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||||
|
|
||||||
|
We have a quick list of common questions to get you started engaging with this project in
|
||||||
|
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
11
.changeset/config.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
|
||||||
|
"changelog": "@changesets/cli/changelog",
|
||||||
|
"commit": false,
|
||||||
|
"fixed": [],
|
||||||
|
"linked": [],
|
||||||
|
"access": "restricted",
|
||||||
|
"baseBranch": "main",
|
||||||
|
"updateInternalDependencies": "patch",
|
||||||
|
"ignore": []
|
||||||
|
}
|
|
@ -1,17 +1,4 @@
|
||||||
/** @type {import("@types/eslint").Linter.Config} */
|
/** @type {import("@types/eslint").Linter.Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
env: {
|
extends: ["turbo"],
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
plugins: ['@typescript-eslint', 'prettier'],
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:prettier/recommended',
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
// We don't want to leak logging into our user's console unless it's an error
|
|
||||||
'no-console': ['error', { allow: ['warn', 'error'] }],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
76
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
---
|
||||||
|
name: "Bug Report"
|
||||||
|
about: "Report an issue to help the project improve."
|
||||||
|
title: "bug(scope): description "
|
||||||
|
labels: "Type: Bug"
|
||||||
|
---
|
||||||
|
<!--
|
||||||
|
☝️ "scope" in the title could be one of our apps or packages:
|
||||||
|
- form, validator, demo, landing-page, docs...
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Fill up as much information as you can to help us investigate 🙏 -->
|
||||||
|
## **Bug Report**
|
||||||
|
|
||||||
|
### **Describe the bug**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
|
- ***
|
||||||
|
|
||||||
|
### **Is this a regression?**
|
||||||
|
|
||||||
|
<!-- Did this behaviour used to work in the previous version? -->
|
||||||
|
<!-- Yes, the previous version in which this bug was not present was: ... -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **To Reproduce**
|
||||||
|
|
||||||
|
<!-- Steps to reproduce the error:
|
||||||
|
(e.g.:)
|
||||||
|
1. Use x argument / navigate to
|
||||||
|
2. Fill this information
|
||||||
|
3. Go to...
|
||||||
|
4. See error -->
|
||||||
|
|
||||||
|
<!-- Write the steps here (add or remove as many steps as needed)-->
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
4.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Expected behaviour**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
|
- ***
|
||||||
|
|
||||||
|
### **Media proof**
|
||||||
|
|
||||||
|
<!-- If applicable, add screenshots or videos to help explain your problem. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Your environment**
|
||||||
|
|
||||||
|
<!-- use all the applicable bulleted list element for this specific issue,
|
||||||
|
and remove all the bulleted list elements that are not relevant for this issue. -->
|
||||||
|
|
||||||
|
- OS: <!--[e.g. Ubuntu 5.4.0-26-generic x86_64 / Windows 1904 ...]-->
|
||||||
|
- Node version:
|
||||||
|
- Npm version:
|
||||||
|
- Browser name and version:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Additional context**
|
||||||
|
|
||||||
|
<!-- Add any other context or additional information about the problem here.-->
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
<!-- THANK YOU FOR THE CONTRIBUTION! 🚀 -->
|
39
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
name: "Feature Request"
|
||||||
|
about: "Suggest an idea or new feature for this project."
|
||||||
|
title: "feat(scope): description "
|
||||||
|
labels: "Type: Feature"
|
||||||
|
---
|
||||||
|
<!--
|
||||||
|
☝️ "scope" in the title could be one of our apps or packages:
|
||||||
|
- form, validator, demo, landing-page, docs...
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Fill up as much information as you can to help us understand the request 🙏 -->
|
||||||
|
## **Feature Request**
|
||||||
|
|
||||||
|
## **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 [...] -->
|
||||||
|
|
||||||
|
- ***
|
||||||
|
|
||||||
|
## **Describe the solution you'd like**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
|
- ***
|
||||||
|
|
||||||
|
## **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 additional information about the problem here.-->
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
<!-- THANK YOU FOR THE CONTRIBUTION! 🚀 -->
|
BIN
.github/assets/astro-reactive-form-cover.png
vendored
Normal file
After Width: | Height: | Size: 233 KiB |
BIN
.github/assets/astro-reactive-library-cover.png
vendored
Normal file
After Width: | Height: | Size: 232 KiB |
1
.github/assets/logo/astro-reactive-library-logo.svg
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" zoomAndPan="magnify" viewBox="0 0 375 374.999991" height="300" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><clipPath id="702d27c854"><path d="M 124.9375 112.5 L 265 112.5 L 265 262.5 L 124.9375 262.5 Z M 124.9375 112.5 " clip-rule="nonzero"/></clipPath><clipPath id="db9c64370c"><path d="M 169 153 L 189 153 L 189 262.5 L 169 262.5 Z M 169 153 " clip-rule="nonzero"/></clipPath></defs><g clip-path="url(#702d27c854)"><path fill="#004aad" d="M 124.9375 262.386719 C 150.457031 262.386719 167.863281 230.78125 175.042969 207.984375 C 174.734375 207.984375 174.421875 207.984375 174.117188 207.984375 C 172.316406 207.984375 171.382812 206.539062 170.707031 204.882812 C 168.757812 204.882812 166.808594 204.882812 164.859375 204.882812 C 164.226562 206.949219 162.894531 208.851562 161.359375 209.652344 C 158.1875 211.300781 155.019531 212.949219 151.84375 214.597656 C 149.707031 215.710938 147.953125 214.273438 147.953125 211.40625 C 147.953125 208.566406 147.953125 205.730469 147.953125 202.894531 C 147.953125 200.027344 150.296875 197.605469 151.84375 195.644531 C 154.96875 191.703125 158.089844 187.757812 161.214844 183.808594 C 160.820312 178.402344 160.429688 172.996094 160.035156 167.585938 C 160.035156 150.964844 167.257812 136.027344 178.738281 125.710938 C 190.214844 136.027344 197.433594 150.964844 197.433594 167.585938 C 197.042969 172.992188 196.652344 178.402344 196.261719 183.808594 C 199.386719 187.757812 202.507812 191.699219 205.632812 195.644531 C 207.179688 197.605469 209.523438 200.027344 209.523438 202.894531 C 209.523438 205.730469 209.523438 208.570312 209.523438 211.40625 C 209.523438 214.273438 207.769531 215.714844 205.632812 214.597656 C 202.460938 212.949219 199.289062 211.300781 196.117188 209.652344 C 194.582031 208.851562 193.25 206.949219 192.613281 204.882812 C 190.664062 204.882812 188.714844 204.882812 186.769531 204.882812 C 186.09375 206.539062 185.164062 207.984375 183.359375 207.984375 C 183.050781 207.984375 182.746094 207.984375 182.433594 207.984375 C 189.613281 230.777344 207.019531 262.386719 232.539062 262.386719 C 241.136719 262.386719 256.164062 262.386719 264.761719 262.386719 L 227.265625 210.183594 C 264.992188 194.1875 265.183594 149.125 244.851562 128.890625 C 234.769531 118.621094 218.894531 112.628906 195.941406 112.628906 C 172.269531 112.628906 148.605469 112.628906 124.9375 112.628906 C 124.9375 162.550781 124.9375 212.46875 124.9375 262.386719 Z M 124.9375 262.386719 " fill-opacity="1" fill-rule="nonzero"/></g><g clip-path="url(#db9c64370c)"><path fill="#ff1616" d="M 186.925781 231.277344 C 187.671875 231.277344 188.273438 231.886719 188.273438 232.617188 L 188.273438 254.832031 C 188.273438 255.566406 187.664062 256.175781 186.929688 256.175781 L 186.925781 256.175781 C 186.191406 256.175781 185.582031 255.574219 185.582031 254.832031 L 185.582031 232.617188 C 185.578125 231.878906 186.183594 231.277344 186.925781 231.277344 Z M 170.546875 231.277344 C 171.292969 231.277344 171.894531 231.886719 171.894531 232.617188 L 171.894531 254.832031 C 171.894531 255.566406 171.28125 256.175781 170.550781 256.175781 L 170.546875 256.175781 C 169.8125 256.175781 169.203125 255.574219 169.203125 254.832031 L 169.203125 232.617188 C 169.203125 231.878906 169.804688 231.277344 170.546875 231.277344 Z M 178.738281 169.320312 C 183.066406 169.320312 186.578125 165.816406 186.578125 161.5 C 186.578125 157.183594 183.066406 153.683594 178.738281 153.683594 C 174.40625 153.683594 170.898438 157.183594 170.898438 161.5 C 170.894531 165.820312 174.40625 169.320312 178.738281 169.320312 Z M 178.734375 221.804688 C 179.480469 221.804688 180.082031 222.414062 180.082031 223.144531 L 180.082031 261.042969 C 180.082031 261.773438 179.46875 262.382812 178.738281 262.382812 L 178.734375 262.382812 C 178 262.382812 177.390625 261.78125 177.390625 261.042969 L 177.390625 223.148438 C 177.390625 222.410156 177.992188 221.804688 178.734375 221.804688 Z M 178.734375 221.804688 " fill-opacity="1" fill-rule="evenodd"/></g></svg>
|
After Width: | Height: | Size: 4 KiB |
BIN
.github/assets/logo/min-banner.png
vendored
Normal file
After Width: | Height: | Size: 5.6 KiB |
30
.github/pull_request_template.md
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
## type(scope): description
|
||||||
|
<!--
|
||||||
|
☝️ Put your PR title up here!
|
||||||
|
|
||||||
|
"scope" could be one of our apps or packages:
|
||||||
|
- form, validator, demo, landing-page, docs...
|
||||||
|
|
||||||
|
✨ Example PR titles:
|
||||||
|
- feat(form): implement new FormControl isValid state
|
||||||
|
- fix(validator): correct the variable name typo causing errors
|
||||||
|
- style(landing-page): update the logo in the landing page app
|
||||||
|
- docs: update content project CONTRIBUTING.md
|
||||||
|
-->
|
||||||
|
|
||||||
|
Fixes # <!-- 👈🏻 Put the issue number here! -->
|
||||||
|
|
||||||
|
Description of changes: <!-- 👇🏻 List the changes done! -->
|
||||||
|
-
|
||||||
|
-
|
||||||
|
|
||||||
|
Tag a reviewer: @
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
- [ ] I have ran the build command to make sure apps are working: `npm run build`
|
||||||
|
- [ ] I have ran the tests to make sure nothing is broken: `npm run test`
|
||||||
|
- [ ] I have ran the Astro checker: `npm run check`
|
||||||
|
- [ ] I have ran the linter to make sure code is clean: `npm run lint`
|
||||||
|
- [ ] I have reviewed my own code to remove changes that are not needed
|
||||||
|
|
||||||
|
<!-- THANK YOU FOR THE CONTRIBUTION! 🚀 -->
|
32
.github/workflows/build-and-test.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# This workflow will do a clean installation 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: Build and Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-test:
|
||||||
|
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: npm ci
|
||||||
|
- run: npm run check
|
||||||
|
- run: npm run build
|
||||||
|
- run: npm run test
|
||||||
|
- run: npm run lint
|
26
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
name: Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup Node.js 16
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm i
|
||||||
|
- name: Create Release Pull Request
|
||||||
|
uses: changesets/action@v1
|
||||||
|
with:
|
||||||
|
commit: "chore: Update version for release"
|
||||||
|
title: "chore: Update version for release"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
5
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
coverage
|
||||||
|
dist
|
||||||
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
|
@ -10,3 +12,6 @@ pnpm-debug.log*
|
||||||
*~
|
*~
|
||||||
*swp
|
*swp
|
||||||
*swo
|
*swo
|
||||||
|
|
||||||
|
.turbo/
|
||||||
|
|
||||||
|
|
9
.gitpod.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# This configuration file was automatically generated by Gitpod.
|
||||||
|
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
|
||||||
|
# and commit this file to your remote git repository to share the goodness with others.
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- init: npm install && npm run build
|
||||||
|
command: npm run start
|
||||||
|
|
||||||
|
|
1
.npmrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
legacy-peer-deps=true
|
7
.vscode/settings.json
vendored
|
@ -3,6 +3,9 @@
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": true
|
"source.fixAll": true
|
||||||
},
|
},
|
||||||
"cSpell.words": ["Astro"],
|
"cSpell.words": ["Astro", "maxlength"],
|
||||||
"prettier.documentSelectors": ["**/*.astro"]
|
"prettier.documentSelectors": ["**/*.astro"],
|
||||||
|
"[astro]": {
|
||||||
|
"editor.defaultFormatter": "astro-build.astro-vscode"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
129
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
- Demonstrating empathy and kindness toward other people
|
||||||
|
- Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
- Giving and gracefully accepting constructive feedback
|
||||||
|
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
- Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
- The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
- Public or private harassment
|
||||||
|
- Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
- Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
ayo@ayco.io.
|
||||||
|
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
150
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|

|
||||||
|
|
||||||
|
# Hi, explorer! 🚀
|
||||||
|
|
||||||
|
Thanks for checking out the Astro Reactive Library! Welcome to a new adventure.
|
||||||
|
|
||||||
|
This is a library of components and utilities for building reactive user interfaces with [Astro](https://astro.build)--a modern web framework.
|
||||||
|
|
||||||
|
There's a lot of opportunity to contribute. A good start will be to understand what Astro is, and how to set up a basic Astro project. For this, the [Astro website](https://astro.build) and [documentation](https://docs.astro.build/en/getting-started/) are good places to start.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Any contribution is welcome. Feel free to look around to find something that interests you. :)
|
||||||
|
|
||||||
|
The [issues page](https://github.com/astro-reactive/astro-reactive/issues?q=is%3Aopen+is%3Aissue+label%3A%22accepting+PRs%22) contains some ideas, but they should not limit your contribution.
|
||||||
|
|
||||||
|
If you don't find anything there, we are happy to help you get your contribution in.
|
||||||
|
|
||||||
|
You can always [create a new issue](https://github.com/astro-reactive/astro-reactive/issues/new/choose) for your own idea, [post on our discussions](https://github.com/astro-reactive/astro-reactive/discussions) or join our [Discord](https://discord.gg/kkvW7GYNAp).
|
||||||
|
|
||||||
|
## The Astro Reactive Library
|
||||||
|
|
||||||
|
This project aims to be a library that developers will use to create reactive UIs with Astro.
|
||||||
|
|
||||||
|
The project is made up of [NPM workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces), which are node projects that share a singular root package. It is good to understand the basics of this, but basically, the project will have multiple packages (under the `packages` directory) that share a common root package information.
|
||||||
|
|
||||||
|
We are using [Turborepo](https://turbo.build/repo) as our monorepo build system.
|
||||||
|
|
||||||
|
### Packages:
|
||||||
|
|
||||||
|
1. [demo](https://github.com/astro-reactive/astro-reactive/tree/main/apps/demo) in the directory `apps/demo`
|
||||||
|
- Astro web application that we use to test and demonstrate the library components
|
||||||
|
1. [form](https://github.com/astro-reactive/astro-reactive/tree/main/packages/form) in the directory `packages/form`
|
||||||
|
- component that allows developers to programmatically build a form
|
||||||
|
1. [validator](https://github.com/astro-reactive/astro-reactive/tree/main/packages/validator) in the directory `packages/astro-reactive-validator`
|
||||||
|
- component that allows developers to set up validators for their forms easily
|
||||||
|
|
||||||
|
### Apps
|
||||||
|
1. [docs](https://github.com/astro-reactive/astro-reactive/tree/main/apps/docs) - in the directory `apps/docs`
|
||||||
|
- Astro website for the library's extensive documentation
|
||||||
|
1. [landing-page](https://github.com/astro-reactive/astro-reactive/tree/main/apps/landing-page) - in the directory `apps/landing-page`
|
||||||
|
|
||||||
|
- Astro website for the library's introductory landing page
|
||||||
|
|
||||||
|
[](https://gitpod.io/#https://github.com/astro-reactive/astro-reactive.git)
|
||||||
|
|
||||||
|
## Running locally
|
||||||
|
|
||||||
|
We mainly use the `demo` app to see changes we make on the packages. Do the following to start hacking:
|
||||||
|
|
||||||
|
1. Fork the project then clone to your computer
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@github.com:<your-user-name>/astro-reactive.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Go into the project directory
|
||||||
|
|
||||||
|
```
|
||||||
|
cd astro-reactive
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install the node dependencies
|
||||||
|
|
||||||
|
```
|
||||||
|
npm i
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Run the demo application
|
||||||
|
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Open the demo application on you browser. Browse to the address
|
||||||
|
|
||||||
|
```
|
||||||
|
https://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
# Applications
|
||||||
|
|
||||||
|
We also maintain the documentation website and the project landing page in this repository. The source for these applications is found in the `apps` directory.
|
||||||
|
|
||||||
|
You can start the dev server for the docs and landing-page websites with the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run docs
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run landing-page
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the linter and tests
|
||||||
|
|
||||||
|
Please run the linter and tests before creating a PR to avoid delays in PR reviews. Fix all linting errors or failing tests whey you run the following commands.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
✨ _HINT: Some linting errors could be automatically fixed with a command_
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run lint:fix
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hacking with the packages
|
||||||
|
|
||||||
|
As mentioned above, this project involves packages that are intended to be used in Astro applications. The demo app is our way to test and play with the packages.
|
||||||
|
|
||||||
|
If you plan to add features or fix bugs that are found in the packages, such as `@astro-reactive/form`, you can find the source code for this inside the `packages` directory.
|
||||||
|
|
||||||
|
Thank you again for your interest in contributing!
|
||||||
|
|
||||||
|
## Next Actions
|
||||||
|
|
||||||
|
✍️ Read on [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/); you'll see this used around issues, PRs, and commit messages
|
||||||
|
|
||||||
|
🏘️ Read our [community guidelines](https://github.com/astro-reactive/astro-reactive/blob/main/CODE_OF_CONDUCT.md)
|
||||||
|
|
||||||
|
📝 Check the [discussion board](https://github.com/astro-reactive/astro-reactive/discussions) for announcements or post your messages and questions
|
||||||
|
|
||||||
|
💬 Hang-out with the team on our [Discord](https://discord.gg/kkvW7GYNAp) to share feedback, get support, or just have some laughs over memes 😅
|
||||||
|
|
||||||
|
🛠️ Create a [new issue](https://github.com/astro-reactive/astro-reactive/issues/new/choose) for bugs found or improvement ideas
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
## Play around examples:
|
||||||
|
|
||||||
|
<a href="https://stackblitz.com/edit/github-ze9ebb-tthuka?file=package.json,src%2Fpages%2Findex.astro">
|
||||||
|
<img
|
||||||
|
src="https://developer.stackblitz.com/img/open_in_stackblitz_small.svg"
|
||||||
|
alt="Play around in Stackblitz"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<a href="https://codesandbox.io/s/astro-reactive-library-u72dgj?file=/src/pages/index.astro">
|
||||||
|
<img
|
||||||
|
src="https://img.shields.io/badge/Open%20in-CodeSandbox-040404?logo=codesandbox"
|
||||||
|
alt="CodeSandbox"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
-->
|
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Astro Reactive
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
54
MONOREPO.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# Monorepo Guide
|
||||||
|
This project is a monorepo configured with Turborepo + NPM workspace. Here are some common development scripts.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
To clean and remove files, such as `node_modules`, `dist`, `.turbo` in every workspace.
|
||||||
|
```bash
|
||||||
|
npm run clean
|
||||||
|
```
|
||||||
|
|
||||||
|
Filtering workspaces. For more detail [https://turbo.build/repo/docs/core-concepts/monorepos/filtering](https://turbo.build/repo/docs/core-concepts/monorepos/filtering).
|
||||||
|
```bash
|
||||||
|
# Append the `npm run` command with `-- --filter=<workspace>`
|
||||||
|
|
||||||
|
# with workspace name
|
||||||
|
npm run test -- --filter=validator
|
||||||
|
|
||||||
|
# Or equivalent
|
||||||
|
npm run test -- --filter=packages/validator
|
||||||
|
```
|
||||||
|
|
||||||
|
To run tests.
|
||||||
|
```bash
|
||||||
|
# Run all tests in every workspace.
|
||||||
|
npm run test
|
||||||
|
|
||||||
|
# Run test in selected workspace.
|
||||||
|
npm run test -- --filter=<workspace>
|
||||||
|
|
||||||
|
npm run test -- --filter=form
|
||||||
|
|
||||||
|
# Run test in watch mode. Can be filtered too.
|
||||||
|
npm run test:watch -- --filter=<workspace>
|
||||||
|
```
|
||||||
|
|
||||||
|
To lint workspaces.
|
||||||
|
```bash
|
||||||
|
# Lint all workspaces. Can be filtered.
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
# Lint and fix.
|
||||||
|
npm run lint:fix
|
||||||
|
```
|
||||||
|
|
||||||
|
To build workspaces.
|
||||||
|
```bash
|
||||||
|
# Build all workspaces. Can be filtered.
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
To typecheck workspaces.
|
||||||
|
```bash
|
||||||
|
# Typecheck all workspaces. Can be filtered.
|
||||||
|
npm run check
|
||||||
|
```
|
168
README.md
|
@ -1,81 +1,121 @@
|
||||||
# Astro Reactive Form 🔥
|
> [!WARNING]
|
||||||
|
>
|
||||||
|
> Please read: [an important announcement about the project](https://github.com/astro-reactive/astro-reactive/discussions/304)
|
||||||
|
>
|
||||||
|
> *As of now we still are in an exploratory phase and the library is not ready for production. We appreciate the interest. We look forward to your feedback and welcome all kinds of contribution. :)*
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/astro-reactive-form)
|
<p align="center">
|
||||||
[](https://www.npmjs.com/package/astro-reactive-form)
|
<img src="https://raw.githubusercontent.com/astro-reactive/astro-reactive/main/.github/assets/logo/min-banner.png" alt="Astro Reactive Library Logo">
|
||||||
[](https://www.npmjs.com/package/astro-reactive-form)
|
<br />
|
||||||
[](https://github.com/ayoayco/astro-reactive-form)
|
<strong>Astro Reactive Library</strong>
|
||||||
|
<br />
|
||||||
|
Server-Side Rendered, Dynamic Components
|
||||||
|
<br />
|
||||||
|
Let your data build your UI with <a href="https://astro.build">Astro</a>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/astro-reactive/astro-reactive/actions/workflows/build-and-test.yml">
|
||||||
|
<img src="https://github.com/astro-reactive/astro-reactive/actions/workflows/build-and-test.yml/badge.svg?branch=main" alt="Build & Test Result" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/astro-reactive/astro-reactive">
|
||||||
|
<img alt="Last Commit" src="https://img.shields.io/github/last-commit/astro-reactive/astro-reactive?logo=github" />
|
||||||
|
</a>
|
||||||
|
<a href="https://gitpod.io/#https://github.com/astro-reactive/astro-reactive.git">
|
||||||
|
<img
|
||||||
|
src="https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod"
|
||||||
|
alt="Contribute with Gitpod"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
|
||||||
The Reactive Form component for [Astro](https://astro.build) 🔥
|
<br />
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
|
||||||
_[All contributions are welcome.](https://github.com/ayoayco/astro-reactive-form/issues)_
|
| Package | Release notes | Description |
|
||||||
|
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||||
|
| [form](https://github.com/astro-reactive/astro-reactive/blob/main/packages/form/README.md) | [](./packages/form/CHANGELOG.md) | a dynamic form which can be modified programmatically |
|
||||||
|
| [validator](https://github.com/astro-reactive/astro-reactive/blob/main/packages/validator/README.md) | [](./packages/validator/CHANGELOG.md) | validators for editable fields |
|
||||||
|
| data-grid | 🛠 | a dynamic data grid of values |
|
||||||
|
| themes | 🛠 | easy-to-use, accessible, consistent cross-browser styles |
|
||||||
|
| viz | 🛠 | data visualization that emits and responds to events |
|
||||||
|
|
||||||
## Installation
|
# Running locally
|
||||||
|
|
||||||
|
We mainly use the `demo` app to see changes we make on the packages. Do the following to start hacking:
|
||||||
|
|
||||||
|
1. Fork the project then clone to your computer
|
||||||
|
|
||||||
```
|
```
|
||||||
npm i astro-reactive-form
|
git clone git@github.com:<your-user-name>/astro-reactive.git
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
2. Go into the project directory
|
||||||
|
|
||||||
```astro
|
```
|
||||||
---
|
cd astro-reactive
|
||||||
import Form, { FormControl, FormGroup } from 'astro-reactive-form';
|
|
||||||
|
|
||||||
// example of a form control
|
|
||||||
const radio: FormControl = {
|
|
||||||
name: 'is-good-looking',
|
|
||||||
type: 'radio',
|
|
||||||
label: 'Is Good Looking?',
|
|
||||||
value: 'checked',
|
|
||||||
labelPosition: 'right',
|
|
||||||
};
|
|
||||||
|
|
||||||
const form = new FormGroup([
|
|
||||||
// this is just an array of FormControl
|
|
||||||
{
|
|
||||||
name: 'first-name',
|
|
||||||
value: 'Ayo',
|
|
||||||
label: 'First Name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'last-name',
|
|
||||||
value: 'Ayco',
|
|
||||||
label: 'Last Name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'is-awesome',
|
|
||||||
type: 'checkbox',
|
|
||||||
label: 'Is Awesome?',
|
|
||||||
value: 'checked',
|
|
||||||
labelPosition: 'right',
|
|
||||||
},
|
|
||||||
radio, // the form control we declared earlier
|
|
||||||
]);
|
|
||||||
---
|
|
||||||
|
|
||||||
<Form formGroup={form} />
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Result:
|
3. Install the node dependencies
|
||||||
|
|
||||||

|
```
|
||||||
|
npm i
|
||||||
|
```
|
||||||
|
|
||||||
# Future Plans
|
4. Run the demo application
|
||||||
|
|
||||||
Currently this only supports very basic form creation, but the goal of the project is ambitious:
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
1. Themes - unstyled, light mode, dark mode, compact, large
|
5. Open the demo application on your browser. Browse to the address:
|
||||||
1. FormGroup class
|
|
||||||
1. `get(controlName: string)` - returns the FormControl with matching name
|
|
||||||
1. `statusChanges` - observable that emits the form status when it changes
|
|
||||||
1. `valueChanges` - observable that emits the values of all controls when they change
|
|
||||||
1. FormControl class
|
|
||||||
1. `setValue(value)` - set the value of the control programmatically
|
|
||||||
1. `statusChanges` - observable that emits the control status when it changes
|
|
||||||
1. `valueChanges` - observable that emits the control value when it changes
|
|
||||||
1. `value` - property that reflects the control value
|
|
||||||
1. Validator library for common validation scenarios
|
|
||||||
|
|
||||||
... and so much more
|
```
|
||||||
|
https://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
_All contributions are welcome. Let's make the fastest web form component powered by Astro_
|
6. To run the tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other apps
|
||||||
|
|
||||||
|
We also maintain the docs website and the project landing page in this repository. Run the following to start the dev servers:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run docs
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run landing-page
|
||||||
|
```
|
||||||
|
|
||||||
|
# Contributors
|
||||||
|
|
||||||
|
This project is only possible because of the support and contribution of our community ❤️
|
||||||
|
|
||||||
|
<a href="https://github.com/astro-reactive/astro-reactive/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=astro-reactive/astro-reactive" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
👉 _[Join our contributors!](https://github.com/astro-reactive/astro-reactive/blob/main/CONTRIBUTING.md)_
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
## Play around examples:
|
||||||
|
|
||||||
|
<a href="https://stackblitz.com/edit/github-ze9ebb-tthuka?file=package.json,src%2Fpages%2Findex.astro">
|
||||||
|
<img
|
||||||
|
src="https://developer.stackblitz.com/img/open_in_stackblitz_small.svg"
|
||||||
|
alt="Play around in Stackblitz"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<a href="https://codesandbox.io/s/astro-reactive-library-u72dgj?file=/src/pages/index.astro">
|
||||||
|
<img
|
||||||
|
src="https://img.shields.io/badge/Open%20in-CodeSandbox-040404?logo=codesandbox"
|
||||||
|
alt="CodeSandbox"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
2
apps/demo/.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
5
apps/demo/.eslintrc.cjs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/** @type {import("@types/eslint").Linter.Config} */
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
extends: ['@astro-reactive/eslint-config-custom'],
|
||||||
|
};
|
25
apps/demo/.prettierrc.cjs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/** @type {import("@types/prettier").Options} */
|
||||||
|
module.exports = {
|
||||||
|
printWidth: 100,
|
||||||
|
semi: true,
|
||||||
|
singleQuote: true,
|
||||||
|
tabWidth: 2,
|
||||||
|
trailingComma: 'es5',
|
||||||
|
useTabs: true,
|
||||||
|
plugins: ['prettier-plugin-astro'],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: '*.astro',
|
||||||
|
options: {
|
||||||
|
parser: 'astro',
|
||||||
|
astroAllowShorthand: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['.*', '*.json', '*.md', '*.toml', '*.yml'],
|
||||||
|
options: {
|
||||||
|
useTabs: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
36
apps/demo/CHANGELOG.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# @astro-reactive/demo
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- a1cc4b0: Update homepage to https://astro-reactive.js.org
|
||||||
|
- Updated dependencies [a1cc4b0]
|
||||||
|
- @astro-reactive/validator@0.4.1
|
||||||
|
- @astro-reactive/form@0.9.1
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 4d2a577: Support Astro 3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [4d2a577]
|
||||||
|
- @astro-reactive/validator@0.4.0
|
||||||
|
- @astro-reactive/form@0.9.0
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- fb11b73: Initial `create-astro-reactive` package
|
||||||
|
Update packages' meta information (author, homepage)
|
||||||
|
Upadte LICENSE owner info to `astro-reactive` organization
|
||||||
|
- 30de516: Change the default of `validateOnLoad` property to true, making server-side rendering validation the default behavior for the `Form` component.
|
||||||
|
Update the demo `index.astro` page by removing the `validateOnLoad` property/directive on the example which should still result to server-side rendered validation results.
|
||||||
|
- Updated dependencies [fb11b73]
|
||||||
|
- Updated dependencies [30de516]
|
||||||
|
- @astro-reactive/validator@0.3.3
|
||||||
|
- @astro-reactive/form@0.8.0
|
7
apps/demo/README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|

|
||||||
|
|
||||||
|
# Demo App for Astro Reactive Library
|
||||||
|
|
||||||
|
Start the dev server by running: `npm start`
|
||||||
|
|
||||||
|
👉 _[Join our contributors!](https://github.com/astro-reactive/astro-reactive/blob/main/CONTRIBUTING.md)_
|
4
apps/demo/astro.config.mjs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
|
// https://astro.build/config
|
||||||
|
export default defineConfig({});
|
46
apps/demo/package.json
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"name": "@astro-reactive/demo",
|
||||||
|
"description": "Demo App for Astro Reactive Library",
|
||||||
|
"version": "0.1.1",
|
||||||
|
"author": "astro-reactive",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "astro dev",
|
||||||
|
"start": "astro dev",
|
||||||
|
"check": "astro check",
|
||||||
|
"build": "astro build",
|
||||||
|
"preview": "astro preview",
|
||||||
|
"astro": "astro",
|
||||||
|
"format": "prettier -w .",
|
||||||
|
"lint": "eslint . --ext .ts,.js",
|
||||||
|
"lint:fix": "eslint --fix . --ext .ts,.js",
|
||||||
|
"clean": "rimraf node_modules .turbo dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@astro-reactive/form": "*",
|
||||||
|
"@astro-reactive/validator": "*",
|
||||||
|
"@astrojs/check": "^0.2.0",
|
||||||
|
"astro": "^4.0.3",
|
||||||
|
"typescript": "^5.2.2"
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/astro-reactive/astro-reactive.git"
|
||||||
|
},
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/astro-reactive/astro-reactive/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://astro-reactive.js.org",
|
||||||
|
"devDependencies": {
|
||||||
|
"@astro-reactive/eslint-config-custom": "*",
|
||||||
|
"@astro-reactive/tsconfig": "*",
|
||||||
|
"@types/eslint": "^8.44.3",
|
||||||
|
"@types/prettier": "^3.0.0",
|
||||||
|
"eslint": "^8.50.0",
|
||||||
|
"prettier": "^3.0.3",
|
||||||
|
"prettier-plugin-astro": "^0.12.0",
|
||||||
|
"rimraf": "^5.0.1"
|
||||||
|
}
|
||||||
|
}
|
BIN
apps/demo/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
13
apps/demo/public/favicon.svg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36">
|
||||||
|
<path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/>
|
||||||
|
<path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#000"/>
|
||||||
|
<stop offset="1" stop-color="#000" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<style>
|
||||||
|
@media (prefers-color-scheme:dark){:root{filter:invert(100%)}}
|
||||||
|
</style>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 873 B |
30
apps/demo/src/components/Layout.astro
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
import Nav from './Nav.astro';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
title: string;
|
||||||
|
theme?: 'dark' | 'light';
|
||||||
|
}
|
||||||
|
const { theme = 'light', title } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<html lang="en" class={theme}>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
<title>{title} | Astro Reactive Demo</title>
|
||||||
|
</head>
|
||||||
|
<body class={theme}>
|
||||||
|
<Nav />
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<slot />
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
html.dark,
|
||||||
|
body.dark {
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
25
apps/demo/src/components/Nav.astro
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
const links = [
|
||||||
|
{ label: 'Home', url: '/' },
|
||||||
|
{ label: 'Pizza Delivery', url: '/pizza-delivery' },
|
||||||
|
{ label: 'Job Application', url: '/job-application' },
|
||||||
|
{ label: 'Docs Examples', url: '/examples' },
|
||||||
|
{ label: 'Experimental', url: '/experimental' },
|
||||||
|
];
|
||||||
|
---
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
{links.map((link) => <a href={link.url}>{link.label}</a>)}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
nav a::after {
|
||||||
|
content: ' | ';
|
||||||
|
}
|
||||||
|
nav a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
nav a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
1
apps/demo/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="astro/client" />
|
85
apps/demo/src/pages/examples/form-component.astro
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
---
|
||||||
|
import type { Submit } from '@astro-reactive/common';
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import Layout from '../../components/Layout.astro';
|
||||||
|
|
||||||
|
const simpleForm = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
value: 'awesome_dev',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'comment',
|
||||||
|
label: 'Feedback',
|
||||||
|
type: 'textarea',
|
||||||
|
value: 'Nice!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'size',
|
||||||
|
label: 'Size',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: ['S', 'M', 'L', 'XL', 'XXL'],
|
||||||
|
placeholder: '-- Please choose an option --',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const nameForm = new FormGroup(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'firstName',
|
||||||
|
label: 'First Name',
|
||||||
|
value: 'John',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lastName',
|
||||||
|
label: 'Last Name',
|
||||||
|
value: 'Doe',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'Name'
|
||||||
|
);
|
||||||
|
|
||||||
|
const skills = new FormGroup(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'JavaScript',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'JavaScript',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TypeScript',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'TypeScript',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'React',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'React',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Vue',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'Vue',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'Skills'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* comment
|
||||||
|
*/
|
||||||
|
|
||||||
|
const submitControl: Submit = {
|
||||||
|
name: 'submit',
|
||||||
|
type: 'submit',
|
||||||
|
};
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Form API examples">
|
||||||
|
<h2>Simple Form</h2>
|
||||||
|
<Form formGroups={simpleForm} submitControl={submitControl} />
|
||||||
|
|
||||||
|
<h2>Form with nested form groups</h2>
|
||||||
|
<Form formGroups={[nameForm, skills]} />
|
||||||
|
</Layout>
|
9
apps/demo/src/pages/examples/index.astro
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
import Layout from '../../components/Layout.astro';
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Docs Examples">
|
||||||
|
<ul>
|
||||||
|
<li><a href="./examples/form-component">Form Component</a></li>
|
||||||
|
</ul>
|
||||||
|
</Layout>
|
23
apps/demo/src/pages/experimental/hyperdrive.astro
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
import Layout from '../../components/Layout.astro';
|
||||||
|
const Counter = {
|
||||||
|
count: 0,
|
||||||
|
increment() {
|
||||||
|
this.count++;
|
||||||
|
},
|
||||||
|
decrement() {
|
||||||
|
this.count--;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Hyperdrive Experiment">
|
||||||
|
<!-- PROBLEM STATEMENT
|
||||||
|
This is the problem that `hyperdrive` is trying to solve.
|
||||||
|
After this is rendered in the server, the Counter object is not serialized.
|
||||||
|
When the HTML reaches the browser, it has no idea what Counter is.
|
||||||
|
-->
|
||||||
|
<button onclick="Counter.increment()">
|
||||||
|
{Counter.count}
|
||||||
|
</button>
|
||||||
|
</Layout>
|
9
apps/demo/src/pages/experimental/index.astro
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
import Layout from '../../components/Layout.astro';
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Experimental Demos">
|
||||||
|
<ul>
|
||||||
|
<li><a href="./experimental/hyperdrive">Hyperdrive</a></li>
|
||||||
|
</ul>
|
||||||
|
</Layout>
|
114
apps/demo/src/pages/index.astro
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
---
|
||||||
|
import Form, { FormGroup, FormControl } from '@astro-reactive/form';
|
||||||
|
import type { ControlConfig } from '@astro-reactive/form';
|
||||||
|
import type { Submit } from '@astro-reactive/common';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
import Layout from '../components/Layout.astro';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
validators: [
|
||||||
|
{
|
||||||
|
validator: Validators.required,
|
||||||
|
category: 'info',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
validators: [
|
||||||
|
{ validator: Validators.required },
|
||||||
|
{ validator: Validators.email, category: 'warn' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
type: 'password',
|
||||||
|
validators: [Validators.required, Validators.minLength(8)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rating',
|
||||||
|
label: 'Rating',
|
||||||
|
type: 'radio',
|
||||||
|
options: ['1', '2', '3', '4', '5'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'agreement',
|
||||||
|
label: 'Agreement',
|
||||||
|
type: 'radio',
|
||||||
|
value: 'yes',
|
||||||
|
options: [
|
||||||
|
{ label: 'Agree', value: 'yes' },
|
||||||
|
{ label: 'Disagree', value: 'no' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'size',
|
||||||
|
label: 'Size',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: ['S', 'M', 'L', 'XL', 'XXL'],
|
||||||
|
placeholder: '-- Please choose an option --',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'comment',
|
||||||
|
label: 'Feedback',
|
||||||
|
type: 'textarea',
|
||||||
|
value: 'Nice!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'terms',
|
||||||
|
label: 'Terms and Conditions',
|
||||||
|
type: 'checkbox',
|
||||||
|
validators: [Validators.requiredChecked],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
form.name = 'Simple Form';
|
||||||
|
|
||||||
|
const config: ControlConfig = {
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'isAwesome',
|
||||||
|
label: 'is Awesome?',
|
||||||
|
};
|
||||||
|
|
||||||
|
// insert a control
|
||||||
|
form.controls.push(new FormControl(config));
|
||||||
|
|
||||||
|
// set the value of multiple controls
|
||||||
|
form.setValue({
|
||||||
|
username: 'RAMOOOON',
|
||||||
|
isAwesome: 'checked',
|
||||||
|
});
|
||||||
|
|
||||||
|
// set the value of a specific control
|
||||||
|
const ratingControl = form.get('rating');
|
||||||
|
ratingControl?.setValue('5');
|
||||||
|
|
||||||
|
// setting an invalid value will cause errors as server-rendered
|
||||||
|
form.get('email')?.setValue('invalid-email');
|
||||||
|
|
||||||
|
// switch between light and dark mode
|
||||||
|
const title = 'Form Demo';
|
||||||
|
const theme = 'dark';
|
||||||
|
|
||||||
|
const submit: Submit = {
|
||||||
|
name: 'submit',
|
||||||
|
type: 'submit',
|
||||||
|
value: "Let's go!",
|
||||||
|
};
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title={title} theme={theme}>
|
||||||
|
<Form
|
||||||
|
showValidationHints
|
||||||
|
formGroups={form}
|
||||||
|
theme={theme}
|
||||||
|
submitControl={submit}
|
||||||
|
action="https://localhost"
|
||||||
|
method="post"
|
||||||
|
/>
|
||||||
|
</Layout>
|
112
apps/demo/src/pages/job-application.astro
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
---
|
||||||
|
import Form, { FormControl, FormGroup } from '@astro-reactive/form';
|
||||||
|
import type { ControlConfig } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
import type { Submit } from '@astro-reactive/common';
|
||||||
|
import Layout from '../components/Layout.astro';
|
||||||
|
|
||||||
|
const infoForm = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'firstName',
|
||||||
|
label: 'First Name',
|
||||||
|
placeholder: 'ex. John',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lastName',
|
||||||
|
label: 'Last Name',
|
||||||
|
placeholder: 'ex. Doe',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
placeholder: 'ex. john.doe@email.com',
|
||||||
|
validators: [Validators.email, Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'whyHire',
|
||||||
|
label: 'Why should we hire you?',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'country',
|
||||||
|
label: 'Country of Residence',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: ['U.S.A', 'Canada', 'Mexico', 'Cuba', 'Guatamala', 'Greenland', 'Haiti'],
|
||||||
|
placeholder: 'Choose Your Country',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'eligible',
|
||||||
|
label: 'Are you eligible to work?',
|
||||||
|
type: 'radio',
|
||||||
|
options: [
|
||||||
|
{ label: 'Yes', value: 'yes' },
|
||||||
|
{ label: 'No', value: 'no' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const skillsForm = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'js',
|
||||||
|
label: 'Javascript',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'java',
|
||||||
|
label: 'Java',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'astro',
|
||||||
|
label: 'Astro',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cpp',
|
||||||
|
label: 'C/C++',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sql',
|
||||||
|
label: 'SQL',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'devops',
|
||||||
|
label: 'DevOps',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const resume: ControlConfig = {
|
||||||
|
name: 'resume',
|
||||||
|
label: 'Upload Resume',
|
||||||
|
type: 'file',
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit: Submit = {
|
||||||
|
name: 'submit',
|
||||||
|
type: 'submit',
|
||||||
|
value: "Let's go!",
|
||||||
|
};
|
||||||
|
|
||||||
|
const values = {
|
||||||
|
firstName: 'James',
|
||||||
|
lastName: 'Bond',
|
||||||
|
email: 'james.bond@gmail.com',
|
||||||
|
country: 'U.S.A',
|
||||||
|
eligible: 'yes',
|
||||||
|
};
|
||||||
|
|
||||||
|
infoForm.setValue(values);
|
||||||
|
|
||||||
|
infoForm.name = 'Application Form';
|
||||||
|
skillsForm.name = 'Skills';
|
||||||
|
|
||||||
|
skillsForm.controls.push(new FormControl(resume));
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Programmer Job Application">
|
||||||
|
<Form showValidationHints formGroups={[infoForm, skillsForm]} submitControl={submit} />
|
||||||
|
</Layout>
|
96
apps/demo/src/pages/pizza-delivery.astro
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
import Layout from '../components/Layout.astro';
|
||||||
|
|
||||||
|
const baseForm = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'crust',
|
||||||
|
label: 'Crust',
|
||||||
|
type: 'radio',
|
||||||
|
options: [{ label: 'Garlic', value: 'garlic' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'size',
|
||||||
|
label: 'Size',
|
||||||
|
type: 'radio',
|
||||||
|
options: ['Small', 'Medium', 'Large'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sauce',
|
||||||
|
label: 'Sauce',
|
||||||
|
type: 'radio',
|
||||||
|
options: ['Tomato', 'Barbeque'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const toppingsForm = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'mushrooms',
|
||||||
|
label: 'Mushrooms',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extraCheese',
|
||||||
|
label: 'Extra Cheese',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onions',
|
||||||
|
label: 'Onions',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'peppers',
|
||||||
|
label: 'Peppers',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'pepperoni',
|
||||||
|
label: 'Pepperoni',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sausage',
|
||||||
|
label: 'Sausage',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'chicken',
|
||||||
|
label: 'Chicken',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'pineapple',
|
||||||
|
label: 'Pineapple',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const infoForm = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: 'Name',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'address',
|
||||||
|
label: 'Delivery Address',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'contact',
|
||||||
|
label: 'Contact Number',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
baseForm.name = 'Base';
|
||||||
|
toppingsForm.name = 'Toppings';
|
||||||
|
infoForm.name = 'Customer Info';
|
||||||
|
infoForm.get('contact')?.setValidators([Validators.minLength(9)]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Pizza Form Demo">
|
||||||
|
<Form showValidationHints formGroups={[baseForm, toppingsForm, infoForm]} />
|
||||||
|
</Layout>
|
6
apps/demo/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "@astro-reactive/tsconfig/base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
2
apps/docs/.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
5
apps/docs/.eslintrc.cjs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/** @type {import("@types/eslint").Linter.Config} */
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
extends: ['@astro-reactive/eslint-config-custom'],
|
||||||
|
};
|
19
apps/docs/.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# build output
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# macOS-specific files
|
||||||
|
.DS_Store
|
24
apps/docs/.prettierrc.cjs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/** @type {import("@types/prettier").Options} */
|
||||||
|
module.exports = {
|
||||||
|
printWidth: 100,
|
||||||
|
semi: true,
|
||||||
|
singleQuote: true,
|
||||||
|
tabWidth: 2,
|
||||||
|
trailingComma: "es5",
|
||||||
|
useTabs: true,
|
||||||
|
plugins: ['prettier-plugin-astro'],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: "*.astro",
|
||||||
|
options: {
|
||||||
|
parser: "astro",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: [".*", "*.json", "*.md", "*.toml", "*.yml"],
|
||||||
|
options: {
|
||||||
|
useTabs: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
27
apps/docs/CHANGELOG.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# @astro-reactive/docs
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- a1cc4b0: Update homepage to https://astro-reactive.js.org
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 4d2a577: Support Astro 3
|
||||||
|
|
||||||
|
## 0.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 334a4c5: - Update documentation links to release notes
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- fb11b73: Initial `create-astro-reactive` package
|
||||||
|
Update packages' meta information (author, homepage)
|
||||||
|
Upadte LICENSE owner info to `astro-reactive` organization
|
7
apps/docs/README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|

|
||||||
|
|
||||||
|
# Documentation Website
|
||||||
|
|
||||||
|
Start the dev server by running: `npm run docs`
|
||||||
|
|
||||||
|
👉 _[Join our contributors!](https://github.com/astro-reactive/astro-reactive/blob/main/CONTRIBUTING.md)_
|
14
apps/docs/astro.config.mjs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import preact from '@astrojs/preact';
|
||||||
|
import react from '@astrojs/react';
|
||||||
|
|
||||||
|
// https://astro.build/config
|
||||||
|
export default defineConfig({
|
||||||
|
integrations: [
|
||||||
|
// Enable Preact to support Preact JSX components.
|
||||||
|
preact(),
|
||||||
|
// Enable React for the Algolia search component.
|
||||||
|
react(),
|
||||||
|
],
|
||||||
|
site: `https://docs.astro-reactive.js.org`,
|
||||||
|
});
|
55
apps/docs/package.json
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"name": "@astro-reactive/docs",
|
||||||
|
"type": "module",
|
||||||
|
"version": "0.1.1",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "astro dev",
|
||||||
|
"start": "astro dev",
|
||||||
|
"docs": "astro dev",
|
||||||
|
"check": "astro check",
|
||||||
|
"build": "astro build",
|
||||||
|
"preview": "astro preview",
|
||||||
|
"astro": "astro",
|
||||||
|
"format": "prettier -w .",
|
||||||
|
"lint": "eslint . --ext .ts,.js",
|
||||||
|
"lint:fix": "eslint --fix . --ext .ts,.js",
|
||||||
|
"clean": "rimraf node_modules .turbo dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@algolia/client-search": "^4.20.0",
|
||||||
|
"@astrojs/preact": "^3.0.0",
|
||||||
|
"@astrojs/react": "^3.0.2",
|
||||||
|
"@docsearch/css": "^3.5.2",
|
||||||
|
"@docsearch/react": "^3.5.2",
|
||||||
|
"@types/node": "^20.6.5",
|
||||||
|
"@types/react": "^18.2.22",
|
||||||
|
"@types/react-dom": "^18.2.7",
|
||||||
|
"astro": "^4.0.3",
|
||||||
|
"preact": "^10.17.1",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
|
},
|
||||||
|
"description": "```bash npm create astro@latest -- --template docs ```",
|
||||||
|
"main": "index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/astro-reactive/astro-reactive.git"
|
||||||
|
},
|
||||||
|
"author": "astro-reactive",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/astro-reactive/astro-reactive/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://astro-reactive.js.org",
|
||||||
|
"devDependencies": {
|
||||||
|
"@astro-reactive/eslint-config-custom": "*",
|
||||||
|
"@astro-reactive/tsconfig": "*",
|
||||||
|
"@types/eslint": "^8.44.3",
|
||||||
|
"@types/prettier": "^2.7.3",
|
||||||
|
"eslint": "^8.50.0",
|
||||||
|
"prettier": "^3.0.3",
|
||||||
|
"prettier-plugin-astro": "^0.12.0",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
|
}
|
||||||
|
}
|
BIN
apps/docs/public/default-og-image.png
Normal file
After Width: | Height: | Size: 731 KiB |
BIN
apps/docs/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
13
apps/docs/public/favicon.svg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36">
|
||||||
|
<path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/>
|
||||||
|
<path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#000"/>
|
||||||
|
<stop offset="1" stop-color="#000" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<style>
|
||||||
|
@media (prefers-color-scheme:dark){:root{filter:invert(100%)}}
|
||||||
|
</style>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 873 B |
4
apps/docs/public/make-scrollable-code-focusable.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
Array.from(document.getElementsByTagName('pre')).forEach((element) => {
|
||||||
|
element.setAttribute('tabindex', '0');
|
||||||
|
});
|
171
apps/docs/src/components/Footer/AvatarList.astro
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
---
|
||||||
|
// fetch all commits for just this page's path
|
||||||
|
type Props = {
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
const { path } = Astro.props as Props;
|
||||||
|
const resolvedPath = `apps/docs/${path}`;
|
||||||
|
const url = `https://api.github.com/repos/astro-reactive/astro-reactive/commits?path=${resolvedPath}`;
|
||||||
|
const commitsURL = `https://github.com/astro-reactive/astro-reactive/commits/main/${resolvedPath}`;
|
||||||
|
|
||||||
|
type Commit = {
|
||||||
|
author: {
|
||||||
|
id: string;
|
||||||
|
login: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getCommits(url: string) {
|
||||||
|
try {
|
||||||
|
const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN ?? 'hello';
|
||||||
|
if (!token) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`;
|
||||||
|
|
||||||
|
const res = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Authorization: auth,
|
||||||
|
'User-Agent': 'astro-docs/1.0',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Request to fetch commits failed. Reason: ${res.statusText}
|
||||||
|
Message: ${data.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data as Commit[];
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`[error] /src/components/AvatarList.astro
|
||||||
|
${(e as any)?.message ?? e}`);
|
||||||
|
return [] as Commit[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDups(arr: Commit[]) {
|
||||||
|
const map = new Map<string, Commit['author']>();
|
||||||
|
|
||||||
|
for (let item of arr) {
|
||||||
|
const author = item.author;
|
||||||
|
// Deduplicate based on author.id
|
||||||
|
map.set(author.id, { login: author.login, id: author.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...map.values()];
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await getCommits(url);
|
||||||
|
const unique = removeDups(data);
|
||||||
|
const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors
|
||||||
|
const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! -->
|
||||||
|
<div class="contributors">
|
||||||
|
<ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}>
|
||||||
|
{
|
||||||
|
recentContributors.map((item) => (
|
||||||
|
<li>
|
||||||
|
<a href={`https://github.com/${item.login}`}>
|
||||||
|
<img
|
||||||
|
alt={`Contributor ${item.login}`}
|
||||||
|
title={`Contributor ${item.login}`}
|
||||||
|
width="64"
|
||||||
|
height="64"
|
||||||
|
src={`https://avatars.githubusercontent.com/u/${item.id}`}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
{
|
||||||
|
additionalContributors > 0 && (
|
||||||
|
<span>
|
||||||
|
<a href={commitsURL}>{`and ${additionalContributors} additional contributor${
|
||||||
|
additionalContributors > 1 ? 's' : ''
|
||||||
|
}.`}</a>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{unique.length === 0 && <a href={commitsURL}>Contributors</a>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.avatar-list {
|
||||||
|
--avatar-size: 2.5rem;
|
||||||
|
--avatar-count: 3;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
list-style: none;
|
||||||
|
/* Default to displaying most of the avatar to
|
||||||
|
enable easier access on touch devices, ensuring
|
||||||
|
the WCAG touch target size is met or exceeded */
|
||||||
|
grid-template-columns: repeat(var(--avatar-count), max(44px, calc(var(--avatar-size) / 1.15)));
|
||||||
|
/* `padding` matches added visual dimensions of
|
||||||
|
the `box-shadow` to help create a more accurate
|
||||||
|
computed component size */
|
||||||
|
padding: 0.08em;
|
||||||
|
font-size: var(--avatar-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (any-hover: hover) and (any-pointer: fine) {
|
||||||
|
.avatar-list {
|
||||||
|
/* We create 1 extra cell to enable the computed
|
||||||
|
width to match the final visual width */
|
||||||
|
grid-template-columns: repeat(calc(var(--avatar-count) + 1), calc(var(--avatar-size) / 1.75));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-list li {
|
||||||
|
width: var(--avatar-size);
|
||||||
|
height: var(--avatar-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-list li:hover ~ li a,
|
||||||
|
.avatar-list li:focus-within ~ li a {
|
||||||
|
transform: translateX(33%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-list img,
|
||||||
|
.avatar-list a {
|
||||||
|
display: block;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-list a {
|
||||||
|
transition: transform 180ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-list img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-list a:focus {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
/* Double-layer trick to work for dark and light backgrounds */
|
||||||
|
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contributors {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contributors > * + * {
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
}
|
||||||
|
</style>
|
19
apps/docs/src/components/Footer/Footer.astro
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
import AvatarList from './AvatarList.astro';
|
||||||
|
type Props = {
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
const { path } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<AvatarList path={path} />
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
footer {
|
||||||
|
margin-top: auto;
|
||||||
|
padding: 2rem;
|
||||||
|
border-top: 3px solid var(--theme-divider);
|
||||||
|
}
|
||||||
|
</style>
|
44
apps/docs/src/components/HeadCommon.astro
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
import '../styles/theme.css';
|
||||||
|
import '../styles/index.css';
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Global Metadata -->
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
|
||||||
|
<link rel="sitemap" href="/sitemap.xml" />
|
||||||
|
|
||||||
|
<!-- Preload Fonts -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Scrollable a11y code helper -->
|
||||||
|
<script src="/make-scrollable-code-focusable.js" is:inline></script>
|
||||||
|
|
||||||
|
<!-- This is intentionally inlined to avoid FOUC -->
|
||||||
|
<script is:inline>
|
||||||
|
const root = document.documentElement;
|
||||||
|
const theme = localStorage.getItem('theme');
|
||||||
|
if (theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
root.classList.add('theme-dark');
|
||||||
|
} else {
|
||||||
|
root.classList.remove('theme-dark');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
|
<!-- <script async src="https://www.googletagmanager.com/gtag/js?id=G-TEL60V1WM9" is:inline></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', 'G-TEL60V1WM9');
|
||||||
|
</script> -->
|
47
apps/docs/src/components/HeadSEO.astro
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
import { SITE, OPEN_GRAPH } from '../config';
|
||||||
|
import type { Frontmatter } from '../config';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
frontmatter: Frontmatter;
|
||||||
|
canonicalUrl: URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { frontmatter, canonicalUrl } = Astro.props as Props;
|
||||||
|
const formattedContentTitle = `${frontmatter.title} 🚀 ${SITE.title}`;
|
||||||
|
const imageSrc = frontmatter.image?.src ?? OPEN_GRAPH.image.src;
|
||||||
|
const canonicalImageSrc = new URL(imageSrc, Astro.site);
|
||||||
|
const imageAlt = frontmatter.image?.alt ?? OPEN_GRAPH.image.alt;
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Page Metadata -->
|
||||||
|
<link rel="canonical" href={canonicalUrl} />
|
||||||
|
|
||||||
|
<!-- OpenGraph Tags -->
|
||||||
|
<meta property="og:title" content={formattedContentTitle} />
|
||||||
|
<meta property="og:type" content="article" />
|
||||||
|
<meta property="og:url" content={canonicalUrl} />
|
||||||
|
<meta property="og:locale" content={frontmatter.ogLocale ?? SITE.defaultLanguage} />
|
||||||
|
<meta property="og:image" content={canonicalImageSrc} />
|
||||||
|
<meta property="og:image:alt" content={imageAlt} />
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
property="og:description"
|
||||||
|
content={frontmatter.description ?? SITE.description}
|
||||||
|
/>
|
||||||
|
<meta property="og:site_name" content={SITE.title} />
|
||||||
|
|
||||||
|
<!-- Twitter Tags -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:site" content={OPEN_GRAPH.twitter} />
|
||||||
|
<meta name="twitter:title" content={formattedContentTitle} />
|
||||||
|
<meta name="twitter:description" content={frontmatter.description ?? SITE.description} />
|
||||||
|
<meta name="twitter:image" content={canonicalImageSrc} />
|
||||||
|
<meta name="twitter:image:alt" content={imageAlt} />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense?
|
||||||
|
Docs: https://developers.google.com/search/docs/advanced/structured-data/intro-structured-data
|
||||||
|
https://www.npmjs.com/package/schema-dts seems like a great resource for implementing this.
|
||||||
|
Even better, there's a React component that integrates with `schema-dts`: https://github.com/google/react-schemaorg
|
||||||
|
-->
|
152
apps/docs/src/components/Header/Header.astro
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
---
|
||||||
|
import { getLanguageFromURL, KNOWN_LANGUAGE_CODES } from '../../languages';
|
||||||
|
import ThemeToggleButton from './ThemeToggleButton';
|
||||||
|
import * as CONFIG from '../../config';
|
||||||
|
// import AstroLogo from "./AstroLogo.astro";
|
||||||
|
import SkipToContent from './SkipToContent.astro';
|
||||||
|
import SidebarToggle from './SidebarToggle';
|
||||||
|
import LanguageSelect from './LanguageSelect';
|
||||||
|
// import Search from "./Search";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
currentPage: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { currentPage } = Astro.props as Props;
|
||||||
|
const lang = getLanguageFromURL(currentPage);
|
||||||
|
---
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<SkipToContent />
|
||||||
|
<nav class="nav-wrapper" title="Top Navigation">
|
||||||
|
<div class="menu-toggle">
|
||||||
|
<SidebarToggle client:idle />
|
||||||
|
</div>
|
||||||
|
<div class="logo flex">
|
||||||
|
<a href="/">
|
||||||
|
<h1>{CONFIG.SITE.title ?? 'Documentation'}</h1>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="flex-grow: 1;"></div>
|
||||||
|
{KNOWN_LANGUAGE_CODES.length > 1 && <LanguageSelect lang={lang} client:idle />}
|
||||||
|
<!-- TODO: enable search -->
|
||||||
|
<!-- <div class="search-item">
|
||||||
|
<Search client:idle />
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<ThemeToggleButton client:visible />
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
z-index: 11;
|
||||||
|
height: var(--theme-navbar-height);
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--theme-navbar-bg);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 30px;
|
||||||
|
font-size: 2rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
color: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
gap: 0.25em;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo a {
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em 0.25em;
|
||||||
|
margin: -0.5em -0.25em;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo a {
|
||||||
|
transition: color 100ms ease-out;
|
||||||
|
color: var(--theme-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo a:hover,
|
||||||
|
.logo a:focus {
|
||||||
|
color: var(--theme-text-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo h1 {
|
||||||
|
display: none;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 1em;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 82em;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
header {
|
||||||
|
position: static;
|
||||||
|
padding: 2rem 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo h1 {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Style Algolia */
|
||||||
|
:root {
|
||||||
|
--docsearch-primary-color: var(--theme-accent);
|
||||||
|
--docsearch-logo-color: var(--theme-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-item {
|
||||||
|
display: none;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-right: 0.7rem;
|
||||||
|
display: flex;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
.search-item {
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style is:global>
|
||||||
|
.search-item > * {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
</style>
|
47
apps/docs/src/components/Header/LanguageSelect.css
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
.language-select {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 48px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.33em 0.5em;
|
||||||
|
overflow: visible;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
background-color: var(--theme-bg);
|
||||||
|
border-color: var(--theme-text-lighter);
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
outline: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-property: border-color, color;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
.language-select-wrapper .language-select:hover,
|
||||||
|
.language-select-wrapper .language-select:focus {
|
||||||
|
color: var(--theme-text);
|
||||||
|
border-color: var(--theme-text-light);
|
||||||
|
}
|
||||||
|
.language-select-wrapper {
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.language-select-wrapper > svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
left: 10px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
.language-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
49
apps/docs/src/components/Header/LanguageSelect.tsx
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/** @jsxImportSource react */
|
||||||
|
import type { FunctionComponent } from 'react';
|
||||||
|
import './LanguageSelect.css';
|
||||||
|
import { KNOWN_LANGUAGES, langPathRegex } from '../../languages';
|
||||||
|
|
||||||
|
const LanguageSelect: FunctionComponent<{ lang: string }> = ({ lang }) => {
|
||||||
|
return (
|
||||||
|
<div className="language-select-wrapper">
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
focusable="false"
|
||||||
|
role="img"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 88.6 77.3"
|
||||||
|
height="1.2em"
|
||||||
|
width="1.2em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<select
|
||||||
|
className="language-select"
|
||||||
|
value={lang}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newLang = e.target.value;
|
||||||
|
let actualDest = window.location.pathname.replace(langPathRegex, '/');
|
||||||
|
if (actualDest == '/') actualDest = `/introduction`;
|
||||||
|
window.location.pathname = '/' + newLang + actualDest;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Object.entries(KNOWN_LANGUAGES).map(([key, value]) => {
|
||||||
|
return (
|
||||||
|
<option value={value} key={value}>
|
||||||
|
<span>{key}</span>
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LanguageSelect;
|
76
apps/docs/src/components/Header/Search.css
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/** Style Algolia */
|
||||||
|
:root {
|
||||||
|
--docsearch-primary-color: var(--theme-accent);
|
||||||
|
--docsearch-logo-color: var(--theme-text);
|
||||||
|
}
|
||||||
|
.search-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.33em 0.5em;
|
||||||
|
overflow: visible;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
background-color: var(--theme-divider);
|
||||||
|
border-color: var(--theme-divider);
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
outline: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-property: border-color, color;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
.search-input:hover,
|
||||||
|
.search-input:focus {
|
||||||
|
color: var(--theme-text);
|
||||||
|
border-color: var(--theme-text-light);
|
||||||
|
}
|
||||||
|
.search-input:hover::placeholder,
|
||||||
|
.search-input:focus::placeholder {
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
}
|
||||||
|
.search-input::placeholder {
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
}
|
||||||
|
.search-hint {
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
right: 19px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
display: none;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
letter-spacing: 0.125em;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
pointer-events: none;
|
||||||
|
border-color: var(--theme-text-lighter);
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
line-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
.search-hint {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ *\
|
||||||
|
DocSearch (Algolia)
|
||||||
|
\* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
.DocSearch-Modal .DocSearch-Hit a {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid var(--theme-accent);
|
||||||
|
}
|
97
apps/docs/src/components/Header/Search.tsx
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/** @jsxImportSource react */
|
||||||
|
import { useState, useCallback, useRef } from 'react';
|
||||||
|
import { ALGOLIA } from '../../config';
|
||||||
|
import '@docsearch/css';
|
||||||
|
import './Search.css';
|
||||||
|
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
import * as docSearchReact from '@docsearch/react';
|
||||||
|
|
||||||
|
/** FIXME: This is still kinda nasty, but DocSearch is not ESM ready. */
|
||||||
|
const DocSearchModal =
|
||||||
|
docSearchReact.DocSearchModal || (docSearchReact as any).default.DocSearchModal;
|
||||||
|
const useDocSearchKeyboardEvents =
|
||||||
|
docSearchReact.useDocSearchKeyboardEvents ||
|
||||||
|
(docSearchReact as any).default.useDocSearchKeyboardEvents;
|
||||||
|
|
||||||
|
export default function Search() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const searchButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const [initialQuery, setInitialQuery] = useState('');
|
||||||
|
|
||||||
|
const onOpen = useCallback(() => {
|
||||||
|
setIsOpen(true);
|
||||||
|
}, [setIsOpen]);
|
||||||
|
|
||||||
|
const onClose = useCallback(() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
}, [setIsOpen]);
|
||||||
|
|
||||||
|
const onInput = useCallback(
|
||||||
|
(e: KeyboardEvent) => {
|
||||||
|
setIsOpen(true);
|
||||||
|
setInitialQuery(e.key);
|
||||||
|
},
|
||||||
|
[setIsOpen, setInitialQuery]
|
||||||
|
);
|
||||||
|
|
||||||
|
useDocSearchKeyboardEvents({
|
||||||
|
isOpen,
|
||||||
|
onOpen,
|
||||||
|
onClose,
|
||||||
|
onInput,
|
||||||
|
searchButtonRef,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button type="button" ref={searchButtonRef} onClick={onOpen} className="search-input">
|
||||||
|
<svg width="24" height="24" fill="none">
|
||||||
|
<path
|
||||||
|
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span>Search</span>
|
||||||
|
|
||||||
|
<span className="search-hint">
|
||||||
|
<span className="sr-only">Press </span>
|
||||||
|
|
||||||
|
<kbd>/</kbd>
|
||||||
|
|
||||||
|
<span className="sr-only"> to search</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isOpen &&
|
||||||
|
createPortal(
|
||||||
|
<DocSearchModal
|
||||||
|
initialQuery={initialQuery}
|
||||||
|
initialScrollY={window.scrollY}
|
||||||
|
onClose={onClose}
|
||||||
|
indexName={ALGOLIA.indexName}
|
||||||
|
appId={ALGOLIA.appId}
|
||||||
|
apiKey={ALGOLIA.apiKey}
|
||||||
|
transformItems={(items) => {
|
||||||
|
return items.map((item) => {
|
||||||
|
// We transform the absolute URL into a relative URL to
|
||||||
|
// work better on localhost, preview URLS.
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = item.url;
|
||||||
|
const hash = a.hash === '#overview' ? '' : a.hash;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
url: `${a.pathname}${hash}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
document.body
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
44
apps/docs/src/components/Header/SidebarToggle.tsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/** @jsxImportSource preact */
|
||||||
|
import type { FunctionalComponent } from 'preact';
|
||||||
|
import { useState, useEffect } from 'preact/hooks';
|
||||||
|
|
||||||
|
const MenuToggle: FunctionalComponent = () => {
|
||||||
|
const [sidebarShown, setSidebarShown] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const body = document.querySelector('body')!;
|
||||||
|
if (sidebarShown) {
|
||||||
|
body.classList.add('mobile-sidebar-toggle');
|
||||||
|
} else {
|
||||||
|
body.classList.remove('mobile-sidebar-toggle');
|
||||||
|
}
|
||||||
|
}, [sidebarShown]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-pressed={sidebarShown ? 'true' : 'false'}
|
||||||
|
id="menu-toggle"
|
||||||
|
onClick={() => setSidebarShown(!sidebarShown)}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="1em"
|
||||||
|
height="1em"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 6h16M4 12h16M4 18h16"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span className="sr-only">Toggle sidebar</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MenuToggle;
|
26
apps/docs/src/components/Header/SkipToContent.astro
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
type Props = {};
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href="#article" class="sr-only focus:not-sr-only skiplink"><span>Skip to Content</span></a>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.skiplink,
|
||||||
|
.skiplink:focus,
|
||||||
|
.skiplink:focus-visible {
|
||||||
|
position: absolute;
|
||||||
|
padding: 0.25em;
|
||||||
|
font-size: larger;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 9;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
background-color: var(--theme-text-accent);
|
||||||
|
color: var(--theme-bg);
|
||||||
|
border-radius: 0.25em;
|
||||||
|
outline: var(--theme-bg) solid 1px;
|
||||||
|
outline-offset: 0;
|
||||||
|
}
|
||||||
|
</style>
|
37
apps/docs/src/components/Header/ThemeToggleButton.css
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
.theme-toggle {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25em;
|
||||||
|
padding: 0.33em 0.67em;
|
||||||
|
border-radius: 99em;
|
||||||
|
background-color: var(--theme-code-inline-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle > label:focus-within {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle > label {
|
||||||
|
color: var(--theme-code-inline-text);
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle .checked {
|
||||||
|
color: var(--theme-accent);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[name='theme-toggle'] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
82
apps/docs/src/components/Header/ThemeToggleButton.tsx
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import type { FunctionalComponent } from 'preact';
|
||||||
|
import { useState, useEffect } from 'preact/hooks';
|
||||||
|
import './ThemeToggleButton.css';
|
||||||
|
|
||||||
|
const themes = ['light', 'dark'];
|
||||||
|
|
||||||
|
const icons = [
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>,
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
||||||
|
</svg>,
|
||||||
|
];
|
||||||
|
|
||||||
|
const ThemeToggle: FunctionalComponent = () => {
|
||||||
|
const [theme, setTheme] = useState(() => {
|
||||||
|
if (import.meta.env.SSR) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (typeof localStorage !== undefined && localStorage.getItem('theme')) {
|
||||||
|
return localStorage.getItem('theme');
|
||||||
|
}
|
||||||
|
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
return 'dark';
|
||||||
|
}
|
||||||
|
return 'light';
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
if (theme === 'light') {
|
||||||
|
root.classList.remove('theme-dark');
|
||||||
|
} else {
|
||||||
|
root.classList.add('theme-dark');
|
||||||
|
}
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="theme-toggle">
|
||||||
|
{themes.map((t, i) => {
|
||||||
|
const icon = icons[i];
|
||||||
|
const checked = t === theme;
|
||||||
|
return (
|
||||||
|
<label className={checked ? ' checked' : ''}>
|
||||||
|
{icon}
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme-toggle"
|
||||||
|
checked={checked}
|
||||||
|
value={t}
|
||||||
|
title={`Use ${t} theme`}
|
||||||
|
aria-label={`Use ${t} theme`}
|
||||||
|
onChange={() => {
|
||||||
|
localStorage.setItem('theme', t);
|
||||||
|
setTheme(t);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThemeToggle;
|
119
apps/docs/src/components/LeftSidebar/LeftSidebar.astro
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
---
|
||||||
|
import { getLanguageFromURL } from '../../languages';
|
||||||
|
import { SIDEBAR } from '../../config';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
currentPage: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { currentPage } = Astro.props as Props;
|
||||||
|
const currentPageMatch = currentPage.endsWith('/')
|
||||||
|
? currentPage.slice(1, -1)
|
||||||
|
: currentPage.slice(1);
|
||||||
|
const langCode = getLanguageFromURL(currentPage);
|
||||||
|
const sidebar = SIDEBAR[langCode];
|
||||||
|
---
|
||||||
|
|
||||||
|
<nav aria-labelledby="grid-left">
|
||||||
|
<ul class="nav-groups">
|
||||||
|
{
|
||||||
|
Object.entries(sidebar).map(([header, children]) => (
|
||||||
|
<li>
|
||||||
|
<div class="nav-group">
|
||||||
|
<h2>{header}</h2>
|
||||||
|
<ul>
|
||||||
|
{children.map((child) => {
|
||||||
|
const url = Astro.site?.pathname + child.link;
|
||||||
|
return (
|
||||||
|
<li class="nav-link">
|
||||||
|
<a href={url} aria-current={currentPageMatch === child.link ? 'page' : false}>
|
||||||
|
{child.text}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script is:inline>
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
var target = document.querySelector('[aria-current="page"]');
|
||||||
|
if (target && target.offsetTop > window.innerHeight - 100) {
|
||||||
|
document.querySelector('.nav-groups').scrollTop = target.offsetTop;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
nav {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-groups {
|
||||||
|
height: 100%;
|
||||||
|
padding: 2rem;
|
||||||
|
overflow-x: visible;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-groups > li + li {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-groups > :first-child {
|
||||||
|
padding-top: var(--doc-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-groups > :last-child {
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
margin-bottom: var(--theme-navbar-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0.1rem 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link a {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin: 1px;
|
||||||
|
padding: 0.3rem 1rem;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link a:hover,
|
||||||
|
.nav-link a:focus {
|
||||||
|
background-color: var(--theme-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link a[aria-current='page'] {
|
||||||
|
color: var(--theme-text-accent);
|
||||||
|
background-color: var(--theme-bg-accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
.nav-groups {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style is:global>
|
||||||
|
:root.theme-dark .nav-link a[aria-current='page'] {
|
||||||
|
color: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
}
|
||||||
|
</style>
|
53
apps/docs/src/components/PageContent/PageContent.astro
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
import type { Frontmatter } from '../../config';
|
||||||
|
import MoreMenu from '../RightSidebar/MoreMenu.astro';
|
||||||
|
import TableOfContents from '../RightSidebar/TableOfContents';
|
||||||
|
import type { MarkdownHeading } from 'astro';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
frontmatter: Frontmatter;
|
||||||
|
headings: MarkdownHeading[];
|
||||||
|
githubEditUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { frontmatter, headings, githubEditUrl } = Astro.props as Props;
|
||||||
|
const title = frontmatter.title;
|
||||||
|
---
|
||||||
|
|
||||||
|
<article id="article" class="content">
|
||||||
|
<section class="main-section">
|
||||||
|
<h1 class="content-title" id="overview">{title}</h1>
|
||||||
|
<nav class="block sm:hidden">
|
||||||
|
<TableOfContents client:media="(max-width: 50em)" headings={headings} />
|
||||||
|
</nav>
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
<nav class="block sm:hidden">
|
||||||
|
<MoreMenu editHref={githubEditUrl} />
|
||||||
|
</nav>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.content {
|
||||||
|
padding: 0;
|
||||||
|
max-width: 75ch;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > section {
|
||||||
|
margin-bottom: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
.sm\:hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
75
apps/docs/src/components/RightSidebar/MoreMenu.astro
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
import * as CONFIG from '../../config';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
editHref: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { editHref } = Astro.props as Props;
|
||||||
|
const showMoreSection = CONFIG.COMMUNITY_INVITE_URL;
|
||||||
|
---
|
||||||
|
|
||||||
|
{showMoreSection && <h2 class="heading">More</h2>}
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
editHref && (
|
||||||
|
<li class={`heading-link depth-2`}>
|
||||||
|
<a class="edit-on-github" href={editHref} target="_blank">
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
focusable="false"
|
||||||
|
data-prefix="fas"
|
||||||
|
data-icon="pen"
|
||||||
|
class="svg-inline--fa fa-pen fa-w-16"
|
||||||
|
role="img"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
height="1em"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Edit this page</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CONFIG.COMMUNITY_INVITE_URL && (
|
||||||
|
<li class={`heading-link depth-2`}>
|
||||||
|
<a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank">
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
focusable="false"
|
||||||
|
data-prefix="fas"
|
||||||
|
data-icon="comment-alt"
|
||||||
|
class="svg-inline--fa fa-comment-alt fa-w-16"
|
||||||
|
role="img"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
height="1em"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Join our community</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.edit-on-github {
|
||||||
|
text-decoration: none;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
34
apps/docs/src/components/RightSidebar/RightSidebar.astro
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
import TableOfContents from './TableOfContents';
|
||||||
|
import MoreMenu from './MoreMenu.astro';
|
||||||
|
import type { MarkdownHeading } from 'astro';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
headings: MarkdownHeading[];
|
||||||
|
githubEditUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { headings, githubEditUrl } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<nav class="sidebar-nav" aria-labelledby="grid-right">
|
||||||
|
<div class="sidebar-nav-inner">
|
||||||
|
<TableOfContents client:media="(min-width: 50em)" headings={headings} />
|
||||||
|
<MoreMenu editHref={githubEditUrl} />
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sidebar-nav {
|
||||||
|
width: 100%;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav-inner {
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
padding-top: var(--doc-padding);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
</style>
|
56
apps/docs/src/components/RightSidebar/TableOfContents.tsx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import type { FunctionalComponent } from 'preact';
|
||||||
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
||||||
|
import type { MarkdownHeading } from 'astro';
|
||||||
|
|
||||||
|
type ItemOffsets = {
|
||||||
|
id: string;
|
||||||
|
topOffset: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({
|
||||||
|
headings = [],
|
||||||
|
}) => {
|
||||||
|
const itemOffsets = useRef<ItemOffsets[]>([]);
|
||||||
|
// FIXME: Not sure what this state is doing. It was never set to anything truthy.
|
||||||
|
const [activeId] = useState<string>('');
|
||||||
|
useEffect(() => {
|
||||||
|
const getItemOffsets = () => {
|
||||||
|
const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)');
|
||||||
|
itemOffsets.current = Array.from(titles).map((title) => ({
|
||||||
|
id: title.id,
|
||||||
|
topOffset: title.getBoundingClientRect().top + window.scrollY,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
getItemOffsets();
|
||||||
|
window.addEventListener('resize', getItemOffsets);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', getItemOffsets);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="heading">On this page</h2>
|
||||||
|
<ul>
|
||||||
|
<li className={`heading-link depth-2 ${activeId === 'overview' ? 'active' : ''}`.trim()}>
|
||||||
|
<a href="#overview">Overview</a>
|
||||||
|
</li>
|
||||||
|
{headings
|
||||||
|
.filter(({ depth }) => depth > 1 && depth < 4)
|
||||||
|
.map((heading) => (
|
||||||
|
<li
|
||||||
|
className={`heading-link depth-${heading.depth} ${
|
||||||
|
activeId === heading.slug ? 'active' : ''
|
||||||
|
}`.trim()}
|
||||||
|
>
|
||||||
|
<a href={`#${heading.slug}`}>{heading.text}</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableOfContents;
|
68
apps/docs/src/config.ts
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
export const SITE = {
|
||||||
|
title: 'Astro Reactive Docs',
|
||||||
|
description: 'Let your data build your UI with native Astro components and architecture.',
|
||||||
|
defaultLanguage: 'en_US',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OPEN_GRAPH = {
|
||||||
|
image: {
|
||||||
|
src: 'https://github.com/astro-reactive/astro-reactive/blob/main/.github/assets/astro-reactive-library-cover.png?raw=true',
|
||||||
|
alt: 'astro logo and astro reactive library text on a starry expanse of space',
|
||||||
|
},
|
||||||
|
twitter: 'astroreactive',
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is the type of the frontmatter you put in the docs markdown files.
|
||||||
|
export type Frontmatter = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
layout: string;
|
||||||
|
image?: { src: string; alt: string };
|
||||||
|
dir?: 'ltr' | 'rtl';
|
||||||
|
ogLocale?: string;
|
||||||
|
lang?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const KNOWN_LANGUAGES = {
|
||||||
|
English: 'en',
|
||||||
|
} as const;
|
||||||
|
export const KNOWN_LANGUAGE_CODES = Object.values(KNOWN_LANGUAGES);
|
||||||
|
|
||||||
|
export const GITHUB_EDIT_URL = `https://github.com/astro-reactive/astro-reactive/tree/main/apps/docs`;
|
||||||
|
|
||||||
|
export const COMMUNITY_INVITE_URL = `https://discord.gg/kkvW7GYNAp`;
|
||||||
|
|
||||||
|
// See "Algolia" section of the README for more information.
|
||||||
|
export const ALGOLIA = {
|
||||||
|
indexName: 'XXXXXXXXXX',
|
||||||
|
appId: 'XXXXXXXXXX',
|
||||||
|
apiKey: 'XXXXXXXXXX',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Sidebar = Record<
|
||||||
|
(typeof KNOWN_LANGUAGE_CODES)[number],
|
||||||
|
Record<string, { text: string; link: string }[]>
|
||||||
|
>;
|
||||||
|
export const SIDEBAR: Sidebar = {
|
||||||
|
en: {
|
||||||
|
// TODO: create tutorial
|
||||||
|
// Tutorial: [
|
||||||
|
// { text: "Getting Started", link: "en/getting-started" },
|
||||||
|
// { text: "Page 2", link: "en/page-2" },
|
||||||
|
// { text: "Page 3", link: "en/page-3" },
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// TODO: create overview
|
||||||
|
Introduction: [
|
||||||
|
{ text: 'Overview', link: 'en/introduction' },
|
||||||
|
// { text: "Philosophy", link: "en/philosophy" },
|
||||||
|
],
|
||||||
|
|
||||||
|
'API Docs': [
|
||||||
|
{ text: 'Form', link: 'en/api/form/form-component' },
|
||||||
|
{ text: 'FormGroup', link: 'en/api/form/form-group' },
|
||||||
|
{ text: 'FormControl', link: 'en/api/form/form-control' },
|
||||||
|
{ text: 'Validators', link: 'en/api/validator/validators' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
1
apps/docs/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="astro/client" />
|
10
apps/docs/src/languages.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { KNOWN_LANGUAGES, KNOWN_LANGUAGE_CODES } from './config';
|
||||||
|
export { KNOWN_LANGUAGES, KNOWN_LANGUAGE_CODES };
|
||||||
|
|
||||||
|
export const langPathRegex = /\/([a-z]{2}-?[A-Z]{0,2})\//;
|
||||||
|
|
||||||
|
export function getLanguageFromURL(pathname: string) {
|
||||||
|
const langCodeMatch = pathname.match(langPathRegex);
|
||||||
|
const langCode = langCodeMatch ? langCodeMatch[1] : 'en';
|
||||||
|
return langCode as (typeof KNOWN_LANGUAGE_CODES)[number];
|
||||||
|
}
|
153
apps/docs/src/layouts/MainLayout.astro
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
---
|
||||||
|
import HeadCommon from '../components/HeadCommon.astro';
|
||||||
|
import HeadSEO from '../components/HeadSEO.astro';
|
||||||
|
import Header from '../components/Header/Header.astro';
|
||||||
|
import PageContent from '../components/PageContent/PageContent.astro';
|
||||||
|
import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro';
|
||||||
|
import RightSidebar from '../components/RightSidebar/RightSidebar.astro';
|
||||||
|
import * as CONFIG from '../config';
|
||||||
|
import type { MarkdownHeading } from 'astro';
|
||||||
|
import Footer from '../components/Footer/Footer.astro';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
frontmatter: CONFIG.Frontmatter;
|
||||||
|
headings: MarkdownHeading[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const { frontmatter, headings } = Astro.props as Props;
|
||||||
|
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||||
|
const currentPage = Astro.url.pathname;
|
||||||
|
const currentFile = `src/pages${currentPage.replace(/\/$/, '')}.md`;
|
||||||
|
const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`;
|
||||||
|
---
|
||||||
|
|
||||||
|
<html dir={frontmatter.dir ?? 'ltr'} lang={frontmatter.lang ?? 'en-us'} class="initial">
|
||||||
|
<head>
|
||||||
|
<HeadCommon />
|
||||||
|
<HeadSEO frontmatter={frontmatter} canonicalUrl={canonicalURL} />
|
||||||
|
<title>
|
||||||
|
{frontmatter.title ? `${frontmatter.title} | ${CONFIG.SITE.title}` : CONFIG.SITE.title}
|
||||||
|
</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: var(--theme-navbar-height) 1fr;
|
||||||
|
--gutter: 0.5rem;
|
||||||
|
--doc-padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
grid-template-columns:
|
||||||
|
minmax(var(--gutter), 1fr) minmax(0, var(--max-width))
|
||||||
|
minmax(var(--gutter), 1fr);
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-sidebar {
|
||||||
|
height: 100vh;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid-left {
|
||||||
|
position: fixed;
|
||||||
|
background-color: var(--theme-bg);
|
||||||
|
z-index: 10;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid-main {
|
||||||
|
padding: 0 var(--gutter);
|
||||||
|
grid-column: 2;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid-right {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
.layout {
|
||||||
|
overflow: initial;
|
||||||
|
grid-template-columns: 20rem minmax(0, var(--max-width));
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid-left {
|
||||||
|
display: flex;
|
||||||
|
padding-left: 2rem;
|
||||||
|
position: sticky;
|
||||||
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 72em) {
|
||||||
|
.layout {
|
||||||
|
grid-template-columns: 20rem minmax(0, var(--max-width)) 18rem;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid-right {
|
||||||
|
grid-column: 3;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style is:global>
|
||||||
|
.warning {
|
||||||
|
background-color: var(--theme-bg-accent);
|
||||||
|
color: var(--theme-text-accent);
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 1.25em 1.5rem;
|
||||||
|
border-radius: 0 0.25rem 0.25rem 0;
|
||||||
|
border-left: 3px solid var(--theme-text-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout > * {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-sidebar-toggle {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-sidebar-toggle #grid-left {
|
||||||
|
display: block;
|
||||||
|
top: 2rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Header currentPage={currentPage} />
|
||||||
|
<main class="layout">
|
||||||
|
<aside id="grid-left" class="grid-sidebar" title="Site Navigation">
|
||||||
|
<LeftSidebar currentPage={currentPage} />
|
||||||
|
</aside>
|
||||||
|
<div id="grid-main">
|
||||||
|
<div class="warning">
|
||||||
|
<strong>🛠 Under Construction:</strong> This library and the documentation are works in progress.
|
||||||
|
Read and join our <a href="https://github.com/astro-reactive/astro-reactive/discussions"
|
||||||
|
>discussions</a
|
||||||
|
> for questions, suggestions, or feedback.
|
||||||
|
</div>
|
||||||
|
<PageContent frontmatter={frontmatter} headings={headings} githubEditUrl={githubEditUrl}>
|
||||||
|
<slot />
|
||||||
|
</PageContent>
|
||||||
|
</div>
|
||||||
|
<aside id="grid-right" class="grid-sidebar" title="Table of Contents">
|
||||||
|
<RightSidebar headings={headings} githubEditUrl={githubEditUrl} />
|
||||||
|
</aside>
|
||||||
|
</main>
|
||||||
|
<Footer path={currentFile} />
|
||||||
|
</body>
|
||||||
|
</html>
|
236
apps/docs/src/pages/en/api/form/form-component.md
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
---
|
||||||
|
title: Form
|
||||||
|
type: component
|
||||||
|
package: '@astro-reactive/form'
|
||||||
|
description: The Reactive Form component for Astro
|
||||||
|
layout: ../../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
The `Form` component renders a form element and various control components (e.g., `Input`, `TextArea`, `Select`) depending on the data that you provide through its `formGroups` property.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
const form = new FormGroup();
|
||||||
|
// your controls configuration data
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
npm i @astro-reactive/form
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Setting up the `Form` component is mainly done by providing it your configuration via the `formGroups` property which takes either a `FormGroup` or an array `FormGroup[]`.
|
||||||
|
|
||||||
|
_See the documentation for the [FormGroup](/en/api/form/form-group) class._
|
||||||
|
|
||||||
|
### Setting up a form
|
||||||
|
|
||||||
|
Assigning a `FormGroup` object to the `formGroup` property will set up a form.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
value: 'awesome_dev',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'comment',
|
||||||
|
label: 'Feedback',
|
||||||
|
type: 'textarea',
|
||||||
|
value: 'Nice!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'size',
|
||||||
|
label: 'Size',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: ['S', 'M', 'L', 'XL', 'XXL'],
|
||||||
|
placeholder: '-- Please choose an option --',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
||||||
|
|
||||||
|
The example above will result in a form containing three controls: a text field `username`, a textarea `comment`, and a `size` dropdown.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The `FormGroup` constructor takes an array `ControlConfig[]`.
|
||||||
|
|
||||||
|
> **📝 Note:** The `ControlConfig` type will be defined in the [FormControl](/en/api/form/form-control) class documentation.
|
||||||
|
|
||||||
|
### Setting up multiple field sets
|
||||||
|
|
||||||
|
To render a form with multiple field sets, assign an array `FormGroup[]` to the `formGroups` property.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
|
||||||
|
const nameForm = new FormGroup(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'firstName',
|
||||||
|
label: 'First Name',
|
||||||
|
value: 'John',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lastName',
|
||||||
|
label: 'Last Name',
|
||||||
|
value: 'Doe',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'Name'
|
||||||
|
);
|
||||||
|
|
||||||
|
const skills = new FormGroup(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'JavaScript',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'JavaScript',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TypeScript',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'TypeScript',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'React',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'React',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Vue',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'Vue',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'Skills'
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={[nameForm, skills]} />
|
||||||
|
```
|
||||||
|
|
||||||
|
The example above renders a form with two field sets with legend `Name` and `Skills`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The `FormGroup` constructor optionally takes a name property to set the legend for the field set.
|
||||||
|
|
||||||
|
### Setting up the Submit button
|
||||||
|
|
||||||
|
The `Form` component takes an optional `submitControl` property. This property is of type `Submit` which is a special type for the submit button.
|
||||||
|
|
||||||
|
This implementation is to distinguish the submit button from other buttons and limit the form to only have one of it.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
|
||||||
|
const form = new FormGroup([]);
|
||||||
|
|
||||||
|
const submitControl: Submit = {
|
||||||
|
name: 'submit',
|
||||||
|
type: 'submit',
|
||||||
|
};
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} submitControl={submitControl} />
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a very crude solution to prevent having multiple submit buttons. For suggestions to improve this, join our [discussions](https://github.com/astro-reactive/astro-reactive/discussions).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
The following are input properties a `Form` component can take. Only the `formGroups` property is required.
|
||||||
|
|
||||||
|
| Property | Type | |
|
||||||
|
| ------------------------------------------- | ----------------------------- | -------- |
|
||||||
|
| [formGroups](#formgroups) | `FormGroup \| FormGroup[]` | required |
|
||||||
|
| [action](#action) | `string` | optional |
|
||||||
|
| [method](#method) | `'get' \| 'post' \| 'dialog'` | optional |
|
||||||
|
| [readOnly](#readonly) | `boolean` | optional |
|
||||||
|
| [showValidationHints](#showvalidationhints) | `boolean` | optional |
|
||||||
|
| [submitControl](#submitcontrol) | `Submit` | optional |
|
||||||
|
| [theme](#theme) | `'light' \| 'dark'` | optional |
|
||||||
|
| [validateOnLoad](#validateOnLoad) | `boolean` | optional |
|
||||||
|
|
||||||
|
### `formGroups`
|
||||||
|
|
||||||
|
Type: `FormGroup | FormGroup[]`
|
||||||
|
|
||||||
|
Determines how the form is rendered
|
||||||
|
|
||||||
|
### action
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
Sets the `action` [attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-action) for the form. Set this to the URL that processes the form submission.
|
||||||
|
|
||||||
|
### method
|
||||||
|
|
||||||
|
Type: HTTPSubmitMethod
|
||||||
|
|
||||||
|
Sets the `method` [attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-method) for the form. Set this to the HTTP method to submit the form: 'post', 'get', or 'dialog'.
|
||||||
|
|
||||||
|
From [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-method):
|
||||||
|
|
||||||
|
- `post` - The POST method; form data sent as the request body.
|
||||||
|
- `get (default)` - The GET method; form data appended to the action URL with a ? separator. Use this method when the form has no side effects.
|
||||||
|
- `dialog` - When the form is inside a <dialog>, closes the dialog and throws a submit event on submission without submitting data or clearing the form.
|
||||||
|
|
||||||
|
### `readOnly`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Sets the whole form as read-only.
|
||||||
|
|
||||||
|
### `showValidationHints`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
When used with our `validator` package, the `Form` component is able to render validation hints when `showValidationHints` is set to true:
|
||||||
|
|
||||||
|
- asterisks on required controls' labels
|
||||||
|
- controls with validation errors are colored red
|
||||||
|
|
||||||
|
### `submitControl`
|
||||||
|
|
||||||
|
Type: `Submit`
|
||||||
|
|
||||||
|
A special button that triggers the submit event for a form.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const submit: Submit = {
|
||||||
|
type: 'submit',
|
||||||
|
value: "Let's go!",
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### `theme`
|
||||||
|
|
||||||
|
Type: `'light' | 'dark'`
|
||||||
|
|
||||||
|
Sets the form to use light or dark mode.
|
||||||
|
|
||||||
|
### `validateOnLoad`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
When used with our `validator` package, the `Form` component is able to render validation errors on server-side rendering when `validateOnLoad` is set to true. Otherwise, the validation errors will only be rendered on the client-side upon user interaction.
|
9
apps/docs/src/pages/en/api/form/form-control.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
title: FormControl
|
||||||
|
type: class
|
||||||
|
package: '@astro-reactive/form'
|
||||||
|
description: FormControl class
|
||||||
|
layout: ../../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
> **❗ Note:** This documentation is incomplete.
|
29
apps/docs/src/pages/en/api/form/form-group.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
title: FormGroup
|
||||||
|
type: class
|
||||||
|
package: '@astro-reactive/form'
|
||||||
|
description: The FormGroup class represents a group of controls that will be rendered as a fieldset element in a form.
|
||||||
|
layout: ../../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
The `FormGroup` class represents a group of controls that will be rendered as a fieldset element in a form.
|
||||||
|
|
||||||
|
> **❗ Note:** This documentation is incomplete.
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Property | Type | |
|
||||||
|
| --------------------- | --------------- | -------- |
|
||||||
|
| [controls](#controls) | `FormControl[]` | required |
|
||||||
|
| [name](#name) | `string` | optional |
|
||||||
|
|
||||||
|
### controls
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
| Method | Parameters | Returns |
|
||||||
|
| ------------- | ------------ | ------------ |
|
||||||
|
| [get](#get) | name: string | `FormControl | undefined` |
|
||||||
|
| [name](#name) | `string` | optional |
|
5
apps/docs/src/pages/en/api/form/index.astro
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<script is:inline>
|
||||||
|
// Redirect your homepage to the first page of documentation.
|
||||||
|
// If you have a landing page, remove this script and add it here!
|
||||||
|
window.location.pathname = `/en/api/form/form-component`;
|
||||||
|
</script>
|
5
apps/docs/src/pages/en/api/index.astro
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<script is:inline>
|
||||||
|
// Redirect your homepage to the first page of documentation.
|
||||||
|
// If you have a landing page, remove this script and add it here!
|
||||||
|
window.location.pathname = `/en/api/form/form-component`;
|
||||||
|
</script>
|
3
apps/docs/src/pages/en/api/validator/index.astro
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<script is:inline>
|
||||||
|
window.location.pathname = `/en/api/validator/validators`;
|
||||||
|
</script>
|
193
apps/docs/src/pages/en/api/validator/validators.md
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
---
|
||||||
|
title: Validators
|
||||||
|
type: class
|
||||||
|
package: '@astro-reactive/validators'
|
||||||
|
description: Validator package for @astro-reactive/forms package for providing validation to forms.
|
||||||
|
layout: ../../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
The `Validators` class provides a set of built-in validators that can be used by form controls right out of the box.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
validators: [Validators.required, Validators.minLength(8)],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
||||||
|
|
||||||
|
_See the documentation for the [validators prop](#) here._
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
npm i @astro-reactive/validator
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Simply import the `Validators` class from the `@astro-reactive/validator` package and use the validators as needed.
|
||||||
|
|
||||||
|
### `Validators.required`
|
||||||
|
|
||||||
|
The `Validators.required` validator is used to ensure that a form control has a non-empty value.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Validators.requiredChecked`
|
||||||
|
|
||||||
|
The `Validators.requiredChecked` validator is used to ensure that a checkbox is checked.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'terms',
|
||||||
|
label: 'Terms and Conditions',
|
||||||
|
type: 'checkbox',
|
||||||
|
validators: [Validators.requiredChecked],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Validators.email`
|
||||||
|
|
||||||
|
The `Validators.email` validator is used to ensure that a form control has a valid email address. It uses a regular expression to validate the email address.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
validators: [Validators.email],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Validators.min`
|
||||||
|
|
||||||
|
The `Validators.min` validator is used to ensure that the numeric value of form control is greater than or equal to given value.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'price',
|
||||||
|
label: 'Price',
|
||||||
|
type: 'number',
|
||||||
|
validators: [Validators.min(8)],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={forms} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Validators.max`
|
||||||
|
|
||||||
|
The `Validators.max` validator is used to ensure that the numeric value of form control is less than or equal to given value.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'price',
|
||||||
|
label: 'Price',
|
||||||
|
type: 'number',
|
||||||
|
validators: [Validators.max(8)],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={forms} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Validators.minLength`
|
||||||
|
|
||||||
|
The `Validators.minLength` validator is used to ensure that the length of the value of form control is greater than or equal to given value.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
validators: [Validators.minLength(8)],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={forms} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Validators.maxLength`
|
||||||
|
|
||||||
|
The `Validators.maxLength` validator is used to ensure that the length of the value of form control is less than or equal to given value.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
validators: [Validators.maxLength(8)],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={forms} />
|
||||||
|
```
|
5
apps/docs/src/pages/en/index.astro
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<script is:inline>
|
||||||
|
// Redirect your homepage to the first page of documentation.
|
||||||
|
// If you have a landing page, remove this script and add it here!
|
||||||
|
window.location.pathname = `/en/introduction`;
|
||||||
|
</script>
|
57
apps/docs/src/pages/en/introduction.md
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
title: Hi, explorer!
|
||||||
|
description: Astro Reactive Library Docs
|
||||||
|
layout: ../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
Thanks for checking out the Astro Reactive Library! Welcome to a new adventure.
|
||||||
|
|
||||||
|
This project aims to be a new library of components and utilities for building reactive user interfaces with [Astro](https://astro.build).
|
||||||
|
|
||||||
|
We will update this documentation with a fun and easy tutorial so you can start building reactive UIs with Astro from scratch using our packages.
|
||||||
|
|
||||||
|
> **📝 Note:** See our [API Docs](/en/api) for example usage.
|
||||||
|
|
||||||
|
## Reactive what?
|
||||||
|
|
||||||
|
We are in pursuit of an easy developer experience for implementing reactive UIs in an Astro app. By this we mean components that are able to emit and listen to events, and a huge part of the challenge is "hibernating" the state after server-rendering and "waking" it up on the browser.
|
||||||
|
|
||||||
|
This will be released as a core package of the library to support reactivity across our packages, and hopefully as a utility to use for your own components.
|
||||||
|
|
||||||
|
As of now this is still a _goal_. In other words, we see this as researching the [hyperdrive](https://starwars.fandom.com/wiki/Hyperdrive/Legends) engine to explore new frontiers with Astro.
|
||||||
|
|
||||||
|
And we're having fun.
|
||||||
|
|
||||||
|
_👉 [Join us!](https://github.com/astro-reactive/astro-reactive/blob/main/CONTRIBUTING.md#readme)_
|
||||||
|
|
||||||
|
## Project Motivation
|
||||||
|
|
||||||
|
When you build a page with Astro right now, you have to keep in mind that everything is built into HTML with very minimal, and even zero, JS.
|
||||||
|
|
||||||
|
This is what makes astro great for content-focused web applications.
|
||||||
|
|
||||||
|
However we also see that Astro has given us a good baseline framework to potentially build more complex interactions.
|
||||||
|
|
||||||
|
The challenge right now is that there is no opinionated way to "resume" what your components did from the server to the browser. So I thought: What if there is a library of components and utilities to help us do this?
|
||||||
|
|
||||||
|
In this project, our motivation is to get to this future. This is our _next frontier 🚀_
|
||||||
|
|
||||||
|
## Some Tradeoffs
|
||||||
|
|
||||||
|
The Astro framework is very clear and focused on what they provide: top-tier performance for content-focused websites. In doing so, it has introduced a new world of architecture to a lot of developers.
|
||||||
|
|
||||||
|
Once we take off in pursuit of our project goals, we are aware of some tradeoffs that will be made.
|
||||||
|
|
||||||
|
As we build, we aim to minimize the performance hit to your applications.
|
||||||
|
|
||||||
|
We will also make this clear in our library documentation as we see them.
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
| Package | Release notes | Description |
|
||||||
|
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||||
|
| [form](/en/api/form/form-component) | [](https://github.com/astro-reactive/astro-reactive/blob/main/packages/form/CHANGELOG.md) | a dynamic form which can be modified programmatically |
|
||||||
|
| [validator](https://github.com/astro-reactive/astro-reactive/blob/main/packages/validator/README.md) | [](https://github.com/astro-reactive/astro-reactive/blob/main/packages/validator/CHANGELOG.md) | validators for editable fields |
|
||||||
|
| data-grid | 🛠 | a dynamic data grid of values |
|
||||||
|
| themes | 🛠 | easy-to-use, accessible, consistent cross-browser styles |
|
||||||
|
| viz | 🛠 | data visualization that emits and responds to events |
|
5
apps/docs/src/pages/en/philosophy.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Philosophy
|
||||||
|
description: Library homepage
|
||||||
|
layout: ../../layouts/MainLayout.astro
|
||||||
|
---
|
29
apps/docs/src/pages/en/tutorial/getting-started.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
title: Getting Started
|
||||||
|
description: Library homepage
|
||||||
|
layout: ../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
Consider the following code:
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import Form, { FormGroup } from '@astro-reactive/form';
|
||||||
|
import { Validators } from '@astro-reactive/validator';
|
||||||
|
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
validators: [Validators.required],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
validators: [Validators.required, Validators.minLength(8)],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
---
|
||||||
|
|
||||||
|
<Form formGroups={form} />
|
||||||
|
```
|
106
apps/docs/src/pages/en/tutorial/page-2.md
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
---
|
||||||
|
title: Reactive Form
|
||||||
|
description: Lorem ipsum dolor sit amet - 2
|
||||||
|
layout: ../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[](https://www.npmjs.com/package/@astro-reactive/form)
|
||||||
|
[](https://www.npmjs.com/package/@astro-reactive/form)
|
||||||
|
[](https://www.npmjs.com/package/@astro-reactive/form)
|
||||||
|
[](https://www.npmjs.com/package/@astro-reactive/form)
|
||||||
|
|
||||||
|
# Astro Reactive Form 🔥
|
||||||
|
|
||||||
|
Generate a dynamic form based on your data, and modify programatically.
|
||||||
|
|
||||||
|
The Reactive Form component for [Astro](https://astro.build) 🔥
|
||||||
|
|
||||||
|
_[All contributions are welcome.](https://github.com/astro-reactive/astro-reactive/issues)_
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
In your Astro project:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm i @astro-reactive/form
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Use in an Astro page:
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import { FormControl, FormGroup } from '@astro-reactive/form/core';
|
||||||
|
import Form from '@astro-reactive/form';
|
||||||
|
|
||||||
|
// create a form group
|
||||||
|
const form = new FormGroup([
|
||||||
|
{
|
||||||
|
name: 'username',
|
||||||
|
label: 'Username',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
type: 'password',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// set the name optionally
|
||||||
|
form.name = 'Simple Form';
|
||||||
|
|
||||||
|
// you can insert a control at any point
|
||||||
|
form.controls.push(
|
||||||
|
new FormControl({
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'is-awesome',
|
||||||
|
label: 'is Awesome?',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// you can get a FormControl object
|
||||||
|
const userNameControl = form.get('username');
|
||||||
|
|
||||||
|
// you can set values dynamically
|
||||||
|
userNameControl?.setValue('RAMOOOON');
|
||||||
|
form.get('is-awesome')?.setValue('checked');
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- the formGroups attribute takes an array of FormGroup-->
|
||||||
|
<Form formGroups={[form]} />
|
||||||
|
```
|
||||||
|
|
||||||
|
# Screenshots
|
||||||
|
|
||||||
|
Result of example above:
|
||||||
|
|
||||||
|
<img width="535" alt="Screen Shot 2022-10-01 at 7 29 00 PM" src="https://user-images.githubusercontent.com/4262489/193421174-5c604aca-7d16-4cd6-a7b1-f5b8752c838e.png">
|
||||||
|
|
||||||
|
Example of multiple form groups:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# Future Plans
|
||||||
|
|
||||||
|
Currently this only supports very basic form creation, but the goal of the project is ambitious:
|
||||||
|
|
||||||
|
1. Validator library for common validation scenarios
|
||||||
|
1. Client-side validation
|
||||||
|
1. Server-side validation
|
||||||
|
1. validation hooks - onFocus, onBlur, onSubmit
|
||||||
|
1. Themes - unstyled, light mode, dark mode, compact, large
|
||||||
|
1. FormGroup class
|
||||||
|
1. `statusChanges` - observable that emits the form status when it changes
|
||||||
|
1. `valueChanges` - observable that emits the values of all controls when they change
|
||||||
|
1. FormControl class
|
||||||
|
1. `statusChanges` - observable that emits the control status when it changes
|
||||||
|
1. `valueChanges` - observable that emits the control value when it changes
|
||||||
|
1. `value` - property that reflects the control value
|
||||||
|
1. Documentation website
|
||||||
|
|
||||||
|
... and so much more
|
||||||
|
|
||||||
|
_All contributions are welcome. Let's make the fastest web form component powered by Astro_
|
37
apps/docs/src/pages/en/tutorial/page-3.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
title: Page 3
|
||||||
|
description: Lorem ipsum dolor sit amet - 3
|
||||||
|
layout: ../../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a fully-featured page, written in Markdown!
|
||||||
|
|
||||||
|
## Section A
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, **consectetur adipiscing elit**. Sed ut tortor _suscipit_, posuere ante id, vulputate urna. Pellentesque molestie aliquam dui sagittis aliquet. Sed sed felis convallis, lacinia lorem sit amet, fermentum ex. Etiam hendrerit mauris at elementum egestas. Vivamus id gravida ante. Praesent consectetur fermentum turpis, quis blandit tortor feugiat in. Aliquam erat volutpat. In elementum purus et tristique ornare. Suspendisse sollicitudin dignissim est a ultrices. Pellentesque sed ipsum finibus, condimentum metus eget, sagittis elit. Sed id lorem justo. Vivamus in sem ac mi molestie ornare.
|
||||||
|
|
||||||
|
## Section B
|
||||||
|
|
||||||
|
Nam quam dolor, pellentesque sed odio euismod, feugiat tempus tellus. Quisque arcu velit, ultricies in faucibus sed, ultrices ac enim. Nunc eget dictum est. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ex nisi, egestas mollis ultricies ut, laoreet suscipit libero. Nam condimentum molestie turpis. Sed vestibulum sagittis congue. Maecenas tristique enim et tincidunt tempor. Curabitur ac scelerisque nulla, in malesuada libero. Praesent eu tempus odio. Pellentesque aliquam ullamcorper quam at gravida. Sed non fringilla mauris. Aenean sit amet ultrices erat. Vestibulum congue venenatis tortor, nec suscipit tortor. Aenean pellentesque mauris eget tortor tincidunt pharetra.
|
||||||
|
|
||||||
|
## Section C
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
title: Markdown Page!
|
||||||
|
lang: en
|
||||||
|
layout: ~/layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
# Markdown example
|
||||||
|
|
||||||
|
This is a fully-featured page, written in Markdown!
|
||||||
|
|
||||||
|
## Section A
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, **consectetur adipiscing elit**. Sed ut tortor _suscipit_, posuere ante id, vulputate urna. Pellentesque molestie aliquam dui sagittis aliquet. Sed sed felis convallis, lacinia lorem sit amet, fermentum ex. Etiam hendrerit mauris at elementum egestas. Vivamus id gravida ante. Praesent consectetur fermentum turpis, quis blandit tortor feugiat in. Aliquam erat volutpat. In elementum purus et tristique ornare. Suspendisse sollicitudin dignissim est a ultrices. Pellentesque sed ipsum finibus, condimentum metus eget, sagittis elit. Sed id lorem justo. Vivamus in sem ac mi molestie ornare.
|
||||||
|
|
||||||
|
## Section B
|
||||||
|
|
||||||
|
Nam quam dolor, pellentesque sed odio euismod, feugiat tempus tellus. Quisque arcu velit, ultricies in faucibus sed, ultrices ac enim. Nunc eget dictum est. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ex nisi, egestas mollis ultricies ut, laoreet suscipit libero. Nam condimentum molestie turpis. Sed vestibulum sagittis congue. Maecenas tristique enim et tincidunt tempor. Curabitur ac scelerisque nulla, in malesuada libero. Praesent eu tempus odio. Pellentesque aliquam ullamcorper quam at gravida. Sed non fringilla mauris. Aenean sit amet ultrices erat. Vestibulum congue venenatis tortor, nec suscipit tortor. Aenean pellentesque mauris eget tortor tincidunt pharetra.
|
||||||
|
```
|
5
apps/docs/src/pages/index.astro
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<script is:inline>
|
||||||
|
// Redirect your homepage to the first page of documentation.
|
||||||
|
// If you have a landing page, remove this script and add it here!
|
||||||
|
window.location.pathname = `/en/introduction/`;
|
||||||
|
</script>
|
382
apps/docs/src/styles/index.css
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Global focus outline reset */
|
||||||
|
*:focus:not(:focus-visible) {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--user-font-scale: 1rem - 16px;
|
||||||
|
--max-width: calc(100% - 1rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 50em) {
|
||||||
|
:root {
|
||||||
|
--max-width: 46em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: var(--font-body);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-size: clamp(0.9rem, 0.75rem + 0.375vw + var(--user-font-scale), 1rem);
|
||||||
|
line-height: 1.5;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > section > * + * {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > section > :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2 {
|
||||||
|
max-width: 40ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(h2, h3):not(:first-child) {
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(h4, h5, h6):not(:first-child) {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.25rem;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.65em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content ul {
|
||||||
|
line-height: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
.content ul {
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
small,
|
||||||
|
.text_small {
|
||||||
|
font-size: 0.833rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--theme-text-accent);
|
||||||
|
font-weight: 400;
|
||||||
|
text-underline-offset: 0.08em;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section :is(ul, ol) > * + * {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section nav :is(ul, ol) > * + * {
|
||||||
|
margin-top: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section li > :is(p, pre, blockquote):not(:first-child) {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section :is(ul, ol) {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section nav :is(ul, ol) {
|
||||||
|
padding-left: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section nav {
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section ::marker {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
article > section iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
a > code {
|
||||||
|
position: relative;
|
||||||
|
color: var(--theme-text-accent);
|
||||||
|
background: transparent;
|
||||||
|
text-underline-offset: var(--padding-block);
|
||||||
|
}
|
||||||
|
|
||||||
|
a > code::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: block;
|
||||||
|
background: var(--theme-accent);
|
||||||
|
opacity: var(--theme-accent-opacity);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:focus {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus {
|
||||||
|
outline: 2px solid currentColor;
|
||||||
|
outline-offset: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 600;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Supporting Content */
|
||||||
|
|
||||||
|
code {
|
||||||
|
--border-radius: 3px;
|
||||||
|
--padding-block: 0.2rem;
|
||||||
|
--padding-inline: 0.33rem;
|
||||||
|
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: inherit;
|
||||||
|
background-color: var(--theme-code-inline-bg);
|
||||||
|
padding: var(--padding-block) var(--padding-inline);
|
||||||
|
margin: calc(var(--padding-block) * -1) -0.125em;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.astro-code > code {
|
||||||
|
all: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre > code {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table,
|
||||||
|
pre {
|
||||||
|
position: relative;
|
||||||
|
--padding-block: 1rem;
|
||||||
|
--padding-inline: 2rem;
|
||||||
|
padding: var(--padding-block) var(--padding-inline);
|
||||||
|
padding-right: calc(var(--padding-inline) * 2);
|
||||||
|
margin-left: calc(var(--padding-inline) * -1);
|
||||||
|
margin-right: calc(var(--padding-inline) * -1);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 0.85em;
|
||||||
|
overflow-y: hidden;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--padding-block) 0;
|
||||||
|
margin: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zebra striping */
|
||||||
|
tr:nth-of-type(odd) {
|
||||||
|
background: var(--theme-bg-hover);
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background: var(--color-black);
|
||||||
|
color: var(--theme-color);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding: 6px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: var(--theme-code-bg);
|
||||||
|
color: var(--theme-code-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote code {
|
||||||
|
background-color: var(--theme-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 37.75em) {
|
||||||
|
pre {
|
||||||
|
--padding-inline: 1.25rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 1.25em 1.5rem;
|
||||||
|
border-left: 3px solid var(--theme-text-light);
|
||||||
|
background-color: var(--theme-bg-offset);
|
||||||
|
border-radius: 0 0.25rem 0.25rem 0;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
gap: 0.25em;
|
||||||
|
padding: 0.33em 0.67em;
|
||||||
|
border: 0;
|
||||||
|
background: var(--theme-bg);
|
||||||
|
display: flex;
|
||||||
|
font-size: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25em;
|
||||||
|
border-radius: 99em;
|
||||||
|
color: var(--theme-text);
|
||||||
|
background-color: var(--theme-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2.heading {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0.1rem 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-link {
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.1rem 0 0.1rem 1rem;
|
||||||
|
border-left: 4px solid var(--theme-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-link:hover,
|
||||||
|
.heading-link:focus {
|
||||||
|
border-left-color: var(--theme-accent);
|
||||||
|
color: var(--theme-accent);
|
||||||
|
}
|
||||||
|
.heading-link:focus-within {
|
||||||
|
color: var(--theme-text-light);
|
||||||
|
border-left-color: hsla(var(--color-gray-40), 1);
|
||||||
|
}
|
||||||
|
.heading-link svg {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.heading-link:hover svg {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.heading-link a {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.15em 0 0.15em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-link.depth-3 {
|
||||||
|
padding-left: 2rem;
|
||||||
|
}
|
||||||
|
.heading-link.depth-4 {
|
||||||
|
padding-left: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-link a {
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Screenreader Only Text */
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus\:not-sr-only:focus,
|
||||||
|
.focus\:not-sr-only:focus-visible {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
clip: auto;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
:target {
|
||||||
|
scroll-margin: calc(var(--theme-sidebar-offset, 5rem) + 2rem) 0 2rem;
|
||||||
|
}
|
125
apps/docs/src/styles/theme.css
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
:root {
|
||||||
|
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif,
|
||||||
|
Apple Color Emoji, Segoe UI Emoji;
|
||||||
|
--font-body: system-ui, var(--font-fallback);
|
||||||
|
--font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console',
|
||||||
|
'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono',
|
||||||
|
'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables with --color-base prefix define
|
||||||
|
* the hue, and saturation values to be used for
|
||||||
|
* hsla colors.
|
||||||
|
*
|
||||||
|
* ex:
|
||||||
|
*
|
||||||
|
* --color-base-{color}: {hue}, {saturation};
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
--color-base-white: 0, 0%;
|
||||||
|
--color-base-black: 240, 100%;
|
||||||
|
--color-base-gray: 215, 14%;
|
||||||
|
--color-base-blue: 212, 100%;
|
||||||
|
--color-base-blue-dark: 212, 72%;
|
||||||
|
--color-base-green: 158, 79%;
|
||||||
|
--color-base-orange: 22, 100%;
|
||||||
|
--color-base-purple: 269, 79%;
|
||||||
|
--color-base-red: 351, 100%;
|
||||||
|
--color-base-yellow: 41, 100%;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Color palettes are made using --color-base
|
||||||
|
* variables, along with a lightness value to
|
||||||
|
* define different variants.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
--color-gray-5: var(--color-base-gray), 5%;
|
||||||
|
--color-gray-10: var(--color-base-gray), 10%;
|
||||||
|
--color-gray-20: var(--color-base-gray), 20%;
|
||||||
|
--color-gray-30: var(--color-base-gray), 30%;
|
||||||
|
--color-gray-40: var(--color-base-gray), 40%;
|
||||||
|
--color-gray-50: var(--color-base-gray), 50%;
|
||||||
|
--color-gray-60: var(--color-base-gray), 60%;
|
||||||
|
--color-gray-70: var(--color-base-gray), 70%;
|
||||||
|
--color-gray-80: var(--color-base-gray), 80%;
|
||||||
|
--color-gray-90: var(--color-base-gray), 90%;
|
||||||
|
--color-gray-95: var(--color-base-gray), 95%;
|
||||||
|
|
||||||
|
--color-blue: var(--color-base-blue), 61%;
|
||||||
|
--color-blue-dark: var(--color-base-blue-dark), 39%;
|
||||||
|
--color-green: var(--color-base-green), 42%;
|
||||||
|
--color-orange: var(--color-base-orange), 50%;
|
||||||
|
--color-purple: var(--color-base-purple), 54%;
|
||||||
|
--color-red: var(--color-base-red), 54%;
|
||||||
|
--color-yellow: var(--color-base-yellow), 59%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
--theme-accent: hsla(var(--color-blue), 1);
|
||||||
|
--theme-text-accent: hsla(var(--color-blue), 1);
|
||||||
|
--theme-accent-opacity: 0.15;
|
||||||
|
--theme-divider: hsla(var(--color-gray-95), 1);
|
||||||
|
--theme-text: hsla(var(--color-gray-10), 1);
|
||||||
|
--theme-text-light: hsla(var(--color-gray-40), 1);
|
||||||
|
/* @@@: not used anywhere */
|
||||||
|
--theme-text-lighter: hsla(var(--color-gray-80), 1);
|
||||||
|
--theme-bg: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
--theme-bg-hover: hsla(var(--color-gray-95), 1);
|
||||||
|
--theme-bg-offset: hsla(var(--color-gray-90), 1);
|
||||||
|
--theme-bg-accent: hsla(var(--color-blue), var(--theme-accent-opacity));
|
||||||
|
--theme-code-inline-bg: hsla(var(--color-gray-95), 1);
|
||||||
|
--theme-code-inline-text: var(--theme-text);
|
||||||
|
--theme-code-bg: hsla(217, 19%, 27%, 1);
|
||||||
|
--theme-code-text: hsla(var(--color-gray-95), 1);
|
||||||
|
--theme-navbar-bg: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
--theme-navbar-height: 6rem;
|
||||||
|
--theme-selection-color: hsla(var(--color-blue), 1);
|
||||||
|
--theme-selection-bg: hsla(var(--color-blue), var(--theme-accent-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--theme-bg);
|
||||||
|
color: var(--theme-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.theme-dark {
|
||||||
|
color-scheme: dark;
|
||||||
|
--theme-accent-opacity: 0.15;
|
||||||
|
--theme-accent: hsla(var(--color-blue), 1);
|
||||||
|
--theme-text-accent: hsla(var(--color-blue), 1);
|
||||||
|
--theme-divider: hsla(var(--color-gray-10), 1);
|
||||||
|
--theme-text: hsla(var(--color-gray-90), 1);
|
||||||
|
--theme-text-light: hsla(var(--color-gray-80), 1);
|
||||||
|
|
||||||
|
/* @@@: not used anywhere */
|
||||||
|
--theme-text-lighter: hsla(var(--color-gray-40), 1);
|
||||||
|
--theme-bg: hsla(215, 28%, 17%, 1);
|
||||||
|
--theme-bg-hover: hsla(var(--color-gray-40), 1);
|
||||||
|
--theme-bg-offset: hsla(var(--color-gray-5), 1);
|
||||||
|
--theme-code-inline-bg: hsla(var(--color-gray-10), 1);
|
||||||
|
--theme-code-inline-text: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
--theme-code-bg: hsla(var(--color-gray-5), 1);
|
||||||
|
--theme-code-text: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
--theme-navbar-bg: hsla(215, 28%, 17%, 1);
|
||||||
|
--theme-selection-color: hsla(var(--color-base-white), 100%, 1);
|
||||||
|
--theme-selection-bg: hsla(var(--color-purple), var(--theme-accent-opacity));
|
||||||
|
|
||||||
|
/* DocSearch [Algolia] */
|
||||||
|
--docsearch-modal-background: var(--theme-bg);
|
||||||
|
--docsearch-searchbox-focus-background: var(--theme-divider);
|
||||||
|
--docsearch-footer-background: var(--theme-divider);
|
||||||
|
--docsearch-text-color: var(--theme-text);
|
||||||
|
--docsearch-hit-background: var(--theme-divider);
|
||||||
|
--docsearch-hit-shadow: none;
|
||||||
|
--docsearch-hit-color: var(--theme-text);
|
||||||
|
--docsearch-footer-shadow: inset 0 2px 10px #000;
|
||||||
|
--docsearch-modal-shadow: inset 0 0 8px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
color: var(--theme-selection-color);
|
||||||
|
background-color: var(--theme-selection-bg);
|
||||||
|
}
|
6
apps/docs/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "@astro-reactive/tsconfig/astro-library.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve"
|
||||||
|
}
|
||||||
|
}
|
2
apps/landing-page/.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
5
apps/landing-page/.eslintrc.cjs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/** @type {import("@types/eslint").Linter.Config} */
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
extends: ['@astro-reactive/eslint-config-custom'],
|
||||||
|
};
|
2
apps/landing-page/.npmrc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Expose Astro dependencies for `pnpm` users
|
||||||
|
shamefully-hoist=true
|
2
apps/landing-page/.prettierignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dist/
|
||||||
|
.output/
|
|
@ -6,7 +6,7 @@ module.exports = {
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
trailingComma: 'es5',
|
trailingComma: 'es5',
|
||||||
useTabs: true,
|
useTabs: true,
|
||||||
plugins: ['./node_modules/prettier-plugin-astro'],
|
plugins: ['prettier-plugin-astro'],
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: '*.astro',
|
files: '*.astro',
|
25
apps/landing-page/CHANGELOG.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# @astro-reactive/landing-page
|
||||||
|
|
||||||
|
## 1.0.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- a1cc4b0: Update homepage to https://astro-reactive.js.org
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
### Major Changes
|
||||||
|
|
||||||
|
- 6e27739: Make the npm install script shorter
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 4d2a577: Support Astro 3
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- fb11b73: Initial `create-astro-reactive` package
|
||||||
|
Update packages' meta information (author, homepage)
|
||||||
|
Upadte LICENSE owner info to `astro-reactive` organization
|
9
apps/landing-page/LICENSE
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-present Markus Hsi-Yang Fritz
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|