feat: made project
This commit is contained in:
parent
5089b4a7d2
commit
781be5653e
25 changed files with 2187 additions and 231 deletions
|
|
@ -1,3 +1,4 @@
|
|||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
routerTree.gen.ts
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<!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="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
|
|
|
|||
1647
package-lock.json
generated
1647
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -22,6 +22,10 @@
|
|||
"@tanstack/router-plugin": "^1.121.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"rehype-sanitize": "^6.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"tailwindcss": "^4.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
BIN
public/bg.jpeg
Normal file
BIN
public/bg.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 763 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"short_name": "TanStack App",
|
||||
"name": "Create TanStack App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
41
src/components/Card.tsx
Normal file
41
src/components/Card.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import type { CardDownloadType } from '@/types/cards'
|
||||
import Mdown from './Mdown'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
content: string
|
||||
id?: number
|
||||
downloads?: Array<CardDownloadType>
|
||||
}
|
||||
|
||||
export default function Card({ title, content, id, downloads }: Props) {
|
||||
return (
|
||||
<div className="bg-[#161718] w-lg p-5 flex flex-col gap-5 rounded-xl self-center">
|
||||
<h1 className="text-white text-2xl font-bold" id={id?.toString()}>
|
||||
<Mdown>{title}</Mdown>
|
||||
</h1>
|
||||
<div className=" flex flex-col space-y-1 text-[#9e9b97]">
|
||||
<Mdown>{content}</Mdown>
|
||||
</div>
|
||||
{downloads != null ? (
|
||||
<details className="text-[#9e9b97]">
|
||||
<summary>Téléchargments</summary>
|
||||
<ol className="list-disc list-inside pl-5">
|
||||
{downloads.map((e, i) => (
|
||||
<li>
|
||||
<a
|
||||
href={e.link}
|
||||
key={i}
|
||||
download={e.filename}
|
||||
className="text-sky-600 underline"
|
||||
>
|
||||
{e.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</details>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,16 +1,48 @@
|
|||
import { loadLang, setLang } from '@/integrations/lang/lang'
|
||||
import { Link } from '@tanstack/react-router'
|
||||
|
||||
export default function Header() {
|
||||
const lang = loadLang()
|
||||
|
||||
function toggleLang() {
|
||||
if (lang == 'fr') {
|
||||
setLang('en')
|
||||
} else {
|
||||
setLang('fr')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="p-2 flex gap-2 bg-white text-black justify-between">
|
||||
<nav className="flex flex-row">
|
||||
<div className="px-2 font-bold">
|
||||
<Link to="/">Home</Link>
|
||||
<header className="p-2 flex gap-2 text-[#9e9b97] justify-between bg-[#080b0e]">
|
||||
<nav className="flex flex-row w-screen justify-between">
|
||||
<div className="flex flex-row">
|
||||
<div className="px-2">
|
||||
<Link to="/">{lang == 'fr' ? 'Accueil' : 'Home'}</Link>
|
||||
</div>
|
||||
|
||||
<div className="px-2 font-bold">
|
||||
<Link to="/demo/tanstack-query">TanStack Query</Link>
|
||||
<div className="px-2">
|
||||
<Link to="/projects">
|
||||
{lang == 'fr' ? 'Projets' : 'Projects'}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="px-2">
|
||||
<Link to="/lessons">
|
||||
{lang == 'fr' ? 'Cours' : 'Lessons'}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="px-2">
|
||||
{lang == 'fr'
|
||||
? "[WIP] Livre d'Or"
|
||||
: '[WIP] Golden Book'}
|
||||
</div>
|
||||
</div>
|
||||
<button className="cursor-pointer" onClick={toggleLang}>
|
||||
{lang == 'fr'
|
||||
? 'Translate in English'
|
||||
: 'Traduire en Français'}
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
|
|
|
|||
60
src/components/Mdown.tsx
Normal file
60
src/components/Mdown.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { Link } from '@tanstack/react-router'
|
||||
import Markdown from 'react-markdown'
|
||||
import rehypeRaw from 'rehype-raw'
|
||||
import rehypeSanitize from 'rehype-sanitize'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
|
||||
interface Props {
|
||||
children: string
|
||||
}
|
||||
|
||||
export default function Mdown({ children }: Props) {
|
||||
return (
|
||||
<Markdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
rehypePlugins={[rehypeRaw, rehypeSanitize]}
|
||||
components={{
|
||||
ul(props) {
|
||||
const { node, ...rest } = props
|
||||
return <ul className="list-disc list-inside" {...rest} />
|
||||
},
|
||||
li(props) {
|
||||
const { node, ...rest } = props
|
||||
return <li className="pl-5" {...rest} />
|
||||
},
|
||||
a(props) {
|
||||
const { node, ...rest } = props
|
||||
const classes = 'text-sky-600 underline'
|
||||
if (rest.href?.startsWith('dl:')) {
|
||||
let parts = rest.href.split('/')
|
||||
return (
|
||||
<a
|
||||
className={classes}
|
||||
href={rest.href.replace('dl:', '')}
|
||||
download={parts[parts.length - 1]}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
if (rest.href?.startsWith('/public')) {
|
||||
return (
|
||||
<a className={classes} target="_blank" {...rest} />
|
||||
)
|
||||
}
|
||||
if (rest.href?.startsWith('/')) {
|
||||
return (
|
||||
<Link
|
||||
className={classes}
|
||||
to={rest.href}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return <a className={classes} {...rest} />
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Markdown>
|
||||
)
|
||||
}
|
||||
13
src/integrations/lang/lang.tsx
Normal file
13
src/integrations/lang/lang.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export function loadLang() {
|
||||
let lang = localStorage.getItem('lang')
|
||||
if (lang == null) {
|
||||
localStorage.setItem('lang', 'fr')
|
||||
lang = 'fr'
|
||||
}
|
||||
return lang
|
||||
}
|
||||
|
||||
export function setLang(lang: string) {
|
||||
localStorage.setItem('lang', lang)
|
||||
window.location.reload()
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@ export function Provider({
|
|||
queryClient: QueryClient
|
||||
}) {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
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 After Width: | Height: | Size: 0 B |
|
|
@ -21,7 +21,8 @@ const router = createRouter({
|
|||
defaultPreload: 'intent',
|
||||
scrollRestoration: true,
|
||||
defaultStructuralSharing: true,
|
||||
defaultPreloadStaleTime: 0,
|
||||
defaultPreloadStaleTime: 60_000,
|
||||
defaultStaleTime: 60_000,
|
||||
})
|
||||
|
||||
// Register the router instance for type safety
|
||||
|
|
|
|||
113
src/routeTree.gen.ts
Normal file
113
src/routeTree.gen.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
import { Route as ProjectsIndexRouteImport } from './routes/projects/index'
|
||||
import { Route as LessonsIndexRouteImport } from './routes/lessons/index'
|
||||
import { Route as LessonsLessonNameRouteImport } from './routes/lessons/$lessonName'
|
||||
|
||||
const IndexRoute = IndexRouteImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const ProjectsIndexRoute = ProjectsIndexRouteImport.update({
|
||||
id: '/projects/',
|
||||
path: '/projects/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const LessonsIndexRoute = LessonsIndexRouteImport.update({
|
||||
id: '/lessons/',
|
||||
path: '/lessons/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const LessonsLessonNameRoute = LessonsLessonNameRouteImport.update({
|
||||
id: '/lessons/$lessonName',
|
||||
path: '/lessons/$lessonName',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/lessons/$lessonName': typeof LessonsLessonNameRoute
|
||||
'/lessons': typeof LessonsIndexRoute
|
||||
'/projects': typeof ProjectsIndexRoute
|
||||
}
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/lessons/$lessonName': typeof LessonsLessonNameRoute
|
||||
'/lessons': typeof LessonsIndexRoute
|
||||
'/projects': typeof ProjectsIndexRoute
|
||||
}
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/': typeof IndexRoute
|
||||
'/lessons/$lessonName': typeof LessonsLessonNameRoute
|
||||
'/lessons/': typeof LessonsIndexRoute
|
||||
'/projects/': typeof ProjectsIndexRoute
|
||||
}
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths: '/' | '/lessons/$lessonName' | '/lessons' | '/projects'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/' | '/lessons/$lessonName' | '/lessons' | '/projects'
|
||||
id: '__root__' | '/' | '/lessons/$lessonName' | '/lessons/' | '/projects/'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
LessonsLessonNameRoute: typeof LessonsLessonNameRoute
|
||||
LessonsIndexRoute: typeof LessonsIndexRoute
|
||||
ProjectsIndexRoute: typeof ProjectsIndexRoute
|
||||
}
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/': {
|
||||
id: '/'
|
||||
path: '/'
|
||||
fullPath: '/'
|
||||
preLoaderRoute: typeof IndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/projects/': {
|
||||
id: '/projects/'
|
||||
path: '/projects'
|
||||
fullPath: '/projects'
|
||||
preLoaderRoute: typeof ProjectsIndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/lessons/': {
|
||||
id: '/lessons/'
|
||||
path: '/lessons'
|
||||
fullPath: '/lessons'
|
||||
preLoaderRoute: typeof LessonsIndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/lessons/$lessonName': {
|
||||
id: '/lessons/$lessonName'
|
||||
path: '/lessons/$lessonName'
|
||||
fullPath: '/lessons/$lessonName'
|
||||
preLoaderRoute: typeof LessonsLessonNameRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
LessonsLessonNameRoute: LessonsLessonNameRoute,
|
||||
LessonsIndexRoute: LessonsIndexRoute,
|
||||
ProjectsIndexRoute: ProjectsIndexRoute,
|
||||
}
|
||||
export const routeTree = rootRouteImport
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
|
@ -13,7 +13,8 @@ interface MyRouterContext {
|
|||
}
|
||||
|
||||
export const Route = createRootRouteWithContext<MyRouterContext>()({
|
||||
component: () => (
|
||||
component: () => {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<Outlet />
|
||||
|
|
@ -30,5 +31,6 @@ export const Route = createRootRouteWithContext<MyRouterContext>()({
|
|||
]}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export const Route = createFileRoute('/demo/tanstack-query')({
|
||||
component: TanStackQueryDemo,
|
||||
})
|
||||
|
||||
function TanStackQueryDemo() {
|
||||
const { data } = useQuery({
|
||||
queryKey: ['todos'],
|
||||
queryFn: () =>
|
||||
Promise.resolve([
|
||||
{ id: 1, name: 'Alice' },
|
||||
{ id: 2, name: 'Bob' },
|
||||
{ id: 3, name: 'Charlie' },
|
||||
]),
|
||||
initialData: [],
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-center justify-center min-h-screen bg-gradient-to-br from-purple-100 to-blue-100 p-4 text-white"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'radial-gradient(50% 50% at 95% 5%, #f4a460 0%, #8b4513 70%, #1a0f0a 100%)',
|
||||
}}
|
||||
>
|
||||
<div className="w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10">
|
||||
<h1 className="text-2xl mb-4">
|
||||
TanStack Query Simple Promise Handling
|
||||
</h1>
|
||||
<ul className="mb-4 space-y-2">
|
||||
{data.map((todo) => (
|
||||
<li
|
||||
key={todo.id}
|
||||
className="bg-white/10 border border-white/20 rounded-lg p-3 backdrop-blur-sm shadow-md"
|
||||
>
|
||||
<span className="text-lg text-white">{todo.name}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,39 +1,43 @@
|
|||
import Card from '@/components/Card'
|
||||
import { loadLang } from '@/integrations/lang/lang'
|
||||
import type { DataType } from '@/types/cards'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import logo from '../logo.svg'
|
||||
|
||||
// ===================
|
||||
// =====< UTILS >=====
|
||||
// ===================
|
||||
|
||||
async function fetchData(): Promise<DataType> {
|
||||
const lang = loadLang()
|
||||
let data = await fetch(`${import.meta.env.VITE_API}/${lang}/home`)
|
||||
return await data.json()
|
||||
}
|
||||
|
||||
// =======================
|
||||
// =====< COMPONENT >=====
|
||||
// =======================
|
||||
|
||||
export const Route = createFileRoute('/')({
|
||||
loader: async () => fetchData(),
|
||||
component: App,
|
||||
})
|
||||
|
||||
function App() {
|
||||
let data = Route.useLoaderData()
|
||||
|
||||
const items = data.cards.map((e, i) => (
|
||||
<Card title={e.title} content={e.content} key={i} />
|
||||
))
|
||||
|
||||
return (
|
||||
<div className="text-center">
|
||||
<header className="min-h-screen flex flex-col items-center justify-center bg-[#282c34] text-white text-[calc(10px+2vmin)]">
|
||||
<img
|
||||
src={logo}
|
||||
className="h-[40vmin] pointer-events-none animate-[spin_20s_linear_infinite]"
|
||||
alt="logo"
|
||||
/>
|
||||
<p>
|
||||
Edit <code>src/routes/index.tsx</code> and save to reload.
|
||||
</p>
|
||||
<a
|
||||
className="text-[#61dafb] hover:underline"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
<a
|
||||
className="text-[#61dafb] hover:underline"
|
||||
href="https://tanstack.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn TanStack
|
||||
</a>
|
||||
</header>
|
||||
<div className="bg-[url(/public/bg.jpeg)] bg-cover bg-no-repeat bg-center min-h-screen">
|
||||
<div className="flex flex-col gap-5 pt-10">
|
||||
<h1 className="text-5xl text-white text-center mb-10">
|
||||
{data.title}
|
||||
</h1>
|
||||
{items}
|
||||
<p className="text-[#9e9b97] text-center mb-5">Stay Foss :)</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
55
src/routes/lessons/$lessonName.tsx
Normal file
55
src/routes/lessons/$lessonName.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import Card from '@/components/Card'
|
||||
import { loadLang } from '@/integrations/lang/lang'
|
||||
import type { DataType } from '@/types/cards'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
// ===================
|
||||
// =====< UTILS >=====
|
||||
// ===================
|
||||
|
||||
async function fetchData(lessonName: string): Promise<DataType> {
|
||||
const lang = loadLang()
|
||||
let data = await fetch(
|
||||
`${import.meta.env.VITE_API}/${lang}/lessons/${lessonName}`,
|
||||
)
|
||||
return await data.json()
|
||||
}
|
||||
|
||||
// =======================
|
||||
// =====< COMPONENT >=====
|
||||
// =======================
|
||||
|
||||
export const Route = createFileRoute('/lessons/$lessonName')({
|
||||
loader: async ({ params }) => fetchData(params.lessonName),
|
||||
component: Projects,
|
||||
notFoundComponent: () => {
|
||||
return (
|
||||
<div className="flex items-center self-center text-center">404</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
export default function Projects() {
|
||||
let data = Route.useLoaderData()
|
||||
|
||||
const items = data.cards.map((e, i) => (
|
||||
<Card
|
||||
title={e.title}
|
||||
content={e.content}
|
||||
id={i}
|
||||
key={i}
|
||||
downloads={e?.downloads}
|
||||
/>
|
||||
))
|
||||
|
||||
return (
|
||||
<div className="bg-[url(/public/bg.jpeg)] bg-cover bg-no-repeat bg-center min-h-screen">
|
||||
<div className="flex flex-col gap-5 pt-10">
|
||||
<h1 className="text-5xl text-white text-center mb-10">
|
||||
{data.title}
|
||||
</h1>
|
||||
{items}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
42
src/routes/lessons/index.tsx
Normal file
42
src/routes/lessons/index.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import Card from '@/components/Card'
|
||||
import { loadLang } from '@/integrations/lang/lang'
|
||||
import type { DataType } from '@/types/cards'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
// ===================
|
||||
// =====< UTILS >=====
|
||||
// ===================
|
||||
|
||||
async function fetchData(): Promise<DataType> {
|
||||
const lang = loadLang()
|
||||
let data = await fetch(`${import.meta.env.VITE_API}/${lang}/lessons`)
|
||||
return await data.json()
|
||||
}
|
||||
|
||||
// =======================
|
||||
// =====< COMPONENT >=====
|
||||
// =======================
|
||||
|
||||
export const Route = createFileRoute('/lessons/')({
|
||||
loader: async () => fetchData(),
|
||||
component: Projects,
|
||||
})
|
||||
|
||||
export default function Projects() {
|
||||
let data = Route.useLoaderData()
|
||||
|
||||
const items = data.cards.map((e, i) => (
|
||||
<Card title={e.title} content={e.content} key={i} />
|
||||
))
|
||||
|
||||
return (
|
||||
<div className="bg-[url(/public/bg.jpeg)] bg-cover bg-no-repeat bg-center min-h-screen">
|
||||
<div className="flex flex-col gap-5 pt-10">
|
||||
<h1 className="text-5xl text-white text-center mb-10">
|
||||
{data.title}
|
||||
</h1>
|
||||
{items}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
42
src/routes/projects/index.tsx
Normal file
42
src/routes/projects/index.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import Card from '@/components/Card'
|
||||
import { loadLang } from '@/integrations/lang/lang'
|
||||
import type { DataType } from '@/types/cards'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
// ===================
|
||||
// =====< UTILS >=====
|
||||
// ===================
|
||||
|
||||
async function fetchData(): Promise<DataType> {
|
||||
const lang = loadLang()
|
||||
let data = await fetch(`${import.meta.env.VITE_API}/${lang}/projects`)
|
||||
return await data.json()
|
||||
}
|
||||
|
||||
// =======================
|
||||
// =====< COMPONENT >=====
|
||||
// =======================
|
||||
|
||||
export const Route = createFileRoute('/projects/')({
|
||||
loader: async () => fetchData(),
|
||||
component: Projects,
|
||||
})
|
||||
|
||||
export default function Projects() {
|
||||
let data = Route.useLoaderData()
|
||||
|
||||
const items = data.cards.map((e, i) => (
|
||||
<Card title={e.title} content={e.content} key={i} />
|
||||
))
|
||||
|
||||
return (
|
||||
<div className="bg-[url(/public/bg.jpeg)] bg-cover bg-no-repeat bg-center min-h-screen">
|
||||
<div className="flex flex-col gap-5 pt-10">
|
||||
<h1 className="text-5xl text-white text-center mb-10">
|
||||
{data.title}
|
||||
</h1>
|
||||
{items}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
16
src/types/cards.tsx
Normal file
16
src/types/cards.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export type CardDownloadType = {
|
||||
title: string
|
||||
filename: string
|
||||
link: string
|
||||
}
|
||||
|
||||
export type CardType = {
|
||||
title: string
|
||||
content: string
|
||||
downloads?: Array<CardDownloadType>
|
||||
}
|
||||
|
||||
export type DataType = {
|
||||
title: string
|
||||
cards: Array<CardType>
|
||||
}
|
||||
|
|
@ -2,13 +2,15 @@ import { defineConfig } from 'vite'
|
|||
import viteReact from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
|
||||
import tanstackRouter from '@tanstack/router-plugin/vite'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
TanStackRouterVite({ autoCodeSplitting: true }),
|
||||
tanstackRouter({autoCodeSplitting: true}),
|
||||
viteReact(),
|
||||
tailwindcss(),
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue