Merge pull request #82 from bartvdbraak/feat/workflows
Add new workflows
8
.github/dependabot.yml
vendored
|
@ -1,8 +1,8 @@
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: 'github-actions'
|
||||||
directory: "/"
|
directory: '/'
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: 'weekly'
|
||||||
reviewers:
|
reviewers:
|
||||||
- "bartvdbraak"
|
- 'bartvdbraak'
|
||||||
|
|
5
.github/renovate.json
vendored
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": ["config:base"]
|
"extends": ["config:base"],
|
||||||
|
"reviewers": ["bartvdbraak"]
|
||||||
}
|
}
|
38
.github/workflows/linting.yaml
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
name: Linting
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
checks: write
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-checks:
|
||||||
|
name: Run checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [18]
|
||||||
|
steps:
|
||||||
|
- name: Checkout Git repository
|
||||||
|
uses: actions/checkout@v3.5.3
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v2.4.0
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- 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
|
135
.github/workflows/unlighthouse.yaml
vendored
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
name: Unlighthouse
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unlighthouse:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
COMMENT_ID: unlighthouse-node${{matrix.node-version}}
|
||||||
|
PORT: 8000
|
||||||
|
CLOUDFLARE_PROJECT: hellobart-unlighthouse
|
||||||
|
CLOUDFLARE_BRANCH: pull-${{ github.event.pull_request.number }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [18]
|
||||||
|
steps:
|
||||||
|
- name: Create initial comment
|
||||||
|
uses: marocchino/sticky-pull-request-comment@v2.7.0
|
||||||
|
with:
|
||||||
|
header: ${{ env.COMMENT_ID }}
|
||||||
|
message: |
|
||||||
|
⚡️ Lighthouse report
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3.5.3
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v2.2.4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v3.7.0
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build production
|
||||||
|
run: pnpm run build
|
||||||
|
|
||||||
|
- name: Start Preview and Get Preview URL
|
||||||
|
run: |
|
||||||
|
pnpm run preview --port ${{ env.PORT }} & echo $! > preview_pid
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: pnpm add -g @unlighthouse/cli puppeteer
|
||||||
|
|
||||||
|
- name: Run Unlighthouse
|
||||||
|
run: |
|
||||||
|
unlighthouse-ci \
|
||||||
|
--site "http://localhost:${{ env.PORT }}" \
|
||||||
|
--reporter jsonExpanded \
|
||||||
|
--build-static
|
||||||
|
|
||||||
|
- name: Upload report to Cloudflare pages
|
||||||
|
uses: cloudflare/wrangler-action@2.0.0
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
command: pages deploy .unlighthouse --project-name="${{ env.CLOUDFLARE_PROJECT }}" --branch=${{ env.CLOUDFLARE_BRANCH }}
|
||||||
|
|
||||||
|
- name: Create result content
|
||||||
|
id: create_result_content
|
||||||
|
uses: actions/github-script@v6.4.1
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const result = JSON.parse(fs.readFileSync('.unlighthouse/ci-result.json', 'utf8'));
|
||||||
|
|
||||||
|
const formatScore = score => `${Math.round(score * 100)} (${score})`;
|
||||||
|
const getEmoji = score => score >= 0.9 ? '🟢' : score >= 0.5 ? '🟠' : '🔴';
|
||||||
|
|
||||||
|
const score = res => `${getEmoji(res)} ${formatScore(res)}`;
|
||||||
|
|
||||||
|
const reportUrl = `https://${{ env.CLOUDFLARE_BRANCH }}.${{ env.CLOUDFLARE_PROJECT }}.pages.dev`;
|
||||||
|
|
||||||
|
const comment = [
|
||||||
|
`⚡️ Lighthouse report for the changes in this PR:`,
|
||||||
|
'| Category | Score |',
|
||||||
|
'| --- | --- |',
|
||||||
|
`| Performance | ${score(result.summary.categories.performance.averageScore)} |`,
|
||||||
|
`| Accessibility | ${score(result.summary.categories.accessibility.averageScore)} |`,
|
||||||
|
`| Best practices | ${score(result.summary.categories['best-practices'].averageScore)} |`,
|
||||||
|
`| SEO | ${score(result.summary.categories.seo.averageScore)} |`,
|
||||||
|
`| *Overall* | ${score(result.summary.score)} |`,
|
||||||
|
'',
|
||||||
|
'*Lighthouse scores for individual routes:*',
|
||||||
|
'',
|
||||||
|
'| Path | Performance | Accessibility | Best practices | SEO | Overall |',
|
||||||
|
'| --- | --- | --- | --- | --- | --- |',
|
||||||
|
`${result.routes.map(route => `| ${route.path} | ${score(route.categories.performance.score)} | ${score(route.categories.accessibility.score)} | ${score(route.categories['best-practices'].score)} | ${score(route.categories.seo.score)} | ${score(route.score)} |`).join('\n')}`,
|
||||||
|
'',
|
||||||
|
'*Lighthouse metrics:*',
|
||||||
|
'',
|
||||||
|
'| Metric | Average Value |',
|
||||||
|
'| --- | --- |',
|
||||||
|
`${Object.entries(result.summary.metrics).map(([metric, { averageNumericValue }]) => `| ${metric} | ${averageNumericValue} |`).join('\n')}`,
|
||||||
|
'',
|
||||||
|
`View the full Lighthouse report [here](${reportUrl}).`,
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
core.setOutput("comment", comment);
|
||||||
|
|
||||||
|
- name: Update comment with result
|
||||||
|
uses: marocchino/sticky-pull-request-comment@v2.7.0
|
||||||
|
with:
|
||||||
|
header: ${{ env.COMMENT_ID }}
|
||||||
|
message: ${{ steps.create_result_content.outputs.comment }}
|
||||||
|
|
||||||
|
- name: Update comment on failure
|
||||||
|
uses: marocchino/sticky-pull-request-comment@v2.7.0
|
||||||
|
if: ${{ failure() }}
|
||||||
|
with:
|
||||||
|
header: ${{ env.COMMENT_ID }}
|
||||||
|
message: |
|
||||||
|
⚡️ Lighthouse report failed
|
||||||
|
|
||||||
|
See deployment for any errors
|
||||||
|
|
||||||
|
- name: Update comment on cancel
|
||||||
|
uses: marocchino/sticky-pull-request-comment@v2.7.0
|
||||||
|
if: ${{ cancelled() }}
|
||||||
|
with:
|
||||||
|
header: ${{ env.COMMENT_ID }}
|
||||||
|
message: |
|
||||||
|
⚡️ Lighthouse report cancelled
|
1
.gitignore
vendored
|
@ -8,3 +8,4 @@ node_modules
|
||||||
!.env.example
|
!.env.example
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
.unlighthouse
|
31
README.md
|
@ -1,6 +1,6 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1 align="center">hellob.art</h1>
|
<h1 align="center">hellob.art</h1>
|
||||||
<h5>a simple portfolio</h5>
|
<h5>personal website built with Svelte</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
@ -8,11 +8,6 @@
|
||||||
<a href="https://github.com/bartvdbraak/hellob.art/deployments/activity_log?environment=Production"><img src="https://img.shields.io/github/deployments/bartvdbraak/hellob.art/production?label=vercel&logo=vercel" /></a>
|
<a href="https://github.com/bartvdbraak/hellob.art/deployments/activity_log?environment=Production"><img src="https://img.shields.io/github/deployments/bartvdbraak/hellob.art/production?label=vercel&logo=vercel" /></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<a href="https://hellob.art?ref=github">hellob.art</a>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To install the project and its dependencies, follow these steps:
|
To install the project and its dependencies, follow these steps:
|
||||||
|
@ -52,10 +47,7 @@ pnpm run dev -- --open
|
||||||
- **SvelteKit:** The tooling and routing framework for Svelte projects.
|
- **SvelteKit:** The tooling and routing framework for Svelte projects.
|
||||||
- **Tailwind CSS:** A utility-first CSS framework packed with classes.
|
- **Tailwind CSS:** A utility-first CSS framework packed with classes.
|
||||||
- **Skeleton:** UI Toolkit for Svelte + Tailwind.
|
- **Skeleton:** UI Toolkit for Svelte + Tailwind.
|
||||||
|
- **Threlte:** Declarative Three.js for Svelte.
|
||||||
## Deployment
|
|
||||||
|
|
||||||
The portfolio is hosted using [Vercel](https://vercel.com). You can access it at [https://hellob.art](https://hellob.art).
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -65,12 +57,15 @@ I'm open to contributions! If you find any bugs, have suggestions, or want to ad
|
||||||
|
|
||||||
This project is licensed under the GPLv3 License. Feel free to explore, learn, and have fun!
|
This project is licensed under the GPLv3 License. Feel free to explore, learn, and have fun!
|
||||||
|
|
||||||
## Get in Touch
|
Some dependencies may hold different licenses but are in compliance with GPLv3:
|
||||||
|
|
||||||
Let's connect! You can find me on:
|
- `MIT`: Compatible with GPLv3.
|
||||||
|
- `Apache 2.0`: Compatible with GPLv3.
|
||||||
- Website: [hellob.art](https://hellob.art)
|
- `BSD-3-Clause`: Compatible with GPLv3.
|
||||||
- GitHub: [github.com/bartvdbraak](https://github.com/bartvdbraak)
|
- `BSD-2-Clause`: Compatible with GPLv3.
|
||||||
- Email: bart@vanderbraak.nl
|
- `ISC`: Compatible with GPLv3.
|
||||||
|
- `Python-2.0`: Compatible with GPLv3. (Note: Python has its own license, and version 2.0 is compatible with GPLv3).
|
||||||
Looking forward to hearing from you! 😊
|
- `CC-BY-4.0`: This is a Creative Commons license, which is not a software license. It's generally not recommended to include CC licenses in software projects due to potential compatibility issues. This might cause complications if you choose GPLv3.
|
||||||
|
- `CC0-1.0`: Not a software license, but it is explicitly designed to waive all copyrights, making it effectively compatible with GPLv3.
|
||||||
|
- `0BSD`: Compatible with GPLv3.
|
||||||
|
- `(MIT OR CC0-1.0)`: MIT is compatible with GPLv3, and CC0-1.0 is effectively compatible with GPLv3.
|
||||||
|
|
|
@ -3,10 +3,7 @@ const tailwindcss = require('tailwindcss');
|
||||||
const autoprefixer = require('autoprefixer');
|
const autoprefixer = require('autoprefixer');
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
plugins: [
|
plugins: [tailwindcss(), autoprefixer]
|
||||||
tailwindcss(),
|
|
||||||
autoprefixer
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
34
src/app.html
|
@ -1,20 +1,20 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
|
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="%sveltekit.assets%/apple-touch-icon.png">
|
<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="32x32" href="%sveltekit.assets%/favicon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="%sveltekit.assets%/favicon-16x16.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="manifest" href="%sveltekit.assets%/site.webmanifest" />
|
||||||
<link rel="mask-icon" href="%sveltekit.assets%/safari-pinned-tab.svg" color="#5bbad5">
|
<link rel="mask-icon" href="%sveltekit.assets%/safari-pinned-tab.svg" color="#5bbad5" />
|
||||||
<meta name="msapplication-TileColor" content="#da532c">
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff" />
|
||||||
<title></title>
|
<title></title>
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover">
|
<body data-sveltekit-preload-data="hover">
|
||||||
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
|
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
@apply h-full overflow-hidden
|
@apply h-full overflow-hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
}
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
export function calculateAge(birthdate: string): number {
|
export function calculateAge(birthdate: string): number {
|
||||||
const birthDate = new Date(birthdate);
|
const birthDate = new Date(birthdate);
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
|
|
||||||
let age = currentDate.getFullYear() - birthDate.getFullYear();
|
let age = currentDate.getFullYear() - birthDate.getFullYear();
|
||||||
const monthDiff = currentDate.getMonth() - birthDate.getMonth();
|
const monthDiff = currentDate.getMonth() - birthDate.getMonth();
|
||||||
|
|
||||||
if (monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate())) {
|
if (monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate())) {
|
||||||
age--;
|
age--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return age;
|
return age;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,29 +13,47 @@
|
||||||
|
|
||||||
<AppBar>
|
<AppBar>
|
||||||
<svelte:fragment slot="lead">
|
<svelte:fragment slot="lead">
|
||||||
<button aria-label="Toggle navigation menu" class="md:hidden btn btn-sm mr-4" on:click={drawerOpen}>
|
<button
|
||||||
|
aria-label="Toggle navigation menu"
|
||||||
|
class="md:hidden btn btn-sm mr-4"
|
||||||
|
on:click={drawerOpen}
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<Hamburger />
|
<Hamburger />
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<img src="./icon.svg" alt="Logo" srcset="" class="pr-2" />
|
<img width="32" height="24" src="./icon.svg" alt="Logo" srcset="" class="" />
|
||||||
<h2 class="code">hellob.art</h2>
|
<h1 class="h6">
|
||||||
|
<span
|
||||||
|
class="bg-gradient-to-br logo-text-gradient bg-clip-text text-transparent box-decoration-clone font-mono font-bold tracking-tighter pl-3"
|
||||||
|
>hellob.art</span
|
||||||
|
>
|
||||||
|
</h1>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="trail">
|
<svelte:fragment slot="trail">
|
||||||
<a
|
<a
|
||||||
href="https://linkedin.com/in/bartvdbraak"
|
href="https://linkedin.com/in/bartvdbraak"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="btn-icon btn-icon-sm hover:variant-soft-primary"><LinkedIn /><span class="sr-only">LinkedIn Profile of Bart van der Braak</span></a
|
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
|
<a
|
||||||
href="https://github.com/bartvdbraak"
|
href="https://github.com/bartvdbraak"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="btn-icon btn-icon-sm hover:variant-soft-primary"><GitHub /><span class="sr-only">GitHub Profile of Bart van der Braak</span></a
|
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 />
|
<LightSwitch />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|
||||||
<ProgressBar label="Progress Bar" value={progress} max={100} rounded="" />
|
<span id="progress-bar-label" class="sr-only">Loading Progress</span>
|
||||||
|
<ProgressBar
|
||||||
|
label="Progress Bar"
|
||||||
|
labelledby="progress-bar-label"
|
||||||
|
value={progress}
|
||||||
|
max={100}
|
||||||
|
rounded=""
|
||||||
|
/>
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
<ul>
|
<ul>
|
||||||
{#each routes as route}
|
{#each routes as route}
|
||||||
<li class="pb-2">
|
<li class="pb-2">
|
||||||
<a class="{classesActive(route.url)}" href={route.url} on:click={drawerClose}>{route.label}</a>
|
<a class={classesActive(route.url)} href={route.url} on:click={drawerClose}>{route.label}</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -16,11 +16,15 @@
|
||||||
|
|
||||||
<a class="card bg-initial card-hover overflow-hidden" href={link}>
|
<a class="card bg-initial card-hover overflow-hidden" href={link}>
|
||||||
<header>
|
<header>
|
||||||
<img src={headerImage} class="bg-black/50 w-full aspect-[21/9] object-cover object-top" alt="Post" />
|
<img
|
||||||
|
src={headerImage}
|
||||||
|
class="bg-black/50 w-full aspect-[21/9] object-cover object-top"
|
||||||
|
alt="Post"
|
||||||
|
/>
|
||||||
</header>
|
</header>
|
||||||
<div class="p-4 space-y-4">
|
<div class="p-4 space-y-4">
|
||||||
<h6 class="h6">{headerSubTitle}</h6>
|
<header class="h6">{headerSubTitle}</header>
|
||||||
<h3 class="h3" data-toc-ignore>{title}</h3>
|
<span class="h3" data-toc-ignore>{title}</span>
|
||||||
<article>
|
<article>
|
||||||
<p>
|
<p>
|
||||||
{description}
|
{description}
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
<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>
|
<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: 517 B After Width: | Height: | Size: 529 B |
|
@ -1 +1,18 @@
|
||||||
<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>
|
<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: 326 B After Width: | Height: | Size: 352 B |
|
@ -1 +1,12 @@
|
||||||
<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"></path></svg>
|
<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: 555 B After Width: | Height: | Size: 564 B |
|
@ -1 +1,14 @@
|
||||||
<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>
|
<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 /><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 |
|
@ -1 +1,13 @@
|
||||||
<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>
|
<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: 299 B After Width: | Height: | Size: 303 B |
|
@ -5,77 +5,82 @@ const vitalsUrl = 'https://vitals.vercel-analytics.com/v1/vitals';
|
||||||
|
|
||||||
// Improve type safety by defining the navigator.connection type
|
// Improve type safety by defining the navigator.connection type
|
||||||
interface NavigatorWithConnection extends Navigator {
|
interface NavigatorWithConnection extends Navigator {
|
||||||
connection: {
|
connection: {
|
||||||
effectiveType: string;
|
effectiveType: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
type Params = Record<string, any>; // Define a type for 'params'
|
type Params = Record<string, any>; // Define a type for 'params'
|
||||||
|
|
||||||
function getConnectionSpeed() {
|
function getConnectionSpeed() {
|
||||||
return 'connection' in navigator && 'connection' && 'effectiveType' in (navigator as NavigatorWithConnection).connection
|
return 'connection' in navigator &&
|
||||||
? (navigator as NavigatorWithConnection).connection.effectiveType
|
'connection' &&
|
||||||
: '';
|
'effectiveType' in (navigator as NavigatorWithConnection).connection
|
||||||
|
? (navigator as NavigatorWithConnection).connection.effectiveType
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendToAnalytics(metric: Metric, options: {
|
function sendToAnalytics(
|
||||||
params: Params;
|
metric: Metric,
|
||||||
path: string;
|
options: {
|
||||||
analyticsId: string;
|
params: Params;
|
||||||
debug: boolean;
|
path: string;
|
||||||
}) {
|
analyticsId: string;
|
||||||
const page = Object.entries(options.params).reduce(
|
debug: boolean;
|
||||||
(acc, [key, value]) => acc.replace(value, `[${key}]`),
|
}
|
||||||
options.path
|
) {
|
||||||
);
|
const page = Object.entries(options.params).reduce(
|
||||||
|
(acc, [key, value]) => acc.replace(value, `[${key}]`),
|
||||||
|
options.path
|
||||||
|
);
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
dsn: options.analyticsId,
|
dsn: options.analyticsId,
|
||||||
id: metric.id,
|
id: metric.id,
|
||||||
page,
|
page,
|
||||||
href: location.href,
|
href: location.href,
|
||||||
event_name: metric.name,
|
event_name: metric.name,
|
||||||
value: metric.value.toString(),
|
value: metric.value.toString(),
|
||||||
speed: getConnectionSpeed(),
|
speed: getConnectionSpeed()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.debug) {
|
if (options.debug) {
|
||||||
console.log('[Web Vitals]', metric.name, JSON.stringify(body, null, 2));
|
console.log('[Web Vitals]', metric.name, JSON.stringify(body, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize body to a URLSearchParams object
|
// Serialize body to a URLSearchParams object
|
||||||
const searchParams = new URLSearchParams(body);
|
const searchParams = new URLSearchParams(body);
|
||||||
|
|
||||||
// The type 'Record<string, string>' is compatible with 'URLSearchParams'
|
// The type 'Record<string, string>' is compatible with 'URLSearchParams'
|
||||||
const blob = new Blob([searchParams.toString()], {
|
const blob = new Blob([searchParams.toString()], {
|
||||||
type: 'application/x-www-form-urlencoded',
|
type: 'application/x-www-form-urlencoded'
|
||||||
});
|
});
|
||||||
if (navigator.sendBeacon) {
|
if (navigator.sendBeacon) {
|
||||||
navigator.sendBeacon(vitalsUrl, blob);
|
navigator.sendBeacon(vitalsUrl, blob);
|
||||||
} else {
|
} else {
|
||||||
fetch(vitalsUrl, {
|
fetch(vitalsUrl, {
|
||||||
body: blob,
|
body: blob,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'omit',
|
credentials: 'omit',
|
||||||
keepalive: true,
|
keepalive: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function webVitals(options: {
|
export function webVitals(options: {
|
||||||
params: Params; // Use the defined 'Params' type here
|
params: Params; // Use the defined 'Params' type here
|
||||||
path: string;
|
path: string;
|
||||||
analyticsId: string;
|
analyticsId: string;
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
getFID((metric) => sendToAnalytics(metric, options));
|
getFID((metric) => sendToAnalytics(metric, options));
|
||||||
getTTFB((metric) => sendToAnalytics(metric, options));
|
getTTFB((metric) => sendToAnalytics(metric, options));
|
||||||
getLCP((metric) => sendToAnalytics(metric, options));
|
getLCP((metric) => sendToAnalytics(metric, options));
|
||||||
getCLS((metric) => sendToAnalytics(metric, options));
|
getCLS((metric) => sendToAnalytics(metric, options));
|
||||||
getFCP((metric) => sendToAnalytics(metric, options));
|
getFCP((metric) => sendToAnalytics(metric, options));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Web Vitals]', err);
|
console.error('[Web Vitals]', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
let routes = [
|
let routes = [
|
||||||
{ url: '/', label: 'Home' },
|
{ url: '/', label: 'Home' },
|
||||||
{ url: '/projects', label: 'Projects' },
|
{ url: '/projects', label: 'Projects' },
|
||||||
{ url: '/tools', label: 'Tools' },
|
{ url: '/tools', label: 'Tools' }
|
||||||
// { url: '/blog', label: 'Blog' }
|
// { url: '/blog', label: 'Blog' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>hellob.art — home</title>
|
<title>hellob.art — home</title>
|
||||||
<meta name="description" content="Meet Bart, a passionate DevOps engineer from Zaandam, Netherlands. With expertise in Azure, Kubernetes, and automation, he loves solving challenges through code. Discover his journey, interests in cats and whiskey, and how to connect with him for exciting collaborations.">
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Meet Bart, a passionate DevOps engineer from Zaandam, Netherlands. With expertise in Azure, Kubernetes, and automation, he loves solving challenges through code. Discover his journey, interests in cats and whiskey, and how to connect with him for exciting collaborations."
|
||||||
|
/>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<main class="container mx-auto px-4 py-8 text-left">
|
<main class="container mx-auto px-4 py-8 text-left">
|
||||||
|
@ -38,7 +41,11 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="md:col-span-1 flex justify-end">
|
<div class="md:col-span-1 flex justify-end">
|
||||||
<img src={picture} alt="Bart van der Braak with a noire effect" class="max-w-1/3 mb-4 object-cover" />
|
<img
|
||||||
|
src={picture}
|
||||||
|
alt="Bart van der Braak with a noire effect"
|
||||||
|
class="max-w-1/3 mb-4 object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -46,11 +53,11 @@
|
||||||
|
|
||||||
<p class="text-lg leading-relaxed mb-8">
|
<p class="text-lg leading-relaxed mb-8">
|
||||||
As a DevOps engineer, I thrive on solving complex challenges with the power of code and
|
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
|
automation. My passion for streamlining workflows led me to create internal tooling using APIs,
|
||||||
APIs, boosting productivity for myself and my colleagues. Outside of work, I enjoy taking on
|
boosting productivity for myself and my colleagues. Outside of work, I enjoy taking on side
|
||||||
side projects that push my boundaries, expanding my skill set, and exploring new
|
projects that push my boundaries, expanding my skill set, and exploring new technologies. I
|
||||||
technologies. I strongly believe that innovation and continuous learning are key drivers of
|
strongly believe that innovation and continuous learning are key drivers of success in the
|
||||||
success in the ever-evolving tech landscape.
|
ever-evolving tech landscape.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="text-3xl font-bold mb-4">Cat Lover and Whiskey Enthusiast</h2>
|
<h2 class="text-3xl font-bold mb-4">Cat Lover and Whiskey Enthusiast</h2>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
/** @type {import('./$types').PageData} */
|
/** @type {import('./$types').PageData} */
|
||||||
export let data;
|
export let data;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|
|
@ -49,7 +49,10 @@
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>hellob.art — projects</title>
|
<title>hellob.art — projects</title>
|
||||||
<meta name="description" content="Explore a diverse collection of web applications and virtual tours in the portfolio of a passionate DevOps engineer. Discover innovative projects in React, Golang, Next.js, and more.">
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Explore a diverse collection of web applications and virtual tours in the portfolio of a passionate DevOps engineer. Discover innovative projects in React, Golang, Next.js, and more."
|
||||||
|
/>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<main class="container mx-auto px-4 py-8 text-left">
|
<main class="container mx-auto px-4 py-8 text-left">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Canvas } from '@threlte/core';
|
import { Canvas } from '@threlte/core';
|
||||||
import { T } from '@threlte/core';
|
import { T } from '@threlte/core';
|
||||||
import { ContactShadows, Float, Grid, OrbitControls } from '@threlte/extras';
|
import { ContactShadows, Float, OrbitControls } from '@threlte/extras';
|
||||||
import Github from './models/Github.svelte';
|
import Github from './models/Github.svelte';
|
||||||
import TerraformFlat from './models/TerraformFlat.svelte';
|
import TerraformFlat from './models/TerraformFlat.svelte';
|
||||||
import Kubernetes from './models/Kubernetes.svelte';
|
import Kubernetes from './models/Kubernetes.svelte';
|
||||||
|
@ -11,7 +11,10 @@
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>hellob.art — tools</title>
|
<title>hellob.art — tools</title>
|
||||||
<meta name="description" content="Explore essential DevOps tools like Kubernetes, Terraform, Warp, and version control platforms GitHub, Azure DevOps, and GitLab.">
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Explore essential DevOps tools like Kubernetes, Terraform, Warp, and version control platforms GitHub, Azure DevOps, and GitLab."
|
||||||
|
/>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<main class="container mx-auto px-4 py-8 text-left">
|
<main class="container mx-auto px-4 py-8 text-left">
|
||||||
|
@ -56,15 +59,6 @@
|
||||||
<T.DirectionalLight intensity={0.5} position.x={5} position.y={3} />
|
<T.DirectionalLight intensity={0.5} position.x={5} position.y={3} />
|
||||||
<T.AmbientLight intensity={0.2} />
|
<T.AmbientLight intensity={0.2} />
|
||||||
|
|
||||||
<!-- <Grid
|
|
||||||
position.y={-0.001}
|
|
||||||
cellColor="#ffffff"
|
|
||||||
sectionColor="#ffffff"
|
|
||||||
sectionThickness={0}
|
|
||||||
fadeDistance={40}
|
|
||||||
cellSize={2}
|
|
||||||
/> -->
|
|
||||||
|
|
||||||
<ContactShadows scale={10} blur={2} far={2.5} opacity={0.5} />
|
<ContactShadows scale={10} blur={2} far={2.5} opacity={0.5} />
|
||||||
|
|
||||||
<Float floatIntensity={1} floatingRange={[0, 1]}>
|
<Float floatIntensity={1} floatingRange={[0, 1]}>
|
||||||
|
|
|
@ -4,25 +4,25 @@ Command: npx @threlte/gltf@1.0.0-next.13 ./src/lib/assets/vectors/github.glb --t
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Group } from 'three'
|
import { Group } from 'three';
|
||||||
import { T, forwardEventHandlers } from '@threlte/core'
|
import { T, forwardEventHandlers } from '@threlte/core';
|
||||||
import { useGltf } from '@threlte/extras'
|
import { useGltf } from '@threlte/extras';
|
||||||
|
|
||||||
export const ref = new Group()
|
export const ref = new Group();
|
||||||
|
|
||||||
const gltf = useGltf('/models/github-transformed.glb', { useDraco: true })
|
const gltf = useGltf('/models/github-transformed.glb', { useDraco: true });
|
||||||
|
|
||||||
const component = forwardEventHandlers()
|
const component = forwardEventHandlers();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
||||||
{#await gltf}
|
{#await gltf}
|
||||||
<slot name="fallback" />
|
<slot name="fallback" />
|
||||||
{:then gltf}
|
{:then gltf}
|
||||||
<T.Mesh geometry={gltf.nodes.Github_Mesh.geometry} material={gltf.materials['SVGMat.001']} />
|
<T.Mesh geometry={gltf.nodes.Github_Mesh.geometry} material={gltf.materials['SVGMat.001']} />
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<slot name="error" {error} />
|
<slot name="error" {error} />
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
<slot {ref} />
|
<slot {ref} />
|
||||||
</T>
|
</T>
|
||||||
|
|
|
@ -4,34 +4,34 @@ Command: npx @threlte/gltf@1.0.0-next.13 ./static/models/kubernetes.glb --transf
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Group } from 'three'
|
import { Group } from 'three';
|
||||||
import { T, forwardEventHandlers } from '@threlte/core'
|
import { T, forwardEventHandlers } from '@threlte/core';
|
||||||
import { useGltf } from '@threlte/extras'
|
import { useGltf } from '@threlte/extras';
|
||||||
|
|
||||||
export const ref = new Group()
|
export const ref = new Group();
|
||||||
|
|
||||||
const gltf = useGltf('/models/kubernetes-transformed.glb', { useDraco: true })
|
const gltf = useGltf('/models/kubernetes-transformed.glb', { useDraco: true });
|
||||||
|
|
||||||
const component = forwardEventHandlers()
|
const component = forwardEventHandlers();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
||||||
{#await gltf}
|
{#await gltf}
|
||||||
<slot name="fallback" />
|
<slot name="fallback" />
|
||||||
{:then gltf}
|
{:then gltf}
|
||||||
<T.Mesh
|
<T.Mesh
|
||||||
geometry={gltf.nodes.Curve.geometry}
|
geometry={gltf.nodes.Curve.geometry}
|
||||||
material={gltf.materials['SVGMat.006']}
|
material={gltf.materials['SVGMat.006']}
|
||||||
rotation={[Math.PI / 2, 0, 0.9]}
|
rotation={[Math.PI / 2, 0, 0.9]}
|
||||||
/>
|
/>
|
||||||
<T.Mesh
|
<T.Mesh
|
||||||
geometry={gltf.nodes.Curve001.geometry}
|
geometry={gltf.nodes.Curve001.geometry}
|
||||||
material={gltf.materials['SVGMat.007']}
|
material={gltf.materials['SVGMat.007']}
|
||||||
rotation={[Math.PI / 2, 0, 0.9]}
|
rotation={[Math.PI / 2, 0, 0.9]}
|
||||||
/>
|
/>
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<slot name="error" {error} />
|
<slot name="error" {error} />
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
<slot {ref} />
|
<slot {ref} />
|
||||||
</T>
|
</T>
|
||||||
|
|
|
@ -4,28 +4,28 @@ Command: npx @threlte/gltf@1.0.0-next.13 ./static/models/terraform-flat.glb --tr
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Group } from 'three'
|
import { Group } from 'three';
|
||||||
import { T, forwardEventHandlers } from '@threlte/core'
|
import { T, forwardEventHandlers } from '@threlte/core';
|
||||||
import { useGltf } from '@threlte/extras'
|
import { useGltf } from '@threlte/extras';
|
||||||
|
|
||||||
export const ref = new Group()
|
export const ref = new Group();
|
||||||
|
|
||||||
const gltf = useGltf('/models/terraform-flat-transformed.glb', { useDraco: true })
|
const gltf = useGltf('/models/terraform-flat-transformed.glb', { useDraco: true });
|
||||||
|
|
||||||
const component = forwardEventHandlers()
|
const component = forwardEventHandlers();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
||||||
{#await gltf}
|
{#await gltf}
|
||||||
<slot name="fallback" />
|
<slot name="fallback" />
|
||||||
{:then gltf}
|
{:then gltf}
|
||||||
<T.Group rotation={[Math.PI / 2, 0, 5]}>
|
<T.Group rotation={[Math.PI / 2, 0, 5]}>
|
||||||
<T.Mesh geometry={gltf.nodes.Curve_1.geometry} material={gltf.materials.SVGMat} />
|
<T.Mesh geometry={gltf.nodes.Curve_1.geometry} material={gltf.materials.SVGMat} />
|
||||||
<T.Mesh geometry={gltf.nodes.Curve_2.geometry} material={gltf.materials['SVGMat.001']} />
|
<T.Mesh geometry={gltf.nodes.Curve_2.geometry} material={gltf.materials['SVGMat.001']} />
|
||||||
</T.Group>
|
</T.Group>
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<slot name="error" {error} />
|
<slot name="error" {error} />
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
<slot {ref} />
|
<slot {ref} />
|
||||||
</T>
|
</T>
|
||||||
|
|
|
@ -4,26 +4,34 @@ Command: npx @threlte/gltf@1.0.0-next.13 ./static/models/warp.glb --transform
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Group } from 'three'
|
import { Group } from 'three';
|
||||||
import { T, forwardEventHandlers } from '@threlte/core'
|
import { T, forwardEventHandlers } from '@threlte/core';
|
||||||
import { useGltf } from '@threlte/extras'
|
import { useGltf } from '@threlte/extras';
|
||||||
|
|
||||||
export const ref = new Group()
|
export const ref = new Group();
|
||||||
|
|
||||||
const gltf = useGltf('/models/warp-transformed.glb', { useDraco: true })
|
const gltf = useGltf('/models/warp-transformed.glb', { useDraco: true });
|
||||||
|
|
||||||
const component = forwardEventHandlers()
|
const component = forwardEventHandlers();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
||||||
{#await gltf}
|
{#await gltf}
|
||||||
<slot name="fallback" />
|
<slot name="fallback" />
|
||||||
{:then gltf}
|
{:then gltf}
|
||||||
<T.Mesh geometry={gltf.nodes.Warp.geometry} material={gltf.materials.SVGMat} rotation={[Math.PI / 2, 0, 0.3]} />
|
<T.Mesh
|
||||||
<T.Mesh geometry={gltf.nodes.Warp001.geometry} material={gltf.materials.Gradient} rotation={[Math.PI / 2, 0, 0.3]} />
|
geometry={gltf.nodes.Warp.geometry}
|
||||||
{:catch error}
|
material={gltf.materials.SVGMat}
|
||||||
<slot name="error" {error} />
|
rotation={[Math.PI / 2, 0, 0.3]}
|
||||||
{/await}
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Warp001.geometry}
|
||||||
|
material={gltf.materials.Gradient}
|
||||||
|
rotation={[Math.PI / 2, 0, 0.3]}
|
||||||
|
/>
|
||||||
|
{:catch error}
|
||||||
|
<slot name="error" {error} />
|
||||||
|
{/await}
|
||||||
|
|
||||||
<slot {ref} />
|
<slot {ref} />
|
||||||
</T>
|
</T>
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
|
|
||||||
: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 */
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,19 +1,19 @@
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"short_name": "",
|
"short_name": "",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/android-chrome-192x192.png",
|
"src": "/android-chrome-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/android-chrome-512x512.png",
|
"src": "/android-chrome-512x512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"theme_color": "#ffffff",
|
"theme_color": "#ffffff",
|
||||||
"background_color": "#ffffff",
|
"background_color": "#ffffff",
|
||||||
"display": "standalone"
|
"display": "standalone"
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,29 @@ module.exports = {
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
content: [
|
content: [
|
||||||
'./src/**/*.{html,js,svelte,ts}',
|
'./src/**/*.{html,js,svelte,ts}',
|
||||||
require('path').join(require.resolve(
|
require('path').join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}')
|
||||||
'@skeletonlabs/skeleton'),
|
|
||||||
'../**/*.{html,js,svelte,ts}'
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {
|
||||||
|
colors: {
|
||||||
|
'logo-blue-start': {
|
||||||
|
light: '#314755',
|
||||||
|
DEFAULT: '#314755',
|
||||||
|
dark: '#7196AD'
|
||||||
|
},
|
||||||
|
'logo-blue-stop': {
|
||||||
|
light: '#26a0da',
|
||||||
|
DEFAULT: '#26a0da',
|
||||||
|
dark: '#7CC6E9'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
// <-- Add this section for dark mode classes
|
||||||
|
'logo-text-gradient-dark': {
|
||||||
|
'@apply': 'from-logo-blue-start-dark to-logo-blue-stop-dark'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()]
|
||||||
...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()
|
};
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ import { defineConfig } from 'vite';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()],
|
plugins: [sveltekit()],
|
||||||
ssr: {
|
ssr: {
|
||||||
noExternal: ['three']
|
noExternal: ['three']
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
'import.meta.env.VERCEL_ANALYTICS_ID': JSON.stringify(process.env.VERCEL_ANALYTICS_ID)
|
'import.meta.env.VERCEL_ANALYTICS_ID': JSON.stringify(process.env.VERCEL_ANALYTICS_ID)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|