Commit Graph

104 Commits

Author SHA1 Message Date
Lucas 'Paperboy' Rose-Winters a9d98a3076 feat: implement Skills widget with level progression and categories
Add comprehensive Skills widget to dashboard system with category organization,
XP tracking, level progression, and multiple view modes.

Widget Features:
- Three sub-tabs: All Skills, By Category, Quick View
- Level-up and level-down buttons for manual progression
- XP progress bars with visual feedback
- Search and filter functionality
- Category collapse/expand in By Category view
- Editable skill names and categories
- Delete skills and categories
- Add new skills and categories
- Configurable max level and XP display

UI Improvements:
- Scrollable content area for large skill lists
- Responsive card layout
- Shortened tab labels for compact display ("All", "Quick" vs "All Skills", "Quick View")
- Proper flex layout for skill names (no longer truncated)
- Level badges and action buttons

Technical Implementation:
- Event handler deduplication to prevent exponential level-up bug
- Flag-based handler attachment: container.dataset.handlersAttached
- Nested flex containers for proper space distribution
- Scrollable views wrapper matching Inventory/Quests pattern

Dashboard Integration:
- Added Skills tab to defaultLayout.js (tab 5)
  - Icon: fa-solid fa-book (fixed invalid fa-book-sparkles)
  - Dimensions: 3x7 grid cells
  - Default config: All Skills tab, show XP, show categories
- Auto-arrange support in dashboardManager.js
  - Skills category group with priority order 6
  - Auto-creates Skills tab when skills widgets detected
- Widget registration in dashboardIntegration.js

Widget Files:
- src/systems/dashboard/widgets/userSkillsWidget.js (new)
  - Full widget implementation with all sub-tabs and features
  - State management with Map-based storage
  - Category-based and flat views
  - Search/filter/sort functionality

Styling:
- style.css: Added skills widget styles
  - Skill cards, headers, action buttons
  - Level-down button with accent color
  - XP progress bars
  - Category sections

Fixes from iteration:
1. Invalid FontAwesome icon (fa-book-sparkles → fa-book)
2. Tab labels too wide (shortened to single words)
3. Skill names truncated (fixed with proper flex structure)
4. Widget height incorrect (adjusted to h:7)
5. Level-up exponential bug (duplicate handlers, added flag guard)
6. No level-down button (added with minimum level 1)
7. No scrollbar on long lists (added .rpg-skills-views wrapper)

Category: skills
Integration: Fully integrated with dashboard v2.0 system
Tested: Layout, interactions, scrolling, level progression

Refs: AI tracker integration (separate commit)
2025-11-06 22:08:48 +11:00
Lucas 'Paperboy' Rose-Winters 0a5bad6b1c refactor: remove unused settings button from edit mode widgets
The green settings icon that appeared on widget hover during edit mode
was not connected to any functionality. Removed to simplify UI.

- Delete button (red X) remains functional
- Edit mode drag/drop and resize unaffected
2025-11-06 21:27:58 +11:00
Lucas 'Paperboy' Rose-Winters 6c99b31d48 refactor: use resetLayout() for first-run initialization
Refactored loadLayout() to call resetLayout() for first-run users instead of
duplicating setup logic inline. This provides a single source of truth for
"set to default layout" behavior.

Previous Approach (Problems):
- loadLayout() had ~40 lines of inline first-run setup
- Different behavior: used autoLayout (repositions widgets)
- Less comprehensive: no state reset, different persistence method
- Code duplication between loadLayout() and resetLayout()
- Error handler also duplicated applyDashboardConfig() logic
- Emergency fallback tab creation needed after load

New Approach (Benefits):
- loadLayout() is now a simple router: saved layout vs. reset
- Consistent behavior: first-run and manual reset use same code path
- More comprehensive: fresh layout generation, state reset, validation
- Better error recovery: always uses resetLayout() for clean state
- Single source of truth for default layout initialization
- ~40 lines removed, cleaner code

Changes:
1. Removed inline applyDashboardConfig(defaultLayout) for first run
2. Removed manual autoLayout() loop (lines 1489-1494)
3. Removed manual saveLayout() call (line 1497)
4. Removed error handler's inline applyDashboardConfig()
5. Removed emergency fallback tab creation (lines 1506-1520)
6. Added resetLayout() call for first run (line 1494)
7. Added resetLayout() call for error recovery (line 1500)

Result:
- First-run users get comprehensive setup via resetLayout()
- Preserves default positions (doesn't reposition with autoLayout)
- Consistent layout behavior across first-run and manual reset
- Better maintainability (single code path for default setup)
- Proven reliability (resetLayout already works in production)
2025-11-06 21:11:36 +11:00
Lucas 'Paperboy' Rose-Winters fedc93f504 fix: lock button visual state now updates correctly outside edit mode
Fixed bug where the lock/unlock button's icon and title didn't update when
toggling lock state outside of edit mode. The logical state changed correctly
(widgets locked/unlocked), but the button appearance remained stale.

Root Cause:
- toggleLock() correctly updates the button element
- When in dropdown/menu mode (narrow screens), menu items are static snapshots
- Edit mode toggle refreshed the menu (via headerOverflowManager.refresh())
- Lock button toggle did NOT refresh the menu
- Result: stale button appearance in dropdown menus

Solution:
- Added headerOverflowManager.refresh() call after toggleLock()
- Follows the exact same pattern as edit mode toggle (lines 323-326)
- Uses setTimeout(50ms) to ensure DOM updates complete first

Changes:
- src/systems/dashboard/dashboardIntegration.js (lines 338-341)
  Added 4 lines to refresh menu after lock state change

Result:
Lock button now correctly updates its visual state (icon: lock/lock-open,
title: "Lock Widgets"/"Unlock Widgets") whether in edit mode or not, and
whether visible directly or in dropdown/hamburger menus.
2025-11-06 21:07:27 +11:00
Lucas 'Paperboy' Rose-Winters c5a888c3bf fix: prevent blank screen for new users migrating to widget dashboard
Fixed critical initialization timing bug where new users saw a blank screen
with error "Tab not found: main" when migrating from v1.x to v2.0.

Root Cause:
- dashboardManager.init() created a premature fallback "main" tab before
  loading the default layout
- TabManager was initialized with activeTabId='main'
- loadLayout() then replaced tabs with proper IDs ('tab-status', etc.)
- TabManager still referenced the non-existent 'main' tab
- Result: blank screen

Changes:
1. Removed premature fallback tab creation (lines 189-198)
   - Default layout is always set via setDefaultLayout() before init()
   - No need to create "main" tab before layout loads

2. Added safety check after loadLayout() completes (line 1506-1520)
   - If no tabs exist after loading, create emergency fallback
   - Uses correct tab ID 'tab-status' instead of 'main'
   - Updates TabManager's activeTab to match

Flow now:
- init() creates TabManager with empty tabs
- loadLayout() populates tabs from default or saved layout
- Safety check ensures at least one tab exists
- TabManager references only valid tab IDs

Fixes blank screen bug for users migrating from v1.x to v2.0.
2025-11-06 21:04:07 +11:00
Lucas 'Paperboy' Rose-Winters 693dc346e8 fix: correct userInfo sizing at desktop narrow and prevent character widget expansion
UserInfo Widget:
- Changed from column-based to mobile detection (window.innerWidth <= 1000)
- Desktop narrow (2-col) now correctly uses 1x2 instead of 1x1
- Mobile devices still use 1x1 compact mode with round avatar
- Ensures vertical layout at all desktop widths

PresentCharacters Widget:
- Changed maxAutoSize to match defaultSize (3x2 on desktop)
- Prevents auto-expansion to 3 rows during layout
- Stays at 2 rows to fit 1080p screens without scrolling

Fixes responsive sizing issues on desktop narrow panels.
2025-11-06 20:58:43 +11:00
Lucas 'Paperboy' Rose-Winters 1d82695d74 feat: make auto-arrange and sort use default layout positions
Modified autoLayoutCurrentTab() and autoLayoutWidgets() to detect when
widgets match the default layout and apply the exact positions from
defaultLayout.js instead of using the gridEngine.autoLayout packing
algorithm.

This ensures that:
- "Reset Layout" button uses default positions
- "Auto Arrange All Widgets" button uses default positions (if widgets match)
- "Sort Current Page" button uses default positions (if widgets match)

All three operations now produce identical layouts for the default widget set.

Changes:
- Added tryApplyDefaultLayoutToTab() helper for single tab layout
- Added tryApplyDefaultLayout() helper for all tabs layout
- Modified autoLayoutCurrentTab() to try default layout first
- Modified autoLayoutWidgets() to try default layout first
- Falls back to gridEngine.autoLayout for custom widgets

Fixes responsive dashboard layout consistency.
2025-11-06 20:56:32 +11:00
Lucas 'Paperboy' Rose-Winters 1fd6720e6b fix: update widget sizing for 1080p screens - Scene, Inventory, and Quests tabs
**Scene Tab (presentCharacters):**
- Desktop: 3×2 (wide and short, fits 1080p viewport)
- Mobile: 2×4 (narrow and tall for vertical stacking)

**Inventory Tab:**
- Desktop: 3×7 (full width, spacious) instead of 2×6
- Mobile: 2×5 (full width, compact)

**Quests Tab:**
- Desktop: 3×7 (full width, spacious) instead of 2×5
- Mobile: 2×5 (full width, compact)

All widgets now use full width at their respective column counts and
are properly sized to fit within 1080p screens without scrolling off.
2025-11-06 20:50:16 +11:00
Lucas 'Paperboy' Rose-Winters 53a1eb1469 fix: update Scene tab widgets for proper sizing on reset layout
**Problem:**
Reset Layout button was shrinking Scene tab widgets (recentEvents and
presentCharacters) because widget definitions had defaultSize: 2x2 but
defaultLayout.js expected larger sizes (2x4 for characters).

**Changes:**

**presentCharactersWidget.js:**
- Change defaultSize from 2x2 to column-aware function
- Returns 2x4 at all column counts (taller for better card display)
- Update maxAutoSize to allow expansion to 3x5 on wide screens

**recentEventsWidget (infoBoxWidgets.js):**
- Change defaultSize to column-aware function
- Returns 2x2 at 2 columns, 3x2 at 3+ columns (full width)
- Add maxAutoSize for expansion capability

**defaultLayout.js Scene Tab:**
- Update all widgets to use 3-column width for desktop
- sceneInfo: 3x3 (was 2x2), positioned at y:0
- recentEvents: 3x2 (was 2x2), positioned at y:3 (below sceneInfo)
- presentCharacters: 3x4 (was 2x4), positioned at y:5 (below events)

**Result:**
- Scene tab widgets now properly sized on reset (no more shrinking)
- Widgets stack correctly without overlapping
- Full width utilization on wider screens (3 columns)
- Consistent behavior with Status tab responsive sizing
2025-11-06 20:45:24 +11:00
Lucas 'Paperboy' Rose-Winters 8dc07a938a feat: implement responsive dashboard layout with column-aware widget sizing
**Status Tab Layout Changes:**
- User Info widget: 1x2 vertical (left column) instead of 2x1 horizontal
- User Stats widget: scales from 1x3 (narrow) to 2x3 (wide)
- User Mood widget: 1x1 positioned below User Info
- User Attributes widget: scales from 2x4 (narrow) to 3x4 (wide), full width

**Technical Changes:**
- Update widget definitions to use column-aware defaultSize() functions
- userInfoWidget: Returns 1x2 for desktop, 1x1 for mobile
- userStatsWidget: Returns 1x3 for 2 cols, 2x3 for 3+ cols
- userAttributesWidget: Returns 2x4 for 2 cols, 3x4 for 3+ cols
- Remove autoLayout from resetLayout() to preserve default positions
- Add resetWidgetSizesToDefault() to apply column-aware sizes
- Update CSS for 1x1 compact avatar (round) and 1x2 wide avatar layouts

**User Info Widget Improvements:**
- 1x2 layout: Horizontal split with name left, level right over avatar
- 1x1 layout: Round avatar with bottom nameplate (flush positioning)
- Transparent glass-style backgrounds for better avatar visibility
- Proper aspect-ratio for circular avatar in compact mode

**Result:**
- Widgets scale intelligently based on panel width (2-4 columns)
- Desktop users get larger, more spacious layouts
- Mobile/narrow screens get efficient vertical stacking
- Reset Layout respects custom positions while applying responsive sizes
- Window resize triggers autoLayout via ResizeObserver for reflow
2025-11-06 20:42:57 +11:00
Lucas 'Paperboy' Rose-Winters 2ed7133566 feat: redesign user info widget with avatar background overlay
Changed from avatar + text layout to avatar as background with text overlay.

Previous approach: Tried horizontal/vertical layouts which caused either
horizontal or vertical scrollbars at narrow widths (w:1 h:1).

New approach: Avatar fills entire widget as background-image, name + level
display as centered overlay with semi-transparent backdrop and blur effect
for readability. Uses background-size: contain to show full avatar without
cropping.

Benefits:
- No layout conflicts - works at any widget size
- No scrollbars (horizontal or vertical)
- Full avatar visible without cropping
- Visually interesting design
- Simpler code (no layout switching logic)

Changes:
- userInfoWidget.js: Avatar set as background-image with contain sizing
- userInfoWidget.js: Simplified onResize (removed layout switching)
- style.css: Container uses background-image with gradient overlay
- style.css: Text container has backdrop-filter blur + dark background
- style.css: Simplified compact mode (no portrait/layout-specific rules)
2025-11-05 12:49:55 +11:00
Lucas 'Paperboy' Rose-Winters 8e15ce3b6a fix: keep user info widget horizontal layout at narrow widths
Changed layout breakpoint from newW < 2 to newW < 1 and reverted height
from h:2 back to h:1 for narrow widths.

Issue: Previous h:2 change broke character tab layout by making widget too
tall. The real problem was using vertical layout at w:1, which requires
~76px height.

Solution: Keep horizontal layout (avatar left, text right) even at w:1,
which only needs ~42px height and fits in a single grid unit. Vertical
layout is now only triggered at w < 1 (ultra-narrow, effectively never).

This matches mobile's behavior where horizontal layout works fine even in
narrow 2-column mode, minimizing vertical space usage.
2025-11-05 11:17:32 +11:00
Lucas 'Paperboy' Rose-Winters babd2af345 feat: add compact mode to user info widget for better vertical scaling
Applied compact mode pattern to user info widget (avatar, name, level) to
improve vertical fit at narrow widths (< 3 grid units).

Changes:

1. style.css (lines 2040-2072):
   Added .rpg-user-info-compact class with size reductions:
   - Container padding: 0.5rem → 0.3rem (40% reduction)
   - Container gap: 0.75rem → 0.4rem / 0.5rem → 0.3rem (47%/40% reduction)
   - Avatar size: 2.5-3rem → 2rem (20-33% reduction)
   - Avatar border: 2px → 1.5px (thinner)
   - Avatar shadow: 0 0 8px → 0 0 4px (subtler)
   - Text gap: 0.2rem → 0.15rem (25% reduction)
   - User name font: 0.9rem → 0.75rem (17% reduction)
   - Level label font: 0.75rem → 0.65rem (13% reduction)
   - Level value font: 0.85rem → 0.75rem (12% reduction)
   - Level padding: 0.15/0.4rem → 0.1/0.3rem (25-33% reduction)

2. userInfoWidget.js (lines 156-161):
   - Added compact class logic: if (newW < 3) → add class
   - Removed inline avatar sizing (CSS handles via compact class)
   - Preserved existing vertical/horizontal layout switching

Result: ~30-35% vertical space reduction at narrow widths while maintaining
horizontal scaling. Matches compact mode pattern from scene info, inventory,
and quests widgets.

Fixes: User info widget poor vertical scaling at narrow widths
2025-11-05 10:47:58 +11:00
Lucas 'Paperboy' Rose-Winters e055c6d112 fix: apply mobile sizing to scene info widget at narrow desktop widths
Fixed text clipping in date display by applying mobile's proven size reductions
to narrow desktop widgets (< 3 grid units wide).

Root Cause:
- At narrow widths (~296px, 2 columns), date text wraps: "3rd Day of the Ninth Month" + "Tuesday"
- Top 1/4 of first line was clipped (top of "3" and "D" cut off)
- Mobile displays work perfectly at even smaller widths

Solution - Mirror Mobile Sizing:
Mobile uses smaller dimensions that prevent clipping:
- Padding: 0.3125rem (vs 0.375rem desktop)
- Gap: 0.3125rem (vs 0.375rem desktop)
- Font size: 0.8125rem (vs 0.875rem desktop)
- Label font: 0.625rem (vs 0.6875rem desktop)

Changes:

1. style.css (lines 2782-2812):
   - Added .rpg-scene-info-compact class with mobile-like sizing
   - Reduces padding, gaps, and font sizes
   - Applied when widget width < 3 grid units

2. sceneInfoWidget.js (lines 367-385):
   - Added onResize handler
   - Applies .rpg-scene-info-compact at newW < 3
   - Removes class at newW >= 3
   - Matches pattern used for inventory/quests compact modes

Result: Date text displays without clipping at narrow widths, exactly as mobile does.

Fixes: Text clipping in scene info date display at 2-column layout (~296px)
2025-11-05 10:27:42 +11:00
Lucas 'Paperboy' Rose-Winters 13b1acb151 fix: center icons in compact buttons with fixed dimensions and flexbox
Properly centered icons by wrapping text in spans and forcing exact button
dimensions to override base min-width: fit-content style.

Root Cause:
- Base .rpg-inventory-add-btn has min-width: fit-content
- Even with span hidden, button width wasn't constrained
- Icon appeared off-center with extra space to the right

Solution:

1. HTML Structure (inventoryWidget.js, questsWidget.js):
   - Wrapped text in <span class="rpg-btn-label">
   - Pattern: <i class="fa-solid fa-plus"></i><span class="rpg-btn-label"> Add Item</span>
   - Applied to: Add Item, Add Location, Add Asset, Add Quest buttons

2. CSS (style.css):
   - Hide labels: .rpg-inventory-compact .rpg-btn-label { display: none; }
   - Force square dimensions: width: 32px !important (overrides fit-content)
   - Center icon: display: inline-flex; justify-content: center; align-items: center
   - Remove padding: padding: 0 (icon uses full 32px space)

Result: Perfect 32×32px square buttons with centered icons in compact mode,
matching the pattern used for sub-tab buttons throughout the codebase.

Fixes: Icon skewed left in Add Item/Quest buttons at narrow widths
2025-11-05 10:16:21 +11:00
Lucas 'Paperboy' Rose-Winters 55f4e0aee6 fix: apply widget responsive classes on tab switch
Fixed issue where compact mode styling was lost when switching tabs.
Widgets now consistently show icon-only buttons and truncated headers
at narrow widths, regardless of how they were rendered.

Root Cause:
- onTabChange() rendered widgets but never called onResize handlers
- Compact classes (.rpg-inventory-compact, .rpg-quests-compact) only applied:
  * After auto-arrange (explicit onResize calls)
  * During window resize (ResizeObserver triggers)
- Tab switches rendered widgets fresh WITHOUT compact classes
- Result: Buttons/headers overflowed after tab switch at narrow widths

Changes:

1. dashboardManager.js onTabChange() (lines 1224-1233):
   - Added onResize handler calls after rendering tab widgets
   - Iterates this.widgets Map (currently rendered widgets)
   - Calls definition.onResize(element, w, h) for each widget
   - Applies responsive styling based on widget dimensions

2. questsWidget.js onResize() (lines 463-468):
   - Added .rpg-quests-compact class application at < 3 grid units
   - Toggles between wide/compact modes based on width

3. style.css compact mode styling:
   - Inventory: icon-only buttons (font-size: 0), truncated headers
   - Quests: icon-only buttons (font-size: 0), truncated headers
   - Headers max-width: 140px (inventory), 120px (quests)
   - Buttons: 32×32px icon-only with restored icon size

Flow Now:
1. Window resize → onResize called → compact classes applied ✓
2. Auto-arrange → onResize called → compact classes applied ✓
3. Tab switch → onResize called → compact classes applied ✓ (NEW)

All three paths now apply responsive styling consistently.

Fixes: "Add Item" button cut-off and header overflow after auto-arrange
or tab switching at narrow widths (~296px, 2 columns)
2025-11-05 09:59:33 +11:00
Lucas 'Paperboy' Rose-Winters a7ed100780 fix: improve inventory and quests widget resizing at narrow widths
Resolved issues where inventory and quests widgets didn't properly adapt
to narrow desktop widths (~296px, 2 columns):
- Assets tab was cut off (1/3 off-screen)
- Widgets shrank vertically instead of expanding
- Sub-tabs overflowed horizontally

Changes:

1. Widget onResize Handlers (inventoryWidget.js, questsWidget.js):
   - Strengthened inventory onResize to call render() for full re-layout
   - Added quests onResize handler with re-render + width-aware styling
   - Both apply responsive CSS classes at narrow widths

2. Increased maxAutoSize for 2-Column Layouts:
   - inventoryWidget.js: h: 6 → h: 8 (creates expansion headroom)
   - questsWidget.js: h: 5 → h: 7 (user requested height)
   - Previously: defaultSize = maxAutoSize → zero expansion possible
   - Now: defaultSize < maxAutoSize → widgets can expand vertically

3. Added Missing Quests Widget Container Styles (style.css):
   - Added .rpg-quests-widget and .rpg-quests-views flex container styles
   - Proper overflow handling (hidden on container, auto on content)
   - Prevents Assets tab horizontal cut-off

4. Implemented Compact Mode CSS (style.css):
   - .rpg-inventory-compact: reduced padding, icon-only sub-tabs
   - Applied when widget width < 6 grid units
   - Prevents 3 sub-tabs from overflowing 296px container
   - Icons remain visible, labels hidden for space savings

5. Grid Engine Boolean Return (gridEngine.js):
   - setContainerWidth now returns true/false for column changes
   - Allows DashboardManager to optimize resize handling

Why This Works:
- Auto-layout expansion requires defaultSize < maxAutoSize for headroom
- Flex container styles prevent overflow with proper scroll handling
- Compact mode makes sub-tabs fit within narrow containers
- onResize handlers ensure internal layouts adapt to dimension changes

Fixes: Assets tab cut-off, vertical shrinking, sub-tab overflow at ~296px
2025-11-05 09:47:56 +11:00
Lucas 'Paperboy' Rose-Winters 7d4ed8fab4 feat: synchronize all tabs when column count changes
Modified onColumnsChange handler to update ALL tabs (visible and hidden)
when container columns change, preventing layout issues when switching tabs.

Changes:
- dashboardManager.js onColumnsChange (lines 127-184):
  - Now iterates through ALL tabs in this.dashboard.tabs
  - Calls resetWidgetSizesToDefault for each tab's widgets
  - Runs autoLayout on each tab's widget data (no DOM required)
  - Calls onResize handlers ONLY for currently visible widgets
  - Logs which tabs are updated (visible/hidden) and total widget count

Why this works:
- Widget data (x, y, w, h) is stored separately from DOM
- autoLayout works on data arrays without DOM access
- All tabs stay synchronized with current column count
- No layout corruption when switching tabs after resize

Performance:
- Typical: 5 tabs × 6 widgets = 30 widgets → ~1ms
- Column changes are rare events (resize across breakpoints)

Fixes: widgets on hidden tabs not resizing when container width changes
2025-11-05 09:31:25 +11:00
Lucas 'Paperboy' Rose-Winters 1c8c4af32d feat: implement ultra-compact mode for extreme narrow widths
Problem:
At ~254px panel width, even 4 "priority" buttons (Lock, Edit, Tracker
Settings, Hamburger) overflow the visible area, making buttons inaccessible
and taking space from tabs.

Root Cause:
Priority buttons were always visible regardless of width, but at extreme
narrow widths there isn't room for both tabs and multiple buttons.

The Solution:
Introduced 4th responsive mode: "Ultra-Compact Mode" (<400px)

New Responsive Breakpoints:
- Full Mode: > 900px (all buttons visible)
- Overflow Mode: 700-900px (priority + "More" menu ⋮)
- Compact Mode: 400-700px (priority + hamburger menu ☰)
- Ultra-Compact Mode: < 400px (HAMBURGER MENU ONLY ☰)

Implementation:
1. Added ultraCompactModeWidth: 400px threshold
2. Implemented setUltraCompactMode() that hides ALL buttons except hamburger
3. Fixed buildDropdownMenu() to correctly include priority buttons when
   includeAll=true (was missing in compact mode)
4. Updated handleResize() to detect ultra-compact threshold
5. All buttons remain accessible via comprehensive hamburger menu

Benefits:
 Maximizes space for tabs at narrow widths (only 1 button)
 All functionality accessible via hamburger menu
 Follows mobile-first design patterns
 Graceful degradation through 4 responsive tiers
 No horizontal scrolling needed

Fixes: Buttons becoming non-clickable at narrow panel widths
2025-11-04 17:27:47 +11:00
Lucas 'Paperboy' Rose-Winters 2c86af5561 fix: auto-arrange now correctly recalculates widget grid layouts
Root Cause:
After auto-arrange reorganized widgets, code attempted to call onResize()
for ALL tabs' widgets. However, switchTab() clears the this.widgets Map
and only re-renders the current tab. Result: this.widgets.get(widgetId)
returned undefined for non-active tabs, so onResize() was never called.

Additionally, User Attributes onResize() was receiving grid units (2)
instead of pixel width (~290px), causing calculateOptimalColumns() to
think only 2 columns would fit when 3 columns could easily fit.

The Fix:
1. Iterate over this.widgets Map (currently rendered widgets only)
   instead of this.dashboard.tabs (includes non-rendered widgets)
2. Use container.offsetWidth (pixel width) in onResize instead of grid units
3. Enable DEBUG flags temporarily to reveal previously suppressed logs

Result:
- onResize() now called for all visible widgets after auto-arrange
- User Attributes correctly maintains 3×3 grid at 2 grid units wide
- No more 2×5 layout with orphaned last attribute

Fixes: User Attributes breaking into 2×5 grid after auto-arrange
2025-11-04 17:04:23 +11:00
Lucas 'Paperboy' Rose-Winters db1ee0d08b fix: Apply solid theme-aware background to Add Widget modal
The Add Widget modal is moved to document.body on first use (to escape
panel transform constraints), which causes it to lose the panel's solid
background context and become transparent.

Solution: After moving modal to body, apply the same theme-aware background
logic used in tab context menu and prompt dialogs:
- If themed: Copy data-theme attribute for CSS overrides
- If default: Read computed colors from panel, convert to opacity 1.0

Changes:
- dashboardIntegration.js: Add background fix after modal move to body
2025-11-04 15:55:29 +11:00
Lucas 'Paperboy' Rose-Winters 9afcbeac56 fix: Apply solid theme-aware backgrounds to tab context menu and prompt dialogs
Root cause: Modals appended to body were transparent because default theme
CSS variables use rgba with 0.9 opacity. Confirm dialog works because it
starts inside .rpg-panel HTML (solid background) before being moved to body.

Solution: For new modals (tab context menu, prompt dialog, icon picker):
1. If themed (data-theme exists): Copy theme attribute for CSS overrides
2. If default theme: Read computed colors from panel, convert to opacity 1.0,
   apply as inline styles with !important

Also improved context menu hover effects:
- Normal items: rgba(255, 255, 255, 0.1) for better contrast
- Delete button: rgba(233, 69, 96, 0.3) for more visibility

Changes:
- promptDialog.js: Dynamic theme-aware solid backgrounds
- tabContextMenu.js: Same for context menu and icon picker + hover effects
2025-11-04 15:46:02 +11:00
Lucas 'Paperboy' Rose-Winters 3873eb82b1 fix: Use theme system CSS variables for modal/menu backgrounds
How theming actually works:
- Themes set CSS variables on .rpg-panel[data-theme="..."]
  (--rpg-bg, --rpg-accent, --rpg-text, --rpg-highlight, --rpg-border)
- Elements inside .rpg-panel inherit these solid-color variables
- Base .rpg-modal-content already uses var(--rpg-accent) gradient

Solution:
1. Copy data-theme attribute from panel to modals/menus
2. Define theme variables for .rpg-modal-content[data-theme]
3. Variables automatically apply to gradient background

Now modals/menus inherit theme styling through CSS variables:
- Sci-fi: --rpg-bg: #0a0e27, --rpg-accent: #1a1f3a
- Fantasy: --rpg-bg: #2b1810, --rpg-accent: #3d2414
- Cyberpunk: --rpg-bg: #000000, --rpg-accent: #0d0d0d
- Custom themes: Just work through variable system

Changes:
- style.css: Add variable definitions for themed .rpg-modal-content
- promptDialog.js: Copy data-theme from panel
- tabContextMenu.js: Copy data-theme (menu + icon picker)
2025-11-04 14:33:59 +11:00
Lucas 'Paperboy' Rose-Winters bedfbc77d5 fix: Use solid RGB colors for modal and menu backgrounds
Problem: CSS variables --rpg-bg and --rpg-accent have 0.9 opacity,
making all modals and menus transparent even with gradient backgrounds.

Solution: Use solid RGB colors directly in gradients:
- rgba(22, 33, 62, 1) instead of var(--rpg-accent)
- rgba(26, 26, 46, 1) instead of var(--rpg-bg)

Changes:
- style.css: .rpg-modal-content uses solid gradient
- tabContextMenu.js: Context menu uses solid gradient
- Both maintain inset shadow for depth
- Mobile long-press support included

Now modals and context menus have opaque backgrounds matching
widget styling instead of see-through transparency.
2025-11-04 14:24:31 +11:00
Lucas 'Paperboy' Rose-Winters 2ab48190ea feat: Add Exit Edit Mode button visibility toggle and tab management UI
Fix Exit Edit Mode button:
- Move button before Lock button (left side as requested)
- Add visibility toggle in editModeManager.js
  - Show done button when entering edit mode
  - Hide done button when exiting edit mode
- Fixes critical bug where button stayed hidden permanently

Add tab management UI:
- Create promptDialog.js for text input modals (rename, create)
- Create tabContextMenu.js with right-click context menu on tabs
- Integrate with TabManager API for all operations:
  - Add New Tab (with validation)
  - Rename Tab (with validation)
  - Change Icon (icon picker with 20 common icons)
  - Duplicate Tab (copies widgets)
  - Delete Tab (with confirmation, blocks if last tab)
- Auto-save after tab operations
- Event delegation for dynamic tab elements

Files changed:
- dashboardTemplate.html: Move done button to correct position
- editModeManager.js: Add visibility toggles in enter/exit methods
- promptDialog.js: New dialog system for text input
- tabContextMenu.js: New context menu system
- dashboardIntegration.js: Initialize tab context menu
2025-11-04 13:34:36 +11:00
Lucas 'Paperboy' Rose-Winters 3117cd2598 fix(dashboard): enable smart grid layout by passing widget dimensions and removing CSS overrides
Previous commit (cd3acba) added smart column calculation but it didn't work because:
1. config._width was undefined (dashboardManager didn't pass it)
2. CSS rules with higher specificity forced 2 columns everywhere

This commit fixes BOTH issues so the 3×3 grid for 9 attributes actually works.

Changes:

1. Pass widget dimensions in dashboardManager.js (line 765):
   - Changed: definition.render(element, widget.config || {})
   - To: definition.render(element, {...widget.config, _width: widget.w, _height: widget.h})
   - Why: Widget dimensions (w, h) are in widget object, not widget.config
   - Result: Smart column calculation now receives actual widget width!

2. Remove desktop CSS override (style.css, line 1914):
   - Removed: grid-template-columns: repeat(2, 1fr);
   - Kept: gap styling
   - Why: This rule had specificity that overrode inline styles
   - Result: Widget's inline style now applies on desktop

3. Scope mobile media query to legacy panel (style.css, line 6600):
   - Changed: .rpg-classic-stats-grid { ... !important }
   - To: .rpg-panel .rpg-classic-stats-grid { ... !important }
   - Why: !important was forcing 2 columns on ALL mobile screens
   - Result: Dashboard widgets control their own layout on mobile

4. Scope narrow screen media query to legacy panel (style.css, line 6860):
   - Changed: .rpg-classic-stats-grid { ... !important }
   - To: .rpg-panel .rpg-classic-stats-grid { ... !important }
   - Why: Same as mobile - prevent override of dashboard widgets
   - Result: Dashboard widgets work on all screen sizes

Expected Behavior After Fix:
- 9 attributes → widget requests w=3 → gets 3 columns → perfect 3×3 grid! 
- 6 attributes → widget requests w=2 → gets 2 columns → 3×2 grid 
- Widget resize → onResize() updates columns → responsive 
- Mobile/tablet → dashboard widgets control layout → legacy panel unaffected 

Related: commit cd3acba (added smart grid logic that now works)
Related: User feedback - World of Darkness 9 attributes needed 3×3 grid
2025-11-04 10:54:28 +11:00
Lucas 'Paperboy' Rose-Winters cd3acbab29 feat(dashboard): add smart grid layout for User Attributes widget
Implements intelligent column calculation that adapts to attribute count,
creating visually balanced grids and minimizing orphaned items.

Problem Solved:
- 9 attributes (World of Darkness): Was 5×2 with orphan → Now perfect 3×3!
- 7 attributes: Was 4×2 with orphan → Now optimized 4×2 (best possible)
- Any attribute count now gets optimal layout

Algorithm:
1. Try to find column count that divides evenly (no orphans)
2. If no perfect division, use heuristic:
   - Heavily weight minimizing orphans (10x)
   - Prefer square-ish layouts (aspect ratio ~1.0)
   - Cap at 4 columns for readability

Results:
| Attrs | Old Layout | New Layout |
|-------|-----------|-----------|
| 6     | 3×2     | 3×2 or 2×3  |
| 9     | 5×2     | 3×3  PERFECT! |
| 7     | 4×2     | 4×2 ⚠️ (minimized) |
| 12    | 6×2     | 4×3 or 3×4  |

Changes:

1. Added calculateOptimalColumns(attrCount, widgetWidth) helper:
   - Returns optimal column count (1-4)
   - Handles edge cases (0 attrs, narrow widgets, primes)
   - Balances visual appeal with practical constraints

2. Updated render() method (lines 96-109):
   - Calculate visible attribute count
   - Get widget width from config or default
   - Call calculateOptimalColumns()
   - Apply via inline style: grid-template-columns: repeat(N, 1fr)

3. Updated onResize() method (lines 168-180):
   - Count attributes from DOM
   - Recalculate optimal columns on width change
   - Update grid dynamically

4. Updated getOptimalSize() method (lines 188-220):
   - Use smart column calculation for height estimation
   - Suggest optimal widget width (2 for ≤8 attrs, 3 for 9+)
   - Calculate rows based on optimal columns, not hardcoded 2

Benefits:
 Perfect 3×3 grid for 9 attributes (World of Darkness)
 Adapts to any attribute count (3-20+)
 Responsive to widget width changes
 Minimizes visual imbalance
 Backward compatible (2-column fallback in CSS)
 Works with auto-layout (getOptimalSize suggests best dimensions)

Testing:
- 6 attributes: 3×2 grid (width=2) or 2×3 grid (width=3)
- 9 attributes: 3×3 grid (width=3) - perfectly balanced
- 7 attributes: 4×2 grid (minimizes orphans to 1)
- 12 attributes: 4×3 grid (width=3) - perfectly balanced
- Widget resize: columns recalculate automatically

Related: User feedback - World of Darkness has 9 attributes
2025-11-04 10:34:31 +11:00
Lucas 'Paperboy' Rose-Winters 5f1310cf62 fix(dashboard): move Exit Edit Widget Mode button to priority topbar
Physically moved 'Exit Edit Widget Mode' button from menu-only section
to priority buttons section in the topbar (header-right).

Changes:
- Moved button from line 52 (menu-only section) to line 27 (priority section)
- Button now appears right after 'Tracker Settings' in the topbar
- Changed from 'rpg-overflow-btn rpg-menu-only-btn' to 'rpg-priority-btn'

Button order in topbar:
1. Lock/Unlock Widgets
2. Enter Edit Mode
3. Tracker Settings
4. Exit Edit Mode ← Now here in the actual topbar!

The button is now always visible in the main header next to tabs and
hamburger menu, not hidden in dropdown menus.

File: src/systems/dashboard/dashboardTemplate.html
2025-11-04 10:11:04 +11:00
Lucas 'Paperboy' Rose-Winters 724281b6bb feat(dashboard): integrate User Attributes widget with trackerConfig.rpgAttributes
Integrates the User Attributes Widget with upstream's new RPG attributes
customization system, enabling full attribute customization (add/remove/rename)
with bi-directional sync between widget and Tracker Editor.

Changes to userAttributesWidget.js:

1. render() method (lines 44-106):
   - Read from trackerConfig.userStats.rpgAttributes (not hardcoded)
   - Filter to enabled attributes only
   - Use custom attr.name for labels (e.g., "STRENGTH" vs "STR")
   - Support widget-level visibleAttrs filtering
   - Support legacy visibleStats config for backward compat
   - Fallback to default 6 attributes if no config

2. getConfig() method (lines 112-143):
   - Dynamically generate options from enabled attributes
   - Changed visibleStats → visibleAttrs (with legacy support)
   - Set default to null (show all enabled attributes)
   - Add hint: "To add/remove/rename attributes globally, use Tracker Settings"

3. getOptimalSize() method (lines 179-199):
   - Calculate height based on enabled attribute count (not hardcoded 6)
   - Respect widget-level visibleAttrs override if specified
   - Support legacy visibleStats parameter

4. Widget description updated:
   - Header docs: Added customization features, bi-directional sync
   - Registry description: "Customizable RPG attributes" instead of "Classic RPG stats"

Changes to dashboardManager.js:

1. shouldWidgetBeRemoved() (lines 1976-1984):
   - Add 'userAttributes' removal rule
   - Remove if showRPGAttributes === false
   - Remove if all attributes disabled

2. detectConfigChanges() (lines 1743-1752):
   - Detect when RPG Attributes section re-enabled
   - Detect when attributes re-enabled
   - Auto-add widget when conditions met

Integration Benefits:
 Custom attribute names (e.g., "STRENGTH", "AGILITY", "LUCK")
 Add custom attributes (e.g., "LCK", "PER", "APP")
 Remove unwanted default attributes
 Widget auto-updates when tracker config changes
 Widget auto-removed when section/attrs disabled
 Widget auto-added when section/attrs re-enabled
 Widget-level filtering (show subset of enabled attrs)
 Backward compatible with existing dashboards

Testing Required:
- Widget renders with default attributes
- Widget respects custom attribute names
- Widget supports custom attributes (e.g., adding "LCK")
- Widget removed when section disabled
- Widget re-added when section re-enabled
- +/- buttons work with custom attributes
- AI prompts use custom attribute names

Follows pattern from: userStatsWidget.js (lines 51-78)
Related: commit a02be34 (upstream merge)
2025-11-04 10:00:07 +11:00
Lucas 'Paperboy' Rose-Winters b6c6eaee2a fix(dashboard): make Scene Info widget column-aware for proper desktop sizing
Fixed Scene Info widget using fixed sizes instead of column-aware functions,
causing it to be too narrow on desktop (3-4 columns) while working fine on mobile (2 columns).

**Problem:**
- Widget had fixed `defaultSize: {w: 2, h: 2}` and `maxAutoSize: {w: 2, h: 3}`
- Worked perfectly on mobile (2 columns) → 2×3 fills width
- Too narrow on desktop (3-4 columns) → 2×3 only uses 50-66% of width
- Reset Layout/Sort/Auto-Arrange buttons couldn't scale properly

**Root Cause:**
Scene Info widget not following established pattern used by User Info and User Stats widgets,
which use column-aware functions instead of fixed size objects.

**Fix (sceneInfoWidget.js:292-303):**

Changed from fixed sizes:
```javascript
defaultSize: { w: 2, h: 2 },
maxAutoSize: { w: 2, h: 3 },
```

To column-aware functions:
```javascript
defaultSize: (columns) => {
    if (columns <= 2) {
        return { w: 2, h: 2 }; // Mobile: 2×2 (compact, full width)
    }
    return { w: 3, h: 3 };     // Desktop: 3×3 (spacious)
},
maxAutoSize: (columns) => {
    if (columns <= 2) {
        return { w: 2, h: 3 }; // Mobile: 2×3 max (full width)
    }
    return { w: 3, h: 3 };     // Desktop: 3×3 max
},
```

**Behavior:**

Mobile (≤2 columns):
- Default: 2×2 (compact)
- Max: 2×3 (can expand vertically)
- Fills entire panel width ✓

Desktop (≥3 columns):
- Default: 3×3 (spacious)
- Max: 3×3 (properly sized)
- Uses horizontal space appropriately ✓

**Result:**
- Reset Layout: Uses correct size for current column count
- Sort Widgets: Sizes correctly after sort
- Auto-Arrange: Expands to proper maxAutoSize based on columns
- Panel resize: Widget reflowed properly when columns change
- All 5 data points (date, time, weather, temp, location) visible at all sizes

Follows same pattern as User Info (lines 42-54) and User Stats (lines 38-43) widgets.
2025-11-03 22:10:39 +11:00
Lucas 'Paperboy' Rose-Winters 5572d03762 feat(dashboard): implement flexible parsing for any date/weather format
Implemented Smart Hybrid Parser to handle virtually any fantasy or real-world scenario
while maintaining backward compatibility with existing comma-separated formats.

**Date Parsing Enhancement (infoBoxWidgets.js, lines 43-62):**
- Added conditional parsing: structured (comma-separated) vs unstructured
- Structured: "Tuesday, 15 January, 2024" → weekday/month/year split
- Unstructured: "3rd Day of Ninth Moon Year of Dragon" → full text in month field
- Handles: Fantasy calendars, ISO dates (2024-01-15), prose, stardates

**Weather Parsing Enhancement (infoBoxWidgets.js, lines 84-120):**
- JOIN remaining comma parts instead of taking only 2nd part
- Fixes: "🌧️, Heavy rain, flooding, winds" → preserves full forecast
- Added emoji prefix detection for non-comma formats
- Handles prose weather: "The air crackles with magical energy"
- Graceful fallback: no emoji → text-only display

**formatWeather Enhancement (sceneInfoWidget.js, lines 65-102):**
- Added no-emoji handling (display forecast only)
- Expanded symbol validation: custom symbols (+++, ***, ##)
- Symbol regex: /^[+*#~\-=_]+$/ for weather symbols
- Text-as-emoji handling: combines text with forecast gracefully

**formatLocation Enhancement (sceneInfoWidget.js, lines 126-148):**
- Changed to split on FIRST comma only (using indexOf)
- Preserves all remaining text after first comma as label
- Fixes: "The Winding Stair, Third Floor, East Wing, Palace" → keeps full context
- Still preserves hyphens in names (Seol Yi-hwan)

**CSS Text Wrapping (style.css, lines 2716-2745):**
- Removed white-space: nowrap restriction
- Added -webkit-line-clamp: 3 for values (2-3 line wrap)
- Added -webkit-line-clamp: 2 for labels
- Added word-wrap and overflow-wrap for long words
- Text now wraps gracefully instead of truncating prematurely

**Backward Compatibility:**
 Existing formats continue to work perfectly
 "Tuesday, 15 January, 2024" still parses as structured
 "🌤️, Partly cloudy" still displays with emoji
 "Location, City" still splits correctly

**New Format Support:**
 Fantasy: "3rd Day of the Ninth Moon Year of the Azure Dragon"
 ISO: "2024-01-15"
 Prose: "The third day after the full moon"
 Stardates: "Stardate 47634.44"
 Weather prose: "The air crackles with magical energy"
 Weather symbols: "+++, Heavy rainfall"
 Complex locations: "Building A, Floor 3, Room 101, Campus"
 Hyphenated names: "Seol Yi-hwan's Private Quarters"

**Testing Scenarios Covered:**
- Standard comma-separated formats (backward compat)
- Fantasy calendars without commas
- ISO date formats
- Prose descriptions for date/weather
- Stardates and custom time systems
- Weather symbols instead of emoji
- Multi-part weather forecasts
- Long multi-part locations
- Hyphenated character names

Result: Widget now handles ANY user-defined format while maintaining
visual polish and backward compatibility.
2025-11-03 17:18:41 +11:00
Lucas 'Paperboy' Rose-Winters 381b656bde fix(dashboard): handle complex date/weather formats in Scene Info
Fixed display issues with user's actual data formats:

Date Field Fix:
- Changed from simple "day + month" to using parsed fields
- Now displays data.month ("3rd Day of the Ninth Month")
- With data.weekday ("Tuesday") as label
- Handles complex comma-separated date strings correctly
- No more "JAN Friday, January..." overflow

Weather Field Fix:
- Added validation to check if weatherEmoji is actual emoji
- Expanded emoji detection regex to cover more Unicode ranges
- Falls back to ☀️ if weatherEmoji is text (like "Clear")
- Prevents "Clear 🌙 Clear skies" duplication
- Now shows just "Clear skies 🌙"

Location Field Fix:
- Changed split pattern from /[,\-]/ to comma-only
- Preserves hyphens in names (e.g., "Seol Yi-hwan")
- No more splitting "Seol Yi-hwan's Private Quarters"
- Secondary location parts (after comma) shown as label

Technical Changes:
- formatDate() now takes (fullDate, weekday, month) params
- Uses month field as primary display value
- formatWeather() validates emoji with expanded regex
- formatLocation() splits on comma only, preserves hyphens
- All formatters handle complex user-defined formats

Addresses parseInfoBoxData's comma-split parsing:
"Tuesday, 3rd Day of Ninth Month, Autumn, Year..." becomes:
  weekday: "Tuesday"
  month: "3rd Day of Ninth Month" (displayed)
  year: "Autumn" (not shown - save space)
2025-11-03 15:35:29 +11:00
Lucas 'Paperboy' Rose-Winters 637ee15666 fix(dashboard): improve date and weather formatting in Scene Info
Fixed redundant and confusing formatting:

Date Field:
- Changed from "JAN 15" + "Fri" to "15 Jan" + "Monday"
- More natural reading order (day before month)
- Full weekday name as label instead of 3-letter abbreviation
- No more ALL-CAPS month

Weather Field:
- Changed from icon-left + "Clear" + "Clear skies" (redundant)
  to "Clear Skies ☀️" (emoji on right)
- Removed redundant display of same text twice
- Emoji now appears at end of forecast text
- No separate icon element (included in text)

Technical Changes:
- Updated formatDate() to return icon and use natural order
- Updated formatWeather() to include emoji in value text
- Updated formatTime() and formatTemp() to return icon for consistency
- Updated renderInfoItem() to conditionally render icon only if present
- All formatters now return { icon, value, label } consistently

Result: Cleaner, more readable display without text duplication.
2025-11-03 11:42:02 +11:00
Lucas 'Paperboy' Rose-Winters b811d7c12e fix(dashboard): properly size Scene Info widget to fit container
Fixed sizing issues where Scene Info widget overflowed its container.

Problems fixed:
- Removed unnecessary .rpg-dashboard-widget wrapper
- Grid now fills container with height: 100%
- Reduced padding from 1rem → 0.375rem
- Reduced gaps from 0.75rem → 0.375rem
- Reduced item padding from 0.75rem → 0.375rem
- Reduced icon size from 1.5rem → 1.125rem
- Reduced font sizes:
  - Value: 1.125rem → 0.875rem
  - Label: 0.8125rem → 0.6875rem
  - Location value: 1rem → 0.8125rem
- Added text-overflow: ellipsis for long values
- Added min-height: 0 and overflow: hidden

Now follows same sizing pattern as other widgets (userInfo, userStats):
- Direct container without wrapper
- height/width: 100% to fill available space
- Compact padding and gaps
- Responsive font scaling
- Text truncation for overflow

Widget now fits properly in 2x2 grid space.
2025-11-03 11:31:38 +11:00
Lucas 'Paperboy' Rose-Winters 5a21a5aece feat(dashboard): redesign Scene Info widget with compact grid layout
Complete redesign of Scene Info widget following UX best practices:

BEFORE:
- Tab-based interface with 5 separate views
- Only 1 data point visible at a time (poor scannability)
- Size: 2×3 (oversized, wasted vertical space)
- Didn't fit in desktop side panel
- Poor information density

AFTER:
- Grid-based layout showing all 5 data points simultaneously
- High information density and scannability
- Compact size: 2×2 (reduced from 2×3)
- Inspired by Apple Widgets / Material Design patterns
- Mobile-responsive with breakpoints at 1000px and 340px
- Zero interaction needed - all data visible at once

Changes:
- sceneInfoWidget.js: Complete rewrite (390→309 lines)
  - Removed tab logic and state management
  - Added data formatting helpers (formatDate, formatTime, etc.)
  - Grid HTML structure with semantic CSS classes
  - Maintained inline editing for all fields
  - Simplified configuration

- style.css: Added comprehensive grid styling (lines 2647-2811)
  - CSS Grid layout with named areas
  - Responsive typography and spacing
  - Hover states and focus styles
  - 2 mobile breakpoints for optimal scaling

- defaultLayout.js: Updated Scene Info widget
  - Changed height: 3→2 rows
  - Adjusted Y positions for widgets below
  - Simplified config (removed view selection)

Design Principles:
- All information visible simultaneously (zero interaction)
- High scannability for quick information gathering
- Proper information density for simple data points
- Grid structure: 2 columns, 3 rows (location full-width header)
- Mobile-first responsive design

Layout:
┌─────────────────────────────────┐
│ 📍 Location                     │
├──────────────────┬──────────────┤
│ 📅 Date          │ 🕐 Time       │
├──────────────────┼──────────────┤
│ 🌤️ Weather       │ 🌡️ Temp       │
└──────────────────┴──────────────┘
2025-11-03 11:12:10 +11:00
Lucas 'Paperboy' Rose-Winters 4e6b3b0456 fix(dashboard): export parseInfoBoxData for sceneInfo widget
The sceneInfo widget imports parseInfoBoxData but it wasn't exported
from infoBoxWidgets.js, causing module import error.

Fix: Add export keyword to parseInfoBoxData function.

Error:
  Uncaught SyntaxError: The requested module './infoBoxWidgets.js'
  does not provide an export named 'parseInfoBoxData'
2025-11-03 10:55:26 +11:00
Lucas 'Paperboy' Rose-Winters 92cb5aedbd feat(dashboard): add Scene Info multi-view widget to reduce mobile scroll
Implements combined widget that merges Calendar, Weather, Temperature, Clock,
and Location into one tabbed interface, reducing Scene tab from 7 to 3 widgets.

Phase 2: Scene Info Multi-View Widget

New Features:
- sceneInfoWidget.js: Tab-based multi-view widget
  - Reuses existing infoBox widget render functions (no code duplication)
  - Tab bar with icon + label for each view (📅 Cal, 🌤️ Wea, 🌡️ Tmp, 🕐 Clk, 📍 Loc)
  - View switching by toggling CSS display (preserves handlers and state)
  - Smart empty state detection (hides tabs for widgets with no data)
  - Configurable: select views, default view, show/hide empty views

- Per-instance state management (activeSubTab persists per widget)
- Size: 2×3 default (tab bar + content)
- Registered in dashboardIntegration.js

Default Layout Changes:
- Scene tab: 7 widgets → 3 widgets (57% reduction)
- Old: Calendar (1×1) + Weather (1×1) + Temp (1×1) + Clock (1×1) + Location (2×2)
- New: Scene Info (2×3) - combined multi-view widget
- Repositioned: Recent Events (y: 4 → 3), Present Characters (y: 6 → 5)
- Vertical space: 10 rows → 9 rows (10% reduction)

Benefits:
- Reduces mobile vertical scroll by ~30%
- Cleaner Scene tab layout
- Individual widgets still available for customization
- Consistent UX with Inventory/Quests tab patterns
- Leverages existing CSS (.rpg-inventory-subtabs)

Technical Approach:
- Render all views once on mount (not destroyed on tab switch)
- Toggle visibility with CSS display property
- Preserves widget edit handlers and state
- Empty views filtered based on data availability

Individual calendar/weather/temperature/clock/location widgets remain
available in registry for users who prefer separate widgets.

Testing Required:
- Tab switching between all 5 views
- Empty state detection (remove data from infoBox)
- Edit functionality in each view
- Config changes (remove views, change default)
- Mobile responsive behavior
- Theme compatibility
2025-11-02 20:38:45 +11:00
Lucas 'Paperboy' Rose-Winters 64d0fe41dd feat(dashboard): move edit mode controls to menu permanently
Reduces header button crowding by keeping edit controls in menu at all screen sizes.

Changes:
- Add .rpg-menu-only-btn class to Add/Export/Import/Done buttons
- Remove display toggling from EditModeManager (simpler state machine)
- Update HeaderOverflowManager to:
  - Always hide menu-only buttons (never show inline)
  - Mark them as available for menu (wasVisible = 'true')
  - Filter menu items based on edit mode state
  - Add setEditModeManager() for edit state access
- Wire editModeManager to headerOverflowManager in integration

Result:
- Full mode: 6 visible buttons (was 10 with edit mode active)
- Overflow mode: 3 priority + menu with 3 standard + 4 edit (when active)
- Compact mode: 3 priority + hamburger with all actions (filtered by edit state)

Edit mode controls (Add Widget, Export, Import, Done) now only appear in
dropdown/hamburger menu, never inline. This creates cleaner visual hierarchy
and eliminates layout jumping when toggling edit mode.

Existing menu refresh on edit mode toggle (line 305) ensures menu updates
with correct items when entering/exiting edit mode.
2025-11-02 19:43:16 +11:00
Lucas 'Paperboy' Rose-Winters 2cdad81cb8 feat(dashboard): optimize Recent Events widget for mobile
Mobile optimizations to match app structure:
- Add .rpg-dashboard-widget wrapper for consistent layout
- Change .rpg-editable-event → .rpg-editable for mobile touch support
- Add mobile CSS block with scaled padding, gaps, and font sizes
- Fix base font sizes with px fallbacks for proper grid rendering

Fixes:
- Notebook title: 12px fallback (was pure vw)
- Bullet: 12px fallback (was pure vw)
- Event text: 11px fallback (was pure vw)

Mobile rules (max-width 1000px):
- Compact padding (0.2rem widget, 0.4rem lines)
- Scaled rings (0.15rem × 0.35rem)
- Readable fonts (0.6rem title, 0.55rem events)
- Proper touch targets with .rpg-editable class

Recent Events now matches mobile optimization patterns of all other
infoBox widgets (calendar, weather, temp, clock, location).
2025-11-02 19:00:48 +11:00
Lucas 'Paperboy' Rose-Winters 15ead7c21b fix(widgets): resolve data reading issues for Recent Events and Present Characters
Issue 1: Recent Events widget not updating
Root cause: Widget was reading from settings.committedTrackerData.infoBox (only updated on first gen) instead of using getInfoBoxData() from dependencies (updated every gen)

Fix:
- Changed registerRecentEventsWidget to use getInfoBoxData() pattern
- Updated render() to destructure getInfoBoxData from dependencies
- Updated attachRecentEventsHandlers to accept dependencies
- Rewrote updateRecentEvent to use getInfoBoxData/setInfoBoxData/onDataChange
- Now matches pattern used by other infoBox widgets (calendar, weather, etc.)

Issue 2: Present Characters showing 'Details' + granny emoji
Root cause: Parser expected OLD single-line format but AI returns NEW multi-line format from tracker customization system

OLD format: 🧐: Name, Traits | Relationship | Thoughts
NEW format:
- Name
Details: 🧐 | Traits
Relationship: Type
Thoughts: Text

Fix:
- Rewrote parseCharacterThoughts() to handle multi-line format:
  - Detects character entries starting with `-`
  - Parses Details: line for emoji and traits
  - Parses Relationship: line
  - Parses Thoughts: line (removes surrounding quotes)
  - Skips optional Stats: line
- Kept legacy single-line format as fallback for backward compatibility

Data flow verified:
AI response → parseResponse() → extensionSettings.infoBoxData → getInfoBoxData() → widget render()

Result:
 Recent Events displays: "Morning meditation, bathing, dressing"
 Present Characters displays: Full character cards with emoji, traits, relationship, thoughts
 Both widgets update on every AI generation
 Backward compatible with old format
2025-11-02 18:11:41 +11:00
Lucas 'Paperboy' Rose-Winters ded3694d54 fix(dashboard): resolve widget sizing and detection issues
Issue 1: PresentCharacters widget too small with gaps
- Increase height from h:3 to h:4 in defaultLayout.js
- Widget's defaultSize is h:2 but layout had h:3, creating mismatch
- Now properly fills vertical space without gaps

Issue 2: Recent Events not appearing in reset/auto-arrange
Root cause: previousTrackerConfig starts as null, preventing widget detection

Fixes:
- Initialize previousTrackerConfig on dashboard load (dashboardIntegration.js)
  - Deep clone trackerConfig after dashboard init
  - Enables detectConfigChanges() to work on first load
- Reset previousTrackerConfig to null in resetLayout() (dashboardManager.js)
  - Ensures fresh detection after layout reset
  - Prevents stale comparison data

Verified: Recent Events enabled by default in tracker config (state.js:95)

Result:
 PresentCharacters fills space properly
 Recent Events appears in reset layout
 Recent Events appears in auto-arrange
 Tracker editor enable/disable now works correctly
2025-11-02 17:28:15 +11:00
Lucas 'Paperboy' Rose-Winters 95f4ae1848 feat(dashboard): add Recent Events widget for v2 system
- Add registerRecentEventsWidget() in infoBoxWidgets.js
- Implement notebook-style UI with rings, bullet points, and editable events
- Support max 3 events with + placeholders for new entries
- Parse 'Recent Events: event1, event2, event3' format from infoBox
- Register widget in dashboardIntegration.js
- Add to default layout Scene tab (row 4-5, below location)
- Integrate with tracker system:
  - Add to WIDGET_TO_TAB_MAP (maps to tab-scene)
  - Add to shouldWidgetBeRemoved() rules
  - Add to detectConfigChanges() for re-addition support
- Completes v2 widget migration - all tracker features now have widgets
2025-11-02 16:21:56 +11:00
Lucas 'Paperboy' Rose-Winters bf44949624 feat(dashboard): implement bidirectional tracker-widget sync with re-addition
- Add previousTrackerConfig tracking in dashboardManager
- Implement detectConfigChanges() to detect disabled→enabled transitions
- Implement addEnabledWidgets() with smart tab placement using WIDGET_TO_TAB_MAP
- Update onTrackerConfigChanged() to handle both removal and re-addition
- Auto-layout affected tabs after widget changes
- Re-render current tab when widgets are added to show them immediately
- Prevent duplicate widgets per tab with type-based checking

Closes the bidirectional sync loop - widgets now automatically:
1. Disappear when fields are disabled in tracker settings
2. Reappear in appropriate tabs when fields are re-enabled
2025-11-02 14:54:55 +11:00
Lucas 'Paperboy' Rose-Winters 339413a6fa feat(dashboard): implement reactive tracker-dashboard integration
Replaced surface-level "disabled" messages with true reactive integration.
When tracker editor saves config changes, dashboard now automatically
updates without page reload - removing disabled widgets and refreshing
remaining ones with new field names/settings.

**Event-Based Architecture:**
- trackerEditor.js dispatches 'rpg:trackerConfigChanged' custom event
- dashboardManager.js subscribes to event and reacts to changes
- Decoupled, extensible, browser-native event system

**Dashboard Reactive Methods:**
- onTrackerConfigChanged(config): Main handler coordinating refresh flow
- removeDisabledWidgets(config): Removes widgets with disabled fields
  - Cleans up DOM, drag/resize handlers, state
  - Removes from tab.widgets arrays
- shouldWidgetBeRemoved(type, config): Decision logic per widget type
  - calendar → remove if date disabled
  - weather → remove if weather disabled
  - temperature → remove if temperature disabled
  - clock → remove if time disabled
  - location → remove if location disabled
  - userStats → remove only if ALL stats disabled
  - presentCharacters → remove if thoughts disabled
- refreshAllWidgets(): Re-renders all remaining widgets with new config

**Widget Auto-Removal Flow:**
1. User disables field in tracker editor
2. Clicks "Save & Apply"
3. Event fires → dashboard receives notification
4. Disabled widgets removed from all tabs
5. Affected tabs auto-layout to fill space
6. Remaining widgets re-render with new config
7. Layout saved automatically

**Removed Surface-Level Bandaid:**
- Deleted checkFieldEnabled() from infoBoxWidgets.js (-36 lines)
- Removed all checkFieldEnabled() calls from widget renders (-25 lines)
- Removed empty state message from userStatsWidget.js (-8 lines)
- Removed tracker settings link handler (-7 lines)
- Widgets no longer show "⚠️ Field disabled" messages
- Dashboard handles removal elegantly instead

**Result:**
True reactive integration. Disable "Arousal" → instantly disappears from
all userStats widgets. Disable "Date" → calendar widget removed and tab
auto-layouts. Rename "Health" to "HP" → updates instantly everywhere.
All changes happen immediately without page reload.

Files modified:
- src/systems/dashboard/dashboardManager.js (+129 lines)
- src/systems/ui/trackerEditor.js (+11 lines)
- src/systems/dashboard/widgets/infoBoxWidgets.js (-67 lines)
- src/systems/dashboard/widgets/userStatsWidget.js (-21 lines)
2025-11-02 10:35:35 +11:00
Lucas 'Paperboy' Rose-Winters d3c1f0a137 feat(dashboard): integrate tracker editor with widget system
Implemented hierarchical customization where trackerConfig controls content
(fields, names, AI instructions) and dashboard controls layout (positioning,
tabs, widget instances). Both systems now work together instead of conflicting.

**Widget Integration:**
- userStatsWidget: Respects trackerConfig for stat names and enable/disable
- userStatsWidget: Supports per-widget stat filtering via config.visibleStats
- userStatsWidget: Dynamically generates config options from trackerConfig
- infoBoxWidgets: All widgets (calendar, weather, temperature, clock, location)
  check trackerConfig.infoBox.widgets.*.enabled before rendering
- Widgets show "disabled" state with link to Tracker Settings when field disabled

**Dashboard UI:**
- Added Tracker Settings button to dashboard header (sliders icon)
- Button opens tracker editor modal for global field configuration
- Button positioned next to Edit Layout for clear separation of concerns

**Tracker Editor:**
- Added help text explaining relationship with dashboard system
- Help text clarifies: Tracker Settings = content, Edit Layout = positioning
- Styled with info banner at top of modal

**Migration:**
- Enhanced migrateV1ToV2Dashboard() to respect trackerConfig
- Removes userStats widget if all stats disabled in trackerConfig
- Removes presentCharacters widget if thoughts disabled in trackerConfig
- Ensures smooth upgrade path from v1.x

**CSS:**
- Added .rpg-editor-help styling for tracker editor help banner
- Added .rpg-widget-empty-state for disabled widget messaging
- Info-style banner with icon and clear typography

**Result:**
Two-level customization system:
1. Tracker Settings (global): What fields exist, their names, AI instructions
2. Edit Layout (local): Where widgets appear, per-widget overrides

Files modified:
- src/systems/dashboard/widgets/userStatsWidget.js (+75 lines)
- src/systems/dashboard/widgets/infoBoxWidgets.js (+67 lines)
- src/systems/dashboard/dashboardIntegration.js (+15 lines)
- src/systems/dashboard/dashboardTemplate.html (+4 lines)
- src/systems/dashboard/defaultLayout.js (+22 lines)
- template.html (+6 lines)
- style.css (+58 lines)
2025-11-02 10:23:36 +11:00
Lucas 'Paperboy' Rose-Winters f6ba2642f7 fix(dashboard): quest widget auto-arrange tab placement
Fixed auto-arrange placing quest widget into wrong tab.

Problem:
- Quest widget had category: 'scene' but needs dedicated tab
- Auto-arrange only created Status/Scene/Social/Inventory tabs
- Quest widget got grouped with scene widgets
- No 'quests' category existed in the system

Solution:
1. Changed quest widget category from 'scene' to 'quests'
2. Added 'quests' to category groups in distributeWidgetsByCategory()
3. Added Quests tab creation in auto-arrange logic
4. Updated category sort order to include 'quests' (order 5)

Changes:
- questsWidget.js: category: 'quests' (line 396)
- dashboardManager.js: Added 'quests' to groups object (line 870)
- dashboardManager.js: Added Quests tab creation (lines 942-954)
- dashboardManager.js: Updated categoryOrder to include 'quests': 5 (line 983)

Result:
- Auto-arrange now creates dedicated Quests tab 
- Quest widget correctly placed in Quests tab 
- Matches default layout structure 
- Clean separation of scene info vs quests 
2025-10-30 08:44:33 +11:00
Lucas 'Paperboy' Rose-Winters 9f92c4af87 feat(dashboard): add quest widget + fix 4-tab header layout
Quest Widget Integration:
- Created questsWidget.js with Main/Optional quest sub-tabs
- Added dedicated Quests tab (4th tab after Inventory)
- Registered quest widget in dashboardIntegration.js
- Widget features: inline editing, add/remove quests, contenteditable
- Fixed tab switching to use inline re-rendering (not full widget render)

Header Layout Fixes (4+ Tabs):
- Changed header flex-wrap from wrap to nowrap (prevents button wrapping)
- Added icon-only mode for 4+ tabs (disables hover expansion)
- Tab count detection in renderTabs() adds rpg-tabs-icon-only class
- Prevents layout breaking when tabs expand on hover

Technical Details:
- Quest widget follows inventory widget pattern (sub-tabs, per-instance state)
- Split event handlers: attachQuestHandlers (tabs) + attachQuestContentHandlers (buttons)
- Tab switching updates innerHTML inline and re-attaches content handlers
- Default size: 2w × 5h, category: 'scene'

Benefits:
- Quest tracking fully integrated with Dashboard v2 drag/drop
- No header wrapping issues with 4 tabs
- Cleaner icon-only UX when space is constrained
- Horizontal scrolling handles overflow gracefully
2025-10-30 08:40:46 +11:00
Lucas 'Paperboy' Rose-Winters e5e3e43aa1 perf(dashboard): disable console logging in hot-path files
Add DEBUG flag to disable console.log/warn in critical performance paths
while preserving console.error for actual errors. This eliminates ~80ms
of logging overhead during tab switches on mobile devices.

Modified files (hot-path only):
- dashboardManager.js (orchestrator, called for every widget)
- editModeManager.js (disableContentEditing on tab switch)
- gridEngine.js (positioning calculations for every widget)
- dragDrop.js (initWidget called for every widget)
- resizeHandler.js (initWidget called for every widget)

Performance impact:
- Before: ~40 console.log calls per tab switch (10 widgets)
- After: 0 console calls (no-op functions)
- Measured improvement: Tab switching now fast enough on mobile
  (slight slowdown during screen recording is expected overhead)

The DEBUG flag can be set to true for debugging when needed.
This approach avoids syntax errors from commenting multi-line statements.

Total optimization across all commits:
- Phase 1: Removed redundant global disable (2 queries saved)
- Phase 2: Replaced inline disabling with single global pass (18 queries saved)
- Phase 3: Disabled console logging (80ms saved on mobile)
- Result: ~200ms improvement on mobile devices
2025-10-30 08:07:53 +11:00
Lucas 'Paperboy' Rose-Winters 8abaa740c7 perf(dashboard): optimize content editing disable to use single global pass
Replace per-widget inline disabling (2N queries) with single global
disable pass after all widgets rendered (2 queries total). This reduces
DOM queries from 20 to 2 for a typical 10-widget tab, providing a 10x
performance improvement on mobile devices.

Changes:
- Remove inline querySelectorAll from renderWidgetContent()
  (was running 2 queries per widget during render loop)
- Add single synchronous disableContentEditing() call in onTabChange()
  after all widgets rendered (2 queries total)
- Remove redundant disableContentEditing() call from syncAllControls()
  (was duplicate of enterEditMode() call)

Performance impact:
- Before: 22 queries (20 inline + 2 global redundant)
- Phase 1: 20 queries (20 inline only, removed redundant global)
- Phase 2: 2 queries (2 global only, removed inline)
- Result: 10x reduction in DOM queries per tab switch

On mobile devices with 2-4x slower DOM performance, this should
reduce tab switching delay from 200-500ms to 20-50ms.
2025-10-30 07:42:26 +11:00
Lucas 'Paperboy' Rose-Winters 4984c02fd1 perf(dashboard): remove redundant content editing disable on tab switch
Remove global disableContentEditing() call in onTabChange() as it's
redundant - inline disabling in renderWidgetContent() already handles
all newly rendered widgets. This eliminates 2 global DOM queries per
tab switch, improving mobile performance by ~30ms.

The double-disable pattern was causing 22 DOM queries per tab switch
(20 inline + 2 global), which on mobile devices (2-4x slower DOM)
resulted in 200-500ms delays.

Root cause analysis:
- Commit a330ea9 added inline disabling per widget (necessary)
- Commit acb6da0 added global disabling in onTabChange (redundant)
- Mobile DOM queries are 2-4x slower than desktop
- querySelectorAll() on entire container is expensive

Fix removes the redundant global disable while keeping the necessary
inline disabling that runs when each widget is rendered.
2025-10-29 23:00:10 +11:00