intelligent-system-design-language 0.3.13

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 (209) hide show
  1. package/.claude/agents/langium-language-designer.md +38 -0
  2. package/.claude/agents/typescript-vscode-expert.md +29 -0
  3. package/.claude/agents/ui-ux-designer.md +36 -0
  4. package/.claude/settings.local.json +33 -0
  5. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  6. package/.idea/isdl.iml +14 -0
  7. package/.idea/modules.xml +9 -0
  8. package/.idea/vcs.xml +7 -0
  9. package/.idea/watcherTasks.xml +4 -0
  10. package/.vscodeignore +18 -0
  11. package/LICENSE +674 -0
  12. package/README.md +86 -0
  13. package/bin/cli.js +4 -0
  14. package/bin/lsp.js +8 -0
  15. package/isdl.png +0 -0
  16. package/out/_backgrounds.scss +91 -0
  17. package/out/_handlebars.scss +505 -0
  18. package/out/_isdlStyles.scss +1357 -0
  19. package/out/_vuetifyOverrides.scss +425 -0
  20. package/out/_vuetifyStyles.scss +31957 -0
  21. package/out/cli/cli-util.js +39 -0
  22. package/out/cli/cli-util.js.map +1 -0
  23. package/out/cli/components/_backgrounds.scss +91 -0
  24. package/out/cli/components/_handlebars.scss +505 -0
  25. package/out/cli/components/_isdlStyles.scss +1357 -0
  26. package/out/cli/components/_vuetifyOverrides.scss +425 -0
  27. package/out/cli/components/_vuetifyStyles.scss +31957 -0
  28. package/out/cli/components/active-effect-sheet-generator.js +643 -0
  29. package/out/cli/components/active-effect-sheet-generator.js.map +1 -0
  30. package/out/cli/components/base-actor-sheet-generator.js +125 -0
  31. package/out/cli/components/base-actor-sheet-generator.js.map +1 -0
  32. package/out/cli/components/base-sheet-generator.js +525 -0
  33. package/out/cli/components/base-sheet-generator.js.map +1 -0
  34. package/out/cli/components/chat-card-generator.js +683 -0
  35. package/out/cli/components/chat-card-generator.js.map +1 -0
  36. package/out/cli/components/css-generator.js +58 -0
  37. package/out/cli/components/css-generator.js.map +1 -0
  38. package/out/cli/components/damage-roll-generator.js +173 -0
  39. package/out/cli/components/damage-roll-generator.js.map +1 -0
  40. package/out/cli/components/datamodel-generator.js +672 -0
  41. package/out/cli/components/datamodel-generator.js.map +1 -0
  42. package/out/cli/components/derived-data-generator.js +1340 -0
  43. package/out/cli/components/derived-data-generator.js.map +1 -0
  44. package/out/cli/components/hotbar-drop-hook-generator.js +95 -0
  45. package/out/cli/components/hotbar-drop-hook-generator.js.map +1 -0
  46. package/out/cli/components/init-hook-generator.js +597 -0
  47. package/out/cli/components/init-hook-generator.js.map +1 -0
  48. package/out/cli/components/keywords-generator.js +220 -0
  49. package/out/cli/components/keywords-generator.js.map +1 -0
  50. package/out/cli/components/language-generator.js +110 -0
  51. package/out/cli/components/language-generator.js.map +1 -0
  52. package/out/cli/components/measured-template-preview.js +234 -0
  53. package/out/cli/components/measured-template-preview.js.map +1 -0
  54. package/out/cli/components/method-generator.js +1812 -0
  55. package/out/cli/components/method-generator.js.map +1 -0
  56. package/out/cli/components/ready-hook-generator.js +448 -0
  57. package/out/cli/components/ready-hook-generator.js.map +1 -0
  58. package/out/cli/components/token-generator.js +138 -0
  59. package/out/cli/components/token-generator.js.map +1 -0
  60. package/out/cli/components/utils.js +176 -0
  61. package/out/cli/components/utils.js.map +1 -0
  62. package/out/cli/components/vue/base-components/vue-attribute.js +148 -0
  63. package/out/cli/components/vue/base-components/vue-attribute.js.map +1 -0
  64. package/out/cli/components/vue/base-components/vue-boolean.js +77 -0
  65. package/out/cli/components/vue/base-components/vue-boolean.js.map +1 -0
  66. package/out/cli/components/vue/base-components/vue-calculator.js +106 -0
  67. package/out/cli/components/vue/base-components/vue-calculator.js.map +1 -0
  68. package/out/cli/components/vue/base-components/vue-damage-application.js +369 -0
  69. package/out/cli/components/vue/base-components/vue-damage-application.js.map +1 -0
  70. package/out/cli/components/vue/base-components/vue-damage-bonuses.js +225 -0
  71. package/out/cli/components/vue/base-components/vue-damage-bonuses.js.map +1 -0
  72. package/out/cli/components/vue/base-components/vue-damage-resistances.js +256 -0
  73. package/out/cli/components/vue/base-components/vue-damage-resistances.js.map +1 -0
  74. package/out/cli/components/vue/base-components/vue-damage-track.js +134 -0
  75. package/out/cli/components/vue/base-components/vue-damage-track.js.map +1 -0
  76. package/out/cli/components/vue/base-components/vue-date-time.js +55 -0
  77. package/out/cli/components/vue/base-components/vue-date-time.js.map +1 -0
  78. package/out/cli/components/vue/base-components/vue-dice.js +111 -0
  79. package/out/cli/components/vue/base-components/vue-dice.js.map +1 -0
  80. package/out/cli/components/vue/base-components/vue-die.js +86 -0
  81. package/out/cli/components/vue/base-components/vue-die.js.map +1 -0
  82. package/out/cli/components/vue/base-components/vue-document-choice.js +172 -0
  83. package/out/cli/components/vue/base-components/vue-document-choice.js.map +1 -0
  84. package/out/cli/components/vue/base-components/vue-document-choices.js +203 -0
  85. package/out/cli/components/vue/base-components/vue-document-choices.js.map +1 -0
  86. package/out/cli/components/vue/base-components/vue-document-link.js +73 -0
  87. package/out/cli/components/vue/base-components/vue-document-link.js.map +1 -0
  88. package/out/cli/components/vue/base-components/vue-extended-choice.js +101 -0
  89. package/out/cli/components/vue/base-components/vue-extended-choice.js.map +1 -0
  90. package/out/cli/components/vue/base-components/vue-inventory.js +532 -0
  91. package/out/cli/components/vue/base-components/vue-inventory.js.map +1 -0
  92. package/out/cli/components/vue/base-components/vue-macro-choice.js +150 -0
  93. package/out/cli/components/vue/base-components/vue-macro-choice.js.map +1 -0
  94. package/out/cli/components/vue/base-components/vue-measured-template.js +543 -0
  95. package/out/cli/components/vue/base-components/vue-measured-template.js.map +1 -0
  96. package/out/cli/components/vue/base-components/vue-money.js +496 -0
  97. package/out/cli/components/vue/base-components/vue-money.js.map +1 -0
  98. package/out/cli/components/vue/base-components/vue-number.js +184 -0
  99. package/out/cli/components/vue/base-components/vue-number.js.map +1 -0
  100. package/out/cli/components/vue/base-components/vue-paperdoll.js +56 -0
  101. package/out/cli/components/vue/base-components/vue-paperdoll.js.map +1 -0
  102. package/out/cli/components/vue/base-components/vue-parent-property-reference.js +89 -0
  103. package/out/cli/components/vue/base-components/vue-parent-property-reference.js.map +1 -0
  104. package/out/cli/components/vue/base-components/vue-prosemirror.js +31 -0
  105. package/out/cli/components/vue/base-components/vue-prosemirror.js.map +1 -0
  106. package/out/cli/components/vue/base-components/vue-resource.js +149 -0
  107. package/out/cli/components/vue/base-components/vue-resource.js.map +1 -0
  108. package/out/cli/components/vue/base-components/vue-roll-visualizer.js +121 -0
  109. package/out/cli/components/vue/base-components/vue-roll-visualizer.js.map +1 -0
  110. package/out/cli/components/vue/base-components/vue-self-property-reference.js +75 -0
  111. package/out/cli/components/vue/base-components/vue-self-property-reference.js.map +1 -0
  112. package/out/cli/components/vue/base-components/vue-string-choice.js +111 -0
  113. package/out/cli/components/vue/base-components/vue-string-choice.js.map +1 -0
  114. package/out/cli/components/vue/base-components/vue-string-choices.js +216 -0
  115. package/out/cli/components/vue/base-components/vue-string-choices.js.map +1 -0
  116. package/out/cli/components/vue/base-components/vue-string.js +73 -0
  117. package/out/cli/components/vue/base-components/vue-string.js.map +1 -0
  118. package/out/cli/components/vue/base-components/vue-text-field.js +66 -0
  119. package/out/cli/components/vue/base-components/vue-text-field.js.map +1 -0
  120. package/out/cli/components/vue/base-components/vue-tracker.js +444 -0
  121. package/out/cli/components/vue/base-components/vue-tracker.js.map +1 -0
  122. package/out/cli/components/vue/vue-action-component-generator.js +88 -0
  123. package/out/cli/components/vue/vue-action-component-generator.js.map +1 -0
  124. package/out/cli/components/vue/vue-active-effect-sheet-generator.js +1016 -0
  125. package/out/cli/components/vue/vue-active-effect-sheet-generator.js.map +1 -0
  126. package/out/cli/components/vue/vue-base-components-generator.js +59 -0
  127. package/out/cli/components/vue/vue-base-components-generator.js.map +1 -0
  128. package/out/cli/components/vue/vue-datatable-component-generator.js +307 -0
  129. package/out/cli/components/vue/vue-datatable-component-generator.js.map +1 -0
  130. package/out/cli/components/vue/vue-datatable-sheet-class-generator.js +342 -0
  131. package/out/cli/components/vue/vue-datatable-sheet-class-generator.js.map +1 -0
  132. package/out/cli/components/vue/vue-datatable2-component-generator.js +939 -0
  133. package/out/cli/components/vue/vue-datatable2-component-generator.js.map +1 -0
  134. package/out/cli/components/vue/vue-document-creation-app.js +140 -0
  135. package/out/cli/components/vue/vue-document-creation-app.js.map +1 -0
  136. package/out/cli/components/vue/vue-document-creation-sheet.js +105 -0
  137. package/out/cli/components/vue/vue-document-creation-sheet.js.map +1 -0
  138. package/out/cli/components/vue/vue-generator.js +240 -0
  139. package/out/cli/components/vue/vue-generator.js.map +1 -0
  140. package/out/cli/components/vue/vue-mixin.js +338 -0
  141. package/out/cli/components/vue/vue-mixin.js.map +1 -0
  142. package/out/cli/components/vue/vue-pinned-datatable-component-generator.js +306 -0
  143. package/out/cli/components/vue/vue-pinned-datatable-component-generator.js.map +1 -0
  144. package/out/cli/components/vue/vue-prompt-generator.js +201 -0
  145. package/out/cli/components/vue/vue-prompt-generator.js.map +1 -0
  146. package/out/cli/components/vue/vue-prompt-sheet-class-generator.js +252 -0
  147. package/out/cli/components/vue/vue-prompt-sheet-class-generator.js.map +1 -0
  148. package/out/cli/components/vue/vue-sheet-application-generator.js +2008 -0
  149. package/out/cli/components/vue/vue-sheet-application-generator.js.map +1 -0
  150. package/out/cli/components/vue/vue-sheet-class-generator.js +484 -0
  151. package/out/cli/components/vue/vue-sheet-class-generator.js.map +1 -0
  152. package/out/cli/generator.js +659 -0
  153. package/out/cli/generator.js.map +1 -0
  154. package/out/cli/main.js +43 -0
  155. package/out/cli/main.js.map +1 -0
  156. package/out/datatables.min.css +54 -0
  157. package/out/datatables.min.js +178 -0
  158. package/out/extension/github/githubAuthProvider.js +345 -0
  159. package/out/extension/github/githubAuthProvider.js.map +1 -0
  160. package/out/extension/github/githubConfig.js +132 -0
  161. package/out/extension/github/githubConfig.js.map +1 -0
  162. package/out/extension/github/githubGistActions.js +251 -0
  163. package/out/extension/github/githubGistActions.js.map +1 -0
  164. package/out/extension/github/githubGistManager.js +255 -0
  165. package/out/extension/github/githubGistManager.js.map +1 -0
  166. package/out/extension/github/githubManager.js +1735 -0
  167. package/out/extension/github/githubManager.js.map +1 -0
  168. package/out/extension/github/githubQuickActions.js +659 -0
  169. package/out/extension/github/githubQuickActions.js.map +1 -0
  170. package/out/extension/github/githubTreeProvider.js +181 -0
  171. package/out/extension/github/githubTreeProvider.js.map +1 -0
  172. package/out/extension/github/system-workflow.yml +48 -0
  173. package/out/extension/main.cjs +70315 -0
  174. package/out/extension/main.cjs.map +7 -0
  175. package/out/extension/main.js +237 -0
  176. package/out/extension/main.js.map +1 -0
  177. package/out/extension/package.json +426 -0
  178. package/out/isdl.png +0 -0
  179. package/out/language/generated/ast.js +2992 -0
  180. package/out/language/generated/ast.js.map +1 -0
  181. package/out/language/generated/grammar.js +13970 -0
  182. package/out/language/generated/grammar.js.map +1 -0
  183. package/out/language/generated/module.js +20 -0
  184. package/out/language/generated/module.js.map +1 -0
  185. package/out/language/intelligent-system-design-language-formatter.js +85 -0
  186. package/out/language/intelligent-system-design-language-formatter.js.map +1 -0
  187. package/out/language/intelligent-system-design-language-module.js +69 -0
  188. package/out/language/intelligent-system-design-language-module.js.map +1 -0
  189. package/out/language/intelligent-system-design-language-quickfixes.js +37 -0
  190. package/out/language/intelligent-system-design-language-quickfixes.js.map +1 -0
  191. package/out/language/intelligent-system-design-language-validator.js +515 -0
  192. package/out/language/intelligent-system-design-language-validator.js.map +1 -0
  193. package/out/language/isdl-hover-provider.js +77 -0
  194. package/out/language/isdl-hover-provider.js.map +1 -0
  195. package/out/language/isdl-scope-provider.js +149 -0
  196. package/out/language/isdl-scope-provider.js.map +1 -0
  197. package/out/language/main.cjs +47655 -0
  198. package/out/language/main.cjs.map +7 -0
  199. package/out/language/main.js +11 -0
  200. package/out/language/main.js.map +1 -0
  201. package/out/missing-character.png +0 -0
  202. package/out/package.json +426 -0
  203. package/out/paperdoll_default.png +0 -0
  204. package/out/progressbar.min.js +7 -0
  205. package/out/styles.scss +722 -0
  206. package/out/test/formatting/formatter.test.js +46 -0
  207. package/out/test/formatting/formatter.test.js.map +1 -0
  208. package/out/vuetify.esm.js +30279 -0
  209. package/package.json +426 -0
@@ -0,0 +1,532 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs';
3
+ import { expandToNode, toString } from 'langium/generate';
4
+ export default function generateInventoryComponent(destination, entry) {
5
+ const generatedFileDir = path.join(destination, "system", "templates", "vue", "components");
6
+ const generatedFilePath = path.join(generatedFileDir, `inventory.vue`);
7
+ if (!fs.existsSync(generatedFileDir)) {
8
+ fs.mkdirSync(generatedFileDir, { recursive: true });
9
+ }
10
+ const fileNode = expandToNode `
11
+ <script setup>
12
+ import { ref, computed, inject, onMounted, onUnmounted } from "vue";
13
+
14
+ const props = defineProps({
15
+ label: String,
16
+ systemPath: String,
17
+ context: Object,
18
+ editMode: Boolean,
19
+ icon: String,
20
+ color: String,
21
+ disabled: Boolean,
22
+ maxSlots: {
23
+ type: Number,
24
+ default: 20
25
+ },
26
+ columns: {
27
+ type: Number,
28
+ default: 5
29
+ },
30
+ rows: {
31
+ type: Number,
32
+ default: 3
33
+ },
34
+ slotSize: {
35
+ type: Number,
36
+ default: 60
37
+ },
38
+ documentType: String,
39
+ whereExpression: String,
40
+ globalAllowed: Boolean,
41
+ quantityField: String,
42
+ moneyField: String,
43
+ moneyFieldLabel: String,
44
+ moneyFieldIcon: String,
45
+ sumProperties: Array,
46
+ sumMax: Array,
47
+ sortProperty: String,
48
+ sortOrder: {
49
+ type: String,
50
+ default: 'asc'
51
+ },
52
+ emptySlots: {
53
+ type: String,
54
+ default: 'show'
55
+ },
56
+ summary: {
57
+ type: String,
58
+ default: 'full'
59
+ },
60
+ primaryColor: String,
61
+ secondaryColor: String,
62
+ teritaryColor: String
63
+ });
64
+
65
+ const document = inject('rawDocument');
66
+
67
+ // Calculate grid configuration
68
+ const gridConfig = computed(() => {
69
+ const columns = props.columns || 5;
70
+ const rows = props.rows || 3;
71
+
72
+ // Calculate total slots from columns × rows
73
+ let totalSlots = columns * rows;
74
+
75
+ // Cap at maxSlots if specified
76
+ if (props.maxSlots) {
77
+ totalSlots = Math.min(totalSlots, props.maxSlots);
78
+ }
79
+
80
+ return { totalSlots, columns };
81
+ });
82
+
83
+ // Force update trigger for reactive updates
84
+ const updateKey = ref(0);
85
+ const forceUpdate = () => {
86
+ updateKey.value++;
87
+ };
88
+
89
+ // Get filtered items
90
+ const filteredItems = computed(() => {
91
+ // Depend on updateKey to trigger re-evaluation
92
+ const _ = updateKey.value;
93
+ let items = Array.from(document.items || []);
94
+
95
+ // Filter by document type
96
+ items = items.filter(item => item.type === props.documentType);
97
+
98
+ // Apply where expression if provided
99
+ if (props.whereExpression) {
100
+ try {
101
+ const filterFunc = new Function('item', 'system', \`return \${props.whereExpression}\`);
102
+ items = items.filter(item => filterFunc(item, props.context.system));
103
+ } catch (e) {
104
+ console.error('Error filtering inventory items:', e);
105
+ }
106
+ }
107
+
108
+ // Add global items if allowed
109
+ if (props.globalAllowed) {
110
+ const gameItems = game.items.filter(item => item.type === props.documentType);
111
+ items = items.concat(gameItems);
112
+
113
+ const itemPacks = game.packs.filter(pack => pack.documentName === 'Item');
114
+ for (let pack of itemPacks) {
115
+ const packItems = pack.index.contents.filter(item => item.type === props.documentType);
116
+ packItems.forEach(item => {
117
+ item.compendium = pack;
118
+ });
119
+ items = items.concat(packItems);
120
+ }
121
+ }
122
+
123
+ // Apply sorting if specified
124
+ if (props.sortProperty) {
125
+ items.sort((a, b) => {
126
+ const aProp = foundry.utils.getProperty(a, \`system.\${props.sortProperty.toLowerCase()}\`);
127
+ const bProp = foundry.utils.getProperty(b, \`system.\${props.sortProperty.toLowerCase()}\`);
128
+
129
+ let aVal = aProp;
130
+ let bVal = bProp;
131
+
132
+ // Handle nested values (like resource.value)
133
+ if (typeof aProp === 'object' && aProp?.value !== undefined) aVal = aProp.value;
134
+ if (typeof bProp === 'object' && bProp?.value !== undefined) bVal = bProp.value;
135
+
136
+ if (aVal < bVal) return props.sortOrder === 'asc' ? -1 : 1;
137
+ if (aVal > bVal) return props.sortOrder === 'asc' ? 1 : -1;
138
+ return 0;
139
+ });
140
+ }
141
+
142
+ return items;
143
+ });
144
+
145
+ // Generate slots for display
146
+ const inventorySlots = computed(() => {
147
+ const slots = [];
148
+ const config = gridConfig.value;
149
+ let firstEmptyFound = false;
150
+
151
+ for (let i = 0; i < config.totalSlots; i++) {
152
+ if (i < filteredItems.value.length) {
153
+ const item = filteredItems.value[i];
154
+ let quantity = null;
155
+
156
+ if (props.quantityField) {
157
+ const quantityValue = foundry.utils.getProperty(item, \`system.\${props.quantityField.toLowerCase()}\`);
158
+ quantity = typeof quantityValue === 'object' ? quantityValue.value : quantityValue;
159
+ }
160
+
161
+ slots.push({
162
+ item: item,
163
+ quantity: quantity,
164
+ empty: false,
165
+ isCreateSlot: false
166
+ });
167
+ } else if (props.emptySlots === 'show') {
168
+ const isCreateSlot = !firstEmptyFound;
169
+ if (isCreateSlot) firstEmptyFound = true;
170
+
171
+ slots.push({
172
+ item: null,
173
+ quantity: null,
174
+ empty: true,
175
+ isCreateSlot: isCreateSlot
176
+ });
177
+ }
178
+ }
179
+
180
+ return slots;
181
+ });
182
+
183
+ // Calculate aggregations
184
+ const aggregations = computed(() => {
185
+ if (!props.sumProperties || props.sumProperties.length === 0) {
186
+ return [];
187
+ }
188
+
189
+ return props.sumProperties.map((propName, index) => {
190
+ let total = 0;
191
+
192
+ filteredItems.value.forEach(item => {
193
+ const propValue = foundry.utils.getProperty(item, \`system.\${propName.toLowerCase()}\`);
194
+
195
+ if (typeof propValue === 'number') {
196
+ total += propValue;
197
+ } else if (propValue?.value !== undefined) {
198
+ total += propValue.value;
199
+ }
200
+ });
201
+
202
+ const max = props.sumMax && props.sumMax[index] ? props.sumMax[index] : null;
203
+
204
+ return {
205
+ name: propName,
206
+ label: game.i18n.localize(propName),
207
+ value: total,
208
+ formatted: total.toLocaleString(),
209
+ max: max,
210
+ percentage: max ? Math.min(100, (total / max) * 100) : null
211
+ };
212
+ });
213
+ });
214
+
215
+ // Get money value
216
+ const moneyValue = computed(() => {
217
+ // Depend on updateKey to trigger re-evaluation
218
+ const _ = updateKey.value;
219
+ if (!props.moneyField) return null;
220
+ return foundry.utils.getProperty(document, \`system.\${props.moneyField.toLowerCase()}\`);
221
+ });
222
+
223
+ // Format money display
224
+ const formattedMoney = computed(() => {
225
+ if (!moneyValue.value) return '0';
226
+
227
+ if (typeof moneyValue.value === 'number') {
228
+ return moneyValue.value.toLocaleString();
229
+ }
230
+
231
+ // Multi-denomination money
232
+ if (typeof moneyValue.value === 'object') {
233
+ const parts = [];
234
+ for (const [denom, amount] of Object.entries(moneyValue.value)) {
235
+ if (amount > 0) {
236
+ parts.push(\`\${amount}\${denom.charAt(0)}\`);
237
+ }
238
+ }
239
+ return parts.length > 0 ? parts.join(' ') : '0';
240
+ }
241
+
242
+ return '0';
243
+ });
244
+
245
+ // Get capacity color for a percentage
246
+ const getCapacityColor = (percentage) => {
247
+ if (!percentage) return 'success';
248
+ if (percentage > 100) return 'error';
249
+ if (percentage >= 90) return 'error';
250
+ if (percentage >= 70) return 'warning';
251
+ return 'success';
252
+ };
253
+
254
+ // Handle item click
255
+ const onItemClick = (slot) => {
256
+ if (slot.empty) {
257
+ if (slot.isCreateSlot) {
258
+ onCreateItem();
259
+ }
260
+ return;
261
+ }
262
+ if (slot.item) {
263
+ slot.item.sheet.render(true);
264
+ }
265
+ };
266
+
267
+ // Handle create new item
268
+ const onCreateItem = async () => {
269
+ if (!props.documentType) return;
270
+
271
+ const itemData = {
272
+ name: game.i18n.localize(\`New \${props.documentType}\`),
273
+ type: props.documentType
274
+ };
275
+
276
+ const created = await document.createEmbeddedDocuments('Item', [itemData]);
277
+ if (created && created[0]) {
278
+ created[0].sheet.render(true);
279
+ }
280
+ };
281
+
282
+ // Handle delete item
283
+ const onDeleteItem = async (event, slot) => {
284
+ // Prevent the click from opening the item sheet
285
+ event.stopPropagation();
286
+
287
+ if (!slot.item) return;
288
+
289
+ const confirmed = await Dialog.confirm({
290
+ title: game.i18n.localize('Delete Item'),
291
+ content: \`<p>\${game.i18n.format('Are you sure you want to delete {name}?', { name: slot.item.name })}</p>\`,
292
+ });
293
+
294
+ if (confirmed) {
295
+ await slot.item.delete();
296
+ }
297
+ };
298
+
299
+ // Handle drag start
300
+ const onDragStart = (event, slot) => {
301
+ if (!slot.item) return;
302
+
303
+ const dragData = {
304
+ type: 'Item',
305
+ uuid: slot.item.uuid
306
+ };
307
+
308
+ event.dataTransfer.setData('text/plain', JSON.stringify(dragData));
309
+
310
+ // Add dragging class for visual feedback
311
+ event.target.classList.add('dragging');
312
+ };
313
+
314
+ // Handle drag end
315
+ const onDragEnd = (event) => {
316
+ // Remove dragging class
317
+ event.target.classList.remove('dragging');
318
+ };
319
+
320
+ // Get item name for tooltip
321
+ const getItemName = (slot) => {
322
+ if (slot.empty || !slot.item) return '';
323
+ return slot.item.name;
324
+ };
325
+
326
+ // Get item description for tooltip
327
+ const getItemDescription = (slot) => {
328
+ if (slot.empty || !slot.item) return '';
329
+
330
+ // Get description - handle both value and direct description
331
+ const description = slot.item.system?.description?.value || slot.item.system?.description;
332
+ if (!description) return '';
333
+
334
+ // Truncate if too long
335
+ if (description.length > 200) {
336
+ return description.substring(0, 200) + '...';
337
+ }
338
+
339
+ return description;
340
+ };
341
+
342
+ // Get summed property values for tooltip
343
+ const getItemSumProperties = (slot) => {
344
+ if (slot.empty || !slot.item || !props.sumProperties || props.sumProperties.length === 0) {
345
+ return [];
346
+ }
347
+
348
+ return props.sumProperties.map(propName => {
349
+ const propValue = foundry.utils.getProperty(slot.item, \`system.\${propName.toLowerCase()}\`);
350
+
351
+ let value = 0;
352
+ if (typeof propValue === 'number') {
353
+ value = propValue;
354
+ } else if (propValue?.value !== undefined) {
355
+ value = propValue.value;
356
+ }
357
+
358
+ return {
359
+ name: propName,
360
+ label: game.i18n.localize(propName),
361
+ value: value,
362
+ formatted: value.toLocaleString()
363
+ };
364
+ }).filter(prop => prop.value > 0); // Only show properties with values
365
+ };
366
+
367
+ // Count items
368
+ const itemCount = computed(() => {
369
+ return filteredItems.value.length;
370
+ });
371
+
372
+ // Show summary based on mode
373
+ const showCount = computed(() => props.summary !== 'minimal');
374
+ const showAggregations = computed(() => props.summary === 'full');
375
+ const showMoney = computed(() => props.summary === 'full' && props.moneyField);
376
+
377
+ // Subscribe to item changes
378
+ const onItemChange = (item, options, userId) => {
379
+ // Check if this item belongs to our document
380
+ if (item.parent?.uuid === document.uuid) {
381
+ forceUpdate();
382
+ }
383
+ };
384
+
385
+ onMounted(() => {
386
+ Hooks.on('createItem', onItemChange);
387
+ Hooks.on('updateItem', onItemChange);
388
+ Hooks.on('deleteItem', onItemChange);
389
+ });
390
+
391
+ onUnmounted(() => {
392
+ Hooks.off('createItem', onItemChange);
393
+ Hooks.off('updateItem', onItemChange);
394
+ Hooks.off('deleteItem', onItemChange);
395
+ });
396
+ </script>
397
+
398
+ <template>
399
+ <div class="isdl-inventory" :key="updateKey">
400
+ <!-- Header -->
401
+ <div class="inventory-header" v-if="showCount">
402
+ <div class="header-content">
403
+ <v-icon v-if="icon" :icon="icon" size="small"></v-icon>
404
+ <span class="inventory-label">{{ game.i18n.localize(label) }}</span>
405
+ </div>
406
+ <span class="inventory-count">
407
+ {{ itemCount }}/{{ gridConfig.totalSlots }}
408
+ </span>
409
+ </div>
410
+
411
+ <!-- Grid Container -->
412
+ <div class="inventory-grid-container">
413
+ <div
414
+ class="inventory-grid"
415
+ :style="{
416
+ gridTemplateColumns: \`repeat(\${gridConfig.columns}, \${slotSize}px)\`,
417
+ }"
418
+ >
419
+ <v-tooltip
420
+ v-for="(slot, index) in inventorySlots"
421
+ :key="index"
422
+ :disabled="slot.empty && !slot.isCreateSlot"
423
+ location="top"
424
+ max-width="400"
425
+ >
426
+ <template v-slot:activator="{ props: tooltipProps }">
427
+ <div
428
+ v-bind="tooltipProps"
429
+ class="inventory-slot"
430
+ :class="{
431
+ 'empty': slot.empty,
432
+ 'filled': !slot.empty,
433
+ 'create-slot': slot.isCreateSlot
434
+ }"
435
+ :style="{
436
+ width: \`\${slotSize}px\`,
437
+ height: \`\${slotSize}px\`
438
+ }"
439
+ :draggable="!slot.empty && !!slot.item"
440
+ @click="onItemClick(slot)"
441
+ @dragstart="onDragStart($event, slot)"
442
+ @dragend="onDragEnd($event)"
443
+ >
444
+ <img
445
+ v-if="!slot.empty && slot.item"
446
+ :src="slot.item.img"
447
+ :alt="slot.item.name"
448
+ class="slot-image"
449
+ />
450
+ <v-icon
451
+ v-if="slot.isCreateSlot"
452
+ icon="fa-solid fa-plus"
453
+ size="large"
454
+ class="create-icon"
455
+ ></v-icon>
456
+ <div
457
+ v-if="!slot.empty && slot.item"
458
+ class="delete-button"
459
+ @click="onDeleteItem($event, slot)"
460
+ :data-tooltip="game.i18n.localize('Delete')"
461
+ >
462
+ <v-icon icon="fa-solid fa-times" size="x-small"></v-icon>
463
+ </div>
464
+ <div
465
+ v-if="!slot.empty && slot.quantity && slot.quantity > 1"
466
+ class="quantity-badge"
467
+ >
468
+ {{ slot.quantity }}
469
+ </div>
470
+ </div>
471
+ </template>
472
+ <template v-slot:default>
473
+ <div v-if="slot.isCreateSlot" class="inventory-tooltip">
474
+ <div class="tooltip-title">{{ game.i18n.localize('Create New Item') }}</div>
475
+ </div>
476
+ <div v-else class="inventory-tooltip">
477
+ <div class="tooltip-title">{{ getItemName(slot) }}</div>
478
+ <div v-if="getItemDescription(slot)" class="tooltip-description" v-html="getItemDescription(slot)"></div>
479
+ <div v-if="getItemSumProperties(slot).length > 0" class="tooltip-properties">
480
+ <div v-for="prop in getItemSumProperties(slot)" :key="prop.name" class="tooltip-property">
481
+ <span class="property-label">{{ prop.label }}:</span>
482
+ <span class="property-value">{{ prop.formatted }}</span>
483
+ </div>
484
+ </div>
485
+ </div>
486
+ </template>
487
+ </v-tooltip>
488
+ </div>
489
+ </div>
490
+
491
+ <!-- Footer -->
492
+ <div class="inventory-footer" v-if="showAggregations || showMoney">
493
+ <v-divider class="footer-divider"></v-divider>
494
+
495
+ <!-- Money Display -->
496
+ <div v-if="showMoney" class="inventory-stat money-display">
497
+ <div class="stat-header">
498
+ <v-icon v-if="moneyFieldIcon" :icon="moneyFieldIcon" size="small"></v-icon>
499
+ <span class="stat-label">{{ game.i18n.localize(moneyFieldLabel || 'Currency') }}</span>
500
+ </div>
501
+ <span class="stat-value">{{ formattedMoney }}</span>
502
+ </div>
503
+
504
+ <!-- Aggregations -->
505
+ <div v-if="showAggregations" v-for="agg in aggregations" :key="agg.name" class="inventory-stat aggregation-display">
506
+ <div class="stat-header">
507
+ <v-icon icon="fa-solid fa-calculator" size="small"></v-icon>
508
+ <span class="stat-label">{{ agg.label }}</span>
509
+ </div>
510
+ <div class="stat-value-container">
511
+ <span class="stat-value">
512
+ {{ agg.formatted }}
513
+ <span v-if="agg.max" class="stat-max"> / {{ agg.max }}</span>
514
+ </span>
515
+ <!-- Progress bar for aggregations with max -->
516
+ <v-progress-linear
517
+ v-if="agg.max"
518
+ :model-value="agg.percentage"
519
+ :color="getCapacityColor(agg.percentage)"
520
+ height="6"
521
+ rounded
522
+ class="capacity-progress"
523
+ ></v-progress-linear>
524
+ </div>
525
+ </div>
526
+ </div>
527
+ </div>
528
+ </template>
529
+ `.appendNewLine();
530
+ fs.writeFileSync(generatedFilePath, toString(fileNode));
531
+ }
532
+ //# sourceMappingURL=vue-inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue-inventory.js","sourceRoot":"","sources":["../../../../../src/cli/components/vue/base-components/vue-inventory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG1D,MAAM,CAAC,OAAO,UAAU,0BAA0B,CAAC,WAAmB,EAAE,KAAa;IACjF,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAC5F,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAEvE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;QAClC,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;KACrD;IAED,MAAM,QAAQ,GAAG,YAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAugB5B,CAAC,aAAa,EAAE,CAAC;IAElB,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,150 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs';
3
+ import { expandToNode, toString } from 'langium/generate';
4
+ export default function generateMacroChoiceComponent(destination) {
5
+ const generatedFileDir = path.join(destination, "system", "templates", "vue", "components");
6
+ const generatedFilePath = path.join(generatedFileDir, `macro-field.vue`);
7
+ if (!fs.existsSync(generatedFileDir)) {
8
+ fs.mkdirSync(generatedFileDir, { recursive: true });
9
+ }
10
+ const fileNode = expandToNode `
11
+ <script setup>
12
+ import { ref, inject, computed } from "vue";
13
+
14
+ const props = defineProps({
15
+ label: String,
16
+ systemPath: String,
17
+ context: Object,
18
+ visibility: String,
19
+ editMode: Boolean,
20
+ primaryColor: String,
21
+ secondaryColor: String,
22
+ icon: String
23
+ });
24
+
25
+ const document = inject('rawDocument');
26
+
27
+ const value = ref(foundry.utils.getProperty(document, props.systemPath));
28
+ const onChange = (value) => {
29
+ let update = {};
30
+ update[props.systemPath] = value;
31
+ document.update(update);
32
+ const updated = fromUuidSync(value);
33
+ if (updated) selectedImage.value = updated.img;
34
+ };
35
+
36
+ const selectedImage = ref(value.value?.img);
37
+
38
+ const isHidden = computed(() => {
39
+ if (props.visibility === "hidden") {
40
+ return true;
41
+ }
42
+ if (props.visibility === "gmOnly") {
43
+ return !game.user.isGM;
44
+ }
45
+ if (props.visibility === "secret") {
46
+ const isGm = game.user.isGM;
47
+ const isOwner = document.getUserLevel(game.user) === CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER;
48
+ return !isGm && !isOwner;
49
+ }
50
+ if (props.visibility === "edit") {
51
+ return !props.editMode;
52
+ }
53
+ if (props.visibility === "play") {
54
+ return props.editMode;
55
+ }
56
+
57
+ // Default to visible
58
+ return false;
59
+ });
60
+
61
+ const isDisabled = () => {
62
+ const disabledStates = ["readonly", "locked"];
63
+ if (disabledStates.includes(props.visibility)) {
64
+ return true;
65
+ }
66
+ if (props.visibility === "gmEdit") {
67
+ const isGm = game.user.isGM;
68
+ const isEditMode = props.editMode;
69
+ return !isGm && !isEditMode;
70
+ }
71
+
72
+ if (props.visibility === "unlocked") {
73
+ return false;
74
+ }
75
+
76
+ // Default to enabled while in editMode
77
+ return !props.editMode;
78
+ };
79
+
80
+ const choices = computed(() => {
81
+ let system = props.context.system;
82
+ let allChoices = game.macros.contents;
83
+
84
+ if (allChoices.length === 0) return [{
85
+ id: null,
86
+ name: 'No choices available'
87
+ }];
88
+
89
+ return allChoices.map(choice => {
90
+ let context = {
91
+ id: choice.uuid,
92
+ name: choice.name,
93
+ image: choice.img,
94
+ source: choice.author.name
95
+ };
96
+
97
+ return context;
98
+ });
99
+ });
100
+
101
+ const getLabel = computed(() => {
102
+ const localized = game.i18n.localize(props.label);
103
+ if (props.icon) {
104
+ return \`<i class="fa-solid \${props.icon}"></i> \${localized}\`;
105
+ }
106
+ return localized;
107
+ });
108
+ </script>
109
+ <template>
110
+ <v-autocomplete clearable dense
111
+ v-model="value"
112
+ @update:modelValue="onChange"
113
+ :items="choices"
114
+ item-title="name"
115
+ item-value="id"
116
+ density="compact"
117
+ variant="outlined"
118
+ :disabled="disabled"
119
+ class="double-wide"
120
+ >
121
+ <template #label>
122
+ <span v-html="getLabel" />
123
+ </template>
124
+ <template v-slot:prepend-inner v-if="value">
125
+ <v-avatar rounded="0" :image="selectedImage" size="30" style="background-color: lightgray"></v-avatar>
126
+ </template>
127
+ <template v-slot:item="{ props, item }">
128
+ <v-list-item
129
+ v-bind="props"
130
+ :data-tooltip="item.raw.description"
131
+ >
132
+ <template v-slot:title>
133
+ <div class="flexrow">
134
+ <p style="flex: 1">{{ item.raw.name }}</p>
135
+ <v-spacer />
136
+ <v-chip size="small" label :color="secondaryColor" style="align-self: center; white-space: nowrap; flex: 0; line-height: 26px; display: inline-table;"><v-icon :icon="item.raw.icon" start></v-icon> {{ item.raw.source }}</v-chip>
137
+ </div>
138
+ </template>
139
+ <template v-if="item.raw.image" v-slot:prepend>
140
+ <v-avatar rounded="0" :image="item.raw.image" style="background-color: lightgray">
141
+ </v-avatar>
142
+ </template>
143
+ </v-list-item>
144
+ </template>
145
+ </v-autocomplete>
146
+ </template>
147
+ `;
148
+ fs.writeFileSync(generatedFilePath, toString(fileNode));
149
+ }
150
+ //# sourceMappingURL=vue-macro-choice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue-macro-choice.js","sourceRoot":"","sources":["../../../../../src/cli/components/vue/base-components/vue-macro-choice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAC,YAAY,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAExD,MAAM,CAAC,OAAO,UAAU,4BAA4B,CAAC,WAAmB;IACpE,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAC5F,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;IAEzE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;QAClC,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;KACrD;IAED,MAAM,QAAQ,GAAG,YAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyI5B,CAAC;IAEF,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5D,CAAC"}