feat: rewrite all to use shadcn-svelte
|
@ -1,3 +1,4 @@
|
|||
/** @type { import("eslint").Linter.FlatConfig } */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
|
|
2
.gitignore
vendored
|
@ -8,5 +8,3 @@ node_modules
|
|||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
.unlighthouse
|
||||
.vercel
|
1
.npmrc
|
@ -1,2 +1 @@
|
|||
engine-strict=true
|
||||
resolution-mode=highest
|
||||
|
|
|
@ -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
|
||||
|
|
11
.prettierrc
|
@ -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
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
module.exports = {
|
||||
'**/*.{js,ts,cjs,svelte,tsx}': [
|
||||
() => 'tsc -p tsconfig.json --noEmit',
|
||||
'eslint --fix',
|
||||
'prettier --write'
|
||||
]
|
||||
};
|
44
package.json
|
@ -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}": [
|
||||
|
|
1422
pnpm-lock.yaml
|
@ -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
|
@ -5,6 +5,7 @@ declare global {
|
|||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
|
31
src/app.html
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
Before Width: | Height: | Size: 375 KiB |
BIN
src/lib/assets/john-travolta.gif
Normal file
After Width: | Height: | Size: 4.9 MiB |
BIN
src/lib/assets/logo-icon.png
Normal file
After Width: | Height: | Size: 2 KiB |
|
@ -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 |
Before Width: | Height: | Size: 677 KiB After Width: | Height: | Size: 677 KiB |
BIN
src/lib/assets/root-me.jpg
Normal file
After Width: | Height: | Size: 480 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -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" /> <svg:style
|
||||
type="text/css"
|
||||
id="style1"> .st0{fill:#003778;} .st1{fill:#003764;} .st2{fill:#0094FF;} </svg:style> <svg:g
|
||||
id="g20"
|
||||
transform="matrix(0.84026685,0,0,0.84026685,79.866575,361.81812)"> <svg:g
|
||||
id="g3"> <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" /> <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" /> <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" /> </svg:g> <svg:g
|
||||
id="g13"> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <svg:path
|
||||
class="st0"
|
||||
d="m 840.4,254.6 h 6.9 v 72.8 h -6.9 z"
|
||||
id="path11" /> <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" /> <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" /> </svg:g> <svg:g
|
||||
id="g18"> <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" /> <svg:path
|
||||
class="st0"
|
||||
d="m 508.2,95.7 h 40.1 v 130.2 h -40.1 z"
|
||||
id="path15" /> <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" /> <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" /> <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" /> </svg:g> <svg:g
|
||||
id="g19"> <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" /> <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" /> </svg:g> </svg:g> <script /></svg:svg>
|
Before Width: | Height: | Size: 4.5 KiB |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
BIN
src/lib/assets/tools/table-plus.png
Normal file
After Width: | Height: | Size: 14 KiB |
|
@ -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;
|
||||
}
|
|
@ -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>
|
||||
© {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>
|
|
@ -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"
|
||||
/>
|
|
@ -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>
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
4
src/lib/components/site/icons/github.svelte
Normal 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 |
16
src/lib/components/site/icons/index.ts
Normal 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
|
||||
};
|
44
src/lib/components/site/icons/logo.svelte
Normal 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 |
|
@ -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 |
4
src/lib/components/site/icons/vercel.svelte
Normal 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 |
33
src/lib/components/site/image-fade.svelte
Normal 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>
|
9
src/lib/components/site/index.ts
Normal 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';
|
35
src/lib/components/site/metadata.svelte
Normal 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>
|
25
src/lib/components/site/mode-toggle.svelte
Normal 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>
|
2
src/lib/components/site/nav/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default as MainNav } from './main-nav.svelte';
|
||||
export { default as MobileNav } from './mobile-nav.svelte';
|
23
src/lib/components/site/nav/main-nav.svelte
Normal 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>
|
23
src/lib/components/site/nav/mobile-link.svelte
Normal 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>
|
64
src/lib/components/site/nav/mobile-nav.svelte
Normal 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>
|
12
src/lib/components/site/page-header/index.ts
Normal 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
|
||||
};
|
|
@ -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>
|
|
@ -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>
|
16
src/lib/components/site/page-header/page-header.svelte
Normal 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>
|
4
src/lib/components/site/projects/index.ts
Normal 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 };
|
45
src/lib/components/site/projects/projects-item.svelte
Normal 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>
|
16
src/lib/components/site/projects/projects.svelte
Normal 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>
|
45
src/lib/components/site/site-footer.svelte
Normal 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">
|
||||
© {new Date().getFullYear()} — {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>
|
51
src/lib/components/site/site-header.svelte
Normal 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>
|
10
src/lib/components/site/tailwind-indicator.svelte
Normal 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>
|
5
src/lib/components/site/timeline/index.ts
Normal 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 };
|
14
src/lib/components/site/timeline/timeline-break.svelte
Normal 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>
|
15
src/lib/components/site/timeline/timeline-item.svelte
Normal 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>
|
25
src/lib/components/site/timeline/timeline.svelte
Normal 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>
|
4
src/lib/components/site/tools/index.ts
Normal 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 };
|
29
src/lib/components/site/tools/tools-item.svelte
Normal 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>
|
12
src/lib/components/site/tools/tools.svelte
Normal 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>
|
11
src/lib/components/ui/.eslintrc
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^\\$\\$(Props|Events|Slots|Generic)$"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
16
src/lib/components/ui/avatar/avatar-fallback.svelte
Normal 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>
|
18
src/lib/components/ui/avatar/avatar-image.svelte
Normal 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}
|
||||
/>
|
18
src/lib/components/ui/avatar/avatar.svelte
Normal 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>
|
13
src/lib/components/ui/avatar/index.ts
Normal 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
|
||||
};
|
25
src/lib/components/ui/button/button.svelte
Normal 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>
|
48
src/lib/components/ui/button/index.ts
Normal 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
|
||||
};
|
13
src/lib/components/ui/card/card-content.svelte
Normal 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>
|
13
src/lib/components/ui/card/card-description.svelte
Normal 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>
|
13
src/lib/components/ui/card/card-footer.svelte
Normal 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>
|
13
src/lib/components/ui/card/card-header.svelte
Normal 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>
|
21
src/lib/components/ui/card/card-title.svelte
Normal 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>
|
16
src/lib/components/ui/card/card.svelte
Normal 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>
|
24
src/lib/components/ui/card/index.ts
Normal 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';
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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}
|
||||
/>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
48
src/lib/components/ui/dropdown-menu/index.ts
Normal 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
|
||||
};
|
7
src/lib/components/ui/separator/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Root from './separator.svelte';
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Separator
|
||||
};
|
22
src/lib/components/ui/separator/separator.svelte
Normal 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}
|
||||
/>
|
106
src/lib/components/ui/sheet/index.ts
Normal 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'];
|
41
src/lib/components/ui/sheet/sheet-content.svelte
Normal 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>
|
13
src/lib/components/ui/sheet/sheet-description.svelte
Normal 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>
|
16
src/lib/components/ui/sheet/sheet-footer.svelte
Normal 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>
|
13
src/lib/components/ui/sheet/sheet-header.svelte
Normal 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>
|
21
src/lib/components/ui/sheet/sheet-overlay.svelte
Normal 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}
|
||||
/>
|
13
src/lib/components/ui/sheet/sheet-portal.svelte
Normal 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>
|