Changeset 6e0249f in Klonkt


Ignore:
Timestamp:
06/14/2026 03:21:25 PM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
4c5169f
Parents:
743bb81
Message:

hub: generic home page (not owned by any user) + admin-managed branding

The hub home page was the oldest site (a user's PrutFolio). Now it is a
generic page: title/tagline/intro come from global settings (hub_title/
hub_tagline/hub_intro), editable in Admin -> Settings (hub only). The roster
now shows ALL users (including the admin's own PrutFolio under /user/<slug>)
— no site is singled out as "the company" any more.

POST /admin/settings only updates tenancy when the field is present (a
separate branding form no longer accidentally flips the mode).

Co-Authored-By: Claude <noreply@…>

Location:
src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/routes/admin-settings.js

    r743bb81 r6e0249f  
    11/**
    2  * Admin: globale instellingen — nu de tenancy-modus (Solo/Hub).
     2 * Admin: globale instellingen.
     3 *  - tenancy-modus (Solo/Hub)
     4 *  - hub-branding (naam/tagline/intro van de generieke hub-hoofdpagina)
    35 *
    4  * GET  /admin/settings        -> toon huidige modus + uitleg
    5  * POST /admin/settings        -> sla modus op (god-only)
     6 * GET  /admin/settings   -> toon huidige instellingen
     7 * POST /admin/settings   -> sla op (god-only)
    68 *
    7  * Schakelen is niet-destructief: Solo verbergt alleen de multi-site-onderdelen
    8  * en routeert naar de primaire site; er wordt niets verwijderd.
     9 * De hub-pagina is generiek (van geen enkele user); deze branding leeft in
     10 * globale settings, niet in een site.
    911 */
    1012
     
    1214import { renderPage } from '../middleware/render.js';
    1315import { requireGod } from '../middleware/auth.js';
    14 import { getTenancy, setTenancy } from '../services/SettingsService.js';
     16import { getTenancy, setTenancy, getSetting, setSetting } from '../services/SettingsService.js';
    1517
    1618const router = express.Router();
     
    2123    bodyClass: 'on-admin',
    2224    tenancy: getTenancy(),
     25    hubTitle: getSetting('hub_title') || '',
     26    hubTagline: getSetting('hub_tagline') || '',
     27    hubIntro: getSetting('hub_intro') || '',
    2328    success: req.query.success || null,
    2429  });
     
    2631
    2732router.post('/', requireGod, (req, res) => {
    28   setTenancy(req.body.tenancy === 'hub' ? 'hub' : 'solo');
    29   res.redirect('/admin/settings?success=' + encodeURIComponent('Modus opgeslagen'));
     33  if (typeof req.body.tenancy !== 'undefined') {
     34    setTenancy(req.body.tenancy === 'hub' ? 'hub' : 'solo');
     35  }
     36  if (typeof req.body.hub_title !== 'undefined') {
     37    setSetting('hub_title', (req.body.hub_title || '').toString().slice(0, 80).trim());
     38  }
     39  if (typeof req.body.hub_tagline !== 'undefined') {
     40    setSetting('hub_tagline', (req.body.hub_tagline || '').toString().slice(0, 120).trim());
     41  }
     42  if (typeof req.body.hub_intro !== 'undefined') {
     43    setSetting('hub_intro', (req.body.hub_intro || '').toString().slice(0, 400).trim());
     44  }
     45  res.redirect('/admin/settings?success=' + encodeURIComponent('Opgeslagen'));
    3046});
    3147
  • src/routes/hub.js

    r743bb81 r6e0249f  
    1010import db from '../config/database.js';
    1111import { renderPage } from '../middleware/render.js';
    12 import { getTenancy } from '../services/SettingsService.js';
     12import { getTenancy, getSetting } from '../services/SettingsService.js';
    1313
    1414const router = express.Router();
     
    3535  `).all();
    3636
    37   // De PrutFolio's (sites) voor de gebruikers-lijst.
    38   const sites = db.prepare(`
    39     SELECT s.slug, s.title, s.profile_photo,
    40            u.username AS owner_username,
     37  // ALLE PrutFolio's (elke user, incl. de admin z'n eigen site) voor de roster.
     38  const artists = db.prepare(`
     39    SELECT s.slug, s.title, s.tagline, s.profile_photo,
    4140           (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
    4241    FROM sites s
    43     LEFT JOIN users u ON u.id = s.owner_id
    4442    ORDER BY s.created_at ASC
    4543  `).all();
    4644
    47   // De primaire/oudste site geldt als de bedrijfssite (label). De roster toont
    48   // alleen de artiesten (alle overige sites), niet de bedrijfssite zelf.
    49   const company = res.locals.site || null;
    50   const artists = company ? sites.filter((s) => s.slug !== company.slug) : sites;
     45  // De hub-pagina is GENERIEK (van geen enkele user) — branding komt uit globale
     46  // instellingen die de admin in Beheer beheert, niet uit een site.
     47  const hub = {
     48    title: getSetting('hub_title') || 'Overzicht',
     49    tagline: getSetting('hub_tagline') || '',
     50    intro: getSetting('hub_intro') || '',
     51  };
    5152
    5253  renderPage(req, res, 'pages/hub-home', {
    53     pageTitle: company ? company.title : 'Overzicht',
    54     socialDescr: (company && (company.description || company.tagline)) || '',
     54    pageTitle: hub.title,
     55    socialDescr: hub.intro || hub.tagline || '',
    5556    bodyClass: 'on-home on-hub',
    56     company,
     57    hub,
    5758    artists,
    5859    posts,
  • src/views/pages/admin-settings.ejs

    r743bb81 r6e0249f  
    3030    </form>
    3131  </section>
     32
     33  <% if (tenancy === 'hub') { %>
     34  <section class="set-card" style="margin-top:1rem">
     35    <h2>Hub-hoofdpagina</h2>
     36    <p class="set-help">
     37      De openbare hub-pagina (<code>/</code>) is generiek — van geen enkele gebruiker.
     38      Hier stel je de naam en intro in. Jouw eigen PrutFolio blijft los bestaan onder <code>/user/</code>.
     39    </p>
     40    <form method="post" action="/admin/settings" class="set-form">
     41      <label class="set-field">
     42        <span>Naam</span>
     43        <input type="text" name="hub_title" maxlength="80" value="<%= hubTitle %>" placeholder="bijv. Studio Noord">
     44      </label>
     45      <label class="set-field">
     46        <span>Tagline</span>
     47        <input type="text" name="hub_tagline" maxlength="120" value="<%= hubTagline %>" placeholder="bijv. Onafhankelijk muzieklabel">
     48      </label>
     49      <label class="set-field">
     50        <span>Intro</span>
     51        <textarea name="hub_intro" maxlength="400" rows="3" placeholder="Korte introtekst onder de titel."><%= hubIntro %></textarea>
     52      </label>
     53      <button type="submit" class="btn btn-primary">Opslaan</button>
     54    </form>
     55  </section>
     56  <% } %>
    3257</div>
    3358
     
    4873.set-opt code { background: var(--paper-2); padding: 0.05rem 0.35rem; border-radius: 3px; font-size: 0.85em; }
    4974.set-form .btn { align-self: flex-start; }
     75.set-field { display: flex; flex-direction: column; gap: 0.3rem; }
     76.set-field > span { font-size: 0.8rem; font-weight: 600; color: var(--ink-soft, var(--ink-muted)); }
     77.set-field input, .set-field textarea {
     78  width: 100%; box-sizing: border-box; padding: 0.55rem 0.7rem;
     79  border: 1px solid var(--rule); border-radius: 6px; background: var(--paper); color: var(--ink);
     80  font: inherit; font-size: 0.95rem;
     81}
     82.set-field textarea { resize: vertical; }
     83.set-field input:focus, .set-field textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
    5084.alert { padding: 0.75rem 1rem; border-radius: 6px; margin-bottom: 1rem; }
    5185.alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
  • src/views/pages/hub-home.ejs

    r743bb81 r6e0249f  
    44  <header class="hub-hero">
    55    <div class="hub-hero-inner container">
    6       <h1 class="hub-hero-title"><%= company ? company.title : 'Overzicht' %></h1>
    7       <% if (company && company.tagline) { %>
    8         <p class="hub-hero-tag"><%= company.tagline %></p>
     6      <h1 class="hub-hero-title"><%= hub.title %></h1>
     7      <% if (hub.tagline) { %>
     8        <p class="hub-hero-tag"><%= hub.tagline %></p>
    99      <% } %>
    10       <% if (company && (company.profile_bio || company.description)) { %>
    11         <p class="hub-hero-desc"><%= company.profile_bio || company.description %></p>
     10      <% if (hub.intro) { %>
     11        <p class="hub-hero-desc"><%= hub.intro %></p>
    1212      <% } %>
    1313    </div>
Note: See TracChangeset for help on using the changeset viewer.