@carmaclouds/core 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/cache/CacheManager.d.ts.map +1 -0
  2. package/dist/cache/CacheManager.js +131 -0
  3. package/dist/cache/CacheManager.js.map +1 -0
  4. package/dist/index.d.ts +18 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +22 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/ir/index.d.ts +11 -0
  9. package/dist/ir/index.d.ts.map +1 -0
  10. package/dist/ir/index.js +9 -0
  11. package/dist/ir/index.js.map +1 -0
  12. package/dist/ir/normalize.d.ts +10 -0
  13. package/dist/ir/normalize.d.ts.map +1 -0
  14. package/dist/ir/normalize.js +207 -0
  15. package/dist/ir/normalize.js.map +1 -0
  16. package/dist/ir/persistence.d.ts +26 -0
  17. package/dist/ir/persistence.d.ts.map +1 -0
  18. package/dist/ir/persistence.js +21 -0
  19. package/dist/ir/persistence.js.map +1 -0
  20. package/dist/ir/sync.d.ts +12 -0
  21. package/dist/ir/sync.d.ts.map +1 -0
  22. package/dist/ir/sync.js +36 -0
  23. package/dist/ir/sync.js.map +1 -0
  24. package/dist/ir/types.d.ts +143 -0
  25. package/dist/ir/types.d.ts.map +1 -0
  26. package/dist/ir/types.js +13 -0
  27. package/dist/ir/types.js.map +1 -0
  28. package/dist/ir/views/dnd5e.d.ts +40 -0
  29. package/dist/ir/views/dnd5e.d.ts.map +1 -0
  30. package/dist/ir/views/dnd5e.js +50 -0
  31. package/dist/ir/views/dnd5e.js.map +1 -0
  32. package/dist/render/character.d.ts +19 -0
  33. package/dist/render/character.d.ts.map +1 -0
  34. package/dist/render/character.js +156 -0
  35. package/dist/render/character.js.map +1 -0
  36. package/dist/render/h.d.ts +27 -0
  37. package/dist/render/h.d.ts.map +1 -0
  38. package/dist/render/h.js +64 -0
  39. package/dist/render/h.js.map +1 -0
  40. package/dist/render/index.d.ts +11 -0
  41. package/dist/render/index.d.ts.map +1 -0
  42. package/dist/render/index.js +8 -0
  43. package/dist/render/index.js.map +1 -0
  44. package/dist/render/mount.d.ts +31 -0
  45. package/dist/render/mount.d.ts.map +1 -0
  46. package/dist/render/mount.js +63 -0
  47. package/dist/render/mount.js.map +1 -0
  48. package/dist/supabase/fields.d.ts.map +1 -0
  49. package/dist/supabase/fields.js +120 -0
  50. package/dist/supabase/fields.js.map +1 -0
  51. package/dist/types/character.d.ts.map +1 -0
  52. package/dist/types/character.js +5 -0
  53. package/dist/types/character.js.map +1 -0
  54. package/package.json +73 -0
  55. package/src/browser.js +51 -0
  56. package/src/cache/CacheManager.ts +174 -0
  57. package/src/common/browser-polyfill.js +319 -0
  58. package/src/common/debug.js +123 -0
  59. package/src/common/html-utils.js +134 -0
  60. package/src/common/theme-manager.js +265 -0
  61. package/src/index.ts +25 -0
  62. package/src/ir/__fixtures__/dnd5e-character.json +75962 -0
  63. package/src/ir/__fixtures__/non-dnd-character.json +14218 -0
  64. package/src/ir/index.ts +10 -0
  65. package/src/ir/normalize.ts +245 -0
  66. package/src/ir/persistence.ts +37 -0
  67. package/src/ir/sync.ts +49 -0
  68. package/src/ir/types.ts +161 -0
  69. package/src/ir/views/dnd5e.ts +94 -0
  70. package/src/lib/indexeddb-cache.js +320 -0
  71. package/src/modules/action-announcements.js +102 -0
  72. package/src/modules/action-display.js +1557 -0
  73. package/src/modules/action-executor.js +860 -0
  74. package/src/modules/action-filters.js +167 -0
  75. package/src/modules/action-options.js +117 -0
  76. package/src/modules/card-creator.js +142 -0
  77. package/src/modules/character-portrait.js +169 -0
  78. package/src/modules/character-trait-popups.js +959 -0
  79. package/src/modules/character-traits.js +814 -0
  80. package/src/modules/class-feature-edge-cases.js +1320 -0
  81. package/src/modules/color-utils.js +69 -0
  82. package/src/modules/combat-maneuver-edge-cases.js +660 -0
  83. package/src/modules/companions-manager.js +178 -0
  84. package/src/modules/concentration-tracker.js +178 -0
  85. package/src/modules/data-manager.js +514 -0
  86. package/src/modules/dice-roller.js +719 -0
  87. package/src/modules/effects-manager.js +743 -0
  88. package/src/modules/feature-modals.js +1264 -0
  89. package/src/modules/formula-resolver.js +444 -0
  90. package/src/modules/gm-mode.js +184 -0
  91. package/src/modules/health-modals.js +399 -0
  92. package/src/modules/hp-management.js +752 -0
  93. package/src/modules/inventory-manager.js +242 -0
  94. package/src/modules/macro-system.js +825 -0
  95. package/src/modules/notification-system.js +92 -0
  96. package/src/modules/racial-feature-edge-cases.js +746 -0
  97. package/src/modules/resource-manager.js +775 -0
  98. package/src/modules/sheet-builder.js +654 -0
  99. package/src/modules/spell-action-modals.js +583 -0
  100. package/src/modules/spell-cards.js +602 -0
  101. package/src/modules/spell-casting.js +723 -0
  102. package/src/modules/spell-display.js +314 -0
  103. package/src/modules/spell-edge-cases.js +509 -0
  104. package/src/modules/spell-macros.js +201 -0
  105. package/src/modules/spell-modals.js +1221 -0
  106. package/src/modules/spell-slots.js +224 -0
  107. package/src/modules/status-bar-bridge.js +101 -0
  108. package/src/modules/ui-utilities.js +284 -0
  109. package/src/modules/warlock-invocations.js +219 -0
  110. package/src/modules/window-management.js +211 -0
  111. package/src/render/character.ts +234 -0
  112. package/src/render/h.ts +74 -0
  113. package/src/render/index.ts +10 -0
  114. package/src/render/mount.ts +94 -0
  115. package/src/supabase/client.js +1383 -0
  116. package/src/supabase/config.js +60 -0
  117. package/src/supabase/fields.ts +129 -0
  118. package/src/types/character.ts +85 -0
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Inventory Manager Module
3
+ *
4
+ * Handles inventory display and item card creation.
5
+ * Loaded as a plain script (no ES6 modules) to export to window.
6
+ *
7
+ * Functions exported to globalThis:
8
+ * - rebuildInventory()
9
+ * - buildInventoryDisplay(container, inventory)
10
+ * - createInventoryCard(item)
11
+ */
12
+
13
+ (function() {
14
+ 'use strict';
15
+
16
+ // Inventory filter state (global so popup-sheet.js can update it)
17
+ if (!globalThis.inventoryFilters) {
18
+ globalThis.inventoryFilters = {
19
+ filter: 'equipped', // 'all', 'equipped', 'attuned', 'container'
20
+ search: ''
21
+ };
22
+ }
23
+ const inventoryFilters = globalThis.inventoryFilters;
24
+
25
+ /**
26
+ * Rebuild inventory display with current character data
27
+ */
28
+ function rebuildInventory() {
29
+ if (!characterData || !characterData.inventory) return;
30
+ const container = document.getElementById('inventory-container');
31
+ buildInventoryDisplay(container, characterData.inventory);
32
+ }
33
+
34
+ /**
35
+ * Build and display inventory with filtering
36
+ */
37
+ function buildInventoryDisplay(container, inventory) {
38
+ // Clear container
39
+ container.innerHTML = '';
40
+
41
+ // Update currency display in header
42
+ // updateInventoryCurrencyDisplay(inventory); // Commented out currency viewer
43
+
44
+ if (!inventory || inventory.length === 0) {
45
+ container.innerHTML = '<p style="color: var(--text-secondary); text-align: center; padding: 20px;">No items in inventory</p>';
46
+ return;
47
+ }
48
+
49
+ debug.log(`🎒 Building inventory display with ${inventory.length} items`);
50
+
51
+ // Apply filters
52
+ let filteredInventory = inventory.filter(item => {
53
+ // Filter out coins (currency) - they're tracked separately
54
+ const lowerName = (item.name || '').toLowerCase();
55
+ const coinPatterns = ['platinum piece', 'gold piece', 'silver piece', 'copper piece', 'electrum piece',
56
+ 'platinum coin', 'gold coin', 'silver coin', 'copper coin', 'electrum coin',
57
+ 'pp', 'gp', 'sp', 'cp', 'ep'];
58
+ // Check for exact matches or plurals
59
+ const isCoin = coinPatterns.some(pattern => {
60
+ if (pattern.length <= 2) {
61
+ // Short patterns (pp, gp, etc.) - match exactly or with quantity prefix
62
+ return lowerName === pattern || lowerName === pattern + 's' || lowerName.match(new RegExp(`^\\d+\\s*${pattern}s?$`));
63
+ }
64
+ // Longer patterns - match if name contains it
65
+ return lowerName.includes(pattern);
66
+ });
67
+ if (isCoin) {
68
+ return false;
69
+ }
70
+
71
+ // Filter by type
72
+ if (inventoryFilters.filter === 'equipped' && !item.equipped) {
73
+ return false;
74
+ }
75
+ if (inventoryFilters.filter === 'attuned' && !item.attuned) {
76
+ return false;
77
+ }
78
+ if (inventoryFilters.filter === 'container' && item.type !== 'container') {
79
+ return false;
80
+ }
81
+
82
+ // Filter by search term
83
+ if (inventoryFilters.search) {
84
+ const searchLower = inventoryFilters.search;
85
+ const name = (item.name || '').toLowerCase();
86
+ const desc = (item.description || '').toLowerCase();
87
+ const tagsString = (item.tags || []).join(' ').toLowerCase();
88
+ if (!name.includes(searchLower) && !desc.includes(searchLower) && !tagsString.includes(searchLower)) {
89
+ return false;
90
+ }
91
+ }
92
+
93
+ return true;
94
+ });
95
+
96
+ if (filteredInventory.length === 0) {
97
+ container.innerHTML = '<p style="color: var(--text-secondary); text-align: center; padding: 20px;">No items match filters</p>';
98
+ return;
99
+ }
100
+
101
+ // Sort inventory: equipped first, then by name
102
+ filteredInventory.sort((a, b) => {
103
+ if (a.equipped && !b.equipped) return -1;
104
+ if (!a.equipped && b.equipped) return 1;
105
+ return (a.name || '').localeCompare(b.name || '');
106
+ });
107
+
108
+ // Group items by category/container
109
+ filteredInventory.forEach(item => {
110
+ const itemCard = createInventoryCard(item);
111
+ container.appendChild(itemCard);
112
+ });
113
+
114
+ debug.log(`✅ Inventory display built with ${filteredInventory.length} items`);
115
+ }
116
+
117
+ /**
118
+ * Create an inventory item card element
119
+ */
120
+ function createInventoryCard(item) {
121
+ const card = document.createElement('div');
122
+ card.className = 'action-card'; // Reuse action card styling
123
+ card.style.cssText = `
124
+ background: var(--bg-card);
125
+ border-left: 4px solid ${item.equipped ? '#27ae60' : item.attuned ? '#9b59b6' : '#95a5a6'};
126
+ padding: 15px;
127
+ margin-bottom: 10px;
128
+ border-radius: 6px;
129
+ cursor: pointer;
130
+ transition: all 0.2s;
131
+ ${item.equipped ? 'box-shadow: 0 0 10px rgba(39, 174, 96, 0.3);' : ''}
132
+ `;
133
+
134
+ card.onmouseover = () => {
135
+ card.style.background = 'var(--bg-card-hover)';
136
+ card.style.transform = 'translateX(2px)';
137
+ };
138
+ card.onmouseout = () => {
139
+ card.style.background = 'var(--bg-card)';
140
+ card.style.transform = 'translateX(0)';
141
+ };
142
+
143
+ // Header with name and quantity
144
+ const header = document.createElement('div');
145
+ header.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;';
146
+
147
+ const nameSection = document.createElement('div');
148
+ nameSection.style.cssText = 'display: flex; align-items: center; gap: 8px;';
149
+
150
+ const itemName = document.createElement('strong');
151
+ itemName.textContent = item.name || 'Unnamed Item';
152
+ itemName.style.cssText = 'color: var(--text-primary); font-size: 1.1em;';
153
+ nameSection.appendChild(itemName);
154
+
155
+ // Add badges for equipped/attuned
156
+ if (item.equipped) {
157
+ const equippedBadge = document.createElement('span');
158
+ equippedBadge.textContent = '⚔️ Equipped';
159
+ equippedBadge.style.cssText = 'background: #27ae60; color: white; padding: 2px 8px; border-radius: 12px; font-size: 0.75em; font-weight: bold;';
160
+ nameSection.appendChild(equippedBadge);
161
+ }
162
+
163
+ if (item.attuned) {
164
+ const attunedBadge = document.createElement('span');
165
+ attunedBadge.textContent = '✨ Attuned';
166
+ attunedBadge.style.cssText = 'background: #9b59b6; color: white; padding: 2px 8px; border-radius: 12px; font-size: 0.75em; font-weight: bold;';
167
+ nameSection.appendChild(attunedBadge);
168
+ }
169
+
170
+ if (item.requiresAttunement && !item.attuned) {
171
+ const requiresBadge = document.createElement('span');
172
+ requiresBadge.textContent = '(Requires Attunement)';
173
+ requiresBadge.style.cssText = 'color: var(--text-muted); font-size: 0.85em; font-style: italic;';
174
+ nameSection.appendChild(requiresBadge);
175
+ }
176
+
177
+ header.appendChild(nameSection);
178
+
179
+ // Quantity display
180
+ const metaSection = document.createElement('div');
181
+ metaSection.style.cssText = 'display: flex; flex-direction: column; align-items: flex-end; gap: 4px;';
182
+
183
+ if (item.quantity > 1 || item.showIncrement) {
184
+ const quantitySpan = document.createElement('span');
185
+ quantitySpan.textContent = `×${item.quantity}`;
186
+ quantitySpan.style.cssText = 'color: var(--text-secondary); font-weight: bold; font-size: 1.1em;';
187
+ metaSection.appendChild(quantitySpan);
188
+ }
189
+
190
+ header.appendChild(metaSection);
191
+ card.appendChild(header);
192
+
193
+ // Weight
194
+ if (item.weight && item.weight > 0) {
195
+ const weightDiv = document.createElement('div');
196
+ const totalWeight = item.weight * item.quantity;
197
+ weightDiv.textContent = `⚖️ ${totalWeight} lb${totalWeight !== 1 ? 's' : ''}`;
198
+ weightDiv.style.cssText = 'color: var(--text-secondary); font-size: 0.85em; margin-bottom: 4px;';
199
+ card.appendChild(weightDiv);
200
+ }
201
+
202
+ // Tags
203
+ if (item.tags && item.tags.length > 0) {
204
+ const tagsDiv = document.createElement('div');
205
+ tagsDiv.style.cssText = 'display: flex; gap: 6px; flex-wrap: wrap; margin: 6px 0;';
206
+ item.tags.forEach(tag => {
207
+ const tagSpan = document.createElement('span');
208
+ tagSpan.textContent = tag;
209
+ tagSpan.style.cssText = 'background: var(--bg-tertiary); color: var(--text-secondary); padding: 2px 6px; border-radius: 8px; font-size: 0.75em;';
210
+ tagsDiv.appendChild(tagSpan);
211
+ });
212
+ card.appendChild(tagsDiv);
213
+ }
214
+
215
+ // Description (collapsed by default, click to expand)
216
+ if (item.description && item.description.trim()) {
217
+ const descDiv = document.createElement('div');
218
+ descDiv.style.cssText = 'color: var(--text-secondary); font-size: 0.9em; margin-top: 8px; border-top: 1px solid var(--border-color); padding-top: 8px; line-height: 1.4; max-height: 0; overflow: hidden; transition: max-height 0.3s;';
219
+ descDiv.innerHTML = item.description.replace(/\n/g, '<br>');
220
+
221
+ card.addEventListener('click', () => {
222
+ if (descDiv.style.maxHeight === '0px' || !descDiv.style.maxHeight) {
223
+ descDiv.style.maxHeight = '500px';
224
+ descDiv.style.paddingTop = '8px';
225
+ } else {
226
+ descDiv.style.maxHeight = '0px';
227
+ descDiv.style.paddingTop = '0px';
228
+ }
229
+ });
230
+
231
+ card.appendChild(descDiv);
232
+ }
233
+
234
+ return card;
235
+ }
236
+
237
+ // Export to globalThis for use across all scripts
238
+ window.rebuildInventory = rebuildInventory;
239
+ window.buildInventoryDisplay = buildInventoryDisplay;
240
+ window.createInventoryCard = createInventoryCard;
241
+
242
+ })();