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)
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.
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)
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
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
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
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
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
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
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.
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
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
The Recent Events widget was appearing as a narrow "little calendar thing"
instead of filling the full container width. The root cause was that
.rpg-events-widget container was missing `width: 100%`.
Changes:
- Add `width: 100%` to .rpg-events-widget (style.css:2517)
This makes the notebook container fill the full widget width
- Remove incorrect `width: 100%` from .rpg-notebook-line (was at line 2597)
This was a previous incorrect fix targeting child elements instead of parent
The parent .rpg-dashboard-widget has `align-items: center`, which causes
flex children without explicit width to shrink to content width. Adding
`width: 100%` to the widget container ensures it stretches to fill the
allocated grid cell.
Fixes: #sceneinfo-width
Related: commit aa50b24 (reverted incorrect fix)
Features:
- Made RPG attributes (STR/DEX/CON/INT/WIS/CHA) fully customizable
- Added enable/disable toggle for entire RPG Attributes section
- Users can add/remove/rename/toggle individual attributes
- Custom attribute names now appear in AI prompts for dice rolls
- Added proper CSS styling for attribute editor fields
Bug Fixes:
- Fixed character stat editing showing 0% on blur but saving correctly
- Character stats now create Stats line if missing from AI response
- Separated stat name from editable percentage value
- Added value sanitization (removes %, validates 0-100 range)
- Stats line now inserts before Thoughts line when created
Technical:
- Added buildAttributesString() helper in promptBuilder.js
- Updated generateTrackerInstructions and generateContextualSummary
- Restructured character stat HTML to prevent nested contenteditable
- Enhanced updateCharacterField to handle missing Stats lines
- Removed legacy default preset/regex import code
Fixed Recent Events widget content not stretching to fill the full widget width.
Content appeared narrow like a "little calendar thing" with wasted space on the right.
**Problem:**
- Vertical height was fixed (widget fills height correctly) ✓
- But content (event lines) didn't stretch horizontally ✗
- Event lines only as wide as their text content
- Unused space on right side of widget
- Notebook appeared narrow and compact
**Root Cause:**
`.rpg-notebook-line` (individual event line container) missing `width: 100%` property.
Without this, the flex container shrinks to fit content's natural width instead of
expanding to fill the parent container (`.rpg-notebook-lines`).
**Fix (style.css:2597):**
Added `width: 100%;` to `.rpg-notebook-line`
**How it works:**
- `.rpg-notebook-lines` has `flex: 1` → fills vertical space
- `.rpg-notebook-line` now has `width: 100%` → fills horizontal space
- `.rpg-event-text` has `flex: 1` → expands to fill remaining space after bullet
- `.rpg-bullet` stays at natural size
**Result:**
Event lines now stretch to use full widget width:
- Content fills horizontally from left to right
- Event text wraps properly using full available width
- No wasted space on the right
- Widget looks properly sized, not like a "little calendar thing"
**Before:**
Event lines shrink to content width → narrow appearance with unused space
**After:**
Event lines stretch to 100% width → full-width content utilizing all available space
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.
- Replace showRPGAttributes boolean with rpgAttributes array in trackerConfig
- Add RPG Attributes section in Edit Trackers with add/remove/rename/toggle
- Dynamically generate attribute display from config in userStats.js
- Add migration from old showRPGAttributes to new rpgAttributes array
- Initialize new attributes with default value of 10 in classicStats
- Default attributes: STR, DEX, CON, INT, WIS, CHA (all enabled)
Fixed CSS flexbox issue where Recent Events widget only used ~20-30% of its
allocated 2×2 grid space. Content was cramped at bottom with large empty space above.
**Root Cause:**
- `.rpg-events-widget` missing height and flex properties
- `.rpg-notebook-lines` (event container) not expanding to fill available space
- Widget only expanded to fit content, not allocated grid cell
**Changes (style.css):**
1. `.rpg-events-widget` (lines 2516-2517):
- Added `height: 100%` to fill parent container
- Added `flex: 1` to participate in flex layout properly
2. `.rpg-notebook-lines` (lines 2588-2589):
- Added `flex: 1` to expand and fill remaining vertical space
- Added `min-height: 0` to prevent flex item overflow
**Result:**
- Widget now properly fills full 2×2 grid allocation
- Events have proper breathing room and spacing
- Notebook aesthetic preserved with better proportions
- Works correctly at any size (2×1, 2×2, 3×3, etc.)
**Before:** ~134px content in ~300-400px space = 30-40% utilization
**After:** Content fills full allocated space with proper distribution
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.
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)
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.
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.
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 │
└──────────────────┴──────────────┘
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'
- Added clamp() to all vw-based font sizes for mobile compatibility
- Fixed collapse toggle button text size on mobile
- Fixed top position panel titles and stats text sizes
- Fixed panel header, loading indicator, and dice display sizes
- Applied overrides for both @media (max-width: 768px) and (max-width: 1000px)
- Ensures all text is readable on mobile devices without being too small
- Font sizes now scale responsively with minimum readable sizes
- Fixed together mode: Render panels before cleaning DOM so trackers display properly
- Fixed temperature unit toggle: Changed from 'celsius'/'fahrenheit' to 'C'/'F' to match config
- Fixed temperature widget: Thermometer color thresholds now use Celsius internally for consistency
- Fixed relationship remove buttons: Removed duplicate class causing wrong fields to be deleted
- Added styling for relationship remove buttons to match custom field buttons
- Added mobile font sizes for Past Events widget for better readability
- Added parsing debug log to help troubleshoot together mode issues
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
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.
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).
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
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
- 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
- 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
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)
Merged upstream/main (82b9564) which includes:
- Full tracker customization system
- Tracker editor UI component
- Custom stat names in AI prompts
- Multi-line tracker format updates
Conflict resolutions:
- src/core/persistence.js: Kept both dashboard v2 and trackerConfig migrations
- style.css: Accepted upstream responsive calendar styling with clamp()
Both migration systems are now active and will run in sequence.
- Completely rewrote updateCharacterField function to work with new multi-line Present Characters format
- Now parses character blocks by '- Name' lines instead of pipe-separated format
- Handles updating Details, Relationship, and Stats lines correctly
- Supports all field types: name, emoji, custom fields, relationship, character stats
- Creates new character blocks if character doesn't exist
- Fixes bug where edits would revert because old format logic couldn't parse new format
- Users can now successfully edit all Present Characters fields
Features:
- Complete tracker configuration UI with add/remove functionality
- User Stats: Custom stats, status fields, skills section
- Info Box: Configurable widgets (date, weather, temp, time, location, events)
- Present Characters: Custom fields, relationships, character stats, thoughts
- Character-specific stats with color interpolation
- New multi-line format for cleaner AI generation and parsing
- Auto-cleanup of placeholder brackets in AI responses
- Relationship badges with emoji mapping
- Advanced inventory v2 system with multi-location storage
- Responsive mobile support with horizontal scrolling
- Removed legacy format support for cleaner codebase
- Fixed context injection for together mode (no duplication)
- Updated README with new features and configuration guide
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 ✅