This commit is contained in:
Dan Finch 2026-05-19 22:33:32 +02:00
parent 4999423af4
commit 87019379d7
22 changed files with 441 additions and 166 deletions

View file

@ -5,8 +5,9 @@
"": {
"name": "dan",
"dependencies": {
"98se.css": "../98se.css",
"98se.css": "/err/98se.css",
"@danielx/civet": "^0.11.7",
"@fontsource/roboto-condensed": "^5.2.8",
"@hypeup/client": "workspace:*",
"@hypeup/lexicon": "workspace:*",
"@hypeup/runtime": "workspace:*",
@ -19,6 +20,7 @@
"hypeup": "workspace:*",
"oxfmt": "^0.47.0",
"oxlint": "^1.62.0",
"playwright": "^1.54.1",
},
},
"../../sig/hypeup/packages/babel": {
@ -92,7 +94,6 @@
"@webref/elements": "^2.7.1",
"css-tree": "^3.2.1",
"html-tags": "^5.1.0",
"known-css-properties": "^0.37.0",
},
"devDependencies": {
"@types/bun": "^1.3.13",
@ -158,7 +159,7 @@
},
},
"packages": {
"98se.css": ["98.css@file:../98se.css", { "devDependencies": { "chokidar": "^3.3.1", "cssnano": "^5.0.1", "dedent": "^0.7.0", "ejs": "^3.0.2", "gh-pages": "^2.2.0", "glob": "^7.1.6", "highlight.js": "^10.4.1", "live-server": "^1.2.1", "mkdirp": "^1.0.4", "postcss": "^8.2.12", "postcss-calc": "^7.0.2", "postcss-copy": "^7.1.0", "postcss-css-variables": "^0.14.0", "postcss-inline": "^1.2.0", "postcss-inline-svg": "^4.1.0" } }],
"98se.css": ["98.css@file:../../err/98se.css", { "devDependencies": { "chokidar": "^3.3.1", "cssnano": "^5.0.1", "dedent": "^0.7.0", "ejs": "^3.0.2", "gh-pages": "^2.2.0", "glob": "^7.1.6", "highlight.js": "^10.4.1", "live-server": "^1.2.1", "mkdirp": "^1.0.4", "postcss": "^8.2.12", "postcss-calc": "^7.0.2", "postcss-copy": "^7.1.0", "postcss-css-variables": "^0.14.0", "postcss-inline": "^1.2.0", "postcss-inline-svg": "^4.1.0" } }],
"@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
@ -226,6 +227,8 @@
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@fontsource/roboto-condensed": ["@fontsource/roboto-condensed@5.2.8", "", {}, "sha512-M2OxXXGJQeif+LhxHjWiCEX3BHIYeZf64CcUTeh9AQFGp7DXo2UAXZiZUUOalVdOiuUtQSIi2CDHLDWFiyoECQ=="],
"@hypeup/babel": ["@hypeup/babel@workspace:../../sig/hypeup/packages/babel"],
"@hypeup/client": ["@hypeup/client@workspace:../../sig/hypeup/packages/client"],
@ -610,7 +613,7 @@
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
@ -706,8 +709,6 @@
"kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
"known-css-properties": ["known-css-properties@0.37.0", "", {}, "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ=="],
"lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
@ -832,6 +833,10 @@
"pinkie-promise": ["pinkie-promise@2.0.1", "", { "dependencies": { "pinkie": "^2.0.0" } }, "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw=="],
"playwright": ["playwright@1.60.0", "", { "dependencies": { "playwright-core": "1.60.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA=="],
"playwright-core": ["playwright-core@1.60.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA=="],
"posix-character-classes": ["posix-character-classes@0.1.1", "", {}, "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg=="],
"postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="],
@ -1070,6 +1075,8 @@
"base/define-property": ["define-property@1.0.0", "", { "dependencies": { "is-descriptor": "^1.0.0" } }, "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA=="],
"chokidar/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"class-utils/define-property": ["define-property@0.2.5", "", { "dependencies": { "is-descriptor": "^0.1.0" } }, "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA=="],
"connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
@ -1174,6 +1181,8 @@
"unset-value/has-value": ["has-value@0.3.1", "", { "dependencies": { "get-value": "^2.0.3", "has-values": "^0.1.4", "isobject": "^2.0.0" } }, "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q=="],
"vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"class-utils/define-property/is-descriptor": ["is-descriptor@0.1.8", "", { "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" } }, "sha512-SceYGWXvdqlWa/OnQ5FQuV+NxvNmMRhMw/w9AHkH71hTzveND4BTYgvp16g+oITK47qbOl/3D0bl0iygehWAWQ=="],

6
compose.yml Normal file
View file

@ -0,0 +1,6 @@
name: da.nfin.ch
services:
printer:
image: gotenberg/gotenberg:8
ports:
- "3000:3000"

BIN
cv.pdf Normal file

Binary file not shown.

View file

@ -2,13 +2,6 @@
"name": "da.nfin.ch",
"private": true,
"type": "module",
"devDependencies": {
"@types/bun": "^1.3.13",
"@typescript/native-preview": "beta",
"oxfmt": "^0.47.0",
"oxlint": "^1.62.0",
"hypeup": "workspace:*"
},
"license": "MIT",
"author": {
"name": "Sigitex",
@ -18,31 +11,42 @@
"type": "git",
"url": "git+https://github.com/sigitex/da.nfin.ch.git"
},
"files": [
"src"
],
"scripts": {
"check": "tsgo --build",
"test": "bun test --pass-with-no-tests --tsconfig-override tsconfig.test.json",
"lint": "oxlint",
"start": "hypeup generate --watch",
"build": "hypeup generate",
"publish:main": "rsync -avz --delete dist/ da.nfin.ch:~/da.nfin.ch",
"build": "bun run build:site && bun run build:cv",
"build:site": "hypeup generate",
"build:cv": "bun scripts/build-cv.ts",
"publish:site": "rsync -avz --delete dist/ da.nfin.ch:~/da.nfin.ch",
"publish:errilaz": "rsync -avz --delete errilaz.org/ da.nfin.ch:~/errilaz.org",
"publish": "bun run publish:main && bun run publish:errilaz"
},
"files": [
"src"
],
"workspaces": {
"packages": [
"/sig/hypeup/packages/*"
]
"publish": "bun run publish:site && bun run publish:errilaz"
},
"dependencies": {
"98se.css": "/err/98se.css",
"@danielx/civet": "^0.11.7",
"@fontsource/roboto-condensed": "^5.2.8",
"@hypeup/client": "workspace:*",
"@hypeup/lexicon": "workspace:*",
"@hypeup/runtime": "workspace:*",
"marked": "^18.0.3",
"marked-gfm-heading-id": "^4.1.4"
},
"devDependencies": {
"@types/bun": "^1.3.13",
"@typescript/native-preview": "beta",
"oxfmt": "^0.47.0",
"oxlint": "^1.62.0",
"hypeup": "workspace:*",
"playwright": "^1.54.1"
},
"workspaces": {
"packages": [
"/sig/hypeup/packages/*"
]
}
}

10
scripts/build-cv.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
mkdir -p dist
thorium-browser \
--headless=new \
--no-sandbox \
--disable-gpu \
--virtual-time-budget=5000 \
--align-pdf-default-print-settings-with-html \
--print-to-pdf="dist/cv.pdf" \
"http://localhost:5173/cv"

41
scripts/build-cv.ts Normal file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env bun
import { mkdir } from "node:fs/promises"
import { dirname } from "node:path"
import { chromium } from "playwright"
const url = "file:///finch/da.nfin.ch/dist/cv.html"
const output = "dist/cv.pdf"
await mkdir(dirname(output), { recursive: true })
const executablePath =
process.env.CHROMIUM_PATH ??
Bun.which("thorium-browser") ??
Bun.which("chromium") ??
Bun.which("chromium-browser") ??
Bun.which("google-chrome") ??
undefined
const browser = await chromium.launch({
executablePath,
headless: true,
args: ["--no-sandbox", "--disable-gpu"],
})
try {
const page = await browser.newPage()
await page.goto(url, {
waitUntil: "networkidle",
timeout: 30_000,
})
await page.pdf({
path: output,
printBackground: true,
displayHeaderFooter: false,
preferCSSPageSize: true,
})
} finally {
await browser.close()
}

1
src/routes/cv.html.ts Normal file
View file

@ -0,0 +1 @@
export { default } from "ui/CV"

192
src/ui/CV/CV.ts Normal file
View file

@ -0,0 +1,192 @@
import Reset from "ui/Layout/Reset"
import Markdown from "ui/shared/Markdown"
import intro from "ui/Home/intro.md?raw"
import details from "ui/Home/details.md?raw"
import skills from "ui/Home/skills.md?raw"
import experience from "ui/Experience/experience.md?raw"
import Sections from "ui/Tech/Sections"
import roboto from "@fontsource/roboto-condensed?url"
const Color = {
backdrop: "#f0f0f0",
edge: "#808080",
} as const
export default function CV() {
return [
doctype.html5,
html(
head(
link({ rel: "stylesheet", href: roboto }),
style(
Reset(),
rule.pdf(
display.flex,
width("50px"),
height("50px"),
borderRadius("12px"),
backgroundColor("#345c42"),
color.white,
position.fixed,
top("25px"),
right("25px"),
justifyContent.center,
alignItems.center,
fontWeight.bold,
textDecoration.none,
),
$page(
prop("size", "auto"),
margin("0 0 0 0"),
padding("0.5in"),
),
rule(body, [
fontFamily("Roboto Condensed"),
fontSize("12pt"),
display.flex,
justifyContent.center,
backgroundColor(Color.backdrop),
]),
$media("print", [
rule(body, backgroundColor.white),
rule.noprint(display.none),
]),
rule(main, [
backgroundColor.white,
width("8.5in"),
display.flex,
justifyContent.center,
paddingBottom("32pt"),
]),
rule(article, [width("7.0in")]),
rule(header, [
marginTop("0.5in"),
display.flex,
justifyContent.spaceBetween,
alignItems.flexEnd,
paddingBottom("8pt"),
]),
rule(h1, fontSize("28pt")),
rule.links(
fontSize("11pt"),
width("2.75in"),
display.flex,
justifyContent.spaceBetween,
alignItems.center,
rule(">div", [
display.flex,
flexDirection.column,
gap("2pt"),
]),
),
rule.contact(
alignItems.flexEnd,
fontSize("12pt"),
),
rule(section, [
borderTop(`double 3px ${Color.edge}`),
paddingTop("16pt"),
paddingBottom("16pt"),
]),
rule(h2, [marginBottom("12pt")]),
rule(p, [marginTop("12pt")]),
rule(ul, [marginTop("12pt")]),
rule(hr, [
margin("12pt 0"),
borderColor("#f0f0f0"),
]),
rule(".experience .content h2", [
fontSize("14pt"),
]),
rule.expertise(
pageBreakInside.avoid,
rule(ul, marginBottom("12pt")),
rule.blocks(columns(3)),
rule.block(
flex(1),
minWidth("3in"),
breakInside.avoid,
),
),
),
),
body(
main(
article(
Header(),
About(),
Skills(),
Experience(),
Expertise(),
),
),
a.pdf.noprint({ href: "cv.pdf" }, "PDF"),
),
),
]
}
function Header() {
return header(
h1("Dan Finch"),
div.links(
div.www(
a({ href: "https://da.nfin.ch" }, "Website"),
a(
{ href: "https://www.sigitex.com" },
"Open Source",
),
a(
{
href: "https://www.linkedin.com/in/danfinch",
},
"LinkedIn",
),
),
div.contact(
a(
{ href: "mailto:danfinch@outlook.com" },
"danfinch@outlook.com",
),
a({ href: "tel:+436645047583" }, "+43 664 5047583"),
),
),
)
}
function About() {
return section.about(
h2("About Me"),
Markdown(intro),
Markdown(details),
)
}
function Skills() {
return section.skills(h2("Skills"), Markdown(skills))
}
function Experience() {
return section.experience(
h2("Experience"),
Markdown(experience),
)
}
function Expertise() {
return section.expertise(
h2("Expertise"),
div.blocks(
Skillset("Languages", Sections.languages),
Skillset("Platforms", Sections.platforms),
Skillset("Data", Sections.data),
Skillset("Frontend", Sections.frontend),
Skillset("Backend", Sections.backend),
Skillset("Concepts", Sections.concepts),
),
)
}
function Skillset(name: string, content: string) {
return div.block(h3(name), Markdown(content))
}

1
src/ui/CV/index.ts Normal file
View file

@ -0,0 +1 @@
export { default } from "./CV"

View file

@ -14,9 +14,13 @@ export default function Experience() {
{ title },
div(
padding("16px"),
div.content(
h1("My Experience"),
hr(),
Markdown(experience),
),
),
),
),
]
}

View file

@ -1,7 +1,3 @@
# My Experience
---
## Dynatrace - Senior Software Engineer
> July 2023 - Present (Graz, Austria - Hybrid)
@ -80,7 +76,7 @@ operations, testing, maintenance, and security.
- Created complex e-commerce website featuring retail and affiliate marketing management. Owner of dozens of projects within the company.
- Configured and managed production web servers including Microsoft IIS and LAMP stack.
- Worked closely with DBA on data-driven applications powered by SQL Server 2008 and ADO.NET.
- Analyzed and selected supporting software and services, including early adoption of technologies such as ASP.NET MVC, jQuery, F#, Amazon Web Services, and distributed source control.
- Analyzed and selected supporting software and services, including early adoption of technologies such as ASP.NET MVC, jQuery, F#, AWS, and distributed source control.
- Developed solutions using Service Oriented Architecture (SOA), WCF, and Windows services. Integrated software with various cloud data and web service providers, including AWS, Authorize.NET, and Zencoder.
- Studied and implemented e-commerce best practices, web security standards, and PCI compliance.

View file

@ -1,6 +1,9 @@
import Layout from "ui/Layout"
import Markdown from "ui/shared/Markdown"
import about from "./about.md?raw"
import intro from "./intro.md?raw"
import details from "./details.md?raw"
import skills from "./skills.md?raw"
import interests from "./interests.md?raw"
import Window from "ui/Layout/Window"
const title = "Dan Finch - About Me"
@ -8,6 +11,20 @@ const title = "Dan Finch - About Me"
export default function Home() {
return Layout(
{ title, url: "/" },
Window({ title }, div(padding("8px"), Markdown(about))),
Window(
{ title },
div.content(padding("8px"), [
h1("About Me"),
Markdown(intro),
aside.fieldBorderDisabled(
img({ src: "/pfp.jpg", width: "200" }),
),
Markdown(details),
h2("Skills"),
Markdown(skills),
h2("Interests"),
Markdown(interests),
]),
),
)
}

View file

@ -1,29 +0,0 @@
# About Me
I own software end-to-end: building or renewing stacks and evaluating the tools and techniques that will serve the product well. I assist my teams in creating frameworks, automation, standards, and guidance that clear the path to delivering good software and user experiences. I am comfortable working hands-on across code, architecture, UX, and product.
<aside class="field-border-disabled"><img src="/pfp.jpg" width="200"></aside>
My first principle is **user experience**. Software is interesting because of what it can do for people, and we all put up with mediocre software every day. This dissatisfaction drives me to set a high standard for our work.
As a programmer, I've learned to make code **small, simple, and readable**. My aim is prolific and expeditious code output while maintaining quality. I make loosely-coupled components, understandable abstractions, and low-ceremony frameworks.
As a teammate and leader, I am devoted to **friendliness** and **respect**. I am a good communicator, love sharing my knowledge, and learning from others. I've given talks at local user groups and mentored at work and in my free time.
## Skills
- Consciousness of mainstream & emerging technology and trends.
- Quickly vetting and adapting to new technologies - building and improving stacks.
- High standards for great user and developer experiences.
- Interacting directly and empathetically with stakeholders and end users.
- Managing work through all phases of a development cycle.
- Eliminating friction in processes through automation.
- Understanding all the areas of a codebase and recognizing where waste can be reduced.
- Coordinating large, complex upgrades and refactors.
## Interests
- Compilers, interpreters & parsers.
- Metaprogramming, language-oriented programming.
- Developer tools - hacking on build tools and bundlers.
- Automating self-hosted cloud tech.

5
src/ui/Home/details.md Normal file
View file

@ -0,0 +1,5 @@
My first principle is **user experience**. Software is interesting because of what it can do for people, and we all put up with mediocre software every day. This dissatisfaction drives me to set a high standard for our work.
As a programmer, I've learned to make code **small, simple, and readable**. My aim is prolific and expeditious code output while maintaining quality. I make loosely-coupled components, understandable abstractions, and low-ceremony frameworks.
As a teammate and leader, I am devoted to **friendliness** and **respect**. I am a good communicator, love sharing my knowledge, and learning from others. I've given talks at local user groups and mentored at work and in my free time.

4
src/ui/Home/interests.md Normal file
View file

@ -0,0 +1,4 @@
- Compilers, interpreters & parsers.
- Metaprogramming, language-oriented programming.
- Developer tools - hacking on build tools and bundlers.
- Automating self-hosted cloud tech.

1
src/ui/Home/intro.md Normal file
View file

@ -0,0 +1 @@
I own software end-to-end: building or renewing stacks and evaluating the tools and techniques that will serve the product well. I assist my teams in creating frameworks, automation, standards, and guidance that clear the path to delivering good software and user experiences. I am comfortable working hands-on across code, architecture, UX, and product.

8
src/ui/Home/skills.md Normal file
View file

@ -0,0 +1,8 @@
- Consciousness of mainstream & emerging technology and trends.
- Quickly vetting and adapting to new technologies - building and improving stacks.
- High standards for great user and developer experiences.
- Interacting directly and empathetically with stakeholders and end users.
- Managing work through all phases of a development cycle.
- Eliminating friction in processes through automation.
- Understanding all the areas of a codebase and recognizing where waste can be reduced.
- Coordinating large, complex upgrades and refactors.

View file

@ -17,16 +17,15 @@ export default function Theme() {
display.flex,
alignItems.center,
]),
rule("h1", fontSize("20px")),
rule("h2", fontSize("16px")),
rule("ul", paddingInlineStart("30px")),
rule(
".markdown",
rule(h1, fontSize("20px")),
rule(h2, fontSize("16px")),
rule(ul, paddingInlineStart("30px")),
rule.content(
textAlign.justify,
fontFamily("Arial"),
fontSize("14px"),
rule("h1", fontSize("28px")),
rule("h2", fontSize("20px")),
rule(h1, fontSize("28px")),
rule(h2, fontSize("20px")),
rule(aside,
float.right,
marginLeft("20px"),

78
src/ui/Tech/Sections.ts Normal file
View file

@ -0,0 +1,78 @@
export default {
languages: `
- TypeScript
- JavaScript
- C#
- F#
- SQL
`,
platforms: `
- Node.js
- Deno
- Bun
- HTML + CSS
- Linux
- Electron
- Browser Extensions
- React Native
- .NET Core
- .NET Framework
`,
frontend: `
- React
- Vite
- Zustand
- Immer
- Webpack
- Parcel
- Emotion
- Styled Components
- Mithril
- Redux
- React Router
- React Query
- Vanilla Extract
- CSS Modules
- SCSS, Stylus, Less
`,
backend: `
- Express
- Koa
- ASP.NET
- Fastify
- Hapi
- NestJS
- Docker
- Cloudflare
- Firebase
- Supabase
- AWS
- GitHub Actions
`,
data: `
- Postgres
- Redis
- Sqlite
- MongoDB
- MySQL
- ElasticSearch
- SQL Server
`,
concepts: `
- Domain-driven design (DDD)
- TDD & BDD
- Unit testing
- E2E testing
- Object-Oriented Programming (OOP)
- Functional Programming (FP)
- SOLID Principles
- REST & Microservices
- CI/CD, Infrastructure as Code
- RDBMS
- NoSQL
- Agile & Scrum
- Unix philosophy
- Responsive design
- IoC & Dependency Injection
`,
}

View file

@ -1,6 +1,7 @@
import Layout from "ui/Layout"
import Window from "ui/Layout/Window"
import Markdown from "ui/shared/Markdown"
import Sections from "./Sections"
const title = "Dan Finch - Tech"
@ -10,18 +11,22 @@ export default function Tech() {
Window(
{ title, flat: true },
div(
[
display.flex,
flexWrap.wrap,
marginRight("8px"),
paddingBottom("16px"),
gap("8px"),
Skillset("Languages", languages),
Skillset("Platforms", platforms),
Skillset("Frontend", frontend),
Skillset("Backend", backend),
Skillset("Data", data),
Skillset("Cloud / Infra / DevOps", cloud),
Skillset("Methodologies & Concepts", concepts),
],
Skillset("Languages", Sections.languages),
Skillset("Platforms", Sections.platforms),
Skillset("Frontend", Sections.frontend),
Skillset("Backend", Sections.backend),
Skillset("Data", Sections.data),
Skillset(
"Methodologies & Concepts",
Sections.concepts,
),
),
),
)
@ -29,91 +34,13 @@ export default function Tech() {
function Skillset(title: string, markdown: Content) {
return div(
[
flex(1),
minWidth("250px"),
display.flex,
flexDirection.column,
],
h2(title),
div.fieldBorder(flex(1), Markdown(markdown)),
)
}
const languages = `
- TypeScript
- JavaScript
- C#
- F#
- SQL
`
const platforms = `
- Node.js / Deno / Bun
- HTML + CSS
- .NET & .NET Core
- Linux
- Electron
- Browser Extensions
- React Native
- Cloudflare Workers
`
const frontend = `
- React
- Vite
- Zustand
- Immer
- Webpack
- Parcel
- Emotion / Styled Components
- Mithril
- Redux
- React Router
- TanStack Query, React Query
- Vanilla Extract
- SCSS, Stylus, Less, CSS Modules
- Lodash, Immer, RxJS, Kefir
`
const backend = `
- Express
- Koa
- ASP.NET
- Fastify
- Hapi
- Nest
`
const data = `
- Postgres
- Redis
- Sqlite
- MongoDB
- MySQL
- ElasticSearch
- SQL Server
`
const cloud = `
- Docker
- Cloudflare
- Firebase
- Supabase
- AWS
- GitHub Actions
`
const concepts = `
- Domain-driven design (DDD)
- TDD & BDD, unit testing, & E2E testing
- Object-Oriented Programming (OOP)
- Functional Programming (FP)
- SOLID Principles
- REST & Microservices
- CI/CD, Infrastructure as Code
- RDBMS
- NoSQL
- Agile & Scrum
- Unix philosophy
- Responsive design
- IoC & Dependency Injection
`

View file

@ -2,7 +2,7 @@ import { Marked } from "marked"
import { gfmHeadingId } from "marked-gfm-heading-id"
export default function Markdown(md: string) {
return div.markdown(raw(marked.parse(md)))
return div.content(raw(marked.parse(md)))
}
const marked = new Marked({ gfm: true })

View file

@ -8,7 +8,8 @@
},
"include": [
"*.config.ts",
"*.config.cjs"
"*.config.cjs",
"scripts/*.ts"
],
"files": []
}