feat: add project pages
This commit is contained in:
parent
5fc58fd0bc
commit
d41a23cfcf
16 changed files with 171 additions and 28 deletions
10
package.json
10
package.json
|
|
@ -1,7 +1,12 @@
|
|||
{
|
||||
"name": "myblog",
|
||||
"version": "0.0.1",
|
||||
"name": "daichendt.one",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"email": "me@daichendt.one",
|
||||
"name": "Alex Daichendt"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
|
|
@ -43,7 +48,6 @@
|
|||
"vite": "^4.0.3",
|
||||
"vite-imagetools": "^4.0.12"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fontsource/ubuntu-mono": "^4.5.11",
|
||||
"@mdi/js": "^7.1.96",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
const NAV_ITEMS = [
|
||||
{ href: '/', label: 'Home' },
|
||||
{ href: '/blog', label: 'Blog' },
|
||||
{ href: '/projects', label: 'Projects' },
|
||||
{ href: '/contact', label: 'Contact' },
|
||||
];
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -30,10 +30,11 @@
|
|||
{...props}
|
||||
{href}
|
||||
>
|
||||
<span class="text"><slot /></span>
|
||||
|
||||
{#if !disableIcon && !internal}
|
||||
<Icon path={internal ? mdiChevronRight : mdiLinkVariant} size="1rem" />
|
||||
{/if}
|
||||
<span class="text"><slot /></span>
|
||||
</a><style>
|
||||
a {
|
||||
color: var(--special-color);
|
||||
|
|
|
|||
|
|
@ -33,13 +33,19 @@
|
|||
<SEO {title} {description} {keywords} />
|
||||
|
||||
<h1>{title}</h1>
|
||||
<aside role="note">
|
||||
{#if updated || created}
|
||||
<aside role="note">
|
||||
{#if updated}
|
||||
<Icon path={mdiPencil} size="0.8rem" /> updated {new Date(updated).toLocaleDateString('en-GB')};
|
||||
<Icon path={mdiPencil} size="0.8rem" /> updated {new Date(updated).toLocaleDateString(
|
||||
'en-GB',
|
||||
)};
|
||||
{/if}
|
||||
{#if created}
|
||||
<Icon path={mdiCalendar} size="0.8rem" /> created
|
||||
{new Date(created).toLocaleDateString('en-GB')}
|
||||
</aside>
|
||||
{/if}
|
||||
</aside>
|
||||
{/if}
|
||||
<Divider />
|
||||
<slot />
|
||||
|
||||
|
|
|
|||
0
src/lib/layouts/projects.svelte
Normal file
0
src/lib/layouts/projects.svelte
Normal file
|
|
@ -10,6 +10,17 @@ export interface BlogPostFrontmatter {
|
|||
export interface BlogPostMeta extends BlogPostFrontmatter {
|
||||
href: string;
|
||||
}
|
||||
|
||||
export interface ProjectsFrontmatter {
|
||||
title: string;
|
||||
description: string;
|
||||
keywords: string[];
|
||||
inProgress: boolean;
|
||||
}
|
||||
export interface ProjectMeta extends ProjectsFrontmatter {
|
||||
href: string;
|
||||
}
|
||||
|
||||
export interface Skill {
|
||||
name: string;
|
||||
years: number;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
}
|
||||
|
||||
:global(.container) {
|
||||
max-width: 70rem;
|
||||
max-width: 50rem;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
overflow-x: hidden;
|
||||
|
|
|
|||
|
|
@ -60,12 +60,18 @@
|
|||
|
||||
<p>I am a software engineer, Linux enthusiast and a friend of lightweight, resilient systems.</p>
|
||||
<p>
|
||||
Programming has been a hobby of mine since my teens. Been working on countless projects for
|
||||
various games. For a few years now I am maintaining a small homelab, which got me into DevOps/SRE.
|
||||
I am a privacy enthusiast and advocate for non-invasive software. Sometimes, I build slick
|
||||
websites that do not load megabytes of data and try to follow best-practices. Currently, I am
|
||||
working on my Masters degree in computer science at <Link href="https://www.tum.de/">TUM</Link>.
|
||||
My journey in the tech world has been a dynamic one. I've immersed myself in countless projects
|
||||
spanning various video games and, for the past few years, have been maintaining a small homelab,
|
||||
which ignited my passion for DevOps / SRE. I am a privacy enthusiast and advocate for non-invasive
|
||||
software. Occasionally, I channel my creativity into building sleek web applications that
|
||||
prioritize efficiency and adhere to web standards and best practices.
|
||||
</p>
|
||||
<p>
|
||||
Currently, I'm pursuing a Master's degree in computer science at <Link href="https://www.tum.de/"
|
||||
>TUM</Link
|
||||
>, where I successfully contribute to numerous research papers.
|
||||
</p>
|
||||
|
||||
<h2>Skills</h2>
|
||||
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export async function load() {
|
|||
return {
|
||||
seo: {
|
||||
title: 'Home',
|
||||
description: 'Alex Daichendt"s website, blog, and yard of stuffs and things of modern tech.',
|
||||
description: 'Alex Daichendt"s website, blog, and collection of thoughts on modern tech.',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
22
src/routes/projects/+page.server.ts
Normal file
22
src/routes/projects/+page.server.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { ProjectMeta, ProjectsFrontmatter } from '$lib/utils/types';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
const removeExtension = (path: string) => path.replace(/\.[^.]*$/g, '').replace('/+page', '');
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
const modulesSVX = import.meta.glob('./**/*.svx');
|
||||
const modulesMD = import.meta.glob('./**/*.md');
|
||||
const modules = { ...modulesMD, ...modulesSVX };
|
||||
const projects: ProjectMeta[] = [];
|
||||
const resolved = (await Promise.all(Object.values(modules).map((f) => f()))) as {
|
||||
metadata: ProjectsFrontmatter;
|
||||
}[];
|
||||
resolved.forEach((file, index) => {
|
||||
const path = Object.keys(modules)[index];
|
||||
const { metadata } = file;
|
||||
|
||||
projects.push({ ...metadata, href: `projects/${removeExtension(path)}` });
|
||||
});
|
||||
|
||||
return { projects };
|
||||
};
|
||||
22
src/routes/projects/+page.svelte
Normal file
22
src/routes/projects/+page.svelte
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<script lang="ts">
|
||||
import Link from '$components/Link.svelte';
|
||||
import ListItem from '$components/ListItem.svelte';
|
||||
import Seo from '$components/SEO.svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
$: projects = data.projects;
|
||||
</script>
|
||||
|
||||
<Seo />
|
||||
|
||||
<h1>Projects</h1>
|
||||
|
||||
<p>Detailed descriptions of my contributions to various projects.</p>
|
||||
<ul>
|
||||
{#each projects as project}
|
||||
<ListItem>
|
||||
<Link href={project.href}>{project.title}</Link>
|
||||
</ListItem>
|
||||
{/each}
|
||||
</ul>
|
||||
11
src/routes/projects/+page.ts
Normal file
11
src/routes/projects/+page.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = ({ data }) => {
|
||||
return {
|
||||
projects: data.projects,
|
||||
seo: {
|
||||
title: 'Projects',
|
||||
description: 'Detailed descriptions of projects created by Alex Daichendt',
|
||||
},
|
||||
};
|
||||
};
|
||||
61
src/routes/projects/gw2-gear-optimizer/+page.md
Normal file
61
src/routes/projects/gw2-gear-optimizer/+page.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
title: 'GW2 Gear Optimizer'
|
||||
description: 'The Gear Optimizer helps Guild Wars 2 players find optimal builds for fractals, raids, and strike missions.'
|
||||
keywords:
|
||||
- gw2
|
||||
- guild wars 2
|
||||
- optimizer
|
||||
layout: blog
|
||||
---
|
||||
|
||||
<script>
|
||||
import overview from "./images/gear-optimizer.png?default"
|
||||
import Image from "$components/Image.svelte"
|
||||
</script>
|
||||
|
||||
## TL;DR
|
||||
|
||||
{description}
|
||||
|
||||
- Demo / live site: [https://optimizer.discretize.eu](https://optimizer.discretize.eu)
|
||||
- Code: [Github](https://github.com/discretize/discretize-gear-optimizer)
|
||||
|
||||
I made signifcant contributions to the frontend as well as to the calculation core by rewriting it in Rust and implementing threading.
|
||||
Furthermore, I worked closely with and coordinated a small team of a few developers from all over the world ([see here](https://github.com/discretize/discretize-gear-optimizer/graphs/contributors)) to improve the project further.
|
||||
|
||||
<Image meta={overview} />
|
||||
|
||||
## Description
|
||||
|
||||
Interesting features for players of the video game:
|
||||
|
||||
- find optimal builds based on various parameters
|
||||
- build templates with extensive sensible defaults that are used by players
|
||||
- support for different game modes with different balancing
|
||||
- Uptime input for conditional buffs
|
||||
- keyboard shortcuts
|
||||
- custom arbitrary modifier input to allow simulating theoretical balancing
|
||||
- infusion helper: calculates the cheapest way to acquire n agony resistance
|
||||
- input condition distribution
|
||||
- displays the results just like in game
|
||||
- share settings and results with a single link
|
||||
|
||||
## Most Significant Contributions
|
||||
|
||||
- I rewrote the frontend from scratch utilizing modern JS tooling
|
||||
-> the old optimizer consisted out of one 10k LoC HTML file and an equally large js file; bundled with gulp and jquery ...
|
||||
- ported the calculation core to Rust; refactored the combination generation code to support multi-threading
|
||||
-> added some heuristics to reduce the amount of combinations
|
||||
- state compression algorithm based on a schema so that players can share links to their builds without a server storing data
|
||||
|
||||
## Technical Details
|
||||
|
||||
The optimizer has numerous interesting technical features:
|
||||
|
||||
- React SPA without SSR with Vite
|
||||
- Built with Material-UI 5 and Emotion for CSS-in-JS
|
||||
- Statemanagement with ReduxJS
|
||||
- multithreaded calculations with Rust compiled to WASM and WebWorkers
|
||||
- i18n localization (Chinese and German)
|
||||
- hosted on Cloudflare pages utilizing Workers and KV
|
||||
- custom algorithm for lossless state compress based on a schema into base64, url-save strings
|
||||
BIN
src/routes/projects/gw2-gear-optimizer/images/gear-optimizer.png
Normal file
BIN
src/routes/projects/gw2-gear-optimizer/images/gear-optimizer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 568 KiB |
|
|
@ -1,3 +1,6 @@
|
|||
User-agent: *
|
||||
Disallow: /contact
|
||||
Disallow: /admin
|
||||
|
||||
User-agent: GPTBot
|
||||
Disallow: /
|
||||
13
yarn.lock
13
yarn.lock
|
|
@ -551,15 +551,10 @@ callsites@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
caniuse-lite@^1.0.30001400:
|
||||
version "1.0.30001411"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001411.tgz#303c8594ca5903b193a6d875ac613548cb73379a"
|
||||
integrity sha512-HPnJKESKuhKpHvMY1/ux7J3nG7xG8jRuL4lbyCjDRm0doTNV91tcRk60xrP7Ym9DtJH/yuqntDWBJCqpXB4b7g==
|
||||
|
||||
caniuse-lite@^1.0.30001426:
|
||||
version "1.0.30001441"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz#987437b266260b640a23cd18fbddb509d7f69f3e"
|
||||
integrity sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==
|
||||
caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
|
||||
version "1.0.30001534"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz"
|
||||
integrity sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==
|
||||
|
||||
ccount@^2.0.0:
|
||||
version "2.0.1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue