source: Klonkt/src/routes/hub.js@ 0b7ebbf

main
Last change on this file since 0b7ebbf was 63edb0d, checked in by Robin Genis <roboburr@…>, 3 months ago

hub: hero image upload + dark overlay slider

Reconcile of live edits on /srv that were not yet in git (split-brain).

  • admin-settings: multer upload (jpg/png/webp/gif, 5MB, SVG blocked against XSS) + overlay clamp
  • hub.js / hub-home.ejs: dark overlay as CSS var (default 45%, non-breaking)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@…>

  • Property mode set to 100644
File size: 3.5 KB
RevLine 
[bf61be7]1/**
2 * Hub-hoofdpagina — alleen in hub-modus. In plaats van de primaire PrutFolio te
3 * tonen, rendert '/' hier een bedrijfs-overview: de laatste posts van ALLE
4 * gebruikers samengevat + een lijst van de PrutFolio's.
5 *
6 * In solo-modus doet dit niets (next()) en rendert posts.js de enige site.
7 */
8
9import express from 'express';
10import db from '../config/database.js';
11import { renderPage } from '../middleware/render.js';
[6e0249f]12import { getTenancy, getSetting } from '../services/SettingsService.js';
[bf61be7]13
14const router = express.Router();
15
16router.get('/', (req, res, next) => {
17 if (getTenancy() !== 'hub') return next();
[743bb81]18 // Als resolveSite een specifieke site adresseerde (/user/:slug of /sites/:slug),
19 // is req.url naar '/' herschreven — dan NIET de overview tonen maar de site zelf
20 // laten renderen door posts.js. siteUrlBase is dan gezet.
21 if (res.locals.siteUrlBase) return next();
[bf61be7]22
23 // Laatste gepubliceerde posts over álle sites heen.
24 const posts = db.prepare(`
25 SELECT p.title, p.slug, p.excerpt, p.published_at, p.created_at,
26 p.cover_image_url, p.type,
27 s.slug AS site_slug, s.title AS site_title, s.profile_photo AS site_photo,
28 u.username AS author_username
29 FROM posts p
30 JOIN sites s ON s.id = p.site_id
31 LEFT JOIN users u ON u.id = p.author_id
32 WHERE p.status = 'published'
33 ORDER BY COALESCE(p.published_at, p.created_at) DESC
34 LIMIT 24
35 `).all();
36
[ce8c8c2]37 // De hoofd-/labelsite (oudste = de bedrijfs-/hoofdaccount) is GEEN artiest;
38 // die tonen we apart bovenaan, niet in de Artiesten-roster.
39 const mainSite = db.prepare(`
40 SELECT s.id, s.slug, s.title, s.tagline, s.profile_photo, s.accent,
41 u.avatar_url AS owner_avatar,
42 (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
43 FROM sites s
44 LEFT JOIN users u ON u.id = s.owner_id
45 ORDER BY s.created_at ASC
46 LIMIT 1
47 `).get() || null;
48 const mainId = mainSite ? mainSite.id : '';
49
[8afbdd6]50 // Uitgelichte PrutFolio's voor de home-roster: meest-actief eerst (aantal
[ce8c8c2]51 // gepubliceerde posts), dan nieuwste. Excl. de hoofdsite. Beperkt tot
[a1c8cb8]52 // HOME_ROSTER_LIMIT zodat de home schaalt — volledige lijst staat op /leden.
[8afbdd6]53 const HOME_ROSTER_LIMIT = 24;
[6e0249f]54 const artists = db.prepare(`
[4c5169f]55 SELECT s.slug, s.title, s.tagline, s.profile_photo, s.accent,
[ab544fd]56 u.avatar_url AS owner_avatar,
[bf61be7]57 (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
58 FROM sites s
[ab544fd]59 LEFT JOIN users u ON u.id = s.owner_id
[ce8c8c2]60 WHERE s.id != @mainId
[8afbdd6]61 ORDER BY post_count DESC, s.created_at DESC
[ce8c8c2]62 LIMIT @limit
63 `).all({ mainId, limit: HOME_ROSTER_LIMIT });
64 const totalArtists = db.prepare('SELECT COUNT(*) AS c FROM sites WHERE id != ?').get(mainId).c;
[bf61be7]65
[6e0249f]66 // De hub-pagina is GENERIEK (van geen enkele user) — branding komt uit globale
67 // instellingen die de admin in Beheer beheert, niet uit een site.
68 const hub = {
69 title: getSetting('hub_title') || 'Overzicht',
70 tagline: getSetting('hub_tagline') || '',
71 intro: getSetting('hub_intro') || '',
[4c5169f]72 heroImage: getSetting('hub_hero_image') || '',
[63edb0d]73 heroOverlay: (() => { const v = parseInt(getSetting('hub_hero_overlay'), 10); return Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 45; })(),
[6e0249f]74 };
[bf61be7]75
76 renderPage(req, res, 'pages/hub-home', {
[6e0249f]77 pageTitle: hub.title,
78 socialDescr: hub.intro || hub.tagline || '',
[4d7443b]79 bodyClass: 'on-home on-hub',
[6e0249f]80 hub,
[ce8c8c2]81 mainSite,
[4d7443b]82 artists,
[8afbdd6]83 totalArtists,
84 rosterLimit: HOME_ROSTER_LIMIT,
[bf61be7]85 posts,
86 });
87});
88
89export default router;
Note: See TracBrowser for help on using the repository browser.