feat(inventory): add list/grid view modes with individual item management

Implemented comprehensive individual item management system with toggleable view modes:

- Added item parsing utilities (parseItems/serializeItems) for comma-separated strings
- Implemented list view (full-width rows) and grid view (responsive cards)
- Added view mode toggle buttons per inventory section (onPerson, stored, assets)
- View preferences persist per-section in settings
- Replaced text-based editing with add/remove item controls
- Added inline forms for adding new items (matching existing UX patterns)
- Applied theme accent color (--rpg-highlight) to all outlines and active states
- Updated all tabs (desktop/mobile/inventory subtabs) with theme-consistent styling

Technical improvements:
- Created itemParser.js utility module for item string manipulation
- Enhanced inventory rendering with conditional list/grid HTML generation
- Added switchViewMode handler with settings persistence
- Fixed [object Object] display bug with comprehensive type checking
- All buttons and items now use transparent backgrounds with theme accent borders
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-17 17:30:57 +11:00
parent 26acee3a70
commit 73050a085b
5 changed files with 679 additions and 95 deletions
+68
View File
@@ -0,0 +1,68 @@
/**
* Item Parser Module
* Utilities for parsing item strings into arrays and vice versa
*/
/**
* Parses a comma-separated item string into an array of trimmed item names.
* Filters out empty strings and handles "None" gracefully.
*
* @param {string} itemString - Comma-separated items (e.g., "Sword, Shield, 3x Potions")
* @returns {string[]} Array of item names, or empty array if none
*
* @example
* parseItems("Sword, Shield, 3x Potions") // ["Sword", "Shield", "3x Potions"]
* parseItems("None") // []
* parseItems("") // []
* parseItems(null) // []
*/
export function parseItems(itemString) {
// Handle null/undefined/non-string
if (!itemString || typeof itemString !== 'string') {
return [];
}
// Trim and check for "None" (case-insensitive)
const trimmed = itemString.trim();
if (trimmed === '' || trimmed.toLowerCase() === 'none') {
return [];
}
// Split by comma, trim each item, filter empties
return itemString
.split(',')
.map(item => item.trim())
.filter(item => item !== '' && item.toLowerCase() !== 'none');
}
/**
* Serializes an array of items back into a comma-separated string.
* Returns "None" for empty arrays.
*
* @param {string[]} itemArray - Array of item names
* @returns {string} Comma-separated string, or "None" if empty
*
* @example
* serializeItems(["Sword", "Shield", "3x Potions"]) // "Sword, Shield, 3x Potions"
* serializeItems([]) // "None"
* serializeItems(["Sword"]) // "Sword"
*/
export function serializeItems(itemArray) {
// Handle null/undefined/non-array
if (!itemArray || !Array.isArray(itemArray)) {
return 'None';
}
// Filter out empty strings and trim
const cleaned = itemArray
.filter(item => item && typeof item === 'string' && item.trim() !== '')
.map(item => item.trim());
// Return "None" if array is empty after cleaning
if (cleaned.length === 0) {
return 'None';
}
// Join with comma and space
return cleaned.join(', ');
}