Merge pull request #70 from bartvdbraak/feat/3js-tools

Migrate to Svelte
This commit is contained in:
Bart van der Braak 2023-07-29 15:29:21 +02:00 committed by GitHub
commit bcde770547
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
95 changed files with 2222 additions and 2423 deletions

View file

@ -1,3 +0,0 @@
{
"extends": ["@commitlint/config-conventional"]
}

View file

@ -1,2 +0,0 @@
ignores: ["@types/node", "@types/react-dom", "autoprefixer", "postcss", "@commitlint/config-conventional", "prettier", "@t3-oss/env-nextjs"]
skip-missing: false

View file

@ -1,10 +0,0 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

View file

@ -1,4 +0,0 @@
# -----------------------------------------------------------------------------
# App
# -----------------------------------------------------------------------------
NEXT_PUBLIC_APP_URL=http://localhost:3000

13
.eslintignore Normal file
View file

@ -0,0 +1,13 @@
.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
yarn.lock

30
.eslintrc.cjs Normal file
View file

@ -0,0 +1,30 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

View file

@ -1,3 +0,0 @@
{
"extends": "next/core-web-vitals"
}

View file

@ -1,14 +1,8 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
reviewers:
- "bartvdbraak"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "bartvdbraak"
- "bartvdbraak"

View file

@ -1,4 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base"]
}
}

View file

@ -1,47 +0,0 @@
name: Linting and Dependency Check
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
checks: write
contents: write
jobs:
run-checks:
name: Run checks
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- name: Checkout Git repository
uses: actions/checkout@v3.5.3
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
with:
version: 8.6.2
- name: Setup Node.js
uses: actions/setup-node@v3.7.0
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
- name: Install Node.js dependencies
run: pnpm install --frozen-lockfile
- name: Run linters
uses: wearerequired/lint-action@v2.3.0
with:
eslint: true
prettier: true
- name: Run dependency check
run: npx depcheck

43
.gitignore vendored
View file

@ -1,35 +1,10 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

View file

@ -1,4 +0,0 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit "$1"

View file

@ -1,3 +0,0 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx pretty-quick --staged

2
.npmrc Normal file
View file

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

View file

@ -1,8 +1,13 @@
cache
.cache
package.json
pnpm-lock.yaml
public
.DS_Store
node_modules
.next
.github
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

9
.prettierrc Normal file
View file

@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View file

@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
hellob.art -- a simple portfolio journey created using svelte
Copyright (C) 2023 Bart van der Braak
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
hellob.art Copyright (C) 2023 Bart van der Braak
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View file

@ -28,18 +28,6 @@ To install the project and its dependencies, follow these steps:
pnpm install
```
### Environment Variables
After setting up the required services, you need to set the corresponding environment variables in the `/.env` file. To do this, follow these steps:
1. Make a copy of the `.env.example` file:
```sh-session
cp .env.example .env
```
2. Open the `.env` file in a text editor and populate the values for the services mentioned above.
## Build
To build the project, execute the following command:
@ -54,4 +42,35 @@ To run the project locally, use the following command:
```sh-session
pnpm run dev
# or
pnpm run dev -- --open
```
## Technologies Used
- **Svelte:** The framework used for building this portfolio project.
- **SvelteKit:** The tooling and routing framework for Svelte projects.
- **Tailwind CSS:** A utility-first CSS framework packed with classes.
- **Skeleton:** UI Toolkit for Svelte + Tailwind.
## Deployment
The portfolio is hosted using [Vercel](https://vercel.com). You can access it at [https://hellob.art](https://hellob.art).
## Contributing
I'm open to contributions! If you find any bugs, have suggestions, or want to add something interesting, feel free to open an issue or submit a pull request.
## License
This project is licensed under the GPLv3 License. Feel free to explore, learn, and have fun!
## Get in Touch
Let's connect! You can find me on:
- Website: [hellob.art](https://hellob.art)
- GitHub: [github.com/bartvdbraak](https://github.com/bartvdbraak)
- Email: bart@vanderbraak.nl
Looking forward to hearing from you! 😊

View file

@ -1,33 +0,0 @@
import Link from "next/link";
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
interface MarketingLayoutProps {
children: React.ReactNode;
}
export default async function MarketingLayout({
children,
}: MarketingLayoutProps) {
return (
<div className="flex min-h-screen flex-col">
<header className="container z-40 bg-background">
<div className="flex h-20 items-center justify-between py-6">
<nav>
<Link
href="https://github.com/bartvdbraak"
className={cn(
buttonVariants({ variant: "secondary", size: "sm" }),
"px-4"
)}
>
My GitHub
</Link>
</nav>
</div>
</header>
<main className="flex-1">{children}</main>
</div>
);
}

View file

@ -1,43 +0,0 @@
import Link from "next/link";
import { siteConfig } from "@/config/site";
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
export default function IndexPage() {
return (
<>
<section className="space-y-6 pb-8 pt-6 md:pb-12 md:pt-10 lg:py-32">
<div className="container flex max-w-[64rem] flex-col items-center gap-4 text-center">
<Link
href={siteConfig.links.linkedIn}
className="rounded-2xl bg-muted px-4 py-1.5 text-sm font-medium"
target="_blank"
>
View my LinkedIn profile
</Link>
<h1 className="font-heading text-3xl sm:text-5xl md:text-6xl lg:text-7xl">
hellob.art
</h1>
<p className="max-w-[42rem] leading-normal text-muted-foreground sm:text-xl sm:leading-8">
In progress build of my portfolio using Next.js 13 server
components.
</p>
<div className="space-x-4">
<Link href="/login" className={cn(buttonVariants({ size: "lg" }))}>
Get Started
</Link>
<Link
href={siteConfig.links.github.profile}
target="_blank"
rel="noreferrer"
className={cn(buttonVariants({ variant: "outline", size: "lg" }))}
>
GitHub
</Link>
</div>
</div>
</section>
</>
);
}

View file

@ -1,98 +0,0 @@
import { Inter as FontSans } from "next/font/google";
import localFont from "next/font/local";
import "@/styles/globals.css";
import { siteConfig } from "@/config/site";
import { cn } from "@/lib/utils";
import { Analytics } from "@vercel/analytics/react";
import { TailwindIndicator } from "@/components/tailwind-indicator";
import { ThemeProvider } from "@/components/theme-provider";
export const metadata = {
title: {
default: siteConfig.name,
template: `%s | ${siteConfig.name}`,
},
metadataBase: new URL(`https://${siteConfig.url}}`),
description: siteConfig.description,
keywords: [
"Portfolio",
"Next.js",
"React",
"Azure",
"Kubernetes",
"DevOps",
"Python",
],
authors: [
{
name: "Bart van der Braak",
url: siteConfig.url,
},
],
creator: "bartvdbraak",
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "white" },
{ media: "(prefers-color-scheme: dark)", color: "black" },
],
openGraph: {
type: "website",
locale: "en_US",
url: siteConfig.url,
title: siteConfig.name,
description: siteConfig.description,
siteName: siteConfig.name,
},
twitter: {
card: "summary_large_image",
title: siteConfig.name,
description: siteConfig.description,
images: [`${siteConfig.url}/og.jpg`],
creator: "@bartvdbraak",
},
icons: {
icon: "/favicon.ico",
shortcut: "/favicon-16x16.png",
apple: "/apple-touch-icon.png",
},
manifest: `${siteConfig.url}/site.webmanifest`,
};
interface RootLayoutProps {
children: React.ReactNode;
}
const fontSans = FontSans({
subsets: ["latin"],
variable: "--font-sans",
});
const fontHeading = localFont({
src: "../assets/fonts/CalSans-SemiBold.woff2",
variable: "--font-heading",
});
interface RootLayoutProps {
children: React.ReactNode;
}
export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="en" suppressHydrationWarning>
<head />
<body
className={cn(
"min-h-screen bg-background font-sans antialiased",
fontSans.variable,
fontHeading.variable
)}
>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
<TailwindIndicator />
</ThemeProvider>
<Analytics />
</body>
</html>
);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,25 +0,0 @@
export function TailwindIndicator() {
if (process.env.NODE_ENV === "production") return null;
const breakpoints = [
{ name: "xs", css: "block sm:hidden" },
{
name: "sm",
css: "hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden",
},
{ name: "md", css: "hidden md:block lg:hidden xl:hidden 2xl:hidden" },
{ name: "lg", css: "hidden lg:block xl:hidden 2xl:hidden" },
{ name: "xl", css: "hidden xl:block 2xl:hidden" },
{ name: "2xl", css: "hidden 2xl:block" },
];
return (
<div className="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">
{breakpoints.map((breakpoint) => (
<div key={breakpoint.name} className={breakpoint.css}>
{breakpoint.name}
</div>
))}
</div>
);
}

View file

@ -1,9 +0,0 @@
"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { ThemeProviderProps } from "next-themes/dist/types";
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

View file

@ -1,51 +0,0 @@
import * as React from "react";
import { VariantProps, cva } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
{
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 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: "underline-offset-4 hover:underline text-primary",
},
size: {
default: "h-10 py-2 px-4",
sm: "h-9 px-3 rounded-md",
lg: "h-11 px-8 rounded-md",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = "Button";
export { Button, buttonVariants };

View file

@ -1,8 +0,0 @@
export const navigationConfig = {
mainNav: [
{
title: "Projects",
href: "/#projects",
},
],
};

View file

@ -1,15 +0,0 @@
import { env } from "@/env.mjs";
export const siteConfig = {
name: "hellob.art",
description: "a simple portfolio made by bart van der braak.",
url: env.NEXT_PUBLIC_APP_URL || "https://hellob.art",
ogImage: "https://hellob.art/og.jpg",
links: {
linkedIn: "https://linkedin.com/in/bartvdbraak",
github: {
project: "https://github.com/bartvdbraak/hellob.art",
profile: "https://github.com/bartvdbraak",
},
},
};

15
env.mjs
View file

@ -1,15 +0,0 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
// This is optional because it's only used in development.
// See https://next-auth.js.org/deployment.
},
client: {
NEXT_PUBLIC_APP_URL: z.string().min(1),
},
runtimeEnv: {
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
},
});

View file

@ -1,21 +0,0 @@
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { env } from "@/env.mjs";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function formatDate(input: string | number): string {
const date = new Date(input);
return date.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
});
}
export function absoluteUrl(path: string) {
return `${env.NEXT_PUBLIC_APP_URL}${path}`;
}

View file

@ -1,6 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};
module.exports = nextConfig;

View file

@ -1,46 +1,42 @@
{
"name": "hellob.art",
"version": "0.1.0",
"private": true,
"author": {
"name": "Bart van der Braak",
"url": "https://hellob.art"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prepare": "husky install",
"typecheck": "tsc --noEmit",
"format:write": "prettier . --write --cache",
"format:check": "prettier . --check --cache"
},
"dependencies": {
"@t3-oss/env-nextjs": "^0.6.0",
"@tailwindcss/typography": "^0.5.9",
"@types/node": "20.4.2",
"@types/react": "18.2.15",
"@types/react-dom": "18.2.7",
"@vercel/analytics": "^1.0.1",
"autoprefixer": "10.4.14",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"eslint": "8.45.0",
"eslint-config-next": "13.4.10",
"next": "13.4.10",
"next-themes": "^0.2.1",
"postcss": "8.4.26",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwind-merge": "^1.14.0",
"tailwindcss": "3.3.3",
"tailwindcss-animate": "^1.0.6",
"typescript": "5.1.6"
},
"devDependencies": {
"@commitlint/config-conventional": "^17.6.6",
"husky": "^8.0.3",
"prettier": "2.8.8"
}
"name": "hellob.art",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@skeletonlabs/skeleton": "^1.10.0",
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
"postcss": "^8.4.24",
"postcss-load-config": "^4.0.1",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tailwindcss": "^3.3.2",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
},
"type": "module",
"dependencies": {
"@threlte/core": "6.0.0-next.11",
"@threlte/extras": "5.0.0-next.16",
"@types/three": "^0.154.0",
"three": "^0.155.0"
}
}

File diff suppressed because it is too large Load diff

12
postcss.config.cjs Normal file
View file

@ -0,0 +1,12 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [
tailwindcss(),
autoprefixer
]
};
module.exports = config;

View file

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,9 +0,0 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4 12C5.65685 12 7 10.6569 7 9C7 7.34315 5.65685 6 4 6C2.34315 6 1 7.34315 1 9C1 10.6569 2.34315 12 4 12Z"
stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M1 4V12" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M9 1L8.36667 2.93333C8.33424 3.03374 8.27844 3.12501 8.20386 3.19965C8.12928 3.27429 8.03805 3.33016 7.93767 3.36267L6 4L7.93333 4.63333C8.03374 4.66576 8.12501 4.72156 8.19965 4.79614C8.27429 4.87072 8.33016 4.96195 8.36267 5.06233L9 7L9.63333 5.06667C9.66576 4.96626 9.72156 4.87499 9.79614 4.80035C9.87072 4.72571 9.96195 4.66984 10.0623 4.63733L12 4L10.0667 3.36667C9.96626 3.33424 9.87499 3.27844 9.80035 3.20386C9.72571 3.12928 9.66984 3.03805 9.63733 2.93767L9 1Z"
stroke="#EAAF17" stroke-linecap="round" stroke-linejoin="round" />
</svg>

Before

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

12
src/app.d.ts vendored Normal file
View file

@ -0,0 +1,12 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}
export {};

19
src/app.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<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="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
</body>
</html>

4
src/app.postcss Normal file
View file

@ -0,0 +1,4 @@
html,
body {
@apply h-full overflow-hidden
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

View file

@ -0,0 +1 @@
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

13
src/lib/calculate-age.ts Normal file
View file

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

View file

@ -0,0 +1,30 @@
<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-2">
<p>
<a href="https://svelte.dev/" target="_blank" rel="noopener noreferrer">
Made with <Svelte />
</a>
|
<a href="https://vercel.com/" target="_blank" rel="noopener noreferrer">
Hosted on <Vercel />
</a>
|
<a href="https://github.com/bartvdbraak/hellob.art" target="_blank" rel="noopener noreferrer">
Source code at <GitHub />
</a>
</p>
<p>
Licensed under GPLv3 &mdash; &copy; {new Date().getFullYear()} hellob.art &mdash; Bart van der Braak
</p>
</footer>
<style>
:global(.inline-svg) {
display: inline;
}
</style>

View file

@ -0,0 +1,34 @@
<script lang="ts">
import { AppBar, LightSwitch, ProgressBar, drawerStore } from '@skeletonlabs/skeleton';
import GitHub from './icons/GitHub.svelte';
import Hamburger from './icons/Hamburger.svelte';
export let progress: number;
function drawerOpen(): void {
drawerStore.open();
}
</script>
<AppBar>
<svelte:fragment slot="lead">
<button class="md:hidden btn btn-sm mr-4" on:click={drawerOpen}>
<span>
<Hamburger />
</span>
</button>
<img src="./icon.svg" alt="Logo" srcset="" class="pr-2" />
<code class="code">hellob.art</code>
</svelte:fragment>
<svelte:fragment slot="trail">
<a
href="https://github.com/bartvdbraak/hellob.art"
target="_blank"
rel="noopener noreferrer"
class="btn-icon variant-primary"><GitHub /></a
>
<LightSwitch />
</svelte:fragment>
</AppBar>
<ProgressBar label="Progress Bar" value={progress} max={100} rounded="" />

View file

@ -0,0 +1,21 @@
<script lang="ts">
import { page } from '$app/stores';
import { drawerStore } from '@skeletonlabs/skeleton';
$: classesActive = (href: string) => (href === $page.url.pathname ? '!bg-primary-500' : '');
export let routes: { url: string; label: string }[];
function drawerClose(): void {
drawerStore.close();
}
</script>
<nav class="list-nav p-4">
<ul>
{#each routes as route}
<li>
<a class="{classesActive(route.url)}" href={route.url} on:click={drawerClose}>{route.label}</a>
</li>
{/each}
</ul>
</nav>

View file

@ -0,0 +1,41 @@
<script>
import { Avatar } from '@skeletonlabs/skeleton';
export let link = '';
export let headerImage = '';
export let headerSubTitle = '';
export let title = '';
export let description = '';
export let logo = '';
/**
* @type {any[]}
*/
export let contributors = [];
export let date = '';
</script>
<a class="card bg-initial card-hover overflow-hidden" href={link}>
<header>
<img src={headerImage} class="bg-black/50 w-full aspect-[21/9] object-cover" alt="Post" />
</header>
<div class="p-4 space-y-4">
<h6 class="h6">{headerSubTitle}</h6>
<h3 class="h3" data-toc-ignore>{title}</h3>
<article>
<p>
{description}
</p>
</article>
</div>
<hr class="opacity-50" />
<footer class="p-4 flex justify-start items-center space-x-4">
<Avatar src={logo} width="w-8" />
<div class="flex-auto flex justify-between items-center">
{#each contributors as contributor}
<Avatar src={contributor.imageSrc} width="w-8" />
{/each}
<small>{new Date(date).toLocaleDateString()}</small>
</div>
</footer>
</a>

View file

@ -0,0 +1,105 @@
<script lang="ts">
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import * as THREE from 'three';
let camera: THREE.PerspectiveCamera,
scene: THREE.Scene,
renderer: THREE.WebGLRenderer,
cube: THREE.Mesh<THREE.BoxGeometry, THREE.MeshBasicMaterial>;
const renderContainerId = 'render';
const toolsData = [
{ name: 'Git', info: 'Short note about Git and its usage.' },
{ name: 'DBeaver', info: 'Short note about DBeaver and its usage.' },
{ name: 'Notion', info: 'Short note about Notion and its usage.' },
{ name: 'Insomnia', info: 'Short note about Insomnia and its usage.' },
{ name: 'Cyberduck', info: 'Short note about Cyberduck and its usage.' },
{ name: 'Mullvad VPN', info: 'Short note about Mullvad VPN and its usage.' },
{ name: 'Maccy', info: 'Short note about Maccy and its usage.' }
];
onMount(() => {
init();
addTools();
animate();
});
const init = () => {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
const renderContainer = document.getElementById(renderContainerId);
if (renderContainer) {
renderContainer.appendChild(renderer.domElement);
}
camera.position.z = 5;
};
const addTool = (name: string, x: number, y: number, z: number) => {
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
cube = new THREE.Mesh(geometry, material);
cube.position.set(x, y, z);
scene.add(cube);
cube.userData.name = name;
cube.userData.info = toolsData.find((tool) => tool.name === name)?.info || '';
cube.addEventListener('click', () => {
alert(`${cube.userData.name}: ${cube.userData.info}`);
});
};
const addTools = () => {
addTool('Git', -2, 0, 0);
addTool('DBeaver', 0, 0, 0);
addTool('Notion', 2, 0, 0);
addTool('Insomnia', -2, 2, 0);
addTool('Cyberduck', 0, 2, 0);
addTool('Mullvad VPN', 2, 2, 0);
addTool('Maccy', 0, 4, 0);
};
const render = () => {
renderer.clear();
renderer.render(scene, camera);
};
const isMeshType = (object?: THREE.Object3D): object is THREE.Mesh => {
return object?.type === 'Mesh';
};
const animate = () => {
if (!browser) {
return;
}
requestAnimationFrame(animate);
scene.traverse((object: THREE.Object3D) => {
if (isMeshType(object) && object.isMesh) {
object.rotation.x += 0.005;
object.rotation.y += 0.005;
}
});
render();
};
</script>
<style>
#render {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
<section id="render" />

View file

@ -0,0 +1,29 @@
<!--
Auto-generated by: https://github.com/threlte/threlte/tree/main/packages/gltf
Command: npx @threlte/gltf@1.0.0-next.13 ./src/lib/assets/vectors/github.glb --transform
-->
<script>
import { Group } from 'three';
import { T, forwardEventHandlers } from '@threlte/core';
import { useGltf } from '@threlte/extras';
export const ref = new Group();
const gltf = useGltf('./github-transformed.glb', { useDraco: true });
const component = forwardEventHandlers();
</script>
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
{#await gltf}
<slot name="fallback" />
{:then gltf}
<T.Mesh geometry={gltf.nodes.Github_Mesh.geometry}
><T.MeshPhysicalMaterial color={[0,0,0]} /></T.Mesh
>
{:catch error}
<slot name="error" {error} />
{/await}
<slot {ref} />
</T>

View file

@ -0,0 +1 @@
<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"></path></svg>

After

Width:  |  Height:  |  Size: 517 B

View file

@ -0,0 +1 @@
<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>

After

Width:  |  Height:  |  Size: 326 B

View file

@ -0,0 +1 @@
<svg class="inline-svg" stroke="currentColor" fill="currentColor" stroke-width="0" role="img" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><title></title><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"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1 @@
<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><path d="M3 19h18l-9 -15z"></path></svg>

After

Width:  |  Height:  |  Size: 299 B

45
src/lib/extrude-svg.ts Normal file
View file

@ -0,0 +1,45 @@
import type * as THREE from 'three';
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader';
import type { SVGResult, SVGResultPaths } from 'three/examples/jsm/loaders/SVGLoader';
import { Mesh } from 'three/src/objects/Mesh';
import { Group } from 'three/src/objects/Group';
import { MeshNormalMaterial } from 'three/src/materials/MeshNormalMaterial';
import { ExtrudeGeometry } from 'three/src/geometries/ExtrudeGeometry';
/**
* Parses the provided SVG markup and extrudes it into a 3D model using THREE.js.
* @param svgMarkup - SVG markup to extrude.
* @return Group containing all of the extruded SVG paths.
* @throws Error If the SVG markup is empty.
*/
export function extrudeSvg(svgMarkup: string): Group {
if (!svgMarkup) {
throw new Error('SVG markup is empty');
}
const svgData: SVGResult = new SVGLoader().parse(svgMarkup);
const material: MeshNormalMaterial = new MeshNormalMaterial();
const svgGroup: Mesh[][] = svgData.paths.map(createShapeFromPath);
const group = new Group();
svgGroup.flat().forEach(mesh => group.add(mesh));
return group;
function createShapeFromPath(path: SVGResultPaths): Mesh[] {
const shapes: THREE.Shape[] = path.toShapes(true);
return shapes.map(shape => extrudeShape(shape, material));
}
function extrudeShape(shape: THREE.Shape, material: MeshNormalMaterial): Mesh {
const geometry = new ExtrudeGeometry(shape, {
depth: 20,
bevelEnabled: false
});
return new Mesh(geometry, material);
}
}

47
src/routes/+layout.svelte Normal file
View file

@ -0,0 +1,47 @@
<script lang="ts">
import '../theme.postcss';
import '@skeletonlabs/skeleton/styles/skeleton.css';
import '../app.postcss';
import { AppShell, Drawer, ProgressBar, drawerStore } from '@skeletonlabs/skeleton';
import Footer from '../lib/components/Footer.svelte';
import Navigation from '../lib/components/Navigation.svelte';
import Header from '$lib/components/Header.svelte';
let routes = [
{ url: '/', label: 'Home' },
{ url: '/projects', label: 'Projects' },
{ url: '/tools', label: 'Tools' },
{ url: '/blog', label: 'Blog' }
];
let progress = 0;
function handleScroll(event: Event) {
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget as HTMLElement;
progress = (scrollTop / (scrollHeight - clientHeight)) * 100;
}
</script>
<Drawer width="w-[280px] md:w-[480px]">
<Navigation {routes} />
</Drawer>
<AppShell
slotSidebarLeft="w-0 md:w-52"
on:scroll={handleScroll}
>
<svelte:fragment slot="header">
<Header {progress} />
</svelte:fragment>
<svelte:fragment slot="sidebarLeft">
<Navigation {routes} />
</svelte:fragment>
<!-- Router Slot -->
<div class="container p-10 mx-auto">
<slot />
</div>
<!-- ---- / ---- -->
<svelte:fragment slot="pageFooter">
<Footer />
</svelte:fragment>
</AppShell>

63
src/routes/+page.svelte Normal file
View file

@ -0,0 +1,63 @@
<script lang='ts'>
import { calculateAge } from '$lib/calculate-age';
</script>
<svelte:head>
<title>hellob.art &mdash; home</title>
</svelte:head>
<main class="container mx-auto px-4 py-8 text-left">
<h2 class="text-3xl font-bold mb-4">About Me</h2>
<p class="text-lg leading-relaxed mb-8">
Welcome to my homepage! I'm a passionate DevOps engineer based in Zaandam, Netherlands. At {calculateAge("1994-10-18")}
years old, I've already gathered a wealth of experience and expertise in the world of
technology. From programming in Python, Javascript, and Bash to utilizing cutting-edge
technologies like Terraform, Bicep, and Kubernetes, I've honed my skills to drive efficient and
innovative solutions. My journey in the tech industry began during my Information Sciences
studies, where I fell in love with data-driven projects and statistical learning. This passion
led me to explore languages like Python and LaTeX, enabling me to bring ideas to life through
powerful data management and visualization.
</p>
<h2 class="text-3xl font-bold mb-4">Empowering the Cloud with Azure</h2>
<p class="text-lg leading-relaxed mb-8">
My career took off when I joined Triple as a DevOps Engineer. At Triple, I've embraced the world
of Azure and Azure DevOps, mastering the intricacies of cloud architecture and deployment.
Holding certifications like AZ-104 and CKA has further solidified my expertise, empowering me to
build and manage robust, scalable, and secure cloud environments. My proficiency in
containerization and Kubernetes has allowed me to take application development to new heights,
ensuring seamless and efficient deployment at scale.
</p>
<h2 class="text-3xl font-bold mb-4">Solving Problems with Code and Automation</h2>
<p class="text-lg leading-relaxed mb-8">
As a DevOps engineer, I thrive on solving complex challenges with the power of code and
automation. My passion for streamlining workflows led me to create internal tooling using APIs,
boosting productivity for myself and my colleagues. Outside of work, I enjoy taking on side
projects that push my boundaries, expanding my skill set, and exploring new technologies. I
strongly believe that innovation and continuous learning are key drivers of success in the
ever-evolving tech landscape.
</p>
<h2 class="text-3xl font-bold mb-4">Cat Lover and Whiskey Enthusiast</h2>
<p class="text-lg leading-relaxed mb-8">
When I'm not busy crafting technological solutions, you'll often find me indulging in two of my
favorite passions: cats and whiskey. There's something special about the companionship of cats,
and their playful antics never fail to bring joy to my day. As for whiskey, I appreciate the
intricate flavors and the artistry behind its production. I find both interests to be a
delightful way to unwind and recharge my creative energies.
</p>
<h2 class="text-3xl font-bold mb-4">Let's Connect</h2>
<p class="text-lg leading-relaxed">
I'm always eager to collaborate on exciting projects and explore new opportunities. Whether it's
discussing data-driven ideas, cloud architecture, or just sharing cute cat pictures, I'd love to
connect with like-minded individuals. Feel free to reach out to me through the provided contact
information. Let's work together to create something extraordinary!
</p>
</main>

View file

@ -0,0 +1,7 @@
<svelte:head>
<title>hellob.art &mdash; blog</title>
</svelte:head>
<main class="container mx-auto px-4 py-8 text-left">
<h2 class="text-3xl font-bold mb-8">Blog posts</h2>
</main>

0
src/routes/blog/[slug]/$types.d.ts vendored Normal file
View file

View file

@ -0,0 +1,11 @@
<script>
/** @type {import('./$types').PageData} */
export let data;
</script>
<svelte:head>
<title>hellob.art &mdash; {data.title}</title>
</svelte:head>
<!-- <h1>{data.title}</h1>
<div>{@html data.content}</div> -->

View file

@ -0,0 +1,56 @@
<script>
import videowallImage from '$lib/assets/videowall-irl.jpeg';
import tripleLogo from '$lib/assets/triple-logo.png';
import zaantjeImage from '$lib/assets/zaantje-3d.png';
import zaantjeLogo from '$lib/assets/zaantje-logo.png';
import ProjectCard from '$lib/components/ProjectCard.svelte';
let projects = [
{
id: 1,
link: '#',
headerImage: videowallImage,
headerSubTitle: 'Internal Project',
title: 'Videowall',
description: `An internal application to control an impressive 6x5 monitor setup with a user-friendly
frontend built on Next.js and a powerful backend developed in Golang.`,
logo: tripleLogo,
contributors: [],
date: '2021'
},
{
id: 2,
link: 'https://zaantje.com',
headerImage: zaantjeImage,
headerSubTitle: 'Personal Project',
title: 'Zaantje',
description: `A SPA crafted with Nuxt.js and Vue.js, backed by Sanity CMS, taking you
on a virtual tour of Zaandam, showcasing locations of famous music videos.`,
logo: zaantjeLogo,
contributors: [],
date: '2020'
}
];
</script>
<svelte:head>
<title>hellob.art &mdash; projects</title>
</svelte:head>
<main class="container mx-auto px-4 py-8 text-left">
<h2 class="text-3xl font-bold mb-8">My Projects</h2>
<div class="w-full text-token grid grid-cols-1 md:grid-cols-2 gap-4">
{#each projects as project}
<ProjectCard
link={project.link}
headerImage={project.headerImage}
headerSubTitle={project.headerSubTitle}
title={project.title}
description={project.description}
logo={project.logo}
contributors={project.contributors}
date={project.date}
/>
{/each}
</div>
</main>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { Canvas } from '@threlte/core';
import Scene from './Scene.svelte';
import Github3d from '$lib/components/gltf/Github3d.svelte';
</script>
<svelte:head>
<title>hellob.art &mdash; tools</title>
</svelte:head>
<main class="container mx-auto px-4 py-8 text-left">
<h2 class="text-3xl font-bold mb-8">Tools</h2>
<Canvas>
<Scene />
<Github3d />
</Canvas>
</main>

View file

@ -0,0 +1,42 @@
<script>
import Github3d from '$lib/components/gltf/Github3d.svelte';
import { T, useFrame } from '@threlte/core';
import { interactivity } from '@threlte/extras';
import { spring } from 'svelte/motion';
interactivity();
const scale = spring(1);
let rotation = 0;
useFrame((_state, delta) => {
rotation += delta;
});
</script>
<T.PerspectiveCamera
makeDefault
position={[10, 10, 10]}
on:create={({ ref }) => {
ref.lookAt(0, 1, 0);
}}
/>
<T.Mesh
rotation.y={rotation}
position.y={1}
scale={$scale}
on:pointerenter={() => scale.set(1.5)}
on:pointerleave={() => scale.set(1)}
on:click={() => scale.set(3)}
>
<T.BoxGeometry args={[1, 2, 1]} />
<T.MeshBasicMaterial color={[0, 0, 0]} />
</T.Mesh>
<Github3d
position={[0, 0, 0]}
scale={$scale}
on:pointerenter={() => scale.set(1.5)}
on:pointerleave={() => scale.set(1)}
on:click={() => scale.set(3)}
/>

98
src/theme.postcss Normal file
View file

@ -0,0 +1,98 @@
:root {
/* =~= Theme Properties =~= */
--theme-font-family-base: system-ui;
--theme-font-family-heading: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--theme-font-color-base: 0 0 0;
--theme-font-color-dark: 255 255 255;
--theme-rounded-base: 4px;
--theme-rounded-container: 12px;
--theme-border-base: 2px;
/* =~= Theme On-X Colors =~= */
--on-primary: 0 0 0;
--on-secondary: 255 255 255;
--on-tertiary: 0 0 0;
--on-success: 0 0 0;
--on-warning: 0 0 0;
--on-error: 255 255 255;
--on-surface: 255 255 255;
/* =~= Theme Colors =~= */
/* primary | #67a1ba */
--color-primary-50: 232 241 245; /* ⬅ #e8f1f5 */
--color-primary-100: 225 236 241; /* ⬅ #e1ecf1 */
--color-primary-200: 217 232 238; /* ⬅ #d9e8ee */
--color-primary-300: 194 217 227; /* ⬅ #c2d9e3 */
--color-primary-400: 149 189 207; /* ⬅ #95bdcf */
--color-primary-500: 103 161 186; /* ⬅ #67a1ba */
--color-primary-600: 93 145 167; /* ⬅ #5d91a7 */
--color-primary-700: 77 121 140; /* ⬅ #4d798c */
--color-primary-800: 62 97 112; /* ⬅ #3e6170 */
--color-primary-900: 50 79 91; /* ⬅ #324f5b */
/* secondary | #4F46E5 */
--color-secondary-50: 229 227 251; /* ⬅ #e5e3fb */
--color-secondary-100: 220 218 250; /* ⬅ #dcdafa */
--color-secondary-200: 211 209 249; /* ⬅ #d3d1f9 */
--color-secondary-300: 185 181 245; /* ⬅ #b9b5f5 */
--color-secondary-400: 132 126 237; /* ⬅ #847eed */
--color-secondary-500: 79 70 229; /* ⬅ #4F46E5 */
--color-secondary-600: 71 63 206; /* ⬅ #473fce */
--color-secondary-700: 59 53 172; /* ⬅ #3b35ac */
--color-secondary-800: 47 42 137; /* ⬅ #2f2a89 */
--color-secondary-900: 39 34 112; /* ⬅ #272270 */
/* tertiary | #0EA5E9 */
--color-tertiary-50: 219 242 252; /* ⬅ #dbf2fc */
--color-tertiary-100: 207 237 251; /* ⬅ #cfedfb */
--color-tertiary-200: 195 233 250; /* ⬅ #c3e9fa */
--color-tertiary-300: 159 219 246; /* ⬅ #9fdbf6 */
--color-tertiary-400: 86 192 240; /* ⬅ #56c0f0 */
--color-tertiary-500: 14 165 233; /* ⬅ #0EA5E9 */
--color-tertiary-600: 13 149 210; /* ⬅ #0d95d2 */
--color-tertiary-700: 11 124 175; /* ⬅ #0b7caf */
--color-tertiary-800: 8 99 140; /* ⬅ #08638c */
--color-tertiary-900: 7 81 114; /* ⬅ #075172 */
/* success | #84cc16 */
--color-success-50: 237 247 220; /* ⬅ #edf7dc */
--color-success-100: 230 245 208; /* ⬅ #e6f5d0 */
--color-success-200: 224 242 197; /* ⬅ #e0f2c5 */
--color-success-300: 206 235 162; /* ⬅ #ceeba2 */
--color-success-400: 169 219 92; /* ⬅ #a9db5c */
--color-success-500: 132 204 22; /* ⬅ #84cc16 */
--color-success-600: 119 184 20; /* ⬅ #77b814 */
--color-success-700: 99 153 17; /* ⬅ #639911 */
--color-success-800: 79 122 13; /* ⬅ #4f7a0d */
--color-success-900: 65 100 11; /* ⬅ #41640b */
/* warning | #EAB308 */
--color-warning-50: 252 244 218; /* ⬅ #fcf4da */
--color-warning-100: 251 240 206; /* ⬅ #fbf0ce */
--color-warning-200: 250 236 193; /* ⬅ #faecc1 */
--color-warning-300: 247 225 156; /* ⬅ #f7e19c */
--color-warning-400: 240 202 82; /* ⬅ #f0ca52 */
--color-warning-500: 234 179 8; /* ⬅ #EAB308 */
--color-warning-600: 211 161 7; /* ⬅ #d3a107 */
--color-warning-700: 176 134 6; /* ⬅ #b08606 */
--color-warning-800: 140 107 5; /* ⬅ #8c6b05 */
--color-warning-900: 115 88 4; /* ⬅ #735804 */
/* error | #d31922 */
--color-error-50: 248 221 222; /* ⬅ #f8ddde */
--color-error-100: 246 209 211; /* ⬅ #f6d1d3 */
--color-error-200: 244 198 200; /* ⬅ #f4c6c8 */
--color-error-300: 237 163 167; /* ⬅ #eda3a7 */
--color-error-400: 224 94 100; /* ⬅ #e05e64 */
--color-error-500: 211 25 34; /* ⬅ #d31922 */
--color-error-600: 190 23 31; /* ⬅ #be171f */
--color-error-700: 158 19 26; /* ⬅ #9e131a */
--color-error-800: 127 15 20; /* ⬅ #7f0f14 */
--color-error-900: 103 12 17; /* ⬅ #670c11 */
/* surface | #063142 */
--color-surface-50: 218 224 227; /* ⬅ #dae0e3 */
--color-surface-100: 205 214 217; /* ⬅ #cdd6d9 */
--color-surface-200: 193 204 208; /* ⬅ #c1ccd0 */
--color-surface-300: 155 173 179; /* ⬅ #9badb3 */
--color-surface-400: 81 111 123; /* ⬅ #516f7b */
--color-surface-500: 6 49 66; /* ⬅ #063142 */
--color-surface-600: 5 44 59; /* ⬅ #052c3b */
--color-surface-700: 5 37 50; /* ⬅ #052532 */
--color-surface-800: 4 29 40; /* ⬅ #041d28 */
--color-surface-900: 3 24 32; /* ⬅ #031820 */
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
static/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

9
static/browserconfig.xml Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

BIN
static/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

BIN
static/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

9
static/icon.svg Normal file
View file

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<radialGradient id="myGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" stop-color="#314755" />
<stop offset="100%" stop-color="#26a0da" />
</radialGradient>
</defs>
<path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 13a3 3 0 1 1 3-3 3 3 0 0 1-3 3zm2.75-7.17A5 5 0 0 0 13 7.1v-3a7.94 7.94 0 0 1 3.9 1.62zM11 7.1a5 5 0 0 0-1.75.73L7.1 5.69A7.94 7.94 0 0 1 11 4.07zM7.83 9.25A5 5 0 0 0 7.1 11h-3a7.94 7.94 0 0 1 1.59-3.9zM7.1 13a5 5 0 0 0 .73 1.75L5.69 16.9A7.94 7.94 0 0 1 4.07 13zm2.15 3.17a5 5 0 0 0 1.75.73v3a7.94 7.94 0 0 1-3.9-1.62zm3.75.73a5 5 0 0 0 1.75-.73l2.15 2.14a7.94 7.94 0 0 1-3.9 1.62zm3.17-2.15A5 5 0 0 0 16.9 13h3a7.94 7.94 0 0 1-1.62 3.9zM16.9 11a5 5 0 0 0-.73-1.75l2.14-2.15a7.94 7.94 0 0 1 1.62 3.9z" fill="url(#myGradient)"></path>
</svg>

After

Width:  |  Height:  |  Size: 901 B

BIN
static/mstile-150x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,47 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3378 6415 c-2 -2 -46 -5 -98 -9 -52 -3 -117 -8 -145 -12 -49 -6
-271 -47 -310 -57 -11 -3 -33 -8 -50 -12 -217 -51 -536 -183 -760 -316 -336
-198 -660 -494 -881 -804 -117 -164 -239 -379 -304 -535 -17 -41 -37 -88 -45
-105 -40 -88 -121 -364 -144 -490 -18 -96 -20 -107 -30 -175 -33 -208 -33
-561 -1 -795 88 -626 371 -1202 810 -1645 142 -143 172 -170 290 -261 349
-272 768 -465 1196 -553 65 -14 142 -28 169 -31 28 -4 61 -8 75 -11 134 -23
592 -23 705 1 11 2 39 7 63 9 173 21 518 112 647 171 17 7 54 23 84 35 145 57
438 224 586 335 108 80 232 190 345 305 659 668 949 1595 794 2535 -158 957
-824 1801 -1723 2184 -290 124 -569 195 -891 226 -63 7 -377 14 -382 10z
m-168 -1045 l0 -439 -42 -11 c-146 -37 -298 -99 -411 -167 -32 -19 -60 -34
-62 -32 -2 2 -144 143 -314 313 l-311 308 78 56 c245 176 539 307 847 379 42
9 171 31 193 32 l22 1 0 -440z m710 414 c311 -48 715 -226 987 -435 23 -17 22
-17 -256 -290 -154 -151 -295 -289 -314 -308 l-35 -33 -60 36 c-107 65 -271
131 -409 166 l-43 11 0 436 0 436 48 -7 c26 -4 63 -9 82 -12z m-1931 -1187
c157 -159 288 -290 290 -292 2 -2 -13 -31 -33 -64 -64 -104 -143 -297 -161
-389 -13 -68 31 -62 -452 -62 l-435 0 6 54 c4 29 9 64 11 77 3 13 9 49 15 79
9 52 21 95 57 215 28 92 84 229 140 340 54 109 79 150 177 297 l51 77 24 -22
c13 -12 152 -152 310 -310z m3476 153 c122 -188 227 -424 284 -641 29 -109 60
-264 61 -301 0 -17 -28 -18 -440 -18 l-439 0 -11 43 c-34 137 -101 302 -166
409 -20 32 -35 61 -33 63 2 2 143 144 313 314 l308 311 31 -43 c17 -23 58 -85
92 -137z m-1845 -384 c172 -21 347 -106 484 -235 359 -340 358 -920 -1 -1262
-350 -334 -903 -322 -1234 27 -159 169 -242 377 -243 609 0 356 231 687 569
814 33 13 67 24 75 26 157 32 224 36 350 21z m-1540 -1199 c40 -153 98 -297
167 -410 19 -32 34 -60 32 -62 -2 -2 -142 -143 -311 -313 l-308 -310 -29 36
c-53 68 -158 237 -206 331 -118 237 -202 499 -232 728 l-5 42 441 0 440 0 11
-42z m3720 19 c0 -39 -39 -224 -70 -333 -71 -247 -193 -497 -346 -710 l-51
-72 -269 273 c-148 151 -286 292 -308 314 l-38 40 35 59 c67 111 128 260 167
410 l11 42 434 0 435 0 0 -23z m-3041 -940 c111 -67 264 -129 409 -166 l42
-11 0 -434 c0 -493 11 -443 -91 -425 -30 5 -69 12 -88 15 -153 26 -448 130
-598 212 -117 63 -143 79 -208 121 -38 25 -88 61 -111 79 l-41 33 116 114
c238 235 506 496 510 496 2 0 29 -15 60 -34z m1861 -280 l310 -309 -62 -44
c-69 -48 -235 -153 -243 -153 -3 0 -22 -11 -43 -23 -53 -33 -260 -120 -371
-156 -105 -34 -288 -77 -369 -87 l-52 -6 2 443 c3 384 5 442 18 445 51 10 75
16 143 39 85 27 215 87 292 134 28 16 53 29 57 28 4 -1 147 -141 318 -311z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -1,6 +1,6 @@
{
"name": "hellob.art",
"short_name": "hellob.art",
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
@ -13,7 +13,7 @@
"type": "image/png"
}
],
"theme_color": "#5c5c5c",
"background_color": "#5c5c5c",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View file

@ -1,81 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 47.4% 11.2%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--card: 0 0% 100%;
--card-foreground: 222.2 47.4% 11.2%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 100% 50%;
--destructive-foreground: 210 40% 98%;
--ring: 215 20.2% 65.1%;
--radius: 0.5rem;
}
.dark {
--background: 224 71% 4%;
--foreground: 213 31% 91%;
--muted: 223 47% 11%;
--muted-foreground: 215.4 16.3% 56.9%;
--accent: 216 34% 17%;
--accent-foreground: 210 40% 98%;
--popover: 224 71% 4%;
--popover-foreground: 215 20.2% 65.1%;
--border: 216 34% 17%;
--input: 216 34% 17%;
--card: 224 71% 4%;
--card-foreground: 213 31% 91%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 1.2%;
--secondary: 222.2 47.4% 11.2%;
--secondary-foreground: 210 40% 98%;
--destructive: 0 63% 31%;
--destructive-foreground: 210 40% 98%;
--ring: 216 34% 17%;
--radius: 0.5rem;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1;
}
}

13
svelte.config.js Normal file
View file

@ -0,0 +1,13 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [vitePreprocess({})],
kit: {
adapter: adapter()
}
};
export default config;

18
tailwind.config.cjs Normal file
View file

@ -0,0 +1,18 @@
/* eslint-disable @typescript-eslint/no-var-requires */
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: 'class',
content: [
'./src/**/*.{html,js,svelte,ts}',
require('path').join(require.resolve(
'@skeletonlabs/skeleton'),
'../**/*.{html,js,svelte,ts}'
)
],
theme: {
extend: {},
},
plugins: [
...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()
]
}

View file

@ -1,82 +0,0 @@
const { fontFamily } = require("tailwindcss/defaultTheme");
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./ui/**/*.{ts,tsx}",
"./content/**/*.{md,mdx}",
],
darkMode: ["class"],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: `var(--radius)`,
md: `calc(var(--radius) - 2px)`,
sm: "calc(var(--radius) - 4px)",
},
fontFamily: {
sans: ["var(--font-sans)", ...fontFamily.sans],
heading: ["var(--font-heading)", ...fontFamily.sans],
},
keyframes: {
"accordion-down": {
from: { height: 0 },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
};

View file

@ -1,28 +1,17 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

11
types/index.d.ts vendored
View file

@ -1,11 +0,0 @@
export type NavItem = {
title: string;
href: string;
disabled?: boolean;
};
export type MainNavItem = NavItem;
export type NavigationConfig = {
mainNav: MainNavItem[];
};

9
vite.config.ts Normal file
View file

@ -0,0 +1,9 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
ssr: {
noExternal: ['three']
}
});