From 6336955849cb499ae267d7ee9596b14482ad34bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nedim=20Arabac=C4=B1?= Date: Wed, 22 May 2024 16:14:39 +0300 Subject: [PATCH 1/2] adding vite-react-pwa example --- examples/vite-react-pwa/.eslintrc.cjs | 18 + examples/vite-react-pwa/.gitignore | 25 ++ examples/vite-react-pwa/README.md | 30 ++ examples/vite-react-pwa/index.html | 13 + examples/vite-react-pwa/package.json | 36 ++ examples/vite-react-pwa/public/favicon.svg | 130 ++++++ examples/vite-react-pwa/pwa-assets.config.ts | 12 + examples/vite-react-pwa/src/App.css | 50 +++ examples/vite-react-pwa/src/App.tsx | 42 ++ examples/vite-react-pwa/src/EvoluDemo.tsx | 434 +++++++++++++++++++ examples/vite-react-pwa/src/PWABadge.css | 29 ++ examples/vite-react-pwa/src/PWABadge.tsx | 77 ++++ examples/vite-react-pwa/src/assets/react.svg | 1 + examples/vite-react-pwa/src/index.css | 68 +++ examples/vite-react-pwa/src/main.tsx | 10 + examples/vite-react-pwa/src/vite-env.d.ts | 2 + examples/vite-react-pwa/tsconfig.json | 25 ++ examples/vite-react-pwa/tsconfig.node.json | 11 + examples/vite-react-pwa/vite.config.ts | 52 +++ 19 files changed, 1065 insertions(+) create mode 100644 examples/vite-react-pwa/.eslintrc.cjs create mode 100644 examples/vite-react-pwa/.gitignore create mode 100644 examples/vite-react-pwa/README.md create mode 100644 examples/vite-react-pwa/index.html create mode 100644 examples/vite-react-pwa/package.json create mode 100644 examples/vite-react-pwa/public/favicon.svg create mode 100644 examples/vite-react-pwa/pwa-assets.config.ts create mode 100644 examples/vite-react-pwa/src/App.css create mode 100644 examples/vite-react-pwa/src/App.tsx create mode 100644 examples/vite-react-pwa/src/EvoluDemo.tsx create mode 100644 examples/vite-react-pwa/src/PWABadge.css create mode 100644 examples/vite-react-pwa/src/PWABadge.tsx create mode 100644 examples/vite-react-pwa/src/assets/react.svg create mode 100644 examples/vite-react-pwa/src/index.css create mode 100644 examples/vite-react-pwa/src/main.tsx create mode 100644 examples/vite-react-pwa/src/vite-env.d.ts create mode 100644 examples/vite-react-pwa/tsconfig.json create mode 100644 examples/vite-react-pwa/tsconfig.node.json create mode 100644 examples/vite-react-pwa/vite.config.ts diff --git a/examples/vite-react-pwa/.eslintrc.cjs b/examples/vite-react-pwa/.eslintrc.cjs new file mode 100644 index 000000000..d6c953795 --- /dev/null +++ b/examples/vite-react-pwa/.eslintrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/examples/vite-react-pwa/.gitignore b/examples/vite-react-pwa/.gitignore new file mode 100644 index 000000000..6d6ae5aca --- /dev/null +++ b/examples/vite-react-pwa/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +dev-dist +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/vite-react-pwa/README.md b/examples/vite-react-pwa/README.md new file mode 100644 index 000000000..0d6babedd --- /dev/null +++ b/examples/vite-react-pwa/README.md @@ -0,0 +1,30 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@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 +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default { + // other rules... + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +} +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- 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 diff --git a/examples/vite-react-pwa/index.html b/examples/vite-react-pwa/index.html new file mode 100644 index 000000000..7b6e4c31f --- /dev/null +++ b/examples/vite-react-pwa/index.html @@ -0,0 +1,13 @@ + + + + + + + vite-react-pwa + TS + + +
+ + + diff --git a/examples/vite-react-pwa/package.json b/examples/vite-react-pwa/package.json new file mode 100644 index 000000000..2a418c3b5 --- /dev/null +++ b/examples/vite-react-pwa/package.json @@ -0,0 +1,36 @@ +{ + "name": "vite-react-pwa", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@evolu/react": "^8.0.2", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/react": "^18.3.1", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.8.0", + "@typescript-eslint/parser": "^7.8.0", + "@vite-pwa/assets-generator": "^0.2.4", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.6", + "typescript": "^5.2.2", + "vite": "^5.2.10", + "vite-plugin-pwa": "^0.20.0", + "workbox-core": "^7.1.0" + }, + "resolutions": { + "sharp": "0.32.6", + "sharp-ico": "0.1.5" + } +} diff --git a/examples/vite-react-pwa/public/favicon.svg b/examples/vite-react-pwa/public/favicon.svg new file mode 100644 index 000000000..733f4fb45 --- /dev/null +++ b/examples/vite-react-pwa/public/favicon.svg @@ -0,0 +1,130 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/vite-react-pwa/pwa-assets.config.ts b/examples/vite-react-pwa/pwa-assets.config.ts new file mode 100644 index 000000000..452b31fa6 --- /dev/null +++ b/examples/vite-react-pwa/pwa-assets.config.ts @@ -0,0 +1,12 @@ +import { + defineConfig, + minimal2023Preset as preset, +} from '@vite-pwa/assets-generator/config' + +export default defineConfig({ + headLinkOptions: { + preset: '2023', + }, + preset, + images: ['public/favicon.svg'], +}) diff --git a/examples/vite-react-pwa/src/App.css b/examples/vite-react-pwa/src/App.css new file mode 100644 index 000000000..92de7e348 --- /dev/null +++ b/examples/vite-react-pwa/src/App.css @@ -0,0 +1,50 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +button { + margin: 0 0.4em; +} + +li { + margin: 0.5em 0; +} diff --git a/examples/vite-react-pwa/src/App.tsx b/examples/vite-react-pwa/src/App.tsx new file mode 100644 index 000000000..ecb9bf879 --- /dev/null +++ b/examples/vite-react-pwa/src/App.tsx @@ -0,0 +1,42 @@ +import { useState } from "react"; +import "./App.css"; +import ViteExample from "./EvoluDemo.tsx"; +import PWABadge from "./PWABadge.tsx"; +import reactLogo from "./assets/react.svg"; +import appLogo from "/favicon.svg"; + +function App() { + const [count, setCount] = useState(0); + + return ( + <> +
+ + vite-react-pwa logo + + + React logo + +
+

vite-react-pwa

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+
+ +
+ + + ); +} + +export default App; diff --git a/examples/vite-react-pwa/src/EvoluDemo.tsx b/examples/vite-react-pwa/src/EvoluDemo.tsx new file mode 100644 index 000000000..3b3e04c70 --- /dev/null +++ b/examples/vite-react-pwa/src/EvoluDemo.tsx @@ -0,0 +1,434 @@ +import * as S from "@effect/schema/Schema"; +import { formatError } from "@effect/schema/TreeFormatter"; +import { + EvoluProvider, + ExtractRow, + NonEmptyString1000, + NotNull, + SqliteBoolean, + String, + cast, + createEvolu, + createIndexes, + database, + id, + jsonArrayFrom, + parseMnemonic, + table, + useEvolu, + useEvoluError, + useOwner, + useQuery, +} from "@evolu/react"; +import { Effect, Exit } from "effect"; +import { + ChangeEvent, + FC, + Suspense, + memo, + startTransition, + useEffect, + useState, +} from "react"; + +// Let's start with the database schema. + +// Every table needs Id. It's defined as a branded type. +// Branded types make database types super safe. +const TodoId = id("Todo"); +type TodoId = typeof TodoId.Type; + +const TodoCategoryId = id("TodoCategory"); +type TodoCategoryId = typeof TodoCategoryId.Type; + +// This branded type ensures a string must be validated before being put +// into the database. Check the prompt function to see Schema validation. +const NonEmptyString50 = String.pipe( + S.minLength(1), + S.maxLength(50), + S.brand("NonEmptyString50"), +); +type NonEmptyString50 = typeof NonEmptyString50.Type; + +// Now we can define tables. +const TodoTable = table({ + id: TodoId, + title: NonEmptyString1000, + isCompleted: S.NullOr(SqliteBoolean), + categoryId: S.NullOr(TodoCategoryId), +}); +type TodoTable = typeof TodoTable.Type; + +// Evolu tables can contain typed JSONs. +const SomeJson = S.Struct({ foo: S.String, bar: S.Boolean }); +type SomeJson = typeof SomeJson.Type; + +// Let's make a table with JSON value. +const TodoCategoryTable = table({ + id: TodoCategoryId, + name: NonEmptyString50, + json: S.NullOr(SomeJson), +}); +type TodoCategoryTable = typeof TodoCategoryTable.Type; + +// Now, we can define the database schema. +const Database = database({ + todo: TodoTable, + todoCategory: TodoCategoryTable, +}); +type Database = typeof Database.Type; + +/** + * Indexes are not necessary for development but are required for production. + * Before adding an index, use `logExecutionTime` and `logExplainQueryPlan` + * createQuery options. + * + * See https://www.evolu.dev/docs/indexes + */ +const indexes = createIndexes((create) => [ + create("indexTodoCreatedAt").on("todo").column("createdAt"), + create("indexTodoCategoryCreatedAt").on("todoCategory").column("createdAt"), +]); + +const evolu = createEvolu(Database, { + indexes, + initialData: (evolu) => { + const { id: categoryId } = evolu.create("todoCategory", { + name: S.decodeSync(NonEmptyString50)("Not Urgent"), + }); + evolu.create("todo", { + title: S.decodeSync(NonEmptyString1000)("Try React Suspense"), + categoryId, + }); + }, +}); + +const ViteExample = memo(function ViteExample() { + const [currentTab, setCurrentTab] = useState<"todos" | "categories">("todos"); + + const handleTabClick = () => + // https://react.dev/reference/react/useTransition#building-a-suspense-enabled-router + startTransition(() => { + setCurrentTab(currentTab === "todos" ? "categories" : "todos"); + }); + + return ( + + + +

+ {currentTab === "todos" ? "Todos" : "Categories"} +

+ {currentTab === "todos" ? : } +