Add detailed console logging to trace how skills are being parsed and
categorized. This will help diagnose why skills are ending up in
"Uncategorized" instead of their proper categories.
Debug logs added:
- Log all lines extracted from skills section
- Log when category headers are detected
- Log when category arrays are created
- Log when skills are added to categories vs uncategorized
- Log ERROR when skill can't be added due to missing category array
- Log final skills data structure with category counts
Fallback behavior:
- If skill can't be added to its category (category array doesn't exist),
fall back to uncategorized with ERROR log
To see logs:
- Enable Debug Mode in RPG Companion settings
- Check browser console during AI response parsing
- Look for "[RPG Parser]" prefix
Related: Skills categorization issue investigation
Parser was only matching numeric levels "(Lv 5)" but AI was returning
text proficiencies like "(Proficient)", "(Advanced)", causing all skills
to be ignored and not categorized.
Changes to parser.js:
- Add fallback regex to match text proficiency format: "- Skill (Proficient)"
- Map text proficiencies to numeric levels:
- Initiated/Novice → Lv 1
- Basic/Beginner → Lv 2
- Intermediate → Lv 4
- Proficient → Lv 5
- Competent → Lv 6
- Advanced → Lv 7
- Expert → Lv 8
- Mastered/Master → Lv 9
- Grandmaster/Legendary → Lv 10
- Default to Lv 5 for unrecognized proficiency text
- Try numeric format first, fall back to text format
Changes to promptBuilder.js:
- Make prompt instructions more explicit about numeric format
- Add negative examples: "write 'Lv 5' not 'Proficient'"
- Add guidance: "1=novice, 5=intermediate, 10=expert"
- Emphasize with "IMPORTANT:" prefix
Benefits:
- Parser now handles both formats (backward compatible)
- AI has clearer instructions to use numeric levels
- Skills with text proficiencies now parse correctly and show in categories
- Existing numeric format continues to work
Issue Resolution:
- Skills like "Demonic Qi Manipulation (Proficient)" now parse as Lv 5
- Categories like "Demonic Arts:", "Combat:", "Social:" now populate correctly
- Widget displays skills organized by category instead of ignoring them
Related: Skills widget, AI tracker integration
Remove duplicate "Edit Trackers" button from hamburger menu since there's
already a Tracker Settings button in the dashboard header.
Changes:
- Removed "Edit Trackers" button from template.html hamburger menu
- Updated Settings button to full width (removed .rpg-btn-half class)
- Changed dashboard button ID from 'rpg-dashboard-tracker-settings' to
'rpg-open-tracker-editor' to become the canonical button
- Removed redundant event handler in dashboardIntegration.js that was
clicking the old hamburger button
Benefits:
- Reduces UI clutter in hamburger menu
- Single source of truth for Tracker Settings button (dashboard header)
- Existing code in trackerEditor.js, infoBoxWidgets.js continues to work
via jQuery event delegation on ID 'rpg-open-tracker-editor'
Technical Notes:
- jQuery delegation $(document).on('click', '#rpg-open-tracker-editor', ...)
works for any element with that ID, not just a specific one
- No changes needed to trackerEditor.js or widget disabled state handlers
- Dashboard button is now the canonical "Edit Trackers" trigger
Related: Hamburger menu UI, dashboard header controls
Show helpful message when Recent Events tracking is disabled in tracker config.
Changes:
- Check if recentEvents is enabled in trackerConfig before rendering
- If disabled, show dimmed widget with overlay message:
- Info icon + explanation text
- "Enable in Tracker Settings" button
- Button opens Tracker Settings and switches to Info Box tab
UX Improvements:
- Widget opacity reduced to 0.6 to indicate disabled state
- Message centered with clear visual hierarchy
- Button has hover/active states with elevation feedback
- Clicking button directly navigates to the right settings location
Technical Implementation:
- attachDisabledStateHandlers() opens Tracker Settings modal
- Auto-switches to Info Box tab after 100ms delay
- Graceful fallback if button not found (console warning)
CSS Additions:
- .rpg-widget-disabled: Dimmed overlay state
- .rpg-widget-disabled-message: Centered message container
- .rpg-widget-enable-btn: Styled action button with hover effects
Benefits:
- Users immediately understand why Recent Events isn't updating
- One-click access to fix the issue
- Clear visual feedback about widget state
- Pattern can be reused for other widgets (Skills, etc.)
Next Steps:
- Apply this pattern to other widgets that depend on tracker config
- Consider adding similar disabled states for Skills, Stats, etc.
Related: Recent Events widget implementation, tracker config system
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)
Add AI tracker awareness for skills system with proper level and category support.
Changes:
- Add extractSkills() parser function to extract structured skills data
- Parses category-based format: "CategoryName:\n- SkillName (Lv X)"
- Falls back to legacy string format for backward compatibility
- Returns structured data: { version: 1, categories: {}, uncategorized: [] }
- Update prompt instructions to request structured skills format
- AI now generates: "Skills:\nCombat:\n- Swordsmanship (Lv 5)"
- Supports multiple categories (Combat, Magic, Social, Crafting, etc.)
- Includes Uncategorized section for skills without clear category
- Add buildSkillsSummary() utility function
- Converts structured skills data back to formatted text
- Ready for future feature: syncing manual skill edits to AI context
Parser integration:
- parseUserStats() now uses extractSkills() to parse Skills section
- Stores structured data in extensionSettings.userStats.skills
- Widget reads structured data for display and level-up/down functionality
AI workflow:
1. AI generates skills in structured format (via prompt instructions)
2. Parser extracts to structured data (via extractSkills)
3. Widget displays with level controls (already implemented)
4. Raw text flows through committedTrackerData to next generation
Note: Manual skill edits (level-up/down in widget) are not yet synced back
to AI context. This requires additional work to regenerate the raw text
when skills are manually modified. buildSkillsSummary is ready for this.
Refs: Skills widget implementation (previous session)
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
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)
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.
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.
Resolves overlap issue between long character names and level indicator
in 1x2 userInfo widgets. Level now displays at top-right corner flush
with container, while name remains at bottom with full width available.
- Changed level container position from bottom: 0 to top: 0
- Prevents text overlap for names like 'Seol Yi-hwan Lvl 1'
- Maintains clean, compact layout at 1080p and other resolutions
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.
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.
**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.
**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
**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
- New setting in Display Options to auto-expand thought bubble
- When enabled, thought bubble displays immediately without clicking icon
- Checkbox added to settings modal with descriptive help text
- Default is off to maintain current behavior
- Increase character name, traits, and emoji sizes for better mobile readability
- Limit Recent Events section to 150px max height on mobile
- Make events widget scrollable to save screen space
- Reduce padding and gaps for more compact layout
- Load relationshipEmojis from config.relationshipEmojis in thoughts.js
- Custom relationships added in Edit Trackers now display correctly as emojis
- Falls back to default emojis if config not available
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.