diff --git a/bun.lock b/bun.lock index fc4f9b5..5f50328 100644 --- a/bun.lock +++ b/bun.lock @@ -46,6 +46,7 @@ "packages/webapp": { "name": "@website/webapp", "dependencies": { + "@fontsource/permanent-marker": "^5.3.0", "@fontsource/work-sans": "^5.2.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tooltip": "^1.2.8", @@ -231,6 +232,8 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@fontsource/permanent-marker": ["@fontsource/permanent-marker@5.3.0", "", {}, "sha512-ZO/NtYW4SCc/iY8N3dmjWyDITcXJ/vhWZFgnwRcvzwCKKnScMrM/a2/6VHlsjCVuIgmPzNrCFbedEYhv+/jJBg=="], + "@fontsource/work-sans": ["@fontsource/work-sans@5.2.8", "", {}, "sha512-6LaHjVVgts+rnrcqvEkP2+iUB/jw1oDSYsGO0+TltAhnWki9Hnf/UGpgMQh2jcm0GEH8VqCPnq4PpmHLFzxXtQ=="], "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "^0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], diff --git a/packages/webapp/package.json b/packages/webapp/package.json index 0f7e22d..70d5dd1 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -14,6 +14,7 @@ "clean:modules": "rm -rf node_modules" }, "dependencies": { + "@fontsource/permanent-marker": "^5.3.0", "@fontsource/work-sans": "^5.2.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tooltip": "^1.2.8", diff --git a/packages/webapp/public/logos/effect-lens.svg b/packages/webapp/public/logos/effect-lens.svg new file mode 100644 index 0000000..379e92a --- /dev/null +++ b/packages/webapp/public/logos/effect-lens.svg @@ -0,0 +1,64 @@ + + Effect Lens + The layered Effect mark beneath a magnifying glass that highlights lines of code. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/webapp/public/logos/effect-view.svg b/packages/webapp/public/logos/effect-view.svg new file mode 100644 index 0000000..6cacede --- /dev/null +++ b/packages/webapp/public/logos/effect-view.svg @@ -0,0 +1,36 @@ + + Effect View + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/webapp/src/components/portfolio/ProjectCard.tsx b/packages/webapp/src/components/portfolio/ProjectCard.tsx index 6f95e3a..25a0141 100644 --- a/packages/webapp/src/components/portfolio/ProjectCard.tsx +++ b/packages/webapp/src/components/portfolio/ProjectCard.tsx @@ -1,4 +1,5 @@ import { ArrowUpRight } from "lucide-react" +import type { ReactNode } from "react" interface ProjectCardProps { readonly index: string @@ -9,6 +10,9 @@ interface ProjectCardProps { readonly href?: string readonly linkLabel?: string readonly variant?: "light" | "dark" | "outline" + readonly accent?: "teal" | "violet" | "chef" + readonly logo?: ReactNode + readonly categoryIcon?: ReactNode } export function ProjectCard({ @@ -20,15 +24,21 @@ export function ProjectCard({ href, linkLabel = "View project", variant = "light", + accent, + logo, + categoryIcon, }: ProjectCardProps) { return ( -
+
{index} - {category} + {categoryIcon}{category}
+ {logo &&
{logo}
}

{title}

{description}

diff --git a/packages/webapp/src/index.css b/packages/webapp/src/index.css index 11ebd0d..4c0ade2 100644 --- a/packages/webapp/src/index.css +++ b/packages/webapp/src/index.css @@ -6,6 +6,7 @@ @import "@fontsource/work-sans/600.css"; @import "@fontsource/work-sans/700.css"; @import "@fontsource/work-sans/800.css"; +@import "@fontsource/permanent-marker/400.css"; @font-face { font-family: "Pixelated MS Sans Serif"; @@ -141,7 +142,7 @@ button:hover { .site-rail nav a { display: grid; - grid-template-columns: 28px 1fr; + grid-template-columns: 18px 28px 1fr; align-items: center; min-height: 42px; padding: 0 18px; @@ -151,6 +152,11 @@ button:hover { text-transform: uppercase; } +.site-rail nav a > svg { + width: 13px; + height: 13px; +} + .site-rail nav a span { color: var(--muted); font-family: "Pixelated MS Sans Serif", monospace; @@ -259,6 +265,17 @@ button:hover { text-transform: uppercase; } +.hero__kicker { + display: inline-flex; + align-items: center; + gap: 7px; +} + +.hero__kicker svg { + width: 14px; + height: 14px; +} + .hero h1 { max-width: 720px; margin: 26px 0 22px; @@ -439,6 +456,9 @@ button:hover { } .capability-strip li { + display: inline-flex; + align-items: center; + gap: 7px; padding: 12px 16px; border-right: 1px solid #555; font-size: 10px; @@ -447,6 +467,11 @@ button:hover { text-transform: uppercase; } +.capability-strip svg { + width: 13px; + height: 13px; +} + .work-section, .upcoming-section, .repo-section { @@ -531,6 +556,27 @@ button:hover { var(--paper); } +.project-card--teal { + border-top: 5px solid #08777b; + background: + radial-gradient(circle at 100% 100%, rgb(240 161 59 / 22%), transparent 42%), + linear-gradient(145deg, #f8ffff, #e4f4f2); +} + +.project-card--violet { + border-top: 5px solid #6e56cf; + background: + radial-gradient(circle at 100% 100%, rgb(36 214 231 / 20%), transparent 42%), + linear-gradient(145deg, #fbfaff, #ede8ff); +} + +.project-card--chef { + border-top: 5px solid #d59c8d; + background: + radial-gradient(circle at 100% 100%, rgb(213 156 141 / 22%), transparent 42%), + linear-gradient(145deg, #fffdfa, #f7eeea); +} + .project-card__topline { display: flex; justify-content: space-between; @@ -543,8 +589,62 @@ button:hover { text-transform: uppercase; } +.project-card__category { + display: inline-flex; + align-items: center; + justify-content: flex-end; + gap: 5px; + text-align: right; +} + +.project-card__category svg { + width: 12px; + height: 12px; +} + .project-card__body { - margin: 34px 0; + margin: 28px 0 32px; +} + +.project-card__logo { + display: flex; + width: 66px; + height: 66px; + align-items: center; + justify-content: center; + margin-bottom: 20px; +} + +.project-card__logo img { + display: block; + width: 100%; + height: 100%; + border-radius: 15px; + box-shadow: 3px 3px 0 rgb(0 0 0 / 20%); +} + +.comme-le-chef-logo { + display: flex; + width: 66px; + height: 66px; + flex-direction: column; + align-items: flex-start; + justify-content: center; + padding: 8px 6px; + border: 2px solid var(--ink); + background: #fffaf7; + box-shadow: 3px 3px 0 #d59c8d; + font-family: "Permanent Marker", "Comic Sans MS", cursive; + font-size: 17px; + letter-spacing: -0.07em; + line-height: 0.78; + text-transform: uppercase; + transform: rotate(-2deg); +} + +.comme-le-chef-logo span:last-child { + margin-left: 10px; + font-size: 15px; } .project-card h3 { @@ -809,6 +909,7 @@ button:hover { .site-rail__meta, .site-rail nav p, .site-rail nav a span, + .site-rail nav a svg, .site-header { display: none; } diff --git a/packages/webapp/src/routes/_main.index.tsx b/packages/webapp/src/routes/_main.index.tsx index 36b4cad..f9117ff 100644 --- a/packages/webapp/src/routes/_main.index.tsx +++ b/packages/webapp/src/routes/_main.index.tsx @@ -1,5 +1,23 @@ import { createFileRoute } from "@tanstack/react-router" -import { ArrowDown, ArrowUpRight, Code2, GitBranch } from "lucide-react" +import { + AppWindow, + ArrowDown, + ArrowUpRight, + BriefcaseBusiness, + ChefHat, + Code2, + CodeXml, + Database, + GitBranch, + Hammer, + Home, + Library, + MapPin, + PackageOpen, + PanelsTopLeft, + Radio, + UserRound, +} from "lucide-react" import { useEffect, useState } from "react" import { ProjectCard } from "@/components/portfolio/ProjectCard" import { SectionHeading } from "@/components/portfolio/SectionHeading" @@ -10,11 +28,11 @@ export const Route = createFileRoute("/_main/")({ }) const sections = [ - { id: "top", number: "00", label: "Home" }, - { id: "work", number: "01", label: "Selected work" }, - { id: "workbench", number: "02", label: "Workbench" }, - { id: "about", number: "03", label: "About" }, - { id: "repositories", number: "04", label: "Repositories" }, + { id: "top", number: "00", label: "Home", icon: Home }, + { id: "work", number: "01", label: "Selected work", icon: BriefcaseBusiness }, + { id: "workbench", number: "02", label: "Workbench", icon: Hammer }, + { id: "about", number: "03", label: "About", icon: UserRound }, + { id: "repositories", number: "04", label: "Repositories", icon: GitBranch }, ] as const function RouteComponent() { @@ -60,6 +78,7 @@ function RouteComponent() { className={activeSection === section.id ? "is-active" : undefined} aria-current={activeSection === section.id ? "location" : undefined} > +