Commit Graph

38 Commits

Author SHA1 Message Date
simoleo89 be471ca39b feat(toolbar): add two edge collapse buttons for the icon clusters
Add a tab button at the left and right outer edges of the desktop toolbar.
The left one hides/shows the left action icons, the right one hides/shows the
friends/right cluster — each independent, toggled with a chevron that flips
direction. Styled as a semi-transparent gray edge tab matching the bar.
2026-06-14 21:16:25 +02:00
simoleo89 ba4c2f1027 style(toolbar): make the bar a semi-transparent gray
Change the toolbar surface from near-opaque dark (rgba(18,19,24,0.97)) to a
semi-transparent gray (rgba(62,64,72,0.55)) so the room shows through, per the
reference look.
2026-06-14 21:11:57 +02:00
simoleo89 49cd06a26c feat(toolbar): remove show/hide toggle button and its animation
Drop the chevron toggle (tb-toggle) and the collapse/expand behavior: the
toolbar is now always visible (no isToolbarOpen state, no handleToggleClick,
no lock timers). The nav blocks render statically (initial=visible) so there's
no show/hide slide-in effect, and the chat-input frame sits in the bar at all
times. Removes the now-dead tb-toggle CSS and the unused useRef/useCallback
imports.
2026-06-14 20:53:39 +02:00
simoleo89 bd71d326fb style(toolbar): solid bottom bar (classic Habbo look, less glassy) 2026-06-14 18:58:07 +02:00
simoleo89 cdabdedfbf feat(mentions): dedicated toolbar icon sprite 2026-06-02 15:04:11 +02:00
simoleo89 c67c90d4c1 feat(mentions): inbox window, toolbar badge, chat-history tab, ui-config + i18n 2026-06-02 15:04:11 +02:00
duckietm 827c17dc8b 🆙 Small fix toolbar 2026-06-01 14:44:33 +02:00
DuckieTM fa71e8eb4a 🆙 Toolbar fix in rare cases the room-tools container 2026-05-30 07:18:05 +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
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
duckietm 00fbdc6f6d 🆙 Small update toolbar 2026-05-27 15:37:09 +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 11702fa5e0 🆙 Small updates for the HK 2026-05-26 12:51:33 +02:00
duckietm 0996ed24d3 🆙 More toolbar update :) 2026-05-22 17:17:33 +02:00
duckietm b3ff46a771 🆙 Fix Toolbar & Pets layout 2026-05-22 16:00:59 +02:00
simoleo89 18effe33eb feat(toolbar): show open-ticket count badge on ModTools button
When a new CFH ticket arrives the moderator currently only finds out
by opening the ModTools launcher and looking at the Report Tool
counter. If the launcher is closed they have no signal — same
treatment friend requests already get on the People button next door.

Match the existing pattern: read `tickets` from `useModTools()`
(useBetween-shared, no extra subscription cost), filter to
state===1 (OPEN), and render a <LayoutItemCountView> over the
ToolbarItemView in absolute-positioned relative wrapper. Same
positioning as the friend-requests badge (-right-1 -top-1 z-10
pointer-events-none).

Gated on `isMod` so non-mods don't compute the filter or render
the wrapper — and since useModTools is a useBetween singleton its
event listeners only register once across the whole app regardless
of consumer count.

Applied to both toolbar layouts (desktop and mobile, lines ~272 and
~382) so the badge follows the user across breakpoints.
2026-05-20 22:10:43 +02:00
simoleo89 c7e258e3d1 feat(hooks): permission-driven gating via useHasPermission
Replace the rank-level family (useHasRankLevel + STAFF_LEVELS
constants + useIsRank) with a permission-driven family that reads
straight from the deployment's `permission_definitions` table — no
more hardcoded SecurityLevel/rank-id thresholds on the client. A new
rank in permission_ranks or a re-shuffling of permission_definitions
rank columns now propagates through the UI automatically.

Renderer-side wire shipped in companion commit
feat/react19-event-bus@159c5eb (UserPermissionsMapParser + Event,
SessionDataManager.getPermissionsSnapshot + USER_PERMISSIONS_UPDATED).

New public API in `useSessionSnapshots.ts`:
- useUserPermissions(): ReadonlyMap<string, number>  — full map
- useHasPermission(key): boolean                       — > 0 ⇒ true
- usePermissionValue(key): number                      — raw 1/2 or 0
- useIsAmbassador() now aliases useHasPermission('acc_ambassador')
- useUserRank() kept for PRESENTATIONAL use only (badge, prefix,
  prefix color) — documented as such in JSDoc; gating must use
  useHasPermission.

Dropped:
- src/api/nitro/session/RankLevels.ts (STAFF_LEVELS constants)
- useHasRankLevel / useIsRank exports (rank-based gating)

11 consumer migrations, each mapped to the right
`permission_definitions.permission_key`:

  - ToolbarView (mod-only chat-input button)        → acc_supporttool
  - ChooserWidgetView (room-object id column)       → acc_supporttool
  - CatalogClassicView (admin toggles)              → acc_catalogfurni
  - CatalogModernView (admin toggles)               → acc_catalogfurni
  - FurniEditorView (panel access)                  → acc_catalogfurni
  - CalendarView (force-open day)                   → acc_calendar_force
  - InfoStandWidgetFurniView (mod buildtools btn)   → acc_anyroomowner
  - AvatarInfoWidgetPetView (canPickUp)             → acc_anyroomowner
  - FurnitureMannequinView (controller mode)        → acc_anyroomowner
  - YouTubePlayerView (isMyRoom)                    → acc_anyroomowner
  - NavigatorRoomInfoView 'settings'                → acc_anyroomowner
  - NavigatorRoomInfoView 'staff_pick'              → acc_staff_pick

Test refresh:
- useUserRank still tested for the presentational shape.
- useHasPermission: true for non-zero, false for absent/zero.
- usePermissionValue: raw 1 / 2 / 0 (default).
- useUserPermissions: full map exposure.
- Runtime promote test: mutate the permissions map + dispatch
  USER_PERMISSIONS_UPDATED, assert useHasPermission flips false→true.
  Locks in the new reactive contract.

Mock unchanged (the test sets getPermissionsSnapshot via vi.mocked).

Verification: yarn typecheck clean, yarn lint:hooks clean, yarn test
214/214 (213 prior + 1 net new for useUserPermissions). Backward
compatible: older Arcturus deployments don't ship the map → empty
snapshot → every gate is false → mod UI hidden (safe default).
2026-05-19 19:00:10 +02:00
simoleo89 8aa02249e1 feat(hooks): rank-based API tied to permission_ranks DB table
Drop the SecurityLevel-named family (useIsModerator / useIsAdmin /
useIsCommunity / useIsPlayerSupport / useHasSecurityLevel /
useUserSecurityLevel) in favour of a rank-based family tied to the
operator's actual `permission_ranks` rows in the Arcturus DB:

- `useUserRank()` returns `{ id, name, level, badge, prefix,
  prefixColor }` derived from the snapshot. Powered by the renderer's
  extended IUserDataSnapshot (companion commit 87e67d5 on
  feat/react19-event-bus).
- `useHasRankLevel(min)` replaces useHasSecurityLevel; consumers
  pass a `permission_ranks.level` threshold from the deployment.
- `useIsRank(name)` matches `permission_ranks.rank_name` exactly.

To avoid bare integers in widget bodies, added a deployment-scoped
constants file at `src/api/nitro/session/RankLevels.ts`:

  export const STAFF_LEVELS = {
      MEMBER: 1, SUPPORT: 4, MOD: 5, SUPER_MOD: 6, ADMIN: 7
  };

A deployment that re-numbers `permission_ranks` only edits this file.

Migrated all 11 consumer reads (same set as the earlier session's
useIsModerator migration plus the audit catch): ToolbarView,
CatalogClassicView, CatalogModernView, ChooserWidgetView,
CalendarView, YouTubePlayerView, FurniEditorView,
InfoStandWidgetFurniView, AvatarInfoWidgetPetView,
FurnitureMannequinView, NavigatorRoomInfoView. The
NavigatorRoomInfoView `staff_pick` permission was previously
`securityLevel >= COMMUNITY (7)` via the renderer-enum wrapper —
ported to `useHasRankLevel(STAFF_LEVELS.ADMIN)` because in the
default seed level 7 is Administrator, which is the actual rank that
gets the `acc_anyroomowner`-style permissions for staff-picking.

Tests refreshed under `useSessionSnapshots.test.tsx`:
- useUserRank surfaces the full metadata block;
- useHasRankLevel does `>=` against the threshold;
- useIsRank exact-matches against rank_name;
- a runtime promote (snapshot mutation + SESSION_DATA_UPDATED
  dispatch) flips the result, locking in the reactive contract.

Mock extended only minimally — kept the SecurityLevel enum class for
any consumer outside the dropped family that still imports it.

Verification: yarn typecheck clean, yarn lint:hooks clean, yarn test
213/213. The Arcturus-side composer change (UserPermissionsComposer
appending the 5 extra fields) is staged but UNCOMMITTED on Arcturus
main (which has unrelated WIP); the wire is backward-compatible so
the React client works against both pre- and post-extension
emulators.
2026-05-19 18:38:31 +02:00
simoleo89 532cb28ca7 feat(hooks): useIsModerator() + migrate 6 component reads
Adds a reactive `useIsModerator()` derived from
`useUserDataSnapshot().securityLevel >= SecurityLevel.MODERATOR`
(mirrors the renderer-side getter at SessionDataManager.ts:684), and
migrates the six React component-body reads of
`GetSessionDataManager().isModerator`:

- ToolbarView (mod-only chat-input button)
- CatalogClassicView, CatalogModernView (admin toggles in catalog
  header)
- ChooserWidgetView (room-object id column visibility)
- YouTubePlayerView (room-control affordance — hook moved above the
  `if (!isOpen) return null` early return so the hook order stays
  stable when the player opens/closes)
- CalendarView (mod-only "open all" affordance)

UX impact: any future promote/demote that flips
SESSION_DATA_UPDATED now re-renders the mod-only UI live, instead of
requiring an F5. Imperative call sites
(AvatarInfoUtilities.populate*, CanManipulateFurniture,
RoomChatHandler) still read the manager directly — they run at click
time, not in a React render, so reactivity has no upside there.

Five of the six call sites are top-level component-body reads (no
early-return interaction). YouTubePlayerView has an
`if (!isOpen) return null` below the hook list, so the hook had to
move ABOVE it; same shape as the recent CatalogPurchaseWidgetView and
CatalogItemGridWidgetView fixes.

Verification: yarn typecheck clean, yarn lint:hooks clean, yarn test
209/209.
2026-05-19 18:07:17 +02:00
simoleo89 4ab38d3f9a toolbar: always-mount nav rows + drive show/hide via framer variants
Replace the outer AnimatePresence wrapper around the four toolbar rows
(desktop backplate, left-nav, right-nav, mobile-nav) with always-mounted
motion.div elements driven by an isVisible-derived variant string
('visible' or 'hidden'). This eliminates the spam-toggle bug: rapid
clicks on the show/hide chevron previously left motion children in
inconsistent intermediate states (stuck opacity 0, phantom scale 0.8)
because AnimatePresence + Fragment + multiple keyed children breaks
when enter/exit cycles overlap. With variants, framer-motion's spring
solver picks up from the current animated value on each retarget, so
spam-clicking just settles smoothly toward whichever target is current.

Refactor details:

- containerVariants drops its 'exit' state (now lives in 'hidden').
- itemVariants drops 'exit' as well — animation target is the same as
  hidden, and exit doesn't apply without AnimatePresence.
- New shellVariants for the backplate.
- pointer-events is animated per-variant ('auto' visible / 'none'
  hidden) instead of pinned via a Tailwind class, so the hidden rows
  don't intercept clicks.
- Wrapper variants are computed inside the component because
  leftNavVariants.hidden depends on isInRoom (the nav slides in from
  the side in-room, from the bottom otherwise).
- Variant inheritance: outer wrapper drives 'visible'/'hidden';
  inner container (containerVariants) and items (itemVariants) inherit
  via framer's variant propagation, so stagger runs in both directions
  without needing AnimatePresence.
- Inner AnimatePresence around the Me popover stays — it has a single
  keyed child with a clean conditional and doesn't suffer from the
  Fragment-wrapping issue.

Cleanups while here:

- Dropped hasDesktopUnifiedShell: always equal to isToolbarOpen inside
  the isInRoom-gated block, so the ternary was always picking one
  branch. Inlined.
- Dropped showDesktopShell: same redundancy inside the (now removed)
  AnimatePresence. The 'else' branch of its ternary was dead code.
- Extracted spring transition constants (SHELL_TRANSITION,
  NAV_TRANSITION, ME_POPOVER_TRANSITION) so they're declared once.
- Removed pointer-events-auto from wrapper className strings where
  the variant now owns it (mobile-nav, left-nav, right-nav).

Behaviour: identical to before for a single click cycle (open → close
animates with the same spring). The previously broken spam-click path
now settles cleanly. Tests still 193/193, typecheck 0 errors, prod
build unchanged.
2026-05-16 12:52:05 +02:00
simoleo89 b5eeb68b9b Type framer-motion variants as Variants — kill 33 tsgo errors
ToolbarView and FriendsBarView declared their motion variant objects
without a type annotation, so tsgo widened transition.type to 'string'
where framer-motion's Variants narrows it to a literal union (spring /
tween / inertia / etc). Every <motion.div variants={...} /> site flagged
the mismatch.

Annotating the constants as Variants makes the literal inference work
('spring' stays 'spring'); also drops the redundant 'as const' on
staggerDirection now that the parent type pins it.

Net tsgo error count: 133 -> 100.
2026-05-11 21:12:34 +02:00
simoleo89 535fa71020 ESLint --fix: auto-fix brace-style, indent, semi, no-trailing-spaces
Run eslint --fix across src/ to clear ~1900 mechanical lint errors
surfaced by the @typescript-eslint v8 + react-hooks v7 + react-compiler
upgrade in the React 19 modernization PR.

Issues fixed automatically:
- brace-style (Allman): try/catch one-liners reformatted to multi-line
- indent: tab-vs-space and depth corrections
- semi: missing trailing semicolons
- no-trailing-spaces

No semantic changes. Remaining 701 errors are real-code issues
(set-state-in-effect, rules-of-hooks, no-unsafe-* type checks) that
need manual per-file review.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:50 +00:00
Lorenzune 57b83c1097 Refine mobile avatar widgets and login flow 2026-05-07 21:19:15 +02:00
Lorenzune 58e0ed30f6 Merge remote-tracking branch 'duckie-temp/main' into duckie-merge-2026-04-21
# Conflicts:
#	src/components/room/widgets/chat-input/ChatInputView.tsx
#	src/components/toolbar/ToolbarView.tsx
#	src/css/chat/Chats.css
#	src/css/nitrocard/NitroCardView.css
#	src/css/purse/PurseView.css
#	src/css/room/RoomWidgets.css
2026-04-21 11:19:59 +02:00
duckietm 4afdfd8f33 🆕 YoutubeTV Broadcasting in rooms ! 2026-04-10 09:26:50 +02:00
duckietm bbd4ccf30c 🆙 Stage 1 Youtube broadcast 2026-04-09 11:54:57 +02:00
duckietm 3ae51eb5e6 🆙 Fix chatbar for mobile 2026-04-08 12:44:59 +02:00
Lorenzune 954e477e47 feat: add builders club catalog ui flow 2026-04-07 14:40:51 +02:00
Lorenzune 36c0221a54 chore: checkpoint current work 2026-04-03 05:22:26 +02:00
Lorenzune 83540ff329 feat: add advanced wired variable tools UI 2026-04-02 04:44:04 +02:00
Life c4d948cd3a feat: FurniEditor WebSocket — full UI with toolbar icon, infostand button, Edit/Search views, Tailwind styling 2026-03-28 08:52:59 +01:00
duckietm bbe71e9753 🆙 Cleanup Furni-Edit & Fix the avatar-editor 2026-03-27 13:38:03 +01:00
duckietm 19fd0e0809 Revert "Merge pull request #45 from simoleo89/interface-color-pr"
This reverts commit d911196ccb, reversing
changes made to 8dccc509c4.
2026-03-23 13:31:15 +01:00
Life 9c2dccaad6 feat: UI color theming system with live preview, presets and server sync
- RGBA color picker with live preview (debounce 50ms)
- 30 preset colors + 12 theme presets (Ocean, Forest, Sunset, Royal, etc.)
- Header image selection from configurable image library
- Export/Import theme as JSON via clipboard
- CSS variable theming across all UI elements: NitroCard headers/tabs,
  context menus, buttons (primary/dark/gray), InfoStand, toolbar,
  room tools, purse, progress bars, sliders
- All elements use var(--name, fallback) for zero visual change when default
- Smooth 0.3s CSS transitions on theme change
- Server-side persistence via WebSocket (packets 10047/10048)
- Integrated Color/Image tabs into BackgroundsView panel
- All strings use LocalizeText() for i18n support
- Settings persisted in localStorage + server sync with 1s debounce
- Added react-colorful dependency
2026-03-22 21:48:07 +01:00
simoleo89 a11987e1e0 Add FurniEditor tool with Next.js API integration
- FurniEditor component with Search/Edit tabs (NitroCard UI)
- useFurniEditor hook connecting to Next.js API routes via Vite proxy
- Edit Furni button in room infostand (godMode) with sprite ID lookup
- Toolbar: 3-column flex layout (icons | chat | friends)
- Heroicons SVG for ID/Sprite display in infostand and edit view
- Vite config: proxy /api to Next.js, aliases for renderer3 packages
2026-03-15 00:27:09 +01:00
duckietm f2446d232b 🆙 Upgrade to tailwind css 4.2.0 2026-02-20 08:17:17 +01:00
DuckieTM 7feb10ab15 🆙 Init V3 2026-01-31 09:10:52 +01:00