feat: new website

This commit is contained in:
Dan Finch 2026-05-13 02:03:11 +02:00
commit 003752be95
53 changed files with 2532 additions and 0 deletions

1
src/ambient.d.ts vendored Normal file
View file

@ -0,0 +1 @@
import "@hypeup/lexicon"

View file

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

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

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

View file

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

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

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

4
src/types.d.ts vendored Normal file
View file

@ -0,0 +1,4 @@
declare type Content = any
declare module "*?raw" { const src: string; export default src }
declare module "*?url" { const src: string; export default src }

View file

@ -0,0 +1,22 @@
import Layout from "ui/Layout"
import Window from "ui/Layout/Window"
import Markdown from "ui/shared/Markdown"
import experience from "./experience.md?raw"
const title = "Dan Finch - Experience"
export default function Experience() {
return [
backgroundColor.white,
Layout(
{ title, url: "/experience" },
Window(
{ title },
div(
padding("16px"),
Markdown(experience),
),
),
),
]
}

View file

@ -0,0 +1,95 @@
# My Experience
---
## Dynatrace - Senior Software Engineer
> July 2023 - Present (Graz, Austria - Hybrid)
- Implemented an array of features and bug fixes for several Business Analytics applications using **React** and **TypeScript**.
- Designed and implemented a strongly-typed embedded DSL to generate the data warehouse queries which power the apps, significantly reducing maintenance overhead.
- Created an end-to-end testing framework suite based on **Playwright** that substantially streamlined writing and running tests.
- Created and integrated a state management framework based on **Zustand** and **Immer** which greatly simplified and optimized front-end code.
- Initiated ongoing effort to improve code quality and project structure.
- Migrated a large project from Bitbucket+Jenkins to Github+Actions.
---
## Independent Consultant
> Dec 2014 - July 2023 (Remote)
My freelance work in this time included:
- Created a mobile social network app for a startup conference and shared working space provider. This was written in functional **TypeScript** and **React Native**, with some Python/Django and Postgres on a Heroku backend.
- Consulted on JavaScript and front-end tech for Bitbanger Labs for their ColorSpike hybrid mobile app built on Cordova.
- Wrote a Chrome extension using the **Mithril** framework to inspect advertisements embedded in web pages for Bringhub.
- Designed and prototyped an app and backend for a IOT equipment monitoring startup in Sandpoint, ID using **React**, **ElasticSearch**, and **Postgres**.
- Created an **Electron** app connected to the QuickBooks API to build quotes for a greenhouse manufacturer.
---
## RiskLens - Senior Software Engineer
> Jun 2017 - Dec 2017 (Spokane, WA)
Helped lead the front-end development of FAIR-U - a **React** + **Redux**-based app backed by **C\#**, Sql Server, and
Azure & transitioned the team to TypeScript and other modern front-end tools. Gained experience with a
security-focused and process-intensive team.
---
## TenX Logic - Contract Developer
> Oct 2015 - Mar 2016 (Remote)
This project for the oil + gas industry targeted the Mono platform on ARM processors. I designed and
implemented a **C\#**-based driver model to control equipment in the field, with a frontend written in AngularJS.
---
## Kochava - Senior Developer
> Apr 2014 - Nov 2014 (Sandpoint, ID)
Worked on infrastructure and systems to manage large volumes of real-time analytics data. I tackled
complex challenges requiring constant inventiveness and collaboration to help the company scale at
a rapid rate.
My work centered around **Node.js**, **Redis**, Linux, and **MongoDB**. I also led the early implementation of a
scalable high-traffic analytics backend.
---
## Coldwater Creek - Web Developer
> Oct 2012 - Apr 2014 (Sandpoint, ID)
Worked with many teams to finish an amazing number of projects. My work on both internal tooling and
customer experience put the company ahead of its industry in many respects.
- Implemented a product search which outperformed all competitors, including a novel infinite scrolling method.
- Provided an array of features and user interfaces widgets for website with around one million hits per day.
- Wrote or re-wrote around 30 internal web-driven tools for e-commerce & marketing teams.
- Wrote custom jQuery UI powered framework and widgets for tool suite.
- Initiated effort to significantly improve client-side page load performance.
- Created a framework allowing mutual embedding between MVC and WebForms to allow a smooth transition off of legacy code.
---
## Promitheia - Technical Director
> Sep 2006 - Sep 2012 (Austin, TX)
As co-founder of this startup I was responsible for software design, programming, project management,
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.
- 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.
---
## Mercury ML - Founder
> 2002 - 2004 (Lapeer, MI)
I got my start right out of high school helping to scale two companies out of working with unwieldy spreadsheets.
- Released two major versions of a VB6 application to catalog marketing affiliates, track orders, and calculate payouts.
- Wrote and administered affiliate websites in Classic ASP and VBScript.

View file

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

13
src/ui/Home/Home.ts Normal file
View file

@ -0,0 +1,13 @@
import Layout from "ui/Layout"
import Markdown from "ui/shared/Markdown"
import about from "./about.md?raw"
import Window from "ui/Layout/Window"
const title = "Dan Finch - About Me"
export default function Home() {
return Layout(
{ title, url: "/" },
Window({ title }, div(padding("8px"), Markdown(about))),
)
}

29
src/ui/Home/about.md Normal file
View file

@ -0,0 +1,29 @@
# 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.

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

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

19
src/ui/Layout/Head.ts Normal file
View file

@ -0,0 +1,19 @@
const DEFAULT_TITLE = "Dan Finch"
export default function Head(props: { title: string }, ...contents: Content[]) {
return head(
meta({ charset: "UTF-8" }),
meta({
name: "viewport",
content: "width=device-width",
"initial-scale": "1.0",
}),
link({
rel: "shortcut icon",
type: "image/png",
href: "/favicon.png",
}),
title(props.title || DEFAULT_TITLE),
contents,
)
}

50
src/ui/Layout/Layout.ts Normal file
View file

@ -0,0 +1,50 @@
import Head from "./Head"
import background from "assets/background.js?raw"
import css98 from "98se.css?url"
import Taskbar from "ui/Layout/Taskbar"
import Theme from "ui/Layout/Theme"
export default function Layout(
props: { title: string, url: string },
...contents: Content[]
) {
return [
doctype.html5,
html(
Head(props, [
link({ rel: "stylesheet", href: css98 }),
style(Theme()),
]),
body(
backgroundColor.black,
canvas(
{ id: "background" },
display.block,
position.fixed,
width("100%"),
height("100%"),
left(0),
top(0),
zIndex(-1),
),
div(
display.flex,
flexDirection.column,
height("100vh"),
nav(
height.maxContent,
Taskbar({ url: props.url }),
),
main(
flex(1),
overflowY.hidden,
display.flex,
justifyContent.center,
contents,
)
)
),
script(raw(background)),
),
]
}

14
src/ui/Layout/Reset.ts Normal file
View file

@ -0,0 +1,14 @@
export default function Reset() {
return [
rule("*, *::before, *::after", [boxSizing.borderBox]),
rule("*:not(dialog)", [margin(0)]),
rule(
"input, button, textarea, select",
font("inherit"),
),
rule(
"p, h1, h2, h3, h4, h5, h6",
overflowWrap.breakWord,
),
]
}

101
src/ui/Layout/Taskbar.ts Normal file
View file

@ -0,0 +1,101 @@
import favicon from "public/favicon.png?url"
import linkedin from "public/icons/linkedin.svg?raw"
import github from "public/icons/github.svg?raw"
import aboutIcon from "public/icons/about.png?url"
import experienceIcon from "public/icons/experience.png?url"
import projectsIcon from "public/icons/projects.png?url"
import techIcon from "public/icons/tech.png?url"
const vr = hr(height("20px"), margin("0px 2px"))
export default function Taskbar({ url }: { url: string }) {
return div.window(
textWrapMode.nowrap,
overflowX.hidden,
margin("10px"),
div(
display.flex,
alignItems.center,
gap("2px"),
div(
display.flex,
paddingLeft("4px"),
img(
{ src: favicon },
width("12px"),
height("12px"),
marginRight("4px"),
),
div(fontWeight.bold, "Dan Finch"),
),
vr,
a(
{ title: "LinkedIn" },
{ href: "https://www.linkedin.com/in/danfinch/" },
raw(linkedin),
),
a(
{ title: "GitHub" },
{ href: "https://github.com/errilaz" },
raw(github),
),
vr,
Task({
icon: aboutIcon,
title: "About",
href: "/",
active: url === "/",
}),
Task({
icon: projectsIcon,
title: "Projects",
href: "/projects",
active: url === "/projects",
}),
Task({
icon: experienceIcon,
title: "Experience",
href: "/experience",
active: url === "/experience",
}),
Task({
icon: techIcon,
title: "Tech",
href: "/tech",
active: url === "/tech",
}),
),
)
}
function Task({
icon,
title,
href,
active,
}: {
icon: string
title: Content
href?: string
active?: boolean
}) {
return a.button(
{ href },
active && className("active"),
padding("0 4px"),
textAlign.left,
div(
width("100%"),
pad("4px"),
display.flex,
justifyContent.flexStart,
img(
{ src: icon },
width("12px"),
height("12px"),
marginRight("4px"),
),
span(title),
),
)
}

34
src/ui/Layout/Theme.ts Normal file
View file

@ -0,0 +1,34 @@
import Reset from "./Reset"
export default function Theme() {
return [
Reset(),
rule("a.button", [
textDecoration("none"),
cursor("default"),
display.flex,
alignItems.center,
]),
rule("h1", fontSize("20px")),
rule("h2", fontSize("16px")),
rule("ul",
paddingInlineStart("30px"),
),
rule(
".markdown",
textAlign.justify,
fontFamily("Arial"),
fontSize("14px"),
rule("h1", fontSize("28px")),
rule("h2", fontSize("20px")),
rule(
"aside",
float.right,
marginLeft("20px"),
paddingBottom(0),
),
rule("p, h1, h2, h3, ul", margin("12px 0")),
),
rule("iframe", border(0)),
]
}

33
src/ui/Layout/Window.ts Normal file
View file

@ -0,0 +1,33 @@
const DEFAULT_WIDTH = "770px"
export default function Window(
props: { title: string; width?: Content; flat?: boolean },
...contents: Content[]
) {
return article.window(
opacity(0.9),
marginTop("16px"),
marginBottom("24px"),
marginLeft("10px"),
marginRight("10px"),
width(props.width ?? DEFAULT_WIDTH),
maxWidth(props.width ?? DEFAULT_WIDTH),
minHeight("200px"),
display.flex,
flexDirection.column,
div.titleBar(
div.titleBarText(props.title),
div.titleBarControls(
button({ "aria-label": "Minimize" }),
button({ "aria-label": "Maximize" }),
button({ "aria-label": "Close" }),
),
),
div.windowBody(
props.flat ? null : className("field-border"),
flex(1),
overflowY.auto,
contents,
),
)
}

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

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

View file

@ -0,0 +1,17 @@
import Layout from "ui/Layout"
import Window from "ui/Layout/Window"
const title = "Dan Finch - Projects"
export default function Projects() {
return Layout(
{ title, url: "/projects" },
Window(
{ title },
display.flex,
iframe({ src: "https://sigitex.com" },
flex(1)
),
),
)
}

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

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

119
src/ui/Tech/Tech.ts Normal file
View file

@ -0,0 +1,119 @@
import Layout from "ui/Layout"
import Window from "ui/Layout/Window"
import Markdown from "ui/shared/Markdown"
const title = "Dan Finch - Tech"
export default function Tech() {
return Layout(
{ title, url: "/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),
),
),
)
}
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
`

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

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

View file

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