The Articles page turns a writing index into a filesystem listing. Every article is a row in aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/systems-witch/llms.txt
Use this file to discover all available pages before exploring further.
ls -lh-style table with Unix permission strings, human-readable file sizes, short dates, and .md filenames. A $ grep input above the table filters rows in real time as the user types, completing the illusion that they are searching a live directory. The entire layout is font-mono and lives inside the standard page space-y-12 wrapper.
Data structure
Articles are defined in aconst articles array above the component:
| Filename | Size | Date |
|---|---|---|
| architecting-the-void.md | 14K | May 20 |
| css-as-incantation.md | 8.2K | May 15 |
| state-management-rituals.md | 21K | Apr 30 |
| the-death-of-clean-code.md | 12K | Apr 12 |
| webgl-sigils-tutorial.md | 45K | Mar 28 |
-rw-r--r-- permissions (owner read/write, group and other read-only). perms is a plain display string — no logic derives it from the other fields.
Grep filter
The search input is styled as a terminal command prefix:query is a useState("") string. The filtered list is computed at render time:
.toLowerCase()) and matches anywhere in the filename. The placeholder "pattern..." continues the Unix grep metaphor.
The filter only searches
name — not size, date, or perms. If you want multi-field search, expand the filter predicate to check multiple properties.Table layout
The<table> uses w-full text-left whitespace-nowrap inside an overflow-x-auto wrapper for mobile scrolling. Column headers are text-lilac font-normal (not bold) with border-b border-graphite/50 separator:
Row styling
Each<tr> is hover:bg-graphite/30 group cursor-pointer transition-colors. On hover, the row background lifts to graphite/30 and column-specific styles activate via group:
| Column | Default | On row-hover |
|---|---|---|
| PERMS | text-graphite | text-lilac |
| SIZE | text-lilac | (unchanged) |
| DATE | text-lilac | (unchanged) |
| NAME | text-bone | text-acid + underline (decoration-acid/50, underline-offset-4) |
<a> tags — the cursor-pointer on the row handles the affordance signal.
Empty state
When thefiltered array is empty, a full-width cell renders a “no results” message:
text-graphite colour renders the message almost invisible against the black background — a deliberate design choice that mimics the subdued “no results” state of a real terminal.
Customization
Add an article: Append an object to thearticles array:
<Link to={/articles/$}> and add a corresponding route.
Sort by date: The articles render in array order. Re-arrange the array manually, or add a .sort() call before the .filter():
The
date values in the default data ("May 20", "Apr 30", etc.) omit the year. If you want reliable date sorting, switch to ISO 8601 strings like "2026-05-20" in the data array and display them with a toLocaleDateString() formatter in the <td>.