diff --git a/README.md b/README.md index ddb13e3..c7e031f 100644 --- a/README.md +++ b/README.md @@ -895,18 +895,110 @@ Set `data-theme="light"` on `` directly. All component styles react throug --- +## Starting a New App + +### 1. Serve the design system files + +Add an nginx alias so every app on the same host can reference the same files: + +```nginx +# In each app's server block (or a shared include): +location /web_template/ { + alias /path/to/web_template/; + expires 7d; + add_header Cache-Control "public, immutable"; +} +``` + +Then in your HTML: +```html + + +``` + +### 2. Copy the right skeleton + +| Stack | Copy this file | Into your app as | +|-------|---------------|-----------------| +| PHP | `php/layout.php` | `views/layout.php` (or `layout_header.php`) | +| Python/Flask | `python/base.html` | `templates/base.html` | +| Node/Express | `node/middleware.js` + `node/layout.ejs` | `middleware.js` + `views/layout.ejs` | + +### 3. Define your nav + +**PHP** — pass `$navLinks` before including the layout: +```php +$navLinks = [ + ['href' => '/', 'key' => 'dashboard', 'label' => 'Dashboard'], + ['href' => '/reports', 'key' => 'reports', 'label' => 'Reports'], + ['label' => 'Admin', 'key' => 'admin', 'adminOnly' => true, 'children' => [ + ['href' => '/admin/users', 'label' => 'Users'], + ]], +]; +$activeNav = 'dashboard'; +include __DIR__ . '/views/layout.php'; +``` + +**Python/Flask** — inject via context processor or pass directly to `render_template`: +```python +nav_links = [ + {'href': url_for('index'), 'key': 'dashboard', 'label': 'Dashboard'}, + {'href': url_for('settings'), 'key': 'settings', 'label': 'Settings'}, +] +return render_template('page.html', nav_links=nav_links) +``` + +**Node/Express** — set on `res.locals` via `injectLocals` middleware: +```js +app.use((req, res, next) => { + res.locals.navLinks = [ + { href: '/', key: 'dashboard', label: 'Dashboard' }, + { href: '/workers', key: 'workers', label: 'Workers' }, + ]; + next(); +}); +``` + +### 4. Add app-specific CSS + +Create `app.css` in your app. Import nothing from `base.css` — just override tokens or add components: +```css +/* app.css — app-specific extensions only */ +:root { + --app-accent: #FF6B00; /* override if needed */ +} +/* Only put styles here that aren't already in base.css */ +``` + +### 5. Initialise + +In your base template, after `base.js`: +```html + +``` + +--- + ## File Structure ``` web_template/ -├── base.css Design system styles (79 sections, ~5,200 lines) -├── base.js Design system JS (55+ modules, ~2,800 lines) -├── base.html Living reference template -├── README.md This file -└── (framework skeletons) - ├── php/ PHP / Tinker Tickets - ├── python/ Flask / Jinja2 / GANDALF - └── node/ Express / EJS / PULSE +├── base.css Design system styles (79 sections, ~5,200 lines) +├── base.js Design system JS (55+ modules, ~2,800 lines) +├── base.html Living component reference — open in browser to browse everything +├── README.md This file +├── AUTHELIA_INTEGRATION.md Theming Authelia portal with this design system +└── framework skeletons/ + ├── php/ + │ └── layout.php Generic PHP base layout (pass $navLinks) + ├── python/ + │ ├── base.html Jinja2 base template (pass nav_links list) + │ └── auth.py Authelia SSO helper for Flask + └── node/ + ├── middleware.js Express middleware (auth, CSRF, nonce, rate limit) + └── layout.ejs EJS base template (uses res.locals.navLinks) ``` --- diff --git a/node/layout.ejs b/node/layout.ejs new file mode 100644 index 0000000..c1aa757 --- /dev/null +++ b/node/layout.ejs @@ -0,0 +1,146 @@ +<%– + LOTUSGUILD TERMINAL DESIGN SYSTEM — Node.js / Express EJS Base Layout + Extend this in every page template via res.render('page', { ... }). + + Required Express setup (server.js / app.js): + const { requireAuth, cspNonce, injectLocals } = require('./middleware'); + app.use(cspNonce); + app.use(requireAuth); + app.use(injectLocals); + app.set('view engine', 'ejs'); + + Locals injected automatically by middleware.js: + user { username, name, email, groups, isAdmin } + nonce CSP nonce string + appName process.env.APP_NAME + appSubtitle process.env.APP_SUBTITLE + + Locals to set per-route (or via a second res.locals middleware): + pageTitle string — page