├── doc
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── favicon.ico
│ │ ├── docusaurus.png
│ │ ├── docusaurus-social-card.jpg
│ │ ├── logo.svg
│ │ ├── undraw_docusaurus_tree.svg
│ │ ├── undraw_docusaurus_mountain.svg
│ │ └── undraw_docusaurus_react.svg
├── babel.config.js
├── docs
│ ├── tutorial-extras
│ │ ├── img
│ │ │ ├── localeDropdown.png
│ │ │ └── docsVersionDropdown.png
│ │ ├── _category_.json
│ │ ├── manage-docs-versions.md
│ │ └── translate-your-site.md
│ ├── tutorial-basics
│ │ ├── _category_.json
│ │ ├── deploy-your-site.md
│ │ ├── create-a-blog-post.md
│ │ ├── congratulations.md
│ │ ├── create-a-page.md
│ │ ├── create-a-document.md
│ │ └── markdown-features.mdx
│ └── intro.md
├── blog
│ ├── 2021-08-26-welcome
│ │ ├── docusaurus-plushie-banner.jpeg
│ │ └── index.md
│ ├── 2019-05-28-first-blog-post.md
│ ├── tags.yml
│ ├── 2021-08-01-mdx-blog-post.mdx
│ ├── authors.yml
│ └── 2019-05-29-long-blog-post.md
├── src
│ ├── pages
│ │ ├── markdown-page.md
│ │ ├── index.module.css
│ │ └── index.tsx
│ ├── components
│ │ └── HomepageFeatures
│ │ │ ├── styles.module.css
│ │ │ └── index.tsx
│ └── css
│ │ └── custom.css
├── tsconfig.json
├── .gitignore
├── sidebars.ts
├── README.md
├── package.json
└── docusaurus.config.ts
├── api
├── .gitignore
├── prisma
│ ├── dev.db
│ ├── migrations
│ │ ├── migration_lock.toml
│ │ └── 20241008131008_init
│ │ │ └── migration.sql
│ ├── schema.prisma
│ └── seed
│ │ └── main.ts
├── jest.config.js
├── eslint.config.mjs
├── prisma.env
├── src
│ ├── index.ts
│ └── routes
│ │ └── user.ts
├── tsconfig.json
├── __tests__
│ └── userRouter.test.ts
└── package.json
├── app
├── src
│ ├── vite-env.d.ts
│ ├── lib
│ │ └── utils.ts
│ ├── pages
│ │ ├── home.tsx
│ │ └── auth.tsx
│ ├── app.tsx
│ ├── main.tsx
│ ├── components
│ │ ├── ui
│ │ │ ├── label.tsx
│ │ │ ├── input.tsx
│ │ │ ├── button.tsx
│ │ │ └── dropdown-menu.tsx
│ │ ├── mode-toggle.tsx
│ │ ├── theme-provider.tsx
│ │ ├── user-auth-form.tsx
│ │ └── icons.tsx
│ ├── layout.tsx
│ ├── index.css
│ └── assets
│ │ └── react.svg
├── postcss.config.js
├── tsconfig.node.json
├── .gitignore
├── vite.config.ts
├── index.html
├── components.json
├── .eslintrc.cjs
├── tsconfig.json
├── tests
│ └── main.test.jsx
├── README.md
├── public
│ └── vite.svg
├── package.json
└── tailwind.config.js
├── mobile
├── assets
│ ├── images
│ │ ├── icon.png
│ │ ├── splash.png
│ │ ├── favicon.png
│ │ ├── react-logo.png
│ │ ├── adaptive-icon.png
│ │ ├── react-logo@2x.png
│ │ ├── react-logo@3x.png
│ │ └── partial-react-logo.png
│ └── fonts
│ │ └── SpaceMono-Regular.ttf
├── babel.config.js
├── .eslintrc.js
├── tsconfig.json
├── app
│ ├── (home)
│ │ ├── index.tsx
│ │ ├── search.tsx
│ │ ├── settings.tsx
│ │ ├── profile.tsx
│ │ └── _layout.tsx
│ ├── _layout.tsx
│ └── auth.tsx
├── .gitignore
├── __tests__
│ └── main-test.tsx
├── components
│ ├── text.tsx
│ ├── theme-switch-button.tsx
│ ├── theme-provider.tsx
│ └── user-auth-form.jsx
├── constants
│ └── themes.tsx
├── app.json
├── package.json
└── README.md
├── .prettierrc
├── .gitignore
├── LICENSE.md
└── README.md
/doc/static/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | # .env
--------------------------------------------------------------------------------
/app/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/api/prisma/dev.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/api/prisma/dev.db
--------------------------------------------------------------------------------
/doc/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/doc/static/img/favicon.ico
--------------------------------------------------------------------------------
/doc/static/img/docusaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/doc/static/img/docusaurus.png
--------------------------------------------------------------------------------
/mobile/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/icon.png
--------------------------------------------------------------------------------
/mobile/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/splash.png
--------------------------------------------------------------------------------
/mobile/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/favicon.png
--------------------------------------------------------------------------------
/mobile/assets/images/react-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/react-logo.png
--------------------------------------------------------------------------------
/app/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/doc/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve("@docusaurus/core/lib/babel/preset")],
3 | };
4 |
--------------------------------------------------------------------------------
/mobile/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/mobile/assets/images/react-logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/react-logo@2x.png
--------------------------------------------------------------------------------
/mobile/assets/images/react-logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/react-logo@3x.png
--------------------------------------------------------------------------------
/doc/static/img/docusaurus-social-card.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/doc/static/img/docusaurus-social-card.jpg
--------------------------------------------------------------------------------
/mobile/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/mobile/assets/images/partial-react-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/mobile/assets/images/partial-react-logo.png
--------------------------------------------------------------------------------
/doc/docs/tutorial-extras/img/localeDropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/doc/docs/tutorial-extras/img/localeDropdown.png
--------------------------------------------------------------------------------
/doc/docs/tutorial-extras/img/docsVersionDropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/doc/docs/tutorial-extras/img/docsVersionDropdown.png
--------------------------------------------------------------------------------
/mobile/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ["babel-preset-expo"],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "avoid",
3 | "bracketSameLine": true,
4 | "singleAttributePerLine": true,
5 | "tabWidth": 4,
6 | "useTabs": true
7 | }
8 |
--------------------------------------------------------------------------------
/doc/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eimg/spata/HEAD/doc/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg
--------------------------------------------------------------------------------
/doc/docs/tutorial-extras/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Tutorial - Extras",
3 | "position": 3,
4 | "link": {
5 | "type": "generated-index"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/api/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/doc/src/pages/markdown-page.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Markdown page example
3 | ---
4 |
5 | # Markdown page example
6 |
7 | You don't need React to write simple standalone pages.
8 |
--------------------------------------------------------------------------------
/mobile/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://docs.expo.dev/guides/using-eslint/
2 | module.exports = {
3 | env: { node: true, browser: true },
4 | extends: ["expo", "plugin:@tanstack/query/recommended"],
5 | };
6 |
--------------------------------------------------------------------------------
/app/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
--------------------------------------------------------------------------------
/doc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // This file is not used in compilation. It is here just for a nice editor experience.
3 | "extends": "@docusaurus/tsconfig",
4 | "compilerOptions": {
5 | "baseUrl": "."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/doc/src/components/HomepageFeatures/styles.module.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: flex;
3 | align-items: center;
4 | padding: 2rem 0;
5 | width: 100%;
6 | }
7 |
8 | .featureSvg {
9 | height: 200px;
10 | width: 200px;
11 | }
12 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Tutorial - Basics",
3 | "position": 2,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "5 minutes to learn the most important Docusaurus concepts."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/mobile/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true,
5 | "paths": {
6 | "@/*": ["./*"]
7 | }
8 | },
9 | "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/api/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: "ts-jest",
3 | testEnvironment: "node",
4 | verbose: true,
5 | moduleFileExtensions: ["ts", "js"],
6 | transform: {
7 | "^.+\\.(ts|tsx)$": "ts-jest",
8 | },
9 | testMatch: ["**/__tests__/**/*.test.ts"],
10 | };
11 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/mobile/app/(home)/index.tsx:
--------------------------------------------------------------------------------
1 | import { View } from "react-native";
2 | import Text from "@/components/text";
3 |
4 | export default function Home() {
5 | return (
6 |
8 | Home
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/pages/home.tsx:
--------------------------------------------------------------------------------
1 | export default function Home() {
2 | return (
3 |
4 |
7 | Home
8 |
9 |
pages/Home.tsx
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true,
8 | "baseUrl": ".",
9 | "paths": {
10 | "@/*": ["./src/*"]
11 | }
12 | },
13 | "include": ["vite.config.ts"]
14 | }
15 |
--------------------------------------------------------------------------------
/mobile/app/(home)/search.tsx:
--------------------------------------------------------------------------------
1 | import { View } from "react-native";
2 | import Text from "@/components/text";
3 |
4 | export default function Search() {
5 | return (
6 |
8 | Search
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/api/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import globals from "globals";
2 | import pluginJs from "@eslint/js";
3 | import tseslint from "typescript-eslint";
4 |
5 | export default [
6 | { files: ["**/*.{js,mjs,cjs,ts}"] },
7 | { languageOptions: { globals: globals.browser } },
8 | pluginJs.configs.recommended,
9 | ...tseslint.configs.recommended,
10 | ];
11 |
--------------------------------------------------------------------------------
/mobile/app/(home)/settings.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeSwitchButton } from "@/components/theme-switch-button";
2 | import { View } from "react-native";
3 |
4 | export default function Settings() {
5 | return (
6 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/mobile/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
17 | # The following patterns were generated by expo-cli
18 |
19 | expo-env.d.ts
20 | # @end expo-cli
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/doc/blog/2019-05-28-first-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: first-blog-post
3 | title: First Blog Post
4 | authors: [slorber, yangshun]
5 | tags: [hola, docusaurus]
6 | ---
7 |
8 | Lorem ipsum dolor sit amet...
9 |
10 |
11 |
12 | ...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
13 |
--------------------------------------------------------------------------------
/app/vite.config.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import { defineConfig } from "vitest/config";
3 | import react from "@vitejs/plugin-react";
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react()],
8 | resolve: {
9 | alias: {
10 | "@": path.resolve(__dirname, "./src"),
11 | },
12 | },
13 | server: {
14 | port: 4000,
15 | open: true,
16 | },
17 | test: {
18 | environment: "jsdom",
19 | },
20 | });
21 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
12 | Vite + React + TS
13 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/doc/blog/tags.yml:
--------------------------------------------------------------------------------
1 | facebook:
2 | label: Facebook
3 | permalink: /facebook
4 | description: Facebook tag description
5 |
6 | hello:
7 | label: Hello
8 | permalink: /hello
9 | description: Hello tag description
10 |
11 | docusaurus:
12 | label: Docusaurus
13 | permalink: /docusaurus
14 | description: Docusaurus tag description
15 |
16 | hola:
17 | label: Hola
18 | permalink: /hola
19 | description: Hola tag description
20 |
--------------------------------------------------------------------------------
/api/prisma.env:
--------------------------------------------------------------------------------
1 | # Environment variables declared in this file are automatically made available to Prisma.
2 | # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
3 |
4 | # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
5 | # See the documentation for all the connection string options: https://pris.ly/d/connection-strings
6 |
7 | DATABASE_URL="file:./dev.db"
--------------------------------------------------------------------------------
/doc/src/pages/index.module.css:
--------------------------------------------------------------------------------
1 | /**
2 | * CSS files with the .module.css suffix will be treated as CSS modules
3 | * and scoped locally.
4 | */
5 |
6 | .heroBanner {
7 | padding: 4rem 0;
8 | text-align: center;
9 | position: relative;
10 | overflow: hidden;
11 | }
12 |
13 | @media screen and (max-width: 996px) {
14 | .heroBanner {
15 | padding: 2rem;
16 | }
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | align-items: center;
22 | justify-content: center;
23 | }
24 |
--------------------------------------------------------------------------------
/app/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "src/index.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/api/src/index.ts:
--------------------------------------------------------------------------------
1 | import express, { Request, Response } from "express";
2 | const app = express();
3 |
4 | import cors from "cors";
5 | app.use(cors());
6 |
7 | app.use(express.json());
8 | app.use(express.urlencoded({ extended: true }));
9 |
10 | import { router as userRouter } from "./routes/user";
11 | app.use(userRouter);
12 |
13 | app.get("/", (req: Request, res: Response) => {
14 | res.send("Express API Index");
15 | });
16 |
17 | app.listen(8000, () => {
18 | console.log("API server running at port 8000");
19 | });
20 |
--------------------------------------------------------------------------------
/mobile/__tests__/main-test.tsx:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from "@jest/globals";
2 | import { render } from "@testing-library/react-native";
3 |
4 | import Text from "@/components/text";
5 |
6 | describe("sum module", () => {
7 | it("should add 1 + 2 to equal 3", () => {
8 | expect(1 + 2).toBe(3);
9 | });
10 | });
11 |
12 | describe("Custom Text component", () => {
13 | it("should render Text correctly", () => {
14 | const { getByText } = render(Home );
15 |
16 | getByText("Home");
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/api/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "esnext",
5 | "types": ["node"],
6 | "esModuleInterop": true,
7 | "moduleResolution": "node",
8 | "sourceMap": true,
9 | "outDir": "dist",
10 | "allowJs": true,
11 | "lib": ["dom", "es6"],
12 | "baseUrl": "./src",
13 | "paths": {
14 | "@/*": ["./*"]
15 | }
16 | },
17 | "exclude": ["node_modules", "dist"],
18 | "include": ["src/**/*.ts", "prisma/**/*.ts", "__tests__/**/*.test.ts"],
19 | "files": ["src/index.ts"]
20 | }
21 |
--------------------------------------------------------------------------------
/app/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | "eslint:recommended",
6 | "plugin:@typescript-eslint/recommended",
7 | "plugin:react-hooks/recommended",
8 | "plugin:@tanstack/query/recommended",
9 | ],
10 | ignorePatterns: ["dist", ".eslintrc.cjs"],
11 | parser: "@typescript-eslint/parser",
12 | plugins: ["react-refresh"],
13 | rules: {
14 | "react-refresh/only-export-components": [
15 | "warn",
16 | { allowConstantExport: true },
17 | ],
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/mobile/components/text.tsx:
--------------------------------------------------------------------------------
1 | import { Text as DefaultText, StyleProp, TextStyle } from "react-native";
2 | import { useTheme } from "@react-navigation/native";
3 |
4 | type TextProps = {
5 | style?: StyleProp;
6 | children: string | React.ReactNode;
7 | };
8 |
9 | // Text component that support theme color
10 | export default function Text({ style, children }: TextProps) {
11 | const { colors } = useTheme();
12 |
13 | return (
14 |
15 | {children}
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/app.tsx:
--------------------------------------------------------------------------------
1 | import { RouterProvider, createBrowserRouter } from "react-router";
2 |
3 | import Layout from "./layout";
4 | import Home from "./pages/home";
5 | import Auth from "./pages/auth";
6 |
7 | const router = createBrowserRouter([
8 | {
9 | path: "/",
10 | element: ,
11 | children: [
12 | {
13 | path: "/",
14 | element: ,
15 | },
16 | {
17 | path: "/login",
18 | element: ,
19 | },
20 | ],
21 | },
22 | ]);
23 |
24 | export default function App() {
25 | return ;
26 | }
27 |
--------------------------------------------------------------------------------
/api/__tests__/userRouter.test.ts:
--------------------------------------------------------------------------------
1 | import { it, expect, describe } from "@jest/globals";
2 | import request from "supertest";
3 |
4 | import express from "express";
5 | const app = express();
6 |
7 | import { router as userRouter } from "../src/routes/user";
8 | app.use(userRouter);
9 |
10 | describe("GET /users", () => {
11 | it("should respond 200 and json", async () => {
12 | return request(app)
13 | .get("/users")
14 | .expect("Content-Type", /json/)
15 | .expect(200)
16 | .then(res => {
17 | expect(res.statusCode).toBe(200);
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/doc/blog/2021-08-01-mdx-blog-post.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: mdx-blog-post
3 | title: MDX Blog Post
4 | authors: [slorber]
5 | tags: [docusaurus]
6 | ---
7 |
8 | Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).
9 |
10 | :::tip
11 |
12 | Use the power of React to create interactive blog posts.
13 |
14 | :::
15 |
16 | {/* truncate */}
17 |
18 | For example, use JSX to create an interactive button:
19 |
20 | ```js
21 | alert("button clicked!")}>Click me!
22 | ```
23 |
24 | alert("button clicked!")}>Click me!
25 |
--------------------------------------------------------------------------------
/mobile/components/theme-switch-button.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { TouchableOpacity } from "react-native";
3 |
4 | import Ionicons from "@expo/vector-icons/Ionicons";
5 |
6 | import { useTheme } from "./theme-provider";
7 |
8 | export const ThemeSwitchButton = () => {
9 | const { isDark, toggleTheme } = useTheme();
10 |
11 | return (
12 |
13 | {isDark ? (
14 |
19 | ) : (
20 |
24 | )}
25 |
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/api/prisma/migrations/20241008131008_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "User" (
3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4 | "email" TEXT NOT NULL,
5 | "name" TEXT
6 | );
7 |
8 | -- CreateTable
9 | CREATE TABLE "Post" (
10 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
11 | "title" TEXT NOT NULL,
12 | "content" TEXT,
13 | "published" BOOLEAN NOT NULL DEFAULT false,
14 | "authorId" INTEGER NOT NULL,
15 | CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
16 | );
17 |
18 | -- CreateIndex
19 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
20 |
--------------------------------------------------------------------------------
/mobile/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Stack } from "expo-router";
2 | import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
3 | import { ThemeProvider } from "@/components/theme-provider";
4 |
5 | const queryClient = new QueryClient();
6 |
7 | export default function RootLayout() {
8 | return (
9 |
10 |
11 |
12 |
16 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/mobile/constants/themes.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | DefaultTheme as NavigationDefaultTheme,
3 | DarkTheme as NavigationDarkTheme,
4 | } from "@react-navigation/native";
5 |
6 | export const LightTheme = {
7 | ...NavigationDefaultTheme,
8 | colors: {
9 | ...NavigationDefaultTheme.colors,
10 | // primary: "#6200ee",
11 | // background: "#ffffff",
12 | // text: "#000000",
13 | // card: "#f5f5f5",
14 | // border: "#cccccc",
15 | },
16 | };
17 |
18 | export const DarkTheme = {
19 | ...NavigationDarkTheme,
20 | colors: {
21 | ...NavigationDarkTheme.colors,
22 | // primary: "#bb86fc",
23 | // background: "#121212",
24 | // text: "#ffffff",
25 | // card: "#1f1f1f",
26 | // border: "#272727",
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/api/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | // This is your Prisma schema file,
2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema
3 |
4 | generator client {
5 | provider = "prisma-client-js"
6 | }
7 |
8 | datasource db {
9 | provider = "sqlite"
10 | url = env("DATABASE_URL")
11 | }
12 |
13 | model User {
14 | id Int @id @default(autoincrement())
15 | email String @unique
16 | name String?
17 | posts Post[]
18 | }
19 |
20 | model Post {
21 | id Int @id @default(autoincrement())
22 | title String
23 | content String?
24 | published Boolean @default(false)
25 | author User @relation(fields: [authorId], references: [id])
26 | authorId Int
27 | }
28 |
--------------------------------------------------------------------------------
/doc/blog/authors.yml:
--------------------------------------------------------------------------------
1 | yangshun:
2 | name: Yangshun Tay
3 | title: Front End Engineer @ Facebook
4 | url: https://github.com/yangshun
5 | image_url: https://github.com/yangshun.png
6 | page: true
7 | socials:
8 | x: yangshunz
9 | github: yangshun
10 |
11 | slorber:
12 | name: Sébastien Lorber
13 | title: Docusaurus maintainer
14 | url: https://sebastienlorber.com
15 | image_url: https://github.com/slorber.png
16 | page:
17 | # customize the url of the author page at /blog/authors/
18 | permalink: "/all-sebastien-lorber-articles"
19 | socials:
20 | x: sebastienlorber
21 | linkedin: sebastienlorber
22 | github: slorber
23 | newsletter: https://thisweekinreact.com
24 |
--------------------------------------------------------------------------------
/mobile/app/(home)/profile.tsx:
--------------------------------------------------------------------------------
1 | import { View } from "react-native";
2 | import Text from "@/components/text";
3 | import { Link } from "expo-router";
4 |
5 | import { useTheme } from "@react-navigation/native";
6 |
7 | export default function Profile() {
8 | const { colors } = useTheme();
9 |
10 | return (
11 |
13 |
23 |
24 | Login
25 |
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true,
22 |
23 | /* Tailwind shadcn/ui */
24 | "baseUrl": ".",
25 | "paths": {
26 | "@/*": ["./src/*"]
27 | }
28 | },
29 | "include": ["src"],
30 | "references": [{ "path": "./tsconfig.node.json" }]
31 | }
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Essentials
2 | .env
3 | node_modules/
4 |
5 | # OS junks
6 | .fuse_hidden*
7 | .directory
8 | .Trash-*
9 | .nfs*
10 | .DocumentRevisions-V100
11 | .fseventsd
12 | .Spotlight-V100
13 | .TemporaryItems
14 | .Trashes
15 | .VolumeIcon.icns
16 | .com.apple.timemachine.donotpresent
17 | .AppleDB
18 | .AppleDesktop
19 | Network Trash Folder
20 | Temporary Items
21 | .apdisk
22 | $RECYCLE.BIN/
23 |
24 | # macOS
25 | *.DS_Store
26 | .AppleDouble
27 | .LSOverride
28 |
29 | # Thumbnails
30 | ._*
31 |
32 | # Windows
33 | Thumbs.db
34 | ehthumbs.db
35 | ehthumbs_vista.db
36 | Desktop.ini
37 | *.cab
38 | *.msi
39 | *.msm
40 | *.msp
41 | *.lnk
42 |
43 | # Others
44 | *.swp
45 | .idea
46 | cobertura.xml
47 | Config/secrets
48 | Packages
49 | .build
50 | xcuserdata
51 | *.xcodeproj
52 | .git/credentials
53 |
--------------------------------------------------------------------------------
/app/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./app.tsx";
4 | import "./index.css";
5 |
6 | import { ThemeProvider } from "@/components/theme-provider";
7 |
8 | import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
9 | import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
10 |
11 | const queryClient = new QueryClient();
12 |
13 | ReactDOM.createRoot(document.getElementById("root")!).render(
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 | ,
25 | );
26 |
--------------------------------------------------------------------------------
/app/src/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as LabelPrimitive from "@radix-ui/react-label";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const labelVariants = cva(
8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
9 | );
10 |
11 | const Label = React.forwardRef<
12 | React.ElementRef,
13 | React.ComponentPropsWithoutRef &
14 | VariantProps
15 | >(({ className, ...props }, ref) => (
16 |
21 | ));
22 | Label.displayName = LabelPrimitive.Root.displayName;
23 |
24 | export { Label };
25 |
--------------------------------------------------------------------------------
/app/tests/main.test.jsx:
--------------------------------------------------------------------------------
1 | import { it, expect, describe } from "vitest";
2 | import { screen, render, fireEvent } from "@testing-library/react";
3 | import "@testing-library/jest-dom/vitest";
4 |
5 | import App from "@/App";
6 |
7 | describe("math test", () => {
8 | it("should be 3", () => {
9 | expect(1 + 2).toBe(3);
10 | });
11 | });
12 |
13 | describe("UI test", () => {
14 | render( );
15 |
16 | it("should render correctly", () => {
17 | expect(screen.getByRole("title")).toBeInTheDocument();
18 | });
19 |
20 | // it("input and event", async () => {
21 | // await fireEvent.change(screen.getByRole("input"), {
22 | // target: { value: "some value" },
23 | // });
24 | // await fireEvent.click(screen.getByRole("button"));
25 | // expect(screen.getByRole("result").textContent).toBe("something");
26 | // });
27 | });
28 |
--------------------------------------------------------------------------------
/mobile/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "mobile",
4 | "slug": "mobile",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "myapp",
9 | "userInterfaceStyle": "automatic",
10 | "splash": {
11 | "image": "./assets/images/splash.png",
12 | "resizeMode": "contain",
13 | "backgroundColor": "#ffffff"
14 | },
15 | "ios": {
16 | "supportsTablet": true
17 | },
18 | "android": {
19 | "adaptiveIcon": {
20 | "foregroundImage": "./assets/images/adaptive-icon.png",
21 | "backgroundColor": "#ffffff"
22 | }
23 | },
24 | "web": {
25 | "bundler": "metro",
26 | "output": "static",
27 | "favicon": "./assets/images/favicon.png"
28 | },
29 | "plugins": ["expo-router"],
30 | "experiments": {
31 | "typedRoutes": true
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/deploy-your-site.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 5
3 | ---
4 |
5 | # Deploy your site
6 |
7 | Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**).
8 |
9 | It builds your site as simple **static HTML, JavaScript and CSS files**.
10 |
11 | ## Build your site
12 |
13 | Build your site **for production**:
14 |
15 | ```bash
16 | npm run build
17 | ```
18 |
19 | The static files are generated in the `build` folder.
20 |
21 | ## Deploy your site
22 |
23 | Test your production build locally:
24 |
25 | ```bash
26 | npm run serve
27 | ```
28 |
29 | The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/).
30 |
31 | You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**).
32 |
--------------------------------------------------------------------------------
/app/src/layout.tsx:
--------------------------------------------------------------------------------
1 | import { ModeToggle } from "@/components/mode-toggle";
2 | import { Button } from "@/components/ui/button";
3 | import { Home, ArrowLeft } from "lucide-react";
4 | import { Outlet, Link, useLocation } from "react-router";
5 |
6 | export default function Layout() {
7 | const { pathname } = useLocation();
8 |
9 | return (
10 |
11 |
12 |
15 |
16 | {pathname === "/" ? : }
17 |
18 |
19 |
20 |
23 | Login
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes {}
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | );
21 | },
22 | );
23 | Input.displayName = "Input";
24 |
25 | export { Input };
26 |
--------------------------------------------------------------------------------
/doc/sidebars.ts:
--------------------------------------------------------------------------------
1 | import type { SidebarsConfig } from "@docusaurus/plugin-content-docs";
2 |
3 | /**
4 | * Creating a sidebar enables you to:
5 | - create an ordered group of docs
6 | - render a sidebar for each doc of that group
7 | - provide next/previous navigation
8 |
9 | The sidebars can be generated from the filesystem, or explicitly defined here.
10 |
11 | Create as many sidebars as you want.
12 | */
13 | const sidebars: SidebarsConfig = {
14 | // By default, Docusaurus generates a sidebar from the docs folder structure
15 | tutorialSidebar: [{ type: "autogenerated", dirName: "." }],
16 |
17 | // But you can create a sidebar manually
18 | /*
19 | tutorialSidebar: [
20 | 'intro',
21 | 'hello',
22 | {
23 | type: 'category',
24 | label: 'Tutorial',
25 | items: ['tutorial-basics/create-a-document'],
26 | },
27 | ],
28 | */
29 | };
30 |
31 | export default sidebars;
32 |
--------------------------------------------------------------------------------
/doc/README.md:
--------------------------------------------------------------------------------
1 | # Website
2 |
3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
4 |
5 | ### Installation
6 |
7 | ```
8 | $ yarn
9 | ```
10 |
11 | ### Local Development
12 |
13 | ```
14 | $ yarn start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ### Build
20 |
21 | ```
22 | $ yarn build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ### Deployment
28 |
29 | Using SSH:
30 |
31 | ```
32 | $ USE_SSH=true yarn deploy
33 | ```
34 |
35 | Not using SSH:
36 |
37 | ```
38 | $ GIT_USER= yarn deploy
39 | ```
40 |
41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
42 |
--------------------------------------------------------------------------------
/doc/blog/2021-08-26-welcome/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: welcome
3 | title: Welcome
4 | authors: [slorber, yangshun]
5 | tags: [facebook, hello, docusaurus]
6 | ---
7 |
8 | [Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).
9 |
10 | Here are a few tips you might find useful.
11 |
12 |
13 |
14 | Simply add Markdown files (or folders) to the `blog` directory.
15 |
16 | Regular blog authors can be added to `authors.yml`.
17 |
18 | The blog post date can be extracted from filenames, such as:
19 |
20 | - `2019-05-30-welcome.md`
21 | - `2019-05-30-welcome/index.md`
22 |
23 | A blog post folder can be convenient to co-locate blog post images:
24 |
25 | 
26 |
27 | The blog supports tags as well!
28 |
29 | **And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.
30 |
--------------------------------------------------------------------------------
/api/src/routes/user.ts:
--------------------------------------------------------------------------------
1 | import express, { Request, Response } from "express";
2 | export const router = express.Router();
3 |
4 | import { query, validationResult } from "express-validator";
5 |
6 | import { PrismaClient } from "@prisma/client";
7 | const prisma = new PrismaClient();
8 |
9 | router.get("/users", async (req: Request, res: Response) => {
10 | const users = await prisma.user.findMany({
11 | include: {
12 | posts: true,
13 | },
14 | });
15 |
16 | res.send(users);
17 | });
18 |
19 | router.get(
20 | "/users/search",
21 | query("q").notEmpty(),
22 | async (req: Request, res: Response) => {
23 | const result = validationResult(req);
24 |
25 | if (result.isEmpty()) {
26 | const { q } = req.query;
27 |
28 | const data = await prisma.user.findMany({
29 | where: {
30 | name: {
31 | contains: String(q),
32 | },
33 | },
34 | });
35 |
36 | res.json(data);
37 | } else {
38 | res.status(400).json({ errors: result.array() });
39 | }
40 | },
41 | );
42 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright 2024 Fairway Technology
2 |
3 | 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:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | 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.
8 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/create-a-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 3
3 | ---
4 |
5 | # Create a Blog Post
6 |
7 | Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed...
8 |
9 | ## Create your first Post
10 |
11 | Create a file at `blog/2021-02-28-greetings.md`:
12 |
13 | ```md title="blog/2021-02-28-greetings.md"
14 | ---
15 | slug: greetings
16 | title: Greetings!
17 | authors:
18 | - name: Joel Marcey
19 | title: Co-creator of Docusaurus 1
20 | url: https://github.com/JoelMarcey
21 | image_url: https://github.com/JoelMarcey.png
22 | - name: Sébastien Lorber
23 | title: Docusaurus maintainer
24 | url: https://sebastienlorber.com
25 | image_url: https://github.com/slorber.png
26 | tags: [greetings]
27 | ---
28 |
29 | Congratulations, you have made your first post!
30 |
31 | Feel free to play around and edit this post as much as you like.
32 | ```
33 |
34 | A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings).
35 |
--------------------------------------------------------------------------------
/app/src/pages/auth.tsx:
--------------------------------------------------------------------------------
1 | import { UserAuthForm } from "@/components/user-auth-form";
2 |
3 | export default function Auth() {
4 | return (
5 |
6 |
7 |
8 |
9 | Spata Login
10 |
11 |
12 | Enter your email below to sign in or create a new
13 | account
14 |
15 |
16 |
17 |
18 | By clicking continue, you agree to our{" "}
19 |
22 | Terms of Service
23 | {" "}
24 | and{" "}
25 |
28 | Privacy Policy
29 |
30 | .
31 |
32 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/doc/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Any CSS included here will be global. The classic template
3 | * bundles Infima by default. Infima is a CSS framework designed to
4 | * work well for content-centric websites.
5 | */
6 |
7 | /* You can override the default Infima variables here. */
8 | :root {
9 | --ifm-color-primary: #2e8555;
10 | --ifm-color-primary-dark: #29784c;
11 | --ifm-color-primary-darker: #277148;
12 | --ifm-color-primary-darkest: #205d3b;
13 | --ifm-color-primary-light: #33925d;
14 | --ifm-color-primary-lighter: #359962;
15 | --ifm-color-primary-lightest: #3cad6e;
16 | --ifm-code-font-size: 95%;
17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
18 | }
19 |
20 | /* For readability concerns, you should choose a lighter palette in dark mode. */
21 | [data-theme="dark"] {
22 | --ifm-color-primary: #25c2a0;
23 | --ifm-color-primary-dark: #21af90;
24 | --ifm-color-primary-darker: #1fa588;
25 | --ifm-color-primary-darkest: #1a8870;
26 | --ifm-color-primary-light: #29d5b0;
27 | --ifm-color-primary-lighter: #32d8b4;
28 | --ifm-color-primary-lightest: #4fddbf;
29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
30 | }
31 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/congratulations.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 6
3 | ---
4 |
5 | # Congratulations!
6 |
7 | You have just learned the **basics of Docusaurus** and made some changes to the **initial template**.
8 |
9 | Docusaurus has **much more to offer**!
10 |
11 | Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**.
12 |
13 | Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610)
14 |
15 | ## What's next?
16 |
17 | - Read the [official documentation](https://docusaurus.io/)
18 | - Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config)
19 | - Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration)
20 | - Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
21 | - Add a [search bar](https://docusaurus.io/docs/search)
22 | - Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
23 | - Get involved in the [Docusaurus Community](https://docusaurus.io/community/support)
24 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/create-a-page.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Create a Page
6 |
7 | Add **Markdown or React** files to `src/pages` to create a **standalone page**:
8 |
9 | - `src/pages/index.js` → `localhost:3000/`
10 | - `src/pages/foo.md` → `localhost:3000/foo`
11 | - `src/pages/foo/bar.js` → `localhost:3000/foo/bar`
12 |
13 | ## Create your first React Page
14 |
15 | Create a file at `src/pages/my-react-page.js`:
16 |
17 | ```jsx title="src/pages/my-react-page.js"
18 | import React from "react";
19 | import Layout from "@theme/Layout";
20 |
21 | export default function MyReactPage() {
22 | return (
23 |
24 | My React page
25 | This is a React page
26 |
27 | );
28 | }
29 | ```
30 |
31 | A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page).
32 |
33 | ## Create your first Markdown Page
34 |
35 | Create a file at `src/pages/my-markdown-page.md`:
36 |
37 | ```mdx title="src/pages/my-markdown-page.md"
38 | # My Markdown page
39 |
40 | This is a Markdown page
41 | ```
42 |
43 | A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page).
44 |
--------------------------------------------------------------------------------
/api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "jest",
7 | "build": "npx tsc",
8 | "start": "node dist/index.js",
9 | "dev": "nodemon src/index.ts",
10 | "seed": "prisma db seed",
11 | "migrate": "prisma migrate dev",
12 | "migrate:reset": "prisma migrate reset",
13 | "lint": "eslint src"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "description": "",
19 | "devDependencies": {
20 | "@eslint/js": "^9.12.0",
21 | "@snaplet/copycat": "^5.0.0",
22 | "@types/express": "^5.0.0",
23 | "@types/jest": "^29.5.13",
24 | "@types/node": "^22.7.5",
25 | "@types/supertest": "^6.0.2",
26 | "eslint": "^9.12.0",
27 | "express": "^4.21.0",
28 | "globals": "^15.10.0",
29 | "jest": "^29.7.0",
30 | "prisma": "^6.1.0",
31 | "supertest": "^7.0.0",
32 | "ts-jest": "^29.2.5",
33 | "ts-node": "^10.9.2",
34 | "typescript": "^5.6.2",
35 | "typescript-eslint": "^8.8.1"
36 | },
37 | "dependencies": {
38 | "@prisma/client": "^6.1.0",
39 | "cors": "^2.8.5",
40 | "express-validator": "^7.2.0",
41 | "nodemon": "^3.1.7"
42 | },
43 | "prisma": {
44 | "seed": "ts-node prisma/seed/main.ts"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/api/prisma/seed/main.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 | const prisma = new PrismaClient();
3 |
4 | async function main() {
5 | const alice = await prisma.user.upsert({
6 | where: { email: "alice@example.com" },
7 | update: {},
8 | create: {
9 | email: "alice@example.com",
10 | name: "Alice",
11 | posts: {
12 | create: {
13 | title: "Setting up express",
14 | content: "We are going to use TypeScript",
15 | published: true,
16 | },
17 | },
18 | },
19 | });
20 | const bob = await prisma.user.upsert({
21 | where: { email: "bob@example.com" },
22 | update: {},
23 | create: {
24 | email: "bob@example.com",
25 | name: "Bob",
26 | posts: {
27 | create: [
28 | {
29 | title: "Prisma ORM",
30 | content: "With SQLite, win!",
31 | published: true,
32 | },
33 | {
34 | title: "Migration and Seeding",
35 | content: "Let's get started",
36 | published: true,
37 | },
38 | ],
39 | },
40 | },
41 | });
42 | console.log({ alice, bob });
43 | }
44 | main()
45 | .then(async () => {
46 | await prisma.$disconnect();
47 | })
48 | .catch(async e => {
49 | console.error(e);
50 | await prisma.$disconnect();
51 | process.exit(1);
52 | });
53 |
--------------------------------------------------------------------------------
/doc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "doc",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids",
15 | "typecheck": "tsc"
16 | },
17 | "dependencies": {
18 | "@docusaurus/core": "3.5.2",
19 | "@docusaurus/preset-classic": "3.5.2",
20 | "@mdx-js/react": "^3.0.0",
21 | "clsx": "^2.0.0",
22 | "prism-react-renderer": "^2.3.0",
23 | "react": "^18.0.0",
24 | "react-dom": "^18.0.0"
25 | },
26 | "devDependencies": {
27 | "@docusaurus/module-type-aliases": "3.5.2",
28 | "@docusaurus/tsconfig": "3.5.2",
29 | "@docusaurus/types": "3.5.2",
30 | "typescript": "~5.5.2"
31 | },
32 | "browserslist": {
33 | "production": [
34 | ">0.5%",
35 | "not dead",
36 | "not op_mini all"
37 | ],
38 | "development": [
39 | "last 3 chrome version",
40 | "last 3 firefox version",
41 | "last 5 safari version"
42 | ]
43 | },
44 | "engines": {
45 | "node": ">=18.0"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/create-a-document.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # Create a Document
6 |
7 | Documents are **groups of pages** connected through:
8 |
9 | - a **sidebar**
10 | - **previous/next navigation**
11 | - **versioning**
12 |
13 | ## Create your first Doc
14 |
15 | Create a Markdown file at `docs/hello.md`:
16 |
17 | ```md title="docs/hello.md"
18 | # Hello
19 |
20 | This is my **first Docusaurus document**!
21 | ```
22 |
23 | A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello).
24 |
25 | ## Configure the Sidebar
26 |
27 | Docusaurus automatically **creates a sidebar** from the `docs` folder.
28 |
29 | Add metadata to customize the sidebar label and position:
30 |
31 | ```md title="docs/hello.md" {1-4}
32 | ---
33 | sidebar_label: "Hi!"
34 | sidebar_position: 3
35 | ---
36 |
37 | # Hello
38 |
39 | This is my **first Docusaurus document**!
40 | ```
41 |
42 | It is also possible to create your sidebar explicitly in `sidebars.js`:
43 |
44 | ```js title="sidebars.js"
45 | export default {
46 | tutorialSidebar: [
47 | "intro",
48 | // highlight-next-line
49 | "hello",
50 | {
51 | type: "category",
52 | label: "Tutorial",
53 | items: ["tutorial-basics/create-a-document"],
54 | },
55 | ],
56 | };
57 | ```
58 |
--------------------------------------------------------------------------------
/app/src/components/mode-toggle.tsx:
--------------------------------------------------------------------------------
1 | import { Moon, Sun } from "lucide-react";
2 |
3 | import { Button } from "@/components/ui/button";
4 |
5 | import {
6 | DropdownMenu,
7 | DropdownMenuContent,
8 | DropdownMenuItem,
9 | DropdownMenuTrigger,
10 | } from "@/components/ui/dropdown-menu";
11 |
12 | import { useTheme } from "@/components/theme-provider";
13 |
14 | export function ModeToggle() {
15 | const { setTheme } = useTheme();
16 |
17 | return (
18 |
19 |
20 |
23 |
24 |
25 | Toggle theme
26 |
27 |
28 |
29 | setTheme("light")}>
30 | Light
31 |
32 | setTheme("dark")}>
33 | Dark
34 |
35 | setTheme("system")}>
36 | System
37 |
38 |
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/doc/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import clsx from "clsx";
2 | import Link from "@docusaurus/Link";
3 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
4 | import Layout from "@theme/Layout";
5 | import HomepageFeatures from "@site/src/components/HomepageFeatures";
6 | import Heading from "@theme/Heading";
7 |
8 | import styles from "./index.module.css";
9 |
10 | function HomepageHeader() {
11 | const { siteConfig } = useDocusaurusContext();
12 | return (
13 |
30 | );
31 | }
32 |
33 | export default function Home(): JSX.Element {
34 | const { siteConfig } = useDocusaurusContext();
35 | return (
36 |
39 |
40 |
41 |
42 |
43 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/app/README.md:
--------------------------------------------------------------------------------
1 | # React + TypeScript + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
10 | ## Expanding the ESLint configuration
11 |
12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13 |
14 | - Configure the top-level `parserOptions` property like this:
15 |
16 | ```js
17 | export default {
18 | // other rules...
19 | parserOptions: {
20 | ecmaVersion: "latest",
21 | sourceType: "module",
22 | project: ["./tsconfig.json", "./tsconfig.node.json"],
23 | tsconfigRootDir: __dirname,
24 | },
25 | };
26 | ```
27 |
28 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
29 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
31 |
--------------------------------------------------------------------------------
/app/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-extras/manage-docs-versions.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Manage Docs Versions
6 |
7 | Docusaurus can manage multiple versions of your docs.
8 |
9 | ## Create a docs version
10 |
11 | Release a version 1.0 of your project:
12 |
13 | ```bash
14 | npm run docusaurus docs:version 1.0
15 | ```
16 |
17 | The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created.
18 |
19 | Your docs now have 2 versions:
20 |
21 | - `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs
22 | - `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs**
23 |
24 | ## Add a Version Dropdown
25 |
26 | To navigate seamlessly across versions, add a version dropdown.
27 |
28 | Modify the `docusaurus.config.js` file:
29 |
30 | ```js title="docusaurus.config.js"
31 | export default {
32 | themeConfig: {
33 | navbar: {
34 | items: [
35 | // highlight-start
36 | {
37 | type: "docsVersionDropdown",
38 | },
39 | // highlight-end
40 | ],
41 | },
42 | },
43 | };
44 | ```
45 |
46 | The docs version dropdown appears in your navbar:
47 |
48 | 
49 |
50 | ## Update an existing version
51 |
52 | It is possible to edit versioned docs in their respective folder:
53 |
54 | - `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello`
55 | - `docs/hello.md` updates `http://localhost:3000/docs/next/hello`
56 |
--------------------------------------------------------------------------------
/mobile/app/(home)/_layout.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Tabs } from "expo-router";
3 | import Ionicons from "@expo/vector-icons/Ionicons";
4 |
5 | export default function TabLayout() {
6 | return (
7 | <>
8 |
13 | (
18 |
23 | ),
24 | }}
25 | />
26 | (
31 |
36 | ),
37 | }}
38 | />
39 | (
44 |
49 | ),
50 | }}
51 | />
52 | (
57 |
62 | ),
63 | }}
64 | />
65 |
66 | >
67 | );
68 | }
69 |
--------------------------------------------------------------------------------
/doc/docs/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Tutorial Intro
6 |
7 | Let's discover **Docusaurus in less than 5 minutes**.
8 |
9 | ## Getting Started
10 |
11 | Get started by **creating a new site**.
12 |
13 | Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**.
14 |
15 | ### What you'll need
16 |
17 | - [Node.js](https://nodejs.org/en/download/) version 18.0 or above:
18 | - When installing Node.js, you are recommended to check all checkboxes related to dependencies.
19 |
20 | ## Generate a new site
21 |
22 | Generate a new Docusaurus site using the **classic template**.
23 |
24 | The classic template will automatically be added to your project after you run the command:
25 |
26 | ```bash
27 | npm init docusaurus@latest my-website classic
28 | ```
29 |
30 | You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor.
31 |
32 | The command also installs all necessary dependencies you need to run Docusaurus.
33 |
34 | ## Start your site
35 |
36 | Run the development server:
37 |
38 | ```bash
39 | cd my-website
40 | npm run start
41 | ```
42 |
43 | The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there.
44 |
45 | The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/.
46 |
47 | Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes.
48 |
--------------------------------------------------------------------------------
/mobile/app/auth.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import { UserAuthForm } from "@/components/user-auth-form";
4 | import Text from "@/components/text";
5 |
6 | export default function Auth() {
7 | return (
8 |
9 |
10 |
11 | Spata
12 |
13 | Enter your email below to sign in
14 |
15 |
16 |
17 |
18 |
19 |
20 | By clicking continue, you agree to our{" "}
21 |
22 |
23 | Terms of Service and{" "}
24 | Privacy Policy .
25 |
26 |
27 |
28 | );
29 | }
30 |
31 | const styles = StyleSheet.create({
32 | container: {
33 | paddingTop: 80,
34 | flex: 1,
35 | alignItems: "center",
36 | },
37 | innerContainer: {
38 | justifyContent: "center",
39 | alignItems: "center",
40 | },
41 | header: {
42 | flexDirection: "column",
43 | alignItems: "center",
44 | marginBottom: 16,
45 | },
46 | title: {
47 | fontSize: 24,
48 | fontWeight: "600",
49 | textAlign: "center",
50 | },
51 | subtitle: {
52 | fontSize: 14,
53 | color: "#6b7280",
54 | textAlign: "center",
55 | },
56 | termsText: {
57 | paddingHorizontal: 32,
58 | paddingVertical: 2,
59 | fontSize: 14,
60 | color: "#6b7280",
61 | textAlign: "center",
62 | },
63 | link: {
64 | textDecorationLine: "underline",
65 | color: "#3b82f6",
66 | },
67 | });
68 |
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "test": "vitest",
8 | "dev": "vite",
9 | "build": "tsc && vite build",
10 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
11 | "preview": "vite preview"
12 | },
13 | "dependencies": {
14 | "@radix-ui/react-dropdown-menu": "^2.1.2",
15 | "@radix-ui/react-icons": "^1.3.0",
16 | "@radix-ui/react-label": "^2.1.0",
17 | "@radix-ui/react-slot": "^1.1.0",
18 | "@tanstack/react-query": "^5.59.0",
19 | "@tanstack/react-query-devtools": "^5.59.0",
20 | "class-variance-authority": "^0.7.0",
21 | "clsx": "^2.1.1",
22 | "lucide-react": "^0.447.0",
23 | "react": "^18.2.0",
24 | "react-dom": "^18.2.0",
25 | "react-hook-form": "^7.53.0",
26 | "react-router": "^7.1.1",
27 | "tailwind-merge": "^2.5.3",
28 | "tailwindcss-animate": "^1.0.7"
29 | },
30 | "devDependencies": {
31 | "@tanstack/eslint-plugin-query": "^5.59.1",
32 | "@testing-library/dom": "^10.4.0",
33 | "@testing-library/jest-dom": "^6.5.0",
34 | "@testing-library/react": "^16.0.1",
35 | "@types/node": "^22.7.4",
36 | "@types/react": "^18.2.43",
37 | "@types/react-dom": "^18.2.17",
38 | "@typescript-eslint/eslint-plugin": "^6.14.0",
39 | "@typescript-eslint/parser": "^6.14.0",
40 | "@vitejs/plugin-react": "^4.2.1",
41 | "autoprefixer": "^10.4.20",
42 | "eslint": "^8.55.0",
43 | "eslint-plugin-react-hooks": "^4.6.0",
44 | "eslint-plugin-react-refresh": "^0.4.5",
45 | "jsdom": "^25.0.1",
46 | "postcss": "^8.4.47",
47 | "tailwindcss": "^3.4.13",
48 | "typescript": "^5.2.2",
49 | "vite": "^5.0.8",
50 | "vitest": "^2.1.2"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | darkMode: ["class"],
4 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
5 | theme: {
6 | extend: {
7 | borderRadius: {
8 | lg: "var(--radius)",
9 | md: "calc(var(--radius) - 2px)",
10 | sm: "calc(var(--radius) - 4px)",
11 | },
12 | colors: {
13 | background: "hsl(var(--background))",
14 | foreground: "hsl(var(--foreground))",
15 | card: {
16 | DEFAULT: "hsl(var(--card))",
17 | foreground: "hsl(var(--card-foreground))",
18 | },
19 | popover: {
20 | DEFAULT: "hsl(var(--popover))",
21 | foreground: "hsl(var(--popover-foreground))",
22 | },
23 | primary: {
24 | DEFAULT: "hsl(var(--primary))",
25 | foreground: "hsl(var(--primary-foreground))",
26 | },
27 | secondary: {
28 | DEFAULT: "hsl(var(--secondary))",
29 | foreground: "hsl(var(--secondary-foreground))",
30 | },
31 | muted: {
32 | DEFAULT: "hsl(var(--muted))",
33 | foreground: "hsl(var(--muted-foreground))",
34 | },
35 | accent: {
36 | DEFAULT: "hsl(var(--accent))",
37 | foreground: "hsl(var(--accent-foreground))",
38 | },
39 | destructive: {
40 | DEFAULT: "hsl(var(--destructive))",
41 | foreground: "hsl(var(--destructive-foreground))",
42 | },
43 | border: "hsl(var(--border))",
44 | input: "hsl(var(--input))",
45 | ring: "hsl(var(--ring))",
46 | chart: {
47 | 1: "hsl(var(--chart-1))",
48 | 2: "hsl(var(--chart-2))",
49 | 3: "hsl(var(--chart-3))",
50 | 4: "hsl(var(--chart-4))",
51 | 5: "hsl(var(--chart-5))",
52 | },
53 | },
54 | },
55 | },
56 | plugins: [require("tailwindcss-animate")],
57 | };
58 |
--------------------------------------------------------------------------------
/app/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 | @layer base {
5 | :root {
6 | --background: 0 0% 100%;
7 | --foreground: 0 0% 3.9%;
8 | --card: 0 0% 100%;
9 | --card-foreground: 0 0% 3.9%;
10 | --popover: 0 0% 100%;
11 | --popover-foreground: 0 0% 3.9%;
12 | --primary: 0 0% 9%;
13 | --primary-foreground: 0 0% 98%;
14 | --secondary: 0 0% 96.1%;
15 | --secondary-foreground: 0 0% 9%;
16 | --muted: 0 0% 96.1%;
17 | --muted-foreground: 0 0% 45.1%;
18 | --accent: 0 0% 96.1%;
19 | --accent-foreground: 0 0% 9%;
20 | --destructive: 0 84.2% 60.2%;
21 | --destructive-foreground: 0 0% 98%;
22 | --border: 0 0% 89.8%;
23 | --input: 0 0% 89.8%;
24 | --ring: 0 0% 3.9%;
25 | --chart-1: 12 76% 61%;
26 | --chart-2: 173 58% 39%;
27 | --chart-3: 197 37% 24%;
28 | --chart-4: 43 74% 66%;
29 | --chart-5: 27 87% 67%;
30 | --radius: 0.5rem;
31 | }
32 | .dark {
33 | --background: 0 0% 3.9%;
34 | --foreground: 0 0% 98%;
35 | --card: 0 0% 3.9%;
36 | --card-foreground: 0 0% 98%;
37 | --popover: 0 0% 3.9%;
38 | --popover-foreground: 0 0% 98%;
39 | --primary: 0 0% 98%;
40 | --primary-foreground: 0 0% 9%;
41 | --secondary: 0 0% 14.9%;
42 | --secondary-foreground: 0 0% 98%;
43 | --muted: 0 0% 14.9%;
44 | --muted-foreground: 0 0% 63.9%;
45 | --accent: 0 0% 14.9%;
46 | --accent-foreground: 0 0% 98%;
47 | --destructive: 0 62.8% 30.6%;
48 | --destructive-foreground: 0 0% 98%;
49 | --border: 0 0% 14.9%;
50 | --input: 0 0% 14.9%;
51 | --ring: 0 0% 83.1%;
52 | --chart-1: 220 70% 50%;
53 | --chart-2: 160 60% 45%;
54 | --chart-3: 30 80% 55%;
55 | --chart-4: 280 65% 60%;
56 | --chart-5: 340 75% 55%;
57 | }
58 | }
59 | @layer base {
60 | * {
61 | @apply border-border;
62 | }
63 | body {
64 | @apply bg-background text-foreground;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/components/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, useEffect, useState } from "react";
2 |
3 | type Theme = "dark" | "light" | "system";
4 |
5 | type ThemeProviderProps = {
6 | children: React.ReactNode;
7 | defaultTheme?: Theme;
8 | storageKey?: string;
9 | };
10 |
11 | type ThemeProviderState = {
12 | theme: Theme;
13 | setTheme: (theme: Theme) => void;
14 | };
15 |
16 | const initialState: ThemeProviderState = {
17 | theme: "system",
18 | setTheme: () => null,
19 | };
20 |
21 | const ThemeProviderContext = createContext(initialState);
22 |
23 | export function ThemeProvider({
24 | children,
25 | defaultTheme = "system",
26 | storageKey = "app-ui-theme",
27 | ...props
28 | }: ThemeProviderProps) {
29 | const [theme, setTheme] = useState(
30 | () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
31 | );
32 |
33 | useEffect(() => {
34 | const root = window.document.documentElement;
35 |
36 | root.classList.remove("light", "dark");
37 |
38 | if (theme === "system") {
39 | const systemTheme = window.matchMedia(
40 | "(prefers-color-scheme: dark)",
41 | ).matches
42 | ? "dark"
43 | : "light";
44 |
45 | root.classList.add(systemTheme);
46 | return;
47 | }
48 |
49 | root.classList.add(theme);
50 | }, [theme]);
51 |
52 | const value = {
53 | theme,
54 | setTheme: (theme: Theme) => {
55 | localStorage.setItem(storageKey, theme);
56 | setTheme(theme);
57 | },
58 | };
59 |
60 | return (
61 |
64 | {children}
65 |
66 | );
67 | }
68 |
69 | export const useTheme = () => {
70 | const context = useContext(ThemeProviderContext);
71 |
72 | if (context === undefined)
73 | throw new Error("useTheme must be used within a ThemeProvider");
74 |
75 | return context;
76 | };
77 |
--------------------------------------------------------------------------------
/mobile/components/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useContext, useEffect, useState } from "react";
2 |
3 | import { ThemeProvider as NavigationThemeProvider } from "@react-navigation/native";
4 |
5 | import AsyncStorage from "@react-native-async-storage/async-storage";
6 | import { Appearance } from "react-native";
7 | import { StatusBar } from "expo-status-bar";
8 |
9 | import { LightTheme, DarkTheme } from "@/constants/themes";
10 |
11 | type ThemeContextType = {
12 | isDark: boolean;
13 | toggleTheme: () => void;
14 | };
15 |
16 | const ThemeContext = createContext(null);
17 |
18 | const THEME_STORAGE_KEY = "app-ui-theme";
19 |
20 | export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
21 | const systemColorScheme = Appearance.getColorScheme();
22 | const [isDark, setisDark] = useState(systemColorScheme === "dark");
23 |
24 | useEffect(() => {
25 | const loadTheme = async () => {
26 | const savedTheme = await AsyncStorage.getItem(THEME_STORAGE_KEY);
27 | if (savedTheme !== null) {
28 | setisDark(savedTheme === "dark");
29 | }
30 | };
31 |
32 | loadTheme();
33 | }, []);
34 |
35 | const toggleTheme = async () => {
36 | const newTheme = isDark ? "light" : "dark";
37 | setisDark(!isDark);
38 |
39 | await AsyncStorage.setItem(THEME_STORAGE_KEY, newTheme);
40 | };
41 |
42 | return (
43 |
44 |
45 | {children}
46 |
47 |
48 |
49 | );
50 | };
51 |
52 | export const useTheme = () => {
53 | const context = useContext(ThemeContext);
54 | if (!context) {
55 | throw new Error("useTheme must be used within an ThemeProvider");
56 | }
57 |
58 | return context;
59 | };
60 |
--------------------------------------------------------------------------------
/mobile/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mobile",
3 | "main": "expo-router/entry",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "reset-project": "node ./scripts/reset-project.js",
8 | "android": "expo start --android",
9 | "ios": "expo start --ios",
10 | "web": "expo start --web",
11 | "test": "jest --watchAll",
12 | "lint": "expo lint"
13 | },
14 | "jest": {
15 | "preset": "jest-expo"
16 | },
17 | "dependencies": {
18 | "@expo/vector-icons": "^14.0.2",
19 | "@react-native-async-storage/async-storage": "1.23.1",
20 | "@react-navigation/native": "^6.0.2",
21 | "@tanstack/react-query": "^5.59.0",
22 | "expo": "~51.0.28",
23 | "expo-constants": "~16.0.2",
24 | "expo-font": "~12.0.9",
25 | "expo-linking": "~6.3.1",
26 | "expo-router": "~3.5.23",
27 | "expo-splash-screen": "~0.27.5",
28 | "expo-status-bar": "~1.12.1",
29 | "expo-system-ui": "~3.0.7",
30 | "expo-web-browser": "~13.0.3",
31 | "react": "18.2.0",
32 | "react-dom": "18.2.0",
33 | "react-hook-form": "^7.53.0",
34 | "react-native": "0.74.5",
35 | "react-native-gesture-handler": "~2.16.1",
36 | "react-native-reanimated": "~3.10.1",
37 | "react-native-safe-area-context": "4.10.5",
38 | "react-native-screens": "3.31.1",
39 | "react-native-web": "~0.19.10",
40 | "react-native-svg": "15.2.0"
41 | },
42 | "devDependencies": {
43 | "@babel/core": "^7.20.0",
44 | "@tanstack/eslint-plugin-query": "^5.59.1",
45 | "@testing-library/react-native": "^12.7.2",
46 | "@types/jest": "^29.5.12",
47 | "@types/react": "~18.2.45",
48 | "@types/react-test-renderer": "^18.0.7",
49 | "eslint": "^8.57.0",
50 | "eslint-config-expo": "^7.1.2",
51 | "jest": "^29.2.1",
52 | "jest-expo": "~51.0.3",
53 | "react-test-renderer": "18.2.0",
54 | "typescript": "~5.3.3"
55 | },
56 | "private": true,
57 | "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72"
58 | }
59 |
--------------------------------------------------------------------------------
/mobile/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to your Expo app 👋
2 |
3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
4 |
5 | ## Get started
6 |
7 | 1. Install dependencies
8 |
9 | ```bash
10 | npm install
11 | ```
12 |
13 | 2. Start the app
14 |
15 | ```bash
16 | npx expo start
17 | ```
18 |
19 | In the output, you'll find options to open the app in a
20 |
21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/)
22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
25 |
26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
27 |
28 | ## Get a fresh project
29 |
30 | When you're ready, run:
31 |
32 | ```bash
33 | npm run reset-project
34 | ```
35 |
36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
37 |
38 | ## Learn more
39 |
40 | To learn more about developing your project with Expo, look at the following resources:
41 |
42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
43 | - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
44 |
45 | ## Join the community
46 |
47 | Join our community of developers creating universal apps.
48 |
49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
51 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-extras/translate-your-site.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # Translate your site
6 |
7 | Let's translate `docs/intro.md` to French.
8 |
9 | ## Configure i18n
10 |
11 | Modify `docusaurus.config.js` to add support for the `fr` locale:
12 |
13 | ```js title="docusaurus.config.js"
14 | export default {
15 | i18n: {
16 | defaultLocale: "en",
17 | locales: ["en", "fr"],
18 | },
19 | };
20 | ```
21 |
22 | ## Translate a doc
23 |
24 | Copy the `docs/intro.md` file to the `i18n/fr` folder:
25 |
26 | ```bash
27 | mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/
28 |
29 | cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md
30 | ```
31 |
32 | Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French.
33 |
34 | ## Start your localized site
35 |
36 | Start your site on the French locale:
37 |
38 | ```bash
39 | npm run start -- --locale fr
40 | ```
41 |
42 | Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated.
43 |
44 | :::caution
45 |
46 | In development, you can only use one locale at a time.
47 |
48 | :::
49 |
50 | ## Add a Locale Dropdown
51 |
52 | To navigate seamlessly across languages, add a locale dropdown.
53 |
54 | Modify the `docusaurus.config.js` file:
55 |
56 | ```js title="docusaurus.config.js"
57 | export default {
58 | themeConfig: {
59 | navbar: {
60 | items: [
61 | // highlight-start
62 | {
63 | type: "localeDropdown",
64 | },
65 | // highlight-end
66 | ],
67 | },
68 | },
69 | };
70 | ```
71 |
72 | The locale dropdown now appears in your navbar:
73 |
74 | 
75 |
76 | ## Build your localized site
77 |
78 | Build your site for a specific locale:
79 |
80 | ```bash
81 | npm run build -- --locale fr
82 | ```
83 |
84 | Or build your site to include all the locales at once:
85 |
86 | ```bash
87 | npm run build
88 | ```
89 |
--------------------------------------------------------------------------------
/app/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Slot } from "@radix-ui/react-slot";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16 | outline:
17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20 | ghost: "hover:bg-accent hover:text-accent-foreground",
21 | link: "text-primary underline-offset-4 hover:underline",
22 | },
23 | size: {
24 | default: "h-9 px-4 py-2",
25 | sm: "h-8 rounded-md px-3 text-xs",
26 | lg: "h-10 rounded-md px-8",
27 | icon: "h-9 w-9",
28 | },
29 | },
30 | defaultVariants: {
31 | variant: "default",
32 | size: "default",
33 | },
34 | },
35 | );
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean;
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : "button";
46 | return (
47 |
52 | );
53 | },
54 | );
55 | Button.displayName = "Button";
56 |
57 | export { Button, buttonVariants };
58 |
--------------------------------------------------------------------------------
/doc/src/components/HomepageFeatures/index.tsx:
--------------------------------------------------------------------------------
1 | import clsx from "clsx";
2 | import Heading from "@theme/Heading";
3 | import styles from "./styles.module.css";
4 |
5 | type FeatureItem = {
6 | title: string;
7 | Svg: React.ComponentType>;
8 | description: JSX.Element;
9 | };
10 |
11 | const FeatureList: FeatureItem[] = [
12 | {
13 | title: "Easy to Use",
14 | Svg: require("@site/static/img/undraw_docusaurus_mountain.svg").default,
15 | description: (
16 | <>
17 | Docusaurus was designed from the ground up to be easily
18 | installed and used to get your website up and running quickly.
19 | >
20 | ),
21 | },
22 | {
23 | title: "Focus on What Matters",
24 | Svg: require("@site/static/img/undraw_docusaurus_tree.svg").default,
25 | description: (
26 | <>
27 | Docusaurus lets you focus on your docs, and we'll do the
28 | chores. Go ahead and move your docs into the docs{" "}
29 | directory.
30 | >
31 | ),
32 | },
33 | {
34 | title: "Powered by React",
35 | Svg: require("@site/static/img/undraw_docusaurus_react.svg").default,
36 | description: (
37 | <>
38 | Extend or customize your website layout by reusing React.
39 | Docusaurus can be extended while reusing the same header and
40 | footer.
41 | >
42 | ),
43 | },
44 | ];
45 |
46 | function Feature({ title, Svg, description }: FeatureItem) {
47 | return (
48 |
49 |
50 |
54 |
55 |
56 |
{title}
57 |
{description}
58 |
59 |
60 | );
61 | }
62 |
63 | export default function HomepageFeatures(): JSX.Element {
64 | return (
65 |
66 |
67 |
68 | {FeatureList.map((props, idx) => (
69 |
73 | ))}
74 |
75 |
76 |
77 | );
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/components/user-auth-form.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { Icons } from "@/components/icons";
4 | import { Button } from "@/components/ui/button";
5 | import { Input } from "@/components/ui/input";
6 | import { Label } from "@/components/ui/label";
7 |
8 | import { useForm, SubmitHandler } from "react-hook-form";
9 |
10 | interface UserAuthFormProps extends React.HTMLAttributes {}
11 | type Inputs = { email: string };
12 |
13 | export function UserAuthForm({ ...props }: UserAuthFormProps) {
14 | const [isLoading, setIsLoading] = React.useState(false);
15 |
16 | const {
17 | register,
18 | handleSubmit,
19 | formState: { errors },
20 | } = useForm();
21 |
22 | const onSubmit: SubmitHandler = data => {
23 | setIsLoading(true);
24 |
25 | setTimeout(() => {
26 | console.log(data);
27 | setIsLoading(false);
28 | }, 3000);
29 | };
30 |
31 | return (
32 |
35 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Or continue with
74 |
75 |
76 |
77 |
78 |
82 | {isLoading ? (
83 |
84 | ) : (
85 |
86 | )}{" "}
87 | GitHub
88 |
89 |
93 | {isLoading ? (
94 |
95 | ) : (
96 |
97 | )}{" "}
98 | Google
99 |
100 |
101 |
102 | );
103 | }
104 |
--------------------------------------------------------------------------------
/doc/blog/2019-05-29-long-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: long-blog-post
3 | title: Long Blog Post
4 | authors: yangshun
5 | tags: [hello, docusaurus]
6 | ---
7 |
8 | This is the summary of a very long blog post,
9 |
10 | Use a `` comment to limit blog post size in the list view.
11 |
12 |
13 |
14 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
15 |
16 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
17 |
18 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
19 |
20 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
21 |
22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
23 |
24 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
25 |
26 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
27 |
28 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
29 |
30 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
31 |
32 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
33 |
34 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
35 |
36 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
37 |
38 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
39 |
40 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
41 |
42 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
43 |
44 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
45 |
--------------------------------------------------------------------------------
/doc/docs/tutorial-basics/markdown-features.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 4
3 | ---
4 |
5 | # Markdown Features
6 |
7 | Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**.
8 |
9 | ## Front Matter
10 |
11 | Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/):
12 |
13 | ```text title="my-doc.md"
14 | // highlight-start
15 | ---
16 | id: my-doc-id
17 | title: My document title
18 | description: My document description
19 | slug: /my-custom-url
20 | ---
21 | // highlight-end
22 |
23 | ## Markdown heading
24 |
25 | Markdown text with [links](./hello.md)
26 | ```
27 |
28 | ## Links
29 |
30 | Regular Markdown links are supported, using url paths or relative file paths.
31 |
32 | ```md
33 | Let's see how to [Create a page](/create-a-page).
34 | ```
35 |
36 | ```md
37 | Let's see how to [Create a page](./create-a-page.md).
38 | ```
39 |
40 | **Result:** Let's see how to [Create a page](./create-a-page.md).
41 |
42 | ## Images
43 |
44 | Regular Markdown images are supported.
45 |
46 | You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`):
47 |
48 | ```md
49 | 
50 | ```
51 |
52 | 
53 |
54 | You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them:
55 |
56 | ```md
57 | 
58 | ```
59 |
60 | ## Code Blocks
61 |
62 | Markdown code blocks are supported with Syntax highlighting.
63 |
64 | ````md
65 | ```jsx title="src/components/HelloDocusaurus.js"
66 | function HelloDocusaurus() {
67 | return Hello, Docusaurus! ;
68 | }
69 | ```
70 | ````
71 |
72 | ```jsx title="src/components/HelloDocusaurus.js"
73 | function HelloDocusaurus() {
74 | return Hello, Docusaurus! ;
75 | }
76 | ```
77 |
78 | ## Admonitions
79 |
80 | Docusaurus has a special syntax to create admonitions and callouts:
81 |
82 | ```md
83 | :::tip My tip
84 |
85 | Use this awesome feature option
86 |
87 | :::
88 |
89 | :::danger Take care
90 |
91 | This action is dangerous
92 |
93 | :::
94 | ```
95 |
96 | :::tip My tip
97 |
98 | Use this awesome feature option
99 |
100 | :::
101 |
102 | :::danger Take care
103 |
104 | This action is dangerous
105 |
106 | :::
107 |
108 | ## MDX and React Components
109 |
110 | [MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**:
111 |
112 | ```jsx
113 | export const Highlight = ({children, color}) => (
114 | {
123 | alert(`You clicked the color ${color} with label ${children}`)
124 | }}>
125 | {children}
126 |
127 | );
128 |
129 | This is Docusaurus green !
130 |
131 | This is Facebook blue !
132 | ```
133 |
134 | export const Highlight = ({ children, color }) => (
135 | {
144 | alert(`You clicked the color ${color} with label ${children}`);
145 | }}>
146 | {children}
147 |
148 | );
149 |
150 | This is Docusaurus green !
151 |
152 | This is Facebook blue !
153 |
--------------------------------------------------------------------------------
/app/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/docusaurus.config.ts:
--------------------------------------------------------------------------------
1 | import { themes as prismThemes } from "prism-react-renderer";
2 | import type { Config } from "@docusaurus/types";
3 | import type * as Preset from "@docusaurus/preset-classic";
4 |
5 | const config: Config = {
6 | title: "Spata",
7 | tagline: "SPA Starter",
8 | favicon: "img/favicon.ico",
9 |
10 | // Set the production url of your site here
11 | url: "https://your-docusaurus-site.example.com",
12 | // Set the // pathname under which your site is served
13 | // For GitHub pages deployment, it is often '//'
14 | baseUrl: "/",
15 |
16 | // GitHub pages deployment config.
17 | // If you aren't using GitHub pages, you don't need these.
18 | organizationName: "eimg", // Usually your GitHub org/user name.
19 | projectName: "spata", // Usually your repo name.
20 |
21 | onBrokenLinks: "throw",
22 | onBrokenMarkdownLinks: "warn",
23 |
24 | // Even if you don't use internationalization, you can use this field to set
25 | // useful metadata like html lang. For example, if your site is Chinese, you
26 | // may want to replace "en" with "zh-Hans".
27 | i18n: {
28 | defaultLocale: "en",
29 | locales: ["en"],
30 | },
31 |
32 | presets: [
33 | [
34 | "classic",
35 | {
36 | docs: {
37 | sidebarPath: "./sidebars.ts",
38 | // Please change this to your repo.
39 | // Remove this to remove the "edit this page" links.
40 | editUrl:
41 | "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/",
42 | },
43 | blog: {
44 | showReadingTime: true,
45 | feedOptions: {
46 | type: ["rss", "atom"],
47 | xslt: true,
48 | },
49 | // Please change this to your repo.
50 | // Remove this to remove the "edit this page" links.
51 | editUrl:
52 | "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/",
53 | // Useful options to enforce blogging best practices
54 | onInlineTags: "warn",
55 | onInlineAuthors: "warn",
56 | onUntruncatedBlogPosts: "warn",
57 | },
58 | theme: {
59 | customCss: "./src/css/custom.css",
60 | },
61 | } satisfies Preset.Options,
62 | ],
63 | ],
64 |
65 | themeConfig: {
66 | // Replace with your project's social card
67 | image: "img/docusaurus-social-card.jpg",
68 | navbar: {
69 | title: "Spata",
70 | logo: {
71 | alt: "Spata Logo",
72 | src: "img/logo.svg",
73 | },
74 | items: [
75 | {
76 | type: "docSidebar",
77 | sidebarId: "tutorialSidebar",
78 | position: "left",
79 | label: "Tutorial",
80 | },
81 | { to: "/blog", label: "Blog", position: "left" },
82 | {
83 | href: "https://github.com/facebook/docusaurus",
84 | label: "GitHub",
85 | position: "right",
86 | },
87 | ],
88 | },
89 | footer: {
90 | style: "light",
91 | links: [
92 | {
93 | title: "Docs",
94 | items: [
95 | {
96 | label: "Tutorial",
97 | to: "/docs/intro",
98 | },
99 | ],
100 | },
101 | {
102 | title: "Community",
103 | items: [
104 | {
105 | label: "Stack Overflow",
106 | href: "https://stackoverflow.com/questions/tagged/docusaurus",
107 | },
108 | {
109 | label: "Discord",
110 | href: "https://discordapp.com/invite/docusaurus",
111 | },
112 | {
113 | label: "Twitter",
114 | href: "https://twitter.com/docusaurus",
115 | },
116 | ],
117 | },
118 | {
119 | title: "More",
120 | items: [
121 | {
122 | label: "Blog",
123 | to: "/blog",
124 | },
125 | {
126 | label: "GitHub",
127 | href: "https://github.com/facebook/docusaurus",
128 | },
129 | ],
130 | },
131 | ],
132 | copyright: `Copyright © ${new Date().getFullYear()} Spata. Built with Docusaurus.`,
133 | },
134 | prism: {
135 | theme: prismThemes.github,
136 | darkTheme: prismThemes.dracula,
137 | },
138 | } satisfies Preset.ThemeConfig,
139 | };
140 |
141 | export default config;
142 |
--------------------------------------------------------------------------------
/mobile/components/user-auth-form.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | View,
4 | TextInput,
5 | StyleSheet,
6 | ActivityIndicator,
7 | TouchableOpacity,
8 | } from "react-native";
9 |
10 | import Text from "./text";
11 | import { useTheme } from "@react-navigation/native";
12 | import Ionicons from "@expo/vector-icons/Ionicons";
13 | import { useForm, Controller } from "react-hook-form";
14 |
15 | export function UserAuthForm() {
16 | const [isLoading, setIsLoading] = useState(false);
17 |
18 | const {
19 | control,
20 | handleSubmit,
21 | formState: { errors },
22 | } = useForm();
23 |
24 | const onSubmit = data => {
25 | setIsLoading(true);
26 |
27 | setTimeout(() => {
28 | console.log(data);
29 | setIsLoading(false);
30 | }, 3000);
31 | };
32 |
33 | const { colors } = useTheme();
34 |
35 | return (
36 |
37 |
38 | (
44 |
55 | )}
56 | name="email"
57 | />
58 | {errors.email && (
59 |
60 | Email is required.
61 |
62 | )}
63 |
64 |
65 |
69 | Sign in with email
70 |
71 | {isLoading && }
72 |
73 |
74 |
75 |
80 | Or continue with
81 |
82 |
83 |
84 |
85 | {}}
88 | style={[styles.socialButton, { borderColor: colors.text }]}>
89 |
94 | Github
95 |
96 | {}}
99 | style={[styles.socialButton, { borderColor: colors.text }]}>
100 |
105 | Google
106 |
107 |
108 |
109 | );
110 | }
111 |
112 | const styles = StyleSheet.create({
113 | container: {
114 | marginVertical: 10,
115 | },
116 | inputContainer: {
117 | width: 300,
118 | marginBottom: 12,
119 | },
120 | input: {
121 | borderWidth: 1,
122 | padding: 8,
123 | borderRadius: 4,
124 | borderColor: "#ccc",
125 | },
126 | spinner: {
127 | marginTop: 8,
128 | },
129 | button: {
130 | paddingHorizontal: 20,
131 | paddingVertical: 12,
132 | borderRadius: 4,
133 | alignItems: "center",
134 | },
135 | separator: {
136 | marginVertical: 16,
137 | alignItems: "center",
138 | justifyContent: "center",
139 | },
140 | line: {
141 | position: "absolute",
142 | borderBottomWidth: 1,
143 | borderColor: "#6b7280",
144 | width: "100%",
145 | },
146 | orText: {
147 | marginVertical: 8,
148 | fontSize: 12,
149 | textAlign: "center",
150 | paddingHorizontal: 10,
151 | color: "#6b7280",
152 | },
153 | socialButtons: {
154 | gap: 10,
155 | },
156 | socialButton: {
157 | flexDirection: "row",
158 | paddingHorizontal: 20,
159 | paddingVertical: 12,
160 | borderRadius: 4,
161 | justifyContent: "center",
162 | alignItems: "center",
163 | gap: 5,
164 | borderWidth: 1,
165 | marginBottom: 10,
166 | },
167 | });
168 |
--------------------------------------------------------------------------------
/doc/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/components/ui/dropdown-menu.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
3 | import {
4 | CheckIcon,
5 | ChevronRightIcon,
6 | DotFilledIcon,
7 | } from "@radix-ui/react-icons";
8 |
9 | import { cn } from "@/lib/utils";
10 |
11 | const DropdownMenu = DropdownMenuPrimitive.Root;
12 |
13 | const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
14 |
15 | const DropdownMenuGroup = DropdownMenuPrimitive.Group;
16 |
17 | const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
18 |
19 | const DropdownMenuSub = DropdownMenuPrimitive.Sub;
20 |
21 | const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
22 |
23 | const DropdownMenuSubTrigger = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef & {
26 | inset?: boolean;
27 | }
28 | >(({ className, inset, children, ...props }, ref) => (
29 |
37 | {children}
38 |
39 |
40 | ));
41 | DropdownMenuSubTrigger.displayName =
42 | DropdownMenuPrimitive.SubTrigger.displayName;
43 |
44 | const DropdownMenuSubContent = React.forwardRef<
45 | React.ElementRef,
46 | React.ComponentPropsWithoutRef
47 | >(({ className, ...props }, ref) => (
48 |
56 | ));
57 | DropdownMenuSubContent.displayName =
58 | DropdownMenuPrimitive.SubContent.displayName;
59 |
60 | const DropdownMenuContent = React.forwardRef<
61 | React.ElementRef,
62 | React.ComponentPropsWithoutRef
63 | >(({ className, sideOffset = 4, ...props }, ref) => (
64 |
65 |
75 |
76 | ));
77 | DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
78 |
79 | const DropdownMenuItem = React.forwardRef<
80 | React.ElementRef,
81 | React.ComponentPropsWithoutRef & {
82 | inset?: boolean;
83 | }
84 | >(({ className, inset, ...props }, ref) => (
85 |
94 | ));
95 | DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
96 |
97 | const DropdownMenuCheckboxItem = React.forwardRef<
98 | React.ElementRef,
99 | React.ComponentPropsWithoutRef
100 | >(({ className, children, checked, ...props }, ref) => (
101 |
109 |
110 |
111 |
112 |
113 |
114 | {children}
115 |
116 | ));
117 | DropdownMenuCheckboxItem.displayName =
118 | DropdownMenuPrimitive.CheckboxItem.displayName;
119 |
120 | const DropdownMenuRadioItem = React.forwardRef<
121 | React.ElementRef,
122 | React.ComponentPropsWithoutRef
123 | >(({ className, children, ...props }, ref) => (
124 |
131 |
132 |
133 |
134 |
135 |
136 | {children}
137 |
138 | ));
139 | DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
140 |
141 | const DropdownMenuLabel = React.forwardRef<
142 | React.ElementRef,
143 | React.ComponentPropsWithoutRef & {
144 | inset?: boolean;
145 | }
146 | >(({ className, inset, ...props }, ref) => (
147 |
156 | ));
157 | DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
158 |
159 | const DropdownMenuSeparator = React.forwardRef<
160 | React.ElementRef,
161 | React.ComponentPropsWithoutRef
162 | >(({ className, ...props }, ref) => (
163 |
168 | ));
169 | DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
170 |
171 | const DropdownMenuShortcut = ({
172 | className,
173 | ...props
174 | }: React.HTMLAttributes) => {
175 | return (
176 |
183 | );
184 | };
185 | DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
186 |
187 | export {
188 | DropdownMenu,
189 | DropdownMenuTrigger,
190 | DropdownMenuContent,
191 | DropdownMenuItem,
192 | DropdownMenuCheckboxItem,
193 | DropdownMenuRadioItem,
194 | DropdownMenuLabel,
195 | DropdownMenuSeparator,
196 | DropdownMenuShortcut,
197 | DropdownMenuGroup,
198 | DropdownMenuPortal,
199 | DropdownMenuSub,
200 | DropdownMenuSubContent,
201 | DropdownMenuSubTrigger,
202 | DropdownMenuRadioGroup,
203 | };
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SPATA - Full-Stack Starter Template
2 |
3 | [](https://choosealicense.com/licenses/mit/)
4 | [](https://nodejs.org/)
5 | [](https://www.typescriptlang.org/)
6 |
7 | > **SPATA** (SPA Starter) - A comprehensive, production-ready full-stack starter template that gets you from zero to deployment in minutes, not hours.
8 |
9 | ## 🚀 What is SPATA?
10 |
11 | SPATA eliminates the tedious initial setup tasks that every modern web project requires. Instead of spending days configuring linters, tests, routing, state management, and essential packages, you can focus on building your actual product from day one.
12 |
13 | ### ✨ Perfect for:
14 | - 🏢 **Startups** needing to move fast with proven architecture
15 | - 👨💻 **Developers** who want to skip the boilerplate setup
16 | - 🎯 **Product teams** focusing on features, not configuration
17 | - 📚 **Learning** modern full-stack development patterns
18 |
19 | ## 🏗️ Architecture Overview
20 |
21 | SPATA provides a complete ecosystem with four integrated components:
22 |
23 | ```
24 | 📦 SPATA
25 | ├── 🌐 Web App (React SPA)
26 | ├── 📱 Mobile App (React Native + Expo)
27 | ├── ⚡ API Backend (Express + TypeScript)
28 | └── 📖 Documentation (Docusaurus)
29 | ```
30 |
31 | ## 🛠️ Tech Stack
32 |
33 | ### Web App (`/app`)
34 | - **Framework**: React 18 + Vite (lightning-fast development)
35 | - **Language**: TypeScript (type safety)
36 | - **Styling**: Tailwind CSS + shadcn/ui (beautiful, accessible components)
37 | - **Routing**: React Router v7 (client-side routing)
38 | - **State Management**: React Query (server state) + React Hook Form (form state)
39 | - **Testing**: Vitest + React Testing Library + jsdom
40 | - **Theme**: Built-in light/dark mode switcher
41 | - **Linting**: ESLint with React Query rules
42 |
43 | ### Mobile App (`/mobile`)
44 | - **Framework**: React Native + Expo (cross-platform mobile)
45 | - **Language**: TypeScript
46 | - **Navigation**: Expo Router (file-based routing)
47 | - **State Management**: React Query + React Hook Form
48 | - **Testing**: Jest + React Native Testing Library
49 | - **Theme**: Custom theme system with light/dark mode
50 | - **Linting**: ESLint with React Query rules
51 |
52 | ### API Backend (`/api`)
53 | - **Runtime**: Node.js + Express
54 | - **Language**: TypeScript
55 | - **Database**: Prisma ORM + SQLite (easily swappable)
56 | - **Validation**: Express Validator
57 | - **Testing**: Jest + supertest
58 | - **Development**: Hot reload with nodemon
59 | - **Database Tools**: Migrations, seeding, and reset capabilities
60 |
61 | ### Documentation (`/doc`)
62 | - **Framework**: Docusaurus v3
63 | - **Language**: TypeScript + MDX
64 | - **Features**: Blog, versioning, search, and internationalization ready
65 |
66 | ## 🚀 Quick Start
67 |
68 | ### Prerequisites
69 | - **Node.js** 18+ ([Download](https://nodejs.org/))
70 | - **npm** 9+ (comes with Node.js)
71 | - **Git** ([Download](https://git-scm.com/))
72 |
73 | ### 1️⃣ Clone and Setup
74 | ```bash
75 | # Clone the repository
76 | git clone
77 | cd spata
78 |
79 | # Choose your component and get started!
80 | ```
81 |
82 | ### 2️⃣ Start Development
83 |
84 | #### 🌐 Web App
85 | ```bash
86 | cd app
87 | npm install
88 | npm run dev
89 | ```
90 | - Opens at `http://localhost:5173`
91 | - Hot reload enabled
92 | - React DevTools & React Query DevTools included
93 |
94 | #### 📱 Mobile App
95 | ```bash
96 | cd mobile
97 | npm install
98 | npm run start
99 | ```
100 | - Scan QR code with Expo Go app
101 | - Works on iOS, Android, and web
102 | - Hot reload across all platforms
103 |
104 | #### ⚡ API Backend
105 | ```bash
106 | cd api
107 | # Setup environment
108 | cp prisma.env .env
109 |
110 | npm install
111 | npm run migrate # Setup database
112 | npm run seed # Add sample data
113 | npm run dev # Start development server
114 | ```
115 | - Runs at `http://localhost:3000`
116 | - Database UI at `npx prisma studio`
117 | - API automatically restarts on changes
118 |
119 | #### 📖 Documentation
120 | ```bash
121 | cd doc
122 | npm install
123 | npm run start
124 | ```
125 | - Opens at `http://localhost:3000`
126 | - Live editing with hot reload
127 | - Production build with `npm run build`
128 |
129 | ## 📁 Project Structure
130 |
131 | ```
132 | spata/
133 | ├── 📱 app/ # React Web Application
134 | │ ├── src/
135 | │ │ ├── components/ # Reusable UI components
136 | │ │ ├── pages/ # Route components
137 | │ │ ├── lib/ # Utilities and configuration
138 | │ │ └── assets/ # Static assets
139 | │ ├── tests/ # Component and integration tests
140 | │ └── public/ # Public assets
141 | │
142 | ├── 📲 mobile/ # React Native Mobile App
143 | │ ├── app/ # Expo Router pages
144 | │ ├── components/ # Reusable mobile components
145 | │ ├── constants/ # App constants and themes
146 | │ └── __tests__/ # Mobile app tests
147 | │
148 | ├── 🔧 api/ # Express API Backend
149 | │ ├── src/
150 | │ │ ├── routes/ # API route handlers
151 | │ │ └── index.ts # Express server setup
152 | │ ├── prisma/ # Database schema and migrations
153 | │ └── __tests__/ # API endpoint tests
154 | │
155 | └── 📚 doc/ # Docusaurus Documentation
156 | ├── docs/ # Documentation pages
157 | ├── blog/ # Blog posts
158 | └── src/ # Custom components
159 | ```
160 |
161 | ## 🧪 Testing
162 |
163 | Each component includes comprehensive testing setup:
164 |
165 | ```bash
166 | # Web App Testing
167 | cd app && npm test
168 |
169 | # Mobile App Testing
170 | cd mobile && npm test
171 |
172 | # API Testing
173 | cd api && npm test
174 | ```
175 |
176 | ## 🔧 Available Scripts
177 |
178 | ### Web App (`/app`)
179 | - `npm run dev` - Start development server
180 | - `npm run build` - Production build
181 | - `npm run preview` - Preview production build
182 | - `npm test` - Run tests with Vitest
183 | - `npm run lint` - Run ESLint
184 |
185 | ### Mobile App (`/mobile`)
186 | - `npm run start` - Start Expo development server
187 | - `npm run android` - Run on Android device/emulator
188 | - `npm run ios` - Run on iOS device/simulator
189 | - `npm run web` - Run as web app
190 | - `npm test` - Run tests with Jest
191 |
192 | ### API (`/api`)
193 | - `npm run dev` - Start development server with hot reload
194 | - `npm run build` - Compile TypeScript
195 | - `npm run start` - Start production server
196 | - `npm run migrate` - Run database migrations
197 | - `npm run seed` - Seed database with sample data
198 | - `npm run migrate:reset` - Reset database
199 | - `npm test` - Run API tests
200 |
201 | ### Documentation (`/doc`)
202 | - `npm run start` - Start development server
203 | - `npm run build` - Build for production
204 | - `npm run serve` - Serve production build locally
205 |
206 | ## 🎨 Customization
207 |
208 | ### Themes & Styling
209 | - **Web**: Modify `tailwind.config.js` and shadcn/ui components
210 | - **Mobile**: Update theme constants in `constants/Colors.ts`
211 | - Both apps include light/dark mode switching out of the box
212 |
213 | ### Database Schema
214 | ```bash
215 | cd api
216 | # Edit prisma/schema.prisma
217 | npm run migrate
218 | ```
219 |
220 | ### Environment Variables
221 | - **API**: Copy `prisma.env` to `.env` and customize
222 | - **Web/Mobile**: Add environment variables as needed
223 |
224 | ## 🚀 Deployment
225 |
226 | ### Web App
227 | - **Vercel/Netlify**: Connect your Git repository
228 | - **Static Hosting**: Run `npm run build` and deploy `dist/` folder
229 |
230 | ### Mobile App
231 | - **Expo**: Run `expo build` for app store deployment
232 | - **Development Build**: Use EAS Build for custom native code
233 |
234 | ### API
235 | - **Railway/Render**: Connect your Git repository
236 | - **VPS**: Use PM2 with `npm run build && npm run start`
237 |
238 | ### Documentation
239 | - **GitHub Pages**: Use `npm run deploy`
240 | - **Static Hosting**: Deploy `build/` folder after `npm run build`
241 |
242 | ## 🤝 Contributing
243 |
244 | We welcome contributions! Here's how to get started:
245 |
246 | 1. **Fork** the repository
247 | 2. **Create** a feature branch: `git checkout -b feature/amazing-feature`
248 | 3. **Commit** your changes: `git commit -m 'Add amazing feature'`
249 | 4. **Push** to the branch: `git push origin feature/amazing-feature`
250 | 5. **Open** a Pull Request
251 |
252 | ### Development Guidelines
253 | - Follow the existing code style
254 | - Add tests for new features
255 | - Update documentation as needed
256 | - Ensure all tests pass before submitting
257 |
258 | ## 🗺️ Roadmap
259 |
260 | - [ ] **Authentication System** - JWT-based auth with user management
261 | - [ ] **Database Options** - PostgreSQL, MySQL configuration guides
262 | - [ ] **Deployment Scripts** - One-command deployment to popular platforms
263 | - [ ] **Component Library** - Extended shadcn/ui component collection
264 | - [ ] **Testing Coverage** - E2E testing with Playwright
265 | - [ ] **Monitoring** - Built-in error tracking and analytics
266 | - [ ] **i18n Support** - Internationalization for global apps
267 |
268 | ## 📄 License
269 |
270 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.
271 |
272 | ## 💬 Support
273 |
274 | - 🐛 **Issues**: [GitHub Issues](https://github.com/your-org/spata/issues)
275 | - 💡 **Feature Requests**: [GitHub Discussions](https://github.com/your-org/spata/discussions)
276 | - 📖 **Documentation**: Visit `/doc` after running the docs server
277 |
278 | ---
279 |
280 |
281 |
282 | **Built with ❤️ by [Fairway Technology](https://fairway.technology)**
283 |
284 | ⭐ **Star this repo if SPATA helps you build faster!** ⭐
285 |
286 |
287 |
--------------------------------------------------------------------------------
/doc/static/img/undraw_docusaurus_tree.svg:
--------------------------------------------------------------------------------
1 |
2 | Focus on What Matters
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/components/icons.tsx:
--------------------------------------------------------------------------------
1 | type IconProps = React.HTMLAttributes;
2 |
3 | export const Icons = {
4 | logo: (props: IconProps) => (
5 |
9 |
14 |
25 |
36 |
37 | ),
38 | twitter: (props: IconProps) => (
39 |
45 |
46 |
47 | ),
48 | gitHub: (props: IconProps) => (
49 |
52 |
55 |
56 | ),
57 | radix: (props: IconProps) => (
58 |
62 |
65 |
68 |
71 |
72 | ),
73 | aria: (props: IconProps) => (
74 |
79 |
80 |
81 | ),
82 | npm: (props: IconProps) => (
83 |
86 |
90 |
91 | ),
92 | yarn: (props: IconProps) => (
93 |
96 |
100 |
101 | ),
102 | pnpm: (props: IconProps) => (
103 |
106 |
110 |
111 | ),
112 | react: (props: IconProps) => (
113 |
116 |
120 |
121 | ),
122 | tailwind: (props: IconProps) => (
123 |
126 |
130 |
131 | ),
132 | google: (props: IconProps) => (
133 |
137 |
141 |
142 | ),
143 | apple: (props: IconProps) => (
144 |
148 |
152 |
153 | ),
154 | paypal: (props: IconProps) => (
155 |
159 |
163 |
164 | ),
165 | spinner: (props: IconProps) => (
166 |
177 |
178 |
179 | ),
180 | };
181 |
--------------------------------------------------------------------------------
/doc/static/img/undraw_docusaurus_mountain.svg:
--------------------------------------------------------------------------------
1 |
2 | Easy to Use
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/doc/static/img/undraw_docusaurus_react.svg:
--------------------------------------------------------------------------------
1 |
2 | Powered by React
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
--------------------------------------------------------------------------------