Commit Graph

461 Commits

Author SHA1 Message Date
medievalshell 8e95ca9570 style(catalog): logo info torna a contain (immagine intera con bordi) 2026-05-30 03:22:48 +02:00
medievalshell a034517143 style(catalog): logo info edge-to-edge (object-cover) 2026-05-30 03:17:32 +02:00
medievalshell 624a310c59 style(catalog): logo info massimizzato senza crop, testo box piu piccolo 2026-05-30 03:14:36 +02:00
medievalshell 9f737c5129 style(catalog): logo info a tutta larghezza (no crop, no margini) 2026-05-30 03:08:44 +02:00
medievalshell 552cd1f538 fix(catalog): layout info BC nasconde la navigazione vuota a sinistra 2026-05-30 02:43:07 +02:00
medievalshell 6db8d3e191 feat(catalog): layout info BC (logo 70% + box testo nero) via info_duckets 2026-05-30 02:34:25 +02:00
medievalshell 72952318c0 fix(catalog-admin): non re-includere ' (pageId)' nella caption editata
Il form di modifica pagina precompilava la caption con la localization
che include il suffisso ' (id)' aggiunto dal server ai mod, e salvandola
l'id si accumulava (Wired (1114) (1114) ...). Ora striscia quel suffisso.
2026-05-30 00:26:59 +02:00
medievalshell 4f133abe33 feat(catalog): default upstream, toggle classico = Hippiehotel
Default catalog = rebuild upstream ultima release (CatalogClassicView).
Il toggle 'stile classico' mostra il catalogo Hippiehotel (CatalogModernView).
2026-05-29 23:55:36 +02:00
medievalshell 2b8aca23b6 revert(catalog): ripristina catalogo Hippiehotel.nl (Modern+Classic)
Rimpiazza il catalogo del rebuild upstream con quello originale di
Hippiehotel.nl Nitro-V3 (CatalogModernView ripristinato, ClassicView/
sub-views/CSS pre-merge). CatalogView sceglie Modern (default) o Classic
via il toggle 'stile classico'. Rimosso l'hack CatalogClassicLegacy.css.
2026-05-29 23:49:10 +02:00
medievalshell 32dcbaf265 feat(catalog): stile classico completo via skin legacy
Ripristina il look del catalogo pre-merge come CSS scoped sotto
body.catalog-skin-legacy (CatalogClassicLegacy.css), attivato dal toggle
'stile classico'. CatalogView mette/toglie la classe sul body.
2026-05-29 23:40:37 +02:00
medievalshell dc0a8f965e feat(catalog): toggle stile catalogo classico/moderno
Aggiunge un checkbox nelle impostazioni utente per scegliere lo stile del
catalogo (classico vs moderno) + flag globale catalog.classic.style in
ui-config.json come default per tutti. Override per-utente in localStorage.
2026-05-29 23:36:06 +02:00
medievalshell 643e558aa8 Merge remote-tracking branch 'upstream/Dev' into Dev
# Conflicts:
#	src/hooks/navigator/useNavigatorSearch.ts
2026-05-29 23:06:48 +02:00
duckietm 888073acb1 🆙 Update #2 2026-05-29 15:16:14 +02:00
duckietm d0c11f047a 🆙 Complete rebuild of toolbar / catalog / inventory make it 100% mobile friendly Take #1 2026-05-29 11:30:17 +02:00
duckietm fbcda88cd3 🆙 Update Rare-Value page and fix the loading of the json 2026-05-29 08:31:18 +02:00
medievalshell b360595539 Merge upstream/Dev: fortune wheel settings popup + radio toggle
Adopt upstream wheel redo (Settings popup gated by acc_wheeladmin,
RareValues becomes view-only) and the radio enable/disable config gate.
Drop the broken orphaned duplicates under user-settings/fortune-wheel
and user-settings/rare-values (wrong relative import depth, unused,
failed typecheck). Soundboard / radio / background editor untouched.
2026-05-28 22:28:00 +02:00
simoleo89 d5e64ada25 feat(navigator): search-scope filter chips replace the dropdown (P4 wave 1b)
NavigatorFilterChipsView renders the 5 SearchFilterOptions (anything /
room.name / owner / tag / group) as pill chips instead of a <select>.
Active chip uses bg-primary; the chips sit on their own row above the
search input. Drives the existing searchFilterIndex local state — the
debounce effect already rebuilds the query:value string from it, so no
behavioural change to how searches are issued.

Deferred to wave 1c: saved-search chip row (replacing the 600px sidebar).
That one needs care — a saved-search click sends NavigatorSearchComposer
directly, which P2's accept-filter (result.code must match currentTabCode)
can reject; the chip version must route through setTab/setFilter instead.
Wants browser verification.

navigator suites 28/28, lint:hooks clean, no new typecheck errors.
2026-05-28 18:06:29 +02:00
simoleo89 3bce0c0191 feat(navigator): empty-state + skeleton views, fix double search fetch (P4 wave 1a)
Visual polish, first wave:
- NavigatorEmptyStateView: replaces the bare "No rooms found" text with a
  centered icon + message + a Create-room CTA. Reuses existing i18n keys
  (navigator.search.returned.no.results / .roomsettings.moderation.none /
  .createroom.create) so no new localization entries are needed.
- NavigatorSearchSkeletonView: animate-pulse placeholder rows shown while a
  search is in flight and no result is cached yet (matches the HK dashboard
  skeleton pattern). Replaces the NitroCard.Content spinner overlay for the
  result list.

Bug fix bundled in: NavigatorSearchView called useNavigatorSearch() a second
time purely to read searchResult for its input-sync effect. Since the hook is
not a useBetween singleton, that registered a duplicate NavigatorSearchEvent
listener AND fired a duplicate NavigatorSearchComposer on every search.
NavigatorView now owns the single useNavigatorSearch() call and passes
searchResult to NavigatorSearchView via prop.

Test maintenance: useNavigatorSearch.test.tsx was written for the original
useNitroQuery implementation, which upstream reverted (05d71dd1) to
useMessageEvent + useState. Removed the dead QueryClient scaffolding, fixed
case 1 (assert no fetch starts with empty tab), dropped case 7 (the query
invalidator no longer exists). 6 cases, all green.

Full suite 471/471. Typecheck: only the environmental renderer-mismatch
errors (soundboard / rare-values / floorplan APIs absent from the linked
renderer), none in navigator files.
2026-05-28 18:02:48 +02:00
duckietm 47e8338570 🆙 Wheel of prizes ! 2026-05-28 16:27:48 +02:00
duckietm 06b8fda1c9 🆙 Enable or disable the radio 2026-05-28 15:52:29 +02:00
medievalshell 49836bbeef feat: branding furni image position editor (move + scale)
Adds an "Editor Posizione" button to the furni infostand action bar for
branding / MPU furni, opening a dialog to position and zoom the image:
- draggable dot moves offsetX/Y (live, local preview only)
- slider zooms the image (scale, via the renderer's per-sprite scale)
- offsetZ kept as z-index; Save persists + broadcasts via SetObjectData
- radio "Live" + all editor labels go through LocalizeText (external texts)

Pairs with the renderer branding scale/offset support and Arcturus' `scale`
default on InteractionRoomAds.
2026-05-28 15:33:05 +02:00
duckietm e7088595df 🆙 Small update 2026-05-28 14:05:09 +02:00
DuckieTM 475c71af2e Merge branch 'Dev' into Dev 2026-05-28 13:49:43 +02:00
DuckieTM 30039feb31 Merge branch 'Dev' into feat/navigator-p2-query 2026-05-28 13:06:05 +02:00
DuckieTM eef436f65c Merge pull request #169 from simoleo89/feat/navigator-p5-error-boundaries
feat(navigator): wrap sub-views in WidgetErrorBoundary
2026-05-28 13:05:12 +02:00
DuckieTM 8e46eae3d0 Merge pull request #168 from simoleo89/feat/navigator-modernization
feat(navigator): wired-tools-style hook split + Zustand UI store (P1)
2026-05-28 13:04:48 +02:00
duckietm 69042451e6 🆕 Added the option turn in menu for BOT 2026-05-28 13:01:11 +02:00
medievalshell acb3dd7ef1 feat: hotel radio widget (client-side, multi-station)
Adds a compact collapsible radio widget (top-left) that plays internet
radio streams with the HTML5 Audio API — no server/renderer changes.

- station list loaded from a JSON5 config file (loadGamedata: JSON + JSON5),
  shipped as radio-stations.json5.example so each hotel fills in its own
- shows the selected station + a dropdown (3 visible, scrolls if more) to
  switch; volume slider; animated equalizer + LIVE indicator
- first station autostarts quietly (5%) on load, with a resume-on-first-
  gesture fallback for browser autoplay policy
2026-05-28 10:20:15 +02:00
medievalshell 4833ab8447 feat: soundboard pads can load from a JSON5 file (DB fallback)
When the server (soundboard_sounds table) returns no pads, the client now
loads them from a JSON5 config file (loadGamedata accepts plain JSON and
JSON5). Useful when the DB / CMS isn't set up yet.

File-defined pads play locally for the clicker; DB-backed pads still go
through the server broadcast so everyone in the room hears them. Ships a
radio-style soundboard-sounds.json5.example template.
2026-05-28 10:19:16 +02:00
medievalshell 48ed3ad7ba fix: show furniture-occupied tiles in the floor plan editor
The editor never requested occupied tiles, so tiles holding furniture
were indistinguishable from empty floor and could be edited/voided.

- request GetOccupiedTilesMessageComposer when the editor opens
- handle RoomOccupiedTilesMessageEvent -> SET_OCCUPIED_TILES
- new Tile.occupied flag (kept separate from `blocked`/void): occupied
  tiles render with a distinct marker and are protected from PAINT/
  ERASE/ADJUST and brush-to-selection edits
- occupied is purely informational and never changes the saved tilemap
  (no accidental voiding of floor under furni)

Tests: reducer cases for SET_OCCUPIED_TILES + edit protection; container
test asserts the occupied event is non-destructive on save; route the
canvas pointer test through elementFromPoint (jsdom has no getScreenCTM).
2026-05-28 09:20:20 +02:00
medievalshell 7a65e5bf6d feat: soundboard (room-scoped custom audio pads)
Client side of the soundboard. Room owners enable it in Room Settings >
Misc (next to the YouTube TV toggle). When enabled, a soundboard icon
appears in the toolbar for everyone in the room; pressing a pad broadcasts
the sound so all occupants hear it. Incoming SoundboardPlay is played via
the HTML5 Audio API.

Also: fix FloorplanCanvasSVG to use ReactElement instead of the removed
global JSX namespace (React 19), and pair the client Dev branch with the
renderer fork that carries the custom features in CI.

How sounds are managed (works with any CMS):
Sounds are rows in the `soundboard_sounds` table:
    id, name, url, enabled, sort_order
The emulator loads every row with enabled=1 (ordered by sort_order, id)
and sends the list to clients on room enter; the client plays `url`
directly, so any publicly reachable audio URL works (mp3/ogg/wav).

To add a sound from an admin/housekeeping panel of any CMS:
  1. Upload the audio file to wherever the CMS stores public assets
     (same approach as custom badge images).
  2. INSERT a row into `soundboard_sounds` with the display name and the
     public URL of the uploaded file, enabled = 1.
  3. Reload the emulator soundboard (or restart) to pick it up.
Relative urls resolve against the `soundboard.url.prefix` config key
(falls back to `asset.url`); absolute urls are used as-is.
2026-05-28 09:04:17 +02:00
medievalshell 61aceaa422 feat: rare values panel + fortune wheel UI + prize editor
Toolbar buttons, FortuneWheelView (animated wheel, prize icons, recent winners),
RareValuesView (diamond price guide + staff prize-editor tab), furni infostand
value line, useFortuneWheel/useRareValues hooks, it/en text examples.
2026-05-28 02:39:02 +02:00
simoleo89 26772f7073 feat(navigator): drive search via TanStack Query + setTab/setFilter UI store
NavigatorView reads searchResult/isFetching from useNavigatorSearch
instead of useNavigatorData/useNavigatorUiState. Tab clicks call
setTab(code) on the UI store, which atomically updates the query key
and triggers refetch. The 4 lifecycle useEffect blocks driving the
old imperative flow (needsSearch / reloadCurrentSearch / markReady)
are removed — the query handles all of it now.

NavigatorSearchView has a debounced (300ms) onChange -> setFilter
that drives the same query refetch. Explicit submit (Enter / button)
skips the debounce and calls setFilter immediately.

linkTracker case 'search' now setTab + setFilter + show — no more
pendingSearch ref.

useNavigatorSearch.test.tsx: cast constructors as any to satisfy tsgo
against real renderer types while keeping runtime stubs no-arg-safe.

yarn typecheck / test / lint:hooks all clean (only pre-existing
floorplan environmental failures).
2026-05-27 19:25:30 +02:00
simoleo89 d5b0743382 feat(navigator): wrap sub-views in WidgetErrorBoundary
Each of the 5 Navigator sub-views (RoomCreator, DoorState, RoomInfo,
RoomLink, RoomSettings) is now wrapped in its own WidgetErrorBoundary so
a crash inside one no longer takes down the others. Matches the pattern
already applied to the 13 room widgets + 20 furniture widgets.

Zero behavioural change in the happy path. yarn typecheck +
yarn test --run + yarn lint:hooks all clean (only the 3 pre-existing
floorplan failures remain, unrelated to Navigator).
2026-05-27 19:08:38 +02:00
simoleo89 1d580e6d24 refactor(navigator): migrate all 13 consumers off useNavigator god-hook
Mechanical swap to the new filter hooks landed in the previous commits:
- NavigatorDoorStateView -> useDoorState (snapshot/setSnapshot/reset)
- NavigatorView -> useNavigatorData + useNavigatorUiState +
  useNavigatorActions + direct useNavigatorUiStore.getState() in handlers
  (linkTracker collapsed to a dispatch table; 9 useState gone)
- NavigatorSearchView -> useNavigatorData + useNavigatorActions
  (sendSearch prop drilling removed)
- NavigatorSearchResultItemView -> useDoorState (setSnapshot aliased as
  setDoorData; call sites unchanged - DoorStateSnapshot is compatible)
- 9 bulk consumers (one-line import swap) -> useNavigatorData

Zero behavioural change intended. yarn typecheck + yarn test --run +
yarn lint:hooks all clean on this commit.
2026-05-27 18:58:03 +02:00
duckietm 00fbdc6f6d 🆙 Small update toolbar 2026-05-27 15:37:09 +02:00
DuckieTM 7054567e92 Merge pull request #164 from simoleo89/fix/toolbar-desktop-breakpoint-1700
fix(toolbar): bump desktop layout breakpoint to 1700px to avoid icon clip
2026-05-27 13:51:06 +02:00
duckietm b1244cbd5a 🆙 Fix BOTS in catalog and inventory 2026-05-27 13:42:11 +02:00
duckietm a52a4a024a 🆕 Added Pickup furni to the floorplan 2026-05-27 09:39:08 +02:00
simoleo89 6022911448 fix(toolbar): bump desktop layout breakpoint to 1700px to avoid icon clip
The left-nav container is `max-w-[calc(50vw-242px)]` (reserves the chat
frame width) and uses `overflow-x: clip`. With the full icon set
(habbo, rooms, game, catalog, buildersclub, inventory, ME, wired-tools,
camera, youtube, modtools, furnieditor, housekeeping) the icons exceed
the available 528-608px around the 1540-1700px viewport range, so the
last icons get silently clipped on the right.

Raising the desktop breakpoint from 1540px to 1700px makes the client
fall back to the mobile-scrollable layout (`.tb-bar-scroll`) below
1700px, which scrolls horizontally and doesn't clip.

Above 1700px the desktop fixed-icon layout still applies, now with
enough horizontal room for every icon even with mod+HK enabled.

Touch devices are unaffected (already forced onto the mobile layout
via `pointer: coarse`).
2026-05-26 19:27:38 +02:00
duckietm d5d5ca59a8 🆙 Small fix Floorplanner 2026-05-26 17:16:14 +02:00
duckietm bf0a73eaf8 🆕 Brand new Floorplan 2026-05-26 16:38:01 +02:00
DuckieTM 4f0a8be2b0 Merge pull request #158 from simoleo89/pr/floor-editor-modernization
feat(floorplan-editor): React rewrite + live in-room preview + UX polish
2026-05-26 13:21:29 +02:00
duckietm 11702fa5e0 🆙 Small updates for the HK 2026-05-26 12:51:33 +02:00
DuckieTM b9bcf44192 Merge pull request #157 from simoleo89/feat/housekeeping-panel
feat(housekeeping): in-client admin panel
2026-05-26 10:51:09 +02:00
duckietm c61bc3726f 🆙 Update gifts 2026-05-26 10:01:07 +02:00
DuckieTM cef27d5646 Merge branch 'Dev' into merge-duckie-main-2026-05-06 2026-05-25 18:51:48 +02:00
Lorenzune b038ca4542 Add emulator stats dashboard and refresh classic UI views 2026-05-25 10:10:40 +02:00
simoleo89 4378d34e22 fix(floorplan-editor): hand tool sits AFTER the 'Modalita disegno' label
Earlier rev had the hand first, before the label. Feedback: the
label belongs at the very start of the strip; the hand reads
better as the first of the tool buttons it groups with. Same
gesture and exclusive-group behaviour, just visually:

  Modalita disegno  [hand]  [SET][UNSET][UP][DOWN][DOOR] ...
2026-05-24 22:06:03 +02:00
simoleo89 e60d6e2df8 feat(floorplan-editor): hand tool joins the exclusive tool group, sits first in toolbar
Two related changes from the latest feedback:

1) Hand is now the FIRST button in the toolbar (left of the
   'Modalita disegno' label), matching where users typically
   look for a pan affordance in painting / mapping editors.

2) The hand and the brush buttons form one exclusive tool
   group: picking any brush (SET / UNSET / UP / DOWN / DOOR)
   - or select-all / square-select - clears pan mode. No more
   'I clicked SET but the canvas keeps panning'. Same goes
   the other way: clicking the hand stays sticky, and while
   it's active the brush highlights are visually de-selected
   even though state.brush.action still holds the last brush
   (so the user gets it back the moment they pick a brush
   again).

Implementation: replaced the toolbar's onTogglePanMode prop
with an imperative setPanMode(next: boolean) =>. Every other
tool's onClick calls exitPan() first; the hand calls
setPanMode(!panMode) directly. data-active and the border
highlight on the brush + square-select buttons now require
!panMode so the visual state mirrors the gesture state.

No reducer changes - panMode stays a canvas-level UI flag.
2026-05-24 22:04:58 +02:00