intelligent-system-design-language 0.3.21 → 0.3.23
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.
- package/.claude/agents/langium-language-designer.md +38 -38
- package/.claude/agents/typescript-vscode-expert.md +29 -29
- package/.claude/agents/ui-ux-designer.md +36 -36
- package/.claude/settings.local.json +33 -33
- package/.idea/inspectionProfiles/Project_Default.xml +6 -6
- package/.idea/isdl.iml +13 -13
- package/.idea/modules.xml +8 -8
- package/.idea/vcs.xml +6 -6
- package/.idea/watcherTasks.xml +3 -3
- package/.vscodeignore +18 -18
- package/LICENSE +673 -673
- package/README.md +86 -86
- package/bin/cli.js +4 -4
- package/bin/lsp.js +8 -8
- package/out/_backgrounds.scss +91 -91
- package/out/_handlebars.scss +497 -497
- package/out/_isdlStyles.scss +1444 -1381
- package/out/_vuetifyOverrides.scss +425 -425
- package/out/_vuetifyStyles.scss +31957 -31957
- package/out/cli/components/_backgrounds.scss +91 -91
- package/out/cli/components/_handlebars.scss +497 -497
- package/out/cli/components/_isdlStyles.scss +1444 -1381
- package/out/cli/components/_vuetifyOverrides.scss +425 -425
- package/out/cli/components/_vuetifyStyles.scss +31957 -31957
- package/out/cli/components/active-effect-sheet-generator.js +453 -453
- package/out/cli/components/chat-card-generator.js +654 -651
- package/out/cli/components/chat-card-generator.js.map +1 -1
- package/out/cli/components/css-generator.js +4 -4
- package/out/cli/components/damage-roll-generator.js +160 -160
- package/out/cli/components/datamodel-generator.js +264 -257
- package/out/cli/components/datamodel-generator.js.map +1 -1
- package/out/cli/components/derived-data-generator.js +923 -923
- package/out/cli/components/hotbar-drop-hook-generator.js +82 -82
- package/out/cli/components/init-hook-generator.js +495 -495
- package/out/cli/components/language-generator.js +1 -1
- package/out/cli/components/language-generator.js.map +1 -1
- package/out/cli/components/measured-template-preview.js +221 -221
- package/out/cli/components/method-generator.js +979 -887
- package/out/cli/components/method-generator.js.map +1 -1
- package/out/cli/components/ready-hook-generator.js +404 -404
- package/out/cli/components/token-generator.js +116 -116
- package/out/cli/components/vue/base-components/vue-attribute.js +138 -138
- package/out/cli/components/vue/base-components/vue-boolean.js +64 -64
- package/out/cli/components/vue/base-components/vue-calculator.js +93 -93
- package/out/cli/components/vue/base-components/vue-damage-application.js +356 -356
- package/out/cli/components/vue/base-components/vue-damage-bonuses.js +165 -165
- package/out/cli/components/vue/base-components/vue-damage-resistances.js +196 -196
- package/out/cli/components/vue/base-components/vue-damage-track.js +121 -121
- package/out/cli/components/vue/base-components/vue-date-time.js +42 -42
- package/out/cli/components/vue/base-components/vue-dice.js +98 -98
- package/out/cli/components/vue/base-components/vue-die.js +73 -73
- package/out/cli/components/vue/base-components/vue-document-choice.js +149 -149
- package/out/cli/components/vue/base-components/vue-document-choices.js +179 -179
- package/out/cli/components/vue/base-components/vue-document-link.js +60 -60
- package/out/cli/components/vue/base-components/vue-extended-choice.js +88 -88
- package/out/cli/components/vue/base-components/vue-inventory.js +519 -519
- package/out/cli/components/vue/base-components/vue-macro-choice.js +138 -138
- package/out/cli/components/vue/base-components/vue-measured-template.js +530 -530
- package/out/cli/components/vue/base-components/vue-money.js +483 -483
- package/out/cli/components/vue/base-components/vue-number.js +174 -174
- package/out/cli/components/vue/base-components/vue-paperdoll.js +43 -43
- package/out/cli/components/vue/base-components/vue-parent-property-reference.js +76 -76
- package/out/cli/components/vue/base-components/vue-prosemirror.js +18 -18
- package/out/cli/components/vue/base-components/vue-resource.js +136 -136
- package/out/cli/components/vue/base-components/vue-roll-visualizer.js +286 -109
- package/out/cli/components/vue/base-components/vue-roll-visualizer.js.map +1 -1
- package/out/cli/components/vue/base-components/vue-self-property-reference.js +62 -62
- package/out/cli/components/vue/base-components/vue-string-choice.js +98 -98
- package/out/cli/components/vue/base-components/vue-string-choices.js +203 -203
- package/out/cli/components/vue/base-components/vue-string.js +60 -60
- package/out/cli/components/vue/base-components/vue-text-field.js +53 -53
- package/out/cli/components/vue/base-components/vue-tracker.js +431 -431
- package/out/cli/components/vue/vue-action-component-generator.js +64 -64
- package/out/cli/components/vue/vue-active-effect-sheet-generator.js +856 -856
- package/out/cli/components/vue/vue-datatable-sheet-class-generator.js +292 -292
- package/out/cli/components/vue/vue-datatable2-component-generator.js +824 -824
- package/out/cli/components/vue/vue-document-creation-app.js +121 -121
- package/out/cli/components/vue/vue-document-creation-sheet.js +94 -94
- package/out/cli/components/vue/vue-generator.js +40 -40
- package/out/cli/components/vue/vue-mixin.js +296 -296
- package/out/cli/components/vue/vue-pinned-datatable-component-generator.js +260 -260
- package/out/cli/components/vue/vue-prompt-generator.js +91 -76
- package/out/cli/components/vue/vue-prompt-generator.js.map +1 -1
- package/out/cli/components/vue/vue-prompt-sheet-class-generator.js +317 -317
- package/out/cli/components/vue/vue-sheet-application-generator.js +1177 -1167
- package/out/cli/components/vue/vue-sheet-application-generator.js.map +1 -1
- package/out/cli/components/vue/vue-sheet-class-generator.js +510 -510
- package/out/cli/generator.js +438 -433
- package/out/cli/generator.js.map +1 -1
- package/out/extension/github/githubAuthProvider.js +71 -29
- package/out/extension/github/githubAuthProvider.js.map +1 -1
- package/out/extension/github/githubGistManager.js +4 -3
- package/out/extension/github/githubGistManager.js.map +1 -1
- package/out/extension/github/githubManager.js +40 -38
- package/out/extension/github/githubManager.js.map +1 -1
- package/out/extension/github/githubQuickActions.js +120 -120
- package/out/extension/github/system-workflow.yml +47 -47
- package/out/extension/main.cjs +909 -532
- package/out/extension/main.cjs.map +3 -3
- package/out/extension/package.json +419 -419
- package/out/language/generated/ast.js +51 -2
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.js +14240 -13991
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/intelligent-system-design-language-validator.js +32 -2
- package/out/language/intelligent-system-design-language-validator.js.map +1 -1
- package/out/language/isdl-scope-provider.js +14 -1
- package/out/language/isdl-scope-provider.js.map +1 -1
- package/out/language/main.cjs +913 -569
- package/out/language/main.cjs.map +3 -3
- package/out/package.json +419 -419
- package/out/progressbar.min.js +6 -6
- package/out/styles.scss +762 -747
- package/out/test/validating/diagnostics.test.js +40 -0
- package/out/test/validating/diagnostics.test.js.map +1 -1
- package/package.json +419 -419
|
@@ -7,115 +7,292 @@ export default function generateRollVisualizerComponent(destination) {
|
|
|
7
7
|
if (!fs.existsSync(generatedFileDir)) {
|
|
8
8
|
fs.mkdirSync(generatedFileDir, { recursive: true });
|
|
9
9
|
}
|
|
10
|
-
const fileNode = expandToNode `
|
|
11
|
-
<script
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
10
|
+
const fileNode = expandToNode `
|
|
11
|
+
<script>
|
|
12
|
+
// Module-scoped cache (shared across all roll-visualizer instances for the page
|
|
13
|
+
// session, and surviving sheet re-renders/re-opens). Keyed by the RESOLVED formula
|
|
14
|
+
// (after @refs are substituted), so the same dice math -- especially the expensive
|
|
15
|
+
// simulation path -- is only computed once. Cleared on page reload.
|
|
16
|
+
const __rollVisualizerCache = new Map();
|
|
17
|
+
</script>
|
|
18
|
+
<script setup>
|
|
19
|
+
import { ref, watch, computed, inject } from "vue";
|
|
20
|
+
|
|
21
|
+
const props = defineProps({
|
|
22
|
+
label: String,
|
|
23
|
+
icon: String,
|
|
24
|
+
color: String,
|
|
25
|
+
systemPath: String,
|
|
26
|
+
context: Object,
|
|
27
|
+
// The Foundry roll formula (may contain @refs), compiled from the field's value: expression.
|
|
28
|
+
formula: { type: String, default: "" },
|
|
29
|
+
// Data object resolving the @refs, bound from the live (reactive) document/prompt data.
|
|
30
|
+
rollData: { type: Object, default: () => ({}) }
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ----- Distribution engine ---------------------------------------------------
|
|
34
|
+
// For purely additive dice formulas (dice + constants, +/- only, no dice
|
|
35
|
+
// modifiers) we compute the EXACT probability distribution by convolution.
|
|
36
|
+
// Anything more exotic (keep-highest/lowest, exploding, rerolls, multiplied
|
|
37
|
+
// dice, fate dice, pools, functions) falls back to Monte Carlo simulation.
|
|
38
|
+
|
|
39
|
+
// A distribution is a Map<outcomeValue, probability>.
|
|
40
|
+
const dieDist = (faces) => {
|
|
41
|
+
const m = new Map();
|
|
42
|
+
for (let f = 1; f <= faces; f++) m.set(f, 1 / faces);
|
|
43
|
+
return m;
|
|
44
|
+
};
|
|
45
|
+
const convolve = (a, b) => {
|
|
46
|
+
const out = new Map();
|
|
47
|
+
for (const [va, pa] of a) {
|
|
48
|
+
for (const [vb, pb] of b) {
|
|
49
|
+
const v = va + vb;
|
|
50
|
+
out.set(v, (out.get(v) || 0) + pa * pb);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
};
|
|
55
|
+
const negate = (a) => {
|
|
56
|
+
const m = new Map();
|
|
57
|
+
for (const [v, p] of a) m.set(-v, p);
|
|
58
|
+
return m;
|
|
59
|
+
};
|
|
60
|
+
const shift = (a, k) => {
|
|
61
|
+
const m = new Map();
|
|
62
|
+
for (const [v, p] of a) m.set(v + k, p);
|
|
63
|
+
return m;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Classify a Foundry roll term. Foundry does not minify these class names in
|
|
67
|
+
// either v12 or v13, so constructor.name is a reliable signal.
|
|
68
|
+
const classify = (term) => {
|
|
69
|
+
const n = term?.constructor?.name;
|
|
70
|
+
if (n === "Die") return "die";
|
|
71
|
+
if (n === "NumericTerm") return "num";
|
|
72
|
+
if (n === "OperatorTerm") return "op";
|
|
73
|
+
return "other";
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Decide whether a parsed roll can be solved exactly. Guard the convolution
|
|
77
|
+
// against pathological sizes (huge dice pools) by falling back to simulation.
|
|
78
|
+
const MAX_BUCKETS = 5000;
|
|
79
|
+
const canConvolve = (terms) => {
|
|
80
|
+
let minTotal = 0, maxTotal = 0;
|
|
81
|
+
for (const term of terms) {
|
|
82
|
+
const kind = classify(term);
|
|
83
|
+
if (kind === "op") {
|
|
84
|
+
if (term.operator !== "+" && term.operator !== "-") return false;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (kind === "die") {
|
|
88
|
+
if (Array.isArray(term.modifiers) && term.modifiers.length > 0) return false;
|
|
89
|
+
const number = Number(term.number);
|
|
90
|
+
const faces = Number(term.faces);
|
|
91
|
+
if (!Number.isInteger(number) || !Number.isInteger(faces) || faces < 1 || number < 0) return false;
|
|
92
|
+
minTotal += number;
|
|
93
|
+
maxTotal += number * faces;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (kind === "num") {
|
|
97
|
+
if (!Number.isFinite(Number(term.number))) return false;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
return false; // unknown term type
|
|
101
|
+
}
|
|
102
|
+
return (maxTotal - minTotal) <= MAX_BUCKETS;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Build the exact PMF for an additive term list.
|
|
106
|
+
const convolveTerms = (terms) => {
|
|
107
|
+
let acc = new Map([[0, 1]]);
|
|
108
|
+
let sign = 1;
|
|
109
|
+
for (const term of terms) {
|
|
110
|
+
const kind = classify(term);
|
|
111
|
+
if (kind === "op") {
|
|
112
|
+
sign = term.operator === "-" ? -1 : 1;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (kind === "die") {
|
|
116
|
+
let dist = new Map([[0, 1]]);
|
|
117
|
+
for (let i = 0; i < Number(term.number); i++) dist = convolve(dist, dieDist(Number(term.faces)));
|
|
118
|
+
if (sign < 0) dist = negate(dist);
|
|
119
|
+
acc = convolve(acc, dist);
|
|
120
|
+
}
|
|
121
|
+
else if (kind === "num") {
|
|
122
|
+
acc = shift(acc, sign * Number(term.number));
|
|
123
|
+
}
|
|
124
|
+
sign = 1;
|
|
125
|
+
}
|
|
126
|
+
return acc;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Derive the display payload (average, min, max, chart series) from a PMF.
|
|
130
|
+
const summarize = (dist, approximate) => {
|
|
131
|
+
const entries = [...dist.entries()].sort((a, b) => a[0] - b[0]);
|
|
132
|
+
let average = 0, min = Infinity, max = -Infinity;
|
|
133
|
+
for (const [v, p] of entries) {
|
|
134
|
+
average += v * p;
|
|
135
|
+
if (v < min) min = v;
|
|
136
|
+
if (v > max) max = v;
|
|
137
|
+
}
|
|
138
|
+
const outcomeValues = entries.map(([v]) => v);
|
|
139
|
+
const values = entries.map(([, p]) => +(p * 100).toFixed(2));
|
|
140
|
+
// Thin the x-axis labels so they don't cluster/overlap: pick a "nice" step
|
|
141
|
+
// (1, 2, 5, 10, ...) targeting ~8 labels, and only label outcomes that land on
|
|
142
|
+
// a multiple of it -- so the axis reads in round numbers (5, 10, 15, 20 ...).
|
|
143
|
+
const lo = outcomeValues.length ? outcomeValues[0] : 0;
|
|
144
|
+
const hi = outcomeValues.length ? outcomeValues[outcomeValues.length - 1] : 0;
|
|
145
|
+
const span = Math.max(1, hi - lo);
|
|
146
|
+
const rawStep = span / 8;
|
|
147
|
+
const pow = Math.pow(10, Math.floor(Math.log10(rawStep)));
|
|
148
|
+
const norm = rawStep / pow;
|
|
149
|
+
const niceStep = (norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 5 ? 5 : 10) * pow;
|
|
150
|
+
const step = Math.max(1, Math.round(niceStep));
|
|
151
|
+
return {
|
|
152
|
+
average: +average.toFixed(2),
|
|
153
|
+
min: entries.length ? min : 0,
|
|
154
|
+
max: entries.length ? max : 0,
|
|
155
|
+
labels: outcomeValues,
|
|
156
|
+
values,
|
|
157
|
+
step,
|
|
158
|
+
approximate,
|
|
159
|
+
hasData: entries.length > 0
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// ----- Reactive computation --------------------------------------------------
|
|
164
|
+
|
|
165
|
+
const result = ref({ average: 0, min: 0, max: 0, labels: [], values: [], step: 1, approximate: false, hasData: false });
|
|
166
|
+
const iterations = ref(0);
|
|
167
|
+
let runToken = 0;
|
|
168
|
+
|
|
169
|
+
// Monte Carlo fallback. Roll.simulate builds a full Roll per sample (~0.2ms each),
|
|
170
|
+
// so a large batch blocks the main thread for seconds and freezes the sheet on
|
|
171
|
+
// render. Instead, sample a modest target in small chunks and yield to the event
|
|
172
|
+
// loop between each, refining the curve in place. The sheet stays responsive and
|
|
173
|
+
// the chart fills in progressively.
|
|
174
|
+
const SIM_TARGET = 2000;
|
|
175
|
+
const SIM_CHUNK = 200;
|
|
176
|
+
const runSimulation = async (formula, token, cacheKey) => {
|
|
177
|
+
const counts = new Map();
|
|
178
|
+
let done = 0;
|
|
179
|
+
while (done < SIM_TARGET) {
|
|
180
|
+
if (token !== runToken) return; // a newer run superseded us
|
|
181
|
+
const n = Math.min(SIM_CHUNK, SIM_TARGET - done);
|
|
182
|
+
const batch = await Roll.simulate(formula, n);
|
|
183
|
+
if (token !== runToken) return;
|
|
184
|
+
for (const v of batch) counts.set(v, (counts.get(v) || 0) + 1);
|
|
185
|
+
done += n;
|
|
186
|
+
const dist = new Map();
|
|
187
|
+
for (const [v, c] of counts) dist.set(v, c / done);
|
|
188
|
+
result.value = summarize(dist, true);
|
|
189
|
+
iterations.value = done;
|
|
190
|
+
// Yield so the browser can paint and handle input between chunks.
|
|
191
|
+
await new Promise(r => setTimeout(r, 0));
|
|
192
|
+
}
|
|
193
|
+
// Cache the completed estimate so this formula isn't re-simulated later.
|
|
194
|
+
__rollVisualizerCache.set(cacheKey, result.value);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const recompute = () => {
|
|
198
|
+
const token = ++runToken;
|
|
199
|
+
const raw = (props.formula || "").trim();
|
|
200
|
+
if (!raw) {
|
|
201
|
+
result.value = { average: 0, min: 0, max: 0, labels: [], values: [], step: 1, approximate: false, hasData: false };
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
let roll;
|
|
205
|
+
try {
|
|
206
|
+
roll = new Roll(raw, props.rollData || {});
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
result.value = { average: 0, min: 0, max: 0, labels: [], values: [], step: 1, approximate: false, hasData: false };
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// Cache hit on the resolved formula -> reuse the result, no recompute.
|
|
213
|
+
const cacheKey = roll.formula;
|
|
214
|
+
const cached = __rollVisualizerCache.get(cacheKey);
|
|
215
|
+
if (cached) {
|
|
216
|
+
result.value = cached;
|
|
217
|
+
iterations.value = cached.approximate ? SIM_TARGET : 0;
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
// After construction Foundry has substituted @refs into the terms.
|
|
221
|
+
const terms = roll.terms || [];
|
|
222
|
+
if (canConvolve(terms)) {
|
|
223
|
+
iterations.value = 0;
|
|
224
|
+
const summary = summarize(convolveTerms(terms), false);
|
|
225
|
+
__rollVisualizerCache.set(cacheKey, summary);
|
|
226
|
+
result.value = summary;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Simulate against the resolved formula (no @refs remain in roll.formula).
|
|
230
|
+
runSimulation(roll.formula, token, cacheKey);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Debounce so rapid field edits don't kick off redundant simulations.
|
|
235
|
+
let debounceHandle = null;
|
|
236
|
+
watch(
|
|
237
|
+
() => [props.formula, JSON.stringify(props.rollData || {})],
|
|
238
|
+
() => {
|
|
239
|
+
if (debounceHandle) clearTimeout(debounceHandle);
|
|
240
|
+
debounceHandle = setTimeout(recompute, 200);
|
|
241
|
+
},
|
|
242
|
+
{ immediate: true }
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const getLabel = computed(() => {
|
|
246
|
+
const localized = game.i18n.localize(props.label);
|
|
247
|
+
if (props.icon) return \`<i class="fa-solid \${props.icon}"></i> \${localized}\`;
|
|
248
|
+
return localized;
|
|
249
|
+
});
|
|
250
|
+
const accentColor = computed(() => props.color || "#92aed9");
|
|
251
|
+
const averageText = computed(() => (result.value.approximate ? "≈ " : "") + result.value.average);
|
|
252
|
+
</script>
|
|
253
|
+
|
|
254
|
+
<template>
|
|
255
|
+
<v-card class="isdl-roll-visualizer" :name="systemPath" variant="tonal" density="compact">
|
|
256
|
+
<div class="isdl-roll-visualizer__header">
|
|
257
|
+
<span class="isdl-roll-visualizer__label" v-html="getLabel"></span>
|
|
258
|
+
<span class="isdl-roll-visualizer__avg" :style="{ color: accentColor }">{{ averageText }}</span>
|
|
259
|
+
</div>
|
|
260
|
+
<v-sparkline
|
|
261
|
+
v-if="result.hasData"
|
|
262
|
+
:labels="result.labels"
|
|
263
|
+
:model-value="result.values"
|
|
264
|
+
:color="accentColor"
|
|
265
|
+
line-width="2"
|
|
266
|
+
padding="8"
|
|
267
|
+
smooth="6"
|
|
268
|
+
:label-size="10"
|
|
269
|
+
auto-draw
|
|
270
|
+
preserveAspectRatio="none"
|
|
271
|
+
>
|
|
272
|
+
<!-- Render a label only on "nice" round outcomes; blank elsewhere so the
|
|
273
|
+
axis doesn't cluster and never falls back to showing the raw value. -->
|
|
274
|
+
<template #label="item">
|
|
275
|
+
{{ Number(item.value) % result.step === 0 ? item.value : "" }}
|
|
276
|
+
</template>
|
|
277
|
+
</v-sparkline>
|
|
278
|
+
<div v-else class="isdl-roll-visualizer__empty text-caption">
|
|
279
|
+
{{ game.i18n.localize("ROLLVISUALIZER.NoFormula") }}
|
|
280
|
+
</div>
|
|
281
|
+
<div class="isdl-roll-visualizer__footer text-caption">
|
|
282
|
+
<span v-if="result.hasData">
|
|
283
|
+
{{ game.i18n.localize("ROLLVISUALIZER.Min") }}: {{ result.min }}
|
|
284
|
+
·
|
|
285
|
+
{{ game.i18n.localize("ROLLVISUALIZER.Max") }}: {{ result.max }}
|
|
286
|
+
·
|
|
287
|
+
{{ game.i18n.localize("ROLLVISUALIZER.Average") }}: {{ averageText }}
|
|
288
|
+
</span>
|
|
289
|
+
<span v-if="result.approximate && iterations > 0" class="isdl-roll-visualizer__approx">
|
|
290
|
+
({{ iterations }} {{ game.i18n.localize("ROLLVISUALIZER.Simulations") }})
|
|
291
|
+
</span>
|
|
292
|
+
</div>
|
|
293
|
+
</v-card>
|
|
294
|
+
</template>
|
|
295
|
+
`.appendNewLine();
|
|
119
296
|
fs.writeFileSync(generatedFilePath, toString(fileNode));
|
|
120
297
|
}
|
|
121
298
|
//# sourceMappingURL=vue-roll-visualizer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue-roll-visualizer.js","sourceRoot":"","sources":["../../../../../src/cli/components/vue/base-components/vue-roll-visualizer.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,+BAA+B,CAAC,WAAmB;IACvE,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,qBAAqB,CAAC,CAAC;IAE7E,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
|
|
1
|
+
{"version":3,"file":"vue-roll-visualizer.js","sourceRoot":"","sources":["../../../../../src/cli/components/vue/base-components/vue-roll-visualizer.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,+BAA+B,CAAC,WAAmB;IACvE,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,qBAAqB,CAAC,CAAC;IAE7E,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6R5B,CAAC,aAAa,EAAE,CAAC;IAElB,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -7,68 +7,68 @@ export default function generateSelfPropertyReferenceComponent(destination, entr
|
|
|
7
7
|
if (!fs.existsSync(generatedFileDir)) {
|
|
8
8
|
fs.mkdirSync(generatedFileDir, { recursive: true });
|
|
9
9
|
}
|
|
10
|
-
const fileNode = expandToNode `
|
|
11
|
-
<script setup>
|
|
12
|
-
import { ref, computed, inject } from "vue";
|
|
13
|
-
|
|
14
|
-
const props = defineProps({
|
|
15
|
-
label: String,
|
|
16
|
-
systemPath: String,
|
|
17
|
-
context: Object,
|
|
18
|
-
disabled: Boolean,
|
|
19
|
-
icon: String,
|
|
20
|
-
color: String,
|
|
21
|
-
propertyType: String,
|
|
22
|
-
choices: Array
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const document = inject("rawDocument");
|
|
26
|
-
|
|
27
|
-
const value = computed({
|
|
28
|
-
get: () => foundry.utils.getProperty(props.context, props.systemPath),
|
|
29
|
-
set: (newValue) => foundry.utils.setProperty(props.context, props.systemPath, newValue)
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// Filter choices based on property type if provided
|
|
33
|
-
const availableChoices = computed(() => {
|
|
34
|
-
if (!props.choices || !props.propertyType) return [];
|
|
35
|
-
|
|
36
|
-
// Filter properties based on type
|
|
37
|
-
return props.choices.filter(choice => {
|
|
38
|
-
// Here we would check if the choice matches the expected property type
|
|
39
|
-
// For now, return all choices - this could be enhanced with type checking
|
|
40
|
-
return true;
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const fieldColor = computed(() => {
|
|
46
|
-
return props.color || 'primary';
|
|
47
|
-
});
|
|
48
|
-
</script>
|
|
49
|
-
|
|
50
|
-
<template>
|
|
51
|
-
<div class="isdl-self-property-reference single-wide">
|
|
52
|
-
<v-select
|
|
53
|
-
:model-value="value"
|
|
54
|
-
@update:model-value="(v) => { value = v; if (document) document.update({ [props.systemPath]: v }); }"
|
|
55
|
-
:items="availableChoices"
|
|
56
|
-
:name="props.systemPath"
|
|
57
|
-
:disabled="disabled"
|
|
58
|
-
:color="fieldColor"
|
|
59
|
-
variant="outlined"
|
|
60
|
-
density="compact"
|
|
61
|
-
clearable
|
|
62
|
-
>
|
|
63
|
-
<template #label>
|
|
64
|
-
<span class="field-label">
|
|
65
|
-
<v-icon v-if="props.icon" :icon="props.icon" size="small" class="me-1"></v-icon>
|
|
66
|
-
{{ game.i18n.localize(props.label) }}
|
|
67
|
-
</span>
|
|
68
|
-
</template>
|
|
69
|
-
</v-select>
|
|
70
|
-
</div>
|
|
71
|
-
</template>
|
|
10
|
+
const fileNode = expandToNode `
|
|
11
|
+
<script setup>
|
|
12
|
+
import { ref, computed, inject } from "vue";
|
|
13
|
+
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
label: String,
|
|
16
|
+
systemPath: String,
|
|
17
|
+
context: Object,
|
|
18
|
+
disabled: Boolean,
|
|
19
|
+
icon: String,
|
|
20
|
+
color: String,
|
|
21
|
+
propertyType: String,
|
|
22
|
+
choices: Array
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const document = inject("rawDocument");
|
|
26
|
+
|
|
27
|
+
const value = computed({
|
|
28
|
+
get: () => foundry.utils.getProperty(props.context, props.systemPath),
|
|
29
|
+
set: (newValue) => foundry.utils.setProperty(props.context, props.systemPath, newValue)
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Filter choices based on property type if provided
|
|
33
|
+
const availableChoices = computed(() => {
|
|
34
|
+
if (!props.choices || !props.propertyType) return [];
|
|
35
|
+
|
|
36
|
+
// Filter properties based on type
|
|
37
|
+
return props.choices.filter(choice => {
|
|
38
|
+
// Here we would check if the choice matches the expected property type
|
|
39
|
+
// For now, return all choices - this could be enhanced with type checking
|
|
40
|
+
return true;
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
const fieldColor = computed(() => {
|
|
46
|
+
return props.color || 'primary';
|
|
47
|
+
});
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<div class="isdl-self-property-reference single-wide">
|
|
52
|
+
<v-select
|
|
53
|
+
:model-value="value"
|
|
54
|
+
@update:model-value="(v) => { value = v; if (document) document.update({ [props.systemPath]: v }); }"
|
|
55
|
+
:items="availableChoices"
|
|
56
|
+
:name="props.systemPath"
|
|
57
|
+
:disabled="disabled"
|
|
58
|
+
:color="fieldColor"
|
|
59
|
+
variant="outlined"
|
|
60
|
+
density="compact"
|
|
61
|
+
clearable
|
|
62
|
+
>
|
|
63
|
+
<template #label>
|
|
64
|
+
<span class="field-label">
|
|
65
|
+
<v-icon v-if="props.icon" :icon="props.icon" size="small" class="me-1"></v-icon>
|
|
66
|
+
{{ game.i18n.localize(props.label) }}
|
|
67
|
+
</span>
|
|
68
|
+
</template>
|
|
69
|
+
</v-select>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
72
72
|
`.appendNewLine();
|
|
73
73
|
fs.writeFileSync(generatedFilePath, toString(fileNode));
|
|
74
74
|
}
|