Commit Graph

510 Commits

Author SHA1 Message Date
simoleo89 e610cfeef4 feat(navigator): reactive favourites via fine-grained store (P3)
Move favourite room ids out of the useBetween navigator store into a
dedicated Zustand store. useNavigatorFavourite(roomId) subscribes only
to s.ids.has(roomId) (a boolean), so a FavouriteChangedEvent for one
room no longer re-renders every favourite-aware view. apply() returns
the same state reference when membership is unchanged.
2026-05-31 01:03:31 +02:00
simoleo89 641593c3ef feat(navigator): responsive layout + saved-search refinement (P4 wave 1c)
- Stack sidebar above results below sm; cap card width to viewport
- Fix tab-bar wrap overlapping content on narrow screens (max-height/height/flex reset)
- Saved-search rows: whole row opens search, hover-reveal delete (no layout shift), bolt icon, empty state
- Hover affordance on navigator grid items and saved-search rows
2026-05-31 00:55:45 +02:00
Life b17cd891b3 Merge branch 'duckietm:main' into feat/navigator-p4-visual-wave1 2026-05-30 09:38:44 +02:00
DuckieTM fa71e8eb4a 🆙 Toolbar fix in rare cases the room-tools container 2026-05-30 07:18:05 +02:00
medievalshell f7e78674c6 fix(client): catalogo mobile, BC/navigator/profilo/amici
- Catalogo Hippiehotel responsive su mobile (finestra 96vw/72vh, rail
  tappabile, sotto-pannelli ristretti); duckie ripristinato come entita
  separata (revert modifiche scrollbar sul suo CSS)
- BC e catalogo normale seguono entrambi il toggle tema; il duckie non
  duplica piu il logo nelle pagine info_duckets
- Navigator: highlight della tab segue currentTabCode (era bloccato su
  Pubblici mentre il contenuto cambiava)
- Inventario: link inventory/show/<tab> per deep-link a una scheda
- User Profile: avatar visibile e allineato a bg/stand, finestra piu
  grande, bordi puliti, Created/Last login mostrano il valore, bottoni
  Change Looks/Rooms/Change Badges/Add friends/Achievement funzionanti
- Amici: header non piu sovradimensionati e teste avatar inquadrate
  (regole flat: quelle annidate .nitro-friends{&...} non si applicavano)
2026-05-30 05:49:04 +02:00
medievalshell d79bdd33e1 fix(catalog): scrollbar-gutter both-edges, icona nav centrata con/senza scroll 2026-05-30 03:42:58 +02:00
medievalshell 52a7dc1604 fix(catalog): scrollbar-gutter stable sulla nav, proporzioni costanti con/senza scroll 2026-05-30 03:32:40 +02:00
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 c9997f6049 fix(catalog): immagini pagina supportano URL completi e estensioni non-gif 2026-05-30 03:03:28 +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 4e96355a94 perf(boot): non pre-fetchare le URL gamedata directory
preloadUrl salta le URL che finiscono con '/' (le gamedata split sono
directory): prima 404avano e sprecavano connessioni all'avvio.
2026-05-30 00:15:07 +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 74747b8aad 🆙 fix the header for catalogue 2026-05-29 16:18:01 +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 7a0b57e267 fix(navigator): ignore search events while disabled + invalidate on FlatCreated
useNavigatorSearch had two gaps its tests cover:
- with no active tab the query is disabled, but a NavigatorSearchEvent still
  updated the data; now such events are ignored until a tab is active
- a newly created room (FlatCreatedEvent) now invalidates the
  ['navigator','search'] query and refetches the current search

Fixes the 2 failing useNavigatorSearch tests; full suite 472/472.
2026-05-28 15:39:46 +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 05d71dd163 🆙 Small fix for the navigator
This mirrors what the old god-hook used to do and what the rest of the codebase still uses for everything else. The TanStack one-shot listener pattern (awaitNitroResponse registers a listener, awaits one matching response, removes itself) is fragile against renderer-bundle quirks — the parser fires but the listener never matches, so the promise never resolves and query.data stays undefined forever. That's exactly the symptom you saw: server logs show the response arriving, client UI stays blank.
2026-05-28 13:46:44 +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 ee3736474d refactor(navigator): remove search ownership from useNavigatorStore
P2 core surgery: search result + NavigatorSearchEvent listener +
sendSearch + reloadCurrentSearch all leave useNavigatorStore. The new
useNavigatorSearch query hook owns the cache. useNavigatorActions is
deleted entirely — the only two actions it exposed are gone, and no
consumer outside Navigator depended on it.

NavigatorMetadataEvent handler now seeds the UI store's currentTabCode
on first arrival, activating the query the moment top-level contexts
land.

useNavigatorData: searchResult removed from closure and return.
useNavigatorUiState: currentTabCode + currentFilter added.
index.ts: useNavigatorActions removed, useNavigatorSearch added.

NavigatorView.tsx is intentionally broken at this commit and gets
fixed in the next.
2026-05-27 19:20:27 +02:00
simoleo89 7435326dad feat(navigator): useNavigatorSearch query hook (P2 core)
useNitroQuery keyed on [currentTabCode, currentFilter] from
navigatorUiStore. Fires NavigatorSearchComposer; subscribes to
NavigatorSearchEvent with an accept-filter that rejects results whose
code does not match the current tab. Invalidates on FlatCreatedEvent
and RoomSettingsUpdatedEvent for server-driven refresh.

nitro-renderer.mock.ts: add connection.send stub to GetCommunication
so SendMessageComposer (which calls GetCommunication().connection.send)
does not throw in tests that exercise useNitroQuery.

TDD: 7 cases incl. enabled-gating, accept-filter rejection on
mismatched tab, invalidator round-trip.
2026-05-27 19:18:24 +02:00
simoleo89 8f1b664b2f feat(navigator): add currentTabCode + currentFilter to UI store (P2 prep)
setTab(code) atomically updates currentTabCode and resets currentFilter
to '' — switching tabs starts a fresh search context. setFilter(value)
updates only the filter — the user is typing in the same tab.

TDD: 3 new cases (16 total in navigatorUiStore.test).
2026-05-27 19:15:08 +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 1148c0a628 refactor(navigator): remove deprecated useNavigator god-hook
P1 complete. All 13 consumers migrated to the wired-tools-style split:
- useNavigatorData / useNavigatorUiState / useNavigatorActions (filters)
- useNavigatorStore (internal useBetween closure with sendSearch + reloadCurrentSearch)
- navigatorUiStore (Zustand for 9 UI flags)
- useDoorState (extracted to src/hooks/rooms/widgets)

Spec: docs/superpowers/specs/2026-05-26-navigator-modernization-p1-design.md
Plan: docs/superpowers/plans/2026-05-26-navigator-modernization-p1.md

Next phases (separate specs/plans): P2 (TanStack Query for search),
P3 (reactive favourites via snapshot), P4 (visual rework + virtualization
+ persistence).
2026-05-27 19:01:48 +02:00