1688 Commits
Author SHA1 Message Date
openhands 187af2e147 fix: strip existing sso param from clientUrl, add aria roles to dropdowns, add x-pathname fallback, move .dropdown-menu into @layer components 2026-07-03 16:17:42 +02:00
openhands 7e616ca6b3 refactor: extract duplicate header into shared renderHeader function 2026-07-03 16:05:56 +02:00
openhands 98c9b951c4 fix: remove duplicate site-bg, handle fullscreen promise rejection, unify tooltip language, improve dropdown CSS compat and accessibility 2026-07-03 16:03:09 +02:00
openhands e5b0649bf1 fix: remove debug console.log from root layout 2026-07-03 15:51:33 +02:00
openhands 7e5813bd97 Fix client loading as atomcms normal 2026-07-03 15:16:47 +02:00
openhands bedf0ee7fa chore: update nodemailer to latest, revert otplib to v12 due to breaking changes 2026-07-02 17:39:48 +02:00
openhands 1b4930af0b chore: add uploaded media files 2026-07-02 17:28:24 +02:00
openhands 518c072491 refactor: convert admin pages to Tailwind and improve media uploads; fix TypeScript error in commandocentrum 2026-07-02 17:26:16 +02:00
openhands 72ef74fc87 refactor: enhance admin panel styling with better card patterns
- Dashboard: use admin-card for sections, refine progress bars and action badges
- Applications: enhanced card styling with p-3 and better text hierarchy
- Emulator: convert remaining 'card' classes to 'admin-card'
- All changes eliminate inline styles and use consistent Tailwind patterns

Co-authored-by: openhands <[email protected]>
2026-07-02 16:27:06 +02:00
openhands 928544100b Convert admin pages to new Tailwind design pattern
- Replace 'card' class with 'admin-card' (gradient cards, dark mode support)
- Replace 'muted' class with consistent Tailwind muted states
- Standardize page headers with gradient backgrounds and Lucide icons
- Convert all inline styles to Tailwind classes
- Add admin-page CSS helpers (admin-card, admin-filter-bar, admin-section-title)
- Apply pattern to all 42 admin pages (was only 6 before)
- Zero TypeScript errors, production builds successfully

Co-authored-by: openhands <[email protected]>
2026-07-02 16:05:35 +02:00
remco b621ec79a3 refactor: improve admin panel styling with new CSS helpers and page layout patterns
- Add .admin-card, .admin-filter-bar, .admin-stat-row, .admin-stat-chip, .admin-section-title, .admin-info-grid, .admin-empty CSS helpers
- Improve admin table styling (uppercase headers, better spacing, border-separate)
- Add dark mode support for admin tables and cards
- Update housekeeping and settings pages to use new layout components
- Clean up inline styles in housekeeping and settings pages
2026-07-02 15:38:17 +02:00
remco 1ea953fd65 fix: housekeeping page onClick in server component replaced with Link 2026-07-02 15:36:05 +02:00
remco cf287dbc8b feat: redesign admin panel with Lucide icons and modern styling
- Add lucide-react for SVG icons throughout the admin
- Redesign sidebar with gradient background, icons per nav item, and sticky layout
- Redesign topbar with cleaner user info display
- Redesign dashboard with icon-backed stat cards, gradient progress bars, activity feed
- Update AdminNavLink with icon support and new active state styling
- Improve table styling in admin-page CSS (rounded corners, hover, spacing)
- Clean up unused admin CSS
2026-07-02 15:33:23 +02:00
remco bd299be55d refactor: convert admin panel to Tailwind CSS
- Convert admin layout, sidebar, and navigation to Tailwind classes
- Convert dashboard components (StatusCard, DiagnosticRow, etc.) to Tailwind
- Convert all ~48 admin page files from admin CSS classes to Tailwind
- Remove unused admin CSS from globals.css (973 → 712 lines)
- Convert developers page badges to Tailwind
- Remove <style jsx> block from OnlineUsersWidget
2026-07-02 15:23:07 +02:00
remco 64f50b2dde fix: resolve auth security issues - 2FA require TOTP on disable, rate limiting, timing-safe login, token expiry check 2026-07-02 14:54:25 +02:00
remco 4a06b30263 feat: complete admin error handling improvements - add error display to articles pages
- Add error display to articles pages (overview, edit, new)
- Improve createArticle action to handle database errors gracefully
- Redirect with error query params for user feedback on failure
- Completes error handling improvements across admin pages
- Enhances error reporting for better user experience
2026-07-01 21:32:59 +02:00
remco 0323c3fcaa fix: improve error handling in admin pages to show user-friendly error messages
- Add error display to help questions new/edit pages
- Improve error visibility in admin-badges, admin-applications, admin-logs, admin-users pages
- Update createHelpQuestion action to properly handle and display unique name collisions and database errors
- Add user-friendly error messages to admin error handling
- Enhances admin page error reporting for better user experience
2026-07-01 21:25:30 +02:00
remco d775e893f4 Rollback housekeeping changes to restore stable state 2026-07-01 20:31:32 +02:00
remco 2efd03de0f fix: complete user admin actions - form-based inline actions and API endpoint for bulk operations 2026-07-01 19:05:18 +02:00
remco c3de7cb576 style: complete housekeeping improvements - online users widget, sidebar cleanup 2026-07-01 18:57:10 +02:00
remco dca77a891b feat: enhance housekeeping page with search, import mode and inline form editing 2026-07-01 18:45:01 +02:00
remco 393e6ccbee feat: add Staff Activity Log (audit trail) page 2026-07-01 18:44:32 +02:00
remco beb36d2dbf feat: improve users page with inline staff actions and commandocentrum cleanup 2026-07-01 18:38:50 +02:00
remco d588ae5f0f style: polish enter button with gradient, inner highlight, arrow icon, and premium hover effects 2026-07-01 18:03:52 +02:00
remco d7138f3a32 fix: make enter button use theme primary color 2026-07-01 17:33:14 +02:00
remco 121459db22 fix: redesign avatar backdrop on home page for professional look
- Improve login card backdrop with cover background, multi-point gradient overlay, and decorative primary glow
- Redesign authenticated user hero section with layered background, dual decorative glows, glass-morphism enter button, and avatar positioned naturally at bottom
- Replace plain bg-black/30 overlay with rich gradient depth
2026-07-01 17:31:28 +02:00
remco 1e787c6c62 feat: complete header and dropdown redesign for professional look
- Redesign site header with multi-layer gradient overlays, decorative glows, dot pattern texture, responsive clamp font sizing, and animated ping online badge
- Add glass-dropdown CSS class with 60% opacity backdrop blur (20px) and smooth dropdownIn animation (scale + translate)
- Fix dropdown positioning with top-full for proper alignment under menu triggers
- Standardize all dropdowns (nav, top-header, color picker, language switcher) to use glass-dropdown class
2026-07-01 17:28:10 +02:00
remco 5bddf99cbe fix: improve backdrop blur visibility on dropdowns and overlays
- Reduce dropdown background opacity from 97% to 80% so backdrop-filter is visible
- Add glass-dropdown CSS class with blur(16px) and saturate(180%)
- Add backdrop blur to mobile nav overlay for smoother feel
- Increase photo lightbox backdrop blur from 2px to 8px
- Add background-blend-mode: overlay to site-bg for richer texture
2026-07-01 17:18:57 +02:00
remco 25d455f0b6 feat: major visual polish - warmer habbo colors, glass-morphism elements, smoother animations, improved site header with gradient overlay, refined card/button/input styles 2026-07-01 17:14:41 +02:00
remco f2d13cf644 fix: serve uploaded images via /api/media/[name] to avoid Next.js static 404 2026-07-01 17:10:43 +02:00
remco 12576cc113 feat: media library with image picker for article forms, browse/upload from folder 2026-07-01 17:00:35 +02:00
remco d35c495539 fix: habbo background with primary color tint, restore epicnabbo text logo 2026-07-01 16:12:47 +02:00
remco ad1a13af00 fix: add navbar background to MobileNav wrapper so middle section (home, shop, etc.) also gets the color 2026-07-01 16:06:21 +02:00
remco f2f340fc83 fix: top-header now uses --color-navbar background and --color-navbar-text for text, so the whole top bar matches the picked navbar color 2026-07-01 16:03:49 +02:00
remco 5b7bd1ebb0 fix: pre-hydration navbar color to prevent flash, fix hydration mismatch in color picker 2026-07-01 16:02:01 +02:00
remco d6ccc250f6 feat: mobile nav, radio layout/requests, leaderboard tabs, client i18n, habbo background, navbar fixes 2026-07-01 15:59:02 +02:00
remco 16096eff0f Restore .env.example 2026-07-01 15:07:50 +02:00
remco 1de72863db latest changes 2026-07-01 15:06:52 +02:00
Simo 56cd6fd058 Fix Nitro client launcher: read the nitro_path setting
The /client launcher read a non-existent `nitro_client_url` setting, so it
always fell through to "No client configured" and the client never launched.
Faithful to AtomCMS's NitroController + nitro.blade.php, build the launch URL
as {nitro_path}/index.html?sso=<ticket> plus the toolbar colour params, via a
shared buildNitroClientUrl helper. The Flash launcher's Nitro fallback used the
same dead key and is fixed too.
2026-06-29 21:10:44 +02:00
Simo 54ec99de6d 101%: app-level DDoS guard, PWA, /api/health, API docs, worker JAR backup
Beyond parity — the web-feasible versions of the "host-only" items plus
extras AtomCMS doesn't have:
- App-level abuse/DDoS guard (src/lib/services/abuse-guard.ts): counts
  requests per IP and auto-adds flooders to website_ip_blacklist (enforced
  by the access guard) + fires ddosDetected(). OFF by default, tunable via
  settings. The iptables layer stays host-only; this is the real app-tier
  mitigation. Access guard now also enforces the IP blacklist (cached).
- PWA: a themeable web manifest (src/app/manifest.ts) + a service worker
  (public/sw.js, cache-first assets / network-first pages) registered after
  hydration — the hotel is now installable.
- /api/health: DB + emulator(RCON) + runtime status probe.
- /developers: a public API documentation page covering every REST endpoint
  with its method, path and auth requirement.
- jobs-worker: daily emulator JAR backup (runs host-side in the worker, like
  AtomCMS's backup command) — copies + prunes; no-ops unless EMULATOR_JAR_PATH
  + EMULATOR_BACKUP_DIR are set.

Verified live (prod, amx_test): /api/health ok, manifest + sw served, docs
page renders, normal pages unaffected by the guard. tsc 0, vitest 49/49,
next build 0.
2026-06-29 18:39:23 +02:00
Simo 4dfe698009 Close remaining web gaps: rich profile, login history, lightbox/slider, flash client, admin chatlog/DJ/chart/WYSIWYG, niche API
- Rich profile (/u/[username]): wallet (credits/duckets/diamonds), friends
  grid (messenger_friendships), and owned rooms sections.
- Login history: new website_login_logs table (model + migration 0007),
  recorded on every successful sign-in (ip + user-agent), surfaced on a new
  /settings/sessions page (with failed-attempt list from failed_logins).
- Photos lightbox + home article slider (client components, no Swiper dep).
- /client/flash launcher (SSO ticket like the Nitro page).
- Admin: private chatlogs section in /admin/logs, /admin/radio/moderation
  (shout moderation), a "users by rank" inline bar chart on the dashboard,
  and a TinyMCE rich-text editor on the article admin forms.
- Niche API: /api/values/[id], /api/guilds(+/[id]), /api/radio/auto-play.

Verified live (prod, amx_test): login recorded → /settings/sessions shows
it with device; profile renders wallet/friends/rooms; dashboard chart +
private-chat logs + /client/flash + /api/guilds all OK. Reverted test data.
tsc 0, vitest 49/49, next build 0.
2026-06-29 18:26:34 +02:00
Simo f7b3845131 Close the web-feasible 100% gaps: REST write/token API, tickets, draw-badge, /me, sanitisation, dusk, radio SSE
Final parity push (web-tier only):
- REST API write + token auth: POST /api/tokens (issue a personal_access_token
  for the session user), Bearer auth via src/lib/api-auth.ts, POST
  /api/articles/[slug]/comment, GET/DELETE /api/me/tokens, full tickets API
  (/api/tickets +[id] +[id]/reply), radio current-dj/points/points-leaderboard/
  embed-config + POST shouts, and a real-time /api/radio/stream (SSE). 31 public
  API routes total.
- Pages: /draw-badge (buy a custom profile badge → credits + RCON), /me
  dashboard (stats + online friends + referral claim). Wired into the nav.
- HTML sanitisation (sanitize-html) — the HTMLPurifier equivalent — applied to
  writeable boxes + article bodies before dangerouslySetInnerHTML.
- "Dusk" dark theme preset + a default-dark site option honoured by the
  no-flash boot script.

Verified live (prod, amx_test): token issue → Bearer endpoint 200, no-token
401; /api/me/tokens lists it; current-dj/leaderboard JSON; /me + /draw-badge
200; reverted the test user + tokens. tsc 0, vitest 49/49, next build 0.
2026-06-29 18:15:01 +02:00
Simo 8cedf5614e UI gaps: radio player widget, logo generator, public room page
Phase D of the parity push:
- Radio player: fixed bottom-right widget (port of atom's radio-player.blade)
  that streams the hotel radio via <audio>, with play/pause, volume, current
  DJ / now-playing and live listener count, polling the public API every 15s.
  A server gate (RadioPlayerGate) only mounts it when radio is enabled + a
  stream URL is set, so no widget JS ships when off. Mounted in the layout.
- Logo generator (/logo): client tool — hotel name + font/colour/size pickers
  with a live preview and "download PNG" via canvas.
- Public room page (/room/[id]): renders an emulator room (name, owner,
  users/max, state, category) in a ContentCard.

Verified live (prod, amx_test): /logo renders the generator, /room/50 shows
the real room "Dark Elegant Bundle", and with radio enabled the player
mounts fixed bottom-right (audio + play/pause + Test FM); reverted the test
settings. tsc 0, vitest 49/49, next build 0.
2026-06-28 21:48:42 +02:00
Simo 80f591a343 Add public REST API, anti-abuse protections, radio/GitHub cron jobs
Phase A — Public REST API (was the biggest gap). 20 JSON endpoints under
/api mirroring AtomCMS: users/[username], online(+/count), me, articles
(+/[slug]), photos, home, staff, teams, leaderboard, shop(+/categories),
values(+/categories), settings, radio/{config,now-playing,listeners,
shouts}. Shared src/lib/api.ts (apiJson — BigInt-safe + CORS, pagination).
Read-only, fail-soft, and field-safe (never exposes password/auth_ticket/
2FA secrets/mail).

Phase B — Anti-abuse on registration: CAPTCHA (Cloudflare Turnstile /
Google reCAPTCHA, settings-driven, widget rendered on the register page),
VPN/proxy detection (proxycheck.io / IPQualityScore via /admin/vpn
settings), and max-accounts-per-IP. All fail-open when unconfigured.
src/lib/services/{captcha,ip-lookup}.ts.

Phase C — jobs-worker cron suite: radio-record-songs (30s, logs track
changes to radio_song_plays), radio-auto-dj (rotates radio_auto_dj_playlist
when no live DJ), github-update-check (hourly, sets update_available).
Shared src/lib/services/radio.ts (now-playing/listeners parsing).

Verified live (prod, amx_test): /api/* return real JSON (leaderboard 6
users, settings carry no secrets, user endpoint hides password). tsc 0,
vitest 49/49, next build 0 (20 new API routes).
2026-06-28 21:44:02 +02:00
Simo 5a4b6f27e9 Extend the theme editor: typography, button/link colours, custom CSS, more presets
Grew /admin/theme from colours-only to a full theme editor, all applied
live via website_settings + ThemeVars:
- Typography: body font (10 web-safe + Google options; Google fonts load
  via an injected <link>) and H1/H2/H3 sizes (globals.css now reads
  --size-heading-* vars).
- Buttons & links: secondary/danger button colours + link/link-hover.
- Custom CSS: a raw textarea injected after the theme variables (staff-
  trusted), for anything the controls don't cover.
- Presets: 6 → 13 (added Galaxy, Royal, Cyberpunk, Neon, Coffee, Arctic,
  Christmas). ThemeVars now injects all the new vars + the font link.

Verified live (prod, amx_test): saved font=mono / H1=44px / custom CSS →
the public home reflected --font-family "Courier New", --size-heading-h1
44px and the injected rule; reverted the test settings. tsc 0,
vitest 49/49, next build 0.
2026-06-28 21:14:10 +02:00
Simo 0cd4d06ff6 Fill the remaining gaps: badge upload, radio tools, VPN, writeable boxes
Built the admin tools previously listed as missing:
- Badge upload (/admin/badges): uploads a <code>.gif into the emulator's
  badge dir via BADGE_UPLOAD_DIR (node:fs); validated code/type/size,
  logged. Made configurable rather than skipped.
- Radio tools: /admin/radio/api-keys (CRUD, server-generated keys),
  /admin/radio/autodj (Auto-DJ playlist CRUD), /admin/radio/embed (embed
  snippet generator), /admin/radio/points (points settings),
  /admin/radio/monitoring (live stream/now-playing/listeners status).
  radio_api_keys + radio_auto_dj_playlist already had real columns.
- /admin/vpn: VPN/proxy detection config (block toggle + provider + key),
  complementing /admin/ip's raw blacklist.
- Writeable boxes: new website_writeable_boxes table (model + migration
  0006) + /admin/writeable-boxes CRUD; active boxes render on the public
  home page. env: BADGE_UPLOAD_DIR.

Verified live (prod, amx_test): all 8 pages render with real data; a test
writeable box appeared on the public home and was reverted. tsc 0,
vitest 49/49, next build 0 (7 new admin routes).
2026-06-28 21:04:34 +02:00
Simo e004dfedaf i18n: translate all public page bodies (EN + IT)
Internationalised the ~44 public pages with next-intl (the shell was
already translated). Each page now pulls its copy from a "pages.<slug>"
namespace via getTranslations (server) / useTranslations (client); the
EN + IT catalogs were authored by parallel agents and merged centrally,
with natural Italian (ICU plurals) and it backfilled from en for any
gap. request.ts gained getMessageFallback/onError so a missing key
degrades to the English value, never a raw key.

Behaviour unchanged (only display text moved to t() calls; queries,
actions, fields, ContentCard structure preserved). Verified on the prod
server: with NEXT_LOCALE=it, home/community/staff/news/shop/rankings all
render Italian copy, no raw-key leakage; English unchanged. The nav
language switcher toggles EN/IT live. tsc 0, vitest 49/49, next build 0.

Admin pages intentionally left in English (staff tooling).
2026-06-28 20:40:06 +02:00
Simo 1199176883 Add Theme Settings tool + polish remaining radio detail pages
- New /admin/theme: recolour the whole site from housekeeping. 6 atom-
  faithful presets (Atom/Midnight/Ocean/Forest/Sunset/Candy) + per-colour
  pickers for the 12 settings ThemeVars injects + border radius. Writes to
  website_settings, busts the siteSettings cache, and revalidates the
  layout so the new palette applies live with no rebuild. Constants live
  in src/lib/theme-presets.ts (a "use server" file can't export objects).
  Added to the admin sidebar (System).
- radio/contests/[id] + giveaways/[id] wrapped in ContentCard to match
  the public design system.
- Skipped a separate VPN page: /admin/ip already manages the IP
  white/blacklist, so it would only duplicate it.

Verified live (prod, amx_test): applied the Ocean preset → home renders
--color-primary #0ea5e9 site-wide; reverted the test rows. tsc 0,
vitest 49/49, next build 0.
2026-06-28 20:20:38 +02:00
Simo 6f15e0c8a3 Production hardening: error pages, rate limiting, metadata
- Custom not-found (404) + error / global-error boundaries, styled with
  the public design system; raw errors logged, never shown to users.
- In-process rate limiter (src/lib/rate-limit.ts) wired into the abuse-
  prone flows: login (10/5min/IP), register (5/10min/IP), password-reset
  request (3/15min/IP), keyed by the proxy-forwarded client IP.
- SEO/metadata: root generateMetadata sets a `%s · {hotel}` title
  template from the live hotel_name; dynamic generateMetadata on
  news/[slug] (article title + excerpt) and u/[username] (name + motto);
  static titles on 12 primary public pages.
- env.ts: added the vars introduced since (PASSWORD_HASH, OPENAI_API_KEY,
  DISCORD_WEBHOOK_URL, ALERT_EMAIL, PAYPAL_*) so env stays authoritative.

Verified on the prod server: /missing → 404 card, news title renders
"News · Habbo". tsc 0, vitest 49/49, next build 0.
2026-06-28 20:12:12 +02:00
Simo e9ea19795a Adapt + improve all public pages to the atom design system
Extended the same design-system treatment to the public site, faithful
to AtomCMS's "atom" theme. New src/components/public/ui.tsx provides the
signature atom building blocks + a scoped CSS layer:
- ContentCard: surface card with a primary-tinted header (icon circle +
  title + subtitle) and padded body — the atom content-card, used as
  every page's header and section wrapper.
- StatBlock / stat-grid, EmptyState, OnlineBadge (online/offline pill),
  RankBadge (medals for the top 3), and responsive .card-grid helpers.

Swept ~45 public pages (home/community/rankings hand-built as the
reference; the rest via parallel agents that read the schema and
preserved every query, server action, auth gate and field name):
heroes → ContentCard headers, lists → card-grids in ContentCards,
"no X" → EmptyState, status → OnlineBadge/RankBadge. The leaderboard
gained Credits/Diamonds/Duckets tabs (usersCurrency).

Behaviour unchanged. Verified on the prod server against amx_test: 15+
public pages render the content-cards/grids with real data, no errors;
computed styles confirm the tinted header, icon circle, medal + online
pills. Fixed an undefined --color-golden ref. tsc 0, vitest 49/49,
next build 0.
2026-06-28 19:28:36 +02:00