138 lines
4.7 KiB
TypeScript
138 lines
4.7 KiB
TypeScript
import type { Metadata } from "next";
|
||
import Hero from "@/components/content/Hero";
|
||
import SectionLabel from "@/components/layout/SectionLabel";
|
||
import Collapsible from "@/components/ui/Collapsible";
|
||
import { hardware, editorAndShell, aiTools } from "@/constants";
|
||
import type { ToolGroup } from "@/constants/uses";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Uses — Angel Mankel",
|
||
};
|
||
|
||
function ToolSection({
|
||
label,
|
||
groups,
|
||
}: {
|
||
label: string;
|
||
groups: ToolGroup[];
|
||
}) {
|
||
return (
|
||
<section className="space-y-4">
|
||
<SectionLabel label={label} />
|
||
<div className="space-y-3">
|
||
{groups.map((group) => (
|
||
<Collapsible
|
||
key={group.label}
|
||
title={group.label}
|
||
subtitle={`${group.items.length} items`}
|
||
>
|
||
<ul className="space-y-2 text-[14px]">
|
||
{group.items.map((item) => (
|
||
<li key={item.name} className="flex flex-col gap-0.5">
|
||
<span className="text-neutral-100">{item.name}</span>
|
||
{item.description && (
|
||
<span className="text-neutral-400">{item.description}</span>
|
||
)}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</Collapsible>
|
||
))}
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
export default function UsesPage() {
|
||
return (
|
||
<div className="space-y-14">
|
||
<Hero label="Uses" subtitle="The gear, software, and setup behind my work." />
|
||
|
||
<section className="space-y-4">
|
||
<SectionLabel label="Hardware" />
|
||
|
||
<div className="space-y-10">
|
||
{hardware.map((group) => (
|
||
<div key={group.label} className="space-y-4">
|
||
<h3 className="text-xs font-semibold uppercase tracking-[0.18em] text-neutral-500">
|
||
{group.label}
|
||
</h3>
|
||
|
||
<div className="space-y-3">
|
||
{group.machines.map((machine) => (
|
||
<Collapsible
|
||
key={machine.name}
|
||
title={machine.name}
|
||
subtitle={machine.role}
|
||
>
|
||
<dl className="space-y-3 text-[14px]">
|
||
<div className="flex flex-col gap-1 sm:flex-row sm:gap-3">
|
||
<dt className="w-20 shrink-0 text-neutral-500">OS</dt>
|
||
<dd className="text-neutral-200">{machine.os}</dd>
|
||
</div>
|
||
<div className="flex flex-col gap-1 sm:flex-row sm:gap-3">
|
||
<dt className="w-20 shrink-0 text-neutral-500">Specs</dt>
|
||
<dd className="flex flex-wrap gap-1.5">
|
||
{machine.specs.map((spec) => (
|
||
<span
|
||
key={spec}
|
||
className="rounded-md border border-neutral-800 bg-neutral-900 px-2 py-0.5 text-[12px] text-neutral-300"
|
||
>
|
||
{spec}
|
||
</span>
|
||
))}
|
||
</dd>
|
||
</div>
|
||
{machine.services && (
|
||
<div className="flex flex-col gap-1 sm:flex-row sm:gap-3">
|
||
<dt className="w-20 shrink-0 text-neutral-500">
|
||
Running
|
||
</dt>
|
||
<dd>
|
||
<ul className="space-y-1 text-neutral-200">
|
||
{machine.services.map((service) => (
|
||
<li
|
||
key={service}
|
||
className="before:mr-2 before:text-neutral-600 before:content-['–']"
|
||
>
|
||
{service}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</dd>
|
||
</div>
|
||
)}
|
||
</dl>
|
||
</Collapsible>
|
||
))}
|
||
</div>
|
||
|
||
{group.extras?.map((extra) => (
|
||
<Collapsible
|
||
key={extra.label}
|
||
title={extra.label}
|
||
subtitle={`${extra.items.length} items`}
|
||
>
|
||
<ul className="space-y-1.5 text-[14px] text-neutral-200">
|
||
{extra.items.map((item) => (
|
||
<li
|
||
key={item}
|
||
className="before:mr-2 before:text-neutral-600 before:content-['–']"
|
||
>
|
||
{item}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</Collapsible>
|
||
))}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
<ToolSection label="Editor & Shell" groups={editorAndShell} />
|
||
<ToolSection label="AI Tools" groups={aiTools} />
|
||
</div>
|
||
);
|
||
}
|