feat: initial next.js boilerplate, set up .env, add outline documents
This commit is contained in:
@@ -32,6 +32,7 @@ yarn-error.log*
|
|||||||
|
|
||||||
# env files (can opt-in for committing if needed)
|
# env files (can opt-in for committing if needed)
|
||||||
.env*
|
.env*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"js/ts.tsdk.path": "node_modules/typescript/lib"
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
// File-based routing: this file's location IS the URL.
|
||||||
|
// /app/about/page.tsx → https://yoursite.com/about
|
||||||
|
//
|
||||||
|
// Conventions:
|
||||||
|
// page.tsx = the route's UI
|
||||||
|
// layout.tsx = a wrapper shared across this folder + any nested routes
|
||||||
|
// loading.tsx = shown while the page is loading
|
||||||
|
// not-found.tsx = shown on 404 within this segment
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
// Route-level metadata. Next reads this at build time and emits the
|
||||||
|
// correct <title>, <meta description>, OG tags, etc. into <head>.
|
||||||
|
// The root layout (/app/layout.tsx) had its own metadata; this overrides
|
||||||
|
// the title for /about specifically.
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "About — Angel Mankel",
|
||||||
|
// description:
|
||||||
|
// "Frontend engineer with deep AI-tooling fluency. Currently at Village Medical.",
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a Server Component by default. It runs on the server, sends
|
||||||
|
// HTML to the browser, and ships zero JavaScript for this page itself.
|
||||||
|
// You only add "use client" at the top of a file when you need
|
||||||
|
// interactivity (useState, onClick, etc).
|
||||||
|
//
|
||||||
|
// Because it's a server component, you could `await fetch()` here, read
|
||||||
|
// a markdown file from disk, or query a DB directly — no API route needed.
|
||||||
|
export default function AboutPage() {
|
||||||
|
return (
|
||||||
|
<main className="mx-auto max-w-2xl px-6 py-24">
|
||||||
|
<h1 className="text-3xl font-semibold mb-12">About</h1>
|
||||||
|
|
||||||
|
<section className="space-y-6 text-base leading-relaxed text-neutral-200">
|
||||||
|
<p>
|
||||||
|
I came up through healthcare IT — help desk, then Salesforce admin,
|
||||||
|
then software engineer at Village Medical, where I lead React and
|
||||||
|
TypeScript redesigns of patient-facing apps and the internal
|
||||||
|
component library.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In parallel I've gone deep on AI-assisted development. Claude
|
||||||
|
Code, custom slash commands, MCP integrations — the tooling layer
|
||||||
|
that's reshaping how I work across the stack.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I'm looking for remote-US product-engineering roles where
|
||||||
|
shipping React is the day job and using and building AI tooling is
|
||||||
|
first-class.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mt-16">
|
||||||
|
<div className="text-xs uppercase tracking-wider text-neutral-500 mb-3">
|
||||||
|
Timeline
|
||||||
|
</div>
|
||||||
|
<ul className="font-mono text-sm space-y-1.5 text-neutral-200">
|
||||||
|
<li>
|
||||||
|
<span className="text-neutral-500 mr-3">2024 – now</span>
|
||||||
|
Village Medical · Software Engineer
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="text-neutral-500 mr-3">2022 – 2024</span>
|
||||||
|
Village Medical · Salesforce Admin
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="text-neutral-500 mr-3">2019 – 2022</span>
|
||||||
|
Gila River · Help Desk / IT
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* next/link does client-side navigation between routes (no full
|
||||||
|
page reload) and prefetches the target route when the link
|
||||||
|
enters the viewport. Use it for any internal nav. For external
|
||||||
|
links and file downloads, plain <a> is fine. */}
|
||||||
|
<p className="mt-10 text-sm">
|
||||||
|
<a href="/cv.pdf" className="underline underline-offset-4 text-amber-400">
|
||||||
|
Download CV (PDF)
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<nav className="mt-16 pt-8 border-t border-neutral-800 flex gap-6 text-sm text-neutral-400">
|
||||||
|
<Link href="/" className="hover:text-white">
|
||||||
|
← Back home
|
||||||
|
</Link>
|
||||||
|
<Link href="/projects" className="hover:text-white">
|
||||||
|
See projects
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// File-based routing: this file's location IS the URL.
|
||||||
|
// /app/about/page.tsx → https://yoursite.com/about
|
||||||
|
//
|
||||||
|
// Conventions:
|
||||||
|
// page.tsx = the route's UI
|
||||||
|
// layout.tsx = a wrapper shared across this folder + any nested routes
|
||||||
|
// loading.tsx = shown while the page is loading
|
||||||
|
// not-found.tsx = shown on 404 within this segment
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
// Route-level metadata. Next reads this at build time and emits the
|
||||||
|
// correct <title>, <meta description>, OG tags, etc. into <head>.
|
||||||
|
// The root layout (/app/layout.tsx) had its own metadata; this overrides
|
||||||
|
// the title for /work specifically.
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Work — Angel Mankel",
|
||||||
|
// description:
|
||||||
|
// "Frontend engineer with deep AI-tooling fluency. Currently at Village Medical.",
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a Server Component by default. It runs on the server, sends
|
||||||
|
// HTML to the browser, and ships zero JavaScript for this page itself.
|
||||||
|
// You only add "use client" at the top of a file when you need
|
||||||
|
// interactivity (useState, onClick, etc).
|
||||||
|
//
|
||||||
|
// Because it's a server component, you could `await fetch()` here, read
|
||||||
|
// a markdown file from disk, or query a DB directly — no API route needed.
|
||||||
|
export default function WorkPage() {
|
||||||
|
return (
|
||||||
|
<main className="mx-auto max-w-2xl px-6 py-24">
|
||||||
|
<h1 className="text-3xl font-semibold mb-12">Work</h1>
|
||||||
|
|
||||||
|
<section className="space-y-6 text-base leading-relaxed text-neutral-200">
|
||||||
|
<p>
|
||||||
|
I came up through healthcare IT — help desk, then Salesforce admin,
|
||||||
|
then software engineer at Village Medical, where I lead React and
|
||||||
|
TypeScript redesigns of patient-facing apps and the internal
|
||||||
|
component library.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In parallel I've gone deep on AI-assisted development. Claude
|
||||||
|
Code, custom slash commands, MCP integrations — the tooling layer
|
||||||
|
that's reshaping how I work across the stack.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I'm looking for remote-US product-engineering roles where
|
||||||
|
shipping React is the day job and using and building AI tooling is
|
||||||
|
first-class.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mt-16">
|
||||||
|
<div className="text-xs uppercase tracking-wider text-neutral-500 mb-3">
|
||||||
|
Timeline
|
||||||
|
</div>
|
||||||
|
<ul className="font-mono text-sm space-y-1.5 text-neutral-200">
|
||||||
|
<li>
|
||||||
|
<span className="text-neutral-500 mr-3">2024 – now</span>
|
||||||
|
Village Medical · Software Engineer
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="text-neutral-500 mr-3">2022 – 2024</span>
|
||||||
|
Village Medical · Salesforce Admin
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="text-neutral-500 mr-3">2019 – 2022</span>
|
||||||
|
Gila River · Help Desk / IT
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<nav className="mt-16 pt-8 border-t border-neutral-800 flex gap-6 text-sm text-neutral-400">
|
||||||
|
<Link href="/" className="hover:text-white">
|
||||||
|
← Back home
|
||||||
|
</Link>
|
||||||
|
<Link href="/about" className="hover:text-white">
|
||||||
|
See about
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
# Portfolio — Angel Mankel
|
||||||
|
|
||||||
|
Personal site at a reserved domain (TBD — see `config.md` once created). This is a hiring-funnel artifact, not a blog or playground.
|
||||||
|
|
||||||
|
## Who this is for
|
||||||
|
|
||||||
|
The reader is a hiring manager or recruiter at one of these companies:
|
||||||
|
|
||||||
|
- **Bullseye:** Vercel, Anthropic, Cursor, Cognition, Replit, Sourcegraph, Continue, Linear, Figma
|
||||||
|
- **Adjacent:** Stripe, Ramp, Notion, Retool, any AI-native product company shipping React-heavy surfaces
|
||||||
|
|
||||||
|
They land here from a CV, LinkedIn DM, or referral. They will spend **60-120 seconds** before deciding to reply or move on. Optimize ruthlessly for that window.
|
||||||
|
|
||||||
|
## Who Angel is (positioning)
|
||||||
|
|
||||||
|
**Headline:** Frontend engineer with deep AI-tooling fluency — ships production React and builds custom Claude Code workflows.
|
||||||
|
|
||||||
|
**The wedge:** Most React devs treat Claude Code as a toy. Most AI tinkerers can't ship a real component library. Angel does both.
|
||||||
|
|
||||||
|
**Background arc:** Healthcare IT → Salesforce admin → Software Engineer at Village Medical (current). Leads React + TypeScript redesigns of patient-facing apps and the internal component library. In parallel, heavy day-to-day Claude Code user — custom slash commands, MCP integrations, agent workflows.
|
||||||
|
|
||||||
|
**Target roles:** Frontend / Product / AI-Native engineer, remote US, mid-level (1-3 yr SWE, broader IT background). Comp target $90-130K USD, floor $100K.
|
||||||
|
|
||||||
|
Full profile lives in `~/Projects/career-ops/config/profile.yml` and `~/Projects/career-ops/cv.md`. Read those before writing any copy.
|
||||||
|
|
||||||
|
## Design direction
|
||||||
|
|
||||||
|
**Aesthetic reference:** Vercel.com, Linear.app, Anthropic.com, Rauno.me, Paco.me, Brittany Chiang's v4.
|
||||||
|
|
||||||
|
**Principles:**
|
||||||
|
- Minimalist, content-first. Typography does the heavy lifting.
|
||||||
|
- Dark only. No light theme, no theme toggle. See `palette.html` for the full spec.
|
||||||
|
- Generous whitespace. Wide line-height. Long-form readable.
|
||||||
|
- **One** signature interaction detail (subtle cursor effect, scroll-driven element, command palette) — not a museum of effects.
|
||||||
|
- No hero video, no parallax stacks, no animated SVG mascots, no "Hi I'm Angel 👋" with a waving emoji.
|
||||||
|
- Monospace accents for technical content (kbd, inline code, metadata) — sparingly.
|
||||||
|
|
||||||
|
**What we are NOT building:**
|
||||||
|
- A WebGL/Three.js showcase. Reads as "junior trying hard" to senior frontend HMs. Angel's graphics range gets one line in About, not a hero.
|
||||||
|
- A flashy gradient/blob landing page.
|
||||||
|
- A blog-first site. (Writing is welcome but not the entry point.)
|
||||||
|
- A "projects" grid of unfinished side projects. Quality over quantity — 3-4 deep case studies beats 12 thumbnails.
|
||||||
|
|
||||||
|
## Information architecture
|
||||||
|
|
||||||
|
Five routes max. Keep it skimmable.
|
||||||
|
|
||||||
|
```
|
||||||
|
/ → Landing. Name + one-line positioning + 3 case study cards + contact.
|
||||||
|
/projects → Case study index (same 3-4 cards, expandable).
|
||||||
|
/projects/[slug] → Individual case study (postmortem format).
|
||||||
|
/about → Background arc, current role, what Angel is looking for.
|
||||||
|
/uses → Optional. Tools, editor setup, Claude Code workflow. High signal for AI-native hiring.
|
||||||
|
```
|
||||||
|
|
||||||
|
Skip `/blog`, `/work` (use `/projects`), `/contact` (inline on `/`), and `/resume` (a chrono strip + Download CV link on `/about` covers it without duplicating content).
|
||||||
|
|
||||||
|
### What `/about` must include
|
||||||
|
|
||||||
|
Beyond the narrative paragraphs:
|
||||||
|
|
||||||
|
- **Chronological strip** — 3-4 rows, plain text, format: `year-range · company · role`. No bullets, no descriptions. Source from `~/Projects/career-ops/cv.md`.
|
||||||
|
- **Download CV (PDF)** — single plain-text link pointing at the PDF generated by career-ops (`generate-pdf.mjs` output). Don't style it as a button or hero CTA — one line, in flow.
|
||||||
|
|
||||||
|
## Case study format (CRITICAL)
|
||||||
|
|
||||||
|
Each case study reads like an engineering postmortem, not a marketing page. Structure:
|
||||||
|
|
||||||
|
1. **One-line summary** — what shipped, who it served, the measurable outcome.
|
||||||
|
2. **Context** — the constraint or problem. 2-3 sentences.
|
||||||
|
3. **Decisions** — 3-5 specific technical/design calls and why. Name the alternatives rejected.
|
||||||
|
4. **Outcome** — measurable result. Numbers when possible. Honest when not.
|
||||||
|
5. **What I'd do differently** — one paragraph. Signals seniority.
|
||||||
|
|
||||||
|
**Do not** include: tech stack badges, "challenges faced" sections, generic "I learned a lot" closers.
|
||||||
|
|
||||||
|
### The 3-4 case studies to write
|
||||||
|
|
||||||
|
Source material in `~/Projects/career-ops/cv.md` and `~/Projects/career-ops/modes/_profile.md` under "proof_points":
|
||||||
|
|
||||||
|
1. **Village Medical patient scheduling redesign** — React + TS rebuild of a patient-facing scheduling app. Lead with scope and UX decisions, not framework name-drops.
|
||||||
|
2. **Village Medical internal component library** — design-system ownership. This is the bullseye proof point for product/design-engineer roles. Show the API of one component, the migration story, governance model.
|
||||||
|
3. **Claude Code custom tooling** — slash commands, MCP integrations, agent workflows used day-to-day. This is the AI-native wedge. Show one concrete workflow with before/after time-on-task.
|
||||||
|
4. **(Optional) Gila River internal Electron apps** — older but quantified (100-150% productivity gains, 70% AD-script speedup). Frame as "how I got into engineering." Skip if it dilutes the frontend narrative; keep if it adds blue-collar engineering credibility.
|
||||||
|
|
||||||
|
## Tech stack recommendation
|
||||||
|
|
||||||
|
**Default:** Next.js 15 (App Router) + TypeScript + Tailwind v4 + MDX for case studies.
|
||||||
|
|
||||||
|
Why: it's the stack the bullseye companies ship. Using it is itself a signal.
|
||||||
|
|
||||||
|
**Deployment:** Self-hosted by Angel. Traefik is already configured and pointing at the domain. Do not propose Vercel, Netlify, Cloudflare Pages, or any managed host — the infra is in-house and stays that way. Build target should produce a standard Node server or static export that drops into the existing Traefik setup; ask Angel for specifics (container? bare Node? static `out/`?) before wiring CI.
|
||||||
|
|
||||||
|
**Alternatives considered:**
|
||||||
|
- Astro — better for static-heavy content sites, but Next.js signals stack alignment with target employers. Use Astro only if Angel wants to demonstrate range.
|
||||||
|
- Plain HTML/CSS — would actually be impressive ("I don't need a framework for this") but reads as contrarian unless the design carries it. Skip.
|
||||||
|
|
||||||
|
**Other choices:**
|
||||||
|
- `next/font` for self-hosted typography. Suggested pairing: Inter (UI) + JetBrains Mono / Geist Mono (code). Or splurge on a paid display face for the name only.
|
||||||
|
- `next-mdx-remote` or built-in MDX for case studies.
|
||||||
|
- `shiki` for code blocks (matches Vercel/Anthropic aesthetic better than Prism).
|
||||||
|
- View Transitions API for `/projects` → `/projects/[slug]` navigation. One signature detail.
|
||||||
|
- No CMS. Content lives in MDX files in-repo. Version-controlled, no DB.
|
||||||
|
|
||||||
|
## Tone and copy
|
||||||
|
|
||||||
|
Read `~/Projects/career-ops/modes/_profile.md` under "Writing Style" if it exists; otherwise extract style from `~/Projects/career-ops/writing-samples/` before drafting any user-facing copy.
|
||||||
|
|
||||||
|
Defaults if no samples found:
|
||||||
|
- First person, active voice. "I led", "I shipped", not "responsible for".
|
||||||
|
- Short sentences. Mix in a longer one for rhythm.
|
||||||
|
- Specific over abstract. "Cut p95 from 2.1s to 380ms" beats "improved performance."
|
||||||
|
- Zero corporate clichés: no "passionate", "results-oriented", "proven track record", "leveraged", "synergies", "cutting-edge."
|
||||||
|
- No emoji in copy. (Emoji on the page = wrong audience signal for these companies.)
|
||||||
|
|
||||||
|
## What "done" looks like for v1
|
||||||
|
|
||||||
|
- [ ] Site reachable at the domain through Angel's Traefik (deployment infra is his — agent does not touch it)
|
||||||
|
- [ ] `/` renders Name + positioning line + 3 case study cards + email contact
|
||||||
|
- [ ] 3 case studies fully written (not lorem ipsum)
|
||||||
|
- [ ] `/about` written, including chrono strip and Download CV link
|
||||||
|
- [ ] CV PDF generated via career-ops and served at a stable path (e.g. `/cv.pdf`)
|
||||||
|
- [ ] Open Graph image + favicon
|
||||||
|
- [ ] Lighthouse: 100/100/100/100 (this is table stakes for the audience)
|
||||||
|
- [ ] Site is responsive but designed desktop-first (hiring managers are on laptops)
|
||||||
|
- [ ] No analytics that block (Plausible or none — definitely not GA)
|
||||||
|
|
||||||
|
## What NOT to do
|
||||||
|
|
||||||
|
- Do not scaffold a Next.js project until Angel says go on the design direction.
|
||||||
|
- Do not write case study copy without first reading `~/Projects/career-ops/cv.md` and `~/Projects/career-ops/modes/_profile.md`.
|
||||||
|
- Do not invent metrics or experience. Pull only from CV + article-digest.md (if present).
|
||||||
|
- Do not add a "currently learning" or "tech stack" badge wall.
|
||||||
|
- Do not commit Angel's phone number, address, or any PII beyond name + email + LinkedIn + GitHub.
|
||||||
|
- Do not generate AI art for the OG image. A clean typographic OG card is the right move.
|
||||||
|
|
||||||
|
## Cross-references
|
||||||
|
|
||||||
|
- CV (source of truth): `~/Projects/career-ops/cv.md`
|
||||||
|
- Profile & narrative: `~/Projects/career-ops/config/profile.yml`, `~/Projects/career-ops/modes/_profile.md`
|
||||||
|
- Proof point details (if exists): `~/Projects/career-ops/article-digest.md`
|
||||||
|
- Writing samples (if exists): `~/Projects/career-ops/writing-samples/`
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Portfolio Palette — Angel Mankel</title>
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0; padding: 0; font-family: ui-sans-serif, system-ui, sans-serif; background: #fff; color: #000; }
|
||||||
|
body { padding: 40px 20px 120px; }
|
||||||
|
.wrap { max-width: 1100px; margin: 0 auto; }
|
||||||
|
h1 { font-size: 22px; margin: 0 0 32px; }
|
||||||
|
h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.08em; margin: 48px 0 12px; color: #555; }
|
||||||
|
|
||||||
|
.row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
|
||||||
|
.swatch { border: 1px solid #000; overflow: hidden; font-family: ui-monospace, monospace; font-size: 11px; }
|
||||||
|
.swatch .chip { height: 100px; border-bottom: 1px solid #000; }
|
||||||
|
.swatch .meta { padding: 8px 10px; line-height: 1.4; }
|
||||||
|
.swatch .role { display: block; font-weight: 600; margin-bottom: 2px; }
|
||||||
|
.swatch .hex { display: block; color: #555; }
|
||||||
|
|
||||||
|
.stage { background: #0a0a0a; padding: 20px; margin-top: 16px; }
|
||||||
|
.stage + .stage { margin-top: 16px; }
|
||||||
|
.preview { background: #1c1c1c; color: #ededed; border: 1px solid #2e2e2e; padding: 28px; font-family: ui-sans-serif, system-ui, sans-serif; }
|
||||||
|
.preview + .preview { margin-top: 16px; }
|
||||||
|
.preview h3 { font-size: 22px; margin: 0 0 6px; font-weight: 600; }
|
||||||
|
.preview p { margin: 0 0 10px; font-size: 13px; line-height: 1.6; }
|
||||||
|
.preview a { color: #d4a24a; text-decoration: underline; text-underline-offset: 3px; }
|
||||||
|
.preview .muted { color: #6b6b6b; }
|
||||||
|
.preview .nav { display: flex; justify-content: space-between; align-items: center; font-family: ui-monospace, monospace; font-size: 12px; }
|
||||||
|
.preview .nav .links { display: flex; gap: 18px; color: #6b6b6b; }
|
||||||
|
.preview .nav .links a { color: inherit; text-decoration: none; }
|
||||||
|
.preview hr { border: 0; border-top: 1px solid #2e2e2e; margin: 20px 0; }
|
||||||
|
.preview .chrono { font-family: ui-monospace, monospace; font-size: 13px; line-height: 1.8; color: #ededed; }
|
||||||
|
.preview .chrono .y { color: #6b6b6b; margin-right: 14px; }
|
||||||
|
.preview .code { background: #0f0f0f; border: 1px solid #2e2e2e; padding: 14px 16px; font-family: ui-monospace, monospace; font-size: 12px; line-height: 1.6; }
|
||||||
|
.preview .code .k { color: #d4a24a; }
|
||||||
|
.preview .code .c { color: #6b6b6b; }
|
||||||
|
.preview .case-meta { font-family: ui-monospace, monospace; font-size: 12px; color: #6b6b6b; margin-bottom: 18px; }
|
||||||
|
.preview .case-meta span + span::before { content: " · "; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrap">
|
||||||
|
|
||||||
|
<h1>Palette — Angel Mankel portfolio</h1>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<h2>Neutrals</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #0a0a0a;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">bg</span>
|
||||||
|
<span class="hex">#0a0a0a</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #1c1c1c;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">bg-elevated</span>
|
||||||
|
<span class="hex">#1c1c1c</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #2e2e2e;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">border</span>
|
||||||
|
<span class="hex">#2e2e2e</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #6b6b6b;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">text-muted</span>
|
||||||
|
<span class="hex">#6b6b6b</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #ededed;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">text</span>
|
||||||
|
<span class="hex">#ededed</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<h2>Accent</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #d4a24a;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">accent</span>
|
||||||
|
<span class="hex">#d4a24a</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<h2>Hover states</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #262626;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">bg-elevated · hover</span>
|
||||||
|
<span class="hex">#262626</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #3d3d3d;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">border · hover</span>
|
||||||
|
<span class="hex">#3d3d3d</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #9a9a9a;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">text-muted · hover</span>
|
||||||
|
<span class="hex">#9a9a9a</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #ffffff;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">text · hover</span>
|
||||||
|
<span class="hex">#ffffff</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swatch">
|
||||||
|
<div class="chip" style="background: #e6b966;"></div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="role">accent · hover</span>
|
||||||
|
<span class="hex">#e6b966</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<h2>Previews</h2>
|
||||||
|
|
||||||
|
<div class="stage"><div class="preview">
|
||||||
|
<div class="nav">
|
||||||
|
<div><strong>Angel Mankel</strong></div>
|
||||||
|
<div class="links"><a href="#">projects</a><a href="#">about</a><a href="#">uses</a><a href="#">email</a></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<div class="stage"><div class="preview">
|
||||||
|
<h3>Frontend engineer with deep AI-tooling fluency.</h3>
|
||||||
|
<p>I ship production React at Village Medical and build custom Claude Code workflows that make the day-to-day faster.</p>
|
||||||
|
<p><a href="#">See selected projects →</a></p>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<div class="stage"><div class="preview">
|
||||||
|
<h3>Village Medical — patient scheduling redesign</h3>
|
||||||
|
<div class="case-meta">
|
||||||
|
<span>Software Engineer</span><span>2024</span><span>React · TypeScript</span>
|
||||||
|
</div>
|
||||||
|
<p>Rebuilt the patient appointment scheduling app from a legacy Salesforce flow into a self-contained React surface used across clinics.</p>
|
||||||
|
<p><a href="#">Read the case study →</a></p>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<div class="stage"><div class="preview">
|
||||||
|
<div class="muted" style="font-family: ui-monospace, monospace; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 12px;">timeline</div>
|
||||||
|
<div class="chrono">
|
||||||
|
<div><span class="y">2024 – now</span>Village Medical · Software Engineer</div>
|
||||||
|
<div><span class="y">2022 – 2024</span>Village Medical · Salesforce Admin</div>
|
||||||
|
<div><span class="y">2019 – 2022</span>Gila River · Help Desk / IT</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<p><a href="#">Download CV (PDF)</a></p>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<div class="stage"><div class="preview">
|
||||||
|
<div class="code">
|
||||||
|
<span class="c">// custom Claude Code slash command</span>
|
||||||
|
<span class="k">export default</span> {
|
||||||
|
name: <span class="k">'review'</span>,
|
||||||
|
run: <span class="k">async</span> (ctx) => {
|
||||||
|
<span class="k">await</span> ctx.runDiffReview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,295 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Portfolio Wireframe — Angel Mankel</title>
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0; padding: 0; background: #fff; color: #000; font-family: ui-sans-serif, system-ui, sans-serif; }
|
||||||
|
body { padding: 40px 20px 120px; }
|
||||||
|
.page-meta { max-width: 1100px; margin: 0 auto 24px; font-size: 13px; color: #555; }
|
||||||
|
.page-meta h1 { font-size: 18px; margin: 0 0 4px; color: #000; }
|
||||||
|
.frame { max-width: 1100px; margin: 0 auto 80px; border: 2px solid #000; }
|
||||||
|
.frame-label { font-family: ui-monospace, monospace; font-size: 12px; background: #000; color: #fff; padding: 6px 10px; }
|
||||||
|
.frame-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
|
||||||
|
.box { border: 1px dashed #333; padding: 14px; font-size: 13px; line-height: 1.4; }
|
||||||
|
.box .tag { font-family: ui-monospace, monospace; font-size: 11px; color: #555; display: block; margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.04em; }
|
||||||
|
.row { display: flex; gap: 12px; }
|
||||||
|
.row > .box { flex: 1; }
|
||||||
|
.row.three > .box { flex: 1 1 0; }
|
||||||
|
.nav { display: flex; justify-content: space-between; align-items: center; }
|
||||||
|
.nav .links { display: flex; gap: 18px; font-family: ui-monospace, monospace; font-size: 12px; }
|
||||||
|
.tall { min-height: 140px; }
|
||||||
|
.taller { min-height: 220px; }
|
||||||
|
.small { font-size: 12px; color: #555; }
|
||||||
|
hr.divider { border: 0; border-top: 1px solid #ccc; margin: 60px 0; }
|
||||||
|
.legend { max-width: 1100px; margin: 0 auto 40px; font-size: 12px; color: #555; padding: 12px; border: 1px dashed #999; }
|
||||||
|
.legend code { background: #eee; padding: 1px 4px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="legend">
|
||||||
|
<strong>Wireframe legend.</strong> Solid black border = page viewport. Dashed border = a content region with a label.
|
||||||
|
No colors, no images, no real type. Purpose: agree on layout structure and flow before touching CSS.
|
||||||
|
Routes shown: <code>/</code>, <code>/projects</code>, <code>/projects/[slug]</code>, <code>/about</code>, <code>/uses</code>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<div class="page-meta">
|
||||||
|
<h1>Route: /</h1>
|
||||||
|
<div>Landing. Goal: in 60-120s, communicate who Angel is, what he ships, how to contact.</div>
|
||||||
|
</div>
|
||||||
|
<div class="frame">
|
||||||
|
<div class="frame-label">VIEWPORT — /</div>
|
||||||
|
<div class="frame-body">
|
||||||
|
|
||||||
|
<div class="box nav">
|
||||||
|
<div><span class="tag">brand</span>Angel Mankel</div>
|
||||||
|
<div class="links">
|
||||||
|
<span>projects</span><span>about</span><span>uses</span><span>email</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box taller">
|
||||||
|
<span class="tag">hero — text only, no image</span>
|
||||||
|
Large name or wordmark. One-line positioning underneath: "Frontend engineer with deep AI-tooling fluency — ships production React and builds custom Claude Code workflows."
|
||||||
|
Below that, a secondary line linking to most recent case study or "Currently at Village Medical." No CTA buttons.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">section heading</span>
|
||||||
|
"Selected projects" — small caps or monospace label. Single line.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row three">
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">case study card 1</span>
|
||||||
|
Title · one-line summary · year · outcome metric.
|
||||||
|
Whole card is clickable → /projects/[slug].
|
||||||
|
</div>
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">case study card 2</span>
|
||||||
|
Same shape as card 1. Three cards total, sometimes four.
|
||||||
|
</div>
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">case study card 3</span>
|
||||||
|
Same shape.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">contact strip</span>
|
||||||
|
Email · LinkedIn · GitHub. Plain text links, no icons-only treatment. Maybe a one-line "Open to remote-US roles."
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box small nav">
|
||||||
|
<div><span class="tag">footer</span>© 2026 Angel Mankel</div>
|
||||||
|
<div>Self-hosted · Traefik · Next.js</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<div class="page-meta">
|
||||||
|
<h1>Route: /projects</h1>
|
||||||
|
<div>Case study index. Same cards as the landing, but full list. Optional filter (year or tag).</div>
|
||||||
|
</div>
|
||||||
|
<div class="frame">
|
||||||
|
<div class="frame-label">VIEWPORT — /projects</div>
|
||||||
|
<div class="frame-body">
|
||||||
|
|
||||||
|
<div class="box nav">
|
||||||
|
<div><span class="tag">brand</span>Angel Mankel</div>
|
||||||
|
<div class="links"><span>projects</span><span>about</span><span>uses</span><span>email</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">page heading</span>
|
||||||
|
"Projects" — single word. Optional one-line intro: "Selected projects, written as postmortems."
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">case study row 1</span>
|
||||||
|
Title · year · one-line summary · key metric. Full-width row, not a card grid (denser, more readable).
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">case study row 2</span>
|
||||||
|
Same shape.
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">case study row 3</span>
|
||||||
|
Same shape.
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">case study row 4 (optional)</span>
|
||||||
|
Same shape. Skip if it dilutes.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box small nav">
|
||||||
|
<div><span class="tag">footer</span>© 2026 Angel Mankel</div>
|
||||||
|
<div>Self-hosted · Traefik · Next.js</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<div class="page-meta">
|
||||||
|
<h1>Route: /projects/[slug]</h1>
|
||||||
|
<div>Individual case study. Postmortem format: context · decisions · outcome · what I'd do differently.</div>
|
||||||
|
</div>
|
||||||
|
<div class="frame">
|
||||||
|
<div class="frame-label">VIEWPORT — /projects/[slug]</div>
|
||||||
|
<div class="frame-body">
|
||||||
|
|
||||||
|
<div class="box nav">
|
||||||
|
<div><span class="tag">brand</span>Angel Mankel</div>
|
||||||
|
<div class="links"><span>projects</span><span>about</span><span>uses</span><span>email</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">case study header</span>
|
||||||
|
Project name (large). Below: role · year · stack · one-line outcome. No hero image.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="box" style="flex: 0 0 200px;">
|
||||||
|
<span class="tag">sidebar (desktop only)</span>
|
||||||
|
Sticky table of contents: Context · Decisions · Outcome · Retrospective. Collapses above the body on mobile.
|
||||||
|
</div>
|
||||||
|
<div class="box taller" style="flex: 1;">
|
||||||
|
<span class="tag">long-form body (MDX)</span>
|
||||||
|
Section: <em>Context</em> — the constraint, 2-3 sentences.<br>
|
||||||
|
Section: <em>Decisions</em> — 3-5 specific calls with rejected alternatives.<br>
|
||||||
|
Section: <em>Outcome</em> — measurable result, honest when not.<br>
|
||||||
|
Section: <em>What I'd do differently</em> — one paragraph.<br>
|
||||||
|
Inline: code blocks (shiki), occasional pull-quote, optional simple diagram. No carousels.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">next/prev case study</span>
|
||||||
|
Two links: ← previous case study · next case study →. Keeps the reader in the work funnel.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box small nav">
|
||||||
|
<div><span class="tag">footer</span>© 2026 Angel Mankel</div>
|
||||||
|
<div>Self-hosted · Traefik · Next.js</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<div class="page-meta">
|
||||||
|
<h1>Route: /about</h1>
|
||||||
|
<div>Background arc. Who Angel is, what he's looking for. Long-form, first person.</div>
|
||||||
|
</div>
|
||||||
|
<div class="frame">
|
||||||
|
<div class="frame-label">VIEWPORT — /about</div>
|
||||||
|
<div class="frame-body">
|
||||||
|
|
||||||
|
<div class="box nav">
|
||||||
|
<div><span class="tag">brand</span>Angel Mankel</div>
|
||||||
|
<div class="links"><span>projects</span><span>about</span><span>uses</span><span>email</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">page heading</span>
|
||||||
|
"About" — single word.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">narrative paragraph 1 — arc</span>
|
||||||
|
Healthcare IT → Salesforce admin → SWE at Village Medical. 3-5 sentences, first person, active voice.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">narrative paragraph 2 — current work + AI wedge</span>
|
||||||
|
What Angel does day-to-day. React + TS leadership. Heavy Claude Code use. The "frontend engineer who actually uses AI to ship" framing.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">narrative paragraph 3 — what I'm looking for</span>
|
||||||
|
One paragraph. Remote US, mid-level, AI-native or product-engineering. Names of companies he'd love to work with (optional but bold).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">chronological strip</span>
|
||||||
|
Three or four rows, plain text. Each row: year-range · company · role. No bullets, no descriptions — the case studies and narrative carry the detail. Example:<br>
|
||||||
|
2024–present · Village Medical · Software Engineer<br>
|
||||||
|
2022–2024 · Village Medical · Salesforce Admin<br>
|
||||||
|
2019–2022 · Gila River · Help Desk / IT
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">download CV</span>
|
||||||
|
Single line: "Download CV (PDF)" link. Points at the PDF generated by career-ops. No fancy treatment.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">contact strip</span>
|
||||||
|
Email · LinkedIn · GitHub. Same as landing.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box small nav">
|
||||||
|
<div><span class="tag">footer</span>© 2026 Angel Mankel</div>
|
||||||
|
<div>Self-hosted · Traefik · Next.js</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<div class="page-meta">
|
||||||
|
<h1>Route: /uses (optional)</h1>
|
||||||
|
<div>Tools, editor setup, Claude Code workflow. High-signal page for AI-native hiring managers.</div>
|
||||||
|
</div>
|
||||||
|
<div class="frame">
|
||||||
|
<div class="frame-label">VIEWPORT — /uses</div>
|
||||||
|
<div class="frame-body">
|
||||||
|
|
||||||
|
<div class="box nav">
|
||||||
|
<div><span class="tag">brand</span>Angel Mankel</div>
|
||||||
|
<div class="links"><span>projects</span><span>about</span><span>uses</span><span>email</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<span class="tag">page heading</span>
|
||||||
|
"Uses" — single word. One-line intro: "What I reach for daily."
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">section: hardware</span>
|
||||||
|
Plain list. Machine, monitors, keyboard. One line each.
|
||||||
|
</div>
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">section: editor & shell</span>
|
||||||
|
VS Code config highlights, terminal, font, theme.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">section: AI workflow</span>
|
||||||
|
Claude Code setup. Custom slash commands. MCP servers. One paragraph per workflow with the time saved.
|
||||||
|
This is the signal-dense section — give it the most space.
|
||||||
|
</div>
|
||||||
|
<div class="box tall">
|
||||||
|
<span class="tag">section: self-hosting</span>
|
||||||
|
Traefik, the box, whatever else runs on it. One-liners. This is where "self-hosted" lives without becoming the lede.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box small nav">
|
||||||
|
<div><span class="tag">footer</span>© 2026 Angel Mankel</div>
|
||||||
|
<div>Self-hosted · Traefik · Next.js</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user