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

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,7 +14,11 @@ export default function Experience() {
{ title },
div(
padding("16px"),
Markdown(experience),
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),
[
display.flex,
flexWrap.wrap,
marginRight("8px"),
paddingBottom("16px"),
gap("8px"),
],
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,
[
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 })