Compare commits
No commits in common. "main" and "list" have entirely different histories.
|
@ -1,23 +0,0 @@
|
|||
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")"
|
66
CarouselExample.html
Normal file
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HTML Carousel Example</title>
|
||||
<!-- Include Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<div id="carouselExample" class="carousel slide" data-bs-ride="carousel">
|
||||
<!-- Indicators -->
|
||||
<div class="carousel-indicators">
|
||||
<button type="button" data-bs-target="#carouselExample" data-bs-slide-to="0" class="active"
|
||||
aria-current="true" aria-label="Slide 1"></button>
|
||||
<button type="button" data-bs-target="#carouselExample" data-bs-slide-to="1"
|
||||
aria-label="Slide 2"></button>
|
||||
<button type="button" data-bs-target="#carouselExample" data-bs-slide-to="2"
|
||||
aria-label="Slide 3"></button>
|
||||
</div>
|
||||
|
||||
<!-- Carousel Items -->
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img src="https://via.placeholder.com/800x400" class="d-block w-100" alt="Slide 1">
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h5>First Slide</h5>
|
||||
<p>Description for the first slide.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="https://via.placeholder.com/800x400" class="d-block w-100" alt="Slide 2">
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h5>Second Slide</h5>
|
||||
<p>Description for the second slide.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="https://via.placeholder.com/800x400" class="d-block w-100" alt="Slide 3">
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h5>Third Slide</h5>
|
||||
<p>Description for the third slide.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Controls -->
|
||||
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExample" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Previous</span>
|
||||
</button>
|
||||
<button class="carousel-control-next" type="button" data-bs-target="#carouselExample" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Include Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
24
build.sh
Normal file → Executable file
|
@ -4,10 +4,28 @@
|
|||
# NODE_ENV is set to production, npm won't install anything
|
||||
unset NODE_ENV
|
||||
|
||||
git pull
|
||||
git reset --hard main
|
||||
echo "Rebuilding deprived main site"
|
||||
echo "cwd: ${pwd}"
|
||||
|
||||
npm ci
|
||||
#rm -rf deprived-main-website
|
||||
#git clone https://gitea.deprived.dev/Sveskejuice/deprived-main-website.git
|
||||
|
||||
git restore .
|
||||
git clean -fd
|
||||
git pull
|
||||
git checkout WeGoingBasic
|
||||
|
||||
echo "Project files up to date. Proceeding to install deps"
|
||||
|
||||
echo "npm config list:"
|
||||
npm config list
|
||||
|
||||
npm cache clean --force
|
||||
npm i
|
||||
npm i @sveltejs/adapter-static
|
||||
npm i @sveltejs/kit
|
||||
npm i @zerodevx/svelte-img
|
||||
npm tailwind init
|
||||
|
||||
echo "Ready to build, building..."
|
||||
|
||||
|
|
|
@ -10,12 +10,7 @@
|
|||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"paths": {
|
||||
"@images/*": ["./src/images/*"],
|
||||
"@src/*": ["./src/*"],
|
||||
"@static/*": ["./static/*"]
|
||||
}
|
||||
"allowImportingTsExtensions": true
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias and https://kit.svelte.dev/docs/configuration#files
|
||||
//
|
||||
|
|
2140
package-lock.json
generated
18
package.json
|
@ -6,33 +6,33 @@
|
|||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"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"
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/adapter-static": "^3.0.1",
|
||||
"@sveltejs/kit": "^2.20.4",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"daisyui": "^5.0.12",
|
||||
"daisyui": "^4.12.12",
|
||||
"postcss": "^8.4.47",
|
||||
"sass": "^1.77.4",
|
||||
"svelte": "^5.25.7",
|
||||
"svelte-check": "^3.8.6",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^3.6.0",
|
||||
"svelte-highlight": "^7.6.0",
|
||||
"tailwindcss": "^4.1.3",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"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-parallax": "^0.6.0",
|
||||
"theme-change": "^2.5.0"
|
||||
}
|
||||
}
|
||||
|
|
2502
pnpm-lock.yaml
generated
6
postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
222
src/app.css
|
@ -1,222 +0,0 @@
|
|||
@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;
|
||||
}
|
||||
}
|
30
src/app.html
|
@ -1,5 +1,5 @@
|
|||
<!doctype html>
|
||||
<html lang="en" data-theme="Deprived" style="overflow-x: hidden;">
|
||||
<html lang="en" data-theme="Synthwave" style="overflow-x: hidden;">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="
|
||||
|
@ -8,35 +8,11 @@
|
|||
<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[randomNumber]);
|
||||
}
|
||||
//else {
|
||||
// console.log("Slecting: " + theme);
|
||||
// document.documentElement.setAttribute('data-theme', theme);
|
||||
//}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="display: contents">
|
||||
<div class="inline relative w-full h-full">
|
||||
%sveltekit.body%
|
||||
</div>
|
||||
</body>
|
||||
<body style="display: contents">%sveltekit.body%</div>
|
||||
</html>
|
||||
|
|
3
src/lib/app.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
|
@ -11,7 +11,9 @@
|
|||
version="1.1"
|
||||
viewBox="0 0 28 20"
|
||||
width="28"
|
||||
xml:space="preserve"><defs
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><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"
|
||||
|
|
|
@ -1,313 +1,296 @@
|
|||
<!-- If url contains "hideOnPrint" param, then detect if start printing then hide elements -->
|
||||
<script lang="ts">
|
||||
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 "$lib/app.css";
|
||||
|
||||
let { children } = $props();
|
||||
import { fly } from 'svelte/transition';
|
||||
import MediaQuery from 'svelte-media-queries';
|
||||
export let hideOnPrint: boolean;
|
||||
|
||||
import DeprivedLogo from "$lib/images/DeprivedLogo.svelte";
|
||||
import HamburgerMenuIcon from "$lib/images/HamburgerMenuIcon.svelte";
|
||||
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 isMobile: boolean = $state(false);
|
||||
import svelteLogo from "$lib/svelteLogos/svelte-logo.png"
|
||||
|
||||
let navbarHidden: boolean = $state(true);
|
||||
const footerCollapseThreshold : string = '1000px';
|
||||
const headerCollapseThreshold : string = '1000px';
|
||||
let footerCollapse : boolean;
|
||||
let isMobile : boolean;
|
||||
|
||||
function resetNavBar() {
|
||||
navbarHidden = true;
|
||||
}
|
||||
let navbarHidden : boolean = true;
|
||||
|
||||
import { afterNavigate } from "$app/navigation";
|
||||
afterNavigate(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
hideOnPrint = params.get("hideOnPrint") === "1";
|
||||
console.log(hideOnPrint);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
function nextTheme() {
|
||||
let theme: string | null = null;
|
||||
|
||||
if (typeof localStorage !== "undefined") {
|
||||
theme = localStorage.getItem("theme");
|
||||
function resetNavBar() {
|
||||
navbarHidden = true;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
afterNavigate(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
hideOnPrint = params.get('hideOnPrint') === '1';
|
||||
//console.log(hideOnPrint);
|
||||
});
|
||||
|
||||
console.log("Slecting: " + nextTheme);
|
||||
document.documentElement.setAttribute("data-theme", nextTheme);
|
||||
localStorage.setItem("theme", nextTheme);
|
||||
}
|
||||
import { onMount } from 'svelte';
|
||||
import { themeChange } from 'theme-change'
|
||||
onMount(() => {
|
||||
const lock = document.createElement('meta');
|
||||
lock.name = 'darkreader-lock';
|
||||
document.head.appendChild(lock);
|
||||
|
||||
themeChange(false) // false parameter is required for svelte
|
||||
});
|
||||
</script>
|
||||
|
||||
{#snippet SwitchThemeButton()}
|
||||
<div
|
||||
class="tooltip tooltip-bottom grid place-content-center"
|
||||
data-tip="Switch theme"
|
||||
>
|
||||
<button class="cursor-pointer" onclick={nextTheme}> <Dices /></button>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<!-- Detect mobile -->
|
||||
<MediaQuery
|
||||
query="(max-width: {footerCollapseThreshold})"
|
||||
bind:matches={footerCollapse}
|
||||
/>
|
||||
<MediaQuery
|
||||
query="(max-width: {headerCollapseThreshold})"
|
||||
bind:matches={isMobile}
|
||||
/>
|
||||
<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' : ''} 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> -->
|
||||
</a>
|
||||
<div class="nav-spacer" />
|
||||
<div class="bg-base-200 p-0">
|
||||
<header class="{hideOnPrint ? 'hide-on-print' : ''}">
|
||||
<div class="nav-bar pr-4 bg-base-200">
|
||||
{#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> -->
|
||||
</a>
|
||||
<div class="nav-spacer" />
|
||||
|
||||
<!-- <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="/">Home</a> -->
|
||||
<!-- <a href="/zhen/notes/physics/1?hideOnPrint=1" target="_blank" style="width: 7.5rem;">Notes</a> -->
|
||||
<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> -->
|
||||
</a>
|
||||
<div class="nav-spacer" />
|
||||
<button id="toggle-nav" on:click={() => navbarHidden = !navbarHidden}>
|
||||
<HamburgerMenuIcon Class="fill-base-content"/>
|
||||
</button>
|
||||
</div>
|
||||
{#if !navbarHidden}
|
||||
<div class="nav-list" transition:fly={{ y: -25, duration: 350 }}>
|
||||
<!-- <a on:click={resetNavBar} href="/">Home</a> -->
|
||||
<a on:click={resetNavBar} href="https://botalex.itch.io/" target="_blank">Games</a>
|
||||
<a href="/zhen/cv/rev2?hideOnPrint=1" target="_blank">Zhen's CV</a>
|
||||
<!-- <a on:click={resetNavBar} href="/posts">Blog</a>
|
||||
<a on:click={resetNavBar} href="/about">About</a> -->
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="collapsed shadow-xl">
|
||||
<a onclick={resetNavBar} href="/" class="nav-head">
|
||||
<DeprivedLogo
|
||||
Class="fill-base-content p-2"
|
||||
Style="width: 3.5rem; height: auto;"
|
||||
/>
|
||||
<!-- <h3 id="logo-text">The Deprived Devs</h3> -->
|
||||
</a>
|
||||
<div class="nav-spacer" />
|
||||
{@render SwitchThemeButton()}
|
||||
<div class="px-1"></div>
|
||||
<button
|
||||
id="toggle-nav"
|
||||
onclick={() => {
|
||||
navbarHidden = !navbarHidden;
|
||||
console.log(navbarHidden);
|
||||
}}
|
||||
>
|
||||
<HamburgerMenuIcon Class="fill-base-content" />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<!-- Page content -->
|
||||
<slot />
|
||||
|
||||
<!-- 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>Snorre Ettrup Altschul</span>
|
||||
<br>
|
||||
<span>Zhentao Wei</span>
|
||||
</div>
|
||||
<div>
|
||||
<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: 2rem;" alt="SvelteKit logo"/></a>
|
||||
</div>
|
||||
<span>Website <a href="https://gitea.deprived.dev/Sveskejuice/deprived-main-website/src/branch/WeGoingBasic" target="_blank">source code</a></span>
|
||||
|
||||
</div>
|
||||
<div class="contact">
|
||||
<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" alt="Discord"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{#if !navbarHidden}
|
||||
<div class="nav-list" transition:fly={{ y: -25, duration: 350 }}>
|
||||
<!-- <a onclick={resetNavBar} href="/">Home</a> -->
|
||||
<a
|
||||
onclick={resetNavBar}
|
||||
href="https://botalex.itch.io/"
|
||||
target="_blank">Games</a
|
||||
>
|
||||
<a href="/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}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Page content -->
|
||||
{@render children?.()}
|
||||
|
||||
<Zooter bind:hideOnPrint />
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
{#if footerCollapse}
|
||||
<style>
|
||||
.about-container {
|
||||
flex-direction: column;
|
||||
justify-content: center !important;
|
||||
gap: 25px;
|
||||
|
||||
<style lang="scss">
|
||||
/* Nav bar. */
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
width: 100%;
|
||||
max-width: 1400px;
|
||||
}
|
||||
|
||||
.desktop {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#toggle-nav {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
.nav-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
#logo-link {
|
||||
width: 64px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
#logo-text {
|
||||
font-size: 24px;
|
||||
color: oklch(var(--bc));
|
||||
font-family: var(--title-font);
|
||||
margin: 0;
|
||||
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.nav-spacer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 22px;
|
||||
font-family: var(--title-font);
|
||||
// Text color
|
||||
color: oklch(var(--bc));
|
||||
}
|
||||
|
||||
/* Footer. */
|
||||
footer {
|
||||
margin-top: 50px;
|
||||
padding: 25px 0;
|
||||
background-color: oklch(var(--b3));
|
||||
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.about-container {
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
|
||||
color: oklch(var(--bc));
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
& h3 {
|
||||
font-size: larger;
|
||||
}
|
||||
}
|
||||
|
||||
.about-container > div {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.credits {
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.contact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.social {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.social > img {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
footer h3 {
|
||||
margin-top: 0px;
|
||||
color: var(--text2);
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: var(--text2);
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
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 isMobile}
|
||||
<style>
|
||||
</style>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
/* Nav bar. */
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
width: 100%;
|
||||
max-width: 1400px;
|
||||
}
|
||||
|
||||
.desktop {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#toggle-nav {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.nav-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
#logo-link {
|
||||
width: 64px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
#logo-text {
|
||||
font-size: 24px;
|
||||
color: oklch(var(--bc));
|
||||
font-family: var(--title-font);
|
||||
margin: 0;
|
||||
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.nav-spacer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 22px;
|
||||
font-family: var(--title-font);
|
||||
// Text color
|
||||
color: oklch(var(--bc));
|
||||
}
|
||||
|
||||
/* Footer. */
|
||||
footer {
|
||||
margin-top: 50px;
|
||||
padding: 25px 0;
|
||||
background-color: oklch(var(--b3));
|
||||
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.about-container {
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
|
||||
color: oklch(var(--bc));
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
& h3 {
|
||||
font-size: larger;
|
||||
}
|
||||
}
|
||||
|
||||
.about-container > div {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.credits {
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.contact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.social {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.social > img {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
footer h3 {
|
||||
margin-top: 0px;
|
||||
color: var(--text2);
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: var(--text2);
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
filter: brightness(130%);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
import Button from '$lib/IO/Button.svelte';
|
||||
import { ButtonType } from '$lib/IO/ButtonType.ts';
|
||||
import Timeline from '../comps/timeline/timeline.svelte';
|
||||
import { onMount, tick } from 'svelte'
|
||||
import { Parallax, ParallaxLayer, StickyLayer } from "svelte-parallax";
|
||||
import { tick } from 'svelte'
|
||||
|
||||
import PreviewDeprivedLogo from "$lib/images/DeprivedLogo-NoBackground.png";
|
||||
|
||||
|
@ -34,28 +35,22 @@
|
|||
|
||||
const mobileThreshold : string = '600px'; // was 1000px. zhen testing
|
||||
let mobile : boolean;
|
||||
|
||||
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} />
|
||||
|
||||
<title id="TabTittle">We are the DEPRIVED DEVS</title>
|
||||
<title>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="We collaborate to create game, and hopefully more in the future! Wanna join? Hit us up." 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);">
|
||||
<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;">
|
||||
{#if !mobile}
|
||||
Deprived Devs
|
||||
{:else}
|
||||
|
@ -72,67 +67,75 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<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">
|
||||
<div class="flex justify-center w-full px-8 py-4">
|
||||
<div class="grid space-y-5" style="width: 100%; max-width: 21cm;">
|
||||
<h2 class="prose main-title" style="font-size: {!mobile ? 3 : 2}rem;">
|
||||
Developers
|
||||
</h2>
|
||||
|
||||
<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>
|
||||
</span>
|
||||
</Profile>
|
||||
|
||||
<Profile name="Sveske / Benjamin" tags={["Programmer", "Back-end Admin"]} isMobile={mobile}>
|
||||
<span>
|
||||
<p><span class="inline line-through">Hi, I use Arch, btw. </span> I use NixOS now</p>
|
||||
<p><a href="https://www.linkedin.com/in/benjamin-dreyer/" target="_blank" style="color:lightblue;">Linked-in</a></p>
|
||||
</span>
|
||||
</Profile>
|
||||
|
||||
<Profile isSnorre={true} tags={["Programmer"]} isMobile={mobile}/>
|
||||
<Profile 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>
|
||||
</span>
|
||||
</Profile>
|
||||
|
||||
<ProfileSpacer/>
|
||||
<Profile name="Sveske / Benjamin" tags={["Programmer", "Back-end Admin"]} isMobile={mobile}>
|
||||
<span>
|
||||
<p>Hi, I use Arch, btw.</p>
|
||||
<p><a href="https://www.linkedin.com/in/benjamin-dreyer/" target="_blank" style="color:lightblue;">Linked-in</a></p>
|
||||
</span>
|
||||
</Profile>
|
||||
|
||||
<ProfileSpacer/>
|
||||
<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>
|
||||
<ProfileSpacer/>
|
||||
<Profile name="Oliver" tags={["Sound designer", "Story designer","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>
|
||||
<ProfileSpacer/>
|
||||
<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>
|
||||
|
||||
<ProfileSpacer/>
|
||||
<Profile name="Zylvester" tags={["2D/3D Artist", "Sound designer", "Story designer"]} isMobile={mobile}>
|
||||
<span>
|
||||
<p>Hi, I am [insert text here]</p>
|
||||
<p>Here's a joke about recursion: <a href="/" target="_blank" style="color:lightblue;">recursion</a></p>
|
||||
</span>
|
||||
</Profile>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="py-4"></div>
|
||||
<!-- space -->
|
||||
<div class="py-8 flex justify-center">
|
||||
<div style="width: 50%;">
|
||||
<ProfileSpacer/>
|
||||
</div>
|
||||
</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" : ""}">
|
||||
<div class="grid place-content-center place-items-center min-h-screen 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> -->
|
||||
</article>
|
||||
|
||||
<!-- Spacer -->
|
||||
<!-- <div style="width: 50%;" class="{!mobile ? "py-16" : "py-4"}">
|
||||
<div style="width: 50%;" class="{!mobile ? "py-16" : "py-4"}">
|
||||
<ProfileSpacer/>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<article class="prose {mobile ? "px-8" : ""}">
|
||||
<article class="pt-16 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>
|
||||
|
@ -158,7 +161,7 @@
|
|||
<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>
|
||||
<a href="https://botalex.itch.io/corrobot-rebounce" target="_blank" class="btn btn-primary">View on itch.io</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -180,7 +183,7 @@
|
|||
<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>
|
||||
<a href="https://botalex.itch.io/mop-of-the-dead" target="_blank" class="btn btn-primary">View on itch.io</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -202,7 +205,7 @@
|
|||
<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>
|
||||
<a href="https://botalex.itch.io/one-more-time" target="_blank" class="btn btn-primary">View on itch.io</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -210,9 +213,7 @@
|
|||
|
||||
|
||||
<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>
|
||||
<figure class="skeleton rounded-b-none" style="height: 15em;"></figure>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">What's next?</h2>
|
||||
<div class="skeleton mt-1 h-4 w-28"></div>
|
||||
|
@ -222,7 +223,7 @@
|
|||
<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>
|
||||
<a href="/" target="_blank" class="btn btn-primary">RECURSION!</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -231,6 +232,11 @@
|
|||
|
||||
|
||||
<style>
|
||||
.main-title {
|
||||
width: 80%;
|
||||
font-family: var(--title-font);
|
||||
}
|
||||
|
||||
#backgroundGif{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
<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>
|
|
@ -11,15 +11,14 @@
|
|||
</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">
|
||||
<div class="developersProfile {isSnorre ? "isSnorre" : ""} pl-4 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="w-full">
|
||||
<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>
|
||||
|
@ -30,38 +29,35 @@
|
|||
<pre> </pre>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="developersProfile snorre-overlay relative pl-1 font-mono">
|
||||
<div class="developersProfile snorre-overlay relative pl-4 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>
|
||||
<p>I'm the diversity hire. (Gay)</p>
|
||||
<p><a href="https://www.linkedin.com/in/snorrealtschul/" target="_blank" style="color:lightblue;">Linked-in</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-image: linear-gradient(oklch(var(--p)) 33%, rgba(255,255,255,0) 0%);
|
||||
background-position: left;
|
||||
background-size: 0.1rem 0.5rem;
|
||||
background-repeat: repeat-y; */
|
||||
background-repeat: repeat-y;
|
||||
}
|
||||
|
||||
.snorre {
|
||||
/* border-left: dashed transparent 0.1rem;
|
||||
border-left: dashed transparent 0.1rem;
|
||||
border-image: linear-gradient(to bottom, red, orange, yellow, green, blue, indigo, violet);
|
||||
border-image-slice: 1; */
|
||||
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-image: linear-gradient(rgba(255,255,255,0) 0%, rgba(255,255,255,0) 40%, oklch(var(--b1)) 40%);
|
||||
background-position: left;
|
||||
background-size: 0.1rem 0.5rem;
|
||||
background-repeat: repeat-y; */
|
||||
background-repeat: repeat-y;
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { Vector2 } from "../zhen/Utils/Vector2";
|
||||
import { Vector2 } from "./../zhen/Utils/Vector2";
|
||||
|
||||
import { Parallax, ParallaxLayer, StickyLayer } from "svelte-parallax";
|
||||
|
||||
// Params
|
||||
let mouseMoveScale: number = 0.25;
|
||||
|
|
|
@ -1,77 +1,38 @@
|
|||
<script lang="ts">
|
||||
export let Tags = ["null"];
|
||||
export let Tags= ["null"];
|
||||
export let isMobile = false;
|
||||
type ColorType = string | { color1: string; color2: string; rotation: string; offset: string };
|
||||
let colors: { [String: string]: ColorType} = {
|
||||
"programmer": "#0CC27F",
|
||||
"uxdesigner": "#027893",
|
||||
"3dartist": "#F4881C",
|
||||
"2dartist": "#F1EAC0",
|
||||
"2d/3dartist": {"color1":"#F1EAC0", "color2":"#F4881C","rotation": "-65deg", "offset": "71.5%"},
|
||||
"sounddesigner": "#F3EC2A",
|
||||
"storydesigner": "#EEC12A",
|
||||
"back-endadmin": "#3236a8",
|
||||
};
|
||||
|
||||
// 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' };">
|
||||
<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}
|
||||
<div class="badge2 text-primary-content cozette" style="background-color: {colors[key] || "#ccc"};">{tag}</div>
|
||||
{:else}
|
||||
<!-- Gradient Badge -->
|
||||
{#if typeof color === 'object' && color !== null}
|
||||
{#if typeof colors[key] === 'object' && colors[key] !== null}
|
||||
<div
|
||||
class="badge2 cozette"
|
||||
style="background: linear-gradient({color.rotation}, {color.color2} {color.offset}, {color.color1} {color.offset});">
|
||||
<span class="invert">
|
||||
{tag}
|
||||
</span>
|
||||
class="badge2 text-primary-content cozette"
|
||||
style="background: linear-gradient({colors[key].rotation}, {colors[key].color2} {colors[key].offset}, {colors[key].color1} {colors[key].offset});">
|
||||
{tag}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="badge2 cozette" style="background-color: #ccc;">
|
||||
<span class="invert">
|
||||
{tag}
|
||||
</span>
|
||||
<div
|
||||
class="badge2 text-primary-content cozette"
|
||||
style="background-color: #ccc;">
|
||||
{tag}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -83,11 +44,12 @@
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 1.25rem; /* 20px */
|
||||
line-height: 1.25rem; /* 20px */
|
||||
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 */
|
||||
padding-left: 0.563rem /* 9.008px */;
|
||||
padding-right: 0.563rem /* 9.008px */;
|
||||
border-radius: var(--rounded-badge, 1.9rem /* 30.4px */);
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
|
@ -1,258 +0,0 @@
|
|||
<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} -->
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import A4 from "../zhen/notes/physics/sharedComps/A4.svelte";
|
||||
import ToolButton from "./comps/ToolButton.svelte";
|
||||
import { BatteryMedium } from '@lucide/svelte';
|
||||
import { BatteryMedium } from 'lucide-svelte';
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center pt-10">
|
||||
|
@ -11,7 +11,7 @@
|
|||
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>
|
||||
<h1 class="text-5xl font-bold">Tools</h1>
|
||||
<span class="w-full text-xl"
|
||||
>These are the tools collected from different places of the
|
||||
internet</span
|
||||
|
@ -28,19 +28,19 @@
|
|||
title="Sleeping battery life"
|
||||
desc="Calculates the battery life depending on sleep and non-sleep power usage."
|
||||
btnText="To calculator"
|
||||
toolIcon={BatteryMedium}
|
||||
icon={BatteryMedium}
|
||||
/>
|
||||
<!-- <ToolButton
|
||||
title="Sleeping battery life"
|
||||
desc="Calculates the battery life depending on sleep and non-sleep power usage."
|
||||
btnText="To calculator"
|
||||
toolIcon={BatteryMedium}
|
||||
icon={BatteryMedium}
|
||||
/>
|
||||
<ToolButton
|
||||
title="Sleeping battery life"
|
||||
desc="Calculates the battery life depending on sleep and non-sleep power usage."
|
||||
btnText="To calculator"
|
||||
toolIcon={BatteryMedium}
|
||||
icon={BatteryMedium}
|
||||
/> -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
<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 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"];
|
||||
const options = ["esp32-s3", "Text Two", "Text Three"];
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center pt-10">
|
||||
|
@ -84,28 +82,21 @@
|
|||
</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>
|
||||
<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>
|
||||
{#if selectedText}
|
||||
<p class="mt-4 text-lg">
|
||||
You selected: {selectedText}
|
||||
</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="form-control">
|
||||
<span class="text-sm text-slate-300 text-opacity-60"
|
||||
|
|
108
src/routes/tools/battery-life-calculator/pageSrc/BatteryCalc.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
export class BatteryLifeCalculator {
|
||||
constructor(
|
||||
timeRunSeconds,
|
||||
timeSleepSeconds,
|
||||
consumptionActiveMilliAmpHours,
|
||||
consumptionSleepMilliAmpHours,
|
||||
powerBatteryTotalMilliAmpHours,
|
||||
powerBatteryBufferBeforeEmptyPercent = 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) {
|
||||
return milliAmps * 1000
|
||||
}
|
||||
|
||||
microAmpToMilliAmp(milliAmps) {
|
||||
return milliAmps * 0.001
|
||||
}
|
||||
|
||||
calculate() {
|
||||
return {
|
||||
powerAveragePerHour: this.powerEstimatedHourly(),
|
||||
runtimeHoursEstimated: this.runtimeHoursEstimated(),
|
||||
runtimeDaysEstimated: this.runtimeDaysEstimated(),
|
||||
runtimeDaysRemainingHoursEstimated: this.runtimeDaysRemainingHoursEstimated()
|
||||
}
|
||||
}
|
||||
|
||||
powerEstimatedHourly() {
|
||||
return this.calcPowerEst(
|
||||
this.powerRun(),
|
||||
this.consumptionActiveMilliAmpHours,
|
||||
this.powerSleep(),
|
||||
this.consumptionSleepMilliAmpHours
|
||||
)
|
||||
}
|
||||
|
||||
runtimeHoursEstimated() {
|
||||
return parseInt(this.powerLipo() / this.powerEstimatedHourly())
|
||||
}
|
||||
|
||||
runtimeDaysEstimated() {
|
||||
return parseInt(this.runtimeHoursEstimated() / 24)
|
||||
}
|
||||
|
||||
runtimeDaysRemainingHoursEstimated() {
|
||||
return parseInt(this.runtimeHoursEstimated() % 24)
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
roundOff(x) {
|
||||
return Math.round(x * 100.0) / 100.0
|
||||
}
|
||||
|
||||
calcPowerLipo(x, y) {
|
||||
return parseFloat((x * (100 - y)) / 100)
|
||||
}
|
||||
|
||||
calcRuns(x, y) {
|
||||
return parseFloat(60 / (x + y))
|
||||
}
|
||||
|
||||
calcRunsHour(x, y) {
|
||||
return parseFloat(3600 / (x + y))
|
||||
}
|
||||
|
||||
calcPowerRun(x, y) {
|
||||
return parseFloat((x / (x + y)) * 3600)
|
||||
}
|
||||
|
||||
calcPowerSleep(x, y) {
|
||||
return parseFloat((y / (x + y)) * 3600)
|
||||
}
|
||||
|
||||
powerLipo() {
|
||||
return this.calcPowerLipo(this.powerBatteryTotalMilliAmpHours, this.powerBatteryBufferBeforeEmptyPercent)
|
||||
}
|
||||
|
||||
runs() {
|
||||
return this.calcRuns(this.timeRunSeconds, this.timeSleepSeconds)
|
||||
}
|
||||
|
||||
runsHour() {
|
||||
return this.calcRunsHour(this.timeRunSeconds, this.timeSleepSeconds)
|
||||
}
|
||||
|
||||
powerRun() {
|
||||
return this.calcPowerRun(this.timeRunSeconds, this.timeSleepSeconds)
|
||||
}
|
||||
|
||||
powerSleep() {
|
||||
return this.calcPowerSleep(this.timeRunSeconds, this.timeSleepSeconds)
|
||||
}
|
||||
|
||||
calcPowerEst(a, b, c, d) {
|
||||
return parseFloat((a / 3600) * b + (c / 3600) * d)
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
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());
|
||||
}
|
||||
}
|
|
@ -6,9 +6,9 @@ export interface MCU_Type {
|
|||
bluetooth?: { [key: string]: Number };
|
||||
}
|
||||
|
||||
const MCUs: MCU_Type[] = [
|
||||
export const MCUs: MCU_Type[] = [
|
||||
{
|
||||
name: "esp32-s3",
|
||||
name: "ESP32-S3",
|
||||
cpu: { // mili amps
|
||||
single_core_40MHz: 21.8,
|
||||
dual_core_40MHz: 24.4,
|
||||
|
@ -33,13 +33,13 @@ const MCUs: MCU_Type[] = [
|
|||
},
|
||||
|
||||
{
|
||||
name: "esp32-c3",
|
||||
name: "ESP32-C3",
|
||||
cpu: {
|
||||
single_core_80MHz: 22,
|
||||
single_core_160MHz: 54.6,
|
||||
active: 130,
|
||||
sleep: 15
|
||||
},
|
||||
sleep: {
|
||||
|
||||
|
||||
},
|
||||
wifi: {
|
||||
active: 110,
|
||||
|
@ -51,13 +51,3 @@ const MCUs: MCU_Type[] = [
|
|||
}
|
||||
}
|
||||
];
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { Component } from 'svelte';
|
||||
import type { SvelteComponent } from "svelte";
|
||||
|
||||
export let toolIcon: Component | undefined = undefined;
|
||||
export let icon: typeof SvelteComponent | 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.";
|
||||
|
@ -18,8 +18,8 @@
|
|||
<div class="text-sm">{desc}</div>
|
||||
|
||||
<div class="flex pt-4">
|
||||
{#if toolIcon != undefined}
|
||||
<svelte:component this={toolIcon}/>
|
||||
{#if icon != undefined}
|
||||
<svelte:component this={icon}/>
|
||||
{/if}
|
||||
<a href="{btnHref}" class="btn ml-auto btn-primary btn-sm">{btnText}</a>
|
||||
</div>
|
||||
|
|
17
src/routes/zhen/+page.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<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>
|
229
src/routes/zhen/Comps/TopAnimatedBackground.svelte
Normal file
|
@ -0,0 +1,229 @@
|
|||
<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";
|
||||
|
||||
// Params
|
||||
let mouseMoveScale: number = 0.25;
|
||||
let targetTextLenght: number = 100;
|
||||
|
||||
// Site variables
|
||||
let mousePos: Vector2;
|
||||
|
||||
// Element binded variables
|
||||
let mouseRelativeScaled: Vector2 = new Vector2(0, 0);
|
||||
|
||||
let windowWidth = 0;
|
||||
let windowHeight = 0;
|
||||
|
||||
let screenCenter: Vector2;
|
||||
|
||||
let StartPageAnimated: Element | null;
|
||||
let windowRef: Window;
|
||||
|
||||
function onMouseMoved(event: MouseEvent) {
|
||||
mousePos = new Vector2(event.clientX, event.clientY);
|
||||
|
||||
updateAnimation(mousePos);
|
||||
}
|
||||
|
||||
function updateAnimation(mousePos: Vector2) {
|
||||
let mouseRelativePos = mousePos.Sub(screenCenter);
|
||||
mouseRelativeScaled = mouseRelativePos.Scale(mouseMoveScale);
|
||||
|
||||
//console.log(mouseRelativePos.x+"\n"+mouseRelativePos.y);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
windowRef = window;
|
||||
|
||||
const updateDimensions = () => {
|
||||
windowWidth = windowRef.innerWidth;
|
||||
windowHeight = windowRef.innerHeight;
|
||||
|
||||
screenCenter = new Vector2(windowWidth / 2, windowHeight / 2);
|
||||
|
||||
//console.log("Window size changed: (" + windowWidth + ", " + windowHeight + ")");
|
||||
};
|
||||
|
||||
updateDimensions(); // On first pass
|
||||
|
||||
windowRef.addEventListener("resize", updateDimensions);
|
||||
|
||||
const RevertToOrigin = () => {
|
||||
if (
|
||||
navigator.userAgent.search(/gecko/i) > 0 &&
|
||||
StartPageAnimated !== null
|
||||
) {
|
||||
StartPageAnimated.classList.add("FirefoxSmoothTranition");
|
||||
}
|
||||
updateAnimation(new Vector2(windowWidth / 2, windowHeight / 2));
|
||||
};
|
||||
document.documentElement.addEventListener("mouseleave", RevertToOrigin);
|
||||
|
||||
const RemoveFirefoxSmoothTranition = () => {
|
||||
if (
|
||||
navigator.userAgent.search(/gecko/i) > 0 &&
|
||||
StartPageAnimated !== null
|
||||
) {
|
||||
StartPageAnimated.classList.remove("FirefoxSmoothTranition");
|
||||
}
|
||||
};
|
||||
document.documentElement.addEventListener(
|
||||
"mouseenter",
|
||||
RemoveFirefoxSmoothTranition,
|
||||
);
|
||||
|
||||
return () => {
|
||||
windowRef.removeEventListener("resize", updateDimensions);
|
||||
};
|
||||
});
|
||||
|
||||
const programmingLanguages: string[] = [
|
||||
"C++",
|
||||
"C#",
|
||||
"ARDUINO",
|
||||
"PYTHON",
|
||||
"JAVA",
|
||||
"JAVASCRIPT",
|
||||
"TYPESCRIPT",
|
||||
"HTML",
|
||||
"CSS",
|
||||
];
|
||||
|
||||
function getRandomInt(max: number) {
|
||||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
function GrabRandomString() {
|
||||
let outString: string = "";
|
||||
while (outString.length < targetTextLenght) {
|
||||
outString +=
|
||||
programmingLanguages[
|
||||
getRandomInt(programmingLanguages.length)
|
||||
] + " ";
|
||||
}
|
||||
|
||||
return outString; // At about target size
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:mousemove={onMouseMoved} />
|
||||
|
||||
|
||||
<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"
|
||||
id="StartPageAnimated"
|
||||
bind:this={StartPageAnimated}
|
||||
style="transform: translate({mouseRelativeScaled.x}px, {mouseRelativeScaled.y}px) translateZ(0) rotate(0.001deg);"
|
||||
>
|
||||
{#each {length: 100} as _, i}
|
||||
|
||||
<span
|
||||
class="rotate45 SkillsText"
|
||||
>
|
||||
{GrabRandomString()}
|
||||
</span
|
||||
>
|
||||
{/each}
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div id="DummyDiv" class="FirefoxSmoothTranition StartPageContainer TopOverlay" style="display: none !important;" />
|
||||
|
||||
<style>
|
||||
.StartPageContainer {
|
||||
/* height: 40vh; */
|
||||
|
||||
background-color: burlywood;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.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;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.FirefoxSmoothTranition {
|
||||
transition: transform 1000ms cubic-bezier(0.16, 1.63, 0.01, 0.99);
|
||||
-moz-transition: transform 1000ms cubic-bezier(0.16, 1.63, 0.01, 0.99) !important;
|
||||
}
|
||||
|
||||
.SkillsText {
|
||||
font-family: "CozetteVector";
|
||||
|
||||
text-align: start;
|
||||
font-size: x-large;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
|
||||
width: 2rem;
|
||||
|
||||
color: rgb(66, 66, 66);
|
||||
}
|
||||
|
||||
.TopOverlay {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.rotate45 {
|
||||
transform: rotate(-45deg); /* Rotate the element by 45 degrees */
|
||||
}
|
||||
</style>
|
|
@ -11,7 +11,7 @@
|
|||
<p class="NickNameText">Alex</p>
|
||||
</span>
|
||||
</div>
|
||||
<div style="flex-grow: 2;" />
|
||||
<div style="flex-grow: 2;" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
21
src/routes/zhen/Utils/Throttle.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
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));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
export class Vector2 {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
Add(vec2: Vector2) {
|
||||
return new Vector2(this.x + vec2.x, this.y + vec2.y);
|
||||
}
|
||||
|
||||
Sub(vec2: Vector2) {
|
||||
return new Vector2(this.x - vec2.x, this.y - vec2.y);
|
||||
}
|
||||
|
||||
Scale(mult: number) {
|
||||
return new Vector2(this.x * mult, this.y * mult);;
|
||||
}
|
||||
}
|
||||
export class Vector2 {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
Add(vec2: Vector2){
|
||||
return new Vector2(this.x + vec2.x, this.y + vec2.y);
|
||||
}
|
||||
|
||||
Sub(vec2: Vector2){
|
||||
return new Vector2(this.x - vec2.x, this.y - vec2.y);
|
||||
}
|
||||
|
||||
Scale(mult: number){
|
||||
return new Vector2(this.x * mult, this.y * mult);;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
</script>
|
||||
|
||||
<div class="container" style="{Style}">
|
||||
<div/>
|
||||
<div>
|
||||
<div>
|
||||
Thank you! ❤
|
||||
|
|
|
@ -53,4 +53,11 @@
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.imagesContainer {
|
||||
> img {
|
||||
border-radius: 5mm;
|
||||
filter: drop-shadow(1mm 1mm 1mm #0000009d);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -74,7 +74,7 @@
|
|||
<LinkedInQR/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="leftSectionSeperator"></div>
|
||||
<div id="leftSectionSeperator"><div/></div>
|
||||
<div id="right-section">
|
||||
<AlexWatermark/>
|
||||
<div id="TopRightSkillsText">
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
<LinkedInQR/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="leftSectionSeperator"></div>
|
||||
<div id="leftSectionSeperator"><div/></div>
|
||||
<div id="right-section">
|
||||
<AlexWatermark/>
|
||||
<div id="TopRightSkillsText">
|
||||
|
|
|
@ -1,254 +1,243 @@
|
|||
<script lang="ts">
|
||||
// Left side
|
||||
import NameAndImage from "../CompsRev2/NameAndImage.svelte";
|
||||
import ShortProfile from "../CompsRev2/ShortProfile.svelte";
|
||||
import CombinedContacts from "../CompsRev2/CombinedContacts.svelte";
|
||||
import LinkedInQR from "../CompsRev2/LinkedInQR.svelte";
|
||||
// Left side
|
||||
import NameAndImage from "../CompsRev2/NameAndImage.svelte";
|
||||
import ShortProfile from "../CompsRev2/ShortProfile.svelte"
|
||||
import CombinedContacts from "../CompsRev2/CombinedContacts.svelte"
|
||||
import LinkedInQR from "../CompsRev2/LinkedInQR.svelte";
|
||||
|
||||
// Right side
|
||||
import Profile from "../CompsRev2/Profile.svelte";
|
||||
import Education from "../CompsRev2/Education.svelte";
|
||||
import Experience from "../CompsRev2/Experience.svelte";
|
||||
import BiggestFlex from "../CompsRev2/BiggestFlex.svelte";
|
||||
import TableOfProjects from "../CompsRev2/TableOfProjects.svelte";
|
||||
|
||||
// Right side
|
||||
import Profile from "../CompsRev2/Profile.svelte";
|
||||
import Education from "../CompsRev2/Education.svelte";
|
||||
import Experience from "../CompsRev2/Experience.svelte";
|
||||
import BiggestFlex from "../CompsRev2/BiggestFlex.svelte";
|
||||
import TableOfProjects from "../CompsRev2/TableOfProjects.svelte";
|
||||
// Decorations
|
||||
import LeftTopDecor from "../CompsRev2/LeftTopDecor.svelte";
|
||||
import BottomRightDecor from "../CompsRev2/BottomRightDecor.svelte";
|
||||
import AlexWatermark from "../CompsRev2/AlexWatermark.svelte";
|
||||
import RepeatedSkills from "../CompsRev2/RepeatedSkills.svelte";
|
||||
|
||||
// Decorations
|
||||
import LeftTopDecor from "../CompsRev2/LeftTopDecor.svelte";
|
||||
import BottomRightDecor from "../CompsRev2/BottomRightDecor.svelte";
|
||||
import AlexWatermark from "../CompsRev2/AlexWatermark.svelte";
|
||||
import RepeatedSkills from "../CompsRev2/RepeatedSkills.svelte";
|
||||
// Cedit
|
||||
import LinkToSource from "../CompsRev2/LinkToSource.svelte";
|
||||
|
||||
// Cedit
|
||||
import LinkToSource from "../CompsRev2/LinkToSource.svelte";
|
||||
// Discord embed
|
||||
import preveiwImage from "$lib/zhen/cv-comps/EposCvPreveiw.png"
|
||||
|
||||
// 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');
|
||||
|
||||
// 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`;
|
||||
}
|
||||
});
|
||||
|
||||
// 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}`;
|
||||
}
|
||||
});
|
||||
|
||||
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="Zhentao Wei's Epos CV" property="og:title" />
|
||||
<meta content="This CV 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 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>
|
||||
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 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="cv-container sections decorations">
|
||||
<div id="left-section">
|
||||
<LeftTopDecor Style="pointer-events: none;" />
|
||||
<BottomRightDecor Style="pointer-events: none;" />
|
||||
<div>
|
||||
<NameAndImage />
|
||||
<ShortProfile />
|
||||
<CombinedContacts />
|
||||
<LinkedInQR />
|
||||
</div>
|
||||
<div class="cv-container sections decorations">
|
||||
<div id="left-section">
|
||||
<LeftTopDecor Style="pointer-events: none;"/>
|
||||
<BottomRightDecor Style="pointer-events: none;"/>
|
||||
<div>
|
||||
<NameAndImage/>
|
||||
<ShortProfile/>
|
||||
<CombinedContacts/>
|
||||
<LinkedInQR/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="leftSectionSeperator"><div/></div>
|
||||
<div id="right-section">
|
||||
<AlexWatermark Style="pointer-events: none;"/>
|
||||
<div id="TopRightSkillsText">
|
||||
<RepeatedSkills targetTextHeight={30} targetTextWidth={75}/>
|
||||
</div>
|
||||
<div id="Credit">
|
||||
<LinkToSource/>
|
||||
</div>
|
||||
<div>
|
||||
<Profile/>
|
||||
<BiggestFlex/>
|
||||
<TableOfProjects/>
|
||||
<Experience/>
|
||||
<Education/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="leftSectionSeperator"></div>
|
||||
<div id="right-section">
|
||||
<AlexWatermark Style="pointer-events: none;" />
|
||||
<div id="TopRightSkillsText">
|
||||
<RepeatedSkills targetTextHeight={30} targetTextWidth={75} />
|
||||
</div>
|
||||
<div id="Credit">
|
||||
<LinkToSource />
|
||||
</div>
|
||||
<div>
|
||||
<Profile />
|
||||
<BiggestFlex />
|
||||
<TableOfProjects />
|
||||
<Experience />
|
||||
<Education />
|
||||
</div>
|
||||
</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;
|
||||
width: calc(100% / 3 * 1);
|
||||
|
||||
> 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;
|
||||
|
||||
.cv-info-container {
|
||||
height: 40mm;
|
||||
background-color: #2b2a2a;
|
||||
display: flex;
|
||||
align-self: flex-end;
|
||||
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;
|
||||
width: calc(100% / 3 * 1);
|
||||
|
||||
> 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>
|
||||
|
||||
</style>
|
117
src/routes/zhen/misc/linkedinBanner/+page.svelte
Normal file
|
@ -0,0 +1,117 @@
|
|||
<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>
|
72
src/routes/zhen/notes/physics/1/+page.svelte
Normal file
|
@ -0,0 +1,72 @@
|
|||
<script lang="ts">
|
||||
import A4 from "../sharedComps/A4.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<script>
|
||||
MathJax = {
|
||||
tex: {
|
||||
inlineMath: [
|
||||
["$", "$"],
|
||||
["\\(", "\\)"],
|
||||
],
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<script
|
||||
id="MathJax-script"
|
||||
async
|
||||
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"
|
||||
></script>
|
||||
</svelte:head>
|
||||
|
||||
<div class="flex justify-center m-auto text-slate-900">
|
||||
<div class="flex flex-col">
|
||||
<A4>
|
||||
<!-- <div>$$v_f = v_i + at$$</div>
|
||||
<div>$$\Delta x = v_i t + \frac{1}{2} a t^2$$</div>
|
||||
<div>$$v_f^2 = v_i^2 + 2a\Delta x$$</div>
|
||||
<div>$$v_{\text{avg} = \frac{v_i + v_f}{2}$$</div>
|
||||
<div>$$\Delta x = v_{\text{avg}} t$$</div> -->
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<!-- head -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$v_i$</td>
|
||||
<td>Initial velo</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$v_f$</td>
|
||||
<td>Final velo</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$a$</td>
|
||||
<td>Accel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$\Delta x$</td>
|
||||
<td>The amount of change.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$t$</td>
|
||||
<td>You're on your own on this one</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</A4>
|
||||
<A4>
|
||||
{#each { length: 3 } as _, i}
|
||||
<div>test {i}</div>
|
||||
{/each}
|
||||
</A4>
|
||||
</div>
|
||||
</div>
|
0
src/routes/zhen/notes/physics/sharedComps/Math.svelte
Normal file
|
@ -1,55 +0,0 @@
|
|||
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()
|
||||
|
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 396 KiB |
Before Width: | Height: | Size: 396 KiB |
Before Width: | Height: | Size: 398 KiB |
Before Width: | Height: | Size: 397 KiB |
Before Width: | Height: | Size: 397 KiB |
Before Width: | Height: | Size: 397 KiB |
Before Width: | Height: | Size: 399 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 403 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 109 KiB |