feat: update app pages and layout
This commit is contained in:
+93
-2
@@ -1,5 +1,11 @@
|
|||||||
import Hero from "@/components/content/Hero";
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import { IconBrandLinkedinFilled, IconMailFilled } from "@tabler/icons-react";
|
||||||
|
import Hero from "@/components/content/Hero";
|
||||||
|
import SectionLabel from "@/components/layout/SectionLabel";
|
||||||
|
import AccentLink from "@/components/navigation/AccentLink";
|
||||||
|
import GiteaIcon from "@/components/icons/GiteaIcon";
|
||||||
|
import Tooltip from "@/components/ui/Tooltip";
|
||||||
|
import { colors, education, timeline } from "@/constants";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "About — Angel Mankel",
|
title: "About — Angel Mankel",
|
||||||
@@ -7,6 +13,91 @@ export const metadata: Metadata = {
|
|||||||
|
|
||||||
export default function AboutPage() {
|
export default function AboutPage() {
|
||||||
return (
|
return (
|
||||||
<Hero label="About"/>
|
<div className="space-y-14">
|
||||||
|
<Hero label="About">
|
||||||
|
<div className="space-y-5 text-[19px] leading-[1.65]">
|
||||||
|
<p>
|
||||||
|
I came up through healthcare IT — help desk, then Salesforce
|
||||||
|
administration, then software engineering. A path that taught me
|
||||||
|
to translate between operations, design, and engineering without
|
||||||
|
losing the thread.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
These days I write React and TypeScript for production, lead
|
||||||
|
component-library work, and spend a lot of time in Claude Code —
|
||||||
|
custom slash commands, MCP integrations, agent workflows. The
|
||||||
|
AI-tooling layer is reshaping how I work across the stack.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Based in Arizona, looking for remote-US roles where shipping
|
||||||
|
frontend product and building AI tooling around it are both
|
||||||
|
first-class. Bonus points for teams that take design seriously
|
||||||
|
and don't hand things off at every layer.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Hero>
|
||||||
|
|
||||||
|
<section className="space-y-4">
|
||||||
|
<SectionLabel label="Education" />
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{education.map((row) => (
|
||||||
|
<li key={row.span} className="flex gap-2 text-sm">
|
||||||
|
<span className="w-36 shrink-0 text-neutral-500">
|
||||||
|
{row.span}
|
||||||
|
</span>
|
||||||
|
<span className="text-neutral-200">{row.degree} · {row.location}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="space-y-4">
|
||||||
|
<SectionLabel label="Timeline" />
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{timeline.map((row) => (
|
||||||
|
<li key={row.span} className="flex gap-2 text-sm">
|
||||||
|
<span className="w-36 shrink-0 text-neutral-500">
|
||||||
|
{row.span}
|
||||||
|
</span>
|
||||||
|
<span className="text-neutral-200">{row.role}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<AccentLink link="/cv.pdf" label="Download CV (PDF)" />
|
||||||
|
|
||||||
|
<nav aria-label="Contact" className="flex gap-5 text-neutral-300">
|
||||||
|
<Tooltip text="Email">
|
||||||
|
<a
|
||||||
|
href="mailto:angelmankel@gmail.com"
|
||||||
|
aria-label="Email"
|
||||||
|
className={`hover:text-neutral-200 rounded-md hover:bg-[${colors.accent}] p-1 transition-colors duration-200`}
|
||||||
|
>
|
||||||
|
<IconMailFilled size={32} />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip text="LinkedIn">
|
||||||
|
<a
|
||||||
|
href="https://www.linkedin.com/in/angel-mankel-0616aa132/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
aria-label="LinkedIn"
|
||||||
|
className={`hover:text-neutral-200 rounded-md hover:bg-[${colors.accent}] p-1 transition-colors duration-200`}
|
||||||
|
>
|
||||||
|
<IconBrandLinkedinFilled size={32} />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip text="Gitea">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
aria-label="Gitea"
|
||||||
|
className={`hover:text-neutral-200 rounded-md hover:bg-[${colors.accent}] p-1 transition-colors duration-200`}
|
||||||
|
>
|
||||||
|
<GiteaIcon size={32} />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -4,6 +4,7 @@ import "./globals.css";
|
|||||||
import Header from "@/components/layout/Header";
|
import Header from "@/components/layout/Header";
|
||||||
import Footer from "@/components/layout/Footer";
|
import Footer from "@/components/layout/Footer";
|
||||||
import Container from "@/components/layout/Container";
|
import Container from "@/components/layout/Container";
|
||||||
|
import Cursor from "@/components/ui/Cursor";
|
||||||
|
|
||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
variable: "--font-inter",
|
variable: "--font-inter",
|
||||||
@@ -29,9 +30,10 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
lang="en"
|
lang="en"
|
||||||
className={`${inter.variable} ${instrumentSerif.variable} h-full antialiased`}
|
className={`${inter.variable} ${instrumentSerif.variable} h-full antialiased scrollbar-track-transparent scrollbar-thumb-neutral-700`}
|
||||||
>
|
>
|
||||||
<body className="min-h-full flex flex-col font-sans">
|
<body className="min-h-full flex flex-col font-sans">
|
||||||
|
{/* <Cursor /> */}
|
||||||
<Header />
|
<Header />
|
||||||
<Container>{children}</Container>
|
<Container>{children}</Container>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
+37
-43
@@ -1,49 +1,22 @@
|
|||||||
import Hero from "@/components/content/Hero";
|
import Hero from "@/components/content/Hero";
|
||||||
import Testimonials from "@/components/content/Testimonials";
|
import Testimonials from "@/components/content/Testimonials";
|
||||||
|
import RotatingWord from "@/components/content/RotatingWord";
|
||||||
import SectionLabel from "@/components/layout/SectionLabel";
|
import SectionLabel from "@/components/layout/SectionLabel";
|
||||||
import AccentLink from "@/components/navigation/AccentLink";
|
import AccentLink from "@/components/navigation/AccentLink";
|
||||||
|
import ProjectCard from "@/components/content/ProjectCard";
|
||||||
type Testimonial = {
|
import { testimonials, projects } from "@/constants";
|
||||||
name: string;
|
|
||||||
title: string;
|
|
||||||
avatar?: string;
|
|
||||||
quote: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const testimonialsData: Testimonial[] = [
|
|
||||||
{
|
|
||||||
name: "Sarah Chen",
|
|
||||||
title: "Senior Software Engineer · Patient Platforms",
|
|
||||||
quote:
|
|
||||||
"Working with Angel was the first time I saw someone treat Claude Code as a real engineering tool instead of a toy. He’d built half a workflow before the rest of us figured out it was possible.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Marcus Whitfield",
|
|
||||||
title: "Staff Frontend Engineer",
|
|
||||||
quote:
|
|
||||||
"He owned the component library end-to-end and ran the migration without breaking a single screen. Quiet shipper — you only notice his work when you go looking for it.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Priya Anand",
|
|
||||||
title: "Product Designer",
|
|
||||||
quote:
|
|
||||||
"Angel is the rare engineer who actually reads designs and asks questions when something feels off. Half my polish budget got returned to me on the projects he was on.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Daniel Okafor",
|
|
||||||
title: "Engineering Manager",
|
|
||||||
quote:
|
|
||||||
"He’s at his best when the problem doesn’t fit cleanly into one stack. I’d hand him an ambiguous brief and a week later he’d come back with a working prototype and a plan.",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Hero label="Angel Mankel">
|
<Hero label="Angel Mankel">
|
||||||
<div className="space-y-5">
|
<div className="space-y-5 mb-4">
|
||||||
<p className="font-serif italic text-3xl leading-[1.3]">
|
<p className="font-serif italic text-3xl leading-[1.3]">
|
||||||
I’m a creator at heart.
|
I'm{" "}
|
||||||
|
<RotatingWord
|
||||||
|
items={["a developer", "a creative", "a tinkerer"]}
|
||||||
|
/>
|
||||||
|
.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="text-[19px] leading-[1.65]">
|
<p className="text-[19px] leading-[1.65]">
|
||||||
@@ -52,16 +25,37 @@ export default function HomePage() {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="text-[19px] leading-[1.65]">
|
<p className="text-[19px] leading-[1.65]">
|
||||||
I’m the kind of engineer who picks up whatever the problem needs and
|
I'm the kind of engineer who picks up whatever the problem needs and
|
||||||
keeps digging — into the code, and into the people it’s meant for.
|
keeps digging — into the code, and into the people it's meant for.
|
||||||
The throughline isn’t a stack, it’s the curiosity.
|
The throughline isn't a stack, it's the curiosity.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<AccentLink label="About Me" link="/about" />
|
||||||
|
</div>
|
||||||
</Hero>
|
</Hero>
|
||||||
<SectionLabel label="Selected Projects" />
|
|
||||||
<AccentLink label="See all projects" link="/projects" />
|
{/* Projects */}
|
||||||
<SectionLabel label="What people say" />
|
<div className="mt-20">
|
||||||
<Testimonials items={testimonialsData} />
|
<SectionLabel label="Selected Projects" />
|
||||||
|
|
||||||
|
{projects.slice(0,3).map((project, index) => (
|
||||||
|
<ProjectCard key={index} {...project} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="mt-5">
|
||||||
|
<AccentLink label="See all projects" link="/projects" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Testimonials */}
|
||||||
|
<div className="mt-20">
|
||||||
|
<SectionLabel label="What people say" />
|
||||||
|
<div className="mt-5">
|
||||||
|
<Testimonials items={testimonials} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -1,5 +1,7 @@
|
|||||||
import Hero from "@/components/content/Hero";
|
import Hero from "@/components/content/Hero";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import ProjectCard from "@/components/content/ProjectCard";
|
||||||
|
import { projects } from "@/constants";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Work — Angel Mankel",
|
title: "Work — Angel Mankel",
|
||||||
@@ -7,6 +9,14 @@ export const metadata: Metadata = {
|
|||||||
|
|
||||||
export default function ProjectsPage() {
|
export default function ProjectsPage() {
|
||||||
return (
|
return (
|
||||||
<Hero label="Projects" subtitle="Selected work, written as postmortems." />
|
<>
|
||||||
|
<div className="mb-15">
|
||||||
|
<Hero label="Projects" subtitle="Selected work, written as postmortems." />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{projects.map((project, index) => (
|
||||||
|
<ProjectCard key={index} {...project} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-2
@@ -1,12 +1,77 @@
|
|||||||
import Hero from "@/components/content/Hero";
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import Hero from "@/components/content/Hero";
|
||||||
|
import SectionLabel from "@/components/layout/SectionLabel";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Uses — Angel Mankel",
|
title: "Uses — Angel Mankel",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Section =
|
||||||
|
| { label: string; kind: "list"; items: string[] }
|
||||||
|
| { label: string; kind: "prose"; paragraphs: string[] };
|
||||||
|
|
||||||
|
const sections: Section[] = [
|
||||||
|
{
|
||||||
|
label: "Hardware",
|
||||||
|
kind: "list",
|
||||||
|
items: [
|
||||||
|
"Custom desktop — i9-12900H, 32GB RAM, Intel Iris Xe",
|
||||||
|
"Nobara Linux 43 · KDE Plasma 6 · Wayland",
|
||||||
|
"Headphones / keyboard / monitor — placeholder",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Editor & Shell",
|
||||||
|
kind: "list",
|
||||||
|
items: [
|
||||||
|
"VS Code with a personal extension pack — placeholder",
|
||||||
|
"Bash / zsh — placeholder for shell",
|
||||||
|
"JetBrains Mono as the editor font",
|
||||||
|
"Theme — placeholder",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "AI Workflow",
|
||||||
|
kind: "prose",
|
||||||
|
paragraphs: [
|
||||||
|
"Claude Code is the daily driver — custom slash commands, MCP servers wired into my editor, and agent workflows that handle the repeat work so I can stay in the design problem.",
|
||||||
|
"Placeholder paragraph two — name a specific workflow and the time it saves.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Self-hosting",
|
||||||
|
kind: "list",
|
||||||
|
items: [
|
||||||
|
"Bare-metal home server, exposed to the internet through Traefik",
|
||||||
|
"This site lives on it — Next.js standalone build, no managed host",
|
||||||
|
"Other services — placeholder",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function UsesPage() {
|
export default function UsesPage() {
|
||||||
return (
|
return (
|
||||||
<Hero label="Uses" subtitle="Tools and technologies I use in my work."/>
|
<div className="space-y-14">
|
||||||
|
<Hero label="Uses" subtitle="What I reach for daily." />
|
||||||
|
|
||||||
|
{sections.map((section) => (
|
||||||
|
<section key={section.label} className="space-y-4">
|
||||||
|
<SectionLabel label={section.label} />
|
||||||
|
{section.kind === "list" ? (
|
||||||
|
<ul className="space-y-2 text-[15px] leading-[1.65] text-neutral-200">
|
||||||
|
{section.items.map((item) => (
|
||||||
|
<li key={item}>{item}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-4 text-[15px] leading-[1.65] text-neutral-200">
|
||||||
|
{section.paragraphs.map((p) => (
|
||||||
|
<p key={p}>{p}</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user