feat: rewrite all to use shadcn-svelte

This commit is contained in:
Bart van der Braak 2024-01-15 02:48:13 +01:00
parent 0df260c5a5
commit b13ece80d5
162 changed files with 3268 additions and 2815 deletions

View file

@ -1,3 +1,4 @@
/** @type { import("eslint").Linter.FlatConfig } */
module.exports = {
root: true,
extends: [

2
.gitignore vendored
View file

@ -8,5 +8,3 @@ node_modules
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.unlighthouse
.vercel

1
.npmrc
View file

@ -1,2 +1 @@
engine-strict=true
resolution-mode=highest

View file

@ -1,12 +1,3 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json

View file

@ -3,6 +3,13 @@
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [
{
"files": "*.svelte",
"options": {
"parser": "svelte"
}
}
]
}

13
components.json Normal file
View file

@ -0,0 +1,13 @@
{
"$schema": "https://shadcn-svelte.com/schema.json",
"style": "default",
"tailwind": {
"config": "tailwind.config.js",
"css": "src/app.pcss",
"baseColor": "stone"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils"
}
}

View file

@ -1,7 +0,0 @@
module.exports = {
'**/*.{js,ts,cjs,svelte,tsx}': [
() => 'tsc -p tsconfig.json --noEmit',
'eslint --fix',
'prettier --write'
]
};

View file

@ -1,6 +1,7 @@
{
"name": "hellob.art",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "vite dev",
@ -13,43 +14,38 @@
"prepare": "npx husky install && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@skeletonlabs/skeleton": "^2.6.0",
"@skeletonlabs/tw-plugin": "^0.3.0",
"@sveltejs/adapter-vercel": "^4.0.2",
"@sveltejs/enhanced-img": "^0.1.6",
"@sveltejs/kit": "^2.0.1",
"@sveltejs/adapter-vercel": "^4.0.4",
"@sveltejs/enhanced-img": "^0.1.8",
"@sveltejs/kit": "^2.3.2",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@types/node": "^20.10.5",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"autoprefixer": "^10.4.16",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"lint-staged": "^15.2.0",
"postcss": "^8.4.32",
"postcss": "^8.4.33",
"postcss-load-config": "^5.0.2",
"prettier": "^3.1.1",
"prettier": "^3.2.2",
"prettier-plugin-svelte": "^3.1.2",
"prettier-plugin-tailwindcss": "^0.5.11",
"svelte": "^4.2.8",
"svelte-check": "^3.6.2",
"tailwindcss": "^3.3.6",
"svelte-check": "^3.6.3",
"tailwindcss": "^3.4.1",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"vite": "^5.0.10",
"vite-plugin-tailwind-purgecss": "^0.1.4"
"vite": "^5.0.11"
},
"type": "module",
"dependencies": {
"@theatre/core": "^0.7.0",
"@theatre/studio": "^0.7.0",
"@threlte/core": "7.0.10",
"@threlte/extras": "8.0.8",
"@threlte/theatre": "^2.1.5",
"@types/three": "^0.159.0",
"@vercel/analytics": "^1.1.1",
"three": "^0.159.0",
"web-vitals": "^3.5.0"
"bits-ui": "^0.11.8",
"clsx": "^2.1.0",
"lucide-svelte": "^0.298.0",
"mode-watcher": "^0.1.2",
"radix-icons-svelte": "^1.2.1",
"svelte-wrap-balancer": "^0.0.4",
"tailwind-merge": "^2.2.0",
"tailwind-variants": "^0.1.20"
},
"lint-staged": {
"*.{js,ts,svelte,css,scss,postcss,md,json}": [

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,13 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [tailwindcss(), autoprefixer]
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer
]
};
module.exports = config;

1
src/app.d.ts vendored
View file

@ -5,6 +5,7 @@ declare global {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}

View file

@ -4,31 +4,14 @@
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
<meta name="viewport" content="width=device-width" />
<link rel="apple-touch-icon" sizes="180x180" href="%sveltekit.assets%/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="%sveltekit.assets%/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="%sveltekit.assets%/favicon-16x16.png" />
<link rel="manifest" href="%sveltekit.assets%/site.webmanifest" />
<link rel="mask-icon" href="%sveltekit.assets%/safari-pinned-tab.svg" color="#000000" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" />
<title>hellob.art - home of bart van der braak</title>
<meta property="twitter:image" content="https://hellob.art/og.png" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:title" content="hellob.art - home of bart van der braak" />
<meta
property="twitter:description"
content="Personal website of Bart van der Braak showcasing milestones, tools and ideas."
/>
<meta property="og:image" content="https://hellob.art/og.png" />
<meta property="og:title" content="hellob.art - home of bart van der braak" />
<meta
property="og:description"
content="Personal website of Bart van der Braak showcasing milestones, tools and ideas."
/>
<meta property="og:url" content="https://hellob.art/" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" data-theme="theme">
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
<body
data-sveltekit-preload-data="hover"
class="min-h-screen bg-background font-sans antialiased"
>
<div style="display: contents" class="relative flex min-h-screen flex-col">
%sveltekit.body%
</div>
</body>
</html>

78
src/app.pcss Normal file
View file

@ -0,0 +1,78 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--primary: 24 9.8% 10%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
}
.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--primary: 60 9.1% 97.8%;
--primary-foreground: 24 9.8% 10%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 24 5.7% 82.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

View file

@ -1,26 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;
html,
body {
@apply h-full overflow-hidden;
@apply bg-white;
}
.dark .logo-text-gradient-dark {
@apply from-logo-blue-start-dark to-logo-blue-stop-dark;
}
.logo-text-gradient-light {
@apply from-logo-blue-start-light to-logo-blue-stop-light;
}
.logo-text-gradient {
@apply bg-clip-text text-transparent box-decoration-clone;
/* Direction */
@apply bg-gradient-to-br;
/* Color Stops */
@apply logo-text-gradient-light logo-text-gradient-dark;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,17 +0,0 @@
<svg width="177" height="28" viewBox="0 0 177 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="116.25" height="27" fill="white" stroke="black"/>
<rect x="117.25" width="59.5" height="28" fill="black"/>
<rect x="117.25" y="1.25" width="58.5" height="25.5" stroke="white" stroke-width="0.5"/>
<path d="M6.174 21C6.118 21 6.09 20.965 6.09 20.895L6.111 6.46798C6.111 6.41198 6.146 6.38398 6.216 6.38398H8.547C8.617 6.38398 8.652 6.41198 8.652 6.46798L8.631 12.18H11.781V6.46798C11.781 6.41198 11.809 6.38398 11.865 6.38398H14.196C14.266 6.38398 14.301 6.41198 14.301 6.46798L14.343 20.895C14.343 20.965 14.308 21 14.238 21H11.886C11.816 21 11.781 20.965 11.781 20.895V14.721H8.631V20.895C8.631 20.965 8.603 21 8.547 21H6.174Z" fill="black"/>
<path d="M26.6408 21C26.5848 21 26.5568 20.965 26.5568 20.895L26.5778 6.46798C26.5778 6.41198 26.6058 6.38398 26.6618 6.38398H33.4028C33.4588 6.38398 33.4868 6.41898 33.4868 6.48898V8.84098C33.4868 8.89698 33.4588 8.92498 33.4028 8.92498H29.0978V12.201H33.4028C33.4588 12.201 33.4868 12.229 33.4868 12.285L33.5078 14.658C33.5078 14.714 33.4798 14.742 33.4238 14.742H29.0978V18.417H33.4238C33.4798 18.417 33.5078 18.452 33.5078 18.522V20.916C33.5078 20.972 33.4798 21 33.4238 21H26.6408Z" fill="black"/>
<path d="M45.9592 21C45.9032 21 45.8752 20.965 45.8752 20.895L45.8962 6.48898C45.8962 6.41898 45.9312 6.38398 46.0012 6.38398H48.3322C48.4022 6.38398 48.4372 6.41898 48.4372 6.48898L48.4162 18.417H52.7422C52.8122 18.417 52.8472 18.452 52.8472 18.522V20.895C52.8472 20.965 52.8122 21 52.7422 21H45.9592Z" fill="black"/>
<path d="M64.8058 21C64.7498 21 64.7218 20.965 64.7218 20.895L64.7428 6.48898C64.7428 6.41898 64.7778 6.38398 64.8478 6.38398H67.1788C67.2488 6.38398 67.2838 6.41898 67.2838 6.48898L67.2628 18.417H71.5888C71.6588 18.417 71.6938 18.452 71.6938 18.522V20.895C71.6938 20.965 71.6588 21 71.5888 21H64.8058Z" fill="black"/>
<path d="M87.1664 21.21C86.4104 21.21 85.7174 21.021 85.0874 20.643C84.4714 20.251 83.9744 19.74 83.5964 19.11C83.2184 18.466 83.0294 17.759 83.0294 16.989L83.0504 10.332C83.0504 9.56198 83.2324 8.86198 83.5964 8.23198C83.9744 7.60198 84.4784 7.09798 85.1084 6.71998C85.7384 6.34198 86.4244 6.15298 87.1664 6.15298C87.9224 6.15298 88.6084 6.34198 89.2244 6.71998C89.8404 7.09798 90.3304 7.60198 90.6944 8.23198C91.0724 8.86198 91.2614 9.56198 91.2614 10.332L91.2824 16.989C91.2824 17.759 91.0934 18.466 90.7154 19.11C90.3514 19.74 89.8544 20.251 89.2244 20.643C88.6084 21.021 87.9224 21.21 87.1664 21.21ZM87.1664 18.669C87.5864 18.669 87.9504 18.501 88.2584 18.165C88.5804 17.815 88.7414 17.423 88.7414 16.989L88.7204 10.332C88.7204 9.86998 88.5734 9.47798 88.2794 9.15598C87.9854 8.83398 87.6144 8.67298 87.1664 8.67298C86.7324 8.67298 86.3614 8.83398 86.0534 9.15598C85.7454 9.46398 85.5914 9.85598 85.5914 10.332V16.989C85.5914 17.451 85.7454 17.85 86.0534 18.186C86.3614 18.508 86.7324 18.669 87.1664 18.669Z" fill="black"/>
<path d="M103.463 21C103.407 21 103.379 20.965 103.379 20.895L103.421 6.46798C103.421 6.41198 103.449 6.38398 103.505 6.38398H107.537C108.335 6.38398 109.049 6.57998 109.679 6.97198C110.309 7.34998 110.806 7.85398 111.17 8.48398C111.534 9.11398 111.716 9.79998 111.716 10.542C111.716 11.144 111.576 11.704 111.296 12.222C111.03 12.74 110.708 13.16 110.33 13.482C110.736 13.888 111.051 14.357 111.275 14.889C111.499 15.421 111.611 15.981 111.611 16.569C111.611 17.381 111.415 18.123 111.023 18.795C110.631 19.467 110.099 20.006 109.427 20.412C108.769 20.804 108.034 21 107.222 21H103.463ZM105.941 12.18H107.537C108.027 12.18 108.419 12.012 108.713 11.676C109.021 11.326 109.175 10.948 109.175 10.542C109.175 10.094 109.014 9.70898 108.692 9.38698C108.37 9.05098 107.985 8.88298 107.537 8.88298H105.941V12.18ZM105.92 18.438H107.222C107.726 18.438 108.16 18.256 108.524 17.892C108.888 17.514 109.07 17.073 109.07 16.569C109.07 16.065 108.888 15.631 108.524 15.267C108.16 14.903 107.726 14.721 107.222 14.721H105.941L105.92 18.438Z" fill="black"/>
<path d="M122.626 20.895L125.23 6.46803C125.244 6.41203 125.279 6.38403 125.335 6.38403H128.38C128.436 6.38403 128.471 6.41203 128.485 6.46803L130.984 20.895C130.998 20.965 130.97 21 130.9 21H128.569C128.513 21 128.478 20.965 128.464 20.895L128.233 19.362H125.377L125.146 20.895C125.132 20.965 125.097 21 125.041 21H122.71C122.654 21 122.626 20.965 122.626 20.895ZM125.797 17.115H127.813L126.952 11.214L126.826 10.437L126.742 11.214L125.797 17.115Z" fill="white"/>
<path d="M142.886 21C142.83 21 142.802 20.965 142.802 20.895L142.844 6.46803C142.844 6.41203 142.872 6.38403 142.928 6.38403H147.17C147.926 6.38403 148.619 6.57303 149.249 6.95103C149.893 7.31503 150.404 7.81203 150.782 8.44203C151.16 9.05803 151.349 9.75803 151.349 10.542C151.349 11.06 151.272 11.529 151.118 11.949C150.964 12.355 150.782 12.705 150.572 12.999C150.362 13.279 150.173 13.489 150.005 13.629C150.761 14.469 151.139 15.456 151.139 16.59L151.16 20.895C151.16 20.965 151.125 21 151.055 21H148.682C148.626 21 148.598 20.979 148.598 20.937V16.59C148.598 16.086 148.416 15.652 148.052 15.288C147.702 14.91 147.268 14.721 146.75 14.721H145.364L145.343 20.895C145.343 20.965 145.315 21 145.259 21H142.886ZM145.364 12.201H147.17C147.604 12.201 147.989 12.04 148.325 11.718C148.661 11.396 148.829 11.004 148.829 10.542C148.829 10.094 148.661 9.70903 148.325 9.38703C148.003 9.06503 147.618 8.90403 147.17 8.90403H145.364V12.201Z" fill="white"/>
<path d="M165.123 21C165.067 21 165.039 20.965 165.039 20.895V8.92503H162.309C162.239 8.92503 162.204 8.89003 162.204 8.82003L162.225 6.46803C162.225 6.41203 162.253 6.38403 162.309 6.38403H170.289C170.359 6.38403 170.394 6.41203 170.394 6.46803V8.82003C170.394 8.89003 170.366 8.92503 170.31 8.92503H167.559L167.58 20.895C167.58 20.965 167.552 21 167.496 21H165.123Z" fill="white"/>
<circle cx="117" cy="21" r="2.25" fill="black"/>
<circle cx="117" cy="21" r="2.25" stroke="black" stroke-width="0.5"/>
<circle cx="117" cy="21" r="2.25" stroke="white" stroke-width="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

View file

Before

Width:  |  Height:  |  Size: 677 KiB

After

Width:  |  Height:  |  Size: 677 KiB

BIN
src/lib/assets/root-me.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 23 KiB

View file

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 26.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg:svg
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 1000 1000"
xml:space="preserve"
sodipodi:docname="linuxfoundation.svg"
width="1000"
height="1000"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:svg="http://www.w3.org/2000/svg"><svg:defs
id="defs20" /><sodipodi:namedview
id="namedview20"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1"
inkscape:export-bgcolor="#ffffffff" />&#10;<svg:style
type="text/css"
id="style1">&#10; .st0{fill:#003778;}&#10; .st1{fill:#003764;}&#10; .st2{fill:#0094FF;}&#10;</svg:style>&#10;<svg:g
id="g20"
transform="matrix(0.84026685,0,0,0.84026685,79.866575,361.81812)">&#10; <svg:g
id="g3">&#10; <svg:path
class="st0"
d="m 384.2,1.2 h 57.7 V 7.1 H 416.5 V 74 h -6.9 V 7.2 h -25.4 z"
id="path1" />&#10; <svg:path
class="st0"
d="m 448.7,1.2 h 6.9 v 31.6 h 43.2 V 1.2 h 6.9 V 74 h -6.9 V 38.8 H 455.6 V 74 h -6.9 z"
id="path2" />&#10; <svg:path
class="st0"
d="m 520.5,1.2 h 50.3 V 7.1 H 527.5 V 33.4 H 568 v 5.9 H 527.4 V 68 h 43.8 v 6 h -50.8 z"
id="path3" />&#10; </svg:g>&#10; <svg:g
id="g13">&#10; <svg:path
class="st0"
d="m 384.2,254.6 h 46.2 v 5.9 h -39.2 v 26.3 H 426 v 5.9 h -34.9 v 34.7 h -6.9 z"
id="path4" />&#10; <svg:path
class="st0"
d="m 469.4,253.1 c 22.8,0 34.2,17.9 34.2,37.9 0,20 -11.4,37.9 -34.2,37.9 -22.9,0 -34.4,-17.9 -34.4,-37.9 0,-20 11.4,-37.9 34.4,-37.9 z m 0,69.9 c 19.2,0 27.3,-16.1 27.3,-32 0,-15.9 -8.2,-32 -27.3,-32 -19.3,0 -27.4,16.1 -27.4,32 0,15.9 8.1,32 27.4,32 z"
id="path5" />&#10; <svg:path
class="st0"
d="m 513.7,254.6 h 6.9 v 45.1 c 0,16.8 7.8,23.3 21.3,23.3 13.6,0 21.4,-6.5 21.4,-23.3 v -45.1 h 6.9 v 46.6 c 0,15 -8.1,27.7 -28.3,27.7 -20.1,0 -28.2,-12.7 -28.2,-27.7 z"
id="path6" />&#10; <svg:path
class="st0"
d="m 584.2,254.6 h 7.7 l 42.4,61.6 h 0.2 v -61.6 h 6.9 v 72.8 h -7.7 l -42.4,-61.6 h -0.2 v 61.6 h -6.9 z"
id="path7" />&#10; <svg:path
class="st0"
d="m 656.1,254.6 h 25.2 c 22,0.5 33.4,12.3 33.4,36.4 0,24.1 -11.4,35.9 -33.4,36.4 h -25.2 z m 6.9,66.9 h 14.8 c 20.9,0 30,-8.7 30,-30.5 0,-21.8 -9.1,-30.5 -30,-30.5 H 663 Z"
id="path8" />&#10; <svg:path
class="st0"
d="m 747.2,254.6 h 7.7 l 28.5,72.8 H 776 l -8.9,-22.6 H 734 l -8.8,22.6 h -7.4 z m -11,44.3 h 28.6 l -14.1,-37.3 z"
id="path9" />&#10; <svg:path
class="st0"
d="M 775.3,254.6 H 833 v 5.9 h -25.4 v 66.9 h -6.9 v -66.9 h -25.4 z"
id="path10" />&#10; <svg:path
class="st0"
d="m 840.4,254.6 h 6.9 v 72.8 h -6.9 z"
id="path11" />&#10; <svg:path
class="st0"
d="m 893,253.1 c 22.8,0 34.2,17.9 34.2,37.9 0,20 -11.4,37.9 -34.2,37.9 -22.9,0 -34.4,-17.9 -34.4,-37.9 0,-20 11.4,-37.9 34.4,-37.9 z m 0,69.9 c 19.2,0 27.3,-16.1 27.3,-32 0,-15.9 -8.2,-32 -27.3,-32 -19.3,0 -27.4,16.1 -27.4,32 0,15.9 8.1,32 27.4,32 z"
id="path12" />&#10; <svg:path
class="st1"
d="m 937.9,254.6 h 7.7 l 42.4,61.6 h 0.2 v -61.6 h 6.9 v 72.8 h -7.7 L 945,265.8 h -0.2 v 61.6 h -6.9 z"
id="path13" />&#10; </svg:g>&#10; <svg:g
id="g18">&#10; <svg:path
class="st0"
d="m 384.2,95.7 h 40.1 v 96.8 h 57.6 v 33.4 h -97.8 z"
id="path14" />&#10; <svg:path
class="st0"
d="m 508.2,95.7 h 40.1 v 130.2 h -40.1 z"
id="path15" />&#10; <svg:path
class="st0"
d="m 578.2,95.7 h 41 l 37.9,69.7 h 0.4 V 95.7 h 37.9 v 130.2 h -39 l -39.9,-71.1 h -0.4 v 71.1 h -37.9 z"
id="path16" />&#10; <svg:path
class="st0"
d="m 843.7,175.6 c 0,36.3 -19.1,53.4 -59.3,53.4 -40.1,0 -59.5,-17.1 -59.5,-53.4 V 95.7 H 765 v 70.9 c 0,13.1 -0.2,29.9 19.5,29.9 19,0 19,-16.8 19,-29.9 V 95.7 h 40.1 v 79.9 z"
id="path17" />&#10; <svg:path
class="st0"
d="M 907.5,156.6 864.6,95.7 h 47.1 l 19.7,35.4 19.3,-35.4 h 44.5 l -41.7,61.3 46.5,68.9 h -48.3 l -22.2,-38.8 -23,38.8 h -46 z"
id="path18" />&#10; </svg:g>&#10; <svg:g
id="g19">&#10; <svg:polygon
class="st2"
points="0,327.4 196.5,327.4 196.5,261.9 65.6,261.9 65.6,131 0,131 "
id="polygon18" />&#10; <svg:polygon
class="st0"
points="327.3,327.4 327.3,0 0,0 0,98.2 65.5,98.2 65.5,65.8 261.9,65.8 261.9,261.9 229.2,261.9 229.2,327.4 "
id="polygon19" />&#10; </svg:g>&#10;</svg:g>&#10;<script /></svg:svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23"><path fill="#f3f3f3" d="M0 0h23v23H0z"/><path fill="#f35325" d="M1 1h10v10H1z"/><path fill="#81bc06" d="M12 1h10v10H12z"/><path fill="#05a6f0" d="M1 12h10v10H1z"/><path fill="#ffba08" d="M12 12h10v10H12z"/><script xmlns=""/></svg>

Before

Width:  |  Height:  |  Size: 290 B

View file

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 250 250"
aria-labelledby="triple-logo"
class="navbar__logo logo"
version="1.1"
id="svg3"
sodipodi:docname="triple.svg"
width="250"
height="250"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3" />
<sodipodi:namedview
id="namedview3"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1"
inkscape:export-bgcolor="#ffffffff" />
<title
id="triple-logo">Triple Logo</title>
<g
id="g3"
transform="matrix(0.84137882,0,0,0.84137882,27.26152,82.405441)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 73.7883,58.1616 4.0599,5.9824 c 0.2003,0.2931 0.5265,0.45 0.8548,0.45 0.2002,0 0.4005,-0.0557 0.578,-0.1775 0.4707,-0.318 0.5967,-0.958 0.2725,-1.4307 l -4.0823,-6.0155 -0.0488,0.0346 z M 103.215,37.3373 v 26.2245 c 0,0.5739 0.462,1.0322 1.032,1.0322 0.572,0 1.03,-0.4583 1.03,-1.0322 V 36.368 c 0,-0.1516 -0.032,-0.2957 -0.091,-0.4255 z M 231.031,62.5274 H 213.929 V 50.9909 h 12.69 c 0.57,0 1.031,-0.4583 1.031,-1.0322 0,-0.5636 -0.461,-1.0282 -1.031,-1.0282 h -12.69 V 37.394 h 17.102 c 0.568,0 1.03,-0.4583 1.03,-1.0322 0,-0.5678 -0.462,-1.0261 -1.03,-1.0261 h -18.135 c -0.569,0 -1.03,0.4583 -1.03,1.0261 v 27.1979 c 0,0.5698 0.461,1.0323 1.03,1.0323 h 18.135 c 0.568,0 1.03,-0.4625 1.03,-1.0323 0,-0.5677 -0.462,-1.0323 -1.03,-1.0323 z m -40.718,0.0021 H 175.308 V 36.3638 c 0,-0.5677 -0.463,-1.026 -1.034,-1.026 -0.57,0 -1.031,0.4583 -1.031,1.026 v 27.198 c 0,0.5698 0.461,1.0322 1.031,1.0322 h 16.039 c 0.572,0 1.032,-0.4624 1.032,-1.0322 0,-0.5678 -0.46,-1.0323 -1.032,-1.0323 z M 143.63,35.3378 h -12.753 c -0.571,0 -1.032,0.4624 -1.032,1.0302 v 27.1938 c 0,0.5739 0.461,1.0322 1.032,1.0322 0.568,0 1.031,-0.4583 1.031,-1.0322 V 53.0616 h 11.722 c 4.889,0 8.865,-3.9742 8.865,-8.8629 0,-4.8867 -3.976,-8.8609 -8.865,-8.8609 z m 0,15.6593 H 131.908 V 37.4002 h 11.722 c 3.753,0 6.8,3.0493 6.8,6.7985 0,3.7512 -3.047,6.7984 -6.8,6.7984 z"
fill="#0e0940"
class="logo__text"
id="path1" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 66.8258,63.0902 -2.2152,1.5679 h -10.43 v -2.3742 l 3.4209,-0.929 V 38.4904 L 54.1806,37.613 v -2.3742 h 15.4323 c 5.9354,0 9.0322,2.8903 9.0322,8.0516 0,5.6774 -6.9677,7.7419 -6.9677,7.7419 l 3.7366,5.9786 -3.9142,2.7708 -0.4317,0.3056 -4.2423,-8.2808 h -3.871 v 9.5484 l 3.871,0.929 z m 39.2162,-27.7534 -4.744,3.3572 v -0.183 l -4.0722,-0.7948 v -2.3794 h 7.2262 z M 67.2903,48.4517 H 63.1612 V 38.1291 h 3.6129 c 3.7492,0 6.1936,1.4121 6.1936,5.1613 0,3.7512 -1.9283,5.1613 -5.6774,5.1613 z m -55.742,-3.9536 v -9.1602 l 25.4091,-0.0011 v 9.1613 h -2.6013 l -1.2955,-6.1058 h -6.1729 v 22.9213 l 4.3045,0.9755 v 2.3639 h -6.7406 -7.1381 v -2.3639 l 4.2994,-0.9755 V 38.3923 h -6.2091 l -1.2748,6.1058 z"
fill="#0e0940"
class="logo__text"
id="path2" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 18.7432,97.1164 2.35918,3.2738 108.944,32.9615 l 0.326,0.0909 -33.8476,23.9525 -3.9226,2.7768 -8.5925,6.082 z M 118.998,31.1283 2.11144,0.333934 C 0.949115,-0.0686463 0.127437,0.600257 0.288469,1.82245 L 17.1576,99.7383 c 0.1611,1.2227 1.1252,1.6577 2.1471,0.9637 l 55.4405,-37.487 1.7095,-1.1562 26.7623,-18.0954 2.062,-1.3957 13.979,-9.4513 c 1.022,-0.6896 0.902,-1.5835 -0.26,-1.9881 z"
fill="#ff4f68"
id="path3" />
</g>
<metadata
id="metadata3">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>Triple Logo</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 4 KiB

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<style type="text/css">
.st0{fill:#555555;}
</style>
<polygon class="st0" points="292.5,52.8 434.7,134.9 434.7,348.1 265,446.1 265,10.6 235,25 235,446.1 65.3,348.2 65.3,106.3
36.4,120.1 35.3,365.6 250,489.4 464.7,365.5 464.7,117.5 292.5,18.1 "/>
</svg>

Before

Width:  |  Height:  |  Size: 605 B

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Laag_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 400 400" style="enable-background:new 0 0 400 400;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#0080C9;}
</style>
<rect class="st0" width="400" height="400"/>
<circle class="st0" cx="200" cy="200" r="200"/>
<g>
<g>
<polygon points="70.2,252.8 31.5,148.3 54.7,148.3 84.7,229.2 113.8,148.3 129.4,148.3 91.9,252.8 "/>
<path d="M142,148.3h21.8v64.1c0,11.6,2,19.3,5.9,23c3.9,3.8,9,5.7,15.3,5.7c6.2,0,11.1-1.9,14.7-5.6c3.7-3.7,5.5-10.9,5.5-21.6 v-65.7h18.9v64.2c0,12.1-1.5,20.8-4.6,26c-3,5.3-7.4,9.4-13.2,12.4c-5.7,3-13,4.5-21.8,4.5c-8.7,0-16.1-1.4-22.3-4.2 c-6.2-2.8-11.1-7-14.8-12.5c-3.6-5.5-5.4-14.4-5.4-26.4V148.3z"/>
<path class="st1" d="M253.9,227.3v2.8l0.8-0.7c-0.2-0.8-0.4-1.5-0.5-2.3L253.9,227.3z"/>
<path class="st1" d="M267.9,196.5c0-0.5,0.4-0.9,0.8-0.9c0.5,0,0.8,0.5,0.8,0.9c0,0.5-0.3,0.8-0.8,0.8 C268.2,197.3,267.9,196.9,267.9,196.5"/>
<path class="st1" d="M319.4,221.9c-1.3-3.5-4.6-5.8-9.2-5.4c-2.5-4.8-6.6-2.5-7.7-1.1c1.3,1.1,2.3,1.6,3.8,1.8v1 c-2.9-0.1-3.8-1.3-5.8-3.3c-0.8,6.9,7.3,9.4,9.8,3.7c3.8-0.1,6.1,1.6,6.9,4c0.8,2.4,0,5.1-1.3,6.4c-2.3,2.8-6,2.8-9.3,1 c-2.1-1-4.3-3.2-6.2-5.3c-2.9-3.2-4.5-4.6-6.7-5.8c-1.2-0.6-2.4-0.9-3.6-1c-0.7-0.1-1.4-0.2-2.1-0.2c-0.7,0-1.3,0.1-1.8,0.2 c-4.9,0.5-9.9,3-15.9,3.5h-3.2c-2,1.7-3.8,3.3-5.3,4.7l-3.8,3.3c0,0,0,0,0,0.1c-1.6,1.5-2.6,2.3-2.6,2.3c0.5,3.6,0.6,5.3,0.6,8.5 c0,2.7-0.1,3.9-0.1,5.1c-0.1,1.1-0.4,2.1-0.7,3c-0.2,0.8-0.9,1.5-2.1,1.6c-1,0.2-3.5-1.6-4.3-0.5c-0.7,0.9,0.1,3.1,0.8,3.7h6.8 c0.8-1.7,1.2-2.8,1.6-3.8c0.6-0.8,1-2.1,1.5-2.9c0.5-0.8,0.9-2,1.2-2.8c0.1-0.8,0.5-1.6,0.6-2.2c0.5-1.3,1.1-2.4,1.6-3.1 c0.1-0.2,0.2-0.4,0.4-0.6c0.3,0.4,0.6,0.9,0.8,1.3c1.6,2.5,3,4.5,5.3,5.4c0.9,0.5,1.5,0.8,1.8,1.2c0.4,0.3,0.4,1.4,0.2,2.1 c0,0.9-0.4,1.7-1.3,2.1c-1.5,0.6-3.9-1.6-4.8-0.5c-0.8,0.9,0.1,2.6,0.9,3.8h6.2c1.5-2.4,2.1-5.8,2.1-8.5c0-2.9,0-3.6-1.7-4.3 c-0.6-0.4-1.2-1.7-1.6-3.2c0-0.2,0-0.5,0-0.8c3-1,6.3-2.7,9.8-5.4c0,0.5,0,1,0.1,1.4c0.6,3.9,1,7.5,4,10.4 c0.8,0.8,1.5,1.6,1.6,2.1c0,0.3-0.5,1.6-0.8,2.2c-0.7,1.5-2.2,2.8-3.3,2.9c-1.5,0.2-3.2-1.7-4.4-0.6c-1,1,0.4,3.2,1,3.8h6.3 c2.1-3.8,5-7,6-9.1c0.6-1.5,0.6-2.1-0.6-2.5c-2.1-1.2-1.8-3.7-1.3-6.6c0.2-0.5,0.4-1,0.7-1.4c1.6,4.4,3.6,8.5,8.4,9.7 c0.8,0.1,2,0.7,2.1,0.9c0,0.2,0,1.1-0.1,1.8c-0.2,1.4-1,3-2.1,3.8c-1.2,0.9-4-2.1-5-0.4c-0.7,1.4,0.5,3.2,1,3.7h6.1 c1.7-3.8,3.2-7.2,3.7-9.6c0.5-2.9,0.5-3.9-1.7-4.4c-1.2-0.1-2.1-0.6-2.4-2.2c-0.8-2.9-0.7-7.7-2.9-11.1c2.4,2.9,5.1,5,7.4,6.1 c5.3,2.9,10.8,1.8,13.5-2C320.1,227.2,320.1,223.9,319.4,221.9"/>
<path class="st1" d="M291.7,189.8c13.7-13,32.5-26.9,56.3-32.8C328,164.2,300.4,183,291.7,189.8 M252.5,183.1 c2.2-23.5,12.9-40.8,20.2-48.8C262.2,149.8,256.2,171.2,252.5,183.1 M262.6,186.3c-0.1-0.9-0.6-1.5-1.4-2c1.6-3.9,3.2-7,6.3-11.2 C264.6,178.9,263.2,183.8,262.6,186.3 M372.4,148.7c-4.7-0.6-15.5,0.6-24.7,2.6c5.8-2.9,7.4-3.3,9.5-4.6c0.6-0.3,0.9-1.2,0.9-2.4 c0-1.4-1.3-1.6-2.8-1.4c-1.5,0.1-4.7,1.3-8.7,2.6c-7.8,3.2-19.1,8.5-32.5,17.5c-11.8,8.1-19.6,15-28.2,23.6 c-2.2,2.3-4.8,5.1-7.5,8.3c-0.6-1-1-1.3-2-1c3-6.8,3.3-7.2,5-11.1c0.7-1.9,0.3-3.2-0.3-4c-0.9-1.6-2.2-0.5-3,0.1 c-1.3,1.5-1.6,1.8-4.4,5.3c3.5-11.5,5.3-12.5,8.5-19c0.4-0.8,0.4-2.2-0.1-3.2c-0.3-0.8-0.8-1.3-1.5-0.9c-1.3,0.6-1.6,1.3-4,4.1 c3.5-6.6,8.2-14.3,8.7-15.6c0.6-1.4,1.4-1.6-0.1-3.7c-1.2-1.7-2.2-0.5-3,0.3c-0.7,0.3-2.1,2-4.5,4.9c5.1-9.5,9.8-13.8,10.7-15.5 c1.1-1.8,1.3-2.3,0.3-4.4c-0.8-1.9-2.4-1-3.2,0c-3.6,3.4-3.3,2.6-9.3,9.6c3.1-8.2,8.5-14.4,10.5-17.7c0.8-1.3,0.9-1.7,0.1-4.9 c-0.5-1.4-1.6-1.9-2.8-1.7c-1.7,0.4-3.3,1.3-6.6,4c-6.6,5.9-15.3,14.4-22.5,29.8c-6.9,14.4-8.4,28-8.4,37.4 c0,14.5,3.8,27.1,7.3,35c0-0.3,0-0.5,0-0.8c-0.2-3.9,0.5-8.4,1.2-10.6c1.5-5.8,3.4-8.9,5-11.4l-2.8-3.8l3.7,1.1l-2.2-4.8 c0,0,2.8,0.3,4.9,3.2c1.3-1.2,4.1-2.3,6.7-0.2c1.7-0.1,2.8,0.2,3.7,0.7c2,1.1,1.7,3.2,1.6,3.7c-1-0.9-3.9-2.8-7-0.4l5.8,2 l-7.3,0.6v7.5l-8.7,7.7v3l5.9-5.2v2.7l-10.4,9.4v2.8l13.2-11.8v0l3.3-3c0,0,0,0,0,0c2-1.6,2.8-2.4,3.9-3c1.4-0.9,1.6,0.1,1.8,1.6 c0.3,1.3,1.8,2.5,5-0.3c9.2-8.3,18.9-12.8,29.2-17.7c-5.6,3.8-15.8,9.4-19.3,13.3c-1.5,1.7,0,6,2.4,4.1c4.4-2.9,10.2-3.3,13-3.2 c1.4,0,2.9-0.9,3.7-2.1c0.8-1,0.8-2.2-1-2.3c9.5-2.9,11.9-3.7,19.7-4.4c2.1-0.1,3.3-1.3,3.7-3c0.4-1.6-0.5-2.1-2.4-2.3 c-2.3-0.3-6.3,0.4-10.4,1c9.1-3.9,20.2-6,29-8.5c2.8-0.8,3.1-1.6,3.2-3.2c0.3-1.7-1.1-1.7-4.2-1.7c-6.3,0.3-15.8,0.9-30.2,5.1 c13.6-6.8,21.2-10,33.6-13.1c3.3-0.9,3.9-1.7,4.2-3.5c0.6-2-1-2-2.2-1.7c-1.7,0.1-5.9,0-14.3,2.5c8.2-3.6,17.2-7.7,23.7-9.8 c1.4-0.5,2.2-1.4,2.2-2.9c0-1.1-0.3-1.3-1.7-1.3c-2.8,0-7.3,0.9-12.7,2.5c11.1-4.7,14.4-6.3,21.8-7.6c2.4-0.6,2.9-1.4,3-2.9 C375.4,148.7,374,148.8,372.4,148.7"/>
</g>
</g>
<script xmlns=""/></svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,13 +0,0 @@
export function calculateAge(birthdate: string): number {
const birthDate = new Date(birthdate);
const currentDate = new Date();
let age = currentDate.getFullYear() - birthDate.getFullYear();
const monthDiff = currentDate.getMonth() - birthDate.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate())) {
age--;
}
return age;
}

View file

@ -1,33 +0,0 @@
<script>
import GitHub from './icons/GitHub.svelte';
import Svelte from './icons/Svelte.svelte';
import Vercel from './icons/Vercel.svelte';
</script>
<footer class="text-center px-4 py-4 dark:text-indigo-300 text-indigo-900">
<a href="https://svelte.dev/" target="_blank" rel="external">
Made with <Svelte />
</a>
<span class="divider-vertical mx-2" />
<a href="https://vercel.com/" target="_blank" rel="external">
Hosted on <Vercel />
</a>
<span class="divider-vertical mx-2" />
<a href="https://github.com/bartvdbraak/hellob.art" target="_blank" rel="external">
Source code at <GitHub />
</a>
<br class="my-1" />
<span> Licensed under GPLv3 </span>
<span class="divider-vertical mx-2" />
<span>
&copy {new Date().getFullYear()} hellob.art
</span>
<span class="divider-vertical mx-2" />
<span> Bart van der Braak </span>
</footer>
<style>
:global(.inline-svg) {
display: inline;
}
</style>

View file

@ -1,86 +0,0 @@
<script lang="ts">
import { AppBar, LightSwitch, ProgressBar } from '@skeletonlabs/skeleton';
import { getDrawerStore, type DrawerSettings } from '@skeletonlabs/skeleton';
import GitHub from './icons/GitHub.svelte';
import Hamburger from './icons/Hamburger.svelte';
import LinkedIn from './icons/LinkedIn.svelte';
import logo from '$lib/assets/logo.svg';
import routes from '$lib/routes';
import { page } from '$app/stores';
const drawerStore = getDrawerStore();
export let progress: number;
$: classesActive = (href: string) => (href === $page.url.pathname ? 'underline' : '');
function trigger(position: 'right'): void {
const s: DrawerSettings = { id: 'navigation', position };
drawerStore.open(s);
}
</script>
<AppBar background="">
<svelte:fragment slot="lead">
<a href="/" class="md:ml-4 ml-1">
<img width="212" height="32" src={logo} alt="hellob.art logo" />
</a>
</svelte:fragment>
<nav class="hidden md:block">
<ul class="flex">
{#each routes as { url, label }}
<li class="mx-2">
<a
class={`${classesActive(
url
)} decoration-indigo-500 hover:underline hover:decoration-indigo-300`}
href={url}
>
<span class="flex-auto">{label}</span>
</a>
</li>
{/each}
</ul>
</nav>
<svelte:fragment slot="trail">
<a
href="https://linkedin.com/in/bartvdbraak"
target="_blank"
rel="external"
class="btn-icon btn-icon-sm hover:variant-soft-primary"
>
<LinkedIn />
<span class="sr-only">LinkedIn Profile of Bart van der Braak</span>
</a>
<a
href="https://github.com/bartvdbraak"
target="_blank"
rel="external"
class="btn-icon btn-icon-sm hover:variant-soft-primary"
>
<GitHub />
<span class="sr-only">GitHub Profile of Bart van der Braak</span>
</a>
<LightSwitch bgLight="bg-white" fillLight="fill-white" width="w-8" height="h-4" />
<button
aria-label="Toggle navigation menu"
class="btn-icon btn-icon-sm hover:variant-soft-primary md:hidden"
on:click={() => {
trigger('right');
}}
>
<Hamburger />
</button>
</svelte:fragment>
</AppBar>
<span id="progress-bar-label" class="sr-only">Loading Progress</span>
<ProgressBar
label="Progress Bar"
labelledby="progress-bar-label"
height="h-0.5"
value={progress}
max={100}
rounded=""
meter="bg-indigo-500"
/>

View file

@ -1,49 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import type { Route } from '$lib/routes';
import { getDrawerStore } from '@skeletonlabs/skeleton';
const drawerStore = getDrawerStore();
$: classesActive = (href: string) => (href === $page.url.pathname ? '!text-primary-700' : '');
export let routes: Route[];
</script>
<nav class="list-nav">
<div class="flex justify-end pb-2">
<button
class="button"
on:click={() => {
drawerStore.close();
}}>✕</button
>
</div>
<ul>
{#each routes as route}
<li class="mb-2 flex justify-end">
<a
href={route.url}
on:click={() => {
drawerStore.close();
}}
>
<span class="badge"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-chevron-right text-white"><path d="m9 18 6-6-6-6" /></svg
></span
>
<span class="flex-auto {classesActive(route.url)} text-white">{route.label}</span>
</a>
</li>
{/each}
</ul>
</nav>

View file

@ -1,15 +0,0 @@
<svg
class="inline-svg"
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
><path
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"
/></svg
>

Before

Width:  |  Height:  |  Size: 529 B

View file

@ -1,18 +0,0 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-menu"
><line x1="4" x2="20" y1="12" y2="12" /><line x1="4" x2="20" y1="6" y2="6" /><line
x1="4"
x2="20"
y1="18"
y2="18"
/></svg
>

Before

Width:  |  Height:  |  Size: 352 B

View file

@ -1,12 +0,0 @@
<svg
stroke="currentColor"
fill="currentColor"
stroke-width="0"
viewBox="0 0 1024 1024"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
><path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zM349.3 793.7H230.6V411.9h118.7v381.8zm-59.3-434a68.8 68.8 0 1 1 68.8-68.8c-.1 38-30.9 68.8-68.8 68.8zm503.7 434H675.1V608c0-44.3-.8-101.2-61.7-101.2-61.7 0-71.2 48.2-71.2 98v188.9H423.7V411.9h113.8v52.2h1.6c15.8-30 54.5-61.7 112.3-61.7 120.2 0 142.3 79.1 142.3 181.9v209.4z"
/></svg
>

Before

Width:  |  Height:  |  Size: 564 B

View file

@ -1,13 +0,0 @@
<svg
class="inline-svg"
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M3 19h18l-9 -15z" /></svg
>

Before

Width:  |  Height:  |  Size: 303 B

View file

@ -0,0 +1,4 @@
<svg viewBox="0 0 24 24" {...$$restProps}>
<path d="M0 0h24v24H0z" />
<path d="M3 19h18l-9 -15z" />
</svg>

After

Width:  |  Height:  |  Size: 109 B

View file

@ -0,0 +1,16 @@
import type { Icon as LucideIcon } from 'lucide-svelte';
import { GithubLogo, VercelLogo, LinkedinLogo } from 'radix-icons-svelte';
import Logo from './logo.svelte';
import Svelte from './svelte.svelte';
import LogoIcon from '$lib/assets/logo-icon.png';
export type Icon = LucideIcon;
export const Icons = {
logo: Logo,
logoIcon: LogoIcon,
gitHub: GithubLogo,
svelte: Svelte,
vercel: VercelLogo,
linkedIn: LinkedinLogo
};

View file

@ -0,0 +1,44 @@
<svg width="177" height="28" viewBox="0 0 177 28" {...$$restProps}>
<rect x="0.5" y="0.5" width="116.25" height="27" fill="white" stroke="black" />
<rect x="117.25" width="59.5" height="28" fill="black" />
<rect x="117.25" y="1.25" width="58.5" height="25.5" stroke="white" stroke-width="0.5" />
<path
d="M6.174 21C6.118 21 6.09 20.965 6.09 20.895L6.111 6.46798C6.111 6.41198 6.146 6.38398 6.216 6.38398H8.547C8.617 6.38398 8.652 6.41198 8.652 6.46798L8.631 12.18H11.781V6.46798C11.781 6.41198 11.809 6.38398 11.865 6.38398H14.196C14.266 6.38398 14.301 6.41198 14.301 6.46798L14.343 20.895C14.343 20.965 14.308 21 14.238 21H11.886C11.816 21 11.781 20.965 11.781 20.895V14.721H8.631V20.895C8.631 20.965 8.603 21 8.547 21H6.174Z"
fill="black"
/>
<path
d="M26.6408 21C26.5848 21 26.5568 20.965 26.5568 20.895L26.5778 6.46798C26.5778 6.41198 26.6058 6.38398 26.6618 6.38398H33.4028C33.4588 6.38398 33.4868 6.41898 33.4868 6.48898V8.84098C33.4868 8.89698 33.4588 8.92498 33.4028 8.92498H29.0978V12.201H33.4028C33.4588 12.201 33.4868 12.229 33.4868 12.285L33.5078 14.658C33.5078 14.714 33.4798 14.742 33.4238 14.742H29.0978V18.417H33.4238C33.4798 18.417 33.5078 18.452 33.5078 18.522V20.916C33.5078 20.972 33.4798 21 33.4238 21H26.6408Z"
fill="black"
/>
<path
d="M45.9592 21C45.9032 21 45.8752 20.965 45.8752 20.895L45.8962 6.48898C45.8962 6.41898 45.9312 6.38398 46.0012 6.38398H48.3322C48.4022 6.38398 48.4372 6.41898 48.4372 6.48898L48.4162 18.417H52.7422C52.8122 18.417 52.8472 18.452 52.8472 18.522V20.895C52.8472 20.965 52.8122 21 52.7422 21H45.9592Z"
fill="black"
/>
<path
d="M64.8058 21C64.7498 21 64.7218 20.965 64.7218 20.895L64.7428 6.48898C64.7428 6.41898 64.7778 6.38398 64.8478 6.38398H67.1788C67.2488 6.38398 67.2838 6.41898 67.2838 6.48898L67.2628 18.417H71.5888C71.6588 18.417 71.6938 18.452 71.6938 18.522V20.895C71.6938 20.965 71.6588 21 71.5888 21H64.8058Z"
fill="black"
/>
<path
d="M87.1664 21.21C86.4104 21.21 85.7174 21.021 85.0874 20.643C84.4714 20.251 83.9744 19.74 83.5964 19.11C83.2184 18.466 83.0294 17.759 83.0294 16.989L83.0504 10.332C83.0504 9.56198 83.2324 8.86198 83.5964 8.23198C83.9744 7.60198 84.4784 7.09798 85.1084 6.71998C85.7384 6.34198 86.4244 6.15298 87.1664 6.15298C87.9224 6.15298 88.6084 6.34198 89.2244 6.71998C89.8404 7.09798 90.3304 7.60198 90.6944 8.23198C91.0724 8.86198 91.2614 9.56198 91.2614 10.332L91.2824 16.989C91.2824 17.759 91.0934 18.466 90.7154 19.11C90.3514 19.74 89.8544 20.251 89.2244 20.643C88.6084 21.021 87.9224 21.21 87.1664 21.21ZM87.1664 18.669C87.5864 18.669 87.9504 18.501 88.2584 18.165C88.5804 17.815 88.7414 17.423 88.7414 16.989L88.7204 10.332C88.7204 9.86998 88.5734 9.47798 88.2794 9.15598C87.9854 8.83398 87.6144 8.67298 87.1664 8.67298C86.7324 8.67298 86.3614 8.83398 86.0534 9.15598C85.7454 9.46398 85.5914 9.85598 85.5914 10.332V16.989C85.5914 17.451 85.7454 17.85 86.0534 18.186C86.3614 18.508 86.7324 18.669 87.1664 18.669Z"
fill="black"
/>
<path
d="M103.463 21C103.407 21 103.379 20.965 103.379 20.895L103.421 6.46798C103.421 6.41198 103.449 6.38398 103.505 6.38398H107.537C108.335 6.38398 109.049 6.57998 109.679 6.97198C110.309 7.34998 110.806 7.85398 111.17 8.48398C111.534 9.11398 111.716 9.79998 111.716 10.542C111.716 11.144 111.576 11.704 111.296 12.222C111.03 12.74 110.708 13.16 110.33 13.482C110.736 13.888 111.051 14.357 111.275 14.889C111.499 15.421 111.611 15.981 111.611 16.569C111.611 17.381 111.415 18.123 111.023 18.795C110.631 19.467 110.099 20.006 109.427 20.412C108.769 20.804 108.034 21 107.222 21H103.463ZM105.941 12.18H107.537C108.027 12.18 108.419 12.012 108.713 11.676C109.021 11.326 109.175 10.948 109.175 10.542C109.175 10.094 109.014 9.70898 108.692 9.38698C108.37 9.05098 107.985 8.88298 107.537 8.88298H105.941V12.18ZM105.92 18.438H107.222C107.726 18.438 108.16 18.256 108.524 17.892C108.888 17.514 109.07 17.073 109.07 16.569C109.07 16.065 108.888 15.631 108.524 15.267C108.16 14.903 107.726 14.721 107.222 14.721H105.941L105.92 18.438Z"
fill="black"
/>
<path
d="M122.626 20.895L125.23 6.46803C125.244 6.41203 125.279 6.38403 125.335 6.38403H128.38C128.436 6.38403 128.471 6.41203 128.485 6.46803L130.984 20.895C130.998 20.965 130.97 21 130.9 21H128.569C128.513 21 128.478 20.965 128.464 20.895L128.233 19.362H125.377L125.146 20.895C125.132 20.965 125.097 21 125.041 21H122.71C122.654 21 122.626 20.965 122.626 20.895ZM125.797 17.115H127.813L126.952 11.214L126.826 10.437L126.742 11.214L125.797 17.115Z"
fill="white"
/>
<path
d="M142.886 21C142.83 21 142.802 20.965 142.802 20.895L142.844 6.46803C142.844 6.41203 142.872 6.38403 142.928 6.38403H147.17C147.926 6.38403 148.619 6.57303 149.249 6.95103C149.893 7.31503 150.404 7.81203 150.782 8.44203C151.16 9.05803 151.349 9.75803 151.349 10.542C151.349 11.06 151.272 11.529 151.118 11.949C150.964 12.355 150.782 12.705 150.572 12.999C150.362 13.279 150.173 13.489 150.005 13.629C150.761 14.469 151.139 15.456 151.139 16.59L151.16 20.895C151.16 20.965 151.125 21 151.055 21H148.682C148.626 21 148.598 20.979 148.598 20.937V16.59C148.598 16.086 148.416 15.652 148.052 15.288C147.702 14.91 147.268 14.721 146.75 14.721H145.364L145.343 20.895C145.343 20.965 145.315 21 145.259 21H142.886ZM145.364 12.201H147.17C147.604 12.201 147.989 12.04 148.325 11.718C148.661 11.396 148.829 11.004 148.829 10.542C148.829 10.094 148.661 9.70903 148.325 9.38703C148.003 9.06503 147.618 8.90403 147.17 8.90403H145.364V12.201Z"
fill="white"
/>
<path
d="M165.123 21C165.067 21 165.039 20.965 165.039 20.895V8.92503H162.309C162.239 8.92503 162.204 8.89003 162.204 8.82003L162.225 6.46803C162.225 6.41203 162.253 6.38403 162.309 6.38403H170.289C170.359 6.38403 170.394 6.41203 170.394 6.46803V8.82003C170.394 8.89003 170.366 8.92503 170.31 8.92503H167.559L167.58 20.895C167.58 20.965 167.552 21 167.496 21H165.123Z"
fill="white"
/>
<circle cx="117" cy="21" r="2.25" fill="black" />
<circle cx="117" cy="21" r="2.25" stroke="black" stroke-width="0.5" />
<circle cx="117" cy="21" r="2.25" stroke="white" stroke-width="0.5" />
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -8,7 +8,8 @@
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
><title /><path
{...$$restProps}
><path
d="M10.354 21.125a4.44 4.44 0 0 1-4.765-1.767 4.109 4.109 0 0 1-.703-3.107 3.898 3.898 0 0 1 .134-.522l.105-.321.287.21a7.21 7.21 0 0 0 2.186 1.092l.208.063-.02.208a1.253 1.253 0 0 0 .226.83 1.337 1.337 0 0 0 1.435.533 1.231 1.231 0 0 0 .343-.15l5.59-3.562a1.164 1.164 0 0 0 .524-.778 1.242 1.242 0 0 0-.211-.937 1.338 1.338 0 0 0-1.435-.533 1.23 1.23 0 0 0-.343.15l-2.133 1.36a4.078 4.078 0 0 1-1.135.499 4.44 4.44 0 0 1-4.765-1.766 4.108 4.108 0 0 1-.702-3.108 3.855 3.855 0 0 1 1.742-2.582l5.589-3.563a4.072 4.072 0 0 1 1.135-.499 4.44 4.44 0 0 1 4.765 1.767 4.109 4.109 0 0 1 .703 3.107 3.943 3.943 0 0 1-.134.522l-.105.321-.286-.21a7.204 7.204 0 0 0-2.187-1.093l-.208-.063.02-.207a1.255 1.255 0 0 0-.226-.831 1.337 1.337 0 0 0-1.435-.532 1.231 1.231 0 0 0-.343.15L8.62 9.368a1.162 1.162 0 0 0-.524.778 1.24 1.24 0 0 0 .211.937 1.338 1.338 0 0 0 1.435.533 1.235 1.235 0 0 0 .344-.151l2.132-1.36a4.067 4.067 0 0 1 1.135-.498 4.44 4.44 0 0 1 4.765 1.766 4.108 4.108 0 0 1 .702 3.108 3.857 3.857 0 0 1-1.742 2.583l-5.589 3.562a4.072 4.072 0 0 1-1.135.499m10.358-17.95C18.484-.015 14.082-.96 10.9 1.068L5.31 4.63a6.412 6.412 0 0 0-2.896 4.295 6.753 6.753 0 0 0 .666 4.336 6.43 6.43 0 0 0-.96 2.396 6.833 6.833 0 0 0 1.168 5.167c2.229 3.19 6.63 4.135 9.812 2.108l5.59-3.562a6.41 6.41 0 0 0 2.896-4.295 6.756 6.756 0 0 0-.665-4.336 6.429 6.429 0 0 0 .958-2.396 6.831 6.831 0 0 0-1.167-5.168Z"
/></svg
>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,4 @@
<svg viewBox="0 0 24 24" {...$$restProps}>
<path stroke="none" d="M0 0h24v24H0z" />
<path d="M3 19h18l-9 -15z" />
</svg>

After

Width:  |  Height:  |  Size: 123 B

View file

@ -0,0 +1,33 @@
<script>
import { onMount } from 'svelte';
import catImg from '$lib/assets/root-cat.jpg?enhanced';
import meImg from '$lib/assets/root-me.jpg?enhanced';
const images = [
{ src: meImg, alt: 'Portrait of Bart van der Braak', style: 'object-[50%_10%]' },
{ src: catImg, alt: 'Noire yawning cat and a bottle of whiskey with glass', style: '' }
];
let currentIndex = 0;
let currentImage = images[currentIndex];
onMount(() => {
const interval = setInterval(() => {
currentIndex = (currentIndex + 1) % images.length;
currentImage = images[currentIndex];
}, 15000);
return () => clearInterval(interval);
});
</script>
<div class="relative h-full min-h-96 w-full md:min-h-44">
{#each images as image}
<enhanced:img
src={image.src}
alt={image.alt}
class="absolute left-0 top-0 h-full w-full rounded-xl object-cover transition-opacity duration-1000 {image.style}"
style:opacity={image === currentImage ? 1 : 0}
/>
{/each}
</div>

View file

@ -0,0 +1,9 @@
export { default as Metadata } from './metadata.svelte';
export { default as SiteFooter } from './site-footer.svelte';
export { default as SiteHeader } from './site-header.svelte';
export { default as TailwindIndicator } from './tailwind-indicator.svelte';
export { default as ModeToggle } from './mode-toggle.svelte';
export { default as ImageFade } from './image-fade.svelte';
export * from './icons';
export * from './nav';

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { page } from '$app/stores';
import { siteConfig } from '$lib/config/site';
export let title: string = siteConfig.name;
$: title = $page.data?.title ? `${$page.data.title} - ${siteConfig.name}` : siteConfig.name;
</script>
<svelte:head>
<title>{title}</title>
<meta name="description" content={siteConfig.description} />
<meta name="keywords" content={siteConfig.keywords} />
<meta name="author" content="Bart van der Braak" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content={siteConfig.url} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={siteConfig.description} />
<meta name="twitter:image" content={siteConfig.ogImage} />
<meta name="twitter:image:alt" content={siteConfig.name} />
<meta name="twitter:creator" content="Bart van der Braak" />
<meta property="og:title" content={title} />
<meta property="og:type" content="article" />
<meta property="og:url" content={siteConfig.url + $page.url.pathname} />
<meta property="og:image" content={siteConfig.ogImage} />
<meta property="og:image:alt" content={siteConfig.name} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:description" content={siteConfig.description} />
<meta property="og:site_name" content={siteConfig.name} />
<meta property="og:locale" content="EN_US" />
<link rel="icon" href="/favicon.ico" />
<link rel="shortcut icon" href="/favicon-16x16.png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
</svelte:head>

View file

@ -0,0 +1,25 @@
<script lang="ts">
import { Moon, Sun } from 'lucide-svelte';
import { Button } from '../ui/button';
import * as DropdownMenu from '../ui/dropdown-menu';
import { resetMode, setMode } from 'mode-watcher';
</script>
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild let:builder>
<Button builders={[builder]} variant="ghost" class="w-9 px-0">
<Sun
class="dark:-roate-90 h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:scale-0"
/>
<Moon
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
<span class="sr-only">Toggle theme</span>
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<DropdownMenu.Item on:click={() => setMode('light')}>Light</DropdownMenu.Item>
<DropdownMenu.Item on:click={() => setMode('dark')}>Dark</DropdownMenu.Item>
<DropdownMenu.Item on:click={() => resetMode()}>System</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>

View file

@ -0,0 +1,2 @@
export { default as MainNav } from './main-nav.svelte';
export { default as MobileNav } from './mobile-nav.svelte';

View file

@ -0,0 +1,23 @@
<script lang="ts">
import { page } from '$app/stores';
import { cn } from '$lib/utils';
import { navConfig } from '$lib/config/nav';
</script>
<div class="mr-4 hidden md:flex">
<nav class="flex items-center space-x-6 text-sm font-medium">
{#each navConfig.mainNav as navItem, index (navItem + index.toString())}
{#if navItem.href}
<a
href={navItem.href}
class={cn(
'transition-colors hover:text-foreground/80',
$page.url.pathname === navItem.href ? 'text-foreground' : 'text-foreground/60'
)}
>
{navItem.title}
</a>
{/if}
{/each}
</nav>
</div>

View file

@ -0,0 +1,23 @@
<script lang="ts">
import { page } from '$app/stores';
import { cn } from '$lib/utils';
export let href: string;
export let open: boolean;
let className: string | undefined | null = undefined;
export { className as class };
</script>
<a
{href}
on:click={() => (open = false)}
class={cn(
$page.url.pathname === href ? 'text-foreground' : 'text-foreground/60',
'hover:text-foreground',
className
)}
{...$$restProps}
>
<slot />
</a>

View file

@ -0,0 +1,64 @@
<script lang="ts">
import * as Sheet from '$lib/components/ui/sheet/';
import { HamburgerMenu } from 'radix-icons-svelte';
import { Button } from '$lib/components/ui/button';
import { navConfig } from '$lib/config/nav';
import { siteConfig } from '$lib/config/site';
import { Icons } from '../icons';
import MobileLink from './mobile-link.svelte';
let open = false;
</script>
<Sheet.Root bind:open>
<Sheet.Trigger asChild let:builder>
<Button
builders={[builder]}
variant="ghost"
class="mr-2 px-0 text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 md:hidden"
>
<HamburgerMenu class="h-5 w-5" />
<span class="sr-only">Toggle Menu</span>
</Button>
</Sheet.Trigger>
<Sheet.Content side="right" class="pr-0">
<MobileLink href="/" class="flex items-center" bind:open>
<img src={Icons.logoIcon} class="mr-2 h-4 w-4" alt="icon of hellob.art" />
<span class="font-mono font-bold tracking-tighter">{siteConfig.name}</span>
</MobileLink>
<div class="my-4 h-[calc(100vh-8rem)] overflow-auto pl-1 pt-10">
<div class="flex flex-col space-y-3">
{#each navConfig.mainNav as navItem, index (navItem + index.toString())}
{#if navItem.href}
<MobileLink href={navItem.href} bind:open class="pt-2 text-5xl font-bold">
{navItem.title}
</MobileLink>
{/if}
{/each}
</div>
<div class="flex flex-col space-y-2">
{#each navConfig.sidebarNav as navItem, index (index)}
<div class="flex flex-col space-y-3 pt-6">
<h4 class="font-medium">{navItem.title}</h4>
{#if navItem?.items?.length}
{#each navItem.items as item}
{#if !item.disabled && item.href}
<MobileLink href={item.href} bind:open class="text-muted-foreground">
{item.title}
{#if item.label}
<span
class="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000]"
>
{item.label}
</span>
{/if}
</MobileLink>
{/if}
{/each}
{/if}
</div>
{/each}
</div>
</div>
</Sheet.Content>
</Sheet.Root>

View file

@ -0,0 +1,12 @@
import Root from './page-header.svelte';
import Heading from './page-header-heading.svelte';
import Description from './page-header-description.svelte';
export {
Root,
Heading,
Description,
Root as PageHeader,
Heading as PageHeaderHeading,
Description as PageHeaderDescription
};

View file

@ -0,0 +1,13 @@
<script lang="ts">
import Balancer from 'svelte-wrap-balancer';
import { cn } from '$lib/utils';
let className: string | undefined | null = undefined;
export { className as class };
</script>
<p class={cn('max-w-[750px] text-lg text-muted-foreground sm:text-xl', className)} {...$$restProps}>
<Balancer>
<slot />
</Balancer>
</p>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { cn } from '$lib/utils';
let className: string | undefined | null = undefined;
export { className as class };
</script>
<h1
class={cn(
'text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1]',
className
)}
{...$$restProps}
>
<slot />
</h1>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { cn } from '$lib/utils';
let className: string | undefined | null = undefined;
export { className as class };
</script>
<section
class={cn(
'mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20',
className
)}
{...$$restProps}
>
<slot />
</section>

View file

@ -0,0 +1,4 @@
import Root from './projects.svelte';
import Item from './projects-item.svelte';
export { Root, Item, Root as Projects, Item as ProjectsItem };

View file

@ -0,0 +1,45 @@
<script lang="ts">
import { Circle } from 'radix-icons-svelte';
import { Scale } from 'lucide-svelte';
import * as Card from '$lib/components/ui/card';
import type { Project } from '$lib/content/projects';
import * as Avatar from '$lib/components/ui/avatar';
export let projectsItem: Project;
let { avatarImg, title, description, languages, license, year } = projectsItem;
</script>
<Card.Root class="hover:bg-muted/50">
<Card.Header class="grid grid-cols-[1fr_110px] items-start gap-4 space-y-0">
<div class="space-y-1">
<Card.Title>{title}</Card.Title>
<Card.Description>
{description}
</Card.Description>
</div>
<div class="justify-self-end">
<Avatar.Root>
<Avatar.Image src={avatarImg} alt={title} />
<Avatar.Fallback>NA</Avatar.Fallback>
</Avatar.Root>
</div>
</Card.Header>
<Card.Content>
<div class="flex space-x-4 text-sm text-muted-foreground">
{#each languages as language}
<div class="flex items-center">
<Circle class="mr-1 h-3 w-3 {language.color}" />
{language.name}
</div>
{/each}
<div class="flex items-center">
<Scale class="mr-1 h-3 w-3" />
{license}
</div>
<div>
Started in
{year}
</div>
</div>
</Card.Content>
</Card.Root>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import * as Projects from './';
import projects from '$lib/content/projects';
</script>
<div class="col-span-2 grid items-start gap-6 lg:col-span-2 lg:grid-cols-2">
{#each projects as project}
{#if project.url}
<a href={project.url} target="_blank">
<Projects.Item projectsItem={project} />
</a>
{:else}
<Projects.Item projectsItem={project} />
{/if}
{/each}
</div>

View file

@ -0,0 +1,45 @@
<script lang="ts">
import { siteConfig } from '$lib/config/site';
import Separator from '$lib/components/ui/separator/separator.svelte';
</script>
<footer class="container py-6">
<div class="space-y-1">
<p class="text-center text-sm text-muted-foreground">
&copy; {new Date().getFullYear()} &mdash; {siteConfig.author}. Licensed under GPL-3.0.
</p>
</div>
<Separator class="my-2" />
<div class="flex justify-center">
<div class="flex h-5 items-center space-x-4 text-xs">
<div>
Built using <a
href={siteConfig.links.shadcnSvelte}
target="_blank"
rel="noreferrer"
class="font-medium underline underline-offset-4">shadcn-svelte</a
>
</div>
<Separator orientation="vertical" />
<div>
Hosted on <a
href={siteConfig.links.vercel}
target="_blank"
rel="noreferrer"
class="font-medium underline underline-offset-4">Vercel</a
>
</div>
<Separator orientation="vertical" />
<div>
Source code at <a
href={siteConfig.links.gitHubProject}
target="_blank"
rel="noreferrer"
class="font-medium underline underline-offset-4">GitHub</a
>
</div>
<Separator orientation="vertical" />
<div>Enhanced using LLMs</div>
</div>
</div>
</footer>

View file

@ -0,0 +1,51 @@
<script lang="ts">
import { Icons, ModeToggle, MainNav, MobileNav } from '$lib/components/site';
import { siteConfig } from '$lib/config/site';
import { cn } from '$lib/utils';
import { buttonVariants } from '../ui/button';
</script>
<header
class="sticky top-0 z-50 w-full border-b bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/60"
>
<div class="container flex h-14 items-center">
<a href="/" class="mr-6 flex items-center space-x-2">
<Icons.logo />
</a>
<MainNav />
<div class="flex flex-1 items-center justify-between space-x-2 sm:space-x-4 md:justify-end">
<nav class="flex items-center">
<a href={siteConfig.links.gitHubProfile} target="_blank" rel="noopener noreferrer">
<div
class={cn(
buttonVariants({
size: 'sm',
variant: 'ghost'
}),
'w-9 px-0'
)}
>
<Icons.gitHub class="h-4 w-4" />
<span class="sr-only">GitHub</span>
</div>
</a>
<a href={siteConfig.links.twitter} target="_blank" rel="noreferrer">
<div
class={cn(
buttonVariants({
size: 'sm',
variant: 'ghost'
}),
'w-9 px-0'
)}
>
<Icons.linkedIn class="h-3 w-3 fill-current" />
<span class="sr-only">LinkedIn</span>
</div>
</a>
<ModeToggle />
</nav>
</div>
<MobileNav />
</div>
</header>

View file

@ -0,0 +1,10 @@
<div
class="fixed bottom-1 left-1 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-gray-800 p-3 font-mono text-xs text-white"
>
<div class="block sm:hidden">xs</div>
<div class="hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden">sm</div>
<div class="hidden md:block lg:hidden xl:hidden 2xl:hidden">md</div>
<div class="hidden lg:block xl:hidden 2xl:hidden">lg</div>
<div class="hidden xl:block 2xl:hidden">xl</div>
<div class="hidden 2xl:block">2xl</div>
</div>

View file

@ -0,0 +1,5 @@
import Root from './timeline.svelte';
import Item from './timeline-item.svelte';
import Break from './timeline-break.svelte';
export { Root, Item, Break, Root as Timeline, Item as TimelineItem, Break as TimelineBreak };

View file

@ -0,0 +1,14 @@
<script lang="ts">
export let date: string;
</script>
<div class="relative">
<div class="absolute inset-0 flex items-center">
<span class="w-full border-t" />
</div>
<div class="relative flex justify-center text-xs uppercase">
<span class="bg-card px-2 text-muted-foreground">
{date}
</span>
</div>
</div>

View file

@ -0,0 +1,15 @@
<script lang="ts">
import { type TimelineItem } from '$lib/content/timeline';
export let timelineItem: TimelineItem;
</script>
<div
class="-mx-2 grid grid-cols-[20px,2fr] space-x-4 rounded-md p-2 transition-all hover:bg-accent hover:text-accent-foreground"
>
<svelte:component this={timelineItem.icon} class="h-full w-full" />
<div class="space-y-1">
<p class="text-sm font-medium leading-none">{timelineItem.title}</p>
<p class="text-sm text-muted-foreground">{timelineItem.subTitle}</p>
</div>
</div>

View file

@ -0,0 +1,25 @@
<script lang="ts">
import * as Card from '$lib/components/ui/card';
import * as Timeline from './';
import timeline from '$lib/content/timeline';
</script>
<Card.Root>
<Card.Header class="pb-3">
<Card.Title>Timeline</Card.Title>
<Card.Description>
A time-based overview showcasing when I embarked on projects, jobs, certifications, and
various events.
</Card.Description>
</Card.Header>
<Card.Content class="grid gap-1">
{#each [...new Set(timeline.map((item) => item.startYear))].sort((a, b) => b - a) as year}
<Timeline.Break date={`${year}`} />
{#each timeline as item}
{#if item.startYear === year}
<Timeline.Item timelineItem={item} />
{/if}
{/each}
{/each}
</Card.Content>
</Card.Root>

View file

@ -0,0 +1,4 @@
import Root from './tools.svelte';
import Item from './tools-item.svelte';
export { Root, Item, Root as Tools, Item as ToolsItem };

View file

@ -0,0 +1,29 @@
<script lang="ts">
import * as Card from '$lib/components/ui/card';
import type { Tool } from '$lib/content/tools';
export let toolItem: Tool;
let { description, enhanced, logo, name, tagLine } = toolItem;
</script>
<Card.Root class="mb-4 inline-block h-full w-full hover:bg-muted/50">
<Card.Header class="flex flex-row items-center justify-between space-y-0 pb-1">
<Card.Title>
<h4 class="text-2xl font-bold">{name}</h4>
<span class="text-sm font-medium">{tagLine}</span>
</Card.Title>
{#if enhanced}
<enhanced:img
src={logo}
alt="logo of {name}"
class="h-10 w-10 object-contain"
loading="lazy"
/>
{:else}
<img src={logo} alt="logo of {name}" class="h-10 w-10 object-contain" loading="lazy" />
{/if}
</Card.Header>
<Card.Content class="text-sm text-muted-foreground">
{description}
</Card.Content>
</Card.Root>

View file

@ -0,0 +1,12 @@
<script lang="ts">
import * as Tools from './';
import tools from '$lib/content/tools';
</script>
<div class="columns-1 gap-4 md:columns-2 lg:columns-3">
{#each tools as tool}
<a href={tool.url} target="_blank">
<Tools.Item toolItem={tool} />
</a>
{/each}
</div>

View file

@ -0,0 +1,11 @@
{
"rules": {
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^\\$\\$(Props|Events|Slots|Generic)$"
}
]
}
}

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = AvatarPrimitive.FallbackProps;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Fallback
class={cn('flex h-full w-full items-center justify-center rounded-full bg-muted', className)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Fallback>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = AvatarPrimitive.ImageProps;
let className: $$Props['class'] = undefined;
export let src: $$Props['src'] = undefined;
export let alt: $$Props['alt'] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Image
{src}
{alt}
class={cn('aspect-square h-full w-full', className)}
{...$$restProps}
/>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = AvatarPrimitive.Props;
let className: $$Props['class'] = undefined;
export let delayMs: $$Props['delayMs'] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Root
{delayMs}
class={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Root>

View file

@ -0,0 +1,13 @@
import Root from './avatar.svelte';
import Image from './avatar-image.svelte';
import Fallback from './avatar-fallback.svelte';
export {
Root,
Image,
Fallback,
//
Root as Avatar,
Image as AvatarImage,
Fallback as AvatarFallback
};

View file

@ -0,0 +1,25 @@
<script lang="ts">
import { Button as ButtonPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { buttonVariants, type Props, type Events } from '.';
type $$Props = Props;
type $$Events = Events;
let className: $$Props['class'] = undefined;
export let variant: $$Props['variant'] = 'default';
export let size: $$Props['size'] = 'default';
export let builders: $$Props['builders'] = [];
export { className as class };
</script>
<ButtonPrimitive.Root
{builders}
class={cn(buttonVariants({ variant, size, className }))}
type="button"
{...$$restProps}
on:click
on:keydown
>
<slot />
</ButtonPrimitive.Root>

View file

@ -0,0 +1,48 @@
import Root from './button.svelte';
import { tv, type VariantProps } from 'tailwind-variants';
import type { Button as ButtonPrimitive } from 'bits-ui';
const buttonVariants = tv({
base: 'inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
});
type Variant = VariantProps<typeof buttonVariants>['variant'];
type Size = VariantProps<typeof buttonVariants>['size'];
type Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
};
type Events = ButtonPrimitive.Events;
export {
Root,
type Props,
type Events,
//
Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants
};

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { cn } from '$lib/utils';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<div class={cn('p-6 pt-0', className)} {...$$restProps}>
<slot />
</div>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
type $$Props = HTMLAttributes<HTMLParagraphElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<p class={cn('text-sm text-muted-foreground', className)} {...$$restProps}>
<slot />
</p>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<div class={cn('flex items-center p-6 pt-0', className)} {...$$restProps}>
<slot />
</div>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<div class={cn('flex flex-col space-y-1.5 p-6', className)} {...$$restProps}>
<slot />
</div>

View file

@ -0,0 +1,21 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
import type { HeadingLevel } from '.';
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
tag?: HeadingLevel;
};
let className: $$Props['class'] = undefined;
export let tag: $$Props['tag'] = 'h3';
export { className as class };
</script>
<svelte:element
this={tag}
class={cn('text-lg font-semibold leading-none tracking-tight', className)}
{...$$restProps}
>
<slot />
</svelte:element>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<div
class={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)}
{...$$restProps}
>
<slot />
</div>

View file

@ -0,0 +1,24 @@
import Root from './card.svelte';
import Content from './card-content.svelte';
import Description from './card-description.svelte';
import Footer from './card-footer.svelte';
import Header from './card-header.svelte';
import Title from './card-title.svelte';
export {
Root,
Content,
Description,
Footer,
Header,
Title,
//
Root as Card,
Content as CardContent,
Description as CardDescription,
Footer as CardFooter,
Header as CardHeader,
Title as CardTitle
};
export type HeadingLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { Check } from 'lucide-svelte';
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
let className: $$Props['class'] = undefined;
export let checked: $$Props['checked'] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.CheckboxItem
bind:checked
class={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50',
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.CheckboxIndicator>
<Check class="h-4 w-4" />
</DropdownMenuPrimitive.CheckboxIndicator>
</span>
<slot />
</DropdownMenuPrimitive.CheckboxItem>

View file

@ -0,0 +1,27 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils';
type $$Props = DropdownMenuPrimitive.ContentProps;
type $$Events = DropdownMenuPrimitive.ContentEvents;
let className: $$Props['class'] = undefined;
export let sideOffset: $$Props['sideOffset'] = 4;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Content
{transition}
{transitionConfig}
{sideOffset}
class={cn(
'z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none',
className
)}
{...$$restProps}
on:keydown
>
<slot />
</DropdownMenuPrimitive.Content>

View file

@ -0,0 +1,31 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = DropdownMenuPrimitive.ItemProps & {
inset?: boolean;
};
type $$Events = DropdownMenuPrimitive.ItemEvents;
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Item
class={cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50',
inset && 'pl-8',
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<slot />
</DropdownMenuPrimitive.Item>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = DropdownMenuPrimitive.LabelProps & {
inset?: boolean;
};
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Label
class={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
{...$$restProps}
>
<slot />
</DropdownMenuPrimitive.Label>

View file

@ -0,0 +1,11 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
type $$Props = DropdownMenuPrimitive.RadioGroupProps;
export let value: $$Props['value'] = undefined;
</script>
<DropdownMenuPrimitive.RadioGroup {...$$restProps} bind:value>
<slot />
</DropdownMenuPrimitive.RadioGroup>

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { Circle } from 'lucide-svelte';
type $$Props = DropdownMenuPrimitive.RadioItemProps;
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
let className: $$Props['class'] = undefined;
export let value: $$Props['value'];
export { className as class };
</script>
<DropdownMenuPrimitive.RadioItem
class={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50',
className
)}
{value}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.RadioIndicator>
<Circle class="h-2 w-2 fill-current" />
</DropdownMenuPrimitive.RadioIndicator>
</span>
<slot />
</DropdownMenuPrimitive.RadioItem>

View file

@ -0,0 +1,14 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = DropdownMenuPrimitive.SeparatorProps;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Separator
class={cn('-mx-1 my-1 h-px bg-muted', className)}
{...$$restProps}
/>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { cn } from '$lib/utils';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<span class={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...$$restProps}>
<slot />
</span>

View file

@ -0,0 +1,30 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils';
type $$Props = DropdownMenuPrimitive.SubContentProps;
type $$Events = DropdownMenuPrimitive.SubContentEvents;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = {
x: -10,
y: 0
};
export { className as class };
</script>
<DropdownMenuPrimitive.SubContent
{transition}
{transitionConfig}
class={cn(
'z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none',
className
)}
{...$$restProps}
on:keydown
on:focusout
on:pointermove
>
<slot />
</DropdownMenuPrimitive.SubContent>

View file

@ -0,0 +1,32 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { ChevronRight } from 'lucide-svelte';
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
inset?: boolean;
};
type $$Events = DropdownMenuPrimitive.SubTriggerEvents;
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.SubTrigger
class={cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground',
inset && 'pl-8',
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>

View file

@ -0,0 +1,48 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import Item from './dropdown-menu-item.svelte';
import Label from './dropdown-menu-label.svelte';
import Content from './dropdown-menu-content.svelte';
import Shortcut from './dropdown-menu-shortcut.svelte';
import RadioItem from './dropdown-menu-radio-item.svelte';
import Separator from './dropdown-menu-separator.svelte';
import RadioGroup from './dropdown-menu-radio-group.svelte';
import SubContent from './dropdown-menu-sub-content.svelte';
import SubTrigger from './dropdown-menu-sub-trigger.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
const Trigger = DropdownMenuPrimitive.Trigger;
const Group = DropdownMenuPrimitive.Group;
export {
Sub,
Root,
Item,
Label,
Group,
Trigger,
Content,
Shortcut,
Separator,
RadioItem,
SubContent,
SubTrigger,
RadioGroup,
CheckboxItem,
//
Root as DropdownMenu,
Sub as DropdownMenuSub,
Item as DropdownMenuItem,
Label as DropdownMenuLabel,
Group as DropdownMenuGroup,
Content as DropdownMenuContent,
Trigger as DropdownMenuTrigger,
Shortcut as DropdownMenuShortcut,
RadioItem as DropdownMenuRadioItem,
Separator as DropdownMenuSeparator,
RadioGroup as DropdownMenuRadioGroup,
SubContent as DropdownMenuSubContent,
SubTrigger as DropdownMenuSubTrigger,
CheckboxItem as DropdownMenuCheckboxItem
};

View file

@ -0,0 +1,7 @@
import Root from './separator.svelte';
export {
Root,
//
Root as Separator
};

View file

@ -0,0 +1,22 @@
<script lang="ts">
import { Separator as SeparatorPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = SeparatorPrimitive.Props;
let className: $$Props['class'] = undefined;
export let orientation: $$Props['orientation'] = 'horizontal';
export let decorative: $$Props['decorative'] = undefined;
export { className as class };
</script>
<SeparatorPrimitive.Root
class={cn(
'shrink-0 bg-border',
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
className
)}
{orientation}
{decorative}
{...$$restProps}
/>

View file

@ -0,0 +1,106 @@
import { Dialog as SheetPrimitive } from 'bits-ui';
import { tv, type VariantProps } from 'tailwind-variants';
import Portal from './sheet-portal.svelte';
import Overlay from './sheet-overlay.svelte';
import Content from './sheet-content.svelte';
import Header from './sheet-header.svelte';
import Footer from './sheet-footer.svelte';
import Title from './sheet-title.svelte';
import Description from './sheet-description.svelte';
const Root = SheetPrimitive.Root;
const Close = SheetPrimitive.Close;
const Trigger = SheetPrimitive.Trigger;
export {
Root,
Close,
Trigger,
Portal,
Overlay,
Content,
Header,
Footer,
Title,
Description,
//
Root as Sheet,
Close as SheetClose,
Trigger as SheetTrigger,
Portal as SheetPortal,
Overlay as SheetOverlay,
Content as SheetContent,
Header as SheetHeader,
Footer as SheetFooter,
Title as SheetTitle,
Description as SheetDescription
};
export const sheetVariants = tv({
base: 'fixed z-50 gap-4 bg-background p-6 shadow-lg',
variants: {
side: {
top: 'inset-x-0 top-0 border-b',
bottom: 'inset-x-0 bottom-0 border-t',
left: 'inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
right: 'inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm'
}
},
defaultVariants: {
side: 'right'
}
});
export const sheetTransitions = {
top: {
in: {
y: '-100%',
duration: 500,
opacity: 1
},
out: {
y: '-100%',
duration: 300,
opacity: 1
}
},
bottom: {
in: {
y: '100%',
duration: 500,
opacity: 1
},
out: {
y: '100%',
duration: 300,
opacity: 1
}
},
left: {
in: {
x: '-100%',
duration: 500,
opacity: 1
},
out: {
x: '-100%',
duration: 300,
opacity: 1
}
},
right: {
in: {
x: '100%',
duration: 500,
opacity: 1
},
out: {
x: '100%',
duration: 300,
opacity: 1
}
}
};
export type Side = VariantProps<typeof sheetVariants>['side'];

View file

@ -0,0 +1,41 @@
<script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { SheetOverlay, SheetPortal, sheetTransitions, sheetVariants, type Side } from '.';
import { X } from 'lucide-svelte';
import { cn } from '$lib/utils';
import { fly } from 'svelte/transition';
type $$Props = SheetPrimitive.ContentProps & {
side?: Side;
};
let className: $$Props['class'] = undefined;
export let side: $$Props['side'] = 'right';
export { className as class };
export let inTransition: $$Props['inTransition'] = fly;
export let inTransitionConfig: $$Props['inTransitionConfig'] =
sheetTransitions[side ? side : 'right']['in'];
export let outTransition: $$Props['outTransition'] = fly;
export let outTransitionConfig: $$Props['outTransitionConfig'] =
sheetTransitions[side ? side : 'right']['out'];
</script>
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
{inTransition}
{inTransitionConfig}
{outTransition}
{outTransitionConfig}
class={cn(sheetVariants({ side }), className)}
{...$$restProps}
>
<slot />
<SheetPrimitive.Close
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
>
<X class="h-4 w-4" />
<span class="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = SheetPrimitive.DescriptionProps;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<SheetPrimitive.Description class={cn('text-sm text-muted-foreground', className)} {...$$restProps}>
<slot />
</SheetPrimitive.Description>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { cn } from '$lib/utils';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<div
class={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
{...$$restProps}
>
<slot />
</div>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { cn } from '$lib/utils';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<div class={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...$$restProps}>
<slot />
</div>

View file

@ -0,0 +1,21 @@
<script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
import { fade } from 'svelte/transition';
type $$Props = SheetPrimitive.OverlayProps;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = fade;
export let transitionConfig: $$Props['transitionConfig'] = {
duration: 150
};
export { className as class };
</script>
<SheetPrimitive.Overlay
{transition}
{transitionConfig}
class={cn('fixed inset-0 z-50 bg-background/80 backdrop-blur-sm ', className)}
{...$$restProps}
/>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils';
type $$Props = SheetPrimitive.PortalProps;
let className: $$Props['class'] = undefined;
export { className as class };
</script>
<SheetPrimitive.Portal class={cn(className)} {...$$restProps}>
<slot />
</SheetPrimitive.Portal>

Some files were not shown because too many files have changed in this diff Show more