diff --git a/src/systems/dashboard/dashboardManager.js b/src/systems/dashboard/dashboardManager.js index 56abb18..839a23d 100644 --- a/src/systems/dashboard/dashboardManager.js +++ b/src/systems/dashboard/dashboardManager.js @@ -1740,6 +1740,17 @@ export class DashboardManager { console.log('[DashboardManager] Detected re-enabled userStats widget'); } + // Check userAttributes widget (enabled when RPG Attributes section is enabled AND at least one attribute is enabled) + const oldAttrsDisabled = oldConfig.userStats?.showRPGAttributes === false || + (oldConfig.userStats?.rpgAttributes?.filter(a => a.enabled).length || 0) === 0; + const newAttrsEnabled = newConfig.userStats?.showRPGAttributes !== false && + (newConfig.userStats?.rpgAttributes?.filter(a => a.enabled).length || 0) > 0; + + if (oldAttrsDisabled && newAttrsEnabled) { + widgetsToAdd.push('userAttributes'); + console.log('[DashboardManager] Detected re-enabled userAttributes widget'); + } + // Check presentCharacters widget const wasThoughtsDisabled = oldConfig.presentCharacters?.thoughts?.enabled === false; const isThoughtsEnabled = newConfig.presentCharacters?.thoughts?.enabled !== false; @@ -1973,6 +1984,15 @@ export class DashboardManager { const customStats = config.userStats?.customStats || []; return customStats.filter(s => s.enabled).length === 0; }, + 'userAttributes': () => { + // Remove if RPG Attributes section is disabled + if (config.userStats?.showRPGAttributes === false) { + return true; + } + // Remove if all attributes are disabled + const rpgAttrs = config.userStats?.rpgAttributes || []; + return rpgAttrs.filter(attr => attr.enabled).length === 0; + }, 'presentCharacters': () => config.presentCharacters?.thoughts?.enabled === false }; diff --git a/src/systems/dashboard/widgets/userAttributesWidget.js b/src/systems/dashboard/widgets/userAttributesWidget.js index 7a3ae3e..390cb0e 100644 --- a/src/systems/dashboard/widgets/userAttributesWidget.js +++ b/src/systems/dashboard/widgets/userAttributesWidget.js @@ -1,14 +1,17 @@ /** * User Attributes Widget * - * Displays classic D&D-style attribute scores with +/- adjustment buttons. - * Shows STR, DEX, CON, INT, WIS, CHA stats. + * Displays customizable RPG attribute scores with +/- adjustment buttons. + * Integrates with Tracker Settings for full attribute customization. * * Features: - * - 6 classic RPG attributes + * - Fully customizable attributes (add/remove/rename via Tracker Settings) + * - Custom attribute names (e.g., "STRENGTH" instead of "STR", or add "LCK") + * - Widget-level filtering (show subset of globally enabled attributes) * - +/- buttons for quick adjustments (1-20 range) - * - Responsive grid layout - * - Smart sizing: compact for narrow, grid for wide + * - Responsive 2-column grid layout + * - Smart sizing: auto-adjusts height based on attribute count + * - Bi-directional sync with Tracker Editor */ import { parseNumber } from '../widgetBase.js'; @@ -29,7 +32,7 @@ export function registerUserAttributesWidget(registry, dependencies) { registry.register('userAttributes', { name: 'User Attributes', icon: '⚔️', - description: 'Classic RPG stats (STR, DEX, CON, INT, WIS, CHA)', + description: 'Customizable RPG attributes with +/- buttons (STR, DEX, etc.)', category: 'user', minSize: { w: 2, h: 2 }, defaultSize: { w: 2, h: 2 }, @@ -44,22 +47,48 @@ export function registerUserAttributesWidget(registry, dependencies) { render(container, config = {}) { const settings = getExtensionSettings(); const classicStats = settings.classicStats; + const trackerConfig = settings.trackerConfig?.userStats; + + // Get globally enabled attributes from trackerConfig + const globallyEnabledAttrs = trackerConfig?.rpgAttributes + ?.filter(attr => attr.enabled) + .map(attr => ({ id: attr.id, name: attr.name })) || []; + + // If no globally enabled attrs, fall back to defaults + const availableAttrs = globallyEnabledAttrs.length > 0 + ? globallyEnabledAttrs + : [ + { id: 'str', name: 'STR' }, + { id: 'dex', name: 'DEX' }, + { id: 'con', name: 'CON' }, + { id: 'int', name: 'INT' }, + { id: 'wis', name: 'WIS' }, + { id: 'cha', name: 'CHA' } + ]; + + // Apply widget-level filter if specified (support both visibleAttrs and legacy visibleStats) + let visibleAttrs = availableAttrs; + const filterList = config.visibleAttrs || config.visibleStats; + if (filterList && filterList.length > 0) { + visibleAttrs = availableAttrs.filter(attr => + filterList.includes(attr.id) + ); + } // Merge default config const finalConfig = { - visibleStats: ['str', 'dex', 'con', 'int', 'wis', 'cha'], showLabels: true, ...config }; - // Build stats HTML - const statsHtml = finalConfig.visibleStats.map(stat => ` -
- ${finalConfig.showLabels ? `${stat.toUpperCase()}` : ''} + // Build stats HTML using custom names from trackerConfig + const statsHtml = visibleAttrs.map(attr => ` +
+ ${finalConfig.showLabels ? `${attr.name}` : ''}
- - ${classicStats[stat]} - + + ${classicStats[attr.id] || 10} +
`).join(''); @@ -84,19 +113,29 @@ export function registerUserAttributesWidget(registry, dependencies) { * @returns {Object} Configuration schema */ getConfig() { + const settings = getExtensionSettings(); + const trackerConfig = settings.trackerConfig?.userStats; + + // Get enabled attributes from trackerConfig for options + const enabledAttrs = trackerConfig?.rpgAttributes + ?.filter(attr => attr.enabled) + .map(attr => ({ value: attr.id, label: attr.name })) || [ + { value: 'str', label: 'STR' }, + { value: 'dex', label: 'DEX' }, + { value: 'con', label: 'CON' }, + { value: 'int', label: 'INT' }, + { value: 'wis', label: 'WIS' }, + { value: 'cha', label: 'CHA' } + ]; + return { - visibleStats: { + visibleAttrs: { type: 'multiselect', label: 'Visible Attributes', - default: ['str', 'dex', 'con', 'int', 'wis', 'cha'], - options: [ - { value: 'str', label: 'Strength (STR)' }, - { value: 'dex', label: 'Dexterity (DEX)' }, - { value: 'con', label: 'Constitution (CON)' }, - { value: 'int', label: 'Intelligence (INT)' }, - { value: 'wis', label: 'Wisdom (WIS)' }, - { value: 'cha', label: 'Charisma (CHA)' } - ] + default: null, // null means "show all enabled attributes" + options: enabledAttrs, + description: 'Select which attributes to show in this widget (leave empty to show all enabled attributes)', + hint: 'To add/remove/rename attributes globally, use Tracker Settings' }, showLabels: { type: 'boolean', @@ -141,11 +180,20 @@ export function registerUserAttributesWidget(registry, dependencies) { * @returns {Object} Optimal size { w, h } */ getOptimalSize(config = {}) { - const visibleStatCount = config.visibleStats?.length || 6; + const settings = getExtensionSettings(); + const trackerConfig = settings.trackerConfig?.userStats; - // Each stat needs ~0.35 rows in 2-column grid - // For 6 stats: 3 rows (0.5 row padding = 3.5 total) - const optimalHeight = Math.ceil((visibleStatCount / 2) * 0.7 + 0.5); + // Count globally enabled attributes + const globallyEnabledCount = trackerConfig?.rpgAttributes + ?.filter(attr => attr.enabled).length || 6; + + // If widget has visibleAttrs override, use that count (support legacy visibleStats too) + const filterList = config.visibleAttrs || config.visibleStats; + const visibleAttrCount = filterList?.length || globallyEnabledCount; + + // Each attribute needs ~0.35 rows in 2-column grid + // For 6 attrs: 3 rows (0.5 row padding = 3.5 total) + const optimalHeight = Math.ceil((visibleAttrCount / 2) * 0.7 + 0.5); return { w: 2, // Prefer 2-column grid layout