Compare commits

...
Sign in to create a new pull request.

83 commits
dev ... main

Author SHA1 Message Date
900888ee07 Fixed random themes at first login. (this commit is from a macbook in Bilka) 2025-05-31 17:00:48 +00:00
11274585f6 sync 2025-05-28 20:29:57 +02:00
04ef603bca bring back blue background 2025-05-28 20:15:19 +02:00
3efc93280f Added Yaaumma in experience 2025-05-28 20:10:17 +02:00
32b57ea003 nvim pissed me off. imma sleep 2025-05-27 04:30:15 +02:00
7fd7682f98 Changed photo to vr setup 2025-05-27 03:59:26 +02:00
72811eacc4 fixed my CV with Vim! 2025-05-26 05:19:26 +02:00
d3e11c32e6 fixed header not hiding when wanting to print 2025-05-25 00:15:40 +02:00
0c2ab8d93f I think i forgot to include this file lol 2025-05-24 23:45:49 +02:00
0925af468e changed source code link 2025-05-24 05:17:51 +02:00
e65b6c97c6 removed the scroll thing, because i'm too lazy to continue for a while 2025-05-24 05:12:04 +02:00
e3f015d4b3 source code location updated. and something else but too drunk lol 2025-05-13 01:41:41 +02:00
f1a8ccd319 updated embed 2025-05-13 01:39:34 +02:00
983813020e scroll thingy good. now animation 2025-05-13 00:43:47 +02:00
50c08b6b67 progress on scrolling thing 2025-05-12 20:44:22 +02:00
71ad89b197 Fixed hamburger and slight layout improvement 2025-05-12 20:18:00 +02:00
4bd2b48590 Started on something 2025-05-12 20:08:09 +02:00
eaf10d4475 Added deprived theme 2025-05-12 19:01:19 +02:00
93b7c5e7c7 slightly better bloat loading 2025-05-10 20:53:02 +02:00
d6501f0b3a Hello mr. Would you like some bloat? 2025-05-10 20:29:57 +02:00
2291cf927b workflow for signalling rebuild 2025-05-04 23:48:32 +02:00
1249e30ec7 get branch name 2025-05-04 23:46:55 +02:00
c90e8555da test workflow 2025-05-04 18:20:00 +02:00
abf264544f Zylvester is 2d and 3d artist 2025-04-06 17:46:51 +02:00
18a49a3165 Added zylvester's linkedin 2025-04-06 17:41:18 +02:00
efbaaef915 snorre 2025-04-06 06:23:06 +02:00
062e883afb theme switch button and tooltip 2025-04-06 06:14:24 +02:00
e3f43f86f1 Theme switcher 2025-04-06 06:07:17 +02:00
162158340b faster theme load 2025-04-06 05:32:18 +02:00
68ebf556c4 Loading last theme selected 2025-04-06 05:29:49 +02:00
4b933b7b0e better mobile again 2025-04-06 05:26:39 +02:00
a3daf3cfd5 randomized theme 2025-04-06 05:18:02 +02:00
BOT Alex
a0eaeb15fd All in cozette font 2025-04-06 01:36:50 +02:00
BOT Alex
33b291f3bf Mobile is better now 2025-04-06 01:26:19 +02:00
BOT Alex
2408174b8b Improved main page 2025-04-06 01:21:16 +02:00
BOT Alex
b56ef35802 Added text specifing timezone 2025-04-06 00:37:12 +02:00
BOT Alex
1fe30148f7 Added build timestamp 2025-04-06 00:35:42 +02:00
BOT Alex
379577cc5c Removed ALL errors 2025-04-06 00:17:55 +02:00
BOT Alex
f64ae9f991 deleted vibe coded file 2025-04-05 22:49:57 +02:00
BOT Alex
49c6816d07 Fixed inconsistent navbar 2025-04-05 22:30:16 +02:00
BOT Alex
4fa68a8e7f Migrated to daisyui 5 2025-04-05 22:28:32 +02:00
BOT Alex
2fa0e4ee8e Removed svelte parallax 2025-04-05 21:43:05 +02:00
BOT Alex
2558592d9c Update source code location url 2025-04-05 21:36:02 +02:00
BOT Alex
a5fdd78d4e Svelte 5 update? 2025-04-05 21:35:02 +02:00
2b5da73712 use main branch for build 2025-03-17 01:46:21 +01:00
62f7199a76 Added a WIP disclaimer to website 2025-03-17 01:39:15 +01:00
f27dbcee8c progress on mcus 2025-03-03 11:32:49 +01:00
b1c92296a6 removed about us 2025-03-03 03:31:50 +01:00
f45fc592b8 sync 2025-02-28 09:24:37 +01:00
22cabd41ac Now changes tab tittle on load 2025-02-28 08:38:35 +01:00
fe120609fb Merge branch 'WeGoingBasic' of https://gitea.deprived.dev/Sveskejuice/deprived-main-website into WeGoingBasic 2025-02-27 18:46:39 +01:00
01865b473b Update +page.svelte 2025-02-27 18:46:38 +01:00
Your Name
d025b2432b Update buildscript 2025-02-25 16:04:15 +01:00
BOT Alex
d8416aa883 sync 2025-02-25 15:24:26 +01:00
ece1ed6bbe started on battery life calculator 2025-02-24 05:19:12 +01:00
BOT Alex
0d9ecf1fb9 fuck this. we sticking to latex 2025-02-13 11:56:05 +01:00
BOT Alex
71fe791ef7 added kim 2025-02-13 11:12:56 +01:00
BOT Alex
4025e233d8 updated source code link 2025-02-13 10:47:42 +01:00
4feb8b3e76 More SEO 2025-02-02 21:07:17 +01:00
99e260c00f Fuck it, SEO optimisation 2025-02-02 20:48:37 +01:00
d7ed881a22 added back-end tag 2025-01-14 20:17:03 +01:00
e89e92becf didn't build because of benjamin's legacy server-side code. he stupid 2025-01-14 03:18:23 +01:00
3fea371315 switched colors of 2d and 3d because wrong lol 2025-01-14 03:15:05 +01:00
02cabb05ad added better logo 2025-01-14 03:13:13 +01:00
6bb351e2bd I forgot to add <slot> 2025-01-14 02:57:49 +01:00
1dffd47bc1 oh fuck, even more cooking!!! 2025-01-14 02:56:20 +01:00
6d55a75aa4 fuck guys, I've might have cooked again :( 2025-01-14 02:08:26 +01:00
7faf1b01d0 "feature" 2025-01-14 00:34:50 +01:00
87255bb9cd added snorre to footer 2025-01-14 00:08:52 +01:00
c6b7c5790b Added snorre to the list 2025-01-14 00:05:06 +01:00
Your Name
b8913fe805 perms 2025-01-10 00:38:31 +01:00
Your Name
6480b80e91 build script 2025-01-10 00:36:51 +01:00
a9b8f55591 added easier cv link 2025-01-09 17:09:13 +01:00
3a6148cf90 slight cv update 2025-01-09 17:03:43 +01:00
BOT Alex
31cf1587d2 import instead of require 2025-01-01 01:27:02 +01:00
BOT Alex
16138b580a build passed this time 2024-12-31 18:14:39 +01:00
BOT Alex
4e4747d718 test 2024-12-31 17:51:57 +01:00
BOT Alex
37d075fbd6 should be fixed now 2024-12-31 17:50:58 +01:00
BOT Alex
a27bd352cd found out theres git size limits. wtf 2024-12-31 17:48:12 +01:00
BOT Alex
f2489db1df still conflics 2024-12-31 17:47:38 +01:00
BOT Alex
473c4307d3 Update timelineItem.svelte 2024-12-31 17:43:29 +01:00
BOT Alex
8ff7ef5a0f merge conflics... 2024-12-31 17:43:18 +01:00
5f78e8bf04 There's complexity in simplicity: 2024-12-31 05:04:13 +01:00
470 changed files with 10488 additions and 7568 deletions
.forgejo/workflows
build.logbuild.shjsconfig.jsonpackage-lock.jsonpackage.jsonpnpm-lock.yamlpostcss.config.js
src
static

View file

@ -0,0 +1,23 @@
name: Rebuild signaller for deprived.dev to rebuild site
on: [push]
jobs:
test_service:
runs-on: native
steps:
- name: Get branch
run: echo "BRANCH=$(echo "${{ gitea.ref }}" | cut -d'/' -f3)" >> $GITHUB_ENV
- name: Signal deprived.dev for rebuild
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
run: |
sshkey=$(mktemp)
trap "rm -rf $sshkey" exit
echo -e $SSH_PRIVATE_KEY > $sshkey
service="build-deprived-website-$BRANCH"
sshargs="-o LogLevel=ERROR -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
echo "Starting systemd oneshot service: $service"
ssh -i $sshkey -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no deprivedbuilder@deprived.dev -t "sudo /run/current-system/sw/bin/systemctl start $service"
echo "Build Log: $(ssh -i $sshkey $sshargs deprivedbuilder@deprived.dev "cat ~/latest_build.log")"

0
build.log Normal file
View file

16
build.sh Normal file
View file

@ -0,0 +1,16 @@
#!/usr/bin/env bash
# motherfucking hate npm. Spent 3 hours debugging that when
# NODE_ENV is set to production, npm won't install anything
unset NODE_ENV
git pull
git reset --hard main
npm ci
echo "Ready to build, building..."
npm run build
echo "Done rebuilding!"

View file

@ -10,7 +10,12 @@
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true
"allowImportingTsExtensions": true,
"paths": {
"@images/*": ["./src/images/*"],
"@src/*": ["./src/*"],
"@static/*": ["./static/*"]
}
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias and https://kit.svelte.dev/docs/configuration#files
//

3397
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,36 +6,33 @@
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --compiler-warnings \"css-unused-selector:ignore,unused-export-let:ignore\" --threshold error",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch --threshold error"
},
"devDependencies": {
"@poppanator/sveltekit-svg": "^4.2.1",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/kit": "^2.20.4",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tailwindcss/typography": "^0.5.15",
"@zerodevx/svelte-img": "^2.1.0",
"autoprefixer": "^10.4.20",
"daisyui": "^4.12.12",
"postcss": "^8.4.47",
"daisyui": "^5.0.12",
"sass": "^1.77.4",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"svelte-confetti": "^1.0.0",
"svelte": "^5.25.7",
"svelte-check": "^3.8.6",
"svelte-highlight": "^7.6.0",
"svelte-parallax": "^0.6.0",
"tailwindcss": "^3.4.13",
"tailwindcss": "^4.1.3",
"typescript": "^5.0.0",
"vite": "^5.0.3",
"vite-plugin-svgr": "^4.2.0"
},
"type": "module",
"dependencies": {
"@lucide/svelte": "^0.487.0",
"@tailwindcss/vite": "^4.1.3",
"lucide-svelte": "^0.475.0",
"svelte-katex": "^0.1.2",
"svelte-media-queries": "^1.6.2",
"svelte-particles": "^2.12.0",
"theme-change": "^2.5.0",
"tsparticles-slim": "^2.12.0"
"theme-change": "^2.5.0"
}
}

2502
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +0,0 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

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;
}
}

View file

@ -1,16 +1,42 @@
<!doctype html>
<html lang="en" data-theme="Synthwave">
<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/main-theme.css" />
<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>
<div style="display: contents">%sveltekit.body%</div>
<body style="display: contents">
<div class="inline relative w-full h-full">%sveltekit.body%</div>
</body>
</html>

View file

@ -1,6 +1,5 @@
<script lang="ts">
import HorizonalStack from "../Utils/HorizonalStack.svelte";
import Img from '@zerodevx/svelte-img'
import VerticalStack from "../Utils/VerticalStack.svelte";
import ZSpacer from "../Utils/ZSpacer.svelte";
import MediaQuery from 'svelte-media-queries';

Binary file not shown.

After

(image error) Size: 711 KiB

Binary file not shown.

After

(image error) Size: 387 KiB

Binary file not shown.

After

(image error) Size: 756 KiB

Binary file not shown.

After

(image error) Size: 193 KiB

Binary file not shown.

After

(image error) Size: 64 KiB

Binary file not shown.

After

(image error) Size: 829 KiB

Binary file not shown.

After

(image error) Size: 708 KiB

Binary file not shown.

After

(image error) Size: 129 KiB

Binary file not shown.

After

(image error) Size: 131 KiB

Binary file not shown.

After

(image error) Size: 121 KiB

Binary file not shown.

After

(image error) Size: 123 KiB

Binary file not shown.

After

(image error) Size: 106 KiB

Binary file not shown.

After

(image error) Size: 135 KiB

View file

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

Binary file not shown.

After

(image error) Size: 8.2 KiB

File diff suppressed because one or more lines are too long

View file

@ -11,9 +11,7 @@
version="1.1"
viewBox="0 0 28 20"
width="28"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
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"

Binary file not shown.

After

(image error) Size: 673 KiB

Binary file not shown.

After

(image error) Size: 14 KiB

View file

@ -1,135 +1,150 @@
<!-- If url contains "hideOnPrint" param, then detect if start printing then hide elements -->
<script lang="ts">
import "$lib/app.css";
import "../app.css";
import { fly } from "svelte/transition";
import MediaQuery from "svelte-media-queries";
import { Dices } from "@lucide/svelte";
let hideOnPrint: boolean = $state(false);
import { fly } from 'svelte/transition';
import MediaQuery from 'svelte-media-queries';
export let hideOnPrint: boolean;
let { children } = $props();
import DeprivedLogo from "$lib/images/DeprivedLogo.svelte";
import HamburgerMenuIcon from "$lib/images/HamburgerMenuIcon.svelte";
const footerCollapseThreshold : string = '1000px';
const headerCollapseThreshold : string = '1000px';
let footerCollapse : boolean;
let headerCollapse : boolean;
const footerCollapseThreshold: string = "1000px";
const headerCollapseThreshold: string = "1000px";
let footerCollapse: boolean;
let isMobile: boolean = $state(false);
let navbarHidden : boolean = true;
let navbarHidden: boolean = $state(true);
function resetNavBar() {
navbarHidden = true;
}
import { afterNavigate } from '$app/navigation';
import { afterNavigate } from "$app/navigation";
afterNavigate(() => {
const params = new URLSearchParams(window.location.search);
hideOnPrint = params.get('hideOnPrint') === '1';
//console.log(hideOnPrint);
hideOnPrint = params.get("hideOnPrint") === "1";
console.log(hideOnPrint);
});
import { onMount } from 'svelte';
import { themeChange } from 'theme-change'
onMount(() => {
const lock = document.createElement('meta');
lock.name = 'darkreader-lock';
import { onMount } from "svelte";
import Zooter from "./comps/Zooter.svelte";
onMount(async () => {
const lock = document.createElement("meta");
lock.name = "darkreader-lock";
document.head.appendChild(lock);
themeChange(false) // false parameter is required for svelte
});
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={headerCollapse} />
<MediaQuery
query="(max-width: {footerCollapseThreshold})"
bind:matches={footerCollapse}
/>
<MediaQuery
query="(max-width: {headerCollapseThreshold})"
bind:matches={isMobile}
/>
<!-- Nav bar -->
<div class="bg-base-200 p-0">
<header class="{hideOnPrint ? 'hide-on-print' : ''}">
<div class="nav-bar pr-4 bg-base-200">
{#if !headerCollapse}
<div class=" bg-base-200 p-0">
<header class="{hideOnPrint ? 'hide-on-print' : ''} bg-base-300">
<div class="nav-bar pr-4">
{#if !isMobile}
<div class="desktop">
<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>
<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" />
<select class="prose" data-choose-theme>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="synthwave">Synthwave</option>
<option value="retro">Retro</option>
<option value="cyberpunk">Cyberpunk</option>
<option value="valentine">Valentine</option>
<option value="halloween">Halloween</option>
<option value="forest">Forest</option>
<option value="aqua">Aqua</option>
<option value="black">Black</option>
<option value="luxury">Luxury</option>
<option value="dracula">Dracula</option>
<option value="business">Business</option>
<option value="night">Night</option>
<option value="coffee">Coffee</option>
<option value="dim">Dim</option>
<option value="sunset" selected>Sunset</option>
</select>
<a href="/">Home</a>
<a href="https://botalex.itch.io/">Games</a>
<!-- <a href="/">Home</a> -->
<!-- <a href="/zhen/notes/physics/1?hideOnPrint=1" target="_blank" style="width: 7.5rem;">Notes</a> -->
{@render SwitchThemeButton()}
<a
href="/zhen/cv/rev2?hideOnPrint=1"
target="_blank"
style="width: 7.5rem;">Zhen CV</a
>
<a href="/tools" style="width: 7.5rem;">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">
<a on:click={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>
<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" />
<button id="toggle-nav" on:click={() => navbarHidden = !navbarHidden}>
<HamburgerMenuIcon Class="fill-base-content"/>
{@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 }}>
<select data-choose-theme>
<option value="light">Default</option>
<option value="dark">Dark</option>
<option value="cupcake">Cupcake</option>
<option value="bumblebee">Bumblebee</option>
<option value="emerald">Emerald</option>
<option value="corporate">Corporate</option>
<option value="synthwave">Synthwave</option>
<option value="retro">Retro</option>
<option value="cyberpunk">Cyberpunk</option>
<option value="valentine">Valentine</option>
<option value="halloween">Halloween</option>
<option value="garden">Garden</option>
<option value="forest">Forest</option>
<option value="aqua">Aqua</option>
<option value="lofi">Lofi</option>
<option value="pastel">Pastel</option>
<option value="fantasy">Fantasy</option>
<option value="wireframe">Wireframe</option>
<option value="black">Black</option>
<option value="luxury">Luxury</option>
<option value="dracula">Dracula</option>
<option value="cmyk">CMYK</option>
<option value="autumn">Autumn</option>
<option value="business">Business</option>
<option value="acid">Acid</option>
<option value="lemonade">Lemonade</option>
<option value="night">Night</option>
<option value="coffee">Coffee</option>
<option value="winter">Winter</option>
<option value="dim">Dim</option>
<option value="nord">Nord</option>
<option value="sunset">Sunset</option>
</select>
<a on:click={resetNavBar} href="/">Home</a>
<a on:click={resetNavBar} href="https://botalex.itch.io/">Games</a>
<!-- <a on:click={resetNavBar} href="/posts">Blog</a>
<a on:click={resetNavBar} href="/about">About</a> -->
<!-- <a onclick={resetNavBar} href="/">Home</a> -->
<a
onclick={resetNavBar}
href="https://botalex.itch.io/"
target="_blank">Games</a
>
<a href="/zhen/cv/rev2?hideOnPrint=1" target="_blank">Zhen's CV</a>
<!-- <a onclick={resetNavBar} href="/posts">Blog</a>
<a onclick={resetNavBar} href="/about">About</a> -->
</div>
{/if}
{/if}
@ -137,40 +152,25 @@
</header>
<!-- Page content -->
<slot />
{@render children?.()}
<!-- About footer -->
<footer class="{hideOnPrint ? 'hide-on-print' : ''}">
<div class="about-container">
<div class="credits">
<span>© 2023-2024</span>
<br>
<span>Benjamin Dreyer</span>
<br>
<span>Oliver Schwenger</span>
<br>
<span>Sylvester Junge</span>
<br>
<span>Zhentao Wei</span>
<br>
<br>
<span>Website <a href="https://gitea.deprived.dev/Sveskejuice/deprived-main-website/src/branch/dev" target="_blank">source code</a></span>
</div>
<div>
<h3>About Us</h3>
<a href="/about">About</a>
</div>
<div class="contact">
<h3>Contact</h3>
<a href="https://discord.gg/awatEEqc3M" target="_blank" class="social">
<img src="/images/icons/discord.svg" alt="Discord"/>
<span>Discord</span>
</a>
</div>
</div>
</footer>
<Zooter bind:hideOnPrint />
</div>
{#if footerCollapse}
<style>
.about-container {
flex-direction: column;
justify-content: center !important;
gap: 25px;
}
</style>
{/if}
{#if isMobile}
<style>
</style>
{/if}
<style lang="scss">
/* Nav bar. */
@ -204,7 +204,6 @@
border: none;
}
.nav-list {
display: flex;
flex-direction: column;
@ -268,6 +267,10 @@
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
& h3 {
font-size: larger;
}
}
.about-container > div {
@ -307,26 +310,4 @@
a:hover {
filter: brightness(130%);
}
@media print {
.hide-on-print {
display: none;
}
}
</style>
{#if footerCollapse}
<style>
.about-container {
flex-direction: column;
justify-content: center !important;
gap: 25px;
}
</style>
{/if}
{#if headerCollapse}
<style>
</style>
{/if}

View file

@ -1,168 +1,259 @@
<script lang="ts">
import ProfileSpacer from './comps/ProfileSpacer.svelte';
import MediaQuery from 'svelte-media-queries';
import NewsCard from '$lib/posts/NewsCard.svelte';
import ShowcaseNewsCard from '$lib/posts/ShowcaseNewsCard.svelte';
import Button from '$lib/IO/Button.svelte';
import { ButtonType } from '$lib/IO/ButtonType.ts';
import Timeline from '../comps/timeline/timeline.svelte';
import { Parallax, ParallaxLayer, StickyLayer } from "svelte-parallax";
import { Confetti } from "svelte-confetti"
import { tick } from 'svelte'
import { onMount, tick } from 'svelte'
import PreviewDeprivedLogo from "$lib/images/DeprivedLogo-NoBackground.png";
import BackgroundVideo from "$lib/videos/DeprivedDevMontage.gif"
import FrontFold from './comps/FrontFold.svelte';
import Carousel from './comps/Carousel.svelte';
import Corrobot1 from "$lib/GamePreviews/Corrobot-rebouce-title.jpg"
import Corrobot2 from "$lib/GamePreviews/Corrobot-rebouce-gameplay1.png"
import Corrobot3 from "$lib/GamePreviews/Corrobot-rebouce-gameplay2.png"
import Blood1 from "$lib/GamePreviews/Blood-title.png"
import Blood2 from "$lib/GamePreviews/Blood-preview1.png"
import Blood3 from "$lib/GamePreviews/Blood-preview2.png"
import Blood4 from "$lib/GamePreviews/Blood-preview3.png"
import Blood5 from "$lib/GamePreviews/Blood-preview4.png"
import Time1 from "$lib/GamePreviews/Time-1.png"
import Time2 from "$lib/GamePreviews/time-2.png"
import Time3 from "$lib/GamePreviews/time-3.png"
import Time4 from "$lib/GamePreviews/time-4.png"
import Time5 from "$lib/GamePreviews/time-5.gif"
import Tags from './comps/Tags.svelte';
import NameAndTag from './comps/NameAndTag.svelte';
import Profile from './comps/Profile.svelte';
const mobileThreshold : string = '600px'; // was 1000px. zhen testing
let mobile : boolean;
import { onMount } from 'svelte';
// Restore scroll position on mount
let showConfetti: boolean = false;
function onProgressConfetti(progress: number){
console.log(progress);
showConfetti = !mobile && progress > 0.225 || mobile && progress > 0.32;
}
onMount(()=> {
let tabTittleElement = window.document.getElementById("TabTittle");
if (tabTittleElement) // Not null
tabTittleElement.innerHTML = "Deprived devs";
});
</script>
<!-- Detect mobile -->
<MediaQuery query='(max-width: {mobileThreshold})' bind:matches={mobile} />
<Parallax sections={2.5}>
<ParallaxLayer span={0.6} rate={0.2} class="pointer-events-none">
<div class="pointer-events-auto" style="position: relative; width: 100%; height: 100%; overflow: hidden;">
<img src="{BackgroundVideo}" style="width: 100%; height: 100%; object-fit: cover; filter: blur(5px) brightness(0.6);" alt="Background video"/>
<div class="main-title m-auto" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; justify-content: center; align-items: center; gap: 2rem; color: white; padding: 1rem;">
<h1 style="font-size: {!mobile ? 5 : 3}rem; text-shadow: 0.2rem 0.2rem 1rem rgba(0, 0, 0, 0.9); z-index: 100;">{@html !mobile ? "Deprived Devs" : "Deprived<br/>Devs"}</h1>
<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="pointer-events-auto" style="position: relative; width: 100%; height: 100%; overflow: hidden;">
<img id="backgroundGif" src="{BackgroundVideo}" alt="Background video"/>
<div class="main-title m-auto cozette" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; justify-content: center; align-items: center; gap: 2rem; color: white; padding: 1rem;">
<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>
</ParallaxLayer>
<ParallaxLayer offset={0.55} rate={0.3} class="bg-base-200 pointer-events-none">
</div>
</ParallaxLayer>
<div class="cozette flex flex-col justify-center items-center 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">
<ParallaxLayer onProgress={onProgressConfetti} offset={0.75}>
<div class="prose flex justify-center m-auto">
<h1 class="main-title text-center" style="font-size: {!mobile ? 3 : 2}rem;">
Developers!
</h1>
</div>
</ParallaxLayer>
<!-- Decorative: -->
<StickyLayer offset={(!mobile) ? ({ top: 0.4, bottom: 0.75 }) : ({ top: 0.4, bottom: 0.4 })} class="pointer-events-none">
<div class="prose font-mono pointer-events-auto h-full" style="max-width: 100%;">
<div class="flex justify-center items-center h-full relative">
<div class="flex justify-center" style="position: absolute; top: 30vh; {!mobile ? "max-width: 35vw;" : "width: 100%;"}">
{#if showConfetti}
<div>
<Confetti noGravity cone amount={50} colorArray={["white"]} />
</div>
{/if}
</div>
<div class="grid gap-4" style="{!mobile ? "max-width: 50vw;" : ""} background: linear-gradient(to bottom, transparent 0%, oklch(var(--b2)) 5%)">
<FrontFold Title="Alex / Zhen" Checked={true}>
<p>Hi, I am Alex/Zhen, I'm that chinese guy.</p>
<Profile name="Zhen / Alex" tags={["Programmer", "3D artist", "UX Designer"]} isMobile={mobile}>
<span>
<p>Hi, I am Alex/Zhen, {@html !mobile ? "" : "<br/>"} I'm that chinese guy.</p>
<p>Here's my CV: <a href="/zhen/cv/rev2?hideOnPrint=1" style="color:lightblue;">pdf</a></p>
</FrontFold>
<FrontFold Title="Sveske / Benjamin">
<p>Hi, I use Arch, btw.</p>
<p>Here's my Linked-in: <a href="https://www.linkedin.com/in/benjamin-dreyer/" style="color:lightblue;">Linked-in</a></p>'
</FrontFold>
<FrontFold Title="Zylvester">
<p>Hi, I am [insert text here]</p>
<p>Here's a joke about recursion: <a href="/" style="color:lightblue;">recursion</a></p>
</FrontFold>
</div>
</div>
</div>
</StickyLayer>
</span>
</Profile>
<ParallaxLayer offset={1.5} rate={0.3} class="bg-base-200 pointer-events-none" style="box-shadow: 0 -1rem 10px rgba(0, 0, 0, 0.2);" >
<div class="grid place-content-center place-items-center min-h-screen pointer-events-auto">
<article class="pt-16 prose overflow-hidden font-mono {mobile ? "px-8" : ""}">
<h1 class="main-title {!mobile ? "text-center m-auto" : "m-0"}" style="font-size: {!mobile ? 5 : 3}rem; ">About us</h1>
<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 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></p>
</span>
</Profile>
<Profile 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></p>
</span>
</Profile>
<Profile name="Zylvester" tags={["Sound/Story", "2D/3D artist"]} isMobile={mobile}>
<span>
<p>Closeted omega weeb</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></p>
</span>
</Profile>
</div>
</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 class="{!mobile ? "py-16" : "py-4"}"/>
<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">
<div class="flex w-52 flex-col gap-4">
<div class="skeleton h-32 w-full"></div>
<div class="skeleton h-4 w-28"></div>
<div class="skeleton h-4 w-full"></div>
<div class="skeleton h-4 w-full"></div>
<!-- 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 class="flex w-52 flex-col gap-4">
<div class="skeleton h-32 w-full"></div>
<div class="skeleton h-4 w-28"></div>
<div class="skeleton h-4 w-full"></div>
<div class="skeleton h-4 w-full"></div>
</div>
{#if !mobile}
<div class="flex w-52 flex-col gap-4">
<div class="skeleton h-32 w-full"></div>
<div class="skeleton h-4 w-28"></div>
<div class="skeleton h-4 w-full"></div>
<div class="skeleton h-4 w-full"></div>
</div>
<div class="flex w-52 flex-col gap-4">
<div class="skeleton h-32 w-full"></div>
<div class="skeleton h-4 w-28"></div>
<div class="skeleton h-4 w-full"></div>
<div class="skeleton h-4 w-full"></div>
</div>
{/if}
</div>
<h6 class="prose text-base-300"><b>(These will never load)</b></h6>
<!-- 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>
</ParallaxLayer>
<!-- <StickyLayer offset={{ top: 1.75, bottom: 2 }} >
<div class="flex justify-center prose main-title overflow-hidden">
<h1 style="font-size: {!mobile ? 5 : 3}rem;">About us</h1>
</div>
</StickyLayer> -->
</Parallax>
<Timeline/>
<!-- 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>
<style>
.main-title {
width: 80%;
font-family: var(--title-font);
#backgroundGif{
width: 100%;
height: 100%;
max-height: 40vh;
object-fit: cover;
filter: blur(5px) brightness(0.6);
}
</style>
{#if mobile}
{#if !mobile}
<style>
#news-section {
transition-duration: 500ms;
transition-property: width;
width: 90% !important;
.games {
width: 24rem /* 384px */;
}
.news-container {
flex-direction: column !important;
</style>
{:else}
<style>
.games {
width: 80%;
display: flex;
justify-self: center;
}
.dummy {
width: 0% !important;
}
/* #more-posts { */
/* flex-grow: 1 !important; */
/* } */
</style>
{/if}

View file

@ -0,0 +1,64 @@
<script lang="ts">
import { onMount } from "svelte";
let scrollY = 0;
const animateInterval = 16;
const startMove = 64;
const numFrames = 312;
let framesLoaded = 1;
let ballsLoaded = 0;
let frameLoader: HTMLImageElement;
let frameLoader2: HTMLImageElement;
let frameLoader3: HTMLImageElement;
let frameLoader4: HTMLImageElement;
onMount(()=>{
// Force load once
ballsLoaded = 4;
onLoaded();
});
function onLoaded (){
ballsLoaded++;
if (ballsLoaded > 3) {
frameLoader.src = "/images/spinning_cat/untitled_" + framesLoaded.toString().padStart(5, '0') + ".png";
framesLoaded++;
frameLoader2.src = "/images/spinning_cat/untitled_" + framesLoaded.toString().padStart(5, '0') + ".png";
framesLoaded++;
frameLoader3.src = "/images/spinning_cat/untitled_" + framesLoaded.toString().padStart(5, '0') + ".png";
framesLoaded++;
frameLoader4.src = "/images/spinning_cat/untitled_" + framesLoaded.toString().padStart(5, '0') + ".png";
framesLoaded++;
ballsLoaded = 0;
}
}
let frameIndex = 0;
$: frameIndex = Math.min(Math.floor(Math.max(scrollY-startMove, 0) / animateInterval+1), numFrames);
</script>
<svelte:window bind:scrollY />
<div class="w-full flex justify-center" style="height: 5000px;">
<!-- Image Loader -->
<img on:load={()=>{onLoaded()}} bind:this={frameLoader} style="height: 0.01px; width: 0.01px;" class="" src="/images/spinning_cat/untitled_00001.png" alt="">
<img on:load={()=>{onLoaded()}} bind:this={frameLoader2} style="height: 0.01px; width: 0.01px;" class="" src="/images/spinning_cat/untitled_00001.png" alt="">
<img on:load={()=>{onLoaded()}} bind:this={frameLoader3} style="height: 0.01px; width: 0.01px;" class="" src="/images/spinning_cat/untitled_00001.png" alt="">
<img on:load={()=>{onLoaded()}} bind:this={frameLoader4} style="height: 0.01px; width: 0.01px;" class="" src="/images/spinning_cat/untitled_00001.png" alt="">
<!-- add "top-0" so it sticks at the top -->
<div class="sticky top-0" style="width: 200px; height: 200px;">
<div class="flex justify-center items-center" style="width: 200px; height: 200px;">
<img src="/images/spinning_cat/untitled_{frameIndex.toString().padStart(5, '0')}.png" class="object-contain w-full h-full" alt="">
</div>
<div>{frameIndex}</div>
</div>
</div>
<div class="h-[1000px] bg-amber-700 w-full">
</div>

View file

@ -0,0 +1,133 @@
<script lang="ts">
import { onMount } from "svelte";
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,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,67 @@
<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;
// Shit code but who cares, if it works /shrug
</script>
<div class="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={name} tags={tags} isMobile={isMobile}/>
<slot/>
<MobileTags tags={tags} isMobile={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={tags} isMobile={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={tags} isMobile={isMobile}/>
</div>
</div>
{/if}
</div>
<style>
.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

@ -1,10 +1,6 @@
<script lang="ts">
import { onMount } from "svelte";
import { Vector2 } from "./../Utils/Vector2";
import TopNameTextPlate from "./TopNameTextPlate.svelte";
//import { throttle } from "./../Utils/Throttle";
import { Parallax, ParallaxLayer, StickyLayer } from "svelte-parallax";
import { Vector2 } from "../zhen/Utils/Vector2";
// Params
let mouseMoveScale: number = 0.25;
@ -113,32 +109,8 @@
<svelte:window on:mousemove={onMouseMoved} />
<ParallaxLayer class="StartPageContainer" rate={0.25} offset={0} span={0}>
<div
class="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>
</ParallaxLayer>
<ParallaxLayer rate={0} offset={0.25} span={0}>
<TopNameTextPlate />
</ParallaxLayer>
<!-- <div class="StartPageContainer">
<div class="TopOverlay">
<TopNameTextPlate/>
</div>
<div
class="StartPageAnimated"
<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);"
@ -153,10 +125,6 @@
>
{/each}
</div>
</div> -->
<div id="DummyDiv" class="FirefoxSmoothTranition StartPageContainer TopOverlay" style="display: none !important;" />
<style>
.StartPageContainer {
/* height: 40vh; */
@ -173,20 +141,10 @@
}
.StartPageAnimated {
/* background: url("https://i1.adis.ws/i/canon/future_of_forests_header_16x9_dc14bbe1e35040f79bf566eedaf5c8f7?$hero-header-half-16by9-dt$"); */
background-color: #131313;
position: absolute;
height: 150vh;
width: 150vw;
padding: 0;
transition: transform 1000ms cubic-bezier(0.16, 1.63, 0.01, 0.99);
-moz-transition: none;
left: -25vw;
top: -50vh;
justify-content: center;
vertical-align: middle;
display: flex;
@ -214,15 +172,6 @@
color: rgb(66, 66, 66);
}
.TopOverlay {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
padding: 0;
}
.rotate45 {
transform: rotate(-45deg); /* Rotate the element by 45 degrees */
}

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,258 @@
<script lang="ts">
import svelteLogo from "$lib/svelteLogos/svelte-logo.png";
import { browser } from "$app/environment";
import { onDestroy, onMount } from "svelte";
import { ArrowBigDown } from "lucide-svelte";
import { fly } from "svelte/transition";
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);
}
// Out animation:
function flyInFromTop(
node: HTMLElement,
{
y = -window.innerHeight,
duration = 400,
opacity = 0,
}: { y?: number; duration?: number; opacity?: number } = {},
) {
const {
delay = 0,
duration: d,
easing = (t) => t,
css,
} = fly(node, { y, duration: d, opacity });
let start: number;
function step(now: number) {
if (!start) start = now;
const elapsed = now - start - delay;
if (elapsed < 0) return requestAnimationFrame(step);
const t = Math.min(elapsed / d, 1);
if (css) node.style.cssText = css(easing(t), 1 - easing(t));
if (elapsed < d) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
onMount(() => {
return; // Fuck this, I'm too lazy to fix this atm
totalScroll = document.documentElement.scrollHeight - window.innerHeight;
unscrollInterval = setInterval(() => {
// Prevents scroll to bottom on first try
if (
!notFirstScroll &&
scrollY > totalScroll - unscrollScrollDiv.scrollHeight
) {
smoothScrollTo(totalScroll - unscrollScrollDiv.scrollHeight * 1.1, 0);
// Allow further scroll after delay
setTimeout(() => {
notFirstScroll = true;
}, 1000);
}
// console.log("Time with delay: " + (Date.now() - -unscrollDelay) + " Other " + lastScrollTime);
// console.log(isBeingTouched);
if (
!notFirstScroll ||
isBeingTouched ||
Date.now() < lastScrollTime - -unscrollDelay
) {
// console.log("nah");
return;
}
if (totalScroll - unscrollScrollDiv.scrollHeight < scrollY) {
smoothScrollTo(totalScroll - unscrollScrollDiv.scrollHeight, 200);
}
if (totalScroll <= scrollY) {
console.log("Hit!");
// isLeavingAnimating = true;
flyInFromTop(tranisitionOverlay, { duration: 800 });
}
}, 10);
});
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">
<!-- Keep scrolling thing -->
<div class="hidden h-64 w-full flex flex-col justify-center items-center">
<div>Keep scrolling to veiw Zhen's portfolio site!</div>
<div class="flex justify-center">
<ArrowBigDown />
<ArrowBigDown />
<ArrowBigDown />
<ArrowBigDown />
</div>
</div>
<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 mt-8"
>
<div class="flex justify-center">
<div class="grid gap-8 sm:grid-cols-3 items-center w-full">
<div class="flex flex-col items-center">
<span class="font-bold">© 2023-2025</span>
<br />
<span>Benjamin Dreyer</span>
<br />
<span>Oliver Schwenger</span>
<br />
<span>Sylvester Junge</span>
<br />
<span>Snorre Ettrup Altschul</span>
<br />
<span>Zhentao Wei</span>
</div>
<div class="flex flex-col items-center">
<h3><b>About this website</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:zhen@deprived.dev">zhen@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} -->

View file

@ -0,0 +1,53 @@
<script>
import A4 from "../zhen/notes/physics/sharedComps/A4.svelte";
import ToolButton from "./comps/ToolButton.svelte";
import { BatteryMedium } from '@lucide/svelte';
</script>
<div class="flex justify-center pt-10">
<A4
bottomBorder={false}
bgColor={"rounded-lg bg-base-300"}
class="cozette text-base-content h-full"
>
<div class="p-4 flex flex-col h-full">
<h1 class="text-5xl font-bold">Tools (NOT FINISHED. come back in the future.)</h1>
<span class="w-full text-xl"
>These are the tools collected from different places of the
internet</span
>
<!-- Spacing -->
<div class="pt-14"></div>
<div class="p-4 bg-base-200 rounded-lg">
<h2 class="text-2xl font-bolc">MPUs/SoCs</h2>
<span>Whatever acronym you want lol</span>
<div class="grid grid-cols-3 gap-4">
<ToolButton
title="Sleeping battery life"
desc="Calculates the battery life depending on sleep and non-sleep power usage."
btnText="To calculator"
toolIcon={BatteryMedium}
/>
<!-- <ToolButton
title="Sleeping battery life"
desc="Calculates the battery life depending on sleep and non-sleep power usage."
btnText="To calculator"
toolIcon={BatteryMedium}
/>
<ToolButton
title="Sleeping battery life"
desc="Calculates the battery life depending on sleep and non-sleep power usage."
btnText="To calculator"
toolIcon={BatteryMedium}
/> -->
</div>
</div>
<div class="mt-auto align-text-bottom">
I if you have tool suggestions, then either create an issue, create a pull request, or send an email. I probably wont add it though, since this is free work lol.
</div>
</div>
</A4>
</div>

View file

@ -0,0 +1,183 @@
<script lang="ts">
import A4 from "../../zhen/notes/physics/sharedComps/A4.svelte";
import { BatteryLifeCalculator } from "./pageSrc/BatteryCalc";
import { getMCU, type MCU_Type } from "./pageSrc/MCU_defs";
// let mathMachine = new BatteryLifeCalculator();
let useCustom: boolean = false;
let selectedText: string = "";
let selectedMcu: MCU_Type | undefined = undefined;
$: selectedMcu = getMCU(selectedText)
const options = ["esp32-s3", "esp32-s3"];
</script>
<div class="flex justify-center pt-10">
<A4
bottomBorder={false}
bgColor={"rounded-lg bg-base-300"}
class="cozette text-base-content h-full"
>
<div class="p-4 flex flex-col h-full">
<h1 class="text-5xl font-bold">Battery life calculator</h1>
<span class="w-full text-xl">
Calculates the time a battery will last. Too lazy to explain
more.
</span>
<!-- Spacing -->
<div class="pt-14"></div>
<div class="p-4 bg-base-200 rounded-lg">
<h2 class="text-2xl font-bolc">Software</h2>
<div class="grid grid-cols-2 gap-4">
<div class="form-control">
<span class="text-sm text-slate-300 text-opacity-60"
>Duration of code execution</span
>
<div class="join">
<input
type="number"
class="input input-bordered input-sm join-item appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
/>
<div
class="bg-base-content bg-opacity-60 join-item grid place-content-center"
>
<span class="text-center pl-1 pr-2">sec</span>
</div>
</div>
</div>
<div class="form-control">
<span class="text-sm text-slate-300 text-opacity-60"
>sleep time</span
>
<div class="join">
<input
type="number"
class="input input-bordered input-sm join-item appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
/>
<div
class="bg-base-content bg-opacity-60 join-item grid place-content-center"
>
<span class="text-center pl-1 pr-2">sec</span>
</div>
</div>
</div>
<div class="col-span-full">
<h2 class=" text-2xl font-bolc">Hardware</h2>
<div class="flex">
<div
class="text-sm text-slate-300 text-opacity-60 text"
>
Use custom values
</div>
<input
bind:checked={useCustom}
class="ml-2 checkbox checkbox-xs my-auto"
type="checkbox"
/>
</div>
</div>
{#if !useCustom}
<div>
<select
bind:value={selectedText}
class="select select-sm select-bordered w-56 max-w-xs"
>
<option disabled value="">Select a text</option>
{#each options as option}
<option value={option}>{option}</option>
{/each}
</select>
{#if selectedMcu != undefined && selectedMcu?.wifi != undefined}
<p class="mt-4 text-lg">
wifi
</p>
{/if}
{#if selectedMcu != undefined && selectedMcu?.wifi != undefined}
<p class="mt-4 text-lg">
ble
</p>
{/if}
</div>
{:else}
<div class="form-control">
<span class="text-sm text-slate-300 text-opacity-60"
>Duration of code execution</span
>
<div class="join">
<input
type="number"
class="input input-bordered input-sm join-item appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
/>
<div
class="bg-base-content bg-opacity-60 join-item grid place-content-center"
>
<span class="text-center pl-1 pr-2"
>sec</span
>
</div>
</div>
</div>
<div class="form-control">
<span class="text-sm text-slate-300 text-opacity-60"
>sleep time</span
>
<div class="join">
<input
type="number"
class="input input-bordered input-sm join-item appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
/>
<div
class="bg-base-content bg-opacity-60 join-item grid place-content-center"
>
<span class="text-center pl-1 pr-2"
>sec</span
>
</div>
</div>
</div>
{/if}
</div>
</div>
<div class="mt-auto align-text-bottom text-center">
Source for the calculations is at this
<a
class="text-blue-500 underline"
target="_blank"
href="https://github.com/simonneutert/batterylife-calculator"
>github</a
>
and the
<a
class="text-blue-500 underline"
target="_blank "
href="https://www.of-things.de/battery-life-calculator.php"
>original website.</a
>
I just mearly made additions.
</div>
</div>
</A4>
</div>
<style>
/* Hide the spinner for Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Hide the spinner for Firefox */
input[type="number"] {
-moz-appearance: textfield;
}
</style>

View file

@ -0,0 +1,123 @@
export class BatteryLifeCalculator {
timeRunSeconds: number;
timeSleepSeconds: number;
consumptionActiveMilliAmpHours: number;
consumptionSleepMilliAmpHours: number;
powerBatteryTotalMilliAmpHours: number;
powerBatteryBufferBeforeEmptyPercent: number;
constructor(
timeRunSeconds: number,
timeSleepSeconds: number,
consumptionActiveMilliAmpHours: number,
consumptionSleepMilliAmpHours: number,
powerBatteryTotalMilliAmpHours: number,
powerBatteryBufferBeforeEmptyPercent: number = 20
) {
this.timeRunSeconds = timeRunSeconds;
this.timeSleepSeconds = timeSleepSeconds;
this.consumptionActiveMilliAmpHours = consumptionActiveMilliAmpHours;
this.consumptionSleepMilliAmpHours = consumptionSleepMilliAmpHours;
this.powerBatteryTotalMilliAmpHours = powerBatteryTotalMilliAmpHours;
this.powerBatteryBufferBeforeEmptyPercent = powerBatteryBufferBeforeEmptyPercent;
console.log(
"The source of this battery calc is here: https://github.com/simonneutert/batterylife-calculator\nI was too lazy to make the math myself."
);
}
// public API
milliAmpToMicroAmp(milliAmps: number): number {
return milliAmps * 1000;
}
microAmpToMilliAmp(milliAmps: number): number {
return milliAmps * 0.001;
}
calculate(): {
powerAveragePerHour: number;
runtimeHoursEstimated: number;
runtimeDaysEstimated: number;
runtimeDaysRemainingHoursEstimated: number;
} {
return {
powerAveragePerHour: this.powerEstimatedHourly(),
runtimeHoursEstimated: this.runtimeHoursEstimated(),
runtimeDaysEstimated: this.runtimeDaysEstimated(),
runtimeDaysRemainingHoursEstimated: this.runtimeDaysRemainingHoursEstimated(),
};
}
powerEstimatedHourly(): number {
return this.calcPowerEst(
this.powerRun(),
this.consumptionActiveMilliAmpHours,
this.powerSleep(),
this.consumptionSleepMilliAmpHours
);
}
runtimeHoursEstimated(): number {
return parseInt((this.powerLipo() / this.powerEstimatedHourly()).toString(), 10);
}
runtimeDaysEstimated(): number {
return parseInt((this.runtimeHoursEstimated() / 24).toString(), 10);
}
runtimeDaysRemainingHoursEstimated(): number {
return parseInt((this.runtimeHoursEstimated() % 24).toString(), 10);
}
// private methods
private roundOff(x: number): number {
return Math.round(x * 100.0) / 100.0;
}
private calcPowerLipo(x: number, y: number): number {
return parseFloat(((x * (100 - y)) / 100).toString());
}
private calcRuns(x: number, y: number): number {
return parseFloat((60 / (x + y)).toString());
}
private calcRunsHour(x: number, y: number): number {
return parseFloat((3600 / (x + y)).toString());
}
private calcPowerRun(x: number, y: number): number {
return parseFloat(((x / (x + y)) * 3600).toString());
}
private calcPowerSleep(x: number, y: number): number {
return parseFloat(((y / (x + y)) * 3600).toString());
}
powerLipo(): number {
return this.calcPowerLipo(this.powerBatteryTotalMilliAmpHours, this.powerBatteryBufferBeforeEmptyPercent);
}
runs(): number {
return this.calcRuns(this.timeRunSeconds, this.timeSleepSeconds);
}
runsHour(): number {
return this.calcRunsHour(this.timeRunSeconds, this.timeSleepSeconds);
}
powerRun(): number {
return this.calcPowerRun(this.timeRunSeconds, this.timeSleepSeconds);
}
powerSleep(): number {
return this.calcPowerSleep(this.timeRunSeconds, this.timeSleepSeconds);
}
private calcPowerEst(a: number, b: number, c: number, d: number): number {
return parseFloat(((a / 3600) * b + (c / 3600) * d).toString());
}
}

View file

@ -0,0 +1,63 @@
export interface MCU_Type {
name: string;
cpu: { [key: string]: Number }; // state: power consumption
sleep: { [key: string]: Number };
wifi?: { [key: string]: Number };
bluetooth?: { [key: string]: Number };
}
const MCUs: MCU_Type[] = [
{
name: "esp32-s3",
cpu: { // mili amps
single_core_40MHz: 21.8,
dual_core_40MHz: 24.4,
single_core_80MHz: 42.6,
dual_core_80MHz: 47.3,
single_core_160MHz: 54.6,
dual_core_160MHz: 54.1,
single_core_240MHz: 65.9,
dual_core_240MHz: 81.3,
},
sleep: {
},
wifi: { //
dBm_21: 318.2,
sleep: 10
},
bluetooth: {
active: 100,
sleep: 5
}
},
{
name: "esp32-c3",
cpu: {
single_core_80MHz: 22,
single_core_160MHz: 54.6,
},
sleep: {
},
wifi: {
active: 110,
sleep: 9
},
bluetooth: {
active: 90,
sleep: 4
}
}
];
export function getMCU(name: string): MCU_Type | undefined{
for (let i = 0; i < MCUs.length; i++) {
const element = MCUs[i];
if (element.name == name)
return element
}
return undefined;
}

View file

@ -0,0 +1,27 @@
<script lang="ts">
import type { Component } from 'svelte';
export let toolIcon: Component | undefined = undefined;
export let title: string = "Sleeping battery life";
export let desc: string = "Calculates the battery life depending on sleep and non-sleep power usage.";
export let btnText: string = "To calculator";
export let btnHref: string = "/tools/battery-life-calculator";
</script>
<div class="min-w-10 min-h-10 bg-base-100 rounded-lg">
<div class="p-4">
<div class="flex">
<div class="font-bold text-xl">{title}</div>
</div>
<div class="text-sm">{desc}</div>
<div class="flex pt-4">
{#if toolIcon != undefined}
<svelte:component this={toolIcon}/>
{/if}
<a href="{btnHref}" class="btn ml-auto btn-primary btn-sm">{btnText}</a>
</div>
</div>
</div>

View file

@ -1,17 +0,0 @@
<script lang="ts">
import TopAnimatedBackground from "./Comps/TopAnimatedBackground.svelte";
import { Parallax, ParallaxLayer, StickyLayer } from "svelte-parallax";
import ZhenInformatikTimeline from "./Comps/ZhenInformatikTimeline.svelte"
import AboutMe from "./Comps/AboutMe.svelte"
</script>
<Parallax sections={3} config={{ stiffness: 0.1, damping: 0.3 }}>
<TopAnimatedBackground/>
<ParallaxLayer rate={0.5} offset={0.5} style="background-color: var(--background);">
<AboutMe/>
</ParallaxLayer>
<ParallaxLayer rate={0.5} offset={0.8} style="background-color: var(--background);">
<ZhenInformatikTimeline/>
</ParallaxLayer>
</Parallax>

View file

@ -1,21 +0,0 @@
export function throttle(callback, wait) {
let timeoutId = null;
let lastExecutedTime = 0;
return function (...args) {
const currentTime = Date.now();
const execute = () => {
lastExecutedTime = currentTime;
callback.apply(this, args);
};
if (currentTime - lastExecutedTime >= wait) {
execute();
} else {
clearTimeout(timeoutId);
timeoutId = setTimeout(execute, wait - (currentTime - lastExecutedTime));
}
};
}

View file

@ -7,15 +7,15 @@ export class Vector2 {
this.y = y;
}
Add(vec2: Vector2){
Add(vec2: Vector2) {
return new Vector2(this.x + vec2.x, this.y + vec2.y);
}
Sub(vec2: Vector2){
Sub(vec2: Vector2) {
return new Vector2(this.x - vec2.x, this.y - vec2.y);
}
Scale(mult: number){
Scale(mult: number) {
return new Vector2(this.x * mult, this.y * mult);;
}
}

View file

@ -2,19 +2,16 @@
export let Style = "";
</script>
<div class="container" style="{Style}">
<div/>
<div>
<div>
Thank you! ❤
</div>
<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(40.2mm, 5mm) rotate(-45deg);
transform: translate(20.3mm, -5mm) rotate(-45deg);
display: grid;
justify-self: end;
vertical-align: bottom;
@ -26,7 +23,11 @@
padding-top: 5mm;
//border-bottom: #4472c4 dashed 2mm;
background-image: linear-gradient(to right, #4472c4 70%, rgba(255,255,255,0) 0%);
background-image: linear-gradient(
to right,
#4472c4 70%,
rgba(255, 255, 255, 0) 0%
);
background-position: top;
background-size: 6mm 1.5mm;
background-repeat: repeat-x;
@ -49,3 +50,4 @@
}
}
</style>

View file

@ -53,11 +53,4 @@
width: 100%;
}
}
.imagesContainer {
> img {
border-radius: 5mm;
filter: drop-shadow(1mm 1mm 1mm #0000009d);
}
}
</style>

View file

@ -5,12 +5,10 @@
<div class="container">
<div>
This CV was made using html, css and <a class="grid place-content-center" href="https://kit.svelte.dev/"><img src={svelteLogo} alt="SvelteKit logo"/></a>
</div>
<div>
Sources:
<a href="https://gitea.deprived.dev/Sveskejuice/deprived-main-website/src/branch/dev/src/routes/zhen/cv/rev2/+page.svelte">CV source code</a>
and
<a href="https://dev.deprived.dev/zhen/cv/rev1?hideOnPrint=1">My Website</a>
<a href="/zhen/cv/rev2?hideOnPrint=1">My Website</a>
</div>
</div>
@ -19,6 +17,8 @@
z-index: 1;
padding-left: 2mm;
font-size: 0.75rem;
//white-space: nowrap;
color: #777777;

View file

@ -5,7 +5,7 @@
</b>
</div>
<div>
◾ "Artificial intelligence and data" student at DTU.
◾ "AI and data" at DTU. <br>
◾ Working at <a class="underline" href="https://grazper.com/">GrazperAI</a> <br/>
◾ Volunteer at Kildevæld Makerspace.
</div>

View file

@ -19,7 +19,7 @@
</div>
<div class="table-item">
<div>Open-source help</div>
<div>Have contributed in multiple Open-source project on github</div>
<div>Contributed in multiple Open-source projects on github</div>
</div>
<div class="table-item">
<div>PCB designing</div>

View file

@ -0,0 +1,23 @@
<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: #e4e4e4;
transform: translate(32%, -32%) rotate(-90deg);
}
</style>

View file

@ -0,0 +1,27 @@
<div class="short-profile-container">
<div>
<b style="text-align:left;">
Biggest flex
</b>
</div>
<div>
Me and my small group of devs has won each and every gamejam, which we have participated in. <br/>
<h1 style="font-size: 0.75rem; color: grey;">*Gamejams that had competitions.</h1>
</div>
</div>
<style>
.short-profile-container{
display: grid;
place-items: center;
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,
#4472c4 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: #2f5496;
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,76 @@
<div class="container">
<div>
<b style="text-align:left;">
Contact
</b>
</div>
<div class="table-display">
<div class="table-item">
<div>Email</div>
<div>Zhen@deprived.dev</div>
</div>
<div class="table-item">
<div>Phone</div>
<div>+45 42535723</div>
</div>
<div class="table-item">
<div>LinkedIn</div>
<a href="https://www.linkedin.com/in/zhentao-wei-3a3a0a182/">Zhentao-Wei</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 black;
}
.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 {
color: #000000;
&: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,47 @@
<script>
import placeholder from "$lib/zhen/cv-comps/400x400.png";
import DTU_Logo from "$lib/zhen/cv-comps/DTU_Logo.png";
import NextLogo from "$lib/zhen/cv-comps/nextKbhLogo.png";
import SasLogo from "$lib/zhen/cv-comps/SASLogo.png";
import EmphasysLogo from "$lib/zhen/cv-comps/EmphasysLogo.png";
import IconAndText2 from "./IconAndText2.svelte";
</script>
<div class="container">
<div>
<b style="text-align:left;"> Education </b>
</div>
<div class="imagesContainer flex justify-center p-2 gap-4" id="balls">
<IconAndText2 logo={DTU_Logo}>
<b>DTU</b><br />
<p style="font-size: 0.5rem;">Artificial intelligence</p>
</IconAndText2>
<IconAndText2 logo={NextLogo}>
<b>Next</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={EmphasysLogo}>
<b>Emphasys center</b><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,78 @@
<script>
import placeholder from "$lib/zhen/cv-comps/400x400.png";
import MakerspaceLogo from "$lib/zhen/cv-comps/MakerspaceLogo.png";
import EposLogo from "$lib/zhen/cv-comps/EposLogo.png";
import KhoraLogo from "$lib/zhen/cv-comps/KhoraLogo.jpg";
import GrazperAILogo from "$lib/zhen/cv-comps/GrazperLogo.jpg";
import YaaummaLogo from "$lib/zhen/cv-comps/YaaummaLogo.png";
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={YaaummaLogo}>
<b>Full-stack</b><br />
Yaaumma<br />
<i>Feb 2025 - Now</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={GrazperAILogo}>
<b>Data annotator</b><br />
GrazperAI<br />
<i>Jul 2024 - Now</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={MakerspaceLogo}>
<b>3D printer manager</b> - Volunteer<br />
Makerspace - kildevæld Kulturcenter<br />
<i>Nov 2023 - Now</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={EposLogo}>
<b>Machine Learning Engineer</b> - Short term intern<br />
Product design department - Epos<br />
<i>Apr 2024 - Apr 2024</i>
</IconAndText>
</div>
<div class="table-item">
<IconAndText logo={KhoraLogo}>
<b>Assistant</b> - Short term intern<br />
Khora Virtual Reality<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,47 @@
<script lang="ts">
export let logo: string;
export let logoWidths: string = "10%";
export let fontSize: string = "3mm";
export let lineHeight: string = "3.1mm";
import { onMount } from "svelte";
onMount(() => {
imageCaption = logo.split(/(\\|\/)/g).pop();
});
let imageCaption: undefined | string; // Not a high piority, you get the file name and thats it
</script>
<div class="container">
<img
src={logo}
class="bg-white w-10 h-10 object-contain"
alt={imageCaption}
width={logoWidths}
/>
<div style="line-height: {lineHeight};">
<span style="font-size: {fontSize};">
<slot />
</span>
</div>
</div>
<style lang="scss">
.container {
display: flex;
justify-items: start;
& > div {
padding-left: 3mm;
text-align: start;
}
& > img {
border-radius: 2.5mm;
filter: drop-shadow(1mm 1mm 1mm #0000009d);
}
}
</style>

View file

@ -0,0 +1,46 @@
<script lang="ts">
export let logo: string;
export let logoWidths: string = "35%";
export let fontSize: string = "3mm";
export let lineHeight: string = "3.1mm";
import { onMount } from "svelte";
onMount(() => {
imageCaption = logo.split(/(\\|\/)/g).pop();
});
let imageCaption: undefined | string; // Not a high piority, you get the file name and thats it
</script>
<div class="container flex">
<img
src={logo}
class="mr-2 w-6 h-6 object-contain"
alt={imageCaption}
width={logoWidths}
/>
<div style="line-height: {lineHeight};">
<span class="inline" style="font-size: {fontSize};">
<slot />
</span>
</div>
</div>
<style lang="scss">
.container {
width: 100%;
& > div {
text-align: start;
border-left: 0.5mm solid black;
}
& > img {
border-radius: 2.5mm;
filter: drop-shadow(1mm 1mm 1mm #0000009d);
}
}
</style>

View file

@ -0,0 +1,53 @@
<script>
import RepeatedSkills from "./RepeatedSkills.svelte";
export let Style = "";
</script>
<div class="container" style="{Style}">
<div>
<RepeatedSkills textOverride={["Hello", "你好", "Hej"]} targetTextHeight={4} targetTextWidth={50} applyRotation={false}/>
</div>
<div/>
</div>
<style lang="scss">
.container {
position: absolute;
transform: translate(-25mm, 0mm) rotate(-45deg);
display: grid;
justify-self: start;
vertical-align: top;
align-self: flex-start;
z-index: 0;
> div:nth-child(1) {
//background-color: #2f559622;
width: 100mm;
height: 17.5mm;
padding-bottom: 1mm;
// Text inside
display: grid;
place-content: center;
border-bottom: #4472c4 dotted 0.5mm;
&:first-child {
color: #4472c4;
font-size: 3mm;
//font-weight: bold;
}
}
> div:nth-child(2) {
padding-top: 4mm;
//border-bottom: #4472c4 dashed 2mm;
background-image: linear-gradient(to right, #4472c4 70%, rgba(255,255,255,0) 0%);
background-position: bottom;
background-size: 6mm 1.5mm;
background-repeat: repeat-x;
}
}
</style>

View file

@ -0,0 +1,51 @@
<script>
import svelteLogo from "$lib/svelteLogos/svelte-logo-cutout.svg"
</script>
<div class="container">
<div>
This CV was made using html, css and <a class="grid place-content-center" href="https://kit.svelte.dev/"><img src={svelteLogo} alt="SvelteKit logo"/></a>
Sources:
<a href="https://gitea.deprived.dev/Sveskejuice/deprived-main-website/src/branch/dev/src/routes/zhen/cv/rev2/+page.svelte">CV source code</a>
and
<a href="/zhen/cv/rev2?hideOnPrint=1">My Website</a>
</div>
</div>
<style lang="scss">
.container {
z-index: 1;
padding-left: 2mm;
font-size: 0.75rem;
//white-space: nowrap;
color: #777777;
* a {
color: #3d6ddc;
padding-left: 1mm;
padding-right: 1mm;
text-decoration: underline;
}
div:first-child {
display: flex;
place-content: center;
justify-content: start;
a:nth-child(1) > img {
width: 5mm;
padding-left: 1mm;
padding-right: 1mm;
}
}
div:nth-child(2){
padding-bottom: 2mm;
}
}
</style>

View file

@ -0,0 +1,24 @@
<script>
import QRCode from "$lib/zhen/cv-comps/LinkedInQrCode.svg?raw"
</script>
<div class="container">
<div>LinkedIn</div>
<span class="qrcode">{@html QRCode}</span>
</div>
<style lang="scss">
.qrcode {
transform: scale(0.9);
}
.container {
display: grid;
place-items: center;
& * {
font-size: 7.5mm;
}
}
</style>

View file

@ -0,0 +1,26 @@
<script lang="ts">
import NamePlate from "./NamePlate.svelte";
import selfie from "$lib/zhen/cv-comps/VRNerd.jpg"
import zylveterSus from "$lib/zhen/cv-comps/zylveterSus.png"
</script>
<div class="nameAndImageContainer">
<NamePlate/>
<div class="mt-4 w-48 h-48 overflow-hidden shadow-xl rounded-lg flex justify-center items-center">
<img src={selfie} class="selfie-constraints object-cover" alt="Zhentao Wei"/>
</div>
</div>
<style>
.nameAndImageContainer {
display: grid;
place-items: center;
}
.selfie-constraints{
max-width: 100%;
}
</style>

View file

@ -0,0 +1,21 @@
<div class="name-plate-container">
<span style="text-align: center;">
<b>
Zhentao Wei
</b><br/>
(He/Him)
</span>
</div>
<style>
.name-plate-container{
display: grid;
place-items: center;
width: 60%;
/* Bottom border stripe*/
border-bottom: 1mm solid black;
}
</style>

View file

@ -0,0 +1,71 @@
<div class="container">
<div>
<b style="text-align:left;">
Other
</b>
</div>
<div class="table-display">
<div class="table-item">
<div>Itch.io</div>
<a href="https://github.com/MagicBOTAlex">botalex.itch.io</a>
</div>
<div class="table-item">
<div>Github</div>
<a href="https://botalex.itch.io/">@MagicBOTAlex</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 black;
}
.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 {
color: #000000;
&: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,31 @@
<div class="short-profile-container">
<div>
<b style="text-align:left;">
About me
</b>
</div>
<div>
I'm a 20-year-old with a deep passion for programming and
technology.
Most of my knowledge is self-taught from many places on the
internet, so university hasn't helped much. I encourage you to browse my LinkedIn, since I
periodically post my hobby projects on there, and my skills are
described further in depth.
</div>
</div>
<style>
.short-profile-container{
display: grid;
place-items: center;
width: 90%;
}
.short-profile-container > div:first-child {
width: 100%;
/* Bottom border stripe*/
border-bottom: 1mm solid black;
}
</style>

View file

@ -0,0 +1,62 @@
<script lang="ts">
// Width of num chars and height nom of chars
export let targetTextWidth: number;
export let targetTextHeight: number;
export let applyRotation: boolean = true;
export let textOverride: string[] | undefined = undefined;
// Assign default value if textOverride is undefined
let repeatingText : string[] = textOverride ?? [
"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 < targetTextWidth) {
outString +=
repeatingText[
getRandomInt(repeatingText.length)
] + " ";
}
return outString; // At about target size
}
</script>
<div {...$$restProps}>
{#each { length: targetTextHeight } as _, i}
<span class="{applyRotation ? "rotate45" : ""} SkillsText">
{GrabRandomString()}
</span>
{/each}
</div>
<style>
.SkillsText {
text-align: start;
display: flex;
justify-content: center;
align-items: center;
white-space: nowrap;
width: 2rem;
}
.rotate45 {
transform: rotate(-45deg);
}
</style>

View file

@ -0,0 +1,28 @@
<div class="short-profile-container">
<div>
<b style="text-align:left;">
Short profile
</b>
</div>
<div>
◾ "AI and data" at DTU. <br>
◾ Working at <a class="underline" href="https://grazper.com/">GrazperAI</a> <br/>
◾ Volunteer at Kildevæld Makerspace.
</div>
</div>
<style>
.short-profile-container{
display: grid;
place-items: center;
width: 70%;
}
.short-profile-container > div:first-child {
width: 100%;
/* Bottom border stripe*/
border-bottom: 1mm solid black;
}
</style>

View file

@ -0,0 +1,88 @@
<div class="container">
<div>
<b style="text-align:left;">
List of big projects
</b>
</div>
<div class="table-display">
<div class="table-item">
<div>Computer vision</div>
<div>Implimented YoloV1 from scratch. (object detection)</div>
</div>
<div class="table-item">
<div>Arduino</div>
<div>Built my own claw machine with 2 dimentions of movement</div>
</div>
<div class="table-item">
<div>App dev</div>
<div>Made an Doulingo'ish app for learning chinese in 9 days</div>
</div>
<div class="table-item">
<div>Open-source help</div>
<div>Contributed in multiple Open-source projects on github</div>
</div>
<div class="table-item">
<div>PCB designing</div>
<div>I am currently designing my own circuit board</div>
</div>
</div>
<div class="flex" style="font-size: 0.75rem; color: sgray; align-content: start; width: 100%;">
<p>
If you want proof or want to know about other projects. Contact me!
</p>
</div>
</div>
<style lang="scss">
.container{
display: grid;
place-items: center;
width: 90%;
}
.container > div:first-child {
width: 100%;
/* Bottom border stripe*/
border-bottom: 1mm solid black;
}
.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 {
color: #000000;
&:first-child {
width: 30%;
font-size: 4mm;
display: grid;
place-content: center start;
border-right: rgba(128, 128, 128, 0.4) dashed 0.1mm;
}
&:nth-child(2) {
width: 70%;
font-size: 3.25mm;
display: grid;
padding-left: 1mm;
}
}
}
</style>

View file

@ -74,7 +74,7 @@
<LinkedInQR/>
</div>
</div>
<div id="leftSectionSeperator"><div/></div>
<div id="leftSectionSeperator"></div>
<div id="right-section">
<AlexWatermark/>
<div id="TopRightSkillsText">

View file

@ -74,7 +74,7 @@
<LinkedInQR/>
</div>
</div>
<div id="leftSectionSeperator"><div/></div>
<div id="leftSectionSeperator"></div>
<div id="right-section">
<AlexWatermark/>
<div id="TopRightSkillsText">

View file

@ -1,8 +1,8 @@
<script lang="ts">
// Left side
import NameAndImage from "../CompsRev2/NameAndImage.svelte";
import ShortProfile from "../CompsRev2/ShortProfile.svelte"
import CombinedContacts from "../CompsRev2/CombinedContacts.svelte"
import ShortProfile from "../CompsRev2/ShortProfile.svelte";
import CombinedContacts from "../CompsRev2/CombinedContacts.svelte";
import LinkedInQR from "../CompsRev2/LinkedInQR.svelte";
// Right side
@ -22,75 +22,89 @@
import LinkToSource from "../CompsRev2/LinkToSource.svelte";
// Discord embed
import preveiwImage from "$lib/zhen/cv-comps/EposCvPreveiw.png"
import preveiwImage from "$lib/zhen/cv-comps/EposCvPreveiw.png";
// Print detection setup
import { onMount } from "svelte";
onMount(() => {
// Check if the query parameter exists in the URL
const urlParams = new URLSearchParams(window.location.search);
const hideOnPrintParam = urlParams.get('hideOnPrint');
const hideOnPrintParam = urlParams.get("hideOnPrint");
// If the query parameter is not detected, reload the page with the parameter added
if (!hideOnPrintParam) {
window.location.href = `${window.location.href}?hideOnPrint=1`;
}
});
})
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 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>
<title>Zhentao Wei's CV {getFormattedDate()}</title>
<meta content="Zhentao Wei's Epos CV" property="og:title" />
<meta content="This CV is made completely with html + css + js" property="og:description" />
<meta content="Zhentao Wei'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 hide-on-print">
<div>
Under here is my CV rev1 for an application made entirely in HTML and CSS. The page is designed to be saved as PDF.
This can be done by pressing <div class="keyboard-key">P</div> + <div class="keyboard-key">CTRL</div>, then set scaling to 100% and no margins. Lastly, select save to PDF or print.
<br/>
<br/>
I have to sadly recommend chrome for this process. Firefox somehow messes with the quality of the PDF :(
Under here is my CV rev1 for an application made entirely in HTML and CSS.
The page is designed to be saved as PDF. This can be done by pressing <div
class="keyboard-key"
>
P
</div>
+
<div class="keyboard-key">CTRL</div>
, then set scaling to 100% and no margins. Lastly, select save to PDF or print.
<br />
<br />
I have to sadly recommend chrome for this process. Firefox somehow messes with
the quality of the PDF :(
</div>
</div>
<div class="cv-container-container include-in-print">
<div class="NotoSans cv-container-container include-in-print">
<div class="cv-container sections decorations">
<div id="left-section">
<LeftTopDecor Style="pointer-events: none;"/>
<BottomRightDecor Style="pointer-events: none;"/>
<LeftTopDecor Style="pointer-events: none;" />
<BottomRightDecor Style="pointer-events: none;" />
<div>
<NameAndImage/>
<ShortProfile/>
<CombinedContacts/>
<LinkedInQR/>
<NameAndImage />
<ShortProfile />
<CombinedContacts />
<LinkedInQR />
</div>
</div>
<div id="leftSectionSeperator"><div/></div>
<div id="leftSectionSeperator"></div>
<div id="right-section">
<AlexWatermark Style="pointer-events: none;"/>
<AlexWatermark Style="pointer-events: none;" />
<div id="TopRightSkillsText">
<RepeatedSkills targetTextHeight={30} targetTextWidth={75}/>
<RepeatedSkills
class="Cozette"
targetTextHeight={30}
targetTextWidth={75}
/>
</div>
<div id="Credit">
<LinkToSource/>
<LinkToSource />
</div>
<div>
<Profile/>
<BiggestFlex/>
<TableOfProjects/>
<Experience/>
<Education/>
<BiggestFlex />
<TableOfProjects />
<Experience />
<Education />
</div>
</div>
</div>
@ -120,13 +134,7 @@
}
}
@media print {
.hide-on-print {
display: none;
}
}
.cv-container-container{
.cv-container-container {
width: 100%;
height: 100%;
@ -149,11 +157,6 @@
padding: auto;
}
.include-in-print { &, & * {
-webkit-print-color-adjust:exact !important;
print-color-adjust:exact !important;
}}
.sections {
// Shared between sections
> div {
@ -165,7 +168,7 @@
overflow: hidden;
}
#left-section{
#left-section {
background-color: #bdd6ee;
width: calc(100% / 3 * 1);
@ -183,7 +186,7 @@
}
}
#right-section{
#right-section {
width: calc(100% / 3 * 2);
> div:last-child {
@ -200,13 +203,13 @@
padding-bottom: 30mm;
// Disable interactivity for padding
pointer-events:none;
pointer-events: none;
}
}
}
.decorations {
#leftSectionSeperator{
#leftSectionSeperator {
position: relative;
height: 100%;
width: 0%;
@ -238,7 +241,7 @@
mask-image: linear-gradient(180deg, #000 0%, transparent 110%);
color: rgb(190, 190, 190);
font-family: 'CozetteVector';
font-family: "CozetteVector";
font-size: x-large;
}

View file

@ -0,0 +1,260 @@
<script lang="ts">
// Left side
import NameAndImage from "../CompsRev3/NameAndImage.svelte";
import ShortProfile from "../CompsRev3/ShortProfile.svelte";
import CombinedContacts from "../CompsRev3/CombinedContacts.svelte";
import LinkedInQR from "../CompsRev3/LinkedInQR.svelte";
// Right side
import Profile from "../CompsRev3/Profile.svelte";
import Education from "../CompsRev3/Education.svelte";
import Experience from "../CompsRev3/Experience.svelte";
import BiggestFlex from "../CompsRev3/BiggestFlex.svelte";
import TableOfProjects from "../CompsRev3/TableOfProjects.svelte";
// Decorations
import LeftTopDecor from "../CompsRev3/LeftTopDecor.svelte";
import BottomRightDecor from "../CompsRev3/BottomRightDecor.svelte";
import AlexWatermark from "../CompsRev3/AlexWatermark.svelte";
import RepeatedSkills from "../CompsRev3/RepeatedSkills.svelte";
// Cedit
import LinkToSource from "../CompsRev3/LinkToSource.svelte";
// Discord embed
import preveiwImage from "$lib/zhen/cv-comps/EposCvPreveiw.png";
// Print detection setup
import { onMount } from "svelte";
onMount(() => {
// Check if the query parameter exists in the URL
const urlParams = new URLSearchParams(window.location.search);
const hideOnPrintParam = urlParams.get("hideOnPrint");
// If the query parameter is not detected, reload the page with the parameter added
if (!hideOnPrintParam) {
window.location.href = `${window.location.href}?hideOnPrint=1`;
}
});
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>
<title>Zhentao Wei's CV {getFormattedDate()}</title>
<meta content="Zhentao Wei'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 hide-on-print">
<div>
Under here is my CV rev1 for an application made entirely in HTML and CSS.
The page is designed to be saved as PDF. This can be done by pressing <div
class="keyboard-key"
>
P
</div>
+
<div class="keyboard-key">CTRL</div>
, then set scaling to 100% and no margins. Lastly, select save to PDF or print.
<br />
<br />
I have to sadly recommend chrome for this process. Firefox somehow messes with
the quality of the PDF :(
</div>
</div>
<div class="NotoSans cv-container-container include-in-print">
<div class="cv-container sections decorations">
<div id="left-section">
<LeftTopDecor Style="pointer-events: none;" />
<BottomRightDecor Style="pointer-events: none;" />
<div
class="absolute rotate-12 width-[10cm] h-full right-[15cm]"
style="background-color: #bdd6ee"
></div>
<div>
<NameAndImage />
<ShortProfile />
<CombinedContacts />
<LinkedInQR />
</div>
</div>
<div id="leftSectionSeperator"></div>
<div id="right-section">
<AlexWatermark Style="pointer-events: none;" />
<div id="TopRightSkillsText">
<RepeatedSkills
class="Cozette"
targetTextHeight={30}
targetTextWidth={75}
/>
</div>
<div id="Credit">
<LinkToSource />
</div>
<div>
<Profile />
<BiggestFlex />
<TableOfProjects />
<Experience />
<Education />
</div>
</div>
</div>
</div>
<style lang="scss">
.cv-info-container {
height: 40mm;
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;
}
> div {
width: 80%;
height: 60%;
}
}
.cv-container-container {
width: 100%;
height: 100%;
display: grid;
place-items: center;
}
.cv-container-container * {
color: black; // Set all text black
}
.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:last-child {
z-index: 1;
width: 100%;
left: 0;
display: grid;
place-items: center;
padding-top: 30mm;
padding-bottom: 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;
}
#Credit {
position: absolute;
z-index: 0;
display: flex;
align-self: flex-end;
}
}
}
</style>

View file

@ -1,117 +0,0 @@
<script lang="ts">
import RepeatedSkills from "../../cv/Comps/RepeatedSkills.svelte";
// Discord embed
import preveiwImage from "$lib/zhen/cv-comps/EposCvPreveiw.png"
// Print detection setup
import { onMount } from "svelte";
onMount(() => {
// Check if the query parameter exists in the URL
const urlParams = new URLSearchParams(window.location.search);
const hideOnPrintParam = urlParams.get('hideOnPrint');
// If the query parameter is not detected, reload the page with the parameter added
if (!hideOnPrintParam) {
window.location.href = `${window.location.href}?hideOnPrint=1`;
}
});
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>
<title>Zhentao Wei's LinkedIn banner {getFormattedDate()}</title>
<meta content="Zhentao Wei's LinkedIn banner" property="og:title" />
<meta content="This Linkedin banner is made completely with 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 hide-on-print">
<div>
Under here is my Linkedin banner. This page has been able to be saved as PDF, and the banner can be extracted as an image fro mthe pdf.
This can be done by pressing <div class="keyboard-key">P</div> + <div class="keyboard-key">CTRL</div>, then set scaling to 100% and no margins. Lastly, select save to PDF or print.
<br/>
<br/>
I have to sadly recommend chrome for this process. Firefox somehow messes with the quality of the PDF :(
</div>
</div>
<div class="container include-in-print">
<div>
<RepeatedSkills targetTextHeight={70} targetTextWidth={175}/>
</div>
<div/>
</div>
<style lang="scss">
.cv-info-container {
height: 40mm;
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;
}
> div {
width: 80%;
height: 60%;
}
}
@media print {
.hide-on-print {
display: none;
}
}
.include-in-print { &, & * {
-webkit-print-color-adjust:exact !important;
print-color-adjust:exact !important;
}}
.container {
width: 100%;
height: 100%;
display: grid;
place-items: center;
> div:nth-child(1) {
width: 419.1mm;
height: 104.775mm;
background-color: #383636;
overflow: hidden;
display: grid;
place-content: center;
font-size: 10mm;
font-family: cozetteVector;
color: #d4d4d4;
filter: blur(0); // Force save as image
}
> div:nth-child(2){
height: 0;
}
}
</style>

View file

@ -0,0 +1,16 @@
<script lang="ts">
export let bgColor: string | undefined = undefined;
export let bottomBorder: boolean = true;
</script>
<div style="width: 210mm; height: 297mm;" class="{(bgColor)?bgColor:"bg-white"} overflow-y-auto overflow-x-hidden">
<div class="flex flex-col h-full">
<div {...$$restProps}>
<slot></slot>
</div>
{#if bottomBorder}
<div class="border-b-2 mt-auto mb-0 border-dashed border-slate-600 hide-on-print"></div>
{/if}
</div>
</div>

Binary file not shown.

Before

(image error) Size: 9.5 KiB

After

(image error) Size: 10 KiB

Before After
Before After

Binary file not shown.

55
static/images/cropper.py Normal file
View file

@ -0,0 +1,55 @@
import os
import glob
from PIL import Image
from concurrent.futures import ProcessPoolExecutor, as_completed
# Directories
input_dir = 'spinning_cat'
output_dir = 'spinning_cat_cropped'
# Ensure output directory exists
def ensure_output_dir():
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Process a single image: crop transparent borders and save
def process_image(filepath):
try:
img = Image.open(filepath)
if img.mode != 'RGBA':
img = img.convert('RGBA')
alpha = img.split()[-1]
bbox = alpha.getbbox()
cropped = img.crop(bbox) if bbox else img
filename = os.path.basename(filepath)
out_path = os.path.join(output_dir, filename)
cropped.save(out_path)
return out_path, None
except Exception as e:
return filepath, e
# Main execution: parallel processing
def main():
ensure_output_dir()
pattern = os.path.join(input_dir, 'untitled_*.png')
files = sorted(glob.glob(pattern))
if not files:
print(f"No files found in '{input_dir}' with pattern 'untitled_*.png'.")
return
with ProcessPoolExecutor() as executor:
futures = {executor.submit(process_image, fp): fp for fp in files}
for future in as_completed(futures):
fp = futures[future]
out_path, error = future.result()
if error:
print(f"Error processing {fp}: {error}")
else:
print(f"Cropped and saved: {out_path}")
print("Processing complete.")
if __name__ == '__main__':
main()

Binary file not shown.

After

(image error) Size: 8.2 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

Binary file not shown.

After

(image error) Size: 10 KiB

Binary file not shown.

After

(image error) Size: 9.5 KiB

Binary file not shown.

After

(image error) Size: 116 KiB

Binary file not shown.

After

(image error) Size: 396 KiB

Binary file not shown.

After

(image error) Size: 396 KiB

Binary file not shown.

After

(image error) Size: 398 KiB

Binary file not shown.

After

(image error) Size: 397 KiB

Binary file not shown.

After

(image error) Size: 397 KiB

Binary file not shown.

After

(image error) Size: 397 KiB

Binary file not shown.

After

(image error) Size: 399 KiB

Binary file not shown.

After

(image error) Size: 402 KiB

Binary file not shown.

After

(image error) Size: 402 KiB

Binary file not shown.

After

(image error) Size: 402 KiB

Binary file not shown.

After

(image error) Size: 402 KiB

Binary file not shown.

After

(image error) Size: 402 KiB

Binary file not shown.

After

(image error) Size: 403 KiB

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