feat: made project

This commit is contained in:
Alzalia 2025-09-04 20:51:12 +02:00
parent 5089b4a7d2
commit 781be5653e
25 changed files with 2187 additions and 231 deletions

View file

@ -1,3 +1,4 @@
package-lock.json package-lock.json
pnpm-lock.yaml pnpm-lock.yaml
yarn.lock yarn.lock
routerTree.gen.ts

View file

@ -1,9 +1,8 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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="theme-color" content="#000000" />
<meta <meta
name="description" name="description"

1647
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,10 @@
"@tanstack/router-plugin": "^1.121.2", "@tanstack/router-plugin": "^1.121.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^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" "tailwindcss": "^4.0.6"
}, },
"devDependencies": { "devDependencies": {

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

View file

@ -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
View 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>
)
}

View file

@ -1,16 +1,48 @@
import { loadLang, setLang } from '@/integrations/lang/lang'
import { Link } from '@tanstack/react-router' import { Link } from '@tanstack/react-router'
export default function Header() { export default function Header() {
const lang = loadLang()
function toggleLang() {
if (lang == 'fr') {
setLang('en')
} else {
setLang('fr')
}
}
return ( return (
<header className="p-2 flex gap-2 bg-white text-black justify-between"> <header className="p-2 flex gap-2 text-[#9e9b97] justify-between bg-[#080b0e]">
<nav className="flex flex-row"> <nav className="flex flex-row w-screen justify-between">
<div className="px-2 font-bold"> <div className="flex flex-row">
<Link to="/">Home</Link> <div className="px-2">
<Link to="/">{lang == 'fr' ? 'Accueil' : 'Home'}</Link>
</div> </div>
<div className="px-2 font-bold"> <div className="px-2">
<Link to="/demo/tanstack-query">TanStack Query</Link> <Link to="/projects">
{lang == 'fr' ? 'Projets' : 'Projects'}
</Link>
</div> </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> </nav>
</header> </header>
) )

60
src/components/Mdown.tsx Normal file
View 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>
)
}

View 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()
}

View file

@ -15,6 +15,8 @@ export function Provider({
queryClient: QueryClient queryClient: QueryClient
}) { }) {
return ( return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider> <QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
) )
} }

View file

@ -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

Before After
Before After

View file

@ -21,7 +21,8 @@ const router = createRouter({
defaultPreload: 'intent', defaultPreload: 'intent',
scrollRestoration: true, scrollRestoration: true,
defaultStructuralSharing: true, defaultStructuralSharing: true,
defaultPreloadStaleTime: 0, defaultPreloadStaleTime: 60_000,
defaultStaleTime: 60_000,
}) })
// Register the router instance for type safety // Register the router instance for type safety

113
src/routeTree.gen.ts Normal file
View 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>()

View file

@ -13,7 +13,8 @@ interface MyRouterContext {
} }
export const Route = createRootRouteWithContext<MyRouterContext>()({ export const Route = createRootRouteWithContext<MyRouterContext>()({
component: () => ( component: () => {
return (
<> <>
<Header /> <Header />
<Outlet /> <Outlet />
@ -30,5 +31,6 @@ export const Route = createRootRouteWithContext<MyRouterContext>()({
]} ]}
/> />
</> </>
), )
},
}) })

View file

@ -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>
)
}

View file

@ -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 { 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('/')({ export const Route = createFileRoute('/')({
loader: async () => fetchData(),
component: App, component: App,
}) })
function App() { function App() {
let data = Route.useLoaderData()
const items = data.cards.map((e, i) => (
<Card title={e.title} content={e.content} key={i} />
))
return ( return (
<div className="text-center"> <div className="bg-[url(/public/bg.jpeg)] bg-cover bg-no-repeat bg-center min-h-screen">
<header className="min-h-screen flex flex-col items-center justify-center bg-[#282c34] text-white text-[calc(10px+2vmin)]"> <div className="flex flex-col gap-5 pt-10">
<img <h1 className="text-5xl text-white text-center mb-10">
src={logo} {data.title}
className="h-[40vmin] pointer-events-none animate-[spin_20s_linear_infinite]" </h1>
alt="logo" {items}
/> <p className="text-[#9e9b97] text-center mb-5">Stay Foss :)</p>
<p> </div>
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> </div>
) )
} }

View 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>
)
}

View 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>
)
}

View 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
View 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>
}

View file

@ -2,13 +2,15 @@ import { defineConfig } from 'vite'
import viteReact from '@vitejs/plugin-react' import viteReact from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite' import tailwindcss from '@tailwindcss/vite'
import { TanStackRouterVite } from '@tanstack/router-plugin/vite' import tanstackRouter from '@tanstack/router-plugin/vite'
import { resolve } from 'node:path' import { resolve } from 'node:path'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
TanStackRouterVite({ autoCodeSplitting: true }), tanstackRouter({autoCodeSplitting: true}),
viteReact(), viteReact(),
tailwindcss(), tailwindcss(),
], ],