chore(apps): Setup prettier + eslint for all our apps (#254)

* chore(apps): setup prettier + eslint for all our apps

* fix(docs): Fixed the use of implicit any type

* chore(apps): Added .eslintignore files
This commit is contained in:
Lalit 2023-01-14 15:10:40 +05:30 committed by GitHub
parent 0abe83aea9
commit f79ce72a1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 1349 additions and 1265 deletions

2
apps/demo/.eslintignore Normal file
View file

@ -0,0 +1,2 @@
dist
node_modules

5
apps/demo/.eslintrc.cjs Normal file
View file

@ -0,0 +1,5 @@
/** @type {import("@types/eslint").Linter.Config} */
module.exports = {
root: true,
extends: ['@astro-reactive/eslint-config-custom'],
};

24
apps/demo/.prettierrc.cjs Normal file
View 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: ['../../node_modules/prettier-plugin-astro'],
overrides: [
{
files: '*.astro',
options: {
parser: 'astro',
},
},
{
files: ['.*', '*.json', '*.md', '*.toml', '*.yml'],
options: {
useTabs: false,
},
},
],
};

View file

@ -5,4 +5,3 @@
Start the dev server by running: `npm start`
👉 _[Join our contributors!](https://github.com/astro-reactive/astro-reactive/blob/main/CONTRIBUTING.md)_

View file

@ -1,4 +1,4 @@
import { defineConfig } from "astro/config";
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({});

View file

@ -12,10 +12,12 @@
"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/tsconfig": "*",
"@astro-reactive/form": "*",
"@astro-reactive/validator": "*",
"astro": "^1.6.5"
@ -31,7 +33,13 @@
},
"homepage": "https://github.com/astro-reactive/astro-reactive#readme",
"devDependencies": {
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/tsconfig": "*",
"@types/eslint": "^8.4.10",
"@types/prettier": "^2.7.2",
"eslint": "^8.31.0",
"prettier": "^2.8.3",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2"
}
}

View file

@ -1,30 +1,30 @@
---
import Nav from "./Nav.astro";
import Nav from './Nav.astro';
export interface Props {
title: string;
theme?: "dark" | "light";
title: string;
theme?: 'dark' | 'light';
}
const { theme = "light", title } = Astro.props;
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>
<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>

View file

@ -1,25 +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" },
{ 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>)}
{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;
}
nav a::after {
content: ' | ';
}
nav a {
text-decoration: none;
}
nav a:hover {
text-decoration: underline;
}
</style>

View file

@ -1,69 +1,69 @@
---
import type { Submit } from "@astro-reactive/common";
import Form, { FormGroup } from "@astro-reactive/form";
import Layout from "../../components/Layout.astro";
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 --",
},
{
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"
[
{
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"
[
{
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'
);
/**
@ -71,15 +71,15 @@ const skills = new FormGroup(
*/
const submitControl: Submit = {
name: "submit",
type: "submit",
name: 'submit',
type: 'submit',
};
---
<Layout title="Form API examples">
<h2>Simple Form</h2>
<Form formGroups={simpleForm} submitControl={submitControl} />
<h2>Simple Form</h2>
<Form formGroups={simpleForm} submitControl={submitControl} />
<h2>Form with nested form groups</h2>
<Form formGroups={[nameForm, skills]} />
<h2>Form with nested form groups</h2>
<Form formGroups={[nameForm, skills]} />
</Layout>

View file

@ -1,9 +1,9 @@
---
import Layout from "../../components/Layout.astro";
import Layout from '../../components/Layout.astro';
---
<Layout title="Docs Examples">
<ul>
<li><a href="./examples/form-component">Form Component</a></li>
</ul>
<ul>
<li><a href="./examples/form-component">Form Component</a></li>
</ul>
</Layout>

View file

@ -1,23 +1,23 @@
---
import Layout from "../../components/Layout.astro";
import Layout from '../../components/Layout.astro';
const Counter = {
count: 0,
increment() {
this.count++;
},
decrement() {
this.count--;
},
count: 0,
increment() {
this.count++;
},
decrement() {
this.count--;
},
};
---
<Layout title="Hyperdrive Experiment">
<!-- PROBLEM STATEMENT
<!-- 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>
<button onclick="Counter.increment()">
{Counter.count}
</button>
</Layout>

View file

@ -1,9 +1,9 @@
---
import Layout from "../../components/Layout.astro";
import Layout from '../../components/Layout.astro';
---
<Layout title="Experimental Demos">
<ul>
<li><a href="./experimental/hyperdrive">Hyperdrive</a></li>
</ul>
<ul>
<li><a href="./experimental/hyperdrive">Hyperdrive</a></li>
</ul>
</Layout>

View file

@ -1,116 +1,112 @@
---
import Form, {
ControlConfig,
FormGroup,
FormControl,
} from "@astro-reactive/form";
import type { Submit } from "@astro-reactive/common/types";
import { Validators } from "@astro-reactive/validator";
import Layout from "../components/Layout.astro";
import Form, { ControlConfig, FormGroup, FormControl } from '@astro-reactive/form';
import type { Submit } from '@astro-reactive/common/types';
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",
value: "5",
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],
},
{
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',
value: '5',
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";
form.name = 'Simple Form';
const config: ControlConfig = {
type: "checkbox",
name: "is-awesome",
label: "is Awesome?",
type: 'checkbox',
name: 'is-awesome',
label: 'is Awesome?',
};
// insert a control
form.controls.push(new FormControl(config));
// get the FormControl object
const userNameControl = form.get("username");
const userNameControl = form.get('username');
// set values dynamically
userNameControl?.setValue("RAMOOOON");
form.get("is-awesome")?.setValue("checked");
userNameControl?.setValue('RAMOOOON');
form.get('is-awesome')?.setValue('checked');
// setting an invalid value will cause errors as server-rendered
form.get("email")?.setValue("invalid-email");
form.get('email')?.setValue('invalid-email');
// switch between light and dark mode
const title = "Form Demo";
const theme = "dark";
const title = 'Form Demo';
const theme = 'dark';
const submit: Submit = {
name: "submit",
type: "submit",
value: "Let's go!",
name: 'submit',
type: 'submit',
value: "Let's go!",
};
---
<Layout title={title} theme={theme}>
<Form
validateOnLoad
showValidationHints
formGroups={form}
theme={theme}
submitControl={submit}
action="https://localhost"
method="post"
/>
<Form
validateOnLoad
showValidationHints
formGroups={form}
theme={theme}
submitControl={submit}
action="https://localhost"
method="post"
/>
</Layout>

View file

@ -1,127 +1,111 @@
---
import Form, {
ControlConfig,
FormControl,
FormGroup,
} from "@astro-reactive/form";
import { Validators } from "@astro-reactive/validator";
import type { Submit } from "@astro-reactive/common";
import Layout from "../components/Layout.astro";
import Form, { ControlConfig, FormControl, FormGroup } 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" },
],
},
{
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",
},
{
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",
name: 'resume',
label: 'Upload Resume',
type: 'file',
};
const submit: Submit = {
name: "submit",
type: "submit",
value: "Let's go!",
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",
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";
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}
/>
<Form showValidationHints formGroups={[infoForm, skillsForm]} submitControl={submit} />
</Layout>

View file

@ -1,96 +1,96 @@
---
import Form, { FormGroup } from "@astro-reactive/form";
import { Validators } from "@astro-reactive/validator";
import Layout from "../components/Layout.astro";
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"],
},
{
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",
},
{
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],
},
{
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)]);
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]} />
<Form showValidationHints formGroups={[baseForm, toppingsForm, infoForm]} />
</Layout>

View file

@ -1,3 +1,3 @@
{
"extends": "@astro-reactive/tsconfig/base.json"
}
}

2
apps/docs/.eslintignore Normal file
View file

@ -0,0 +1,2 @@
dist
node_modules

5
apps/docs/.eslintrc.cjs Normal file
View file

@ -0,0 +1,5 @@
/** @type {import("@types/eslint").Linter.Config} */
module.exports = {
root: true,
extends: ['@astro-reactive/eslint-config-custom'],
};

24
apps/docs/.prettierrc.cjs Normal file
View 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: ["../../node_modules/prettier-plugin-astro"],
overrides: [
{
files: "*.astro",
options: {
parser: "astro",
},
},
{
files: [".*", "*.json", "*.md", "*.toml", "*.yml"],
options: {
useTabs: false,
},
},
],
};

View file

@ -5,4 +5,3 @@
Start the dev server by running: `npm run docs`
👉 _[Join our contributors!](https://github.com/astro-reactive/astro-reactive/blob/main/CONTRIBUTING.md)_

View file

@ -11,6 +11,9 @@
"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": {
@ -24,7 +27,6 @@
"@types/react-dom": "^18.0.0",
"astro": "^1.4.4",
"preact": "^10.7.3",
"prettier-plugin-astro": "^0.7.0",
"react": "^18.1.0",
"react-dom": "^18.1.0"
},
@ -41,7 +43,13 @@
},
"homepage": "https://github.com/astro-reactive/astro-reactive#readme",
"devDependencies": {
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/tsconfig": "*",
"@types/eslint": "^8.4.10",
"@types/prettier": "^2.7.2",
"eslint": "^8.31.0",
"prettier": "^2.8.3",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2"
}
}

View file

@ -1,3 +1,4 @@
// eslint-disable-next-line no-undef
Array.from(document.getElementsByTagName('pre')).forEach((element) => {
element.setAttribute('tabindex', '0');
});

View file

@ -1,7 +1,7 @@
---
// fetch all commits for just this page's path
type Props = {
path: string;
path: string;
};
const { path } = Astro.props as Props;
const resolvedPath = `apps/docs/${path}`;
@ -9,58 +9,58 @@ const url = `https://api.github.com/repos/astro-reactive/astro-reactive/commits?
const commitsURL = `https://github.com/astro-reactive/astro-reactive/commits/main/${resolvedPath}`;
type Commit = {
author: {
id: string;
login: string;
};
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.'
);
}
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 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 res = await fetch(url, {
method: 'GET',
headers: {
Authorization: auth,
'User-Agent': 'astro-docs/1.0',
},
});
const data = await res.json();
const data = await res.json();
if (!res.ok) {
throw new Error(
`Request to fetch commits failed. Reason: ${res.statusText}
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
return data as Commit[];
} catch (e) {
console.warn(`[error] /src/components/AvatarList.astro
${(e as any)?.message ?? e}`);
return [] as Commit[];
}
return [] as Commit[];
}
}
function removeDups(arr: Commit[]) {
const map = new Map<string, Commit["author"]>();
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 });
}
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()];
return [...map.values()];
}
const data = await getCommits(url);
@ -71,112 +71,101 @@ const additionalContributors = unique.length - recentContributors.length; // lis
<!-- 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>}
<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;
.avatar-list {
--avatar-size: 2.5rem;
--avatar-count: 3;
display: grid;
list-style: none;
/* Default to displaying most of the avatar to
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
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);
}
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
@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)
);
}
}
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 {
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 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 img,
.avatar-list a {
display: block;
border-radius: 50%;
}
.avatar-list a {
transition: transform 180ms ease-in-out;
}
.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 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;
}
.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 {
display: flex;
align-items: center;
}
.contributors > * + * {
margin-left: 0.75rem;
}
.contributors > * + * {
margin-left: 0.75rem;
}
</style>

View file

@ -21,9 +21,7 @@ import '../styles/index.css';
/>
<!-- Scrollable a11y code helper -->
<script src="/make-scrollable-code-focusable.js" is:inline>
</script>
<script src="/make-scrollable-code-focusable.js" is:inline></script>
<!-- This is intentionally inlined to avoid FOUC -->
<script is:inline>

View file

@ -1,15 +1,15 @@
---
import { getLanguageFromURL, KNOWN_LANGUAGE_CODES } from "../../languages";
import ThemeToggleButton from "./ThemeToggleButton";
import * as CONFIG from "../../config";
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 SkipToContent from './SkipToContent.astro';
import SidebarToggle from './SidebarToggle';
import LanguageSelect from './LanguageSelect';
// import Search from "./Search";
type Props = {
currentPage: string;
currentPage: string;
};
const { currentPage } = Astro.props as Props;
@ -17,140 +17,136 @@ 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">
<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>
<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;
}
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 {
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 {
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 {
transition: color 100ms ease-out;
color: var(--theme-text);
}
.logo a:hover,
.logo a:focus {
color: var(--theme-text-accent);
}
.logo a:hover,
.logo a:focus {
color: var(--theme-text-accent);
}
.logo h1 {
display: none;
font: inherit;
color: inherit;
margin: 0;
}
.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;
}
.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;
}
@media (min-width: 50em) {
header {
position: static;
padding: 2rem 0rem;
}
.logo {
width: auto;
margin: 0;
z-index: 0;
}
.logo {
width: auto;
margin: 0;
z-index: 0;
}
.logo h1 {
display: initial;
}
.logo h1 {
display: initial;
}
.menu-toggle {
display: none;
}
}
.menu-toggle {
display: none;
}
}
/** Style Algolia */
:root {
--docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text);
}
/** 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;
}
.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;
}
}
@media (min-width: 50em) {
.search-item {
max-width: 400px;
}
}
</style>
<style is:global>
.search-item > * {
flex-grow: 1;
}
.search-item > * {
flex-grow: 1;
}
</style>

View file

@ -28,7 +28,7 @@ export default function Search() {
}, [setIsOpen]);
const onInput = useCallback(
(e) => {
(e: KeyboardEvent) => {
setIsOpen(true);
setInitialQuery(e.key);
},

View file

@ -1,124 +1,119 @@
---
import { getLanguageFromURL } from "../../languages";
import { SIDEBAR } from "../../config";
import { getLanguageFromURL } from '../../languages';
import { SIDEBAR } from '../../config';
type Props = {
currentPage: string;
currentPage: string;
};
const { currentPage } = Astro.props as Props;
const currentPageMatch = currentPage.endsWith("/")
? currentPage.slice(1, -1)
: currentPage.slice(1);
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>
<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;
}
});
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 {
width: 100%;
margin-right: 1rem;
}
.nav-groups {
height: 100%;
padding: 2rem;
overflow-x: visible;
overflow-y: auto;
max-height: 100vh;
}
.nav-groups {
height: 100%;
padding: 2rem;
overflow-x: visible;
overflow-y: auto;
max-height: 100vh;
}
.nav-groups > li + li {
margin-top: 2rem;
}
.nav-groups > li + li {
margin-top: 2rem;
}
.nav-groups > :first-child {
padding-top: var(--doc-padding);
}
.nav-groups > :first-child {
padding-top: var(--doc-padding);
}
.nav-groups > :last-child {
padding-bottom: 2rem;
margin-bottom: var(--theme-navbar-height);
}
.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-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 {
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: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;
}
.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;
}
}
@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);
}
:root.theme-dark .nav-link a[aria-current='page'] {
color: hsla(var(--color-base-white), 100%, 1);
}
</style>

View file

@ -1,13 +1,13 @@
---
import type { Frontmatter } from "../../config";
import MoreMenu from "../RightSidebar/MoreMenu.astro";
import TableOfContents from "../RightSidebar/TableOfContents";
import type { MarkdownHeading } from "astro";
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;
frontmatter: Frontmatter;
headings: MarkdownHeading[];
githubEditUrl: string;
};
const { frontmatter, headings, githubEditUrl } = Astro.props as Props;
@ -15,39 +15,39 @@ 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>
<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 {
padding: 0;
max-width: 75ch;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.content > section {
margin-bottom: 4rem;
}
.content > section {
margin-bottom: 4rem;
}
.block {
display: block;
}
.block {
display: block;
}
@media (min-width: 50em) {
.sm\:hidden {
display: none;
}
}
@media (min-width: 50em) {
.sm\:hidden {
display: none;
}
}
</style>

View file

@ -1,8 +1,8 @@
---
import * as CONFIG from "../../config";
import * as CONFIG from '../../config';
type Props = {
editHref: string;
editHref: string;
};
const { editHref } = Astro.props as Props;
@ -11,65 +11,65 @@ 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>
)
}
{
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;
}
.edit-on-github {
text-decoration: none;
font: inherit;
color: inherit;
font-size: 1rem;
}
</style>

View file

@ -1,31 +1,30 @@
export const SITE = {
title: "Astro Reactive Docs",
description:
"Let your data build your UI with native Astro components and architecture.",
defaultLanguage: "en_US",
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",
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;
title: string;
description: string;
layout: string;
image?: { src: string; alt: string };
dir?: 'ltr' | 'rtl';
ogLocale?: string;
lang?: string;
};
export const KNOWN_LANGUAGES = {
English: "en",
English: 'en',
} as const;
export const KNOWN_LANGUAGE_CODES = Object.values(KNOWN_LANGUAGES);
@ -35,35 +34,35 @@ export const COMMUNITY_INVITE_URL = `https://discord.gg/fkpkKdPJ`;
// See "Algolia" section of the README for more information.
export const ALGOLIA = {
indexName: "XXXXXXXXXX",
appId: "XXXXXXXXXX",
apiKey: "XXXXXXXXXX",
indexName: 'XXXXXXXXXX',
appId: 'XXXXXXXXXX',
apiKey: 'XXXXXXXXXX',
};
export type Sidebar = Record<
typeof KNOWN_LANGUAGE_CODES[number],
Record<string, { text: string; link: string }[]>
(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" },
// ],
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" },
],
// 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" },
],
},
'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' },
],
},
};

View file

@ -6,5 +6,5 @@ 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];
return langCode as (typeof KNOWN_LANGUAGE_CODES)[number];
}

View file

@ -1,167 +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";
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[];
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 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;
}
<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;
}
.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-sidebar {
height: 100vh;
position: sticky;
top: 0;
padding: 0;
}
#grid-left {
position: fixed;
background-color: var(--theme-bg);
z-index: 10;
display: none;
}
#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-main {
padding: 0 var(--gutter);
grid-column: 2;
display: flex;
flex-direction: column;
height: 100%;
}
#grid-right {
display: none;
}
#grid-right {
display: none;
}
@media (min-width: 50em) {
.layout {
overflow: initial;
grid-template-columns: 20rem minmax(0, var(--max-width));
gap: 1em;
}
@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;
}
}
#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;
}
@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);
}
#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%;
}
.layout > * {
width: 100%;
height: 100%;
}
.mobile-sidebar-toggle {
overflow: hidden;
}
.mobile-sidebar-toggle {
overflow: hidden;
}
.mobile-sidebar-toggle #grid-left {
display: block;
top: 2rem;
}
</style>
</head>
.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 undergoing rigorous development. 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>
<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 undergoing rigorous
development. 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>

View file

@ -1,7 +1,7 @@
---
title: Form
type: component
package: "@astro-reactive/form"
package: '@astro-reactive/form'
description: The Reactive Form component for Astro
layout: ../../../../layouts/MainLayout.astro
---
@ -10,7 +10,7 @@ The `Form` component renders a form element and various control components (e.g.
```astro
---
import Form, { FormGroup } from "@astro-reactive/form";
import Form, { FormGroup } from '@astro-reactive/form';
const form = new FormGroup();
// your controls configuration data
---
@ -36,26 +36,26 @@ Assigning a `FormGroup` object to the `formGroup` property will set up a form.
```astro
---
import Form, { FormGroup } from "@astro-reactive/form";
import Form, { FormGroup } from '@astro-reactive/form';
const form = new FormGroup([
{
name: "username",
label: "Username",
value: "awesome_dev",
name: 'username',
label: 'Username',
value: 'awesome_dev',
},
{
name: "comment",
label: "Feedback",
type: "textarea",
value: "Nice!",
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 --",
name: 'size',
label: 'Size',
type: 'dropdown',
options: ['S', 'M', 'L', 'XL', 'XXL'],
placeholder: '-- Please choose an option --',
},
]);
---
@ -77,48 +77,48 @@ To render a form with multiple field sets, assign an array `FormGroup[]` to the
```astro
---
import Form, { FormGroup } from "@astro-reactive/form";
import Form, { FormGroup } from '@astro-reactive/form';
const nameForm = new FormGroup(
[
{
name: "firstName",
label: "First Name",
value: "John",
name: 'firstName',
label: 'First Name',
value: 'John',
},
{
name: "lastName",
label: "Last Name",
value: "Doe",
name: 'lastName',
label: 'Last Name',
value: 'Doe',
},
],
"Name"
'Name'
);
const skills = new FormGroup(
[
{
name: "JavaScript",
type: "checkbox",
label: "JavaScript",
name: 'JavaScript',
type: 'checkbox',
label: 'JavaScript',
},
{
name: "TypeScript",
type: "checkbox",
label: "TypeScript",
name: 'TypeScript',
type: 'checkbox',
label: 'TypeScript',
},
{
name: "React",
type: "checkbox",
label: "React",
name: 'React',
type: 'checkbox',
label: 'React',
},
{
name: "Vue",
type: "checkbox",
label: "Vue",
name: 'Vue',
type: 'checkbox',
label: 'Vue',
},
],
"Skills"
'Skills'
);
---
@ -139,13 +139,13 @@ This implementation is to distinguish the submit button from other buttons and l
```astro
---
import Form, { FormGroup } from "@astro-reactive/form";
import Form, { FormGroup } from '@astro-reactive/form';
const form = new FormGroup([]);
const submitControl: Submit = {
name: "submit",
type: "submit",
name: 'submit',
type: 'submit',
};
---
@ -160,16 +160,16 @@ This is a very crude solution to prevent having multiple submit buttons. For sug
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 |
| 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`
@ -190,6 +190,7 @@ 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.
@ -218,8 +219,8 @@ A special button that triggers the submit event for a form.
```ts
const submit: Submit = {
type: 'submit',
value: 'Let\'s go!'
}
value: "Let's go!",
};
```
### `theme`
@ -233,4 +234,3 @@ Sets the form to use light or dark mode.
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.

View file

@ -1,9 +1,9 @@
---
title: FormControl
type: class
package: "@astro-reactive/form"
package: '@astro-reactive/form'
description: FormControl class
layout: ../../../../layouts/MainLayout.astro
---
> **❗ Note:** This documentation is incomplete.
> **❗ Note:** This documentation is incomplete.

View file

@ -1,7 +1,7 @@
---
title: FormGroup
type: class
package: "@astro-reactive/form"
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
---
@ -12,11 +12,11 @@ The `FormGroup` class represents a group of controls that will be rendered as a
## Properties
| Property | Type | |
|---|---|---|
| [controls](#controls) | `FormControl[]` | required |
| [name](#name) | `string` | optional |
| Property | Type | |
| --------------------- | --------------- | -------- |
| [controls](#controls) | `FormControl[]` | required |
| [name](#name) | `string` | optional |
### controls
### name
### name

View file

@ -1,5 +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`;
// 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>

View file

@ -1,5 +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`;
// 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>

View file

@ -1,3 +1,3 @@
<script is:inline>
window.location.pathname = `/en/api/validator/validators`;
window.location.pathname = `/en/api/validator/validators`;
</script>

View file

@ -1,7 +1,7 @@
---
title: Validators
type: class
package: "@astro-reactive/validators"
package: '@astro-reactive/validators'
description: Validator package for @astro-reactive/forms package for providing validation to forms.
layout: ../../../../layouts/MainLayout.astro
---
@ -10,21 +10,21 @@ The `Validators` class provides a set of built-in validators that can be used by
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "username",
label: "Username",
name: 'username',
label: 'Username',
validators: [Validators.required],
},
{
name: "password",
label: "Password",
name: 'password',
label: 'Password',
validators: [Validators.required, Validators.minLength(8)],
},
])
]);
---
<Form formGroups={form} />
@ -48,16 +48,16 @@ The `Validators.required` validator is used to ensure that a form control has a
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "username",
label: "Username",
name: 'username',
label: 'Username',
validators: [Validators.required],
},
])
]);
---
<Form formGroups={form} />
@ -69,17 +69,17 @@ The `Validators.requiredChecked` validator is used to ensure that a checkbox is
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
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",
name: 'terms',
label: 'Terms and Conditions',
type: 'checkbox',
validators: [Validators.requiredChecked],
},
])
]);
---
<Form formGroups={form} />
@ -91,16 +91,16 @@ The `Validators.email` validator is used to ensure that a form control has a val
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "email",
label: "Email",
name: 'email',
label: 'Email',
validators: [Validators.email],
},
])
]);
---
<Form formGroups={form} />
@ -112,17 +112,17 @@ The `Validators.min` validator is used to ensure that the numeric value of form
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "price",
label: "Price",
type: "number",
name: 'price',
label: 'Price',
type: 'number',
validators: [Validators.min(8)],
},
])
]);
---
<Form formGroups={forms} />
@ -134,17 +134,17 @@ The `Validators.max` validator is used to ensure that the numeric value of form
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "price",
label: "Price",
type: "number",
name: 'price',
label: 'Price',
type: 'number',
validators: [Validators.max(8)],
},
])
]);
---
<Form formGroups={forms} />
@ -156,16 +156,16 @@ The `Validators.minLength` validator is used to ensure that the length of the va
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "password",
label: "Password",
name: 'password',
label: 'Password',
validators: [Validators.minLength(8)],
},
])
]);
---
<Form formGroups={forms} />
@ -177,16 +177,16 @@ The `Validators.maxLength` validator is used to ensure that the length of the va
```astro
---
import Form, {FormGroup} from "@astro-reactive/form"
import {Validators} from "@astro-reactive/validator"
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: "password",
label: "Password",
name: 'password',
label: 'Password',
validators: [Validators.maxLength(8)],
},
])
]);
---
<Form formGroups={forms} />

View file

@ -1,5 +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`;
// 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>

View file

@ -48,11 +48,10 @@ We will also make this clear in our library documentation as we see them.
## Packages
| Package | Release notes | Description |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| Package | Release notes | Description |
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| [form](/en/api/form/form-component) | [![npm](https://img.shields.io/npm/v/@astro-reactive/form)](https://github.com/astro-reactive/astro-reactive/blob/main/packages/form/RELEASE.md) | a dynamic form which can be modified programmatically |
| [validator](https://github.com/astro-reactive/astro-reactive/blob/main/packages/validator/README.md) | [![npm](https://img.shields.io/npm/v/@astro-reactive/validator)](https://github.com/astro-reactive/astro-reactive/blob/main/packages/validator/RELEASE.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 |
| 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 |

View file

@ -2,4 +2,4 @@
title: Philosophy
description: Library homepage
layout: ../../layouts/MainLayout.astro
---
---

View file

@ -6,26 +6,24 @@ layout: ../../../layouts/MainLayout.astro
Consider the following code:
``` astro
```astro
---
import Form { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
import Form, { FormGroup } from '@astro-reactive/form';
import { Validators } from '@astro-reactive/validator';
const form = new FormGroup([
{
name: 'username',
label: 'Username',
validators: [Validators.required]
validators: [Validators.required],
},
{
name: 'password',
label: 'Password',
validators: [Validators.required, Validators.minLength(8)]
validators: [Validators.required, Validators.minLength(8)],
},
]);
---
<Form formGroups={form} />
```

View file

@ -33,45 +33,44 @@ Use in an Astro page:
```astro
---
import { FormControl, FormGroup } from "@astro-reactive/form/core";
import Form from "@astro-reactive/form";
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: 'username',
label: 'Username',
},
{
name: "password",
label: "Password",
type: "password",
name: 'password',
label: 'Password',
type: 'password',
},
]);
// set the name optionally
form.name = "Simple Form";
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?",
type: 'checkbox',
name: 'is-awesome',
label: 'is Awesome?',
})
);
// you can get a FormControl object
const userNameControl = form.get("username");
const userNameControl = form.get('username');
// you can set values dynamically
userNameControl?.setValue("RAMOOOON");
form.get('is-awesome')?.setValue("checked");
userNameControl?.setValue('RAMOOOON');
form.get('is-awesome')?.setValue('checked');
---
<!-- the formGroups attribute takes an array of FormGroup-->
<Form formGroups={[form]} />
```
# Screenshots
@ -105,4 +104,3 @@ Currently this only supports very basic form creation, but the goal of the proje
... and so much more
_All contributions are welcome. Let's make the fastest web form component powered by Astro_

View file

@ -1,5 +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/`;
// 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>

View file

@ -1,7 +1,6 @@
{
"extends": "astro/tsconfigs/base",
"extends": "@astro-reactive/tsconfig/astro-library.json",
"compilerOptions": {
"jsx": "preserve",
"skipLibCheck": true
"jsx": "preserve"
}
}
}

View file

@ -0,0 +1,2 @@
dist
node_modules

View file

@ -0,0 +1,5 @@
/** @type {import("@types/eslint").Linter.Config} */
module.exports = {
root: true,
extends: ['@astro-reactive/eslint-config-custom'],
};

View 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: ['../../node_modules/prettier-plugin-astro'],
overrides: [
{
files: '*.astro',
options: {
parser: 'astro',
},
},
{
files: ['.*', '*.json', '*.md', '*.toml', '*.yml'],
options: {
useTabs: false,
},
},
],
};

View file

@ -1 +0,0 @@
{}

View file

@ -1,12 +1,12 @@
import tailwind from "@astrojs/tailwind";
import { defineConfig } from "astro/config";
import tailwind from '@astrojs/tailwind';
import { defineConfig } from 'astro/config';
export default defineConfig({
site: "https://astro-reactive.dev",
integrations: [tailwind()],
vite: {
ssr: {
external: ["svgo"],
},
},
site: 'https://astro-reactive.dev',
integrations: [tailwind()],
vite: {
ssr: {
external: ['svgo'],
},
},
});

View file

@ -10,16 +10,22 @@
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
"format": "prettier --write .",
"format": "prettier -w .",
"lint": "eslint . --ext .ts,.js",
"lint:fix": "eslint --fix . --ext .ts,.js",
"clean": "rimraf dist node_modules dist .turbo"
},
"devDependencies": {
"@astro-reactive/eslint-config-custom": "*",
"@astrojs/tailwind": "^2.0.2",
"@types/eslint": "^8.4.10",
"@types/micromodal": "^0.3.3",
"@types/prettier": "^2.7.2",
"astro": "^1.4.7",
"astro-icon": "^0.8.0",
"prettier": "2.7.1",
"prettier-plugin-astro": "^0.7.0",
"eslint": "^8.31.0",
"prettier": "^2.7.1",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2",
"tailwindcss-fluid-type": "^2.0.3"
},
@ -41,4 +47,3 @@
},
"homepage": "https://github.com/astro-reactive/astro-reactive#readme"
}

View file

@ -1,12 +1,12 @@
/* TODO: consider creating <Button> and <GradientText> components */
a,
.btn {
@apply transition-colors duration-200;
@apply hover:text-secondary;
@apply focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent focus:ring-secondary;
@apply transition-colors duration-200;
@apply hover:text-secondary;
@apply focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent focus:ring-secondary;
}
.gradient-text {
@apply text-transparent bg-clip-text;
@apply bg-gradient-to-br from-indigo-500 via-fuchsia-500 to-pink-500;
@apply text-transparent bg-clip-text;
@apply bg-gradient-to-br from-indigo-500 via-fuchsia-500 to-pink-500;
}

View file

@ -1,2 +1,2 @@
@import "global.css";
@import "theme.css";
@import 'global.css';
@import 'theme.css';

View file

@ -1,19 +1,19 @@
[data-theme="light"] {
--color-primary: theme("colors.pink.500");
--color-secondary: theme("colors.indigo.500");
--color-text: theme("colors.gray.900");
--color-text-offset: theme("colors.gray.600");
--color-background: theme("colors.gray.50");
--color-background-offset: theme("colors.gray.100");
--color-border: theme("colors.gray.900" / 10%);
[data-theme='light'] {
--color-primary: theme('colors.pink.500');
--color-secondary: theme('colors.indigo.500');
--color-text: theme('colors.gray.900');
--color-text-offset: theme('colors.gray.600');
--color-background: theme('colors.gray.50');
--color-background-offset: theme('colors.gray.100');
--color-border: theme('colors.gray.900' / 10%);
}
[data-theme="dark"] {
--color-primary: theme("colors.pink.400");
--color-secondary: theme("colors.indigo.400");
--color-text: theme("colors.gray.50");
--color-text-offset: theme("colors.gray.400");
--color-background: theme("colors.gray.900");
--color-background-offset: theme("colors.gray.800");
--color-border: theme("colors.gray.50" / 10%);
[data-theme='dark'] {
--color-primary: theme('colors.pink.400');
--color-secondary: theme('colors.indigo.400');
--color-text: theme('colors.gray.50');
--color-text-offset: theme('colors.gray.400');
--color-background: theme('colors.gray.900');
--color-background-offset: theme('colors.gray.800');
--color-border: theme('colors.gray.50' / 10%);
}

View file

@ -1,38 +1,38 @@
const defaultTheme = require("tailwindcss/defaultTheme");
const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,svelte,ts,tsx,vue}"],
theme: {
screens: {
"astro-sm": { max: "1000px" },
"astro-md": { min: "640px", max: "1000px" },
"astro-img": { min: "600px", max: "1000px" },
"astro-lg": { min: "1000px" },
...defaultTheme.screens,
},
extend: {
fontFamily: {
sans: ["Inter", ...defaultTheme.fontFamily.sans],
},
colors: {
primary: "var(--color-primary)",
secondary: "var(--color-secondary)",
},
textColor: {
default: "var(--color-text)",
offset: "var(--color-text-offset)",
},
backgroundColor: {
default: "var(--color-background)",
offset: "var(--color-background-offset)",
},
borderColor: {
default: "var(--color-border)",
},
},
},
corePlugins: {
fontSize: false,
},
plugins: [require("tailwindcss-fluid-type")],
content: ['./src/**/*.{astro,html,js,jsx,svelte,ts,tsx,vue}'],
theme: {
screens: {
'astro-sm': { max: '1000px' },
'astro-md': { min: '640px', max: '1000px' },
'astro-img': { min: '600px', max: '1000px' },
'astro-lg': { min: '1000px' },
...defaultTheme.screens,
},
extend: {
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
},
colors: {
primary: 'var(--color-primary)',
secondary: 'var(--color-secondary)',
},
textColor: {
default: 'var(--color-text)',
offset: 'var(--color-text-offset)',
},
backgroundColor: {
default: 'var(--color-background)',
offset: 'var(--color-background-offset)',
},
borderColor: {
default: 'var(--color-border)',
},
},
},
corePlugins: {
fontSize: false,
},
plugins: [require('tailwindcss-fluid-type')],
};

59
package-lock.json generated
View file

@ -30,11 +30,17 @@
"license": "ISC",
"dependencies": {
"@astro-reactive/form": "*",
"@astro-reactive/tsconfig": "*",
"@astro-reactive/validator": "*",
"astro": "^1.6.5"
},
"devDependencies": {
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/tsconfig": "*",
"@types/eslint": "^8.4.10",
"@types/prettier": "^2.7.2",
"eslint": "^8.31.0",
"prettier": "^2.8.3",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2"
}
},
@ -53,11 +59,17 @@
"@types/react-dom": "^18.0.0",
"astro": "^1.4.4",
"preact": "^10.7.3",
"prettier-plugin-astro": "^0.7.0",
"react": "^18.1.0",
"react-dom": "^18.1.0"
},
"devDependencies": {
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/tsconfig": "*",
"@types/eslint": "^8.4.10",
"@types/prettier": "^2.7.2",
"eslint": "^8.31.0",
"prettier": "^2.8.3",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2"
}
},
@ -71,20 +83,25 @@
"tailwindcss": "^3.1.8"
},
"devDependencies": {
"@astro-reactive/eslint-config-custom": "*",
"@astrojs/tailwind": "^2.0.2",
"@types/eslint": "^8.4.10",
"@types/micromodal": "^0.3.3",
"@types/prettier": "^2.7.2",
"astro": "^1.4.7",
"astro-icon": "^0.8.0",
"prettier": "2.7.1",
"prettier-plugin-astro": "^0.7.0",
"eslint": "^8.31.0",
"prettier": "^2.7.1",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2",
"tailwindcss-fluid-type": "^2.0.3"
}
},
"apps/landing-page/node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin-prettier.js"
},
@ -6450,9 +6467,9 @@
}
},
"node_modules/prettier": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
"integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
"bin": {
"prettier": "bin-prettier.js"
},
@ -8647,10 +8664,16 @@
"@astro-reactive/demo": {
"version": "file:apps/demo",
"requires": {
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/form": "*",
"@astro-reactive/tsconfig": "*",
"@astro-reactive/validator": "*",
"@types/eslint": "^8.4.10",
"@types/prettier": "^2.7.2",
"astro": "^1.6.5",
"eslint": "^8.31.0",
"prettier": "^2.8.3",
"prettier-plugin-astro": "^0.7.2",
"rimraf": "^3.0.2"
}
},
@ -8658,16 +8681,22 @@
"version": "file:apps/docs",
"requires": {
"@algolia/client-search": "^4.13.1",
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/tsconfig": "*",
"@astrojs/preact": "^1.1.1",
"@astrojs/react": "^1.1.4",
"@docsearch/css": "^3.1.0",
"@docsearch/react": "^3.1.0",
"@types/eslint": "^8.4.10",
"@types/node": "^18.0.0",
"@types/prettier": "^2.7.2",
"@types/react": "^18.0.24",
"@types/react-dom": "^18.0.0",
"astro": "^1.4.4",
"eslint": "^8.31.0",
"preact": "^10.7.3",
"prettier-plugin-astro": "^0.7.0",
"prettier": "^2.8.3",
"prettier-plugin-astro": "^0.7.2",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"rimraf": "^3.0.2"
@ -8709,11 +8738,15 @@
"@astro-reactive/landing-page": {
"version": "file:apps/landing-page",
"requires": {
"@astro-reactive/eslint-config-custom": "*",
"@astro-reactive/tsconfig": "*",
"@astrojs/tailwind": "^2.0.2",
"@types/eslint": "*",
"@types/micromodal": "^0.3.3",
"@types/prettier": "*",
"astro": "^1.4.7",
"astro-icon": "^0.8.0",
"eslint": "*",
"micromodal": "^0.4.10",
"prettier": "2.7.1",
"prettier-plugin-astro": "^0.7.0",
@ -8724,6 +8757,8 @@
"dependencies": {
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true
}
}
@ -12904,9 +12939,9 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
},
"prettier": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg=="
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
"integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw=="
},
"prettier-linter-helpers": {
"version": "1.0.0",