git commit -am "Pruned git history"
All checks were successful
Rebuild signaller for deprived.dev to rebuild site / Rebuild Signaller (push) Successful in 21s

This commit is contained in:
BOTAlex 2026-05-05 13:42:47 +02:00
commit 158918c0f5
201 changed files with 24558 additions and 0 deletions

222
src/app.css Normal file
View file

@ -0,0 +1,222 @@
@import "tailwindcss";
@plugin "daisyui";
@plugin "daisyui/theme" {
name: "Deprived";
default: true;
prefersdark: true;
--color-base-100: oklch(14% 0 0);
--color-base-200: oklch(20% 0 0);
--color-base-300: oklch(26% 0 0);
--color-base-content: oklch(97% 0 0);
--color-primary: oklch(72% 0.219 149.579);
--color-primary-content: oklch(98% 0.018 155.826);
--color-secondary: oklch(58% 0.233 277.117);
--color-secondary-content: oklch(96% 0.018 272.314);
--color-accent: oklch(60% 0.25 292.717);
--color-accent-content: oklch(96% 0.016 293.756);
--color-neutral: oklch(20% 0 0);
--color-neutral-content: oklch(98% 0 0);
--color-info: oklch(58% 0.158 241.966);
--color-info-content: oklch(97% 0.013 236.62);
--color-success: oklch(64% 0.2 131.684);
--color-success-content: oklch(98% 0.031 120.757);
--color-warning: oklch(68% 0.162 75.834);
--color-warning-content: oklch(98% 0.026 102.212);
--color-error: oklch(57% 0.245 27.325);
--color-error-content: oklch(97% 0.013 17.38);
--radius-selector: 1rem;
--radius-field: 0.5rem;
--radius-box: 1rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 0;
--noise: 0;
}
@plugin "daisyui/theme" {
name: "dark";
color-scheme: "dark";
--color-base-100: oklch(14% 0 0);
--color-base-200: oklch(20% 0 0);
--color-base-300: oklch(26% 0 0);
--color-base-content: oklch(97% 0 0);
--color-primary: oklch(90% 0.182 98.111);
--color-primary-content: oklch(28% 0.066 53.813);
--color-secondary: oklch(84% 0.143 164.978);
--color-secondary-content: oklch(26% 0.051 172.552);
--color-accent: oklch(87% 0.01 258.338);
--color-accent-content: oklch(13% 0.028 261.692);
--color-neutral: oklch(26% 0 0);
--color-neutral-content: oklch(98% 0 0);
--color-info: oklch(71% 0.143 215.221);
--color-info-content: oklch(98% 0.019 200.873);
--color-success: oklch(76% 0.233 130.85);
--color-success-content: oklch(98% 0.031 120.757);
--color-warning: oklch(70% 0.213 47.604);
--color-warning-content: oklch(98% 0.016 73.684);
--color-error: oklch(65% 0.241 354.308);
--color-error-content: oklch(97% 0.014 343.198);
--radius-selector: 0rem;
--radius-field: 0.5rem;
--radius-box: 1rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 0;
--noise: 1;
}
@plugin "daisyui/theme" {
name: "pink";
color-scheme: "light";
--color-base-100: oklch(96% 0.015 12.422);
--color-base-200: oklch(94% 0.03 12.58);
--color-base-300: oklch(89% 0.058 10.001);
--color-base-content: oklch(41% 0.159 10.272);
--color-primary: oklch(86% 0.127 207.078);
--color-primary-content: oklch(30% 0.056 229.695);
--color-secondary: oklch(0% 0 0);
--color-secondary-content: oklch(100% 0 0);
--color-accent: oklch(87% 0.169 91.605);
--color-accent-content: oklch(27% 0.077 45.635);
--color-neutral: oklch(51% 0.222 16.935);
--color-neutral-content: oklch(96% 0.015 12.422);
--color-info: oklch(74% 0.16 232.661);
--color-info-content: oklch(29% 0.066 243.157);
--color-success: oklch(77% 0.152 181.912);
--color-success-content: oklch(27% 0.046 192.524);
--color-warning: oklch(75% 0.183 55.934);
--color-warning-content: oklch(26% 0.079 36.259);
--color-error: oklch(70% 0.191 22.216);
--color-error-content: oklch(25% 0.092 26.042);
--radius-selector: 0.25rem;
--radius-field: 0.25rem;
--radius-box: 0.25rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 1;
--noise: 0;
}
@plugin "daisyui/theme" {
name: "netherrack";
color-scheme: "dark";
--color-base-100: oklch(25% 0.092 26.042);
--color-base-200: oklch(39% 0.141 25.723);
--color-base-300: oklch(44% 0.177 26.899);
--color-base-content: oklch(93% 0.032 17.717);
--color-primary: oklch(83% 0.128 66.29);
--color-primary-content: oklch(26% 0.079 36.259);
--color-secondary: oklch(82% 0.111 230.318);
--color-secondary-content: oklch(29% 0.066 243.157);
--color-accent: oklch(78% 0.115 274.713);
--color-accent-content: oklch(25% 0.09 281.288);
--color-neutral: oklch(57% 0.245 27.325);
--color-neutral-content: oklch(97% 0.013 17.38);
--color-info: oklch(71% 0.143 215.221);
--color-info-content: oklch(98% 0.019 200.873);
--color-success: oklch(72% 0.219 149.579);
--color-success-content: oklch(98% 0.018 155.826);
--color-warning: oklch(76% 0.188 70.08);
--color-warning-content: oklch(98% 0.022 95.277);
--color-error: oklch(63% 0.237 25.331);
--color-error-content: oklch(97% 0.013 17.38);
--radius-selector: 2rem;
--radius-field: 2rem;
--radius-box: 2rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 1;
--noise: 1;
}
@plugin "daisyui/theme" {
name: "green";
color-scheme: "dark";
--color-base-100: oklch(26% 0.065 152.934);
--color-base-200: oklch(39% 0.095 152.535);
--color-base-300: oklch(44% 0.119 151.328);
--color-base-content: oklch(96% 0.044 156.743);
--color-primary: oklch(80% 0.105 251.813);
--color-primary-content: oklch(28% 0.091 267.935);
--color-secondary: oklch(80% 0.105 251.813);
--color-secondary-content: oklch(28% 0.091 267.935);
--color-accent: oklch(89% 0.196 126.665);
--color-accent-content: oklch(27% 0.072 132.109);
--color-neutral: oklch(52% 0.154 150.069);
--color-neutral-content: oklch(98% 0.018 155.826);
--color-info: oklch(78% 0.154 211.53);
--color-info-content: oklch(30% 0.056 229.695);
--color-success: oklch(79% 0.209 151.711);
--color-success-content: oklch(26% 0.065 152.934);
--color-warning: oklch(85% 0.199 91.936);
--color-warning-content: oklch(28% 0.066 53.813);
--color-error: oklch(71% 0.202 349.761);
--color-error-content: oklch(28% 0.109 3.907);
--radius-selector: 0.25rem;
--radius-field: 0.5rem;
--radius-box: 1rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 0;
--noise: 1;
}
.bg-grid-100 {
background:
linear-gradient(-90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px),
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), #f2f2f2;
background-size:
4px 4px,
4px 4px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px;
background-color: var(--color-base-100);
}
.bg-grid-200 {
background:
linear-gradient(-90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px),
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), #f2f2f2;
background-size:
4px 4px,
4px 4px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px;
background-color: var(--color-base-200);
}
.bg-grid-300 {
background:
linear-gradient(-90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px),
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), #f2f2f2;
background-size:
4px 4px,
4px 4px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px;
background-color: var(--color-base-300);
}
@media print {
.hide-on-print {
display: none !important;
}
}

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

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

42
src/app.html Normal file
View file

@ -0,0 +1,42 @@
<!doctype html>
<html lang="en" data-theme="Deprived" style="overflow-x: hidden">
<head>
<meta charset="utf-8" />
<meta
name="description"
content="
We are the deprived devs, and we are a team of developers specializing in indie game development, full-stack development, and anything tech-related!"
/>
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Change theme for site here -->
<link rel="stylesheet" href="/stylesheets/global.css" />
%sveltekit.head%
<script>
let theme = null;
if (typeof localStorage !== "undefined") {
theme = localStorage.getItem("theme");
}
window.AvailableThemes = ["green", "netherrack", "dark", "pink"];
if (!theme) {
// const randomNumber = Math.floor(Math.random() * 4);
// console.log("Slecting: " + AvailableThemes[randomNumber]);
// document.documentElement.setAttribute('data-theme', AvailableThemes[randomNumber]);
localStorage.setItem("theme", AvailableThemes[0]);
}
//else {
// console.log("Slecting: " + theme);
// document.documentElement.setAttribute('data-theme', theme);
//}
</script>
</head>
<body style="display: contents">
%sveltekit.body%
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View file

@ -0,0 +1,18 @@
<script>
export let Class = '';
export let Style = '';
</script>
<svg
class={Class}
style={Style}
height="20"
id="Layer_1"
version="1.1"
viewBox="0 0 28 20"
width="28"
xml:space="preserve"><defs
id="defs1" /><path
d="M 2,4 H 26 C 27.104,4 28,3.104 28,2 28,0.896 27.104,0 26,0 H 2 C 0.896,0 0,0.896 0,2 0,3.104 0.896,4 2,4 Z M 26,8 H 2 c -1.104,0 -2,0.896 -2,2 0,1.104 0.896,2 2,2 h 24 c 1.104,0 2,-0.896 2,-2 0,-1.104 -0.896,-2 -2,-2 z m 0,8 H 2 c -1.104,0 -2,0.896 -2,2 0,1.104 0.896,2 2,2 h 24 c 1.104,0 2,-0.896 2,-2 0,-1.104 -0.896,-2 -2,-2 z"
id="path1"
style="fill-opacity:1" /></svg>

View file

@ -0,0 +1,11 @@
# Svelte Branding Guidelines
## Conditions of usage
1. The term "Svelte logo" refers to the Svelte logo and other official artwork/mark. It also includes the official color scheme used by the project.
2. The term "Svelte library" refers to the Svelte tooling, associated libraries and official projects in the Svelte ecosystem.
3. Usage of the Svelte logo must not give the impression or implication that the Svelte project (or any contributor to the project) is sponsoring or endorsing any other project, service, product or organization.
4. Usage of the Svelte logo, to indicate, imply or assert compatibility or operability with the Svelte library, must be accurate and done in good faith.

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="519" height="139" viewBox="0 0 519 139"><title>svelte-horizontal</title><path d="M172.4428,100.3382a24.0793,24.0793,0,0,1-13.72-3.8769,19.8715,19.8715,0,0,1-8.0107-10.6094l8.3515-3.0683a15.4054,15.4054,0,0,0,5.4541,6.6044,14.3656,14.3656,0,0,0,8.2657,2.4288,12.1375,12.1375,0,0,0,7.8818-2.3858,8.2746,8.2746,0,0,0,2.94-6.8174,7.4559,7.4559,0,0,0-.8095-3.4511,10.325,10.325,0,0,0-1.8321-2.6,12.3611,12.3611,0,0,0-3.1533-2.0879q-2.1314-1.0635-3.5361-1.6192-1.4062-.5521-4.1328-1.4912-3.41-1.1924-5.1133-1.874a38.46,38.46,0,0,1-4.4737-2.2588,16.5385,16.5385,0,0,1-4.1757-3.1523,15.2908,15.2908,0,0,1-2.5137-4.1338,14.77,14.77,0,0,1,4.0049-16.7871q5.1138-4.5162,13.8906-4.5166,7.3272,0,12.0576,3.2382a15.6579,15.6579,0,0,1,6.3487,8.6075l-8.1807,2.7265a9.5238,9.5238,0,0,0-3.9629-4.3887,13.31,13.31,0,0,0-6.9443-1.6621,10.703,10.703,0,0,0-6.69,1.875,6.2891,6.2891,0,0,0-2.4287,5.2832,5.5132,5.5132,0,0,0,1.874,4.0909,12.885,12.885,0,0,0,3.92,2.6416q2.0464.8524,6.2217,2.3007,2.5547.939,3.791,1.4063t3.6221,1.5762a24.997,24.997,0,0,1,3.6641,2.0029,32.1346,32.1346,0,0,1,2.9824,2.4287,12.7235,12.7235,0,0,1,2.6,3.11,17.39,17.39,0,0,1,1.5332,3.8339,17.5828,17.5828,0,0,1,.64,4.8155q0,8.3524-5.71,13.08Q181.3892,100.3388,172.4428,100.3382Zm54.6221-1.0224L206.6128,39.6644h9.5449L229.7065,81.25a64.4659,64.4659,0,0,1,1.875,6.8173,64.0335,64.0335,0,0,1,1.875-6.8173l13.3789-41.586h9.459L235.9272,99.3158Zm47.294,0V39.6644h36.9843V48.016H283.2221V64.3773h18.15v8.3516h-18.15V90.9642h29.9952v8.3516Zm61.44,0V39.6644h8.8633v51.13h29.1435v8.5215Zm71.41-51.13v51.13h-8.8632v-51.13H381.4741V39.6644h42.6074v8.5215Zm35.1934,51.13V39.6644h36.9844V48.016H451.2661V64.3773h18.15v8.3516h-18.15V90.9642h29.9951v8.3516Z" style="fill:#4a4a55"/><path d="M110.2859,28.3189c-10.4-14.8851-30.94-19.2971-45.7914-9.8348L38.4118,35.1078A29.9232,29.9232,0,0,0,24.8931,55.1506a31.5143,31.5143,0,0,0,3.1076,20.2318,30.0059,30.0059,0,0,0-4.4761,11.1829,31.8885,31.8885,0,0,0,5.4472,24.1157c10.4022,14.8865,30.9424,19.2966,45.7915,9.8348l26.0826-16.6237a29.9182,29.9182,0,0,0,13.5187-20.0428,31.5276,31.5276,0,0,0-3.1057-20.2323,30.0012,30.0012,0,0,0,4.4742-11.1824,31.88,31.88,0,0,0-5.4472-24.1157" style="fill:#ff3e00"/><path d="M61.9463,112.0815A20.718,20.718,0,0,1,39.71,103.8389a19.173,19.173,0,0,1-3.2766-14.5025,18.1886,18.1886,0,0,1,.6233-2.4357l.4912-1.4978,1.3362.9815a33.6466,33.6466,0,0,0,10.203,5.0978l.9694.2941-.0892.9675a5.8469,5.8469,0,0,0,1.052,3.8781,6.2388,6.2388,0,0,0,6.6952,2.485,5.7456,5.7456,0,0,0,1.602-.7041L85.3993,81.781A5.431,5.431,0,0,0,87.85,78.15a5.7944,5.7944,0,0,0-.9876-4.3712,6.2435,6.2435,0,0,0-6.6977-2.4864,5.7427,5.7427,0,0,0-1.6.7036l-9.9533,6.3449a19.0336,19.0336,0,0,1-5.2964,2.3259A20.7182,20.7182,0,0,1,41.078,72.4241a19.173,19.173,0,0,1-3.2766-14.5024,17.9892,17.9892,0,0,1,8.13-12.0513L72.0125,29.2472a19.0031,19.0031,0,0,1,5.3-2.3287A20.718,20.718,0,0,1,99.549,35.1611a19.1734,19.1734,0,0,1,3.2766,14.5025,18.4,18.4,0,0,1-.6233,2.4357l-.4912,1.4978-1.3356-.98a33.6175,33.6175,0,0,0-10.2037-5.1l-.9693-.2942.0892-.9675a5.8576,5.8576,0,0,0-1.052-3.878,6.2388,6.2388,0,0,0-6.6952-2.485,5.7456,5.7456,0,0,0-1.602.7041L53.8592,57.219A5.422,5.422,0,0,0,51.41,60.85a5.7858,5.7858,0,0,0,.9857,4.3717,6.2435,6.2435,0,0,0,6.6977,2.4864,5.7652,5.7652,0,0,0,1.602-.7041l9.952-6.3425a18.9787,18.9787,0,0,1,5.2958-2.3278,20.7183,20.7183,0,0,1,22.2369,8.2427,19.173,19.173,0,0,1,3.2766,14.5024,17.9982,17.9982,0,0,1-8.13,12.0532L67.246,109.7528a19.0031,19.0031,0,0,1-5.3,2.3287" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -0,0 +1 @@
<svg id="svelte" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 688.774 139"><defs><style>.cls-1{fill:#8d8d93;}.cls-2{fill:#4a4a55;}.cls-3{fill:#ff3e00;}.cls-4{fill:#fff;}</style></defs><g id="horizontal"><path id="kit" class="cls-1" d="M547.528,99.316,530.741,68.127,520.173,80.91V99.316h-8.862V39.664h8.862V68.553l23.009-28.889h10.226l-16.7,20.964,21.218,38.688Zm29.569,0V39.664h8.862V99.316Zm55.049-51.13v51.13h-8.863V48.186H606.411V39.664h42.607v8.522Z"/><path id="svelte-2" data-name="svelte" class="cls-2" d="M172.442,100.338a24.076,24.076,0,0,1-13.719-3.877,19.876,19.876,0,0,1-8.011-10.609l8.351-3.068a15.41,15.41,0,0,0,5.455,6.6,14.366,14.366,0,0,0,8.266,2.429,12.137,12.137,0,0,0,7.882-2.386,8.277,8.277,0,0,0,2.94-6.817,7.461,7.461,0,0,0-.81-3.452,10.314,10.314,0,0,0-1.832-2.6,12.342,12.342,0,0,0-3.153-2.088q-2.132-1.063-3.537-1.619t-4.133-1.491q-3.408-1.193-5.112-1.874a38.492,38.492,0,0,1-4.474-2.259,16.522,16.522,0,0,1-4.176-3.153,15.277,15.277,0,0,1-2.513-4.133,14.766,14.766,0,0,1,4-16.787q5.113-4.516,13.889-4.517,7.329,0,12.059,3.238a15.658,15.658,0,0,1,6.348,8.608l-8.18,2.726a9.521,9.521,0,0,0-3.963-4.388,13.306,13.306,0,0,0-6.945-1.663,10.706,10.706,0,0,0-6.69,1.875,6.29,6.29,0,0,0-2.428,5.284,5.511,5.511,0,0,0,1.874,4.09,12.869,12.869,0,0,0,3.92,2.642q2.048.852,6.222,2.3,2.554.939,3.791,1.406t3.622,1.576a25.1,25.1,0,0,1,3.664,2,32.066,32.066,0,0,1,2.983,2.429,12.706,12.706,0,0,1,2.6,3.11,17.342,17.342,0,0,1,1.533,3.834,17.58,17.58,0,0,1,.64,4.816q0,8.352-5.71,13.08T172.442,100.338Zm54.623-1.022L206.613,39.664h9.545L229.707,81.25a64.791,64.791,0,0,1,1.875,6.818,63.829,63.829,0,0,1,1.875-6.818l13.378-41.586h9.459L235.927,99.316Zm47.294,0V39.664h36.984v8.352H283.222V64.377h18.151v8.352H283.222V90.964h30v8.352Zm61.44,0V39.664h8.864v51.13h29.143v8.522Zm71.41-51.13v51.13h-8.863V48.186H381.474V39.664h42.608v8.522ZM442.4,99.316V39.664h36.984v8.352H451.266V64.377h18.15v8.352h-18.15V90.964h30v8.352Z"/><g id="logo"><path id="orange" class="cls-3" d="M110.286,28.319c-10.4-14.885-30.941-19.3-45.792-9.835L38.412,35.108A29.921,29.921,0,0,0,24.893,55.151,31.514,31.514,0,0,0,28,75.382a29.987,29.987,0,0,0-4.476,11.183,31.888,31.888,0,0,0,5.447,24.116c10.4,14.887,30.942,19.3,45.791,9.835l26.083-16.624a29.92,29.92,0,0,0,13.519-20.043,31.529,31.529,0,0,0-3.106-20.232,30,30,0,0,0,4.474-11.182,31.878,31.878,0,0,0-5.447-24.116"/><path id="white" class="cls-4" d="M61.946,112.082a20.72,20.72,0,0,1-22.237-8.243,19.176,19.176,0,0,1-3.276-14.5,18.143,18.143,0,0,1,.623-2.435l.491-1.5,1.337.981a33.633,33.633,0,0,0,10.2,5.1l.969.294-.089.968a5.844,5.844,0,0,0,1.052,3.878,6.24,6.24,0,0,0,6.7,2.485,5.748,5.748,0,0,0,1.6-.7L85.4,81.781A5.43,5.43,0,0,0,87.85,78.15a5.794,5.794,0,0,0-.988-4.371,6.244,6.244,0,0,0-6.7-2.487,5.737,5.737,0,0,0-1.6.7l-9.954,6.345a19.047,19.047,0,0,1-5.3,2.326,20.72,20.72,0,0,1-22.237-8.243,19.171,19.171,0,0,1-3.277-14.5A17.992,17.992,0,0,1,45.932,45.87L72.013,29.247a19.011,19.011,0,0,1,5.3-2.329,20.719,20.719,0,0,1,22.237,8.243,19.176,19.176,0,0,1,3.277,14.5A18.453,18.453,0,0,1,102.2,52.1l-.491,1.5-1.336-.979a33.616,33.616,0,0,0-10.2-5.1l-.97-.294.09-.968a5.859,5.859,0,0,0-1.052-3.878,6.24,6.24,0,0,0-6.695-2.485,5.742,5.742,0,0,0-1.6.7L53.859,57.219a5.425,5.425,0,0,0-2.449,3.63,5.79,5.79,0,0,0,.986,4.372,6.245,6.245,0,0,0,6.7,2.487,5.773,5.773,0,0,0,1.6-.7l9.952-6.342a18.978,18.978,0,0,1,5.3-2.328A20.718,20.718,0,0,1,98.18,66.576a19.171,19.171,0,0,1,3.277,14.5,18,18,0,0,1-8.13,12.054L67.246,109.753a19,19,0,0,1-5.3,2.329"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,4 @@
<svg viewBox="30 31 400 50" xmlns="http://www.w3.org/2000/svg">
<path d="M348.645 80.0599L335.205 55.1536L326.745 65.3616V80.0599H319.648V32.4241H326.745V55.4938L345.169 32.4241H353.356L339.986 49.1652L356.974 80.0599H348.645ZM372.319 80.0599V32.4241H379.416V80.0599H372.319ZM416.394 39.2295V80.0599H409.3V39.2295H395.789V32.4241H429.902V39.2295H416.394Z" fill="#8D8D93"/>
<path d="M48.3359 80.876C44.4451 80.9736 40.6159 79.8942 37.3519 77.78C34.3023 75.7742 32.0378 72.7827 30.9387 69.3081L37.6241 66.8581C38.5518 68.991 40.066 70.8183 41.9916 72.1286C43.9468 73.4367 46.2574 74.1149 48.6113 74.0715C50.8732 74.1893 53.1053 73.5154 54.9219 72.1661C55.7123 71.5043 56.3367 70.6675 56.7454 69.7223C57.1541 68.7772 57.3357 67.7499 57.2758 66.7223C57.2852 65.7649 57.063 64.8193 56.6281 63.9657C56.2495 63.2023 55.7547 62.5019 55.1613 61.8894C54.4103 61.2078 53.5586 60.6454 52.6361 60.222C51.4981 59.6561 50.5542 59.2252 49.8042 58.9292C49.0543 58.6332 47.9513 58.2363 46.4952 57.7385C44.6761 57.1034 43.3118 56.6046 42.4023 56.242C41.1703 55.719 39.9737 55.1164 38.8202 54.4381C37.579 53.7813 36.4506 52.9313 35.4776 51.9202C34.6349 50.9339 33.9554 49.8197 33.4647 48.6198C32.5217 46.3326 32.3235 43.8075 32.8983 41.4018C33.473 38.9961 34.7915 36.8316 36.6673 35.2143C39.3991 32.8106 43.1066 31.6085 47.7898 31.608C51.7018 31.608 54.9201 32.4699 57.4448 34.1937C59.8955 35.819 61.695 38.2524 62.528 41.0678L55.9772 43.2446C55.3192 41.7704 54.2079 40.5431 52.8042 39.7406C51.1067 38.8008 49.184 38.3416 47.2438 38.4125C45.3411 38.3039 43.4564 38.8307 41.8875 39.9098C41.247 40.4053 40.7359 41.0476 40.3976 41.7822C40.0593 42.5168 39.9038 43.322 39.9443 44.1294C39.95 44.7485 40.0866 45.3594 40.3452 45.9222C40.6037 46.485 40.9784 46.987 41.4447 47.3956C42.3512 48.2863 43.4153 49.0016 44.5833 49.5054C45.6753 49.9589 47.3356 50.5712 49.5641 51.342C50.9278 51.8419 51.9396 52.2162 52.5993 52.4648C53.259 52.7134 54.2249 53.1332 55.4968 53.7242C56.5174 54.1744 57.4987 54.7086 58.4304 55.3213C59.2647 55.9196 60.0622 56.5673 60.8187 57.261C61.6416 57.9722 62.3444 58.8107 62.9003 59.7445C63.4302 60.7128 63.8425 61.7406 64.1285 62.8062C64.4763 64.0584 64.6485 65.3527 64.6401 66.6521C64.6401 71.0984 63.1162 74.5802 60.0685 77.0972C57.0207 79.6143 53.1098 80.8739 48.3359 80.876ZM92.0693 80.0599L75.6946 32.4241H83.3367L94.1846 65.6331C94.784 67.4193 95.2852 69.2369 95.6858 71.0777C96.085 69.2366 96.5861 67.4189 97.187 65.6331L107.899 32.4241H115.472L99.1646 80.0599H92.0693ZM129.935 80.0599V32.4241H159.546V39.0937H137.031V52.159H151.563V58.8286H137.031V73.3903H161.05V80.0599H129.935ZM179.126 80.0599V32.4241H186.223V73.2546H209.556V80.0599H179.126ZM236.301 39.2295V80.0599H229.204V39.2295H215.696V32.4241H249.813V39.2295H236.301ZM264.478 80.0599V32.4241H294.088V39.0937H271.574V52.159H286.106V58.8286H271.574V73.3903H295.593V80.0599H264.478Z" fill="#4A4A55"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1 @@
<svg id="svelte" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 354.69 300"><defs><style>.cls-1{fill:#8d8d93;}.cls-2{fill:#4a4a55;}.cls-3{fill:#ff3e00;}.cls-4{fill:#fff;}</style></defs><g id="vertical"><path id="kit" class="cls-1" d="M262.738,265.277l-9.776-18.162-6.154,7.443v10.719h-5.161V230.539h5.161v16.824l13.4-16.824h5.955l-9.727,12.209,12.357,22.529Zm17.22,0V230.539h5.161v34.738ZM312.016,235.5v29.775h-5.162V235.5h-9.826v-4.963h24.813V235.5Z"/><path id="svelte-2" data-name="svelte" class="cls-2" d="M44.3,265.873a14.021,14.021,0,0,1-7.989-2.258,11.575,11.575,0,0,1-4.665-6.178l4.863-1.787A8.979,8.979,0,0,0,39.69,259.5,8.364,8.364,0,0,0,44.5,260.91a7.068,7.068,0,0,0,4.59-1.389,4.818,4.818,0,0,0,1.713-3.97,4.342,4.342,0,0,0-.472-2.01,6.011,6.011,0,0,0-1.067-1.514,7.214,7.214,0,0,0-1.836-1.216q-1.24-.62-2.06-.943T42.964,249q-1.984-.695-2.977-1.091a22.434,22.434,0,0,1-2.605-1.316,9.6,9.6,0,0,1-2.432-1.836,8.917,8.917,0,0,1-1.464-2.407,8.6,8.6,0,0,1,2.333-9.776,11.785,11.785,0,0,1,8.088-2.63,12.178,12.178,0,0,1,7.023,1.885,9.122,9.122,0,0,1,3.7,5.013l-4.764,1.588a5.548,5.548,0,0,0-2.308-2.556,7.751,7.751,0,0,0-4.045-.968A6.235,6.235,0,0,0,39.615,236a3.662,3.662,0,0,0-1.414,3.077,3.21,3.21,0,0,0,1.091,2.382A7.489,7.489,0,0,0,41.575,243q1.192.5,3.623,1.34,1.488.547,2.208.819t2.109.918a14.553,14.553,0,0,1,2.134,1.167,18.647,18.647,0,0,1,1.737,1.414,7.419,7.419,0,0,1,1.514,1.811,10.557,10.557,0,0,1,1.265,5.037,9.356,9.356,0,0,1-3.325,7.618A12.935,12.935,0,0,1,44.3,265.873Zm31.81-.6L64.2,230.539h5.558l7.891,24.218a37.7,37.7,0,0,1,1.092,3.97,37.217,37.217,0,0,1,1.092-3.97l7.791-24.218h5.508L81.275,265.277Zm27.542,0V230.539h21.538V235.4H108.818v9.528h10.57v4.863h-10.57v10.62h17.468v4.863Zm35.78,0V230.539H144.6v29.776H161.57v4.962ZM181.023,235.5v29.775h-5.162V235.5h-9.826v-4.963h24.813V235.5Zm20.5,29.775V230.539h21.538V235.4H206.679v9.528h10.57v4.863h-10.57v10.62h17.468v4.863Z"/><g id="logo"><path id="orange" class="cls-3" d="M240.635,52.089C224.292,28.7,192.014,21.765,168.677,36.634L127.69,62.757a47.02,47.02,0,0,0-21.244,31.5,49.527,49.527,0,0,0,4.883,31.793,47.178,47.178,0,0,0-7.034,17.573,50.113,50.113,0,0,0,8.56,37.9c16.347,23.393,48.624,30.323,71.958,15.455L225.8,170.847a47.015,47.015,0,0,0,21.244-31.5,49.549,49.549,0,0,0-4.88-31.794A47.162,47.162,0,0,0,249.2,89.985a50.1,50.1,0,0,0-8.56-37.9"/><path id="white" class="cls-4" d="M164.672,183.716a32.556,32.556,0,0,1-34.943-12.953,30.13,30.13,0,0,1-5.149-22.789,28.58,28.58,0,0,1,.979-3.828l.772-2.354,2.1,1.543a52.89,52.89,0,0,0,16.033,8.011l1.524.462-.141,1.52a9.188,9.188,0,0,0,1.654,6.094,9.8,9.8,0,0,0,10.521,3.905,9.018,9.018,0,0,0,2.517-1.106l40.988-26.12a8.534,8.534,0,0,0,3.851-5.706,9.1,9.1,0,0,0-1.552-6.869,9.81,9.81,0,0,0-10.525-3.907,9.006,9.006,0,0,0-2.514,1.105L175.146,130.7a29.912,29.912,0,0,1-8.323,3.655A32.557,32.557,0,0,1,131.879,121.4a30.129,30.129,0,0,1-5.149-22.789A28.268,28.268,0,0,1,139.507,79.67l40.984-26.122a29.851,29.851,0,0,1,8.328-3.66,32.556,32.556,0,0,1,34.943,12.953,30.126,30.126,0,0,1,5.149,22.789,28.92,28.92,0,0,1-.979,3.828l-.772,2.354-2.1-1.54a52.846,52.846,0,0,0-16.034-8.014L207.5,81.8l.14-1.52a9.21,9.21,0,0,0-1.653-6.094,9.8,9.8,0,0,0-10.521-3.905,9.011,9.011,0,0,0-2.518,1.106L151.964,97.5a8.52,8.52,0,0,0-3.848,5.7,9.1,9.1,0,0,0,1.549,6.87,9.81,9.81,0,0,0,10.525,3.907,9.036,9.036,0,0,0,2.517-1.106l15.639-9.967a29.823,29.823,0,0,1,8.322-3.658,32.557,32.557,0,0,1,34.944,12.953A30.13,30.13,0,0,1,226.761,135a28.28,28.28,0,0,1-12.776,18.94L173,180.056a29.838,29.838,0,0,1-8.328,3.66"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.8.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 93.2 112" style="enable-background:new 0 0 93.2 112;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FF3E00;}
</style>
<path class="st0" d="M87.3,14.8L87.3,14.8C76.9-0.1,56.3-4.5,41.5,5L15.4,21.6c-7.1,4.5-12,11.8-13.5,20c-1.2,6.9-0.2,14,3.1,20.2
c-2.2,3.4-3.8,7.2-4.5,11.2C-1,81.5,1,90.2,5.9,97.2c10.4,14.9,30.9,19.3,45.8,9.8l26.1-16.6c7.1-4.5,12-11.8,13.5-20
c1.2-6.9,0.2-14-3.1-20.2c2.2-3.4,3.8-7.2,4.5-11.2C94.2,30.5,92.2,21.8,87.3,14.8z M79.8,36.2c-0.2,0.8-0.4,1.6-0.6,2.4l-0.5,1.5
l-1.3-1c-3.1-2.3-6.5-4-10.2-5.1l-1-0.3l0.1-1c0.1-1.4-0.3-2.7-1.1-3.9c-1.5-2.2-4.2-3.1-6.7-2.5c-0.6,0.2-1.1,0.4-1.6,0.7
L30.8,43.7c-1.3,0.8-2.2,2.1-2.4,3.6c-0.3,1.5,0.1,3.1,1,4.4c1.5,2.2,4.2,3.1,6.7,2.5c0.6-0.2,1.1-0.4,1.6-0.7l10-6.3
c1.6-1,3.4-1.8,5.3-2.3c8.4-2.2,17.3,1.1,22.2,8.2c3,4.2,4.2,9.4,3.3,14.5c-0.9,5-3.8,9.4-8.1,12.1L44.2,96.3
c-1.6,1-3.4,1.8-5.3,2.3h0c-8.4,2.2-17.3-1.1-22.2-8.2c-3-4.2-4.2-9.4-3.3-14.5c0.2-0.8,0.4-1.6,0.6-2.4l0.5-1.5l1.3,1
c3.1,2.3,6.5,4,10.2,5.1l1,0.3l-0.1,1c-0.1,1.4,0.3,2.8,1.1,3.9c1.5,2.2,4.2,3.1,6.7,2.5c0.6-0.2,1.1-0.4,1.6-0.7l26.1-16.6
c1.3-0.8,2.2-2.1,2.5-3.6c0.3-1.5-0.1-3.1-1-4.4c-1.5-2.2-4.2-3.1-6.7-2.5c-0.6,0.2-1.1,0.4-1.6,0.7l-10,6.3c-1.6,1-3.4,1.8-5.3,2.3
C31.9,69.4,23,66.1,18,58.9c-3-4.2-4.2-9.4-3.3-14.5c0.9-5,3.8-9.4,8.1-12.1L49,15.7c1.6-1,3.4-1.8,5.3-2.3
c8.4-2.2,17.3,1.1,22.2,8.2C79.5,25.9,80.7,31.1,79.8,36.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416.9 93.1c-41.1-58.9-122.4-76.3-181.2-38.9L132.5 120c-28.2 17.7-47.6 46.5-53.5 79.3-4.9 27.3-.6 55.5 12.3 80-8.8 13.4-14.9 28.5-17.7 44.2-5.9 33.4 1.8 67.8 21.6 95.4 41.2 58.9 122.4 76.3 181.2 38.9L379.6 392c28.2-17.7 47.6-46.5 53.5-79.3 4.9-27.3.6-55.5-12.3-80 8.8-13.4 14.9-28.4 17.7-44.2 5.8-33.4-1.9-67.8-21.6-95.4" style="fill:#ff3e00"/><path d="M225.6 424.5c-33.3 8.6-68.4-4.4-88-32.6-11.9-16.6-16.5-37.3-13-57.4.6-3.3 1.4-6.5 2.5-9.6l1.9-5.9 5.3 3.9c12.2 9 25.9 15.8 40.4 20.2l3.8 1.2-.4 3.8c-.5 5.4 1 10.9 4.2 15.3 5.9 8.5 16.5 12.4 26.5 9.8 2.2-.6 4.4-1.5 6.3-2.8l103.2-65.8c5.1-3.2 8.6-8.4 9.7-14.4 1.1-6.1-.3-12.3-3.9-17.3-5.9-8.5-16.5-12.4-26.5-9.8-2.2.6-4.4 1.5-6.3 2.8L252 291c-6.5 4.1-13.5 7.2-21 9.2-33.3 8.6-68.4-4.4-88-32.6-11.9-16.6-16.5-37.3-13-57.4 3.5-19.7 15.2-37 32.2-47.7l103.2-65.8c6.5-4.1 13.5-7.2 21-9.2 33.3-8.6 68.4 4.4 88 32.6 11.9 16.6 16.5 37.3 13 57.4-.6 3.3-1.4 6.5-2.5 9.6L383 193l-5.3-3.9c-12.2-9-25.9-15.8-40.4-20.2l-3.8-1.2.4-3.8c.5-5.4-1-10.9-4.2-15.3-5.9-8.5-16.5-12.4-26.5-9.8-2.2.6-4.4 1.5-6.3 2.8l-103.2 65.8c-5.1 3.2-8.6 8.4-9.7 14.4-1.1 6.1.3 12.3 3.9 17.3 5.9 8.5 16.5 12.4 26.5 9.8 2.2-.6 4.4-1.5 6.3-2.8L260 221c6.5-4.1 13.5-7.2 21-9.2 33.3-8.6 68.4 4.4 88 32.6 11.9 16.6 16.5 37.3 13 57.4-3.5 19.7-15.2 37-32.2 47.7l-103.2 65.8c-6.5 4.1-13.6 7.2-21 9.2" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.1566,22.8189c-10.4-14.8851-30.94-19.2971-45.7914-9.8348L22.2825,29.6078A29.9234,29.9234,0,0,0,8.7639,49.6506a31.5136,31.5136,0,0,0,3.1076,20.2318A30.0061,30.0061,0,0,0,7.3953,81.0653a31.8886,31.8886,0,0,0,5.4473,24.1157c10.4022,14.8865,30.9423,19.2966,45.7914,9.8348L84.7167,98.3921A29.9177,29.9177,0,0,0,98.2353,78.3493,31.5263,31.5263,0,0,0,95.13,58.117a30,30,0,0,0,4.4743-11.1824,31.88,31.88,0,0,0-5.4473-24.1157" style="fill:#ff3e00"/><path d="M45.8171,106.5815A20.7182,20.7182,0,0,1,23.58,98.3389a19.1739,19.1739,0,0,1-3.2766-14.5025,18.1886,18.1886,0,0,1,.6233-2.4357l.4912-1.4978,1.3363.9815a33.6443,33.6443,0,0,0,10.203,5.0978l.9694.2941-.0893.9675a5.8474,5.8474,0,0,0,1.052,3.8781,6.2389,6.2389,0,0,0,6.6952,2.485,5.7449,5.7449,0,0,0,1.6021-.7041L69.27,76.281a5.4306,5.4306,0,0,0,2.4506-3.631,5.7948,5.7948,0,0,0-.9875-4.3712,6.2436,6.2436,0,0,0-6.6978-2.4864,5.7427,5.7427,0,0,0-1.6.7036l-9.9532,6.3449a19.0329,19.0329,0,0,1-5.2965,2.3259,20.7181,20.7181,0,0,1-22.2368-8.2427,19.1725,19.1725,0,0,1-3.2766-14.5024,17.9885,17.9885,0,0,1,8.13-12.0513L55.8833,23.7472a19.0038,19.0038,0,0,1,5.3-2.3287A20.7182,20.7182,0,0,1,83.42,29.6611a19.1739,19.1739,0,0,1,3.2766,14.5025,18.4,18.4,0,0,1-.6233,2.4357l-.4912,1.4978-1.3356-.98a33.6175,33.6175,0,0,0-10.2037-5.1l-.9694-.2942.0893-.9675a5.8588,5.8588,0,0,0-1.052-3.878,6.2389,6.2389,0,0,0-6.6952-2.485,5.7449,5.7449,0,0,0-1.6021.7041L37.73,51.719a5.4218,5.4218,0,0,0-2.4487,3.63,5.7862,5.7862,0,0,0,.9856,4.3717,6.2437,6.2437,0,0,0,6.6978,2.4864,5.7652,5.7652,0,0,0,1.602-.7041l9.9519-6.3425a18.978,18.978,0,0,1,5.2959-2.3278,20.7181,20.7181,0,0,1,22.2368,8.2427,19.1725,19.1725,0,0,1,3.2766,14.5024,17.9977,17.9977,0,0,1-8.13,12.0532L51.1167,104.2528a19.0038,19.0038,0,0,1-5.3,2.3287" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="406" height="139" viewBox="0 0 406 139"><title>svelte-logotype</title><path d="M59.4561,100.3382a24.08,24.08,0,0,1-13.72-3.8769,19.8715,19.8715,0,0,1-8.0107-10.6094l8.3515-3.0683a15.4054,15.4054,0,0,0,5.4541,6.6044,14.3656,14.3656,0,0,0,8.2657,2.4288,12.1373,12.1373,0,0,0,7.8818-2.3858,8.2746,8.2746,0,0,0,2.94-6.8174,7.4559,7.4559,0,0,0-.8095-3.4511,10.3225,10.3225,0,0,0-1.8321-2.6,12.3611,12.3611,0,0,0-3.1533-2.0879q-2.1314-1.0635-3.5361-1.6192-1.4062-.5521-4.1328-1.4912-3.41-1.1924-5.1133-1.874a38.4516,38.4516,0,0,1-4.4736-2.2588,16.5374,16.5374,0,0,1-4.1758-3.1523,15.2908,15.2908,0,0,1-2.5137-4.1338,14.77,14.77,0,0,1,4.0049-16.7871q5.1138-4.5162,13.8906-4.5166,7.3272,0,12.0576,3.2382a15.6575,15.6575,0,0,1,6.3487,8.6075L69,53.2142a9.5238,9.5238,0,0,0-3.9629-4.3887,13.31,13.31,0,0,0-6.9443-1.6621,10.703,10.703,0,0,0-6.6895,1.875,6.2891,6.2891,0,0,0-2.4287,5.2832,5.5132,5.5132,0,0,0,1.874,4.0909,12.8853,12.8853,0,0,0,3.92,2.6416q2.0463.8524,6.2216,2.3007,2.5548.939,3.791,1.4063t3.6221,1.5762A24.997,24.997,0,0,1,72.0674,68.34,32.1346,32.1346,0,0,1,75.05,70.7689a12.7235,12.7235,0,0,1,2.6,3.11,17.39,17.39,0,0,1,1.5332,3.8339,17.5828,17.5828,0,0,1,.64,4.8155q0,8.3524-5.71,13.08Q68.4024,100.3388,59.4561,100.3382Zm54.622-1.0224L93.626,39.6644h9.5449L116.72,81.25a64.4659,64.4659,0,0,1,1.875,6.8173A64.0335,64.0335,0,0,1,120.47,81.25l13.3789-41.586h9.459L122.94,99.3158Zm47.294,0V39.6644h36.9843V48.016h-28.121V64.3773h18.15v8.3516h-18.15V90.9642h29.9951v8.3516Zm61.44,0V39.6644h8.8633v51.13h29.1435v8.5215Zm71.41-51.13v51.13h-8.8633v-51.13H268.4873V39.6644h42.6074v8.5215Zm35.1933,51.13V39.6644H366.4V48.016H338.2793V64.3773h18.15v8.3516h-18.15V90.9642h29.9951v8.3516Z" style="fill:#4a4a55"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="300" viewBox="0 0 256 300"><title>svelte-vertical</title><path d="M44.4129,265.87a14.0218,14.0218,0,0,1-7.9891-2.2576,11.5714,11.5714,0,0,1-4.6647-6.178l4.8632-1.7867a8.97,8.97,0,0,0,3.1759,3.8459,8.3658,8.3658,0,0,0,4.8132,1.4142,7.068,7.068,0,0,0,4.59-1.3892,4.8185,4.8185,0,0,0,1.7122-3.97,4.3412,4.3412,0,0,0-.4714-2.01,6.0115,6.0115,0,0,0-1.0668-1.5138,7.2027,7.2027,0,0,0-1.8362-1.2158q-1.2411-.6192-2.0591-.9428-.819-.3216-2.4066-.8684-1.9858-.6943-2.9775-1.0912a22.4089,22.4089,0,0,1-2.6051-1.3153,9.6307,9.6307,0,0,1-2.4316-1.8357,8.9022,8.9022,0,0,1-1.4637-2.4071,8.6,8.6,0,0,1,2.3321-9.7753,11.7841,11.7841,0,0,1,8.0886-2.63,12.1677,12.1677,0,0,1,7.0213,1.8857,9.1177,9.1177,0,0,1,3.6969,5.0122l-4.7637,1.5877a5.546,5.546,0,0,0-2.3077-2.5556,7.7507,7.7507,0,0,0-4.0437-.9678,6.2321,6.2321,0,0,0-3.8953,1.0918,3.6619,3.6619,0,0,0-1.4143,3.0764,3.21,3.21,0,0,0,1.0913,2.3822,7.5015,7.5015,0,0,0,2.2826,1.5382q1.1916.4965,3.6229,1.34,1.4877.5468,2.2076.8188t2.1091.9179a14.5435,14.5435,0,0,1,2.1336,1.1663,18.7071,18.7071,0,0,1,1.7367,1.4142,7.4076,7.4076,0,0,1,1.5138,1.8112,10.1257,10.1257,0,0,1,.8928,2.2326,10.24,10.24,0,0,1,.3725,2.8041,9.3524,9.3524,0,0,1-3.325,7.6166A12.9325,12.9325,0,0,1,44.4129,265.87Zm31.807-.5954L64.31,230.5391h5.5581l7.89,24.2159a37.5389,37.5389,0,0,1,1.0919,3.97,37.2955,37.2955,0,0,1,1.0918-3.97l7.7907-24.2159h5.508l-11.86,34.7356Zm27.54,0V230.5391H125.296v4.8632H108.9208V244.93H119.49v4.8632H108.9208v10.6186h17.4665v4.8632Zm35.7774,0V230.5391h5.1612v29.7734h16.9706v4.9622ZM181.12,235.5012v29.7735h-5.1612V235.5012h-9.8248v-4.9621h24.8107v4.9621Zm20.4934,29.7735V230.5391H223.15v4.8632H206.7745V244.93h10.5691v4.8632H206.7745v10.6186h17.4664v4.8632Z" style="fill:#4a4a55"/><path d="M191.8716,52.1065c-16.3379-23.3845-48.6074-30.3158-71.9383-15.45L78.9574,62.7719A47.0092,47.0092,0,0,0,57.72,94.2591a49.5083,49.5083,0,0,0,4.882,31.7842,47.14,47.14,0,0,0-7.032,17.5683,50.097,50.097,0,0,0,8.5576,37.8858c16.3419,23.3867,48.61,30.3149,71.9383,15.45l40.9759-26.1158a47.001,47.001,0,0,0,21.2378-31.4872A49.5286,49.5286,0,0,0,193.4,107.56a47.13,47.13,0,0,0,7.0291-17.5676,50.0832,50.0832,0,0,0-8.5576-37.8857" style="fill:#ff3e00"/><path d="M115.93,183.6976A32.5485,32.5485,0,0,1,80.996,170.7485a30.1218,30.1218,0,0,1-5.1475-22.7834,28.582,28.582,0,0,1,.9792-3.8266l.7717-2.3529,2.0992,1.5418a52.8582,52.8582,0,0,0,16.029,8.0087l1.5229.4621-.14,1.52a9.1869,9.1869,0,0,0,1.6528,6.0925,9.8011,9.8011,0,0,0,10.5181,3.9039,9.0254,9.0254,0,0,0,2.5168-1.1062l40.9769-26.1128a8.5317,8.5317,0,0,0,3.85-5.7043,9.1034,9.1034,0,0,0-1.5515-6.8672,9.8084,9.8084,0,0,0-10.5221-3.9061,9.02,9.02,0,0,0-2.5138,1.1054l-15.6366,9.9678a29.8952,29.8952,0,0,1-8.3206,3.6539A32.5485,32.5485,0,0,1,83.146,121.3959a30.1208,30.1208,0,0,1-5.1475-22.7834A28.261,28.261,0,0,1,90.7712,79.68l40.9729-26.115a29.8528,29.8528,0,0,1,8.3258-3.6584A32.5482,32.5482,0,0,1,175.004,62.8556a30.1218,30.1218,0,0,1,5.1475,22.7834,28.9008,28.9008,0,0,1-.9792,3.8265l-.7717,2.353L176.3024,90.28a52.8164,52.8164,0,0,0-16.03-8.0117l-1.5229-.462.14-1.52a9.2036,9.2036,0,0,0-1.6528-6.0924A9.8011,9.8011,0,0,0,146.7189,70.29a9.0252,9.0252,0,0,0-2.5168,1.1061L103.2252,97.5085a8.5183,8.5183,0,0,0-3.847,5.7035,9.09,9.09,0,0,0,1.5485,6.8681,9.8085,9.8085,0,0,0,10.5221,3.9061,9.0586,9.0586,0,0,0,2.5168-1.1062L129.6,102.9159a29.8159,29.8159,0,0,1,8.32-3.6569,32.5484,32.5484,0,0,1,34.9341,12.9492,30.1207,30.1207,0,0,1,5.1475,22.7834A28.275,28.275,0,0,1,165.23,153.9271l-40.9738,26.112a29.8538,29.8538,0,0,1-8.3257,3.6585" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 MiB

1
src/optimizers/fly.ts Normal file
View file

@ -0,0 +1 @@
export { fly as default } from "svelte/transition";

View file

@ -0,0 +1 @@
export { onDestroy as default } from "svelte";

View file

@ -0,0 +1 @@
export { onMount as default } from "svelte";

View file

@ -0,0 +1 @@
export { sveltekit as default } from "@sveltejs/kit/vite";

1
src/optimizers/tick.ts Normal file
View file

@ -0,0 +1 @@
export { tick as default } from "svelte";

View file

@ -0,0 +1 @@
export { vitePreprocess as default } from "@sveltejs/vite-plugin-svelte";

View file

@ -0,0 +1,102 @@
<script lang="ts">
import CustomScrollBar from "@src/routes/comps/CustomScrollBar.svelte";
import { Info } from "lucide-svelte";
import { marked } from "marked";
import { onMount } from "svelte";
let desc: HTMLDivElement;
const testMarkdown = `
# I'm a Markdown header
## I'm a smaller Markdown header
This is a paragraph of **Lorem Ipsum** text. I can use _italics_, \`inline code\`, and even a [link to Google](https://www.google.com).
Here's a list:
* Item one
* Item two
* Item three
And here's a blockquote:
> This is a quote, a famous one at that, from some wise person.
`;
onMount(async () => {
desc.innerHTML = await marked.parse(testMarkdown);
});
</script>
<div class="grid grid-cols-6 w-full h-[80vh]">
<div class="h-full col-start-2 col-span-2">
<div class="flex flex-col items-center justify-center w-full h-full">
<div class="flex flex-col w-72 gap-4">
<div class="flext justify-center items-center w-full h-72 bg-lime-200">
<img
class="object-cover w-full h-full"
src="https://picsum.photos/seed/picsum/200/300"
alt=""
/>
</div>
<CustomScrollBar overflowX="scroll" overflowY="hidden" Class="">
<div class="relative flex w-full gap-4 pb-4">
{#each { length: 6 } as i}
<img
src="https://placehold.co/600x400"
class="w-16 h-16 object-cover"
alt=""
/>
{/each}
</div>
</CustomScrollBar>
</div>
</div>
</div>
<div class="h-full col-start-4 col-span-2">
<div class="flex flex-col items-center justify-center w-full h-full">
<div class="w-full grid items-center">
<div
class="flex border-l-2 pl-1 border-primary-content text-primary-content flex-col w-full"
>
<span class="text-left text-2xl">Art thing - Zylle</span>
<span class="text-left">100DKK</span>
</div>
<div class="py-1"></div>
<div class="flex">
<div class="flex flex-col text-primary-content opacity-30">
<span>10EUR</span>
<span>10USD</span>
<span>10GBP</span>
</div>
<div
class="tooltip"
data-tip="These conversions is a rough estimate, based on data I found on Google"
>
<Info class="opacity-30 p-1" />
</div>
</div>
<div class="py-16"></div>
<div class="flex w-full gap-2">
<input type="number" class="input w-32" />
<button class="btn grow btn-primary">Buy</button>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-6 w-full h-[80vh]">
<div class="col-start-2 col-span-4">
<div class="tabs tabs-box">
<input type="radio" name="my_tabs_1" class="tab" aria-label="Tab 1" />
<input
type="radio"
name="my_tabs_1"
class="tab"
aria-label="Tab 2"
checked="checked"
/>
<input type="radio" name="my_tabs_1" class="tab" aria-label="Tab 3" />
</div>
<div bind:this={desc}></div>
</div>
</div>

View file

@ -0,0 +1,29 @@
<script lang="ts">
import onMount from "@e/onMount";
import ShopItemCard from "./comps/ShopItemCard.svelte";
import { api } from "@stores";
import ShopItem from "@src/ts/api/classes/ShopItem";
let allItems: undefined | ShopItem[] = undefined;
onMount(async () => {
allItems = await api.GetAllShopItems();
console.log(allItems);
});
</script>
<div class="p-8 flex w-full justify-center">
<div class="text-4xl cozette">Items</div>
</div>
<div class="flex w-full justify-center">
<div class="grid grid-cols-2 gap-8">
{#if allItems != undefined}
{#each allItems as item, i}
<ShopItemCard bind:shopItem={item} />
{/each}
{:else}
<div></div>
{/if}
</div>
</div>

View file

@ -0,0 +1,79 @@
<script lang="ts">
import onMount from "@e/onMount";
let cart = {
trackers: 0,
receivers: 0,
};
function sanityCheck() {
Object.keys(cart).forEach((k) => (cart[k] = Math.max(0, cart[k] || 0)));
}
onMount(async () => {
console.log(window.location.href);
});
</script>
<div class="grid grid-cols-6 gap-8 items-center gap-x-16 pt-32 lg:px-32">
{#each { length: 6 } as i}
<div
class="w-48 h-48 bg-blue-500 justify-self-end max-md:col-start-3"
></div>
<div class="flex flex-col">
<div class="justify-self-start flex flex-col w-full col-start-4">
<div>Tracker</div>
<div>NRF52840 + ICM45856</div>
<div class="flex items-center gap-4">
<div class="flex flex-col">
<div>200DKK</div>
<div class="flex text-sm">
<div>20GBP</div>
<div>25USD</div>
</div>
</div>
<div class="flex join">
<button
class="join-item btn btn-xs btn-primary"
on:click={() => {
cart.trackers--;
sanityCheck();
}}>-</button
>
<div class="join-item input input-xs input-disable cursor-default">
{cart.trackers}
</div>
<button
class="join-item btn btn-xs btn-primary"
on:click={() => {
cart.trackers++;
sanityCheck();
}}>+</button
>
</div>
</div>
</div>
</div>
{/each}
</div>
{#if false}
<!-- This just visualizes the current tailwind breakpoint -->
<div
class="back-to-top text-content rounded-full bg-base-300 p-4 border-secondary border-2 text-primary transition-all duration-300 z-50 fixed"
>
<span style="font-size: 2rem;" class="block sm:hidden"><b>Default</b></span>
<span style="font-size: 2rem;" class="hidden sm:block md:hidden"
><b>SM</b></span
>
<span style="font-size: 2rem;" class="hidden md:block lg:hidden"
><b>MD</b></span
>
<span style="font-size: 2rem;" class="hidden lg:block xl:hidden"
><b>LG</b></span
>
<span style="font-size: 2rem;" class="hidden xl:block 2xl:hidden"
><b>XL</b></span
>
<span style="font-size: 2rem;" class="hidden 2xl:block"><b>2XL</b></span>
</div>
{/if}

View file

@ -0,0 +1,112 @@
<script lang="ts">
import type ShopItem from "@src/ts/api/classes/ShopItem";
import ArrowBigRight from "lucide-svelte/icons/arrow-big-right";
export let shopItem: ShopItem;
const selectionScale = 95;
</script>
<div class="">
<div class="relative w-48 h-48">
<div class="corner-border-container">
<div class="w-full h-full flex flex-col justify-end">
<div class="flex flex-col justify-center items-center">
<span class="text-xl font-semibold text-center w-full"
>{shopItem.item_name}</span
>
<span>{@html shopItem.short_desc}</span>
</div>
<div class="flex justify-end p-2">
<a
class="btn not-hover:btn-outline btn-primary btn-square"
href={shopItem.page_url}><ArrowBigRight /></a
>
</div>
</div>
</div>
<div
class="absolute"
style:top={`${-(selectionScale - 100) / 2}%`}
style:left={`${-(selectionScale - 100) / 2}%`}
style:width={`${selectionScale}%`}
style:height={`${selectionScale}%`}
>
<div class="w-full h-full">
<img
class="object-cover w-full h-full peer rounded"
src={shopItem.preview_image}
alt=""
/>
</div>
</div>
</div>
</div>
<style>
.corner-border-container {
/* Controls */
--length: 8px;
--width: 2px;
--line-color: #eeeeee;
/* Sit on top of the image */
position: absolute;
inset: 0;
z-index: 1;
/* Corner lines (same 8-gradients as before) */
background-image:
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color));
background-position:
top left,
top left,
top right,
top right,
bottom right,
bottom right,
bottom left,
bottom left;
background-repeat: no-repeat;
/* Start: invisible and a bit bigger */
opacity: 0;
transform: scale(1.06);
background-color: transparent;
/* Draw lines from 0 length */
--x: 0;
--y: 0;
background-size:
var(--x) var(--width),
var(--width) var(--y),
var(--x) var(--width),
var(--width) var(--y),
var(--x) var(--width),
var(--width) var(--y),
var(--x) var(--width),
var(--width) var(--y);
transition:
opacity 220ms ease,
transform 220ms ease,
background-size 220ms ease,
background-color 220ms ease;
}
/* On hover: normal size + visible + darken backdrop */
.relative:hover .corner-border-container {
--x: var(--length);
--y: var(--length);
opacity: 1;
transform: scale(1);
background-color: rgba(0, 0, 0, 0.65);
}
</style>

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

@ -0,0 +1,271 @@
<!-- If url contains "hideOnPrint" param, then detect if start printing then hide elements -->
<script lang="ts">
import "../app.css";
import fly from "@e/fly";
import MediaQuery from "svelte-media-queries";
import Dices from "@lucide/svelte/icons/dices";
import re from "@ts/Redaction/Redactor";
let hideOnPrint: boolean = $state(false);
let { children } = $props();
import DeprivedLogo from "$lib/images/DeprivedLogo.svelte";
import HamburgerMenuIcon from "$lib/images/HamburgerMenuIcon.svelte";
const footerCollapseThreshold: string = "40rem";
const headerCollapseThreshold: string = "40rem";
let footerCollapse: boolean;
let isMobile: boolean = $state(false);
let navbarHidden: boolean = $state(true);
let isDevUrl = $state(false);
function resetNavBar() {
navbarHidden = true;
}
function handleUrlParams() {
const params = new URLSearchParams(window.location.search);
hideOnPrint = params.get("hideOnPrint") === "1";
if (!!params.get("key")) {
localStorage.setItem("key", params.get("key")!);
}
}
import { afterNavigate } from "$app/navigation";
afterNavigate(() => {
handleUrlParams();
});
import onMount from "@e/onMount";
import Zooter from "./comps/Zooter.svelte";
import CustomScrollBar from "./comps/CustomScrollBar.svelte";
onMount(async () => {
handleUrlParams();
const lock = document.createElement("meta");
lock.name = "darkreader-lock";
document.head.appendChild(lock);
await re.TryGetUnredacter();
const { hostname } = window.location;
isDevUrl = hostname.includes("dev") || hostname.includes("localhost");
});
function nextTheme() {
let theme: string | null = null;
if (typeof localStorage !== "undefined") {
theme = localStorage.getItem("theme");
}
const themesArr = (window as any).AvailableThemes;
let nextTheme = "dark";
if (
theme == "null" ||
theme == "undefined" ||
theme == undefined ||
theme == null
) {
} else {
nextTheme = themesArr[(1 - -themesArr.indexOf(theme)) % themesArr.length];
}
console.log("Slecting: " + nextTheme);
document.documentElement.setAttribute("data-theme", nextTheme);
localStorage.setItem("theme", nextTheme);
}
</script>
{#snippet SwitchThemeButton()}
<div
class="tooltip tooltip-bottom grid place-content-center"
data-tip="Switch theme"
>
<button class="cursor-pointer" onclick={nextTheme}> <Dices /></button>
</div>
{/snippet}
<!-- Detect mobile -->
<MediaQuery
query="(max-width: {footerCollapseThreshold})"
bind:matches={footerCollapse}
/>
<MediaQuery
query="(max-width: {headerCollapseThreshold})"
bind:matches={isMobile}
/>
<CustomScrollBar
overflowX="hidden"
overflowY="auto"
Class="h-screen {hideOnPrint ? 'hide-on-print' : ''}"
requireAbsolute={true}
hideOnMobile={true}
>
<div class="flex flex-col justify-between min-h-screen bg-base-200 p-0">
<header class="{hideOnPrint ? 'hide-on-print' : ''} bg-base-300">
<div class="nav-bar pr-4">
<!-- TODO: Make this one element instead of this weird ass if statement -->
{#if !isMobile}
<div class="desktop items-center">
<a href="/" class="nav-head">
<DeprivedLogo
Class="fill-base-content p-2"
Style="width: 3.5rem; height: auto;"
/>
<!-- <h3 id="logo-text">The Deprived Devs</h3> -->
</a>
<div class="nav-spacer" />
{@render SwitchThemeButton()}
<a
href="/cv?hideOnPrint=1"
target="_blank"
style="width: 7.5rem;"
class="text-center justify-center text-md"
>{$re?.nick ?? "Alex"}'s CV</a
>
<!-- <a href="/tools" style="width: 7.5rem;" class="text-center">Tools</a> -->
<!-- <a href="https://botalex.itch.io/" target="_blank">Games</a> -->
<!-- <a href="/posts">Blog</a>
<a href="/about">About</a> -->
</div>
{:else}
<div class="collapsed shadow-xl">
<a onclick={resetNavBar} href="/" class="nav-head">
<DeprivedLogo
Class="fill-base-content p-2"
Style="width: 3.5rem; height: auto;"
/>
<!-- <h3 id="logo-text">The Deprived Devs</h3> -->
</a>
<div class="nav-spacer" />
{@render SwitchThemeButton()}
<div class="px-1"></div>
<button
id="toggle-nav"
onclick={() => {
navbarHidden = !navbarHidden;
console.log(navbarHidden);
}}
>
<HamburgerMenuIcon Class="fill-base-content" />
</button>
</div>
{#if !navbarHidden}
<div class="nav-list" transition:fly={{ y: -25, duration: 350 }}>
<!-- <a onclick={resetNavBar} href="/">Home</a> -->
<!-- <a -->
<!-- onclick={resetNavBar} -->
<!-- href="https://botalex.itch.io/" -->
<!-- target="_blank">Games</a -->
<!-- > -->
<a href="/cv?hideOnPrint=1" target="_blank" class="justify-center"
>{$re?.nick ?? "Alex"}'s CV</a
>
<!-- <a onclick={resetNavBar} href="/posts">Blog</a>
<a onclick={resetNavBar} href="/about">About</a> -->
</div>
{/if}
{/if}
</div>
</header>
<div class="flex-1">
<!-- Page content -->
{@render children?.()}
</div>
<Zooter bind:hideOnPrint />
</div>
</CustomScrollBar>
{#if hideOnPrint}
<div class="flex-1 hide-if-not-print">
<!-- Page content -->
{@render children?.()}
</div>
{/if}
{#if footerCollapse}
<style>
.about-container {
flex-direction: column;
justify-content: center !important;
gap: 25px;
}
</style>
{/if}
<style>
/* Nav bar. */
header {
display: flex;
justify-content: center;
}
.back-to-top {
opacity: 1;
right: 16px;
user-select: none;
bottom: 80px;
}
header a {
text-decoration: none;
}
.nav-bar {
width: 100%;
max-width: 1400px;
}
.desktop {
width: 100%;
display: flex;
gap: 30px;
}
.collapsed {
width: 100%;
display: flex;
}
#toggle-nav {
background: transparent;
border: none;
}
.nav-list {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
}
.nav-head {
display: flex;
align-items: center;
gap: 10px;
}
.nav-spacer {
width: 100%;
}
header a {
display: flex;
align-items: center;
font-size: 22px;
font-family: var(--title-font);
color: oklch(var(--bc));
}
a:hover {
filter: brightness(130%);
}
</style>

1
src/routes/+layout.ts Normal file
View file

@ -0,0 +1 @@
export const prerender = true;

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

@ -0,0 +1,353 @@
<script lang="ts">
import MediaQuery from "svelte-media-queries";
import onMount from "@e/onMount";
import PreviewDeprivedLogo from "$lib/images/DeprivedLogo-NoBackground.png";
import BackgroundVideo from "$lib/videos/DeprivedDevMontage.gif";
import Profile from "./comps/Profile.svelte";
import DeprivedTrackerSection from "./comps/DeprivedTrackerSection.svelte";
import re from "@src/ts/Redaction/Redactor";
const mobileThreshold: string = "600px"; // was 1000px.
let mobile: boolean;
let debug = false;
onMount(() => {
let tabTittleElement = window.document.getElementById("TabTittle");
if (tabTittleElement)
// Not null
tabTittleElement.innerHTML = "Deprived devs";
const params = new URLSearchParams(window.location.search);
debug = params.has("debug");
});
</script>
<!-- Detect mobile -->
<MediaQuery query="(max-width: {mobileThreshold})" bind:matches={mobile} />
<div class="h-full w-full">
<title id="TabTittle">We are the DEPRIVED DEVS</title>
<meta content="We are the deprived devs" property="og:title" />
<meta
content="We make everything frontend, backend, games, websites, machine learning, whatever. We're just abunch of nerds, and we love it!"
property="og:description"
/>
<meta content={PreviewDeprivedLogo} property="og:image" />
<meta content="#bdd6ee" data-react-helmet="true" name="theme-color" />
<div
class="relative pointer-events-auto flex overflow-hidden w-full h-[70vh]"
>
<div class=" flex w-full h-full">
<img
class="w-full h-full object-cover filter blur-sm brightness-60"
src={BackgroundVideo}
alt="Background video"
/>
</div>
<div
class="absolute left-0 top-0 w-full h-full flex justify-center items-center"
>
<h1
style="font-size: {!mobile
? 5
: 3}rem; text-shadow: 0.2rem 0.2rem 1rem rgba(0, 0, 0, 0.9);"
>
{#if !mobile}
Deprived Devs
{:else}
Deprived
<br />
<span class="-mt-6 prose" style="font-size: 2rem;"> Devs </span>
{/if}
</h1>
{#if mobile}
<div style="width: 100px; height: 100px;"></div>
{/if}
</div>
</div>
<DeprivedTrackerSection />
<div
class="cozette flex flex-col justify-center items-center h-full w-full md:px-8 pt-4"
>
<h2 class="text-center" style="font-size: {!mobile ? 3 : 2}rem;">
Developers
</h2>
<div class="">
<div
class="grid max-lg:grid-cols-1 sm:grid-cols-2 gap-4 p-4 max-lg:px-0 w-full"
>
<Profile
name={$re?.nick ? $re?.nick + "/Alex" : "Alex"}
tags={["Programmer", "3D artist", "UX Designer"]}
isMobile={mobile}
>
<span>
<p>
Hi, I am {$re?.nick ? $re?.nick + "/Alex" : "Alex"}, {@html !mobile
? ""
: "<br/>"} I'm known as BOTAlex online
</p>
<p>
Here's my CV: <a href="/cv?hideOnPrint=1" style="color:lightblue;"
>pdf</a
>
</p>
</span>
</Profile>
<Profile
name="Sveske / Benjamin"
tags={["Programmer", "Back-end Admin"]}
isMobile={mobile}
>
<span>
<p>
<span class="inline line-through">Hi, I use Arch, btw. </span> I use
NixOS now
</p>
<p>
<!-- <a -->
<!-- href="https://www.linkedin.com/in/benjamin-dreyer/" -->
<!-- target="_blank" -->
<!-- style="color:lightblue;">Linked-in</a -->
<!-- > -->
</p>
</span>
</Profile>
<Profile isSnorre={true} tags={["Programmer"]} isMobile={mobile} />
<Profile
replaced={true}
name="Oliver"
tags={["Sound/Story", "2D Artist", "Programmer"]}
isMobile={mobile}
>
<span>
<p>Snorre does not get paid.</p>
<p>
<!-- <a -->
<!-- href="https://www.linkedin.com/in/oliver-schwenger-291944278/" -->
<!-- target="_blank" -->
<!-- style="color:lightblue;">Linked-in</a -->
<!-- > -->
<br />
</p>
</span>
</Profile>
<Profile
replaced={true}
name="Kim"
tags={["Cinemachine", "3D Artist", "Programmer"]}
isMobile={mobile}
>
<span>
<p>Abla espaniol</p>
<p>
<!-- <a -->
<!-- href="https://www.linkedin.com/in/kim-rex-de-dios-408860299/" -->
<!-- target="_blank" -->
<!-- style="color:lightblue;">Linked-in</a -->
<!-- > -->
<br />
</p>
</span>
</Profile>
<Profile
replaced={true}
name="Zylvester"
tags={["Sound/Story", "2D/3D artist"]}
isMobile={mobile}
>
<span>
<p>Used to draw furry commisions (Wasted potential)</p>
<p>
<!-- <a -->
<!-- href="https://www.linkedin.com/in/sylvester-junge-0b2a73196/" -->
<!-- target="_blank" -->
<!-- style="color:lightblue;">Linked-in</a -->
<!-- >, -->
<!-- <a -->
<!-- href="https://www.youtube.com/watch?v=xvFZjo5PgG0" -->
<!-- style="color:lightblue;">Funny link</a -->
<!-- > -->
<br />
</p>
</span>
</Profile>
</div>
<span class="opacity-20">¹ They don't do shit</span>
</div>
</div>
<div class="py-4"></div>
<div
class="grid place-content-center place-items-center pointer-events-auto font-mono"
>
<!-- <article class="pt-16 prose overflow-hidden {mobile ? "px-8" : ""}">
<h2 class="main-title {!mobile ? "text-center m-auto" : "m-0"}" style="font-size: {!mobile ? 3 : 3}rem; ">About us</h2>
<p>We are a small group of developers and artists who started out as classmates, united by our passion for all things technology.</p>
</article> -->
<!-- Spacer -->
<!-- <div style="width: 50%;" class="{!mobile ? "py-16" : "py-4"}">
<ProfileSpacer/>
</div> -->
<!-- <article class="prose {mobile ? 'px-8' : ''}"> -->
<!-- <h2 -->
<!-- class="main-title {!mobile ? 'text-center m-auto' : 'm-0'}" -->
<!-- style="font-size: {!mobile ? 3 : 3}rem; " -->
<!-- > -->
<!-- Games -->
<!-- </h2> -->
<!-- <p> -->
<!-- Here are some of our games from various gamejams from the past. <br -->
<!-- />(<span class="font-bold">ONLY</span> 48 hours per game) -->
<!-- </p> -->
<!-- </article> -->
<!---->
<!-- Spacer -->
<!-- <div style="width: 50%;" class={!mobile ? "py-8" : "py-4"}></div> -->
<!---->
<!-- <div -->
<!-- class="grid grid-flow-row gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4" -->
<!-- > -->
<!-- Corro rebounce -->
<!-- <div class="games card bg-base-100 shadow-xl"> -->
<!-- <figure style="height: 15em;"> -->
<!-- <Carousel images={[Corrobot1, Corrobot2, Corrobot3]} /> -->
<!-- </figure> -->
<!-- <div class="card-body"> -->
<!-- <h2 class="card-title">Corrobot-rebounce</h2> -->
<!-- <p>A 3D sequel to Corrobot-Takeover</p> -->
<!-- <br /> -->
<!-- <p> -->
<!-- This was made during <a -->
<!-- href="https://itch.io/jam/nordic-game-jam-2024/rate/2659665" -->
<!-- class="underline">Nordic gamejam 2024</a -->
<!-- > -->
<!-- </p> -->
<!-- <div class="card-actions justify-end"> -->
<!-- <a -->
<!-- href="https://botalex.itch.io/corrobot-rebounce" -->
<!-- target="_blank" -->
<!-- class="btn btn-primary text-primary-content">View on itch.io</a -->
<!-- > -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!---->
<!-- Blood -->
<!-- <div class="games card bg-base-100 w-96 shadow-xl"> -->
<!-- <figure style="height: 15em;"> -->
<!-- <Carousel images={[Blood1, Blood2, Blood3, Blood4, Blood5]} /> -->
<!-- </figure> -->
<!-- <div class="card-body"> -->
<!-- <h2 class="card-title">Unnamed blood game</h2> -->
<!-- <p>A game based on an unique kind of combat</p> -->
<!-- <br /> -->
<!-- <p> -->
<!-- This was made during <a -->
<!-- href="https://itch.io/jam/future-game-makers-jam-2024" -->
<!-- class="underline">Future Game Makers</a -->
<!-- >, and of course our team won the competition. -->
<!-- </p> -->
<!-- <div class="card-actions justify-end"> -->
<!-- <a -->
<!-- href="https://botalex.itch.io/mop-of-the-dead" -->
<!-- target="_blank" -->
<!-- class="btn btn-primary text-primary-content">View on itch.io</a -->
<!-- > -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!---->
<!-- Time -->
<!-- <div class="games card bg-base-100 w-96 shadow-xl"> -->
<!-- <figure style="height: 15em;"> -->
<!-- <Carousel images={[Time1, Time2, Time3, Time4, Time5]} /> -->
<!-- </figure> -->
<!-- <div class="card-body"> -->
<!-- <h2 class="card-title">One More Time</h2> -->
<!-- <p> -->
<!-- What if time was money? A rougelike where you need to kill for time, -->
<!-- which you can choose to spend. -->
<!-- </p> -->
<!-- <br /> -->
<!-- <p> -->
<!-- This was made during <a -->
<!-- href="https://itch.io/jam/dmspiljam-november-2021" -->
<!-- class="underline">Denmark Masters jam</a -->
<!-- >. This jam has youths allover Denmark to compete, and of course our -->
<!-- team won the competition again. -->
<!-- </p> -->
<!-- <div class="card-actions justify-end"> -->
<!-- <a -->
<!-- href="https://botalex.itch.io/one-more-time" -->
<!-- target="_blank" -->
<!-- class="btn btn-primary text-primary-content">View on itch.io</a -->
<!-- > -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!---->
<!-- <div class="games card bg-base-100 w-96 shadow-xl"> -->
<!-- <figure class="rounded-b-none" style="height: 15em;"> -->
<!-- <div class="bg-grid-100 flex w-full h-full"></div> -->
<!-- </figure> -->
<!-- <div class="card-body"> -->
<!-- <h2 class="card-title">What's next?</h2> -->
<!-- <div class="skeleton mt-1 h-4 w-28"></div> -->
<!-- <div class="skeleton h-4 w-full"></div> -->
<!-- <div class="skeleton h-4 w-full"></div> -->
<!-- <div class="skeleton h-4 w-28"></div> -->
<!-- <div class="skeleton h-4 w-full"></div> -->
<!-- <div class="flex grow" /> -->
<!-- <div class="card-actions justify-end"> -->
<!-- <a -->
<!-- href="/" -->
<!-- target="_blank" -->
<!-- class="btn btn-primary text-primary-content text-primary-content" -->
<!-- >RECURSION!</a -->
<!-- > -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
</div>
</div>
{#if !mobile}
<style>
.games {
width: 24rem /* 384px */;
}
</style>
{:else}
<style>
.games {
width: 80%;
display: flex;
justify-self: center;
}
</style>
{/if}
<style>
#backgroundGif {
width: 100%;
height: 100%;
max-height: 40vh;
object-fit: cover;
filter: blur(5px) brightness(0.6);
}
</style>

View file

@ -0,0 +1,133 @@
<script lang="ts">
import onMount from "@e/onMount";
export let images: string[] = []; // Expose images as a parameter
let currentIndex: number = 0;
let startX: number | null = null; // Track touch start X position
let deltaX: number = 0; // Track touch delta X
const nextSlide = (): void => {
currentIndex = (currentIndex + 1) % images.length;
};
const prevSlide = (): void => {
currentIndex = (currentIndex - 1 + images.length) % images.length;
};
const handleTouchStart = (event: TouchEvent): void => {
startX = event.touches[0].clientX;
};
const handleTouchMove = (event: TouchEvent): void => {
if (startX !== null) {
deltaX = event.touches[0].clientX - startX;
}
};
const handleTouchEnd = (): void => {
if (startX !== null) {
if (deltaX > 50) {
prevSlide(); // Swipe right
} else if (deltaX < -50) {
nextSlide(); // Swipe left
}
}
// Reset touch variables
startX = null;
deltaX = 0;
};
</script>
<style>
.carousel {
position: relative;
overflow: hidden;
width: 100%;
max-width: 800px;
height: 100%;
margin: auto;
}
.slides {
display: flex;
transition: transform 0.5s ease-in-out;
width: 100%;
}
.slide {
flex: 0 0 100%;
object-fit: cover;
object-position: center;
}
.controls {
position: absolute;
top: 50%;
width: 100%;
display: flex;
justify-content: space-between;
transform: translateY(-50%);
}
.control {
background: rgba(0, 0, 0, 0.5);
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem;
}
.indicators {
display: flex;
justify-content: center;
position: absolute;
bottom: 10px;
width: 100%;
}
.indicator {
width: 10px;
height: 10px;
margin: 0 5px;
background: white;
border-radius: 50%;
opacity: 0.5;
cursor: pointer;
}
.indicator.active {
opacity: 1;
}
</style>
<div
class="carousel"
on:touchstart|preventDefault={handleTouchStart}
on:touchmove|preventDefault={handleTouchMove}
on:touchend|preventDefault={handleTouchEnd}
>
<div
class="slides"
style="transform: translateX(-{currentIndex * 100}%);"
>
{#each images as image (image)}
<img class="slide" src={image} alt="Carousel Slide" />
{/each}
</div>
<div class="controls">
<button class="control" on:click={prevSlide}>&lt;</button>
<button class="control" on:click={nextSlide}>&gt;</button>
</div>
<div class="indicators">
{#each images as _, index}
<div
class="indicator {index === currentIndex ? 'active' : ''}"
on:click={() => (currentIndex = index)}
></div>
{/each}
</div>
</div>

View file

@ -0,0 +1,464 @@
<script lang="ts">
import onMount from "@e/onMount";
import onDestroy from "@e/onDestroy";
import MediaQuery from "svelte-media-queries";
// Public props
export let overflowX: "auto" | "scroll" | "hidden" = "hidden";
export let overflowY: "auto" | "scroll" | "hidden" = "auto";
export let hideOnMobile = false; // True if hide scrollbar when mobile detected
// Visual tuning
export let thickness = 12; // px
export let padding = 0; // px, space around track inside the overlay
export let minThumb = 10; // px
export let contentPadding = 0; // px, inner padding for your content
export let Class = ""; // Extra classes for the scrollbar
// Styling (customize freely)
export let trackStyle = "";
export let trackClass = "";
export let trackOpacity = 0.55;
export let thumbClass =
"bg-black opacity-50 border-white text-xs text-center text-opacity-50 overflow-hidden flex items-center text-nowrap justify-center";
export let thumbLength = 20; // px. doesn't work for some reason, idk
export let requireAbsolute = false; // Some needs absolute for some reason. idk
export let scrollThumbText =
"-------------------------------------------------------------------------------------------------------------------------------Scroll-------------------------------------------------------------------------------------------------------------------------------";
let hideOnPrint = false;
let viewport: HTMLDivElement;
let vBar: HTMLDivElement; // vertical bar container
let hBar: HTMLDivElement; // horizontal bar container
let vThumb: HTMLDivElement;
let hThumb: HTMLDivElement;
let showBarY = false;
let showBarX = false;
let isMobile = false;
// ——— utils
const sMaxY = () =>
Math.max(0, viewport.scrollHeight - viewport.clientHeight);
const sMaxX = () => Math.max(0, viewport.scrollWidth - viewport.clientWidth);
const tMaxY = () =>
Math.max(0, (vBar?.clientHeight || 0) - (vThumb?.offsetHeight || 0));
const tMaxX = () =>
Math.max(0, (hBar?.clientWidth || 0) - (hThumb?.offsetWidth || 0));
function updateVisibility() {
showBarY =
overflowY !== "hidden" &&
viewport.scrollHeight > viewport.clientHeight &&
!(hideOnMobile && isMobile);
showBarX =
overflowX !== "hidden" &&
viewport.scrollWidth > viewport.clientWidth &&
!(hideOnMobile && isMobile);
}
function updateVerticalThumb() {
if (!vThumb || !vBar) return;
const ratio = viewport.clientHeight / viewport.scrollHeight;
const h = Math.max(minThumb, Math.round(ratio * vBar.clientHeight));
vThumb.style.height = `${h}px`;
const top = sMaxY() ? (viewport.scrollTop / sMaxY()) * tMaxY() : 0;
vThumb.style.top = `${top}px`;
vThumb.setAttribute("aria-valuemin", "0");
vThumb.setAttribute("aria-valuemax", String(sMaxY()));
vThumb.setAttribute("aria-valuenow", String(viewport.scrollTop));
}
function updateHorizontalThumb() {
if (!hThumb || !hBar) return;
const ratio = viewport.clientWidth / viewport.scrollWidth;
const w = Math.max(minThumb, Math.round(ratio * hBar.clientWidth));
hThumb.style.width = `${w}px`;
const left = sMaxX() ? (viewport.scrollLeft / sMaxX()) * tMaxX() : 0;
hThumb.style.left = `${left}px`;
hThumb.setAttribute("aria-valuemin", "0");
hThumb.setAttribute("aria-valuemax", String(sMaxX()));
hThumb.setAttribute("aria-valuenow", String(viewport.scrollLeft));
}
function updateAll() {
updateVisibility();
updateVerticalThumb();
updateHorizontalThumb();
}
// Drag state
let draggingV = false;
let draggingH = false;
let dragStart = { x: 0, y: 0, scrollLeft: 0, scrollTop: 0 };
let pointerIdV: number | null = null;
let pointerIdH: number | null = null;
function onVPointerDown(e: PointerEvent) {
draggingV = true;
pointerIdV = e.pointerId;
vThumb.setPointerCapture(e.pointerId);
dragStart = {
x: e.clientX,
y: e.clientY,
scrollLeft: viewport.scrollLeft,
scrollTop: viewport.scrollTop,
};
e.preventDefault();
}
function onVPointerMove(e: PointerEvent) {
if (!draggingV) return;
const dy = e.clientY - dragStart.y;
const pixelsPerThumb = sMaxY() / Math.max(1, tMaxY());
viewport.scrollTop = Math.min(
sMaxY(),
Math.max(0, dragStart.scrollTop + dy * pixelsPerThumb),
);
}
function endVDrag(e: PointerEvent) {
if (!draggingV) return;
draggingV = false;
if (pointerIdV != null) {
try {
vThumb.releasePointerCapture(pointerIdV);
} catch {}
pointerIdV = null;
}
}
function onHPointerDown(e: PointerEvent) {
draggingH = true;
pointerIdH = e.pointerId;
hThumb.setPointerCapture(e.pointerId);
dragStart = {
x: e.clientX,
y: e.clientY,
scrollLeft: viewport.scrollLeft,
scrollTop: viewport.scrollTop,
};
e.preventDefault();
}
function onHPointerMove(e: PointerEvent) {
if (!draggingH) return;
const dx = e.clientX - dragStart.x;
const pixelsPerThumb = sMaxX() / Math.max(1, tMaxX());
viewport.scrollLeft = Math.min(
sMaxX(),
Math.max(0, dragStart.scrollLeft + dx * pixelsPerThumb),
);
}
function endHDrag(e: PointerEvent) {
if (!draggingH) return;
draggingH = false;
if (pointerIdH != null) {
try {
hThumb.releasePointerCapture(pointerIdH);
} catch {}
pointerIdH = null;
}
}
// Track clicks: jump to position
function onVTrackPointerDown(e: PointerEvent) {
if (e.target === vThumb) return;
const rect = vBar.getBoundingClientRect();
const y = e.clientY - rect.top - vThumb.offsetHeight / 2;
const clamped = Math.min(tMaxY(), Math.max(0, y));
viewport.scrollTop = (clamped / Math.max(1, tMaxY())) * sMaxY();
}
function onHTrackPointerDown(e: PointerEvent) {
if (e.target === hThumb) return;
const rect = hBar.getBoundingClientRect();
const x = e.clientX - rect.left - hThumb.offsetWidth / 2;
const clamped = Math.min(tMaxX(), Math.max(0, x));
viewport.scrollLeft = (clamped / Math.max(1, tMaxX())) * sMaxX();
}
// Keyboard on thumbs
function onVKeyDown(e: KeyboardEvent) {
const step = 40;
const page = Math.max(120, Math.floor(viewport.clientHeight * 0.9));
switch (e.key) {
case "ArrowDown":
viewport.scrollBy({ top: step });
e.preventDefault();
break;
case "ArrowUp":
viewport.scrollBy({ top: -step });
e.preventDefault();
break;
case "PageDown":
viewport.scrollBy({ top: page });
e.preventDefault();
break;
case "PageUp":
viewport.scrollBy({ top: -page });
e.preventDefault();
break;
case "Home":
viewport.scrollTo({ top: 0 });
e.preventDefault();
break;
case "End":
viewport.scrollTo({ top: sMaxY() });
e.preventDefault();
break;
}
}
function onHKeyDown(e: KeyboardEvent) {
const step = 40;
const page = Math.max(120, Math.floor(viewport.clientWidth * 0.9));
switch (e.key) {
case "ArrowRight":
viewport.scrollBy({ left: step });
e.preventDefault();
break;
case "ArrowLeft":
viewport.scrollBy({ left: -step });
e.preventDefault();
break;
case "PageDown":
viewport.scrollBy({ left: page });
e.preventDefault();
break;
case "PageUp":
viewport.scrollBy({ left: -page });
e.preventDefault();
break;
case "Home":
viewport.scrollTo({ left: 0 });
e.preventDefault();
break;
case "End":
viewport.scrollTo({ left: sMaxX() });
e.preventDefault();
break;
}
}
let ro: ResizeObserver;
onMount(() => {
const params = new URLSearchParams(window.location.search);
hideOnPrint = params.get("hideOnPrint") === "1";
const onScroll = () => {
updateVerticalThumb();
updateHorizontalThumb();
};
viewport.addEventListener("scroll", onScroll, { passive: true });
ro = new ResizeObserver(() => updateAll());
ro.observe(viewport);
if (viewport.firstElementChild instanceof HTMLElement) {
ro.observe(viewport.firstElementChild);
}
// Global pointer end (in case drag ends outside)
const endAll = () => {
draggingV = draggingH = false;
};
window.addEventListener("pointerup", endAll);
// Initial paint
queueMicrotask(updateAll);
return () => {
viewport.removeEventListener("scroll", onScroll as any);
window.removeEventListener("pointerup", endAll);
};
});
onDestroy(() => {
ro?.disconnect();
});
// Padding for content so the overlay bars dont cover it
$: pr = contentPadding + (showBarY ? thickness + padding * 2 : 0);
$: pb = contentPadding + (showBarX ? thickness + padding * 2 : 0);
</script>
<MediaQuery query="(max-width: 40rem)" bind:matches={isMobile} />
<!-- svelte-ignore element_invalid_self_closing_tag -->
<!-- svelte-ignore a11y_role_has_required_aria_props -->
<!-- Wrapper -->
<div
class="relative {overflowY == 'hidden'
? ''
: 'overflow-y-hidden'} {overflowX == 'hidden'
? ''
: 'overflow-x-hidden'} {Class}"
>
<!-- The real, native scrolling area (we hide its native scrollbar) -->
<div
bind:this={viewport}
class="csb-viewport {requireAbsolute
? 'absolute'
: ''} inset-0 overflow-auto focus:outline-none"
style="
padding: {contentPadding}px {pr}px {pb}px {contentPadding}px;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
"
>
<div class="min-w-0 min-h-0">
<slot />
</div>
</div>
<!-- Vertical overlay bar (mirrors x-scroll structure) -->
{#if showBarY}
<div
bind:this={vBar}
class="absolute bg-base-200 {hideOnPrint ? 'hide-on-print' : ''} "
style="
top: {padding}px;
bottom: {padding}px;
right: {padding}px;
width: {thickness}px;
pointer-events: none;
"
aria-hidden="false"
>
<div class="absolute inset-0 corner-border-container">
<div
class="transition-opacity {trackClass} w-full h-full"
style="
pointer-events: auto;
{trackStyle}
"
on:pointerdown={onVTrackPointerDown}
/>
</div>
<div
bind:this={vThumb}
role="scrollbar"
aria-orientation="vertical"
tabindex="0"
class={`absolute border-y-2 left-0 right-0 rounded-none cursor-grab active:cursor-grabbing focus-visible:outline focus-visible:outline-2 focus-visible:outline-sky-500 ${thumbClass}`}
style="height: {thumbLength}px; pointer-events: auto; touch-action: none;"
on:pointerdown={onVPointerDown}
on:pointermove={onVPointerMove}
on:pointerup={endVDrag}
on:pointercancel={endVDrag}
on:keydown={onVKeyDown}
>
<span class="rotate-90">
{scrollThumbText}
</span>
</div>
</div>
{/if}
<!-- Horizontal overlay bar -->
{#if showBarX}
<div
bind:this={hBar}
class="absolute {hideOnPrint ? 'hide-on-print' : ''} "
style="
left: {padding}px;
right: {padding}px;
bottom: {padding}px;
height: {thickness}px;
pointer-events: none;
"
aria-hidden="false"
>
<div class="absolute inset-0 corner-border-container">
<div
class="transition-opacity {trackClass} h-full"
style="
pointer-events: auto;
{trackStyle}
"
on:pointerdown={onHTrackPointerDown}
/>
</div>
<div
bind:this={hThumb}
role="scrollbar"
aria-orientation="horizontal"
tabindex="0"
class={`absolute border-x-2 top-0 bottom-0 rounded-none cursor-grab active:cursor-grabbing focus-visible:outline focus-visible:outline-2 focus-visible:outline-sky-500 ${thumbClass}`}
style="width: {thumbLength}px; pointer-events: auto; touch-action: none;"
on:pointerdown={onHPointerDown}
on:pointermove={onHPointerMove}
on:pointerup={endHDrag}
on:pointercancel={endHDrag}
on:keydown={onHKeyDown}
>
{scrollThumbText}
</div>
</div>
{/if}
</div>
<style lang="scss">
/* Hide the native scrollbars while keeping native scrolling */
:global(.csb-viewport) {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge legacy */
}
:global(.csb-viewport::-webkit-scrollbar) {
width: 0;
height: 0; /* WebKit */
}
.corner-border-container {
--length: 5px;
--width: 1px;
--line-color: #eeeeee;
--background-color: #0002;
background-color: var(--background-color);
background-image:
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color));
background-size:
var(--length) var(--width),
var(--width) var(--length),
var(--length) var(--width),
var(--width) var(--length),
var(--length) var(--width),
var(--width) var(--length),
var(--length) var(--width),
var(--width) var(--length);
background-position:
top left,
top left,
top right,
top right,
bottom right,
bottom right,
bottom left,
bottom left;
background-repeat: no-repeat;
border-radius: 0;
& > div {
background: repeating-linear-gradient(
-45deg,
#0000,
#0000 15px,
#fff2 10px 20px
);
}
}
</style>

View file

@ -0,0 +1,63 @@
<script>
import onMount from "@e/onMount";
let debug = false;
onMount(()=> {
let tabTittleElement = window.document.getElementById("TabTittle");
if (tabTittleElement) // Not null
tabTittleElement.innerHTML = "Deprived devs";
const params = new URLSearchParams(window.location.search);
debug = params.has('debug');
});
</script>
<!-- Desktop -->
<div class="{debug? "" : "hidden"} max-md:hidden cozette flex flex-col justify-center items-center w-full md:px-8 pt-4">
<div class="grid grid-cols-2 items-center">
<div>
<img src="https://placehold.co/400x400/000000/FFFFFF" alt="">
</div>
<div class="flex flex-col">
<div>
<h2 class="font-semibold text-base-content text-xl">Deprived Trackers</h2>
<span class="text-base-content">
Hopefully the cheapest Smol-type SlimeVR Trackers on the market.
</span>
</div>
<div class="py-2"></div>
<div class="flex justify-center gap-2">
<a href="/" class="btn btn-secondary">Buy</a>
<a href="/shop/trackers" class="btn btn-primary">Learn more</a>
</div>
</div>
</div>
</div>
<!-- Mobile -->
<div class="{debug? "" : "hidden"} md:hidden cozette flex flex-col justify-center items-center w-full md:px-8 pt-4">
<div class="relative grid items-center max-w-64">
<div class="blur-xs">
<img src="https://placehold.co/400x400/000000/FFFFFF" alt="">
</div>
<div class="absolute flex flex-col justify-between h-full p-8">
<div>
<h2 class="font-semibold text-base-content">Deprived Trackers</h2>
<span class="text-base-content">
Hopefully the cheapest Smol-type SlimeVR Trackers on the market.
</span>
</div>
<div class="py-2"></div>
<div class="flex justify-center gap-2">
<a href="/" class="btn btn-secondary">Buy</a>
<a href="/shop/trackers" class="btn btn-primary">Learn more</a>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,16 @@
<script>
export let Title = "";
export let Checked = false;
</script>
<div class="collapse collapse-arrow bg-base-100 text-start shadow-sm" {...$$restProps}>
{#if Checked}
<input type="radio" name="{Title}" checked/>
{:else}
<input type="radio" name="{Title}"/>
{/if}
<div class="collapse-title text-xl font-medium "><b>{Title}</b></div>
<div class="collapse-content" style="border-top: dotted 0.15rem oklch(var(--b3));">
<slot/>
</div>
</div>

View file

@ -0,0 +1,10 @@
<script>
import Tags from "./Tags.svelte";
export let isMobile = false;
export let tags = ["null"];
</script>
{#if isMobile}
<Tags Tags={tags} isMobile={isMobile}/>
{/if}

View file

@ -0,0 +1,15 @@
<script>
import Tags from "./Tags.svelte"; // Should've used better names lol
export let isMobile = false;
export let name = "";
export let tags = ["null"];
</script>
<div class="flex items-center">
<h2 style="font-size: {!isMobile ? 1.5 : 1.5}rem;">{name}</h2>
<div class="flex flex-grow"/>
{#if !isMobile}
<Tags Tags={tags} isMobile={isMobile}/>
{/if}
</div>

View file

@ -0,0 +1,61 @@
<script lang="ts">
import Carousel from './Carousel.svelte';
export let title: string;
export let description: string;
export let jam = { name: '', url: '' };
export let viewUrl : string= '';
export let images: string[] = [];
export let placeholder = false;
</script>
<div class="games card bg-base-100 shadow-xl {placeholder ? 'w-96' : ''}">
{#if !placeholder}
<figure style="height: 15em;">
<Carousel {images} />
</figure>
<div class="card-body">
<h2 class="card-title">{title}</h2>
<p>{description}</p>
<br />
<p>
This was made during
<a href={jam.url} class="underline" target="_blank" rel="noopener">
{jam.name}
</a>
</p>
<div class="card-actions justify-end">
<a href={viewUrl}
class="btn btn-primary text-primary-content"
target="_blank"
rel="noopener"
>
View on itch.io
</a>
</div>
</div>
{:else}
<figure class="rounded-b-none" style="height: 15em;">
<div class="bg-grid-100 flex w-full h-full"></div>
</figure>
<div class="card-body">
<h2 class="card-title">What's next?</h2>
<div class="skeleton mt-1 h-4 w-28"></div>
<div class="skeleton h-4 w-full"></div>
<div class="skeleton h-4 w-full"></div>
<div class="skeleton h-4 w-28"></div>
<div class="skeleton h-4 w-full"></div>
<div class="flex grow"></div>
<div class="card-actions justify-end">
<a href="/"
class="btn btn-primary text-primary-content"
target="_blank"
rel="noopener"
>
RECURSION!
</a>
</div>
</div>
{/if}
</div>

View file

@ -0,0 +1,68 @@
<script>
import PostCard from './PostCard.svelte';
import Corrobot1 from '@images/GamePreviews/Corrobot1.png';
import Corrobot2 from '@images/GamePreviews/Corrobot2.png';
import Corrobot3 from '@images/GamePreviews/Corrobot3.png';
import Blood1 from '@images/GamePreviews/Blood1.png';
import Blood2 from '@images/GamePreviews/Blood2.png';
import Blood3 from '@images/GamePreviews/Blood3.png';
import Blood4 from '@images/GamePreviews/Blood4.png';
import Blood5 from '@images/GamePreviews/Blood5.png';
import Time1 from '@images/GamePreviews/Time1.png';
import Time2 from '@images/GamePreviews/Time2.png';
import Time3 from '@images/GamePreviews/Time3.png';
import Time4 from '@images/GamePreviews/Time4.png';
import Time5 from '@images/GamePreviews/Time5.png';
const games = [
{
title: 'Corrobot-rebounce',
description: 'A 3D sequel to Corrobot-Takeover',
jam: {
name: 'Nordic gamejam 2024',
url: 'https://itch.io/jam/nordic-game-jam-2024/rate/2659665'
},
viewUrl: 'https://botalex.itch.io/corrobot-rebounce',
images: [Corrobot1, Corrobot2, Corrobot3]
},
{
title: 'Unnamed blood game',
description: 'A game based on an unique kind of combat',
jam: {
name: 'Future Game Makers',
url: 'https://itch.io/jam/future-game-makers-jam-2024'
},
viewUrl: 'https://botalex.itch.io/mop-of-the-dead',
images: [Blood1, Blood2, Blood3, Blood4, Blood5]
},
{
title: 'One More Time',
description: 'What if time was money? A roguelike where you need to kill for time, which you can choose to spend.',
jam: {
name: 'Denmark Masters jam',
url: 'https://itch.io/jam/dmspiljam-november-2021'
},
viewUrl: 'https://botalex.itch.io/one-more-time',
images: [Time1, Time2, Time3, Time4, Time5]
}
];
</script>
<div class="grid grid-flow-row gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{#each games as game (game.title)}
<PostCard
title={game.title}
description={game.description}
jam={game.jam}
viewUrl={game.viewUrl}
images={game.images}
/>
{/each}
<!-- placeholder for upcoming game -->
<PostCard placeholder={true} />
</div>

View file

@ -0,0 +1,133 @@
<script>
import MobileTags from "./MobileTags.svelte";
import NameAndTag from "./NameAndTag.svelte";
export let isMobile = false;
export let name = "";
export let tags = ["null"];
export let isSnorre = false;
export let replaced = false;
// Shit code but who cares, if it works /shrug
</script>
<div
class="relative bg-grid-100 border-2 border-base-100 pl-1 pr-4 rounded-md cozette max-lg:pb-2"
>
{#if !isSnorre}
<div class=" developersProfile {isSnorre ? 'isSnorre' : ''} pl-1 font-mono">
<NameAndTag {name} {tags} {isMobile} />
<slot />
<MobileTags {tags} {isMobile} />
</div>
{:else}
<div class="w-full pl-1">
<div
class="developersProfile absolute snorre pl-4 font-mono pointer-events-none select-none"
>
<pre style="font-size: {!isMobile ? 1.5 : 1.5}rem;"></pre>
<span>
<pre></pre>
<pre></pre>
</span>
{#if isMobile}
<pre></pre>
{/if}
</div>
<div class="developersProfile snorre-overlay relative pl-1 font-mono">
<NameAndTag name="Snorre" {tags} {isMobile} />
<span>
<p>
I'm the diversity hire. <span
class="border-b"
style="border-image: linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet); border-image-slice: 1;"
>(Gay)</span
>
</p>
<!-- <p><a href="https://www.linkedin.com/in/snorrealtschul/" target="_blank" style="color:lightblue;">My website</a></p> -->
<p>
<a
href="https://spoodythe.one/"
target="_blank"
style="color:lightblue;">My website</a
>
</p>
</span>
<MobileTags {tags} {isMobile} />
</div>
</div>
{/if}
<div
class="{replaced
? ''
: 'hidden'} replaced flex justify-center items-center h-full absolute top-0 left-0 down-0 right-0"
>
<div class="corner-border-container px-2">Replaced by AI¹</div>
</div>
</div>
<style>
.replaced {
background: repeating-linear-gradient(
45deg,
#0009,
#0009 15px,
#000a 15px 20px
);
}
.corner-border-container {
--length: 5px;
--width: 1px;
--line-color: #eeeeee;
background-color: #0008;
background-image:
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color)),
linear-gradient(var(--line-color), var(--line-color));
background-size:
var(--length) var(--width),
var(--width) var(--length),
var(--length) var(--width),
var(--width) var(--length),
var(--length) var(--width),
var(--width) var(--length),
var(--length) var(--width),
var(--width) var(--length);
background-position:
top left,
top left,
top right,
top right,
bottom right,
bottom right,
bottom left,
bottom left;
background-repeat: no-repeat;
}
.developersProfile:not(.snorre):not(.snorre-overlay) {
/* background-image: linear-gradient(var(--color-neutral) 33%, rgba(255,255,255,0) 0%); */
/* background-image: linear-gradient(var(--color-neutral) 100%);
background-position: left;
background-size: 0.1rem 0.5rem;
background-repeat: repeat-y; */
}
.snorre {
/* border-left: dashed transparent 0.1rem;
border-image: linear-gradient(to bottom, red, orange, yellow, green, blue, indigo, violet);
border-image-slice: 1; */
}
.snorre-overlay {
/* background-image: linear-gradient(rgba(255,255,255,0) 0%, rgba(255,255,255,0) 40%, var(--color-base-200) 40%); */
/* background-position: left;
background-size: 0.1rem 0.5rem;
background-repeat: repeat-y; */
}
</style>

View file

@ -0,0 +1,8 @@
<div class="profileSpacer"></div>
<style>
.profileSpacer{
height: 1px;
border-bottom: solid oklch(var(--b3));
}
</style>

View file

@ -0,0 +1,178 @@
<script lang="ts">
import onMount from "@e/onMount";
import { Vector2 } from "../zhen/Utils/Vector2";
// Params
let mouseMoveScale: number = 0.25;
let targetTextLenght: number = 100;
// Site variables
let mousePos: Vector2;
// Element binded variables
let mouseRelativeScaled: Vector2 = new Vector2(0, 0);
let windowWidth = 0;
let windowHeight = 0;
let screenCenter: Vector2;
let StartPageAnimated: Element | null;
let windowRef: Window;
function onMouseMoved(event: MouseEvent) {
mousePos = new Vector2(event.clientX, event.clientY);
updateAnimation(mousePos);
}
function updateAnimation(mousePos: Vector2) {
let mouseRelativePos = mousePos.Sub(screenCenter);
mouseRelativeScaled = mouseRelativePos.Scale(mouseMoveScale);
//console.log(mouseRelativePos.x+"\n"+mouseRelativePos.y);
}
onMount(() => {
windowRef = window;
const updateDimensions = () => {
windowWidth = windowRef.innerWidth;
windowHeight = windowRef.innerHeight;
screenCenter = new Vector2(windowWidth / 2, windowHeight / 2);
//console.log("Window size changed: (" + windowWidth + ", " + windowHeight + ")");
};
updateDimensions(); // On first pass
windowRef.addEventListener("resize", updateDimensions);
const RevertToOrigin = () => {
if (
navigator.userAgent.search(/gecko/i) > 0 &&
StartPageAnimated !== null
) {
StartPageAnimated.classList.add("FirefoxSmoothTranition");
}
updateAnimation(new Vector2(windowWidth / 2, windowHeight / 2));
};
document.documentElement.addEventListener("mouseleave", RevertToOrigin);
const RemoveFirefoxSmoothTranition = () => {
if (
navigator.userAgent.search(/gecko/i) > 0 &&
StartPageAnimated !== null
) {
StartPageAnimated.classList.remove("FirefoxSmoothTranition");
}
};
document.documentElement.addEventListener(
"mouseenter",
RemoveFirefoxSmoothTranition,
);
return () => {
windowRef.removeEventListener("resize", updateDimensions);
};
});
const programmingLanguages: string[] = [
"C++",
"C#",
"ARDUINO",
"PYTHON",
"JAVA",
"JAVASCRIPT",
"TYPESCRIPT",
"HTML",
"CSS",
];
function getRandomInt(max: number) {
return Math.floor(Math.random() * max);
}
function GrabRandomString() {
let outString: string = "";
while (outString.length < targetTextLenght) {
outString +=
programmingLanguages[
getRandomInt(programmingLanguages.length)
] + " ";
}
return outString; // At about target size
}
</script>
<svelte:window on:mousemove={onMouseMoved} />
<div
class="StartPageAnimated top-0 left-0 w-full h-full"
id="StartPageAnimated"
bind:this={StartPageAnimated}
style="transform: translate({mouseRelativeScaled.x}px, {mouseRelativeScaled.y}px) translateZ(0) rotate(0.001deg);"
>
{#each {length: 100} as _, i}
<span
class="rotate45 SkillsText"
>
{GrabRandomString()}
</span
>
{/each}
</div>
<style>
.StartPageContainer {
/* height: 40vh; */
background-color: burlywood;
overflow: hidden;
position: relative;
justify-content: center;
align-items: center;
display: flex;
padding: 0;
}
.StartPageAnimated {
padding: 0;
transition: transform 1000ms cubic-bezier(0.16, 1.63, 0.01, 0.99);
-moz-transition: none;
justify-content: center;
vertical-align: middle;
display: flex;
pointer-events: none;
}
.FirefoxSmoothTranition {
transition: transform 1000ms cubic-bezier(0.16, 1.63, 0.01, 0.99);
-moz-transition: transform 1000ms cubic-bezier(0.16, 1.63, 0.01, 0.99) !important;
}
.SkillsText {
font-family: "CozetteVector";
text-align: start;
font-size: x-large;
display: flex;
justify-content: center;
align-items: center;
white-space: nowrap;
width: 2rem;
color: rgb(66, 66, 66);
}
.rotate45 {
transform: rotate(-45deg); /* Rotate the element by 45 degrees */
}
</style>

View file

@ -0,0 +1,93 @@
<script lang="ts">
export let Tags = ["null"];
export let isMobile = false;
// Define an interface for our detailed color object.
interface ColorObject {
color1: string;
color2: string;
rotation: string;
offset: string;
}
// ColorType can be a simple string or a ColorObject.
type ColorType = string | ColorObject;
// Create an interface for the color mapping.
interface ColorsMapping {
[key: string]: ColorType;
}
// Define a class to manage the colors.
class ColorManager {
private colors: ColorsMapping;
constructor() {
this.colors = {
"programmer": "#0CC27F",
"uxdesigner": "#027893",
"3dartist": "#F4881C",
"2dartist": "#F1EAC0",
"2d/3dartist": { color1: "#F1EAC0", color2: "#F4881C", rotation: "-65deg", offset: "71.5%" },
"sound/story": { color1: "#F3EC2A", color2: "#EEC12A", rotation: "-65deg", offset: "50%" },
"sounddesigner": "#F3EC2A",
"storydesigner": "#EEC12A",
"back-endadmin": "#3236a8",
};
}
// Return the color for the given key or a default value.
getColor(key: string): ColorType {
return this.colors[key] || "#ccc";
}
}
// Create an instance of ColorManager.
const colorManager = new ColorManager();
</script>
<div class="flex gap-2" style="font-size: { !isMobile ? '0.875rem' : '2vw' };">
{#each Tags as tag}
{@const key = tag.replaceAll(" ", "").toLowerCase()}
{@const color = colorManager.getColor(key)}
{#if key.indexOf("/") < 0}
<!-- Single Color Badge -->
<div class="badge2" style="background-color: {typeof color === 'string' ? color : '#ccc'};">
<span class="invert">
{tag}
</span>
</div>
{:else}
<!-- Gradient Badge -->
{#if typeof color === 'object' && color !== null}
<div
class="badge2 cozette"
style="background: linear-gradient({color.rotation}, {color.color2} {color.offset}, {color.color1} {color.offset});">
<span class="invert">
{tag}
</span>
</div>
{:else}
<div class="badge2 cozette" style="background-color: #ccc;">
<span class="invert">
{tag}
</span>
</div>
{/if}
{/if}
{/each}
</div>
<style>
.badge2 {
display: inline-flex;
align-items: center;
justify-content: center;
height: 1.25rem; /* 20px */
line-height: 1.25rem; /* 20px */
width: fit-content;
padding-left: 0.563rem; /* 9.008px */
padding-right: 0.563rem; /* 9.008px */
border-radius: var(--rounded-badge, 1.9rem); /* 30.4px */
}
</style>

View file

@ -0,0 +1,175 @@
<script lang="ts">
import svelteLogo from "$lib/svelteLogos/svelte-logo.png";
import onMount from "@e/onMount";
import onDestroy from "@e/onDestroy";
import ArrowBigDown from "lucide-svelte/icons/arrow-big-down";
import fly from "@e/fly";
import re from "@ts/Redaction/Redactor";
const buildTime = __BUILD_TIME__;
let scrollY = 0;
const unscrollSpeed = 100;
let unscrollScrollDiv: HTMLDivElement;
let totalScroll = 0;
let unscrollInterval: number | undefined = undefined;
let lastScrollTime = 0; // Used to have delay before unscrolling
let isBeingTouched = false; // Phone support
const unscrollDelay = 100;
let isLeavingAnimating = false;
// prevent direct scroll
let notFirstScroll = false;
let tranisitionOverlay: HTMLElement;
// Function with more scroll control, by chatgpt
function smoothScrollTo(targetY: number, duration: number = 500): void {
const startY: number = window.scrollY;
const diff: number = targetY - startY;
if (duration <= 0) {
window.scrollTo(0, targetY);
return;
}
let startTime: number | null = null;
function step(timestamp: number): void {
if (startTime === null) startTime = timestamp;
const time = timestamp - startTime;
const percent = Math.min(time / duration, 1);
// easeInOutQuad easing
const ease =
percent < 0.5
? 2 * percent * percent
: -1 + (4 - 2 * percent) * percent;
window.scrollTo(0, startY + diff * ease);
if (time < duration) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}
function onScroll() {
lastScrollTime = Date.now();
// console.log("scroll");
}
function onResize() {
totalScroll = document.documentElement.scrollHeight - window.innerHeight;
}
onDestroy(() => {
clearInterval(unscrollInterval);
});
export let hideOnPrint: boolean;
</script>
<svelte:window
bind:scrollY
on:scroll={() => {
onScroll();
}}
on:touchstart={() => {
isBeingTouched = true;
}}
on:touchend={() => {
isBeingTouched = false;
}}
on:resize={onResize}
/>
<div class="{hideOnPrint ? 'hide-on-print' : ''} w-full">
<div
class="hidden h-64 w-full flex flex-col justify-end items-center"
bind:this={unscrollScrollDiv}
>
<img
src="/images/memes/WhatDaDog.png"
class="w-32 h-32 object-contain"
alt="da dog"
/>
</div>
<!-- About footer -->
<div class="sticky bottom-0 flex flex-col justify-center pt-8 bg-base-300">
<div class="flex justify-center">
<div class="grid gap-8 sm:grid-cols-3 align-middle w-full">
<div class="flex flex-col items-center">
<span class="font-bold">© 2023-2025</span>
<br />
<span>{$re?.name ?? "BOT Alex"}</span>
<br />
<span>Benjamin Dreyer</span>
<br />
<span>Snorre Ettrup Altschul</span>
</div>
<div class="flex flex-col items-center">
<h3><b>Info</b></h3>
<!-- <a href="/" target="_blank">Recursion</a> -->
<div class="flex justify-center">
This website was made using <a
class="grid place-content-center"
target="_blank"
href="https://kit.svelte.dev/"
>
<img
class="pl-2"
src={svelteLogo}
style="height: 1.5rem;"
alt="SvelteKit logo"
/></a
>
</div>
<!-- <span -->
<!-- >Website <a -->
<!-- href="https://git.deprived.dev/DeprivedDevs/deprived-main-website" -->
<!-- target="_blank">source code</a -->
<!-- ></span -->
<!-- > -->
</div>
<div class="flex flex-col items-center">
<h3><b>Contact</b></h3>
<a href="mailto:{$re?.email ?? 'Alex@deprived.dev'}"
>{$re?.email ?? "alex@deprived.dev"}</a
>
<div class="mt-2"></div>
<!-- <a -->
<!-- href="https://discord.gg/awatEEqc3M" -->
<!-- target="_blank" -->
<!-- class="social" -->
<!-- > -->
<!-- <span>Discord</span> -->
<!-- <img -->
<!-- src="/images/icons/discord.svg" -->
<!-- class="w-8 h-8 object-contain" -->
<!-- alt="Discord" -->
<!-- /> -->
<!-- </a> -->
</div>
</div>
</div>
<div
class="flex w-full justify-center border-t border-base-100 border-dashed"
>
Last build: {buildTime} (+2 UTC)
</div>
</div>
</div>
<div
bind:this={tranisitionOverlay}
class="{isLeavingAnimating
? ''
: 'hidden'} fixed top-0 left-0 w-screen h-screen bg-base-200"
></div>
<!-- {#if isLeavingAnimating}
{/if} -->

450
src/routes/cv/+page.svelte Normal file
View file

@ -0,0 +1,450 @@
<script lang="ts">
import re from "@ts/Redaction/Redactor";
import * as m from "$paraglide/messages";
import { getLocale, setLocale, locales } from "$paraglide/runtime";
import SendHorizontal from "@lucide/svelte/icons/send-horizontal";
// Left side
import NameAndImage from "./comps/NameAndImage.svelte";
import ShortProfile from "./comps/ShortProfile.svelte";
import CombinedContacts from "./comps/CombinedContacts.svelte";
import LinkedInQR from "./comps/LinkedInQR.svelte";
// Right side
import Profile from "./comps/Profile.svelte";
import Experience from "./comps/Experience.svelte";
import Education from "./comps/Education.svelte";
import BiggestFlex from "./comps/BiggestFlex.svelte";
import TableOfProjects from "./comps/TableOfProjects.svelte";
// Decorations
import LeftTopDecor from "./comps/LeftTopDecor.svelte";
import BottomRightDecor from "./comps/BottomRightDecor.svelte";
import AlexWatermark from "./comps/AlexWatermark.svelte";
import RepeatedSkills from "./comps/RepeatedSkills.svelte";
// Discord embed
import preveiwImage from "$lib/alex/cv-comps/preview.png";
// pages
import Page2 from "./pages/page2.svelte";
// Print detection setup
import onMount from "@e/onMount";
import { goto } from "$app/navigation";
let debug = false;
onMount(() => {
const urlParams = new URLSearchParams(window.location.search);
let needsUrlUpdate = false;
// 1. Safely handle hideOnPrint without reloading
if (!urlParams.has("hideOnPrint")) {
urlParams.set("hideOnPrint", "1");
needsUrlUpdate = true;
}
// 2. Check for locale in URL, fallback to localStorage
const urlLocale = urlParams.get("locale");
const savedLocale = localStorage.getItem("cv_locale");
const targetLocale = urlLocale || savedLocale;
if (targetLocale && targetLocale !== getLocale()) {
setLocale(targetLocale as any); // Update Paraglide
if (!urlLocale) {
urlParams.set("locale", targetLocale);
needsUrlUpdate = true;
}
}
// 3. Update the URL silently if we changed anything
if (needsUrlUpdate) {
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
window.history.replaceState({}, "", newUrl);
}
const params = new URLSearchParams(window.location.search);
debug = params.has("debug");
loadMotivation();
});
function changeLanguage(tag: string) {
setLocale(tag as any);
localStorage.setItem("cv_locale", tag);
const url = new URL(window.location.href);
url.searchParams.set("locale", tag);
window.location.href = url.toString();
}
let motivationInput: HTMLTextAreaElement;
let motivation: string | null = "";
function loadMotivation() {
const content = localStorage.getItem("motivation");
if (content && motivationInput) {
motivationInput.value = content;
motivation = content;
}
}
function submitMotivation() {
if (!motivationInput) return;
const content = motivationInput.value;
if (!content.trim()) {
localStorage.removeItem("motivation");
} else {
localStorage.setItem("motivation", content);
}
window.location.reload();
}
function getFormattedDate(): string {
const date = new Date();
const day = String(date.getDate()).padStart(2, "0");
const month = String(date.getMonth() + 1).padStart(2, "0");
const year = date.getFullYear();
return `${day}-${month}-${year}`;
}
</script>
<div>
<title
>{motivation ? "CUSTOM" : ""}
{$re?.name ?? "Alex"}'s {getLocale().toUpperCase()} CV {getFormattedDate()}</title
>
<meta content="{$re?.name ?? 'Alex'}'s CV" property="og:title" />
<meta
content="This CV is made completely with svelte + html + css + js"
property="og:description"
/>
<meta content={preveiwImage} property="og:image" />
<meta content="#bdd6ee" data-react-helmet="true" name="theme-color" />
<div class="cv-info-container h-[4cm] flex flex-col w-full hide-on-print">
<div class="flex w-full h-full items-center justify-center gap-8">
<div class=" flex flex-col">
<div>
<div class="keyboard-key">P</div>
+
<div class="keyboard-key">CTRL</div>
+ Chrome = PDF
</div>
<div class="flex gap-2">
CV Languages:
{#each locales as tag}
<button
class="btn btn-xs {tag == getLocale()
? 'btn-filled btn-primary text-primary-content'
: 'btn-outline'}"
onclick={() => {
changeLanguage(tag);
// window.location.reload();
}}
>
{tag.toUpperCase()}
</button>
{/each}
</div>
</div>
<div class="flex flex-col">
<div>Insert motivation</div>
<form
onsubmit={(e) => {
e.preventDefault();
submitMotivation();
}}
class="join"
>
<textarea
bind:this={motivationInput}
class="join-item input-xs h-[3cm] w-[12cm] textarea textarea-outline resize-x"
placeholder="Type something..."
></textarea>
<button type="submit" class="btn btn-xs join-item">
<SendHorizontal />
</button>
</form>
</div>
</div>
</div>
<!-- space -->
<!-- space -->
<!-- space -->
<!-- space -->
<div class="w-full flex flex-col max-h-[70cm]">
<div
class="relative w-full flex justify-center {$re?.name ? 'hidden' : ''}"
>
<RepeatedSkills
class="overcozette-force text-5xl text-secondary/32 text-base-300 "
style="transform: translateY(-90rem)"
textOverride={["REDACTED_VERSION"]}
targetTextHeight={90}
targetTextWidth={150}
rotation="-25deg"
textRowPadding={"1rem"}
/>
</div>
<div
class="{$re?.name
? ''
: 'absolute'} h-full w-full flex md:justify-center items-center"
>
<div class="NotoSans flex flex-col cv-config include-in-print">
<div class="cv-container sections decorations">
<div id="left-section" class=" flex justify-center">
<img
class="absolute self-center top-0 bottom-0 text-white"
style="transform: rotate(-90deg) scale(550%) translate(-2.5mm, 0); background-color: rgba(1, 1, 1, 0.85)"
src="/images/Zhen/cv/ZRuler-F_Cu.svg"
alt=""
/>
<LeftTopDecor />
<BottomRightDecor Style="pointer-events: none;" />
<div
class="absolute rotate-12 width-[10cm] h-full right-[15cm]"
style="background-color: #bdd6ee"
></div>
<div class="text-[var(--left-text-color)] pointer-events-none">
<div
class="pointer-events-auto flex flex-col justify-center w-full items-center"
>
<NameAndImage />
<div class="py-2"></div>
<ShortProfile />
<div class="py-2"></div>
<CombinedContacts />
<div class="py-2"></div>
<LinkedInQR />
</div>
</div>
<div class="relative h-full flex flex-col justify-end items-center">
<div class="text-sm w-32 mr-32 opacity-90 text-slate-400">
<div class="bg-black opacity-75 rounded">
I designed this PCB<br />For the nRF52840
</div>
</div>
</div>
</div>
<div id="leftSectionSeperator"></div>
<div
id="right-section"
class="text-[var(--right-text-color)] bg-white"
>
<AlexWatermark Style="pointer-events: none;" />
<div id="TopRightSkillsText">
<RepeatedSkills
class="cozette-force"
targetTextHeight={30}
targetTextWidth={150}
/>
</div>
<div>
<Profile />
<BiggestFlex />
<TableOfProjects />
<Experience />
<Education />
</div>
</div>
</div>
<div class="flex justify-center hide-on-print py-4">
<div>===== Next page =====</div>
</div>
<Page2 />
</div>
</div>
</div>
</div>
<style lang="scss">
.cv-config * {
--left-text-color: #eeeeee;
--left-line-color: #999999;
--left-decor-text-color: #eeeeee;
--left-decor-line-color: #999999;
--qr-color: #999999;
--left-grid-line-color: #ffffff;
--left-grid-bg-color: #000000;
--left-grid-opacity: 0.1;
--left-grid-size: 10px;
--right-text-color: #333333;
}
.corner-border-container {
background-color: var(--left-grid-bg-color);
background-image:
linear-gradient(
var(--left-decor-line-color),
var(--left-decor-line-color)
),
linear-gradient(
var(--left-decor-line-color),
var(--left-decor-line-color)
),
linear-gradient(
var(--left-decor-line-color),
var(--left-decor-line-color)
),
linear-gradient(
var(--left-decor-line-color),
var(--left-decor-line-color)
);
background-size:
30px 4px,
/* top-left horizontal */ 4px 30px,
/* top-left vertical */ 30px 4px,
/* bottom-right horizontal */ 4px 30px; /* bottom-right vertical */
background-repeat: no-repeat;
background-position:
top left,
top left,
bottom right,
bottom right;
}
.bg-grid-cv {
background:
linear-gradient(
-90deg,
rgba(255, 255, 255, var(--left-grid-opacity)) 1px,
transparent 1px
),
linear-gradient(
rgba(255, 255, 255, var(--left-grid-opacity)) 1px,
transparent 1px
),
var(--left-grid-line-color);
background-size:
var(--left-grid-size) var(--left-grid-size),
var(--left-grid-size) var(--left-grid-size),
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px,
80px 80px;
background-color: var(--color-base-100);
}
.cv-info-container {
background-color: #2b2a2a;
display: flex;
justify-content: center;
align-items: center;
.keyboard-key {
display: inline;
padding-left: 1mm;
padding-right: 1mm;
border-radius: 2mm;
background-color: #3e3d3d;
}
}
.cv-container {
width: 210mm;
height: 297mm;
background-color: #eeeeee;
overflow: visible;
display: flex;
padding: auto;
}
.sections {
// Shared between sections
> div {
display: grid;
z-index: 0;
// Needed to cuttoff the extra decoration
position: relative;
overflow: hidden;
}
#left-section {
// background-color: #bdd6ee;
> div:nth-child(5) {
z-index: 1;
width: 17.5rem;
left: 0;
padding-top: 30mm;
}
}
#right-section {
width: calc(100% / 3 * 2);
> div:last-child {
z-index: 1;
width: 100%;
left: 0;
display: grid;
place-items: center;
row-gap: 6mm;
padding-top: 45mm;
padding-bottom: 30mm;
// Disable interactivity for padding
// pointer-events: none;
}
}
}
.decorations {
#leftSectionSeperator {
position: relative;
height: 100%;
width: 0%;
z-index: 1;
overflow: visible;
> div {
position: absolute;
height: 100%;
width: 5mm;
z-index: 1;
background: linear-gradient(90deg, #3636364f, #00000000);
}
}
> div {
#TopRightSkillsText {
position: absolute;
z-index: 0;
display: grid;
place-items: center;
vertical-align: top;
width: 100%;
place-content: center;
padding: 0;
height: 50mm;
mask-image: linear-gradient(180deg, #000 0%, transparent 110%);
color: rgb(190, 190, 190);
font-family: "CozetteVector";
font-size: x-large;
}
}
}
</style>

View file

@ -0,0 +1,22 @@
<script>
export let Style = "";
</script>
<div class="container" style={Style}>ALEX</div>
<style lang="scss">
.container {
position: absolute;
display: grid;
justify-self: end;
vertical-align: bottom;
align-self: flex-end;
// font settings
font-size: 80mm;
color: black;
opacity: 5%;
transform: translate(28%, -7.5mm) rotate(-90deg);
}
</style>

View file

@ -0,0 +1,44 @@
<script lang="ts">
import * as m from "$paraglide/messages";
import { onMount } from "svelte";
let motivation: string | null = "";
onMount(() => {
motivation = localStorage.getItem("motivation");
});
</script>
<div class="short-profile-container">
<div class="flex gap-1">
{#if motivation}
<b style="text-align:left;">Motivation</b>
{:else}
<b style="text-align:left;">{m["zhen.cv.flex.title"]()}</b>
<h1
style="font-size: 0.5rem; color: grey;"
class="flex flex-col justify-end"
>
{m["zhen.cv.flex.tooltip"]()}
</h1>
{/if}
</div>
<div class="text-[0.85rem] text-left">
{#if motivation}
<div>{motivation}</div>
{:else}
{@html m["zhen.cv.flex.body"]()}
{/if}
</div>
</div>
<style>
.short-profile-container {
width: 90%;
}
.short-profile-container > div:first-child {
width: 100%;
/* Bottom border stripe*/
border-bottom: 1mm solid black;
}
</style>

View file

@ -0,0 +1,53 @@
<script>
export let Style = "";
</script>
<div class="container" style={Style}>
<div class="w-full flex justify-center">
<div class="text-center"></div>
</div>
</div>
<style lang="scss">
.container {
position: absolute;
transform: translate(20.3mm, -5mm) rotate(-45deg);
display: grid;
justify-self: end;
vertical-align: bottom;
align-self: flex-end;
z-index: 0;
> div:nth-child(1) {
padding-top: 5mm;
//border-bottom: #4472c4 dashed 2mm;
background-image: linear-gradient(
to right,
var(--left-decor-line-color) 70%,
rgba(255, 255, 255, 0) 0%
);
background-position: top;
background-size: 6mm 1.5mm;
background-repeat: repeat-x;
}
> div:nth-child(2) {
background-color: var(--left-decor-line-color);
width: 100mm;
height: 25mm;
// Text
display: grid;
place-content: center;
align-content: flex-start;
> div {
padding-top: 3.5mm;
color: #4a7bcf;
font-weight: bold;
}
}
}
</style>

View file

@ -0,0 +1,7 @@
<script>
import Contact from "./Contact.svelte";
import OtherContact from "./OtherContact.svelte";
</script>
<Contact/>
<OtherContact/>

View file

@ -0,0 +1,81 @@
<script lang="ts">
import re from "@ts/Redaction/Redactor";
</script>
<div class="container">
<div>
<b style="text-align:left;"> Contact </b>
</div>
<div class="table-display">
<div class="table-item">
<div>Email</div>
<div>{$re?.email ?? "alex@deprived.dev"}</div>
</div>
<div class="table-item">
<div>Phone</div>
<div>{$re?.phone ?? "1-800-273-8255"}</div>
</div>
<div class="table-item">
<div>LinkedIn</div>
<a
href={$re?.linkedIn.link ??
"https://www.youtube.com/watch?v=PaPotS8GSpc"}
>{$re?.linkedIn.text ?? "cool video lmao"}</a
>
</div>
</div>
</div>
<style lang="scss">
.container {
display: grid;
place-items: center;
width: 70%;
}
.container > div:first-child {
width: 100%;
/* Bottom border stripe*/
border-bottom: 1mm solid var(--left-line-color);
}
.table-display {
width: 100%;
}
.table-item {
display: flex;
justify-items: start;
width: 100%;
border-bottom: 0.25mm solid #000000;
> a {
text-decoration: underline;
}
> div,
> a {
&:first-child {
width: 35%;
font-size: 4mm;
display: grid;
place-content: center start;
border-right: rgba(128, 128, 128, 0.4) dashed 0.1mm;
}
&:nth-child(2) {
width: 65%;
font-size: 3.25mm;
display: grid;
place-content: center;
padding-left: 1mm;
}
}
}
</style>

View file

@ -0,0 +1,53 @@
<script>
import SasLogo from "$lib/alex/cv-comps/SASLogo.png";
import IconAndText2 from "./IconAndText2.svelte";
import re from "@src/ts/Redaction/Redactor";
import env, { initEnv } from "@src/ts/EnvHandler";
import onMount from "@src/optimizers/onMount";
onMount(() => {
initEnv();
});
</script>
<div class="container h-10">
<div>
<b style="text-align:left;"> Education </b>
</div>
<div class="flex justify-center p-2 w-full">
<IconAndText2
logo={$re?.education[0].imageId.replace("[PB]", env.POCKETBASE_URL) ?? ""}
>
<b>{$re?.education[0].name ?? "University 🤮"}</b><br />
<p style="font-size: 0.5rem;">AI and data</p>
</IconAndText2>
<IconAndText2 logo={$re?.education[1].imageId ?? ""}>
<b>{$re?.education[1].name ?? "High School 🤮"}</b><br />
<p style="font-size: 0.5rem;">Computer science</p>
</IconAndText2>
<IconAndText2 logo={SasLogo}>
<b>Master class</b><br />
<p style="font-size: 0.5rem;">SAS Programming</p>
</IconAndText2>
<IconAndText2 logo={$re?.education[2].imageId ?? ""}>
<span class="font-semibold"
>{$re?.education[2].name ?? "Paid vecation/certificate"}</span
><br />
<p style="font-size: 0.5rem;">VR development</p>
</IconAndText2>
</div>
</div>
<style lang="scss">
.container {
display: grid;
place-items: center;
width: 90%;
> div:first-child {
border-bottom: black 1mm solid;
width: 100%;
}
}
</style>

View file

@ -0,0 +1,74 @@
<script>
import re from "@src/ts/Redaction/Redactor";
import IconAndText from "./IconAndText.svelte";
</script>
<div class="container">
<div>
<b style="text-align:left;"> Experience </b>
</div>
<div class="table">
<div class="table-item">
<IconAndText logo={$re?.experience[0].imageId ?? ""}>
<b>Full-stack</b> - Part-time<br />
{$re?.experience[0].name ?? "[REDACTED] Deprived devs"}
<br />
<i>Feb 2025 - Now</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={$re?.experience[1].imageId ?? ""}>
<b>Data annotator</b> - Free-time<br />
{$re?.experience[1].name ?? "Some AI company"}<br />
<i>Jul 2024 - Now</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={$re?.experience[2].imageId ?? ""}>
<b>3D printer manager</b> - Volunteer<br />
{$re?.experience[2].name ?? "Actually Volunteering"}<br />
<i>Nov 2023 - Jan 2026</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={$re?.experience[3].imageId ?? ""}>
<b>Machine Learning Engineer</b> - Short term intern<br />
{$re?.experience[3].name ?? "YKYK"}<br />
<i>Apr 2024 - Apr 2024</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={$re?.experience[4].imageId ?? ""}>
<b>Assistant</b> - Short term intern<br />
{$re?.experience[4].name ??
"Awesome VR place, but got rejected 2 times after"}<br />
<i>Oct 2020 - Oct 2020</i>
</IconAndText>
</div>
</div>
</div>
<style lang="scss">
.container {
display: grid;
place-items: center;
width: 90%;
overflow: hidden;
& > div:first-child {
width: 100%;
/* Bottom border stripe*/
border-bottom: 1mm solid black;
}
}
.table-item {
padding: 2mm;
&:not(:last-child) {
border-bottom: 0.25mm solid #000000;
}
}
</style>

View file

@ -0,0 +1,165 @@
<script lang="ts">
import QrCode from "svelte-qrcode";
import DeprivedLogo from "$lib/images/DeprivedLogo.svelte";
const cols = 9;
const rows = 7;
// Geometry Constants
const width = 73; // px
const height = width * 1.1547; // Perfect hexagonal ratio
const gap = 4; // Space between hexagons
// Calculations for layout
const horizontalSpacing = width + gap;
const verticalOverlap = height * 0.25;
const rowHeight = height - verticalOverlap + gap;
const offset = horizontalSpacing / 2;
const hexPath =
"polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)";
import { getSkills, Skill } from "@src/ts/misc/ZhenSkills";
import * as m from "$paraglide/messages";
import { getLocale, setLocale, locales } from "$paraglide/runtime";
import re from "@ts/Redaction/Redactor";
import { redirect } from "@sveltejs/kit";
let cvLink: string = "";
$: cvLink = `/cv?locale=${getLocale() == "en" ? "dk" : "en"}&key=${$re?.key ?? "nah"}`;
let skills: Skill[] = [];
$: skills = getSkills(cvLink);
function getIndex(r: int, c: int): int {
return Math.floor(r / 2) * (2 * cols + 1) + (r % 2) * (cols + 1) + c;
}
</script>
<div class=" text-[#121212] flex flex-col pb-auto">
<div class="flex justify-between items-center px-8 py-4">
<div class="font-semibold text-2xl">
{m["zhen.cv.page2.mini-projects.title"]()}
</div>
<div class="flex gap-4">
<div class="border-b-6 border-[#121212]/32">
{m["zhen.cv.page2.mini-projects.ask"]()}
</div>
<div class="border-b-6 border-[#7bd45d]">
{m["zhen.cv.page2.mini-projects.linked"]()}
</div>
</div>
</div>
<div class="relative overflow-show">
<div
class="relative pb-12"
style="padding-left: 13.5px; width: {cols * horizontalSpacing + offset}px"
>
{#each Array(rows) as _, r}
<div
class="flex"
style="
margin-bottom: -{verticalOverlap - gap}px;
padding-left: {r % 2 !== 0 ? offset : 0}px;
"
>
{#each Array(cols + (r % 2 == 0)) as _, c}
{@const x = getIndex(r, c)}
{#if x < skills.length}
<div class="hidden"></div>
<div
class=" {skills[x].link != undefined
? 'bg-[#7bd45d]'
: 'bg-[#121212]/32'} flex items-center justify-center shrink-0"
style="
width: {width}px;
height: {height}px;
clip-path: {hexPath};
margin-right: {gap}px;
"
>
{#if skills[x].link != undefined}
<a
href={skills[x].link}
target="_blank"
class="relative bg-[#eeeeee] w-full grid items-center shrink-0"
style="
width: {width * 0.9}px;
height: {height * 0.9}px;
clip-path: {hexPath};
"
>
<img class="p-3.5" src={skills[x].image} alt="" />
<div
class="w-0 h-0 absolute text-[0.2cm] top-0 pt-5 text-nowrap {skills[
x
].link != undefined
? 'text-[#589942]'
: 'text-[#121212]/50'}"
style="transform: translate(0, 0%) rotate(-30deg); margin-left: -0.2cm;"
>
{skills[x].alt}
</div>
</a>
{:else}
<div
class="relative bg-[#eeeeee] w-full grid items-center shrink-0"
style="
width: {width * 0.9}px;
height: {height * 0.9}px;
clip-path: {hexPath};
"
>
<img class="p-3.5" src={skills[x].image} alt="" />
<div
class="w-0 h-0 absolute text-[0.2cm] top-0 pt-5 text-nowrap {skills[
x
].link != undefined
? 'text-[#589942]'
: 'text-[#121212]/50'}"
style="transform: translate(0, 0%) rotate(-30deg); margin-left: -0.2cm;"
>
{skills[x].alt}
</div>
<!-- <div class="absolute top-0 right-0"> -->
<!-- <div -->
<!-- style="transform: translate(0, 0%) rotate(30deg); " -->
<!-- class="w-0 text-[0.2cm] w-full pt-1" -->
<!-- > -->
<!-- {skills[x].alt} -->
<!-- </div> -->
<!-- </div> -->
</div>
{/if}
</div>
{/if}
{/each}
</div>
{/each}
</div>
<div class="absolute pointer-events-none left-0 bottom-0">
<DeprivedLogo
Class="fill-[#121212]/6 px-4"
Style="width: 12.5cm; height: auto;"
/>
</div>
<div class="absolute right-0 bottom-0 px-4">
<div class="w-full flex justify-end">
<div class="flex flex-col justify-center items-center">
<div>{m["zhen.cv.page2.qrcode-text"]()}</div>
<div class="w-[50px] h-[50px] overflow-hidden">
<QrCode
size={205}
padding={0}
value={"https://deprived.dev" + cvLink}
background={"#eeeeee"}
/>
</div>
</div>
</div>
</div>
</div>
</div>

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