Compare commits
8 Commits
3324a15cee
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3282d3ab17 | |||
| 9055c9ba6f | |||
| 83081b47d9 | |||
| c4e6232462 | |||
| 6d3da9874c | |||
| 1f9c62774a | |||
| a6df580ff9 | |||
| af080480e4 |
21
app.config.ts
Normal file
21
app.config.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// app.config.ts
|
||||||
|
import { defineConfig } from '@tanstack/react-start/config';
|
||||||
|
import tsConfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
tsr: {
|
||||||
|
appDirectory: 'src',
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
prerender: {
|
||||||
|
routes: ['/about'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vite: {
|
||||||
|
plugins: [
|
||||||
|
tsConfigPaths({
|
||||||
|
projects: ['./tsconfig.json'],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
19
index.html
19
index.html
@@ -1,19 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
||||||
<link rel="icon" href="/favicon.ico"/>
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="TanStack/Router Address Book"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="/logo192.png"/>
|
|
||||||
<link rel="manifest" href="/manifest.json"/>
|
|
||||||
<title>Create TanStack App - tsr-address-book</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
35
package.json
35
package.json
@@ -3,41 +3,48 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite --port 3000",
|
"dev": "vinxi dev",
|
||||||
"build": "vite build && tsc",
|
"build": "vinxi build",
|
||||||
"serve": "vite preview",
|
"start": "vinxi start",
|
||||||
"test": "vitest run"
|
"test": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-router": "^1.114.3",
|
"@tanstack/react-router": "^1.114.29",
|
||||||
"@tanstack/react-router-devtools": "^1.114.3",
|
"@tanstack/react-router-devtools": "^1.114.29",
|
||||||
"@tanstack/router-plugin": "^1.114.3",
|
"@tanstack/react-start": "^1.114.30",
|
||||||
"react": "^19.0.0",
|
"@tanstack/router-plugin": "^1.114.30",
|
||||||
"react-dom": "^19.0.0",
|
"lowdb": "^7.0.1",
|
||||||
"match-sorter": "^8.0.0",
|
"match-sorter": "^8.0.0",
|
||||||
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0",
|
||||||
|
"server-only": "^0.0.1",
|
||||||
"sort-by": "^1.2.0",
|
"sort-by": "^1.2.0",
|
||||||
"tiny-invariant": "^1.3.3"
|
"tiny-invariant": "^1.3.3",
|
||||||
|
"vinxi": "^0.5.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.23.0",
|
"@eslint/js": "^9.23.0",
|
||||||
"@tanstack/eslint-plugin-router": "^1.114.29",
|
"@tanstack/eslint-plugin-router": "^1.114.29",
|
||||||
"@testing-library/dom": "^10.4.0",
|
"@testing-library/dom": "^10.4.0",
|
||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@types/react": "^19.0.8",
|
"@types/node": "^22.13.17",
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react": "^19.0.12",
|
||||||
|
"@types/react-dom": "^19.0.4",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-plugin-react": "^7.37.4",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"jsdom": "^26.0.0",
|
"jsdom": "^26.0.0",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"typescript-eslint": "^8.28.0",
|
"typescript-eslint": "^8.29.0",
|
||||||
"vite": "^6.1.0",
|
"vite": "^6.2.4",
|
||||||
"vitest": "^3.0.5",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"vitest": "^3.1.1",
|
||||||
"web-vitals": "^4.2.4"
|
"web-vitals": "^4.2.4"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
|
"@parcel/watcher",
|
||||||
"esbuild"
|
"esbuild"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4464
pnpm-lock.yaml
generated
4464
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
53
public/logo.svg
Normal file
53
public/logo.svg
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="Layer_1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 841.9 595.3">
|
||||||
|
<!-- Generator: Adobe Illustrator 29.3.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 146) -->
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.st0 {
|
||||||
|
fill: #9ae7fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.st1 {
|
||||||
|
fill: #61dafb;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g>
|
||||||
|
<path class="st1"
|
||||||
|
d="M666.3,296.5c0-32.5-40.7-63.3-103.1-82.4,14.4-63.6,8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6,0,8.3.9,11.4,2.6,13.6,7.8,19.5,37.5,14.9,75.7-1.1,9.4-2.9,19.3-5.1,29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50,32.6-30.3,63.2-46.9,84-46.9v-22.3c-27.5,0-63.5,19.6-99.9,53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7,0,51.4,16.5,84,46.6-14,14.7-28,31.4-41.3,49.9-22.6,2.4-44,6.1-63.6,11-2.3-10-4-19.7-5.2-29-4.7-38.2,1.1-67.9,14.6-75.8,3-1.8,6.9-2.6,11.5-2.6v-22.3c-8.4,0-16,1.8-22.6,5.6-28.1,16.2-34.4,66.7-19.9,130.1-62.2,19.2-102.7,49.9-102.7,82.3s40.7,63.3,103.1,82.4c-14.4,63.6-8,114.2,20.2,130.4,6.5,3.8,14.1,5.6,22.5,5.6,27.5,0,63.5-19.6,99.9-53.6,36.4,33.8,72.4,53.2,99.9,53.2,8.4,0,16-1.8,22.6-5.6,28.1-16.2,34.4-66.7,19.9-130.1,62-19.1,102.5-49.9,102.5-82.3zm-130.2-66.7c-3.7,12.9-8.3,26.2-13.5,39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4,14.2,2.1,27.9,4.7,41,7.9zm-45.8,106.5c-7.8,13.5-15.8,26.3-24.1,38.2-14.9,1.3-30,2-45.2,2s-30.2-.7-45-1.9c-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8,6.2-13.4,13.2-26.8,20.7-39.9,7.8-13.5,15.8-26.3,24.1-38.2,14.9-1.3,30-2,45.2-2s30.2.7,45,1.9c8.3,11.9,16.4,24.6,24.2,38,7.6,13.1,14.5,26.4,20.8,39.8-6.3,13.4-13.2,26.8-20.7,39.9zm32.3-13c5.4,13.4,10,26.8,13.8,39.8-13.1,3.2-26.9,5.9-41.2,8,4.9-7.7,9.8-15.6,14.4-23.7,4.6-8,8.9-16.1,13-24.1zm-101.4,106.7c-9.3-9.6-18.6-20.3-27.8-32,9,.4,18.2.7,27.5.7s18.7-.2,27.8-.7c-9,11.7-18.3,22.4-27.5,32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9,3.7-12.9,8.3-26.2,13.5-39.5,4.1,8,8.4,16,13.1,24s9.5,15.8,14.4,23.4zm73.9-208.1c9.3,9.6,18.6,20.3,27.8,32-9-.4-18.2-.7-27.5-.7s-18.7.2-27.8.7c9-11.7,18.3-22.4,27.5-32zm-74,58.9c-4.9,7.7-9.8,15.6-14.4,23.7-4.6,8-8.9,16-13,24-5.4-13.4-10-26.8-13.8-39.8,13.1-3.1,26.9-5.8,41.2-7.9zm-90.5,125.2c-35.4-15.1-58.3-34.9-58.3-50.6s22.9-35.6,58.3-50.6c8.6-3.7,18-7,27.7-10.1,5.7,19.6,13.2,40,22.5,60.9-9.2,20.8-16.6,41.1-22.2,60.6-9.9-3.1-19.3-6.5-28-10.2zm53.8,142.9c-13.6-7.8-19.5-37.5-14.9-75.7,1.1-9.4,2.9-19.3,5.1-29.4,19.6,4.8,41,8.5,63.5,10.9,13.5,18.5,27.5,35.3,41.6,50-32.6,30.3-63.2,46.9-84,46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7,38.2-1.1,67.9-14.6,75.8-3,1.8-6.9,2.6-11.5,2.6-20.7,0-51.4-16.5-84-46.6,14-14.7,28-31.4,41.3-49.9,22.6-2.4,44-6.1,63.6-11,2.3,10.1,4.1,19.8,5.2,29.1zm38.5-66.7c-8.6,3.7-18,7-27.7,10.1-5.7-19.6-13.2-40-22.5-60.9,9.2-20.8,16.6-41.1,22.2-60.6,9.9,3.1,19.3,6.5,28.1,10.2,35.4,15.1,58.3,34.9,58.3,50.6,0,15.7-23,35.6-58.4,50.6zm-264.9-268.7z"/>
|
||||||
|
<circle class="st1" cx="420.9" cy="296.5" r="45.7"/>
|
||||||
|
<path class="st1" d="M520.5,78.1"/>
|
||||||
|
</g>
|
||||||
|
<circle class="st0" cx="420.8" cy="296.6" r="43"/>
|
||||||
|
<path class="st1"
|
||||||
|
d="M466.1,296.6c0,25-20.2,45.2-45.2,45.2s-45.2-20.2-45.2-45.2,20.2-45.2,45.2-45.2,45.2,20.2,45.2,45.2ZM386,295.6v-6.3c0-1.1,1.2-5.1,1.8-6.2,1-1.9,2.9-3.5,4.6-4.7l-3.4-3.4c4-3.6,9.4-3.7,13.7-.7,1.9-4.7,6.6-7.1,11.6-6.7l-.8,4.2c5.9.2,13.1,4.1,13.1,10.8s0,.5-.7.7c-1.7.3-3.4-.4-5-.6s-1.2-.4-1.2.3,2.5,4.1,3,5.5,1,3.5.8,5.3c-5.6-.8-10.5-3.2-14.8-6.7.3,2.6,4.1,21.7,5.3,21.9s.8-.6,1-1.1,1.3-6.3,1.3-6.7c0-1-1.7-1.8-2.2-2.8-1.2-2.7,1.3-4.7,3.7-3.3s5.2,6.2,7.5,7.3,13,1.4,14.8,3.3-2.9,4.6-1.5,7.6c6.7-2.6,13.5-3.3,20.6-2.5,3.1-9.7,3.1-20.3-.9-29.8-7.3,0-14.7-3.6-17.2-10.8-2.5-7.2-.7-8.6-1.3-9.3-.8-1-6.3.6-7.4-1.5s.3-1.1-.2-1.4-1.9-.6-2.6-.8c-26-6.4-51.3,15.7-49.7,42.1,0,1.6,1.6,10.3,2.4,11.1s4.8,0,6.3,0,3.7.3,5,.5c2.9.4,7.2,2.4,9.4,2.5s2.4-.8,2.7-2.4c.4-2.6.5-7.4.5-10.1s-1-7.8-1.3-11.6c-.9-.2-.7,0-.9.5-.7,1.3-1.1,3.2-1.9,4.8s-5.2,8.7-5.7,9-.7-.5-.8-.8c-1.6-3.5-2-7.9-1.9-11.8-.9-1-5.4,4.9-6.7,5.3l-.8-.4v-.3h-.2ZM455.6,276.4c1.1-1.2-6-8.9-7.2-10-3-2.7-5.4-4.5-3.5,1.4s5.7,7.8,10.6,8.5h.1ZM410.9,270.1c-.4-.5-6.1,2.9-5.5,4.6,1.9-1.3,5.9-1.7,5.5-4.6ZM400.4,276.4c-.3-2.4-6.3-2.7-7.2-1s1.6,1.4,1.9,1.4c1.8.3,3.5-.6,5.2-.4h.1ZM411.3,276.8c3.8,1.3,6.6,3.6,10.9,3.7s0-3-1.2-3.9c-2.2-1.7-5.1-2.4-7.8-2.4s-1.6-.3-1.4.4c2.8.6,7.3.7,8.4,3.8-2.3-.3-3.9-1.6-6.2-2s-2.5-.5-2.6.3h0ZM420.6,290.3c-.8-5.1-5.7-10.8-10.9-11.6s-1.3-.4-.8.5,4.7,3.2,5.7,4,4.5,4.2,2.1,3.8-8.4-7.8-9.4-6.7c.2.9,1.1,1.9,1.7,2.7,3,3.8,6.9,6.8,11.8,7.4h-.2ZM395.3,279.8c-5,1.1-6.9,6.3-6.7,11,.7.8,5-3.8,5.4-4.5s2.7-4.6,1.1-4-2.9,4.4-4.2,4.6.2-2.1.4-2.5c1.1-1.6,2.9-3.1,4-4.6h0ZM400.4,281.5c-.4-.5-2,1.3-2.3,1.7-2.9,3.9-2.6,10.2-1.5,14.8.8.2.8-.3,1.2-.7,3-3.8,5.5-10.5,4.5-15.4-2.1,3.1-3.1,7.3-3.6,11h-1.3c0-4,1.9-7.7,3-11.4h0ZM426.9,305.9c0-1.7-1.7-1.4-2.5-1.9s-1.3-1.9-3-1.4c1.3,2.1,3,3.2,5.5,3.4h0ZM417.2,308.5c7.6.7,5.5-1.9,1.4-5.5-1.3-.3-1.5,4.5-1.4,5.5ZM437,309.7c-3.5-.3-7.8-2-11.2-2.1s-1.3,0-1.9.7c4,1.3,8.4,1.7,12.1,4l1-2.5h0ZM420.5,312.8c-7.3,0-15.1,3.7-20.4,8.8s-4.8,5.3-4.8,6.2c0,1.8,8.6,6.2,10.5,6.8,12.1,4.8,27.5,3.5,38.2-4.2s3.1-2.7,0-6.2c-5.7-6.6-14.7-11.4-23.4-11.3h-.1ZM398.7,316.9c-1.4-1.4-5-1.9-7-2.1s-5.3-.3-6.9.6l13.9,1.4h0ZM456.9,314.8h-7.4c-.9,0-4.9,1.1-6,1.6s-.8.6,0,.5c2.4,0,5.1-1,7.6-1.3s3.5.2,5.1,0,1.3-.3.6-.8h0Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M386,295.6l.8.4c1.3-.3,5.8-6.2,6.7-5.3,0,3.9.3,8.3,1.9,11.8s0,1.2.8.8,5.1-7.8,5.7-9,1.3-3.5,1.9-4.8,0-.7.9-.5c.3,3.8,1.2,7.8,1.3,11.6s0,7.5-.5,10.1-1.1,2.4-2.7,2.4-6.5-2.1-9.4-2.5-3.7-.5-5-.5-5.4,1.1-6.3,0-2.2-9.5-2.4-11.1c-1.5-26.4,23.7-48.5,49.7-42.1s2.2.4,2.6.8,0,1,.2,1.4c1.1,2,6.5.5,7.4,1.5s.4,6.9,1.3,9.3c2.5,7.2,10,10.9,17.2,10.8,4,9.4,4,20.1.9,29.8-7.2-.7-13.9,0-20.6,2.5-1.3-3.1,4.1-5.1,1.5-7.6s-11.8-1.9-14.8-3.3-5.4-6.1-7.5-7.3-4.9.6-3.7,3.3,2.1,1.8,2.2,2.8-1,6.2-1.3,6.7-.3,1.3-1,1.1c-1.1-.3-5-19.3-5.3-21.9,4.3,3.5,9.2,5.9,14.8,6.7.2-1.9-.3-3.5-.8-5.3s-3-5.1-3-5.5c0-.8.9-.3,1.2-.3,1.6,0,3.3.8,5,.6s.7.3.7-.7c0-6.6-7.2-10.6-13.1-10.8l.8-4.2c-5.1-.3-9.6,2-11.6,6.7-4.3-3-9.8-3-13.7.7l3.4,3.4c-1.8,1.3-3.5,2.8-4.6,4.7s-1.8,5.1-1.8,6.2v6.6h.2ZM431.6,265c7.8,2.1,8.7-3.5.2-1.3l-.2,1.3ZM432.4,270.9c.3.6,6.4-.4,5.8-2.3s-4.6.6-5.7.6l-.2,1.7h.1ZM434.5,276c.8,1.2,5.7-1.8,5.5-2.7-.4-1.9-6.6,1.2-5.5,2.7ZM442.9,276.4c-.9-.9-5,2.8-4.6,4,.6,2.4,5.7-3,4.6-4ZM445.1,279.9c-.3.2-3.1,4.6-1.5,5s3.5-3.4,3.5-4-1.3-1.3-2-.9h0ZM448.9,287.4c2.1.8,3.8-5.1,2.3-5.5-1.9-.6-2.6,5.1-2.3,5.5ZM457.3,288.6c.5-1.7,1.1-4.7-1-5.5-1,.3-.6,3.9-.6,4.8l.3.5,1.3.2h0Z"/>
|
||||||
|
<path class="st0" d="M455.6,276.4c-5-.8-9.1-3.6-10.6-8.5s.5-4,3.5-1.4,8.3,8.7,7.2,10h-.1Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M420.6,290.3c-4.9-.6-8.9-3.6-11.8-7.4s-1.5-1.8-1.7-2.7c1-1,8.5,6.6,9.4,6.7,2.4.4-1.8-3.5-2.1-3.8-1-.8-5.4-3.5-5.7-4-.4-.8.5-.5.8-.5,5.2.8,10.1,6.6,10.9,11.6h.2Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M400.4,281.5c-1.1,3.7-3,7.3-3,11.4h1.3c.5-3.7,1.5-7.8,3.6-11,1,4.8-1.5,11.6-4.5,15.4s-.4.8-1.2.7c-1.1-4.5-1.3-10.8,1.5-14.8s1.9-2.2,2.3-1.7h0Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M411.3,276.8c0-.8,2.1-.4,2.6-.3,2.4.4,4,1.7,6.2,2-1.2-3.1-5.7-3.2-8.4-3.8,0-.8.9-.4,1.4-.4,2.8,0,5.6.7,7.8,2.4,2.2,1.7,4,4,1.2,3.9-4.3,0-7.1-2.4-10.9-3.7h0Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M395.3,279.8c-1.1,1.6-3,3-4,4.6s-1.9,2.8-.4,2.5,2.8-4,4.2-4.6-.9,3.6-1.1,4c-.4.7-4.7,5.2-5.4,4.5-.2-4.6,1.8-9.9,6.7-11h0Z"/>
|
||||||
|
<path class="st0" d="M437,309.7l-1,2.5c-3.6-2.3-8-2.8-12.1-4,.5-.7,1.1-.7,1.9-.7,3.4,0,7.8,1.8,11.2,2.1h0Z"/>
|
||||||
|
<path class="st0" d="M417.2,308.5c0-1,0-5.8,1.4-5.5,4,3.5,6.1,6.2-1.4,5.5Z"/>
|
||||||
|
<path class="st0" d="M400.4,276.4c-1.8-.3-3.5.7-5.2.4s-2.3-.8-1.9-1.4c.8-1.6,6.9-1.4,7.2,1h-.1Z"/>
|
||||||
|
<path class="st0" d="M410.9,270.1c.4,3-3.6,3.3-5.5,4.6-.6-1.8,5-5.1,5.5-4.6Z"/>
|
||||||
|
<path class="st0" d="M426.9,305.9c-2.5-.2-4.1-1.3-5.5-3.4,1.7-.4,2,.8,3,1.4s2.6.3,2.5,1.9h0Z"/>
|
||||||
|
<path class="st1" d="M432.4,270.9l.2-1.7c1.1,0,5.1-2.2,5.7-.6s-5.5,2.9-5.8,2.3h-.1Z"/>
|
||||||
|
<path class="st1" d="M431.6,265l.2-1.3c8.4-2.1,7.7,3.4-.2,1.3Z"/>
|
||||||
|
<path class="st1" d="M434.5,276c-1.1-1.5,5.1-4.6,5.5-2.7s-4.6,4-5.5,2.7Z"/>
|
||||||
|
<path class="st1" d="M442.9,276.4c1.1,1.1-4,6.4-4.6,4s3.7-4.9,4.6-4Z"/>
|
||||||
|
<path class="st1" d="M445.1,279.9c.7-.4,2.1,0,2,.9s-2.4,4.4-3.5,4,1.3-4.8,1.5-5h0Z"/>
|
||||||
|
<path class="st1" d="M448.9,287.4c-.3-.3.4-6.1,2.3-5.5,1.4.4-.2,6.2-2.3,5.5Z"/>
|
||||||
|
<path class="st1" d="M457.3,288.6l-1.3-.2-.3-.5c0-.9-.4-4.6.6-4.8,2.1.8,1.5,3.8,1,5.5h0Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M420.5,312.8c8.9,0,17.9,4.7,23.4,11.3,5.6,6.6,3.8,3.5,0,6.2-10.7,7.7-26.1,9-38.2,4.2-1.9-.8-10.5-5.1-10.5-6.8s4-5.3,4.8-6.2c5.3-5,13.1-8.6,20.4-8.8h.1Z"/>
|
||||||
|
<path class="st0" d="M398.7,316.9l-13.9-1.4c1.7-1,5-.8,6.9-.6s5.6.7,7,2.1h0Z"/>
|
||||||
|
<path class="st0"
|
||||||
|
d="M456.9,314.8c.7.5,0,.8-.6.8-1.6.2-3.5-.2-5.1,0-2.4.3-5.2,1.2-7.6,1.3s-1.1,0,0-.5,5.1-1.6,6-1.6h7.4,0Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.6 KiB |
File diff suppressed because one or more lines are too long
14
src/client.tsx
Normal file
14
src/client.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/// <reference types="vinxi/types/client" />
|
||||||
|
import { hydrateRoot } from 'react-dom/client';
|
||||||
|
import { StartClient } from '@tanstack/react-start';
|
||||||
|
import { createRouter } from './router';
|
||||||
|
import reportWebVitals from "@/reportWebVitals.ts";
|
||||||
|
|
||||||
|
const router = createRouter();
|
||||||
|
|
||||||
|
hydrateRoot(document, <StartClient router={router}/>);
|
||||||
|
|
||||||
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
// to log results (for example: reportWebVitals(console.log))
|
||||||
|
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||||
|
reportWebVitals();
|
||||||
539
src/data.ts
539
src/data.ts
@@ -2,11 +2,14 @@
|
|||||||
// 🛑 Nothing in here has anything to do with React Router, it's just a fake database
|
// 🛑 Nothing in here has anything to do with React Router, it's just a fake database
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// noinspection UnnecessaryLocalVariableJS,JSUnusedGlobalSymbols
|
// noinspection UnnecessaryLocalVariableJS,JSUnusedGlobalSymbols
|
||||||
|
|
||||||
import { matchSorter } from "match-sorter";
|
import { matchSorter } from "match-sorter";
|
||||||
// @ts-expect-error - no types, but it's a tiny function
|
// @ts-expect-error - no types, but it's a tiny function
|
||||||
import sortBy from "sort-by";
|
import sortBy from "sort-by";
|
||||||
import invariant from "tiny-invariant";
|
import invariant from "tiny-invariant";
|
||||||
|
import { Low } from "lowdb";
|
||||||
|
import { JSONFile } from "lowdb/node";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { mkdir } from "node:fs/promises";
|
||||||
|
|
||||||
type ContactMutation = {
|
type ContactMutation = {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -23,42 +26,97 @@ export type ContactRecord = ContactMutation & {
|
|||||||
createdAt: string;
|
createdAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// Define the database schema
|
||||||
// This is just a fake DB table. In a real app you'd be talking to a real db or
|
type Schema = {
|
||||||
// fetching from an existing API.
|
records: Record<string, ContactRecord>;
|
||||||
const fakeContacts = {
|
};
|
||||||
records: {} as Record<string, ContactRecord>,
|
|
||||||
|
|
||||||
|
// Set up lowdb
|
||||||
|
const initDb = async (): Promise<Low<Schema>> => {
|
||||||
|
// Ensure the db directory exists
|
||||||
|
const dbDir = join(process.cwd(), '.db');
|
||||||
|
await mkdir(dbDir, { recursive: true });
|
||||||
|
|
||||||
|
const file = join(dbDir, 'contacts.json');
|
||||||
|
const adapter = new JSONFile<Schema>(file);
|
||||||
|
const defaultData: Schema = { records: {} };
|
||||||
|
const db = new Low<Schema>(adapter, defaultData);
|
||||||
|
|
||||||
|
// Load existing data
|
||||||
|
await db.read();
|
||||||
|
|
||||||
|
// Initialize if needed
|
||||||
|
if (!db.data) {
|
||||||
|
db.data = defaultData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a singleton instance of the database
|
||||||
|
let dbPromise: Promise<Low<Schema>> | null = null;
|
||||||
|
|
||||||
|
const getDb = () => {
|
||||||
|
if (!dbPromise) {
|
||||||
|
dbPromise = initDb();
|
||||||
|
}
|
||||||
|
return dbPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This is a DB wrapper using lowdb for persistence
|
||||||
|
const fakeContacts = {
|
||||||
async getAll(): Promise<ContactRecord[]> {
|
async getAll(): Promise<ContactRecord[]> {
|
||||||
return Object.keys(fakeContacts.records)
|
const db = await getDb();
|
||||||
.map((key) => fakeContacts.records[key])
|
return Object.keys(db.data.records)
|
||||||
|
.map((key) => db.data.records[key])
|
||||||
.sort(sortBy("-createdAt", "last"));
|
.sort(sortBy("-createdAt", "last"));
|
||||||
},
|
},
|
||||||
|
|
||||||
async get(id: string): Promise<ContactRecord | null> {
|
async get(id: string): Promise<ContactRecord | null> {
|
||||||
return fakeContacts.records[id] || null;
|
const db = await getDb();
|
||||||
|
return db.data.records[id] || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
async create(values: ContactMutation): Promise<ContactRecord> {
|
async create(values: ContactMutation): Promise<ContactRecord> {
|
||||||
|
const db = await getDb();
|
||||||
const id = values.id || Math.random().toString(36).substring(2, 9);
|
const id = values.id || Math.random().toString(36).substring(2, 9);
|
||||||
const createdAt = new Date().toISOString();
|
const createdAt = new Date().toISOString();
|
||||||
const newContact = { id, createdAt, ...values };
|
const newContact = { id, createdAt, ...values };
|
||||||
fakeContacts.records[id] = newContact;
|
db.data.records[id] = newContact;
|
||||||
|
await db.write();
|
||||||
return newContact;
|
return newContact;
|
||||||
},
|
},
|
||||||
|
|
||||||
async set(id: string, values: ContactMutation): Promise<ContactRecord> {
|
async set(id: string, values: ContactMutation): Promise<ContactRecord> {
|
||||||
const contact = await fakeContacts.get(id);
|
const db = await getDb();
|
||||||
|
const contact = await this.get(id);
|
||||||
invariant(contact, `No contact found for ${id}`);
|
invariant(contact, `No contact found for ${id}`);
|
||||||
const updatedContact = { ...contact, ...values };
|
const updatedContact = { ...contact, ...values };
|
||||||
fakeContacts.records[id] = updatedContact;
|
db.data.records[id] = updatedContact;
|
||||||
|
await db.write();
|
||||||
return updatedContact;
|
return updatedContact;
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy(id: string): null {
|
async destroy(id: string): Promise<null> {
|
||||||
delete fakeContacts.records[id];
|
const db = await getDb();
|
||||||
|
delete db.data.records[id];
|
||||||
|
await db.write();
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// New reset function to restore the initial data
|
||||||
|
async reset(): Promise<void> {
|
||||||
|
const db = await getDb();
|
||||||
|
db.data.records = {};
|
||||||
|
await db.write();
|
||||||
|
|
||||||
|
// Restore initial data
|
||||||
|
const initialContacts = getInitialContacts();
|
||||||
|
for (const contact of initialContacts) {
|
||||||
|
await this.create(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -93,228 +151,243 @@ export async function updateContact(id: string, updates: ContactMutation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteContact(id: string) {
|
export async function deleteContact(id: string) {
|
||||||
fakeContacts.destroy(id);
|
await fakeContacts.destroy(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
[
|
// New function to reset the database to initial state
|
||||||
{
|
export async function resetDatabase() {
|
||||||
avatar:
|
console.log("RESET DATABASE");
|
||||||
"https://sessionize.com/image/124e-400o400o2-wHVdAuNaxi8KJrgtN3ZKci.jpg",
|
await fakeContacts.reset();
|
||||||
first: "Shruti",
|
}
|
||||||
last: "Kapoor",
|
|
||||||
twitter: "@shrutikapoor08",
|
// Helper function to get initial contacts data
|
||||||
},
|
function getInitialContacts() {
|
||||||
{
|
return [
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/1940-400o400o2-Enh9dnYmrLYhJSTTPSw3MH.jpg",
|
avatar:
|
||||||
first: "Glenn",
|
"https://sessionize.com/image/124e-400o400o2-wHVdAuNaxi8KJrgtN3ZKci.jpg",
|
||||||
last: "Reyes",
|
first: "Shruti",
|
||||||
twitter: "@glnnrys",
|
last: "Kapoor",
|
||||||
},
|
twitter: "@shrutikapoor08",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/9273-400o400o2-3tyrUE3HjsCHJLU5aUJCja.jpg",
|
avatar:
|
||||||
first: "Ryan",
|
"https://sessionize.com/image/1940-400o400o2-Enh9dnYmrLYhJSTTPSw3MH.jpg",
|
||||||
last: "Florence",
|
first: "Glenn",
|
||||||
},
|
last: "Reyes",
|
||||||
{
|
twitter: "@glnnrys",
|
||||||
avatar:
|
},
|
||||||
"https://sessionize.com/image/d14d-400o400o2-pyB229HyFPCnUcZhHf3kWS.png",
|
{
|
||||||
first: "Oscar",
|
avatar:
|
||||||
last: "Newman",
|
"https://sessionize.com/image/9273-400o400o2-3tyrUE3HjsCHJLU5aUJCja.jpg",
|
||||||
twitter: "@__oscarnewman",
|
first: "Ryan",
|
||||||
},
|
last: "Florence",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/fd45-400o400o2-fw91uCdGU9hFP334dnyVCr.jpg",
|
avatar:
|
||||||
first: "Michael",
|
"https://sessionize.com/image/d14d-400o400o2-pyB229HyFPCnUcZhHf3kWS.png",
|
||||||
last: "Jackson",
|
first: "Oscar",
|
||||||
},
|
last: "Newman",
|
||||||
{
|
twitter: "@__oscarnewman",
|
||||||
avatar:
|
},
|
||||||
"https://sessionize.com/image/b07e-400o400o2-KgNRF3S9sD5ZR4UsG7hG4g.jpg",
|
{
|
||||||
first: "Christopher",
|
avatar:
|
||||||
last: "Chedeau",
|
"https://sessionize.com/image/fd45-400o400o2-fw91uCdGU9hFP334dnyVCr.jpg",
|
||||||
twitter: "@Vjeux",
|
first: "Michael",
|
||||||
},
|
last: "Jackson",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/262f-400o400o2-UBPQueK3fayaCmsyUc1Ljf.jpg",
|
avatar:
|
||||||
first: "Cameron",
|
"https://sessionize.com/image/b07e-400o400o2-KgNRF3S9sD5ZR4UsG7hG4g.jpg",
|
||||||
last: "Matheson",
|
first: "Christopher",
|
||||||
twitter: "@cmatheson",
|
last: "Chedeau",
|
||||||
},
|
twitter: "@Vjeux",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/820b-400o400o2-Ja1KDrBAu5NzYTPLSC3GW8.jpg",
|
avatar:
|
||||||
first: "Brooks",
|
"https://sessionize.com/image/262f-400o400o2-UBPQueK3fayaCmsyUc1Ljf.jpg",
|
||||||
last: "Lybrand",
|
first: "Cameron",
|
||||||
twitter: "@BrooksLybrand",
|
last: "Matheson",
|
||||||
},
|
twitter: "@cmatheson",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/df38-400o400o2-JwbChVUj6V7DwZMc9vJEHc.jpg",
|
avatar:
|
||||||
first: "Alex",
|
"https://sessionize.com/image/820b-400o400o2-Ja1KDrBAu5NzYTPLSC3GW8.jpg",
|
||||||
last: "Anderson",
|
first: "Brooks",
|
||||||
twitter: "@ralex1993",
|
last: "Lybrand",
|
||||||
},
|
twitter: "@BrooksLybrand",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/5578-400o400o2-BMT43t5kd2U1XstaNnM6Ax.jpg",
|
avatar:
|
||||||
first: "Kent C.",
|
"https://sessionize.com/image/df38-400o400o2-JwbChVUj6V7DwZMc9vJEHc.jpg",
|
||||||
last: "Dodds",
|
first: "Alex",
|
||||||
twitter: "@kentcdodds",
|
last: "Anderson",
|
||||||
},
|
twitter: "@ralex1993",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/c9d5-400o400o2-Sri5qnQmscaJXVB8m3VBgf.jpg",
|
avatar:
|
||||||
first: "Nevi",
|
"https://sessionize.com/image/5578-400o400o2-BMT43t5kd2U1XstaNnM6Ax.jpg",
|
||||||
last: "Shah",
|
first: "Kent C.",
|
||||||
twitter: "@nevikashah",
|
last: "Dodds",
|
||||||
},
|
twitter: "@kentcdodds",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/2694-400o400o2-MYYTsnszbLKTzyqJV17w2q.png",
|
avatar:
|
||||||
first: "Andrew",
|
"https://sessionize.com/image/c9d5-400o400o2-Sri5qnQmscaJXVB8m3VBgf.jpg",
|
||||||
last: "Petersen",
|
first: "Nevi",
|
||||||
},
|
last: "Shah",
|
||||||
{
|
twitter: "@nevikashah",
|
||||||
avatar:
|
},
|
||||||
"https://sessionize.com/image/907a-400o400o2-9TM2CCmvrw6ttmJiTw4Lz8.jpg",
|
{
|
||||||
first: "Scott",
|
avatar:
|
||||||
last: "Smerchek",
|
"https://sessionize.com/image/2694-400o400o2-MYYTsnszbLKTzyqJV17w2q.png",
|
||||||
twitter: "@smerchek",
|
first: "Andrew",
|
||||||
},
|
last: "Petersen",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/08be-400o400o2-WtYGFFR1ZUJHL9tKyVBNPV.jpg",
|
avatar:
|
||||||
first: "Giovanni",
|
"https://sessionize.com/image/907a-400o400o2-9TM2CCmvrw6ttmJiTw4Lz8.jpg",
|
||||||
last: "Benussi",
|
first: "Scott",
|
||||||
twitter: "@giovannibenussi",
|
last: "Smerchek",
|
||||||
},
|
twitter: "@smerchek",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/f814-400o400o2-n2ua5nM9qwZA2hiGdr1T7N.jpg",
|
avatar:
|
||||||
first: "Igor",
|
"https://sessionize.com/image/08be-400o400o2-WtYGFFR1ZUJHL9tKyVBNPV.jpg",
|
||||||
last: "Minar",
|
first: "Giovanni",
|
||||||
twitter: "@IgorMinar",
|
last: "Benussi",
|
||||||
},
|
twitter: "@giovannibenussi",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/fb82-400o400o2-LbvwhTVMrYLDdN3z4iEFMp.jpeg",
|
avatar:
|
||||||
first: "Brandon",
|
"https://sessionize.com/image/f814-400o400o2-n2ua5nM9qwZA2hiGdr1T7N.jpg",
|
||||||
last: "Kish",
|
first: "Igor",
|
||||||
},
|
last: "Minar",
|
||||||
{
|
twitter: "@IgorMinar",
|
||||||
avatar:
|
},
|
||||||
"https://sessionize.com/image/fcda-400o400o2-XiYRtKK5Dvng5AeyC8PiUA.png",
|
{
|
||||||
first: "Arisa",
|
avatar:
|
||||||
last: "Fukuzaki",
|
"https://sessionize.com/image/fb82-400o400o2-LbvwhTVMrYLDdN3z4iEFMp.jpeg",
|
||||||
twitter: "@arisa_dev",
|
first: "Brandon",
|
||||||
},
|
last: "Kish",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/c8c3-400o400o2-PR5UsgApAVEADZRixV4H8e.jpeg",
|
avatar:
|
||||||
first: "Alexandra",
|
"https://sessionize.com/image/fcda-400o400o2-XiYRtKK5Dvng5AeyC8PiUA.png",
|
||||||
last: "Spalato",
|
first: "Arisa",
|
||||||
twitter: "@alexadark",
|
last: "Fukuzaki",
|
||||||
},
|
twitter: "@arisa_dev",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/7594-400o400o2-hWtdCjbdFdLgE2vEXBJtyo.jpg",
|
avatar:
|
||||||
first: "Cat",
|
"https://sessionize.com/image/c8c3-400o400o2-PR5UsgApAVEADZRixV4H8e.jpeg",
|
||||||
last: "Johnson",
|
first: "Alexandra",
|
||||||
},
|
last: "Spalato",
|
||||||
{
|
twitter: "@alexadark",
|
||||||
avatar:
|
},
|
||||||
"https://sessionize.com/image/5636-400o400o2-TWgi8vELMFoB3hB9uPw62d.jpg",
|
{
|
||||||
first: "Ashley",
|
avatar:
|
||||||
last: "Narcisse",
|
"https://sessionize.com/image/7594-400o400o2-hWtdCjbdFdLgE2vEXBJtyo.jpg",
|
||||||
twitter: "@_darkfadr",
|
first: "Cat",
|
||||||
},
|
last: "Johnson",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/6aeb-400o400o2-Q5tAiuzKGgzSje9ZsK3Yu5.JPG",
|
avatar:
|
||||||
first: "Edmund",
|
"https://sessionize.com/image/5636-400o400o2-TWgi8vELMFoB3hB9uPw62d.jpg",
|
||||||
last: "Hung",
|
first: "Ashley",
|
||||||
twitter: "@_edmundhung",
|
last: "Narcisse",
|
||||||
},
|
twitter: "@_darkfadr",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/30f1-400o400o2-wJBdJ6sFayjKmJycYKoHSe.jpg",
|
avatar:
|
||||||
first: "Clifford",
|
"https://sessionize.com/image/6aeb-400o400o2-Q5tAiuzKGgzSje9ZsK3Yu5.JPG",
|
||||||
last: "Fajardo",
|
first: "Edmund",
|
||||||
twitter: "@cliffordfajard0",
|
last: "Hung",
|
||||||
},
|
twitter: "@_edmundhung",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/6faa-400o400o2-amseBRDkdg7wSK5tjsFDiG.jpg",
|
avatar:
|
||||||
first: "Erick",
|
"https://sessionize.com/image/30f1-400o400o2-wJBdJ6sFayjKmJycYKoHSe.jpg",
|
||||||
last: "Tamayo",
|
first: "Clifford",
|
||||||
twitter: "@ericktamayo",
|
last: "Fajardo",
|
||||||
},
|
twitter: "@cliffordfajard0",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/feba-400o400o2-R4GE7eqegJNFf3cQ567obs.jpg",
|
avatar:
|
||||||
first: "Paul",
|
"https://sessionize.com/image/6faa-400o400o2-amseBRDkdg7wSK5tjsFDiG.jpg",
|
||||||
last: "Bratslavsky",
|
first: "Erick",
|
||||||
twitter: "@codingthirty",
|
last: "Tamayo",
|
||||||
},
|
twitter: "@ericktamayo",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/c315-400o400o2-spjM5A6VVfVNnQsuwvX3DY.jpg",
|
avatar:
|
||||||
first: "Pedro",
|
"https://sessionize.com/image/feba-400o400o2-R4GE7eqegJNFf3cQ567obs.jpg",
|
||||||
last: "Cattori",
|
first: "Paul",
|
||||||
twitter: "@pcattori",
|
last: "Bratslavsky",
|
||||||
},
|
twitter: "@codingthirty",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/eec1-400o400o2-HkvWKLFqecmFxLwqR9KMRw.jpg",
|
avatar:
|
||||||
first: "Andre",
|
"https://sessionize.com/image/c315-400o400o2-spjM5A6VVfVNnQsuwvX3DY.jpg",
|
||||||
last: "Landgraf",
|
first: "Pedro",
|
||||||
twitter: "@AndreLandgraf94",
|
last: "Cattori",
|
||||||
},
|
twitter: "@pcattori",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/c73a-400o400o2-4MTaTq6ftC15hqwtqUJmTC.jpg",
|
avatar:
|
||||||
first: "Monica",
|
"https://sessionize.com/image/eec1-400o400o2-HkvWKLFqecmFxLwqR9KMRw.jpg",
|
||||||
last: "Powell",
|
first: "Andre",
|
||||||
twitter: "@indigitalcolor",
|
last: "Landgraf",
|
||||||
},
|
twitter: "@AndreLandgraf94",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/cef7-400o400o2-KBZUydbjfkfGACQmjbHEvX.jpeg",
|
avatar:
|
||||||
first: "Brian",
|
"https://sessionize.com/image/c73a-400o400o2-4MTaTq6ftC15hqwtqUJmTC.jpg",
|
||||||
last: "Lee",
|
first: "Monica",
|
||||||
twitter: "@brian_dlee",
|
last: "Powell",
|
||||||
},
|
twitter: "@indigitalcolor",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/f83b-400o400o2-Pyw3chmeHMxGsNoj3nQmWU.jpg",
|
avatar:
|
||||||
first: "Sean",
|
"https://sessionize.com/image/cef7-400o400o2-KBZUydbjfkfGACQmjbHEvX.jpeg",
|
||||||
last: "McQuaid",
|
first: "Brian",
|
||||||
twitter: "@SeanMcQuaidCode",
|
last: "Lee",
|
||||||
},
|
twitter: "@brian_dlee",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/a9fc-400o400o2-JHBnWZRoxp7QX74Hdac7AZ.jpg",
|
avatar:
|
||||||
first: "Shane",
|
"https://sessionize.com/image/f83b-400o400o2-Pyw3chmeHMxGsNoj3nQmWU.jpg",
|
||||||
last: "Walker",
|
first: "Sean",
|
||||||
twitter: "@swalker326",
|
last: "McQuaid",
|
||||||
},
|
twitter: "@SeanMcQuaidCode",
|
||||||
{
|
},
|
||||||
avatar:
|
{
|
||||||
"https://sessionize.com/image/6644-400o400o2-aHnGHb5Pdu3D32MbfrnQbj.jpg",
|
avatar:
|
||||||
first: "Jon",
|
"https://sessionize.com/image/a9fc-400o400o2-JHBnWZRoxp7QX74Hdac7AZ.jpg",
|
||||||
last: "Jensen",
|
first: "Shane",
|
||||||
twitter: "@jenseng",
|
last: "Walker",
|
||||||
},
|
twitter: "@swalker326",
|
||||||
].forEach((contact) => {
|
},
|
||||||
fakeContacts.create({
|
{
|
||||||
|
avatar:
|
||||||
|
"https://sessionize.com/image/6644-400o400o2-aHnGHb5Pdu3D32MbfrnQbj.jpg",
|
||||||
|
first: "Jon",
|
||||||
|
last: "Jensen",
|
||||||
|
twitter: "@jenseng",
|
||||||
|
},
|
||||||
|
].map(contact => ({
|
||||||
...contact,
|
...contact,
|
||||||
id: `${contact.first
|
id: `${contact.first
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.join("_")}-${contact.last.toLocaleLowerCase()}`,
|
.join("_")}-${contact.last.toLowerCase()}`,
|
||||||
});
|
}));
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// Initialize with seed data on first load
|
||||||
|
(async () => {
|
||||||
|
const db = await getDb();
|
||||||
|
if (Object.keys(db.data.records).length === 0) {
|
||||||
|
await resetDatabase();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|||||||
44
src/logo.svg
44
src/logo.svg
@@ -1,44 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg id="Layer_1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 841.9 595.3">
|
|
||||||
<!-- Generator: Adobe Illustrator 29.3.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 146) -->
|
|
||||||
<defs>
|
|
||||||
<style>
|
|
||||||
.st0 {
|
|
||||||
fill: #9ae7fc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.st1 {
|
|
||||||
fill: #61dafb;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</defs>
|
|
||||||
<g>
|
|
||||||
<path class="st1" d="M666.3,296.5c0-32.5-40.7-63.3-103.1-82.4,14.4-63.6,8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6,0,8.3.9,11.4,2.6,13.6,7.8,19.5,37.5,14.9,75.7-1.1,9.4-2.9,19.3-5.1,29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50,32.6-30.3,63.2-46.9,84-46.9v-22.3c-27.5,0-63.5,19.6-99.9,53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7,0,51.4,16.5,84,46.6-14,14.7-28,31.4-41.3,49.9-22.6,2.4-44,6.1-63.6,11-2.3-10-4-19.7-5.2-29-4.7-38.2,1.1-67.9,14.6-75.8,3-1.8,6.9-2.6,11.5-2.6v-22.3c-8.4,0-16,1.8-22.6,5.6-28.1,16.2-34.4,66.7-19.9,130.1-62.2,19.2-102.7,49.9-102.7,82.3s40.7,63.3,103.1,82.4c-14.4,63.6-8,114.2,20.2,130.4,6.5,3.8,14.1,5.6,22.5,5.6,27.5,0,63.5-19.6,99.9-53.6,36.4,33.8,72.4,53.2,99.9,53.2,8.4,0,16-1.8,22.6-5.6,28.1-16.2,34.4-66.7,19.9-130.1,62-19.1,102.5-49.9,102.5-82.3zm-130.2-66.7c-3.7,12.9-8.3,26.2-13.5,39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4,14.2,2.1,27.9,4.7,41,7.9zm-45.8,106.5c-7.8,13.5-15.8,26.3-24.1,38.2-14.9,1.3-30,2-45.2,2s-30.2-.7-45-1.9c-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8,6.2-13.4,13.2-26.8,20.7-39.9,7.8-13.5,15.8-26.3,24.1-38.2,14.9-1.3,30-2,45.2-2s30.2.7,45,1.9c8.3,11.9,16.4,24.6,24.2,38,7.6,13.1,14.5,26.4,20.8,39.8-6.3,13.4-13.2,26.8-20.7,39.9zm32.3-13c5.4,13.4,10,26.8,13.8,39.8-13.1,3.2-26.9,5.9-41.2,8,4.9-7.7,9.8-15.6,14.4-23.7,4.6-8,8.9-16.1,13-24.1zm-101.4,106.7c-9.3-9.6-18.6-20.3-27.8-32,9,.4,18.2.7,27.5.7s18.7-.2,27.8-.7c-9,11.7-18.3,22.4-27.5,32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9,3.7-12.9,8.3-26.2,13.5-39.5,4.1,8,8.4,16,13.1,24s9.5,15.8,14.4,23.4zm73.9-208.1c9.3,9.6,18.6,20.3,27.8,32-9-.4-18.2-.7-27.5-.7s-18.7.2-27.8.7c9-11.7,18.3-22.4,27.5-32zm-74,58.9c-4.9,7.7-9.8,15.6-14.4,23.7-4.6,8-8.9,16-13,24-5.4-13.4-10-26.8-13.8-39.8,13.1-3.1,26.9-5.8,41.2-7.9zm-90.5,125.2c-35.4-15.1-58.3-34.9-58.3-50.6s22.9-35.6,58.3-50.6c8.6-3.7,18-7,27.7-10.1,5.7,19.6,13.2,40,22.5,60.9-9.2,20.8-16.6,41.1-22.2,60.6-9.9-3.1-19.3-6.5-28-10.2zm53.8,142.9c-13.6-7.8-19.5-37.5-14.9-75.7,1.1-9.4,2.9-19.3,5.1-29.4,19.6,4.8,41,8.5,63.5,10.9,13.5,18.5,27.5,35.3,41.6,50-32.6,30.3-63.2,46.9-84,46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7,38.2-1.1,67.9-14.6,75.8-3,1.8-6.9,2.6-11.5,2.6-20.7,0-51.4-16.5-84-46.6,14-14.7,28-31.4,41.3-49.9,22.6-2.4,44-6.1,63.6-11,2.3,10.1,4.1,19.8,5.2,29.1zm38.5-66.7c-8.6,3.7-18,7-27.7,10.1-5.7-19.6-13.2-40-22.5-60.9,9.2-20.8,16.6-41.1,22.2-60.6,9.9,3.1,19.3,6.5,28.1,10.2,35.4,15.1,58.3,34.9,58.3,50.6,0,15.7-23,35.6-58.4,50.6zm-264.9-268.7z"/>
|
|
||||||
<circle class="st1" cx="420.9" cy="296.5" r="45.7"/>
|
|
||||||
<path class="st1" d="M520.5,78.1"/>
|
|
||||||
</g>
|
|
||||||
<circle class="st0" cx="420.8" cy="296.6" r="43"/>
|
|
||||||
<path class="st1" d="M466.1,296.6c0,25-20.2,45.2-45.2,45.2s-45.2-20.2-45.2-45.2,20.2-45.2,45.2-45.2,45.2,20.2,45.2,45.2ZM386,295.6v-6.3c0-1.1,1.2-5.1,1.8-6.2,1-1.9,2.9-3.5,4.6-4.7l-3.4-3.4c4-3.6,9.4-3.7,13.7-.7,1.9-4.7,6.6-7.1,11.6-6.7l-.8,4.2c5.9.2,13.1,4.1,13.1,10.8s0,.5-.7.7c-1.7.3-3.4-.4-5-.6s-1.2-.4-1.2.3,2.5,4.1,3,5.5,1,3.5.8,5.3c-5.6-.8-10.5-3.2-14.8-6.7.3,2.6,4.1,21.7,5.3,21.9s.8-.6,1-1.1,1.3-6.3,1.3-6.7c0-1-1.7-1.8-2.2-2.8-1.2-2.7,1.3-4.7,3.7-3.3s5.2,6.2,7.5,7.3,13,1.4,14.8,3.3-2.9,4.6-1.5,7.6c6.7-2.6,13.5-3.3,20.6-2.5,3.1-9.7,3.1-20.3-.9-29.8-7.3,0-14.7-3.6-17.2-10.8-2.5-7.2-.7-8.6-1.3-9.3-.8-1-6.3.6-7.4-1.5s.3-1.1-.2-1.4-1.9-.6-2.6-.8c-26-6.4-51.3,15.7-49.7,42.1,0,1.6,1.6,10.3,2.4,11.1s4.8,0,6.3,0,3.7.3,5,.5c2.9.4,7.2,2.4,9.4,2.5s2.4-.8,2.7-2.4c.4-2.6.5-7.4.5-10.1s-1-7.8-1.3-11.6c-.9-.2-.7,0-.9.5-.7,1.3-1.1,3.2-1.9,4.8s-5.2,8.7-5.7,9-.7-.5-.8-.8c-1.6-3.5-2-7.9-1.9-11.8-.9-1-5.4,4.9-6.7,5.3l-.8-.4v-.3h-.2ZM455.6,276.4c1.1-1.2-6-8.9-7.2-10-3-2.7-5.4-4.5-3.5,1.4s5.7,7.8,10.6,8.5h.1ZM410.9,270.1c-.4-.5-6.1,2.9-5.5,4.6,1.9-1.3,5.9-1.7,5.5-4.6ZM400.4,276.4c-.3-2.4-6.3-2.7-7.2-1s1.6,1.4,1.9,1.4c1.8.3,3.5-.6,5.2-.4h.1ZM411.3,276.8c3.8,1.3,6.6,3.6,10.9,3.7s0-3-1.2-3.9c-2.2-1.7-5.1-2.4-7.8-2.4s-1.6-.3-1.4.4c2.8.6,7.3.7,8.4,3.8-2.3-.3-3.9-1.6-6.2-2s-2.5-.5-2.6.3h0ZM420.6,290.3c-.8-5.1-5.7-10.8-10.9-11.6s-1.3-.4-.8.5,4.7,3.2,5.7,4,4.5,4.2,2.1,3.8-8.4-7.8-9.4-6.7c.2.9,1.1,1.9,1.7,2.7,3,3.8,6.9,6.8,11.8,7.4h-.2ZM395.3,279.8c-5,1.1-6.9,6.3-6.7,11,.7.8,5-3.8,5.4-4.5s2.7-4.6,1.1-4-2.9,4.4-4.2,4.6.2-2.1.4-2.5c1.1-1.6,2.9-3.1,4-4.6h0ZM400.4,281.5c-.4-.5-2,1.3-2.3,1.7-2.9,3.9-2.6,10.2-1.5,14.8.8.2.8-.3,1.2-.7,3-3.8,5.5-10.5,4.5-15.4-2.1,3.1-3.1,7.3-3.6,11h-1.3c0-4,1.9-7.7,3-11.4h0ZM426.9,305.9c0-1.7-1.7-1.4-2.5-1.9s-1.3-1.9-3-1.4c1.3,2.1,3,3.2,5.5,3.4h0ZM417.2,308.5c7.6.7,5.5-1.9,1.4-5.5-1.3-.3-1.5,4.5-1.4,5.5ZM437,309.7c-3.5-.3-7.8-2-11.2-2.1s-1.3,0-1.9.7c4,1.3,8.4,1.7,12.1,4l1-2.5h0ZM420.5,312.8c-7.3,0-15.1,3.7-20.4,8.8s-4.8,5.3-4.8,6.2c0,1.8,8.6,6.2,10.5,6.8,12.1,4.8,27.5,3.5,38.2-4.2s3.1-2.7,0-6.2c-5.7-6.6-14.7-11.4-23.4-11.3h-.1ZM398.7,316.9c-1.4-1.4-5-1.9-7-2.1s-5.3-.3-6.9.6l13.9,1.4h0ZM456.9,314.8h-7.4c-.9,0-4.9,1.1-6,1.6s-.8.6,0,.5c2.4,0,5.1-1,7.6-1.3s3.5.2,5.1,0,1.3-.3.6-.8h0Z"/>
|
|
||||||
<path class="st0" d="M386,295.6l.8.4c1.3-.3,5.8-6.2,6.7-5.3,0,3.9.3,8.3,1.9,11.8s0,1.2.8.8,5.1-7.8,5.7-9,1.3-3.5,1.9-4.8,0-.7.9-.5c.3,3.8,1.2,7.8,1.3,11.6s0,7.5-.5,10.1-1.1,2.4-2.7,2.4-6.5-2.1-9.4-2.5-3.7-.5-5-.5-5.4,1.1-6.3,0-2.2-9.5-2.4-11.1c-1.5-26.4,23.7-48.5,49.7-42.1s2.2.4,2.6.8,0,1,.2,1.4c1.1,2,6.5.5,7.4,1.5s.4,6.9,1.3,9.3c2.5,7.2,10,10.9,17.2,10.8,4,9.4,4,20.1.9,29.8-7.2-.7-13.9,0-20.6,2.5-1.3-3.1,4.1-5.1,1.5-7.6s-11.8-1.9-14.8-3.3-5.4-6.1-7.5-7.3-4.9.6-3.7,3.3,2.1,1.8,2.2,2.8-1,6.2-1.3,6.7-.3,1.3-1,1.1c-1.1-.3-5-19.3-5.3-21.9,4.3,3.5,9.2,5.9,14.8,6.7.2-1.9-.3-3.5-.8-5.3s-3-5.1-3-5.5c0-.8.9-.3,1.2-.3,1.6,0,3.3.8,5,.6s.7.3.7-.7c0-6.6-7.2-10.6-13.1-10.8l.8-4.2c-5.1-.3-9.6,2-11.6,6.7-4.3-3-9.8-3-13.7.7l3.4,3.4c-1.8,1.3-3.5,2.8-4.6,4.7s-1.8,5.1-1.8,6.2v6.6h.2ZM431.6,265c7.8,2.1,8.7-3.5.2-1.3l-.2,1.3ZM432.4,270.9c.3.6,6.4-.4,5.8-2.3s-4.6.6-5.7.6l-.2,1.7h.1ZM434.5,276c.8,1.2,5.7-1.8,5.5-2.7-.4-1.9-6.6,1.2-5.5,2.7ZM442.9,276.4c-.9-.9-5,2.8-4.6,4,.6,2.4,5.7-3,4.6-4ZM445.1,279.9c-.3.2-3.1,4.6-1.5,5s3.5-3.4,3.5-4-1.3-1.3-2-.9h0ZM448.9,287.4c2.1.8,3.8-5.1,2.3-5.5-1.9-.6-2.6,5.1-2.3,5.5ZM457.3,288.6c.5-1.7,1.1-4.7-1-5.5-1,.3-.6,3.9-.6,4.8l.3.5,1.3.2h0Z"/>
|
|
||||||
<path class="st0" d="M455.6,276.4c-5-.8-9.1-3.6-10.6-8.5s.5-4,3.5-1.4,8.3,8.7,7.2,10h-.1Z"/>
|
|
||||||
<path class="st0" d="M420.6,290.3c-4.9-.6-8.9-3.6-11.8-7.4s-1.5-1.8-1.7-2.7c1-1,8.5,6.6,9.4,6.7,2.4.4-1.8-3.5-2.1-3.8-1-.8-5.4-3.5-5.7-4-.4-.8.5-.5.8-.5,5.2.8,10.1,6.6,10.9,11.6h.2Z"/>
|
|
||||||
<path class="st0" d="M400.4,281.5c-1.1,3.7-3,7.3-3,11.4h1.3c.5-3.7,1.5-7.8,3.6-11,1,4.8-1.5,11.6-4.5,15.4s-.4.8-1.2.7c-1.1-4.5-1.3-10.8,1.5-14.8s1.9-2.2,2.3-1.7h0Z"/>
|
|
||||||
<path class="st0" d="M411.3,276.8c0-.8,2.1-.4,2.6-.3,2.4.4,4,1.7,6.2,2-1.2-3.1-5.7-3.2-8.4-3.8,0-.8.9-.4,1.4-.4,2.8,0,5.6.7,7.8,2.4,2.2,1.7,4,4,1.2,3.9-4.3,0-7.1-2.4-10.9-3.7h0Z"/>
|
|
||||||
<path class="st0" d="M395.3,279.8c-1.1,1.6-3,3-4,4.6s-1.9,2.8-.4,2.5,2.8-4,4.2-4.6-.9,3.6-1.1,4c-.4.7-4.7,5.2-5.4,4.5-.2-4.6,1.8-9.9,6.7-11h0Z"/>
|
|
||||||
<path class="st0" d="M437,309.7l-1,2.5c-3.6-2.3-8-2.8-12.1-4,.5-.7,1.1-.7,1.9-.7,3.4,0,7.8,1.8,11.2,2.1h0Z"/>
|
|
||||||
<path class="st0" d="M417.2,308.5c0-1,0-5.8,1.4-5.5,4,3.5,6.1,6.2-1.4,5.5Z"/>
|
|
||||||
<path class="st0" d="M400.4,276.4c-1.8-.3-3.5.7-5.2.4s-2.3-.8-1.9-1.4c.8-1.6,6.9-1.4,7.2,1h-.1Z"/>
|
|
||||||
<path class="st0" d="M410.9,270.1c.4,3-3.6,3.3-5.5,4.6-.6-1.8,5-5.1,5.5-4.6Z"/>
|
|
||||||
<path class="st0" d="M426.9,305.9c-2.5-.2-4.1-1.3-5.5-3.4,1.7-.4,2,.8,3,1.4s2.6.3,2.5,1.9h0Z"/>
|
|
||||||
<path class="st1" d="M432.4,270.9l.2-1.7c1.1,0,5.1-2.2,5.7-.6s-5.5,2.9-5.8,2.3h-.1Z"/>
|
|
||||||
<path class="st1" d="M431.6,265l.2-1.3c8.4-2.1,7.7,3.4-.2,1.3Z"/>
|
|
||||||
<path class="st1" d="M434.5,276c-1.1-1.5,5.1-4.6,5.5-2.7s-4.6,4-5.5,2.7Z"/>
|
|
||||||
<path class="st1" d="M442.9,276.4c1.1,1.1-4,6.4-4.6,4s3.7-4.9,4.6-4Z"/>
|
|
||||||
<path class="st1" d="M445.1,279.9c.7-.4,2.1,0,2,.9s-2.4,4.4-3.5,4,1.3-4.8,1.5-5h0Z"/>
|
|
||||||
<path class="st1" d="M448.9,287.4c-.3-.3.4-6.1,2.3-5.5,1.4.4-.2,6.2-2.3,5.5Z"/>
|
|
||||||
<path class="st1" d="M457.3,288.6l-1.3-.2-.3-.5c0-.9-.4-4.6.6-4.8,2.1.8,1.5,3.8,1,5.5h0Z"/>
|
|
||||||
<path class="st0" d="M420.5,312.8c8.9,0,17.9,4.7,23.4,11.3,5.6,6.6,3.8,3.5,0,6.2-10.7,7.7-26.1,9-38.2,4.2-1.9-.8-10.5-5.1-10.5-6.8s4-5.3,4.8-6.2c5.3-5,13.1-8.6,20.4-8.8h.1Z"/>
|
|
||||||
<path class="st0" d="M398.7,316.9l-13.9-1.4c1.7-1,5-.8,6.9-.6s5.6.7,7,2.1h0Z"/>
|
|
||||||
<path class="st0" d="M456.9,314.8c.7.5,0,.8-.6.8-1.6.2-3.5-.2-5.1,0-2.4.3-5.2,1.2-7.6,1.3s-1.1,0,0-.5,5.1-1.6,6-1.6h7.4,0Z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 8.4 KiB |
41
src/main.tsx
41
src/main.tsx
@@ -1,41 +0,0 @@
|
|||||||
import { StrictMode } from 'react';
|
|
||||||
import ReactDOM from 'react-dom/client';
|
|
||||||
import { RouterProvider, createRouter } from '@tanstack/react-router';
|
|
||||||
|
|
||||||
// Import the generated route tree
|
|
||||||
import { routeTree } from './routeTree.gen';
|
|
||||||
|
|
||||||
import reportWebVitals from './reportWebVitals.ts';
|
|
||||||
|
|
||||||
// Create a new router instance
|
|
||||||
const router = createRouter({
|
|
||||||
routeTree,
|
|
||||||
context: {},
|
|
||||||
defaultPreload: 'intent',
|
|
||||||
scrollRestoration: true,
|
|
||||||
defaultStructuralSharing: true,
|
|
||||||
defaultPreloadStaleTime: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register the router instance for type safety
|
|
||||||
declare module '@tanstack/react-router' {
|
|
||||||
interface Register {
|
|
||||||
router: typeof router;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the app
|
|
||||||
const rootElement = document.getElementById('app');
|
|
||||||
if (rootElement && !rootElement.innerHTML) {
|
|
||||||
const root = ReactDOM.createRoot(rootElement);
|
|
||||||
root.render(
|
|
||||||
<StrictMode>
|
|
||||||
<RouterProvider router={router}/>
|
|
||||||
</StrictMode>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
|
||||||
// to log results (for example: reportWebVitals(console.log))
|
|
||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
|
||||||
reportWebVitals();
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
const reportWebVitals = (onPerfEntry?: () => void) => {
|
const reportWebVitals = (onPerfEntry?: () => void) => {
|
||||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||||
import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {
|
import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {
|
||||||
onCLS(onPerfEntry)
|
onCLS(onPerfEntry);
|
||||||
onINP(onPerfEntry)
|
onINP(onPerfEntry);
|
||||||
onFCP(onPerfEntry)
|
onFCP(onPerfEntry);
|
||||||
onLCP(onPerfEntry)
|
onLCP(onPerfEntry);
|
||||||
onTTFB(onPerfEntry)
|
onTTFB(onPerfEntry);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default reportWebVitals
|
export default reportWebVitals;
|
||||||
|
|||||||
@@ -11,79 +11,159 @@
|
|||||||
// Import Routes
|
// Import Routes
|
||||||
|
|
||||||
import { Route as rootRoute } from './routes/__root'
|
import { Route as rootRoute } from './routes/__root'
|
||||||
import { Route as IndexImport } from './routes/index'
|
import { Route as AboutImport } from './routes/about'
|
||||||
import { Route as ContactsContractIdImport } from './routes/contacts.$contractId'
|
import { Route as SidebarImport } from './routes/_sidebar'
|
||||||
|
import { Route as SidebarIndexImport } from './routes/_sidebar/index'
|
||||||
|
import { Route as SidebarContactsImport } from './routes/_sidebar/contacts'
|
||||||
|
import { Route as SidebarContactsContactIdImport } from './routes/_sidebar/contacts.$contactId'
|
||||||
|
|
||||||
// Create/Update Routes
|
// Create/Update Routes
|
||||||
|
|
||||||
const IndexRoute = IndexImport.update({
|
const AboutRoute = AboutImport.update({
|
||||||
id: '/',
|
id: '/about',
|
||||||
path: '/',
|
path: '/about',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
const ContactsContractIdRoute = ContactsContractIdImport.update({
|
const SidebarRoute = SidebarImport.update({
|
||||||
id: '/contacts/$contractId',
|
id: '/_sidebar',
|
||||||
path: '/contacts/$contractId',
|
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const SidebarIndexRoute = SidebarIndexImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () => SidebarRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
const SidebarContactsRoute = SidebarContactsImport.update({
|
||||||
|
id: '/contacts',
|
||||||
|
path: '/contacts',
|
||||||
|
getParentRoute: () => SidebarRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
const SidebarContactsContactIdRoute = SidebarContactsContactIdImport.update({
|
||||||
|
id: '/$contactId',
|
||||||
|
path: '/$contactId',
|
||||||
|
getParentRoute: () => SidebarContactsRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
// Populate the FileRoutesByPath interface
|
// Populate the FileRoutesByPath interface
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
interface FileRoutesByPath {
|
interface FileRoutesByPath {
|
||||||
'/': {
|
'/_sidebar': {
|
||||||
id: '/'
|
id: '/_sidebar'
|
||||||
path: '/'
|
path: ''
|
||||||
fullPath: '/'
|
fullPath: ''
|
||||||
preLoaderRoute: typeof IndexImport
|
preLoaderRoute: typeof SidebarImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
'/contacts/$contractId': {
|
'/about': {
|
||||||
id: '/contacts/$contractId'
|
id: '/about'
|
||||||
path: '/contacts/$contractId'
|
path: '/about'
|
||||||
fullPath: '/contacts/$contractId'
|
fullPath: '/about'
|
||||||
preLoaderRoute: typeof ContactsContractIdImport
|
preLoaderRoute: typeof AboutImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/_sidebar/contacts': {
|
||||||
|
id: '/_sidebar/contacts'
|
||||||
|
path: '/contacts'
|
||||||
|
fullPath: '/contacts'
|
||||||
|
preLoaderRoute: typeof SidebarContactsImport
|
||||||
|
parentRoute: typeof SidebarImport
|
||||||
|
}
|
||||||
|
'/_sidebar/': {
|
||||||
|
id: '/_sidebar/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/'
|
||||||
|
preLoaderRoute: typeof SidebarIndexImport
|
||||||
|
parentRoute: typeof SidebarImport
|
||||||
|
}
|
||||||
|
'/_sidebar/contacts/$contactId': {
|
||||||
|
id: '/_sidebar/contacts/$contactId'
|
||||||
|
path: '/$contactId'
|
||||||
|
fullPath: '/contacts/$contactId'
|
||||||
|
preLoaderRoute: typeof SidebarContactsContactIdImport
|
||||||
|
parentRoute: typeof SidebarContactsImport
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and export the route tree
|
// Create and export the route tree
|
||||||
|
|
||||||
|
interface SidebarContactsRouteChildren {
|
||||||
|
SidebarContactsContactIdRoute: typeof SidebarContactsContactIdRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarContactsRouteChildren: SidebarContactsRouteChildren = {
|
||||||
|
SidebarContactsContactIdRoute: SidebarContactsContactIdRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarContactsRouteWithChildren = SidebarContactsRoute._addFileChildren(
|
||||||
|
SidebarContactsRouteChildren,
|
||||||
|
)
|
||||||
|
|
||||||
|
interface SidebarRouteChildren {
|
||||||
|
SidebarContactsRoute: typeof SidebarContactsRouteWithChildren
|
||||||
|
SidebarIndexRoute: typeof SidebarIndexRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarRouteChildren: SidebarRouteChildren = {
|
||||||
|
SidebarContactsRoute: SidebarContactsRouteWithChildren,
|
||||||
|
SidebarIndexRoute: SidebarIndexRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarRouteWithChildren =
|
||||||
|
SidebarRoute._addFileChildren(SidebarRouteChildren)
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'': typeof SidebarRouteWithChildren
|
||||||
'/contacts/$contractId': typeof ContactsContractIdRoute
|
'/about': typeof AboutRoute
|
||||||
|
'/contacts': typeof SidebarContactsRouteWithChildren
|
||||||
|
'/': typeof SidebarIndexRoute
|
||||||
|
'/contacts/$contactId': typeof SidebarContactsContactIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/about': typeof AboutRoute
|
||||||
'/contacts/$contractId': typeof ContactsContractIdRoute
|
'/contacts': typeof SidebarContactsRouteWithChildren
|
||||||
|
'/': typeof SidebarIndexRoute
|
||||||
|
'/contacts/$contactId': typeof SidebarContactsContactIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRoute
|
__root__: typeof rootRoute
|
||||||
'/': typeof IndexRoute
|
'/_sidebar': typeof SidebarRouteWithChildren
|
||||||
'/contacts/$contractId': typeof ContactsContractIdRoute
|
'/about': typeof AboutRoute
|
||||||
|
'/_sidebar/contacts': typeof SidebarContactsRouteWithChildren
|
||||||
|
'/_sidebar/': typeof SidebarIndexRoute
|
||||||
|
'/_sidebar/contacts/$contactId': typeof SidebarContactsContactIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths: '/' | '/contacts/$contractId'
|
fullPaths: '' | '/about' | '/contacts' | '/' | '/contacts/$contactId'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to: '/' | '/contacts/$contractId'
|
to: '/about' | '/contacts' | '/' | '/contacts/$contactId'
|
||||||
id: '__root__' | '/' | '/contacts/$contractId'
|
id:
|
||||||
|
| '__root__'
|
||||||
|
| '/_sidebar'
|
||||||
|
| '/about'
|
||||||
|
| '/_sidebar/contacts'
|
||||||
|
| '/_sidebar/'
|
||||||
|
| '/_sidebar/contacts/$contactId'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
SidebarRoute: typeof SidebarRouteWithChildren
|
||||||
ContactsContractIdRoute: typeof ContactsContractIdRoute
|
AboutRoute: typeof AboutRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
SidebarRoute: SidebarRouteWithChildren,
|
||||||
ContactsContractIdRoute: ContactsContractIdRoute,
|
AboutRoute: AboutRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const routeTree = rootRoute
|
export const routeTree = rootRoute
|
||||||
@@ -96,15 +176,34 @@ export const routeTree = rootRoute
|
|||||||
"__root__": {
|
"__root__": {
|
||||||
"filePath": "__root.tsx",
|
"filePath": "__root.tsx",
|
||||||
"children": [
|
"children": [
|
||||||
"/",
|
"/_sidebar",
|
||||||
"/contacts/$contractId"
|
"/about"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"/": {
|
"/_sidebar": {
|
||||||
"filePath": "index.tsx"
|
"filePath": "_sidebar.tsx",
|
||||||
|
"children": [
|
||||||
|
"/_sidebar/contacts",
|
||||||
|
"/_sidebar/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"/contacts/$contractId": {
|
"/about": {
|
||||||
"filePath": "contacts.$contractId.tsx"
|
"filePath": "about.tsx"
|
||||||
|
},
|
||||||
|
"/_sidebar/contacts": {
|
||||||
|
"filePath": "_sidebar/contacts.tsx",
|
||||||
|
"parent": "/_sidebar",
|
||||||
|
"children": [
|
||||||
|
"/_sidebar/contacts/$contactId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"/_sidebar/": {
|
||||||
|
"filePath": "_sidebar/index.tsx",
|
||||||
|
"parent": "/_sidebar"
|
||||||
|
},
|
||||||
|
"/_sidebar/contacts/$contactId": {
|
||||||
|
"filePath": "_sidebar/contacts.$contactId.tsx",
|
||||||
|
"parent": "/_sidebar/contacts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/router.tsx
Normal file
16
src/router.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { createRouter as createTanStackRouter } from '@tanstack/react-router';
|
||||||
|
import { routeTree } from './routeTree.gen';
|
||||||
|
|
||||||
|
export function createRouter() {
|
||||||
|
return createTanStackRouter({
|
||||||
|
routeTree,
|
||||||
|
defaultPreload: 'intent',
|
||||||
|
scrollRestoration: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@tanstack/react-router' {
|
||||||
|
interface Register {
|
||||||
|
router: ReturnType<typeof createRouter>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +1,57 @@
|
|||||||
import { Outlet, createRootRoute, Link } from '@tanstack/react-router';
|
import { Outlet, createRootRoute, HeadContent, Scripts } from '@tanstack/react-router';
|
||||||
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
|
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
|
||||||
|
import appCss from '@/App.css?url';
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
component: () => (
|
head: () => ({
|
||||||
<>
|
meta: [{
|
||||||
<div id="sidebar">
|
charSet: 'utf-8',
|
||||||
<h1>React Router Contacts</h1>
|
}, {
|
||||||
<div>
|
name: 'viewport', content: 'width=device-width, initial-scale=1'
|
||||||
<form id="search-form" role="search">
|
}, {
|
||||||
<input
|
name: 'description', content: 'TanStack/Router Address Book'
|
||||||
aria-label="Search contacts"
|
}],
|
||||||
id="q"
|
links: [{
|
||||||
name="q"
|
rel: 'stylesheet', href: appCss
|
||||||
placeholder="Search"
|
}, {
|
||||||
type="search"
|
rel: 'icon', href: '/favicon.ico'
|
||||||
/>
|
}, {
|
||||||
<div aria-hidden hidden={true} id="search-spinner"/>
|
rel: 'apple-touch-icon', href: '/logo192.png'
|
||||||
</form>
|
}, {
|
||||||
<form method="post">
|
rel: 'manifest', href: '/manifest.json'
|
||||||
<button type="submit">New</button>
|
}]
|
||||||
</form>
|
}),
|
||||||
</div>
|
component: RootLayout,
|
||||||
<nav>
|
notFoundComponent: () => {
|
||||||
<ul>
|
return (
|
||||||
<li>
|
<main id="error-page">
|
||||||
<Link to="/contacts/$contractId" params={{ contractId: '1' }}>Your Name</Link>
|
<h1>404</h1>
|
||||||
</li>
|
<p>The requested page could not be found.</p>
|
||||||
<li>
|
</main>
|
||||||
<Link to="/contacts/$contractId" params={{ contractId: '2' }}>Your Friend</Link>
|
);
|
||||||
</li>
|
}
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div id={'detail'}>
|
|
||||||
<Outlet/>
|
|
||||||
</div>
|
|
||||||
<TanStackRouterDevtools/>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
notFoundComponent: NotFoundComponent,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function NotFoundComponent() {
|
function RootLayout() {
|
||||||
return (
|
return (
|
||||||
<main id="error-page">
|
<RootDocument>
|
||||||
<h1>404</h1>
|
<Outlet/>
|
||||||
<p>The requested page could not be found.</p>
|
<TanStackRouterDevtools/>
|
||||||
</main>
|
</RootDocument>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<HeadContent/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{children}
|
||||||
|
<Scripts/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
78
src/routes/_sidebar.tsx
Normal file
78
src/routes/_sidebar.tsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { createFileRoute, Link, Outlet } from '@tanstack/react-router';
|
||||||
|
import { fetchContacts } from "@/utils/contacts.tsx";
|
||||||
|
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_sidebar')({
|
||||||
|
component: Sidebar,
|
||||||
|
loader: async () => fetchContacts(),
|
||||||
|
notFoundComponent: () => <div>Not Found</div>,
|
||||||
|
});
|
||||||
|
|
||||||
|
function Sidebar() {
|
||||||
|
const contacts = Route.useLoaderData();
|
||||||
|
if (contacts === undefined) {
|
||||||
|
console.log("SIDEBAR ERROR!?");
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div id="sidebar">UNDEFINED LOADER DATA IN SIDEBAR</div>
|
||||||
|
<div id={'detail'}>
|
||||||
|
<Outlet/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div id="sidebar">
|
||||||
|
<h1>
|
||||||
|
<Link to="/about">TanStack Start Contacts</Link>
|
||||||
|
</h1>
|
||||||
|
<div>
|
||||||
|
<form id="search-form" role="search">
|
||||||
|
<input
|
||||||
|
aria-label="Search contacts"
|
||||||
|
id="q"
|
||||||
|
name="q"
|
||||||
|
placeholder="Search"
|
||||||
|
type="search"
|
||||||
|
/>
|
||||||
|
<div aria-hidden hidden={true} id="search-spinner"/>
|
||||||
|
</form>
|
||||||
|
<form method="post">
|
||||||
|
<button type="submit">New</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
{contacts.length ? (
|
||||||
|
<ul>
|
||||||
|
{contacts.map((contact) => (
|
||||||
|
<li key={contact.id}>
|
||||||
|
<Link to="/contacts/$contactId" params={{ contactId: contact.id }}>
|
||||||
|
{contact.first || contact.last ? (
|
||||||
|
<>
|
||||||
|
{contact.first} {contact.last}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<i>No Name</i>
|
||||||
|
)}
|
||||||
|
{contact.favorite ? (
|
||||||
|
<span>★</span>
|
||||||
|
) : null}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
<p>
|
||||||
|
<i>No contacts</i>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div id={'detail'}>
|
||||||
|
<Outlet/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
import type { ContactRecord } from "@/data.ts";
|
import { type ContactRecord, fetchContact } from "@/utils/contacts.tsx";
|
||||||
|
|
||||||
export const Route = createFileRoute('/contacts/$contractId')({
|
export const Route = createFileRoute('/_sidebar/contacts/$contactId')({
|
||||||
|
loader: async ({ params }) => {
|
||||||
|
const contact = await fetchContact({ data: params.contactId });
|
||||||
|
return { contact };
|
||||||
|
},
|
||||||
component: Contact,
|
component: Contact,
|
||||||
|
notFoundComponent: () => {
|
||||||
|
return <p>Post not found!</p>;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function Contact() {
|
function Contact() {
|
||||||
const contact = {
|
const { contact } = Route.useLoaderData();
|
||||||
first: "Your",
|
|
||||||
last: "Name",
|
|
||||||
avatar: "https://placecats.com/200/200",
|
|
||||||
twitter: "your_handle",
|
|
||||||
notes: "Some notes",
|
|
||||||
favorite: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="contact">
|
<div id="contact">
|
||||||
19
src/routes/_sidebar/contacts.tsx
Normal file
19
src/routes/_sidebar/contacts.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { createFileRoute, Outlet } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_sidebar/contacts')({
|
||||||
|
component: RouteComponent,
|
||||||
|
notFoundComponent: NotFoundContact,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return <Outlet/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NotFoundContact() {
|
||||||
|
return (
|
||||||
|
<main id="error-page">
|
||||||
|
<h1>404</h1>
|
||||||
|
<p>The requested page could not be found.</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
src/routes/_sidebar/index.tsx
Normal file
19
src/routes/_sidebar/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_sidebar/')({
|
||||||
|
component: App,
|
||||||
|
});
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<p id="index-page">
|
||||||
|
This is a demo for TanStack/Start and Router.
|
||||||
|
<br/>
|
||||||
|
Check out{" "}
|
||||||
|
<a href="https://tanstack.com/">
|
||||||
|
the docs at tanstack.com
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
49
src/routes/about.tsx
Normal file
49
src/routes/about.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/about')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div id="about">
|
||||||
|
<Link to="/">← Go to demo</Link>
|
||||||
|
<h1>About React Router Contacts</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
This is a demo application showing off some of the
|
||||||
|
powerful features of React Router, including
|
||||||
|
dynamic routing, nested routes, loaders, actions,
|
||||||
|
and more.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Features</h2>
|
||||||
|
<p>
|
||||||
|
Explore the demo to see how React Router handles:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Data loading and mutations with loaders and
|
||||||
|
actions
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Nested routing with parent/child relationships
|
||||||
|
</li>
|
||||||
|
<li>URL-based routing with dynamic segments</li>
|
||||||
|
<li>Pending and optimistic UI</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Learn More</h2>
|
||||||
|
<p>
|
||||||
|
Check out the official documentation at{" "}
|
||||||
|
<a href="https://reactrouter.com">
|
||||||
|
reactrouter.com
|
||||||
|
</a>{" "}
|
||||||
|
to learn more about building great web
|
||||||
|
applications with React Router.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
|
||||||
import '../App.css';
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/')({
|
|
||||||
component: App,
|
|
||||||
});
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
return (
|
|
||||||
<div></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
13
src/ssr.tsx
Normal file
13
src/ssr.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/// <reference types="vinxi/types/server" />
|
||||||
|
import {
|
||||||
|
createStartHandler,
|
||||||
|
defaultStreamHandler,
|
||||||
|
} from '@tanstack/react-start/server';
|
||||||
|
import { getRouterManifest } from '@tanstack/react-start/router-manifest';
|
||||||
|
|
||||||
|
import { createRouter } from './router';
|
||||||
|
|
||||||
|
export default createStartHandler({
|
||||||
|
createRouter,
|
||||||
|
getRouterManifest,
|
||||||
|
})(defaultStreamHandler);
|
||||||
20
src/utils/contacts.tsx
Normal file
20
src/utils/contacts.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { createServerFn } from "@tanstack/react-start";
|
||||||
|
import { getContact, getContacts } from "@/data.ts";
|
||||||
|
import { notFound } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export type { ContactRecord } from "@/data.ts";
|
||||||
|
|
||||||
|
export const fetchContacts = createServerFn({ method: 'GET' })
|
||||||
|
.handler(async () => {
|
||||||
|
console.log("Fetch Contacts");
|
||||||
|
return await getContacts();
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchContact = createServerFn({ method: 'GET' })
|
||||||
|
.validator((data: string) => data)
|
||||||
|
.handler(async (ctx) => {
|
||||||
|
console.log(`Fetch Contact ${ctx.data}`);
|
||||||
|
const contact = await getContact(ctx.data);
|
||||||
|
if (contact === null) throw notFound();
|
||||||
|
return contact;
|
||||||
|
});
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// noinspection JSUnresolvedReference
|
|
||||||
|
|
||||||
import { defineConfig } from "vite";
|
|
||||||
import viteReact from "@vitejs/plugin-react";
|
|
||||||
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
|
|
||||||
import { resolve } from "node:path";
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [TanStackRouterVite({ autoCodeSplitting: true }), viteReact()],
|
|
||||||
test: {
|
|
||||||
globals: true,
|
|
||||||
environment: "jsdom",
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
'@': resolve(__dirname, './src'),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user