Adding a Page
Add a new page to Adminator in three steps. Drop an HTML file, register the title with the webpack plugin, append one entry to the NAV array. The sidebar, breadcrumbs, and command palette all pick it up automatically.
Last updated May 21, 2026
The shell architecture is designed so that adding a page is three small edits. No router config, no template inheritance, no boilerplate. Webpack handles HTML output, Shell.js handles navigation.
Let’s add a hypothetical “Reports” page.
1. Create the HTML file
Drop a new file in src/. The simplest version is the standard shell anatomy with your content inside .content:
<!-- src/reports.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Adminator · Reports</title>
<script>
(function () {
try {
var saved = localStorage.getItem('dash26-theme');
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.setAttribute('data-theme', saved || (prefersDark ? 'dark' : 'light'));
} catch (e) {
document.documentElement.setAttribute('data-theme', 'light');
}
})();
</script>
</head>
<body data-active="reports" data-crumbs="Workspace | Reports">
<div class="shell">
<div data-shell-sidebar></div>
<div class="main">
<div data-shell-topbar></div>
<main class="content">
<section class="hero">
<div>
<div class="eyebrow">Q2 2026</div>
<h1>Reports</h1>
<p>Your team's monthly performance, surfaced at a glance.</p>
</div>
</section>
<div class="grid">
<div class="card">
<!-- your content -->
</div>
</div>
</main>
<div data-shell-footer></div>
</div>
</div>
</body>
</html>
The fastest way is to copy src/blank.html — it’s the canonical starter — then change the data-active, data-crumbs, and content.
What the body attributes do
data-active="reports"— must match thekeyyou’ll add toNAVin step 3. The sidebar uses this to highlight the active item.data-crumbs="Workspace | Reports"—|-separated breadcrumb segments. The last one is rendered as the current page (highlighted, no link). Earlier segments render as labels in the topbar.
2. Register the title
Open webpack/plugins/htmlPlugin.js and add an entry to the titles map:
const titles = {
index: 'Adminator · Dashboard',
email: 'Adminator · Email',
// ...
reports: 'Adminator · Reports', // ← add this
};
The webpack plugin scans src/*.html and creates an HtmlWebpackPlugin instance per file. The map keys are filenames without .html. If you skip this step the page still builds, but the document title defaults to whatever you wrote in <title> and won’t be consistent with the rest of the template.
3. Add the nav entry
Open src/assets/scripts/2026/Shell.js and find the NAV array near the top. Add a new item to whichever section makes sense — let’s say Workspace:
export const NAV = [
{
label: 'Workspace',
items: [
{ key: 'dashboard', text: 'Dashboard', href: 'index.html',
icon: '<path d="M3 12 12 3l9 9"/><path d="M5 10v10h14V10"/>' },
// Add this:
{ key: 'reports', text: 'Reports', href: 'reports.html',
icon: '<path d="M3 3v18h18"/><path d="M7 14l3-3 4 4 5-5"/>' },
],
},
// ...
];
The required fields are key (matches your page’s data-active), text (label), href (the HTML file), and icon (inline SVG path data — see below).
Optional fields
badge: { kind: 'new'|'hot'|'pro', text: 'NEW' }— renders a small pill next to the label. Use it to highlight new sections or premium features.children: [...]— turns the item into a group with a submenu. Children are flat{ key, text, href }objects without their own icons.
{ key: 'reports', text: 'Reports',
icon: '<path d="..."/>',
children: [
{ key: 'reports-sales', text: 'Sales', href: 'reports-sales.html' },
{ key: 'reports-traffic', text: 'Traffic', href: 'reports-traffic.html' },
],
},
Where to find icon paths
Adminator’s sidebar icons are hand-trimmed Lucide and Feather icons — 24×24 viewBox, stroke-width: 1.75–2, fill: none. Anything in those libraries works; copy the inner <path> only (not the outer <svg> wrapper, which Shell.js adds).
For example, the dashboard icon:
<path d="M3 12 12 3l9 9"/>
<path d="M5 10v10h14V10"/>
Don’t paste full <svg xmlns="..."> markup — the wrapper is rendered by the shell so icons inherit currentColor and respect the active theme.
4. Restart the dev server
The webpack config picks up new templates only on restart. Stop npm start (Ctrl+C), then run it again:
npm start
Visit http://localhost:4000/reports.html — the page should render with the sidebar, topbar, footer, theme toggle, and ⌘K palette all working. The Reports nav item is highlighted, and the topbar shows “Workspace · Reports”.
What you didn’t have to do
- No router config — pages are static HTML, served by the dev server
- No template inheritance — the shell is JS, mounted at runtime via
mountShell() - No CSS imports — the bundle is the same for every page
- No build-step registration — webpack auto-picks up new
src/*.htmlfiles (after a restart)
Removing a page
Just the reverse:
- Delete
src/reports.html - Remove the entry from
titlesinhtmlPlugin.js - Remove the entry from
NAVinShell.js - Restart the dev server
A common gotcha
If your new page renders without the sidebar/topbar/footer, you probably forgot the three placeholder divs (data-shell-sidebar, data-shell-topbar, data-shell-footer). Shell.js looks for those at runtime — no placeholders, no shell.
If the sidebar renders but no item is highlighted, your data-active value doesn’t match any key in NAV. Both have to agree.
If breadcrumbs are blank, you forgot data-crumbs on <body>.