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,939 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs';
3
+ import { expandToNode, joinToNode, toString } from 'langium/generate';
4
+ import { isAction, isActor, isBooleanExp, isChatCard, isColorParam, isDamageTypeChoiceField, isDateExp, isDateTimeExp, isDiceField, isDieField, isDocument, isDocumentChoiceExp, isHookHandler, isHtmlExp, isIconParam, isInitiativeProperty, isLayout, isMeasuredTemplateField, isPaperDollElement, isParentPropertyRefExp, isProperty, isResourceExp, isStringChoiceField, isStringExp, isTableFieldsParam, isTimeExp, isTrackerExp } from "../../../language/generated/ast.js";
5
+ import { getAllOfType, getSystemPath } from '../utils.js';
6
+ import { AstUtils } from 'langium';
7
+ export function generateVuetifyDatatableComponent(id, document, pageName, table, destination) {
8
+ var _a, _b, _c, _d, _e, _f, _g, _h;
9
+ const type = isActor(document) ? 'actor' : 'item';
10
+ const generatedFileDir = path.join(destination, "system", "templates", "vue", type, document.name.toLowerCase(), "components", "datatables");
11
+ const generatedFilePath = path.join(generatedFileDir, `${document.name.toLowerCase()}${pageName}${table.name}VuetifyDatatable.vue`);
12
+ if (!fs.existsSync(generatedFileDir)) {
13
+ fs.mkdirSync(generatedFileDir, { recursive: true });
14
+ }
15
+ const iconParam = table.params.find(p => isIconParam(p));
16
+ let fieldsParam = table.params.find(x => isTableFieldsParam(x));
17
+ let defaultVisibleFields = [];
18
+ if (fieldsParam) {
19
+ defaultVisibleFields = fieldsParam.fields;
20
+ }
21
+ else if ((_a = table.document.ref) === null || _a === void 0 ? void 0 : _a.body) {
22
+ defaultVisibleFields = (_b = getAllOfType(table.document.ref.body, isProperty, false)
23
+ .map(p => p.name.toLowerCase())) !== null && _b !== void 0 ? _b : [];
24
+ }
25
+ function generateDataTableHeader(refDoc, property) {
26
+ var _a;
27
+ if (isLayout(property)) {
28
+ return expandToNode `
29
+ ${joinToNode(property.body, p => generateDataTableHeader(refDoc, p), { appendNewLineIfNotEmpty: true })}
30
+ `;
31
+ }
32
+ if (isHtmlExp(property) || isInitiativeProperty(property) || isPaperDollElement(property) || isHookHandler(property))
33
+ return undefined;
34
+ if (isProperty(property)) {
35
+ const isHidden = property.modifier == "hidden";
36
+ if (isHidden)
37
+ return undefined;
38
+ let systemPath = getSystemPath(property, [], undefined, false);
39
+ let sortable = true;
40
+ if (isResourceExp(property) || isTrackerExp(property) || isDiceField(property) || isMeasuredTemplateField(property)) {
41
+ sortable = false;
42
+ }
43
+ if (isResourceExp(property) || isTrackerExp(property)) {
44
+ systemPath = systemPath.replace(/\.(value|max)$/, '');
45
+ }
46
+ let localizeName = `${(_a = refDoc === null || refDoc === void 0 ? void 0 : refDoc.ref) === null || _a === void 0 ? void 0 : _a.name}.${property.name}`;
47
+ let minWidth = '100px'; // Default minimum width
48
+ // Set appropriate minimum widths based on field type
49
+ if (isStringExp(property)) {
50
+ minWidth = '140px'; // Text fields need more space for content
51
+ return expandToNode `
52
+ { title: game.i18n.localize("${localizeName}"), key: '${systemPath}', sortable: ${sortable}, minWidth: '${minWidth}' },
53
+ `;
54
+ }
55
+ if (isDocumentChoiceExp(property) || isStringChoiceField(property) || isDamageTypeChoiceField(property)) {
56
+ localizeName += ".label";
57
+ minWidth = '120px'; // Document choices need extra space
58
+ }
59
+ if (isResourceExp(property) || isTrackerExp(property)) {
60
+ minWidth = '90px'; // Resource/tracker columns are compact
61
+ }
62
+ if (isDieField(property) || isDiceField(property)) {
63
+ minWidth = '80px'; // Dice fields are compact
64
+ }
65
+ if (isBooleanExp(property)) {
66
+ minWidth = '80px'; // Boolean chips are compact
67
+ }
68
+ if (isTimeExp(property) || isDateExp(property) || isDateTimeExp(property)) {
69
+ minWidth = '120px'; // Date fields need space for formatting
70
+ }
71
+ if (isMeasuredTemplateField(property)) {
72
+ minWidth = '130px'; // Template fields have longer text
73
+ }
74
+ return expandToNode `
75
+ { title: game.i18n.localize("${localizeName}"), key: '${systemPath}', sortable: ${sortable}, minWidth: '${minWidth}', type: '${property.$type}' },
76
+ `;
77
+ }
78
+ return undefined;
79
+ }
80
+ function generateSlotTemplate(refDoc, property) {
81
+ if (isLayout(property)) {
82
+ return expandToNode `
83
+ ${joinToNode(property.body, p => generateSlotTemplate(refDoc, p), { appendNewLineIfNotEmpty: true })}
84
+ `;
85
+ }
86
+ if (isHtmlExp(property) || isInitiativeProperty(property) || isPaperDollElement(property) || isHookHandler(property))
87
+ return undefined;
88
+ if (isProperty(property)) {
89
+ const isHidden = property.modifier == "hidden";
90
+ if (isHidden)
91
+ return undefined;
92
+ let systemPath = getSystemPath(property, [], undefined, false);
93
+ const slotName = systemPath;
94
+ if (isBooleanExp(property)) {
95
+ return expandToNode `
96
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
97
+ <v-chip
98
+ :color="getNestedValue(item, '${systemPath}') ? props.primaryColor : props.secondaryColor"
99
+ size="x-small"
100
+ variant="elevated"
101
+ class="text-caption"
102
+ label
103
+ >
104
+ <v-icon v-if="getNestedValue(item, '${systemPath}')">fa-solid fa-check</v-icon>
105
+ <v-icon v-else>fa-solid fa-times</v-icon>
106
+ </v-chip>
107
+ </template>
108
+ `;
109
+ }
110
+ if (isStringExp(property)) {
111
+ return expandToNode `
112
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
113
+ <div class="text-caption text-truncate" :data-tooltip="getNestedValue(item, '${systemPath}')" style="max-width: 300px;">
114
+ {{ getNestedValue(item, '${systemPath}') }}
115
+ </div>
116
+ </template>
117
+ `;
118
+ }
119
+ if (isStringChoiceField(property)) {
120
+ systemPath = systemPath.replace(/\.(value)$/, '');
121
+ const parentDocument = AstUtils.getContainerOfType(property, isDocument);
122
+ return expandToNode `
123
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
124
+ <v-chip label size="x-small" variant="elevated" class="text-caption" :color="getNestedValue(item, '${systemPath}.color')" :prepend-icon="getNestedValue(item, '${systemPath}.icon')" :data-tooltip="getExtendedChoiceTooltip(item, '${systemPath}')">
125
+ {{ game.i18n.localize('${parentDocument === null || parentDocument === void 0 ? void 0 : parentDocument.name}.${property.name}.' + getNestedValue(item, '${systemPath}.value')) }}
126
+ </v-chip>
127
+ </template>
128
+ `;
129
+ }
130
+ if (isParentPropertyRefExp(property)) {
131
+ return expandToNode `
132
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
133
+ <span class="text-caption">{{ humanize(getNestedValue(item, '${systemPath}')) }}</span>
134
+ </template>
135
+ `;
136
+ }
137
+ if (isResourceExp(property) || isTrackerExp(property)) {
138
+ systemPath = systemPath.replace(/\.(value|max)$/, '');
139
+ return expandToNode `
140
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName.replace(".value", "")}="{ item }">
141
+ <v-chip
142
+ label
143
+ :color="getResourceColor(getNestedValue(item, '${systemPath}'))"
144
+ size="x-small"
145
+ variant="elevated"
146
+ class="text-caption"
147
+ >
148
+ {{ getNestedValue(item, '${systemPath}.value') }}/{{ getNestedValue(item, '${systemPath}.max') }}
149
+ </v-chip>
150
+ </template>
151
+ `;
152
+ }
153
+ if (isDieField(property)) {
154
+ return expandToNode `
155
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
156
+ <v-chip
157
+ label
158
+ color="primary"
159
+ size="x-small"
160
+ variant="elevated"
161
+ prepend-icon="fa-solid fa-dice"
162
+ class="text-caption"
163
+ >
164
+ {{ getNestedValue(item, '${systemPath}') }}
165
+ </v-chip>
166
+ </template>
167
+ `;
168
+ }
169
+ if (isDiceField(property)) {
170
+ return expandToNode `
171
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
172
+ <v-chip
173
+ label
174
+ color="primary"
175
+ size="x-small"
176
+ variant="elevated"
177
+ prepend-icon="fa-solid fa-dice"
178
+ class="text-caption"
179
+ >
180
+ {{ getNestedValue(item, '${systemPath}').number }}{{ getNestedValue(item, '${systemPath}').die }}
181
+ </v-chip>
182
+ </template>
183
+ `;
184
+ }
185
+ if (isMeasuredTemplateField(property)) {
186
+ return expandToNode `
187
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
188
+ <v-chip
189
+ color="secondary"
190
+ size="x-small"
191
+ variant="elevated"
192
+ prepend-icon="fa-solid fa-ruler-combined"
193
+ class="text-caption"
194
+ label
195
+ >
196
+ {{ getNestedValue(item, '${systemPath}.summary') }}
197
+ </v-chip>
198
+ </template>
199
+ `;
200
+ }
201
+ if (isTimeExp(property) || isDateExp(property) || isDateTimeExp(property)) {
202
+ return expandToNode `
203
+ <template v-if="isColumnVisible('${systemPath}')" v-slot:item.${slotName}="{ item }">
204
+ <span class="text-caption">{{ formatDate(getNestedValue(item, '${systemPath}')) }}</span>
205
+ </template>
206
+ `;
207
+ }
208
+ }
209
+ return undefined;
210
+ }
211
+ let tableDocBody = (_d = (_c = table.document.ref) === null || _c === void 0 ? void 0 : _c.body) !== null && _d !== void 0 ? _d : [];
212
+ const actions = getAllOfType(tableDocBody, isAction, false);
213
+ // Split actions into primary and secondary
214
+ const primaryActions = actions.filter(action => !action.isSecondary);
215
+ const secondaryActions = actions.filter(action => action.isSecondary);
216
+ // Check if any PRIMARY actions have chat cards (exclude secondary actions)
217
+ const hasActionWithChat = primaryActions.some(action => action.method.body.some(expr => isChatCard(expr)));
218
+ const fileNode = expandToNode `
219
+ <script setup>
220
+ import { ref, computed, inject, onMounted, onUnmounted, watch, nextTick } from "vue";
221
+
222
+ const props = defineProps({
223
+ systemPath: String,
224
+ context: Object,
225
+ primaryColor: String,
226
+ secondaryColor: String,
227
+ tertiaryColor: String
228
+ });
229
+
230
+ const document = inject('rawDocument');
231
+ const search = ref('');
232
+ const loading = ref(false);
233
+ const showColumnDialog = ref(false);
234
+
235
+ const columnVisibility = ref({});
236
+ const columnOrder = ref([]);
237
+
238
+ const data = computed(() => {
239
+ // Table fields represent embedded items. Use context.object.items (plain objects
240
+ // from toObject()) to avoid Vue's reactive proxy traversing Foundry's EmbeddedCollection.
241
+ const allItems = props.context?.object?.items ?? [];
242
+ return allItems.filter(i => i.type === '${(_f = (_e = table.document.ref) === null || _e === void 0 ? void 0 : _e.name.toLowerCase()) !== null && _f !== void 0 ? _f : ''}');
243
+ });
244
+
245
+ // Create a map of item _id to item for drag operations
246
+ const itemMap = computed(() => {
247
+ const map = new Map();
248
+ data.value.forEach(item => {
249
+ map.set(item._id, item);
250
+ });
251
+ return map;
252
+ });
253
+
254
+ // Expose itemMap globally for drag handlers to access
255
+ if (!window.isdlItemMaps) window.isdlItemMaps = new Map();
256
+ window.isdlItemMaps.set(document._id, itemMap);
257
+
258
+ const customHeaders = [
259
+ ${joinToNode(table.document.ref.body, p => generateDataTableHeader(table.document, p), { appendNewLineIfNotEmpty: true })}
260
+ ];
261
+
262
+ const orderedHeaders = computed(() => {
263
+ if (columnOrder.value.length === 0) {
264
+ return customHeaders;
265
+ }
266
+
267
+ // Create a map for quick lookup
268
+ const headerMap = new Map();
269
+ customHeaders.forEach(header => {
270
+ headerMap.set(header.key, header);
271
+ });
272
+
273
+ // Build ordered array based on columnOrder, then add any missing headers
274
+ const ordered = [];
275
+ columnOrder.value.forEach(key => {
276
+ if (headerMap.has(key)) {
277
+ ordered.push(headerMap.get(key));
278
+ headerMap.delete(key);
279
+ }
280
+ });
281
+
282
+ // Add any remaining headers that weren't in the order
283
+ headerMap.forEach(header => {
284
+ ordered.push(header);
285
+ });
286
+
287
+ return ordered;
288
+ });
289
+
290
+ const visibleHeaders = computed(() => {
291
+ const baseHeaders = [
292
+ {
293
+ title: "",
294
+ key: 'system.pinned',
295
+ sortable: false,
296
+ width: '40px',
297
+ maxWidth: '40px',
298
+ align: 'center'
299
+ },
300
+ {
301
+ title: game.i18n.localize("Image"),
302
+ key: 'img',
303
+ sortable: false,
304
+ width: '50px',
305
+ maxWidth: '50px'
306
+ },
307
+ {
308
+ title: game.i18n.localize("Name"),
309
+ key: 'name',
310
+ sortable: true,
311
+ minWidth: '120px'
312
+ }
313
+ ];
314
+
315
+ let customHeadersToShow = orderedHeaders.value.filter(header => header && isColumnVisible(header.key));
316
+
317
+ const actionHeaders = [
318
+ {
319
+ title: game.i18n.localize("Actions"),
320
+ key: 'actions',
321
+ sortable: false,
322
+ width: '150px',
323
+ align: 'center'
324
+ }
325
+ ];
326
+
327
+ return [...baseHeaders, ...customHeadersToShow, ...actionHeaders];
328
+ });
329
+
330
+ // Column configuration
331
+ const settingKey = 'documentTableColumns';
332
+
333
+ const defaultVisibileColumns = [
334
+ ${joinToNode(defaultVisibleFields, p => expandToNode `'system.${p.toLowerCase()}'`, { separator: ",", appendNewLineIfNotEmpty: true })}
335
+ ];
336
+
337
+ const initializeColumnSettings = async () => {
338
+ try {
339
+ const savedSettings = game.settings.get("${id}", settingKey) || {};
340
+ const documentTables = savedSettings[document._id] || {};
341
+ const tableSettings = documentTables['${pageName}${table.name}'] || {};
342
+
343
+ // Initialize visibility with defaults if no saved settings
344
+ const defaultVisibility = {};
345
+ customHeaders.forEach(col => {
346
+ if (defaultVisibileColumns.includes(col.key)) {
347
+ defaultVisibility[col.key] = true;
348
+ } else {
349
+ defaultVisibility[col.key] = false;
350
+ }
351
+ if (tableSettings.visibility && tableSettings.visibility[col.key] !== undefined) {
352
+ defaultVisibility[col.key] = tableSettings.visibility[col.key];
353
+ }
354
+ });
355
+
356
+ columnVisibility.value = defaultVisibility;
357
+
358
+ // Initialize order
359
+ if (tableSettings.order && Array.isArray(tableSettings.order)) {
360
+ columnOrder.value = [...tableSettings.order];
361
+ } else {
362
+ // Default order is the order they appear in customHeaders
363
+ columnOrder.value = customHeaders.map(h => h.key);
364
+ }
365
+ } catch (error) {
366
+ console.warn("Failed to load column settings, using defaults:", error);
367
+ // Use defaults if setting doesn't exist yet
368
+ const defaultVisibility = {};
369
+ customHeaders.forEach(col => {
370
+ if (defaultVisibileColumns.includes(col.key)) {
371
+ defaultVisibility[col.key] = true;
372
+ } else {
373
+ defaultVisibility[col.key] = false;
374
+ }
375
+ });
376
+ columnVisibility.value = defaultVisibility;
377
+ columnOrder.value = customHeaders.map(h => h.key);
378
+ }
379
+ };
380
+
381
+ const saveColumnSettings = async () => {
382
+ try {
383
+ const savedSettings = game.settings.get("${id}", settingKey) || {};
384
+ const documentTables = savedSettings[document._id] || {};
385
+ savedSettings[document._id] = documentTables;
386
+
387
+ const tableSettings = documentTables['${pageName}${table.name}'] || {};
388
+
389
+ // Save visibility
390
+ const visibilitySettings = {};
391
+ customHeaders.forEach(col => {
392
+ visibilitySettings[col.key] = columnVisibility.value[col.key];
393
+ });
394
+
395
+ tableSettings.visibility = visibilitySettings;
396
+ tableSettings.order = [...columnOrder.value];
397
+
398
+ savedSettings[document._id]['${pageName}${table.name}'] = tableSettings;
399
+ await game.settings.set("${id}", settingKey, savedSettings);
400
+ } catch (error) {
401
+ console.error("Failed to save column settings:", error);
402
+ ui.notifications.error("Failed to save column settings");
403
+ }
404
+ };
405
+
406
+ const isColumnVisible = (columnKey) => {
407
+ return columnVisibility.value[columnKey] !== false;
408
+ };
409
+
410
+ const toggleColumn = async (columnKey) => {
411
+ columnVisibility.value[columnKey] = !columnVisibility.value[columnKey];
412
+ await saveColumnSettings();
413
+ };
414
+
415
+ const resetColumns = async () => {
416
+ const defaultVisibility = {};
417
+ customHeaders.forEach(col => {
418
+ if (defaultVisibileColumns.includes(col.key)) {
419
+ defaultVisibility[col.key] = true;
420
+ } else {
421
+ defaultVisibility[col.key] = false;
422
+ }
423
+ });
424
+ columnVisibility.value = defaultVisibility;
425
+ columnOrder.value = customHeaders.map(h => h.key);
426
+ await saveColumnSettings();
427
+ };
428
+
429
+ const moveColumn = async (fromIndex, toIndex) => {
430
+ const newOrder = [...columnOrder.value];
431
+ const [movedItem] = newOrder.splice(fromIndex, 1);
432
+ newOrder.splice(toIndex, 0, movedItem);
433
+ columnOrder.value = newOrder;
434
+ await saveColumnSettings();
435
+ };
436
+
437
+ const onColumnDragStart = (event, index) => {
438
+ event.dataTransfer.effectAllowed = 'move';
439
+ event.dataTransfer.setData('text/plain', index.toString());
440
+ };
441
+
442
+ const onColumnDragOver = (event) => {
443
+ event.preventDefault();
444
+ event.dataTransfer.dropEffect = 'move';
445
+ };
446
+
447
+ const onColumnDrop = async (event, toIndex) => {
448
+ event.preventDefault();
449
+ const fromIndex = parseInt(event.dataTransfer.getData('text/plain'));
450
+ if (fromIndex !== toIndex) {
451
+ await moveColumn(fromIndex, toIndex);
452
+ }
453
+ };
454
+
455
+ onMounted(() => {
456
+ initializeColumnSettings();
457
+ });
458
+
459
+ const humanize = (str) => {
460
+ if (!str) return "";
461
+ let humanized = str.replace(/_/g, " ");
462
+ humanized = humanized.replace("system.", "").replaceAll(".", " ");
463
+ humanized = humanized.charAt(0).toUpperCase() + humanized.slice(1);
464
+ return humanized;
465
+ };
466
+
467
+ const getNestedValue = (obj, path) => {
468
+ const data = foundry.utils.getProperty(obj, path);
469
+ return data;
470
+ };
471
+
472
+ const getResourceColor = (resource) => {
473
+ if (!resource || !resource.max) return 'grey';
474
+ const percentage = (resource.value / resource.max) * 100;
475
+ if (percentage > 75) return 'green';
476
+ if (percentage > 50) return 'orange';
477
+ if (percentage > 25) return 'red';
478
+ return 'red-darken-2';
479
+ };
480
+
481
+ const formatDate = (dateValue) => {
482
+ if (!dateValue) return "";
483
+ return new Date(dateValue).toLocaleDateString();
484
+ };
485
+
486
+ const editItem = (item) => {
487
+ const foundryItem = document.items.get(item._id);
488
+ foundryItem.sheet.render(true);
489
+ };
490
+
491
+ const sendItemToChat = async (item) => {
492
+ const foundryItem = document.items.get(item._id);
493
+ const chatDescription = foundryItem.description ?? foundryItem.system.description;
494
+ const content = await renderTemplate("systems/${id}/system/templates/chat/standard-card.hbs", {
495
+ cssClass: "${id}",
496
+ document: foundryItem,
497
+ hasEffects: foundryItem.effects?.size > 0,
498
+ description: chatDescription,
499
+ hasDescription: chatDescription != ""
500
+ });
501
+ ChatMessage.create({
502
+ content: content,
503
+ speaker: ChatMessage.getSpeaker(),
504
+ style: CONST.CHAT_MESSAGE_STYLES.IC
505
+ });
506
+ };
507
+
508
+ const deleteItem = async (item) => {
509
+ const foundryItem = document.items.get(item._id);
510
+ const shouldDelete = await Dialog.confirm({
511
+ title: "Delete Confirmation",
512
+ content: \`<p>Are you sure you would like to delete the "\${foundryItem.name}" Item?</p>\`,
513
+ defaultYes: false
514
+ });
515
+ if (shouldDelete) foundryItem.delete();
516
+ };
517
+
518
+ const duplicateItem = async (item) => {
519
+ loading.value = true;
520
+ try {
521
+ const foundryItem = document.items.get(item._id);
522
+ const itemData = foundryItem.toObject();
523
+ itemData.name = "Copy of " + itemData.name;
524
+ delete itemData._id;
525
+
526
+ const duplicatedItems = await Item.createDocuments([itemData], {parent: document});
527
+ if (duplicatedItems && duplicatedItems[0]) {
528
+ ui.notifications.info(\`Duplicated "\${foundryItem.name}"\`);
529
+ }
530
+ } catch (error) {
531
+ console.error("Error duplicating item:", error);
532
+ ui.notifications.error("Failed to duplicate item");
533
+ } finally {
534
+ loading.value = false;
535
+ }
536
+ };
537
+
538
+ const customItemAction = async (item, actionName) => {
539
+ const foundryItem = document.items.get(item._id);
540
+ const event = { currentTarget: { dataset: { action: actionName } } };
541
+ foundryItem.sheet._onAction(event);
542
+ };
543
+
544
+ const togglePin = async (item) => {
545
+ const foundryItem = document.items.get(item._id);
546
+ await foundryItem.update({"system.pinned": !foundryItem.system.pinned});
547
+ };
548
+
549
+ const addNewItem = async () => {
550
+ loading.value = true;
551
+ try {
552
+ const type = '${(_g = table.document.ref) === null || _g === void 0 ? void 0 : _g.name.toLowerCase()}';
553
+ const items = await Item.createDocuments([{
554
+ type: type,
555
+ name: "New " + type
556
+ }], {parent: document});
557
+
558
+ if (items && items[0]) {
559
+ items[0].sheet.render(true);
560
+ }
561
+ } catch (error) {
562
+ console.error("Error creating item:", error);
563
+ ui.notifications.error("Failed to create new item");
564
+ } finally {
565
+ loading.value = false;
566
+ }
567
+ };
568
+
569
+ const truncate = (text, maxLength) => {
570
+ if (!text) return '';
571
+ if (text.length > maxLength) {
572
+ return text.substring(0, maxLength) + '...';
573
+ }
574
+ return text;
575
+ }
576
+
577
+ const bindDragDrop = () => {
578
+ try {
579
+ if (document.sheet.element) {
580
+ document.sheet.dragDrop.forEach((d) => d.bind(document.sheet.element));
581
+ }
582
+ } catch (e) {
583
+ console.error(e);
584
+ }
585
+ };
586
+
587
+ const getExtendedChoiceTooltip = (item, systemPath) => {
588
+ const tooltipParts = [];
589
+ const coreKeys = ['value', 'color', 'icon'];
590
+ const base = getNestedValue(item, systemPath);
591
+ for (const key of Object.keys(base)) {
592
+ if (!coreKeys.includes(key)) {
593
+ const value = base[key];
594
+ if (value !== undefined) {
595
+ tooltipParts.push(\`\${key}: \${value}\`);
596
+ }
597
+ }
598
+ }
599
+ return tooltipParts.join('<br>');
600
+ };
601
+
602
+ // Get item props for row attributes (for drag-drop)
603
+ const getItemProps = (item) => {
604
+ // Construct UUID for embedded items: parent.uuid + Item.itemId
605
+ const itemUuid = item.uuid || \`\${document.uuid}.Item.\${item._id}\`;
606
+ return {
607
+ 'data-item-id': item._id,
608
+ 'data-document-id': document._id,
609
+ 'data-uuid': itemUuid
610
+ };
611
+ };
612
+
613
+ // Function to add data attributes to table rows
614
+ const updateTableRowAttributes = () => {
615
+ const tableEl = window.document.querySelector('.custom-datatable table');
616
+ if (!tableEl) {
617
+ console.warn('Table not found for attribute update');
618
+ return;
619
+ }
620
+
621
+ const rows = tableEl.querySelectorAll('tbody tr');
622
+ const items = data.value;
623
+
624
+ rows.forEach((row, index) => {
625
+ if (index < items.length) {
626
+ const item = items[index];
627
+ const itemUuid = item.uuid || \`\${document.uuid}.Item.\${item._id}\`;
628
+ row.setAttribute('data-item-id', item._id);
629
+ row.setAttribute('data-document-id', document._id);
630
+ row.setAttribute('data-uuid', itemUuid);
631
+ }
632
+ });
633
+ };
634
+
635
+ // Watch for data changes and update attributes
636
+ watch(data, () => {
637
+ nextTick(updateTableRowAttributes);
638
+ }, { immediate: false });
639
+
640
+ // Bind drag drop and update attributes after component mount
641
+ onMounted(() => {
642
+ setTimeout(() => {
643
+ updateTableRowAttributes();
644
+ bindDragDrop();
645
+ }, 200);
646
+ });
647
+
648
+ // Clean up item map on unmount
649
+ onUnmounted(() => {
650
+ if (window.isdlItemMaps) {
651
+ window.isdlItemMaps.delete(document._id);
652
+ }
653
+ });
654
+ </script>
655
+
656
+ <template>
657
+ <v-card flat class="isdl-datatable">
658
+ <v-card-title class="d-flex align-center pe-1" style="height: 40px;">
659
+ <v-icon icon="fa-solid ${iconParam ? iconParam.value : 'fa-table'}" size="small" />
660
+ &nbsp; {{ game.i18n.localize("${document.name}.${table.name}") }}
661
+ <v-spacer></v-spacer>
662
+ <v-text-field
663
+ v-model="search"
664
+ density="compact"
665
+ label="Search"
666
+ prepend-inner-icon="fa-solid fa-magnify"
667
+ variant="outlined"
668
+ flat
669
+ hide-details
670
+ single-line
671
+ clearable
672
+ style="margin: 0; margin-right: 8px;"
673
+ ></v-text-field>
674
+ <v-btn
675
+ icon="fa-solid fa-columns"
676
+ size="small"
677
+ variant="text"
678
+ @click="showColumnDialog = true"
679
+ style="margin-right: 8px;"
680
+ >
681
+ <v-icon>fa-solid fa-columns</v-icon>
682
+ <v-tooltip activator="parent" location="top">Configure Columns</v-tooltip>
683
+ </v-btn>
684
+ <v-btn
685
+ :color="primaryColor || 'primary'"
686
+ prepend-icon="fa-solid fa-plus"
687
+ rounded="0"
688
+ size="small"
689
+ :loading="loading"
690
+ @click="addNewItem"
691
+ style="max-width: 80px; height: 38px;"
692
+ >
693
+ {{ game.i18n.localize("Add") }}
694
+ </v-btn>
695
+ </v-card-title>
696
+ <v-divider></v-divider>
697
+
698
+ <v-data-table
699
+ v-model:search="search"
700
+ :headers="visibleHeaders"
701
+ :items="data"
702
+ :search="search"
703
+ hover
704
+ density="compact"
705
+ hide-default-footer
706
+ items-per-page=-1
707
+ style="background: none;"
708
+ class="custom-datatable"
709
+ :sort-by="[{ key: 'system.pinned', order: 'desc' }, { key: 'name', order: 'asc' }]"
710
+ :item-props="getItemProps"
711
+ >
712
+ <!-- Image slot -->
713
+ <template v-slot:item.img="{ item }">
714
+ <v-avatar size="40" rounded="0">
715
+ <v-img :src="item.img" :alt="item.name" cover></v-img>
716
+ </v-avatar>
717
+ </template>
718
+
719
+ <!-- Name slot with description tooltip -->
720
+ <template v-slot:item.name="{ item }">
721
+ <div class="d-flex align-center" :data-tooltip="item.system.description">
722
+ <div class="font-weight-medium text-truncate" style="min-width: 120px; max-width: 200px;">{{ item.name }}</div>
723
+ </div>
724
+ </template>
725
+
726
+ <!-- Pinned slot -->
727
+ <template v-slot:item.system.pinned="{ item }">
728
+ <div class="d-flex justify-center">
729
+ <v-btn
730
+ icon
731
+ size="small"
732
+ variant="text"
733
+ @click="togglePin(item)"
734
+ :data-tooltip="item.system.pinned ? 'Unpin' : 'Pin'"
735
+ >
736
+ <v-icon
737
+ :icon="item.system.pinned ? 'fa-solid fa-thumbtack' : 'fa-regular fa-thumbtack'"
738
+ :color="item.system.pinned ? primaryColor : 'grey'"
739
+ size="small"
740
+ ></v-icon>
741
+ </v-btn>
742
+ </div>
743
+ </template>
744
+
745
+ <!-- Custom field slots -->
746
+ ${joinToNode(table.document.ref.body, p => generateSlotTemplate(table.document, p), { appendNewLineIfNotEmpty: true })}
747
+
748
+ <!-- Actions slot -->
749
+ <template v-slot:item.actions="{ item }">
750
+ <div class="d-flex align-center justify-center ga-1">
751
+ ${joinToNode(primaryActions, generateActionButton, { appendNewLineIfNotEmpty: true })}
752
+ <v-tooltip text="Edit">
753
+ <template v-slot:activator="{ props }">
754
+ <v-btn
755
+ v-bind="props"
756
+ icon="fa-solid fa-edit"
757
+ size="x-small"
758
+ variant="text"
759
+ @click="editItem(item)"
760
+ ></v-btn>
761
+ </template>
762
+ </v-tooltip>
763
+ ${!hasActionWithChat ? expandToNode `
764
+ <v-tooltip text="Send to Chat">
765
+ <template v-slot:activator="{ props }">
766
+ <v-btn
767
+ v-bind="props"
768
+ icon="fa-solid fa-message"
769
+ size="x-small"
770
+ variant="text"
771
+ @click="sendItemToChat(item)"
772
+ ></v-btn>
773
+ </template>
774
+ </v-tooltip>
775
+ ` : ''}
776
+ <v-menu>
777
+ <template v-slot:activator="{ props }">
778
+ <v-btn
779
+ v-bind="props"
780
+ icon="fa-solid fa-ellipsis-vertical"
781
+ size="x-small"
782
+ variant="text"
783
+ ></v-btn>
784
+ </template>
785
+ <v-list density="compact" class="pa-0" min-width="120">
786
+ ${hasActionWithChat ? expandToNode `
787
+ <v-list-item
788
+ @click="sendItemToChat(item)"
789
+ title="Send to Chat"
790
+ min-height="32"
791
+ >
792
+ <template v-slot:prepend>
793
+ <v-icon icon="fa-solid fa-message" size="15"></v-icon>
794
+ </template>
795
+ </v-list-item>
796
+ ` : ''}
797
+ ${joinToNode(secondaryActions, generateSecondaryActionMenuItem, { appendNewLineIfNotEmpty: true })}
798
+ <v-list-item
799
+ @click="duplicateItem(item)"
800
+ title="Duplicate"
801
+ min-height="32"
802
+ >
803
+ <template v-slot:prepend>
804
+ <v-icon icon="fa-solid fa-copy" size="15"></v-icon>
805
+ </template>
806
+ </v-list-item>
807
+ <v-list-item
808
+ @click="deleteItem(item)"
809
+ title="Delete"
810
+ class="text-error"
811
+ min-height="32"
812
+ >
813
+ <template v-slot:prepend>
814
+ <v-icon icon="fa-solid fa-trash" size="15"></v-icon>
815
+ </template>
816
+ </v-list-item>
817
+ </v-list>
818
+ </v-menu>
819
+ </div>
820
+ </template>
821
+
822
+ <!-- No data slot -->
823
+ <template v-slot:no-data>
824
+ <div class="text-center pa-4">
825
+ <v-icon size="48" color="grey-lighten-1">fa-solid fa-inbox</v-icon>
826
+ <div class="text-h6 mt-2">No items found</div>
827
+ <div class="text-body-2 text-medium-emphasis">
828
+ Add your first {{ game.i18n.localize("${(_h = table.document.ref) === null || _h === void 0 ? void 0 : _h.name}").toLowerCase() }} to get started
829
+ </div>
830
+ </div>
831
+ </template>
832
+ </v-data-table>
833
+ </v-card>
834
+
835
+ <!-- Column Configuration Dialog -->
836
+ <v-dialog v-model="showColumnDialog" max-width="600px">
837
+ <v-card>
838
+ <v-card-title class="d-flex align-center">
839
+ <v-icon class="me-2">fa-solid fa-columns</v-icon>
840
+ Configure Columns
841
+ </v-card-title>
842
+ <v-divider></v-divider>
843
+ <v-card-text>
844
+ <div class="text-body-2 mb-4 text-medium-emphasis">
845
+ Drag to reorder columns, check/uncheck to show/hide columns
846
+ </div>
847
+ <v-list density="compact" class="column-config-list">
848
+ <div
849
+ v-for="(columnKey, index) in columnOrder"
850
+ :key="columnKey"
851
+ class="column-config-item"
852
+ draggable="true"
853
+ @dragstart="onColumnDragStart($event, index)"
854
+ @dragover="onColumnDragOver"
855
+ @drop="onColumnDrop($event, index)"
856
+ >
857
+ <v-list-item class="px-2">
858
+ <template v-slot:prepend>
859
+ <v-icon
860
+ icon="fa-solid fa-grip-vertical"
861
+ class="drag-handle me-2"
862
+ size="small"
863
+ style="cursor: grab;"
864
+ ></v-icon>
865
+ <v-checkbox-btn
866
+ :model-value="columnVisibility[columnKey]"
867
+ @update:model-value="toggleColumn(columnKey)"
868
+ class="me-2"
869
+ ></v-checkbox-btn>
870
+ </template>
871
+ <v-list-item-title>
872
+ {{ customHeaders.find(h => h.key === columnKey)?.title || columnKey }}
873
+ </v-list-item-title>
874
+ </v-list-item>
875
+ </div>
876
+ </v-list>
877
+ </v-card-text>
878
+ <v-card-actions class="flexrow">
879
+ <v-btn
880
+ variant="elevated"
881
+ @click="showColumnDialog = false"
882
+ :color="primaryColor"
883
+ >
884
+ Close
885
+ </v-btn>
886
+ <v-btn
887
+ variant="elevated"
888
+ @click="resetColumns"
889
+ prepend-icon="fa-solid fa-undo"
890
+ :color="secondaryColor"
891
+ >
892
+ Reset to Default
893
+ </v-btn>
894
+ </v-card-actions>
895
+ </v-card>
896
+ </v-dialog>
897
+ </template>
898
+ `;
899
+ fs.writeFileSync(generatedFilePath, toString(fileNode));
900
+ function generateActionButton(action) {
901
+ var _a, _b, _c, _d;
902
+ const standardParams = action.params;
903
+ const icon = (_b = (_a = standardParams.find(x => isIconParam(x))) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "fa-solid fa-bolt";
904
+ const color = (_d = (_c = standardParams.find(x => isColorParam(x))) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : "primary";
905
+ const parentDocument = AstUtils.getContainerOfType(action, isDocument);
906
+ return expandToNode `
907
+ <v-tooltip :text="game.i18n.localize('${parentDocument === null || parentDocument === void 0 ? void 0 : parentDocument.name}.${action.name}')">
908
+ <template v-slot:activator="{ props }">
909
+ <v-btn
910
+ v-bind="props"
911
+ icon="${icon}"
912
+ size="x-small"
913
+ variant="text"
914
+ color="${color}"
915
+ @click="customItemAction(item, '${action.name.toLowerCase()}')"
916
+ ></v-btn>
917
+ </template>
918
+ </v-tooltip>
919
+ `;
920
+ }
921
+ function generateSecondaryActionMenuItem(action) {
922
+ var _a, _b;
923
+ const standardParams = action.params;
924
+ const icon = (_b = (_a = standardParams.find(x => isIconParam(x))) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "fa-solid fa-bolt";
925
+ const parentDocument = AstUtils.getContainerOfType(action, isDocument);
926
+ return expandToNode `
927
+ <v-list-item
928
+ @click="customItemAction(item, '${action.name.toLowerCase()}')"
929
+ :title="game.i18n.localize('${parentDocument === null || parentDocument === void 0 ? void 0 : parentDocument.name}.${action.name}')"
930
+ min-height="32"
931
+ >
932
+ <template v-slot:prepend>
933
+ <v-icon icon="${icon}" size="15"></v-icon>
934
+ </template>
935
+ </v-list-item>
936
+ `;
937
+ }
938
+ }
939
+ //# sourceMappingURL=vue-datatable2-component-generator.js.map