basic navbar layout

This commit is contained in:
2026-05-29 21:14:57 +02:00
parent 4cbe1f404e
commit ce9bc0314c
9 changed files with 235 additions and 118 deletions
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BiomeSettings">
<option name="applySafeFixesOnSave" value="true" />
<option name="enableLspFormat" value="true" />
<option name="formatOnSave" value="true" />
<option name="sortImportOnSave" value="true" />
</component>
</project>
+35
View File
@@ -14,6 +14,7 @@
"@tanstack/react-router-ssr-query": "latest", "@tanstack/react-router-ssr-query": "latest",
"@tanstack/react-start": "latest", "@tanstack/react-start": "latest",
"@tanstack/router-plugin": "^1.132.0", "@tanstack/router-plugin": "^1.132.0",
"@unpic/react": "^1.0.2",
"lichess-pgn-viewer": "^2.4.5", "lichess-pgn-viewer": "^2.4.5",
"lucide-react": "^0.545.0", "lucide-react": "^0.545.0",
"nitro": "npm:nitro-nightly@latest", "nitro": "npm:nitro-nightly@latest",
@@ -3438,6 +3439,34 @@
"@types/react": "^19.2.0" "@types/react": "^19.2.0"
} }
}, },
"node_modules/@unpic/core": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@unpic/core/-/core-1.0.3.tgz",
"integrity": "sha512-aum9YNVUGso7MjGLD0Rp/08kywCGLqZ03/q6VQBFFakDBOXWEc8D4kPGcZ8v5wEnGRex3lE+++bOuucBp3KJ/w==",
"license": "MIT",
"dependencies": {
"unpic": "^4.2.2"
}
},
"node_modules/@unpic/react": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@unpic/react/-/react-1.0.2.tgz",
"integrity": "sha512-5RmRfELwTF8w+4zjtQGqjpvX+RU2VLvis3xDCS1O2uWk0PZN2cvatL+3/KAR3mshAuRrkFGTX1XwyAezSXaoCA==",
"license": "MIT",
"dependencies": {
"@unpic/core": "^1.0.3"
},
"peerDependencies": {
"next": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"next": {
"optional": true
}
}
},
"node_modules/@vitejs/plugin-react": { "node_modules/@vitejs/plugin-react": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz",
@@ -5682,6 +5711,12 @@
"pathe": "^2.0.3" "pathe": "^2.0.3"
} }
}, },
"node_modules/unpic": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/unpic/-/unpic-4.2.2.tgz",
"integrity": "sha512-z6T2ScMgRV2y2H8MwwhY5xHZWXhUx/YxtOCGJwfURSl7ypVy4HpLIMWoIZKnnxQa/RKzM0kg8hUh0paIrpLfvw==",
"license": "MIT"
},
"node_modules/unplugin": { "node_modules/unplugin": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz",
+1
View File
@@ -23,6 +23,7 @@
"@tanstack/react-router-ssr-query": "latest", "@tanstack/react-router-ssr-query": "latest",
"@tanstack/react-start": "latest", "@tanstack/react-start": "latest",
"@tanstack/router-plugin": "^1.132.0", "@tanstack/router-plugin": "^1.132.0",
"@unpic/react": "^1.0.2",
"lichess-pgn-viewer": "^2.4.5", "lichess-pgn-viewer": "^2.4.5",
"lucide-react": "^0.545.0", "lucide-react": "^0.545.0",
"nitro": "npm:nitro-nightly@latest", "nitro": "npm:nitro-nightly@latest",
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="64.000000pt" height="64.000000pt" viewBox="0 0 64.000000 64.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
fill="#ffffff" stroke="white">
<path d="M460 605 c0 -8 -7 -15 -15 -15 -10 0 -15 -10 -15 -30 0 -20 5 -30 15
-30 20 0 19 -16 -1 -24 -12 -4 -15 -14 -11 -34 3 -15 1 -34 -4 -44 -16 -29 0
-48 41 -48 42 0 44 -2 55 -80 4 -25 9 -53 11 -62 5 -16 -2 -18 -46 -18 -40 0
-51 3 -47 13 12 32 19 130 9 123 -6 -3 -14 -32 -18 -62 -4 -36 -13 -62 -25
-72 -11 -9 -19 -22 -19 -28 0 -7 -7 -14 -15 -18 -8 -3 -15 -17 -15 -31 0 -25
0 -25 90 -25 53 0 90 4 90 10 0 6 -33 10 -80 10 -47 0 -80 4 -80 10 0 6 43 10
110 10 67 0 110 -4 110 -10 0 -5 -9 -10 -20 -10 -11 0 -20 -4 -20 -10 0 -5 14
-10 30 -10 25 0 30 4 30 25 0 14 -7 28 -15 31 -8 4 -15 12 -15 20 0 7 -7 17
-16 22 -11 6 -21 35 -29 83 -11 64 -11 76 2 91 9 10 12 22 6 30 -4 7 -8 29 -8
48 0 32 -3 35 -32 38 -25 2 -33 8 -33 23 0 10 -7 19 -15 19 -8 0 -15 5 -15 10
0 6 7 10 15 10 8 0 15 7 15 15 0 8 5 15 10 15 6 0 10 -7 10 -15 0 -8 7 -15 15
-15 8 0 15 -4 15 -10 0 -5 -7 -10 -15 -10 -8 0 -15 -4 -15 -10 0 -5 11 -10 25
-10 21 0 25 5 25 30 0 20 -5 30 -15 30 -8 0 -15 7 -15 15 0 10 -10 15 -30 15
-20 0 -30 -5 -30 -15z m66 -131 c-3 -9 -6 -20 -6 -25 0 -5 -13 -9 -30 -9 -16
0 -30 4 -30 9 0 5 -3 16 -6 25 -5 13 2 16 36 16 34 0 41 -3 36 -16z m14 -64
c0 -5 -22 -10 -50 -10 -27 0 -50 5 -50 10 0 6 23 10 50 10 28 0 50 -4 50 -10z
m30 -220 c0 -6 -33 -10 -80 -10 -47 0 -80 4 -80 10 0 6 33 10 80 10 47 0 80
-4 80 -10z"/>
<path d="M118 519 c-56 -29 -78 -80 -78 -179 0 -47 4 -80 10 -80 6 0 10 34 10
83 0 64 4 89 20 115 11 17 24 32 30 32 14 0 13 -5 -10 -42 -17 -28 -20 -51
-20 -160 0 -79 4 -128 10 -128 6 0 10 49 10 126 0 135 9 169 41 159 22 -7 23
-2 8 27 -16 29 -2 34 20 7 22 -25 28 -11 11 22 -9 16 -7 19 14 19 29 0 76 -19
76 -32 0 -10 -3 -10 -34 2 -16 6 -27 6 -31 0 -4 -6 -2 -10 3 -10 5 0 30 -16
56 -35 48 -37 64 -78 26 -68 -22 6 -28 -12 -7 -20 24 -10 -21 -7 -47 3 -34 13
-55 4 -62 -27 -6 -21 2 -33 50 -77 45 -42 56 -58 56 -84 0 -27 -4 -32 -24 -32
-17 0 -27 9 -36 30 -13 32 -37 56 -46 47 -4 -3 3 -18 15 -33 11 -15 21 -31 21
-35 0 -5 -31 -9 -68 -9 -70 0 -92 -10 -92 -41 0 -9 -7 -19 -15 -23 -17 -6 -21
-56 -5 -56 6 0 10 9 10 20 0 19 7 20 150 20 143 0 150 -1 150 -20 0 -11 5 -20
10 -20 16 0 12 50 -5 56 -8 4 -15 14 -15 24 0 10 -7 23 -15 30 -8 7 -15 28
-15 48 0 30 -8 43 -57 87 -41 38 -54 57 -49 70 4 11 12 15 24 10 46 -18 85
-18 98 0 22 30 17 71 -11 94 -20 15 -24 25 -20 44 5 20 1 27 -28 41 -46 21
-93 20 -139 -5z m190 -421 c3 -16 -8 -18 -117 -18 -94 0 -121 3 -121 13 0 25
14 28 124 25 96 -3 111 -5 114 -20z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="64.000000pt" height="64.000000pt" viewBox="0 0 64.000000 64.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
fill="#6f884d" stroke="black">
<path d="M460 605 c0 -8 -7 -15 -15 -15 -10 0 -15 -10 -15 -30 0 -20 5 -30 15
-30 20 0 19 -16 -1 -24 -12 -4 -15 -14 -11 -34 3 -15 1 -34 -4 -44 -16 -29 0
-48 41 -48 42 0 44 -2 55 -80 4 -25 9 -53 11 -62 5 -16 -2 -18 -46 -18 -40 0
-51 3 -47 13 12 32 19 130 9 123 -6 -3 -14 -32 -18 -62 -4 -36 -13 -62 -25
-72 -11 -9 -19 -22 -19 -28 0 -7 -7 -14 -15 -18 -8 -3 -15 -17 -15 -31 0 -25
0 -25 90 -25 53 0 90 4 90 10 0 6 -33 10 -80 10 -47 0 -80 4 -80 10 0 6 43 10
110 10 67 0 110 -4 110 -10 0 -5 -9 -10 -20 -10 -11 0 -20 -4 -20 -10 0 -5 14
-10 30 -10 25 0 30 4 30 25 0 14 -7 28 -15 31 -8 4 -15 12 -15 20 0 7 -7 17
-16 22 -11 6 -21 35 -29 83 -11 64 -11 76 2 91 9 10 12 22 6 30 -4 7 -8 29 -8
48 0 32 -3 35 -32 38 -25 2 -33 8 -33 23 0 10 -7 19 -15 19 -8 0 -15 5 -15 10
0 6 7 10 15 10 8 0 15 7 15 15 0 8 5 15 10 15 6 0 10 -7 10 -15 0 -8 7 -15 15
-15 8 0 15 -4 15 -10 0 -5 -7 -10 -15 -10 -8 0 -15 -4 -15 -10 0 -5 11 -10 25
-10 21 0 25 5 25 30 0 20 -5 30 -15 30 -8 0 -15 7 -15 15 0 10 -10 15 -30 15
-20 0 -30 -5 -30 -15z m66 -131 c-3 -9 -6 -20 -6 -25 0 -5 -13 -9 -30 -9 -16
0 -30 4 -30 9 0 5 -3 16 -6 25 -5 13 2 16 36 16 34 0 41 -3 36 -16z m14 -64
c0 -5 -22 -10 -50 -10 -27 0 -50 5 -50 10 0 6 23 10 50 10 28 0 50 -4 50 -10z
m30 -220 c0 -6 -33 -10 -80 -10 -47 0 -80 4 -80 10 0 6 33 10 80 10 47 0 80
-4 80 -10z"/>
<path d="M118 519 c-56 -29 -78 -80 -78 -179 0 -47 4 -80 10 -80 6 0 10 34 10
83 0 64 4 89 20 115 11 17 24 32 30 32 14 0 13 -5 -10 -42 -17 -28 -20 -51
-20 -160 0 -79 4 -128 10 -128 6 0 10 49 10 126 0 135 9 169 41 159 22 -7 23
-2 8 27 -16 29 -2 34 20 7 22 -25 28 -11 11 22 -9 16 -7 19 14 19 29 0 76 -19
76 -32 0 -10 -3 -10 -34 2 -16 6 -27 6 -31 0 -4 -6 -2 -10 3 -10 5 0 30 -16
56 -35 48 -37 64 -78 26 -68 -22 6 -28 -12 -7 -20 24 -10 -21 -7 -47 3 -34 13
-55 4 -62 -27 -6 -21 2 -33 50 -77 45 -42 56 -58 56 -84 0 -27 -4 -32 -24 -32
-17 0 -27 9 -36 30 -13 32 -37 56 -46 47 -4 -3 3 -18 15 -33 11 -15 21 -31 21
-35 0 -5 -31 -9 -68 -9 -70 0 -92 -10 -92 -41 0 -9 -7 -19 -15 -23 -17 -6 -21
-56 -5 -56 6 0 10 9 10 20 0 19 7 20 150 20 143 0 150 -1 150 -20 0 -11 5 -20
10 -20 16 0 12 50 -5 56 -8 4 -15 14 -15 24 0 10 -7 23 -15 30 -8 7 -15 28
-15 48 0 30 -8 43 -57 87 -41 38 -54 57 -49 70 4 11 12 15 24 10 46 -18 85
-18 98 0 22 30 17 71 -11 94 -20 15 -24 25 -20 44 5 20 1 27 -28 41 -46 21
-93 20 -139 -5z m190 -421 c3 -16 -8 -18 -117 -18 -94 0 -121 3 -121 13 0 25
14 28 124 25 96 -3 111 -5 114 -20z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+36 -53
View File
@@ -1,68 +1,51 @@
import { Link } from '@tanstack/react-router' import { Link } from "@tanstack/react-router";
import { Image } from "@unpic/react";
import logo from "@/assets/images/logo.svg?url";
export default function Header() { export default function Header() {
return ( return (
<header className="sticky top-0 z-50 border-b border-[var(--line)] bg-[var(--header-bg)] px-4 backdrop-blur-lg"> <header>
<nav className="page-wrap flex flex-wrap items-center gap-x-3 gap-y-2 py-3 sm:py-4"> <nav className="w-full max-w-screen-2xl place-self-center p-8 text-neutral">
<h2 className="m-0 flex-shrink-0 text-base font-semibold tracking-tight"> <div className="container mx-auto flex items-center justify-between">
<Link <div className="flex items-center">
to="/" <Link to="/" className="flex flex-row items-center justify-center">
className="inline-flex items-center gap-2 rounded-full border border-[var(--chip-line)] bg-[var(--chip-bg)] px-3 py-1.5 text-sm text-[var(--sea-ink)] no-underline shadow-[0_8px_24px_rgba(30,90,72,0.08)] sm:px-4 sm:py-2" <Image
> src={logo}
<span className="h-2 w-2 rounded-full bg-[linear-gradient(90deg,#56c6be,#7ed3bf)]" /> alt="ChessScribe Logo"
TanStack Start width={50}
height={50}
className="mr-4"
/>
<span className="hidden text-2xl font-extrabold text-primary sm:block">
ChessScribe
</span>
</Link> </Link>
</h2> </div>
<div className="order-3 flex w-full flex-wrap items-center gap-x-4 gap-y-1 pb-1 text-sm font-semibold sm:order-none sm:w-auto sm:flex-nowrap sm:pb-0"> <div>
<Link <ul className="flex flex-1 items-center gap-14 font-semibold">
to="/" <li>
className="nav-link"
activeProps={{ className: 'nav-link is-active' }}
>
Home
</Link>
<Link <Link
to="/chessboard" to="/chessboard"
className="nav-link" className="decoration-2 underline-offset-8 hover:text-primary hover:underline"
activeProps={{ className: 'nav-link is-active' }}
> >
Chessboard Chessboard
</Link> </Link>
</li>
<li>
<Link
to="/contact"
className="decoration-2 underline-offset-8 hover:text-primary hover:underline"
>
Contact
</Link>
</li>
</ul>
</div> </div>
<div className="ml-auto flex items-center gap-1.5 sm:gap-2">
<a
href="https://x.com/tan_stack"
target="_blank"
rel="noreferrer"
className="hidden rounded-xl p-2 text-[var(--sea-ink-soft)] transition hover:bg-[var(--link-bg-hover)] hover:text-[var(--sea-ink)] sm:block"
>
<span className="sr-only">Follow TanStack on X</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="24" height="24">
<path
fill="currentColor"
d="M12.6 1h2.2L10 6.48 15.64 15h-4.41L7.78 9.82 3.23 15H1l5.14-5.84L.72 1h4.52l3.12 4.73L12.6 1zm-.77 12.67h1.22L4.57 2.26H3.26l8.57 11.41z"
/>
</svg>
</a>
<a
href="https://github.com/TanStack"
target="_blank"
rel="noreferrer"
className="hidden rounded-xl p-2 text-[var(--sea-ink-soft)] transition hover:bg-[var(--link-bg-hover)] hover:text-[var(--sea-ink)] sm:block"
>
<span className="sr-only">Go to TanStack GitHub</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="24" height="24">
<path
fill="currentColor"
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
/>
</svg>
</a>
</div> </div>
</nav> </nav>
</header> </header>
) );
} }
+18 -17
View File
@@ -1,38 +1,39 @@
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router' import { TanStackDevtools } from "@tanstack/react-devtools";
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools' import { createRootRoute, HeadContent, Scripts } from "@tanstack/react-router";
import { TanStackDevtools } from '@tanstack/react-devtools' import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools";
import Footer from '../components/Footer' import type { ReactNode } from "react";
import Header from '../components/Header' import Footer from "../components/Footer";
import Header from "../components/Header";
import appCss from '../styles.css?url' import appCss from "../styles.css?url";
const THEME_INIT_SCRIPT = `(function(){try{var stored=window.localStorage.getItem('theme');var mode=(stored==='light'||stored==='dark'||stored==='auto')?stored:'auto';var prefersDark=window.matchMedia('(prefers-color-scheme: dark)').matches;var resolved=mode==='auto'?(prefersDark?'dark':'light'):mode;var root=document.documentElement;root.classList.remove('light','dark');root.classList.add(resolved);if(mode==='auto'){root.removeAttribute('data-theme')}else{root.setAttribute('data-theme',mode)}root.style.colorScheme=resolved;}catch(e){}})();` const THEME_INIT_SCRIPT = `(function(){try{var stored=window.localStorage.getItem('theme');var mode=(stored==='light'||stored==='dark'||stored==='auto')?stored:'auto';var prefersDark=window.matchMedia('(prefers-color-scheme: dark)').matches;var resolved=mode==='auto'?(prefersDark?'dark':'light'):mode;var root=document.documentElement;root.classList.remove('light','dark');root.classList.add(resolved);if(mode==='auto'){root.removeAttribute('data-theme')}else{root.setAttribute('data-theme',mode)}root.style.colorScheme=resolved;}catch(e){}})();`;
export const Route = createRootRoute({ export const Route = createRootRoute({
head: () => ({ head: () => ({
meta: [ meta: [
{ {
charSet: 'utf-8', charSet: "utf-8",
}, },
{ {
name: 'viewport', name: "viewport",
content: 'width=device-width, initial-scale=1', content: "width=device-width, initial-scale=1",
}, },
{ {
title: 'TanStack Start Starter', title: "TanStack Start Starter",
}, },
], ],
links: [ links: [
{ {
rel: 'stylesheet', rel: "stylesheet",
href: appCss, href: appCss,
}, },
], ],
}), }),
shellComponent: RootDocument, shellComponent: RootDocument,
}) });
function RootDocument({ children }: { children: React.ReactNode }) { function RootDocument({ children }: { children: ReactNode }) {
return ( return (
<html lang="en" suppressHydrationWarning> <html lang="en" suppressHydrationWarning>
<head> <head>
@@ -45,11 +46,11 @@ function RootDocument({ children }: { children: React.ReactNode }) {
<Footer /> <Footer />
<TanStackDevtools <TanStackDevtools
config={{ config={{
position: 'bottom-right', position: "bottom-right",
}} }}
plugins={[ plugins={[
{ {
name: 'Tanstack Router', name: "Tanstack Router",
render: <TanStackRouterDevtoolsPanel />, render: <TanStackRouterDevtoolsPanel />,
}, },
]} ]}
@@ -57,5 +58,5 @@ function RootDocument({ children }: { children: React.ReactNode }) {
<Scripts /> <Scripts />
</body> </body>
</html> </html>
) );
} }