@myrmidon/gve-snapshot-rendition 0.0.2 → 0.0.3
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/README.md +18 -0
- package/dist/hint-designer/gve-hint-designer.d.ts +31 -0
- package/dist/index.cjs.min.js +5 -5
- package/dist/index.cjs.min.js.map +1 -1
- package/dist/index.js +450 -124
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -10725,7 +10725,7 @@ function _assertThisInitialized(self) { if (self === void 0) { throw new Referen
|
|
|
10725
10725
|
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
|
|
10726
10726
|
|
|
10727
10727
|
/*!
|
|
10728
|
-
* GSAP 3.
|
|
10728
|
+
* GSAP 3.14.2
|
|
10729
10729
|
* https://gsap.com
|
|
10730
10730
|
*
|
|
10731
10731
|
* @license Copyright 2008-2025, GreenSock. All rights reserved.
|
|
@@ -10785,6 +10785,8 @@ var _config = {
|
|
|
10785
10785
|
_isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView || function () {},
|
|
10786
10786
|
// note: IE10 has ArrayBuffer, but NOT ArrayBuffer.isView().
|
|
10787
10787
|
_isArray = Array.isArray,
|
|
10788
|
+
_randomExp = /random\([^)]+\)/g,
|
|
10789
|
+
_commaDelimExp = /,\s*/g,
|
|
10788
10790
|
_strictNumExp = /(?:-?\.?\d|\.)+/gi,
|
|
10789
10791
|
//only numbers (including negatives and decimals) but NOT relative values.
|
|
10790
10792
|
_numExp$1 = /[-+=.]*\d+[.e\-+]*\d*[e\-+]*\d*/g,
|
|
@@ -11379,7 +11381,7 @@ clamp = function clamp(min, max, value) {
|
|
|
11379
11381
|
return _isString(value) && !leaveStrings || _isArrayLike(value, 1) ? (_accumulator = accumulator).push.apply(_accumulator, toArray(value)) : accumulator.push(value);
|
|
11380
11382
|
}) || accumulator;
|
|
11381
11383
|
},
|
|
11382
|
-
//takes any value and returns an
|
|
11384
|
+
// takes any value and returns an Array. If it's a string (and leaveStrings isn't true), it'll use document.querySelectorAll() and convert that to an array. It'll also accept iterables like jQuery objects.
|
|
11383
11385
|
toArray = function toArray(value, scope, leaveStrings) {
|
|
11384
11386
|
return _context && !scope && _context.selector ? _context.selector(value) : _isString(value) && !leaveStrings && (_coreInitted$1 || !_wake()) ? _slice.call((scope || _doc$1).querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : [];
|
|
11385
11387
|
},
|
|
@@ -11396,7 +11398,7 @@ toArray = function toArray(value, scope, leaveStrings) {
|
|
|
11396
11398
|
});
|
|
11397
11399
|
},
|
|
11398
11400
|
// alternative that's a bit faster and more reliably diverse but bigger: for (let j, v, i = a.length; i; j = (Math.random() * i) | 0, v = a[--i], a[i] = a[j], a[j] = v); return a;
|
|
11399
|
-
//for distributing values across an
|
|
11401
|
+
// for distributing values across an Array. Can accept a number, a function or (most commonly) an object which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array.
|
|
11400
11402
|
distribute = function distribute(v) {
|
|
11401
11403
|
if (_isFunction(v)) {
|
|
11402
11404
|
return v;
|
|
@@ -11583,24 +11585,13 @@ distribute = function distribute(v) {
|
|
|
11583
11585
|
return min + (value > range ? total - value : value);
|
|
11584
11586
|
});
|
|
11585
11587
|
},
|
|
11586
|
-
_replaceRandom = function _replaceRandom(
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
isArray;
|
|
11594
|
-
|
|
11595
|
-
while (~(i = value.indexOf("random(", prev))) {
|
|
11596
|
-
end = value.indexOf(")", i);
|
|
11597
|
-
isArray = value.charAt(i + 7) === "[";
|
|
11598
|
-
nums = value.substr(i + 7, end - i - 7).match(isArray ? _delimitedValueExp : _strictNumExp);
|
|
11599
|
-
s += value.substr(prev, i - prev) + random(isArray ? nums : +nums[0], isArray ? 0 : +nums[1], +nums[2] || 1e-5);
|
|
11600
|
-
prev = end + 1;
|
|
11601
|
-
}
|
|
11602
|
-
|
|
11603
|
-
return s + value.substr(prev, value.length - prev);
|
|
11588
|
+
_replaceRandom = function _replaceRandom(s) {
|
|
11589
|
+
return s.replace(_randomExp, function (match) {
|
|
11590
|
+
//replaces all occurrences of random(...) in a string with the calculated random value. can be a range like random(-100, 100, 5) or an array like random([0, 100, 500])
|
|
11591
|
+
var arIndex = match.indexOf("[") + 1,
|
|
11592
|
+
values = match.substring(arIndex || 7, arIndex ? match.indexOf("]") : match.length - 1).split(_commaDelimExp);
|
|
11593
|
+
return random(arIndex ? values : +values[0], arIndex ? 0 : +values[1], +values[2] || 1e-5);
|
|
11594
|
+
});
|
|
11604
11595
|
},
|
|
11605
11596
|
mapRange = function mapRange(inMin, inMax, outMin, outMax, value) {
|
|
11606
11597
|
var inRange = inMax - inMin,
|
|
@@ -12436,7 +12427,7 @@ var Animation = /*#__PURE__*/function () {
|
|
|
12436
12427
|
}
|
|
12437
12428
|
}
|
|
12438
12429
|
|
|
12439
|
-
if (this._tTime !== _totalTime || !this._dur && !suppressEvents || this._initted && Math.abs(this._zTime) === _tinyNum || !_totalTime && !this._initted && (this.add || this._ptLookup)) {
|
|
12430
|
+
if (this._tTime !== _totalTime || !this._dur && !suppressEvents || this._initted && Math.abs(this._zTime) === _tinyNum || !this._initted && this._dur && _totalTime || !_totalTime && !this._initted && (this.add || this._ptLookup)) {
|
|
12440
12431
|
// check for _ptLookup on a Tween instance to ensure it has actually finished being instantiated, otherwise if this.reverse() gets called in the Animation constructor, it could trigger a render() here even though the _targets weren't populated, thus when _init() is called there won't be any PropTweens (it'll act like the tween is non-functional)
|
|
12441
12432
|
this._ts || (this._pTime = _totalTime); // otherwise, if an animation is paused, then the playhead is moved back to zero, then resumed, it'd revert back to the original time at the pause
|
|
12442
12433
|
//if (!this._lock) { // avoid endless recursion (not sure we need this yet or if it's worth the performance hit)
|
|
@@ -12531,9 +12522,9 @@ var Animation = /*#__PURE__*/function () {
|
|
|
12531
12522
|
|
|
12532
12523
|
_proto.startTime = function startTime(value) {
|
|
12533
12524
|
if (arguments.length) {
|
|
12534
|
-
this._start = value;
|
|
12525
|
+
this._start = _roundPrecise(value);
|
|
12535
12526
|
var parent = this.parent || this._dp;
|
|
12536
|
-
parent && (parent._sort || !this.parent) && _addToTimeline(parent, this,
|
|
12527
|
+
parent && (parent._sort || !this.parent) && _addToTimeline(parent, this, this._start - this._delay);
|
|
12537
12528
|
return this;
|
|
12538
12529
|
}
|
|
12539
12530
|
|
|
@@ -12683,13 +12674,15 @@ var Animation = /*#__PURE__*/function () {
|
|
|
12683
12674
|
};
|
|
12684
12675
|
|
|
12685
12676
|
_proto.then = function then(onFulfilled) {
|
|
12686
|
-
var self = this
|
|
12677
|
+
var self = this,
|
|
12678
|
+
prevProm = self._prom;
|
|
12687
12679
|
return new Promise(function (resolve) {
|
|
12688
12680
|
var f = _isFunction(onFulfilled) ? onFulfilled : _passThrough,
|
|
12689
12681
|
_resolve = function _resolve() {
|
|
12690
12682
|
var _then = self.then;
|
|
12691
12683
|
self.then = null; // temporarily null the then() method to avoid an infinite loop (see https://github.com/greensock/GSAP/issues/322)
|
|
12692
12684
|
|
|
12685
|
+
prevProm && prevProm();
|
|
12693
12686
|
_isFunction(f) && (f = f(self)) && (f.then || f === self) && (self.then = _then);
|
|
12694
12687
|
resolve(f);
|
|
12695
12688
|
self.then = _then;
|
|
@@ -12910,7 +12903,11 @@ var Timeline = /*#__PURE__*/function (_Animation) {
|
|
|
12910
12903
|
this._tTime = tTime; // if a user gets the iteration() inside the onRepeat, for example, it should be accurate.
|
|
12911
12904
|
|
|
12912
12905
|
!suppressEvents && this.parent && _callback(this, "onRepeat");
|
|
12913
|
-
|
|
12906
|
+
|
|
12907
|
+
if (this.vars.repeatRefresh && !isYoyo) {
|
|
12908
|
+
this.invalidate()._lock = 1;
|
|
12909
|
+
prevIteration = iteration; // otherwise, the onStart() may fire on the 2nd iteration.
|
|
12910
|
+
}
|
|
12914
12911
|
|
|
12915
12912
|
if (prevTime && prevTime !== this._time || prevPaused !== !this._ts || this.vars.onRepeat && !this.parent && !this._act) {
|
|
12916
12913
|
// if prevTime is 0 and we render at the very end, _time will be the end, thus won't match. So in this edge case, prevTime won't match _time but that's okay. If it gets killed in the onRepeat, eject as well.
|
|
@@ -12958,7 +12955,7 @@ var Timeline = /*#__PURE__*/function (_Animation) {
|
|
|
12958
12955
|
prevTime = 0; // upon init, the playhead should always go forward; someone could invalidate() a completed timeline and then if they restart(), that would make child tweens render in reverse order which could lock in the wrong starting values if they build on each other, like tl.to(obj, {x: 100}).to(obj, {x: 0}).
|
|
12959
12956
|
}
|
|
12960
12957
|
|
|
12961
|
-
if (!prevTime && tTime && !suppressEvents && !prevIteration) {
|
|
12958
|
+
if (!prevTime && tTime && dur && !suppressEvents && !prevIteration) {
|
|
12962
12959
|
_callback(this, "onStart");
|
|
12963
12960
|
|
|
12964
12961
|
if (this._tTime !== tTime) {
|
|
@@ -13305,6 +13302,7 @@ var Timeline = /*#__PURE__*/function (_Animation) {
|
|
|
13305
13302
|
var child = this._first,
|
|
13306
13303
|
labels = this.labels,
|
|
13307
13304
|
p;
|
|
13305
|
+
amount = _roundPrecise(amount);
|
|
13308
13306
|
|
|
13309
13307
|
while (child) {
|
|
13310
13308
|
if (child._start >= ignoreBeforeTime) {
|
|
@@ -13394,7 +13392,7 @@ var Timeline = /*#__PURE__*/function (_Animation) {
|
|
|
13394
13392
|
max -= start;
|
|
13395
13393
|
|
|
13396
13394
|
if (!parent && !self._dp || parent && parent.smoothChildTiming) {
|
|
13397
|
-
self._start += start / self._ts;
|
|
13395
|
+
self._start += _roundPrecise(start / self._ts);
|
|
13398
13396
|
self._time -= start;
|
|
13399
13397
|
self._tTime -= start;
|
|
13400
13398
|
}
|
|
@@ -15194,7 +15192,7 @@ var gsap$1 = _gsap.registerPlugin({
|
|
|
15194
15192
|
}
|
|
15195
15193
|
}, _buildModifierPlugin("roundProps", _roundModifier), _buildModifierPlugin("modifiers"), _buildModifierPlugin("snap", snap)) || _gsap; //to prevent the core plugins from being dropped via aggressive tree shaking, we must include them in the variable declaration in this way.
|
|
15196
15194
|
|
|
15197
|
-
Tween.version = Timeline.version = gsap$1.version = "3.
|
|
15195
|
+
Tween.version = Timeline.version = gsap$1.version = "3.14.2";
|
|
15198
15196
|
_coreReady = 1;
|
|
15199
15197
|
_windowExists$2() && _wake();
|
|
15200
15198
|
_easeMap.Power0;
|
|
@@ -15217,7 +15215,7 @@ _easeMap.Power0;
|
|
|
15217
15215
|
_easeMap.Circ;
|
|
15218
15216
|
|
|
15219
15217
|
/*!
|
|
15220
|
-
* CSSPlugin 3.
|
|
15218
|
+
* CSSPlugin 3.14.2
|
|
15221
15219
|
* https://gsap.com
|
|
15222
15220
|
*
|
|
15223
15221
|
* Copyright 2008-2025, GreenSock. All rights reserved.
|
|
@@ -15259,6 +15257,10 @@ var _win$1,
|
|
|
15259
15257
|
return data.set(data.t, data.p, ratio ? Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u : data.b, data);
|
|
15260
15258
|
},
|
|
15261
15259
|
//if units change, we need a way to render the original unit/value when the tween goes all the way back to the beginning (ratio:0)
|
|
15260
|
+
_renderCSSPropWithBeginningAndEnd = function _renderCSSPropWithBeginningAndEnd(ratio, data) {
|
|
15261
|
+
return data.set(data.t, data.p, ratio === 1 ? data.e : ratio ? Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u : data.b, data);
|
|
15262
|
+
},
|
|
15263
|
+
//if units change, we need a way to render the original unit/value when the tween goes all the way back to the beginning (ratio:0)
|
|
15262
15264
|
_renderRoundedCSSProp = function _renderRoundedCSSProp(ratio, data) {
|
|
15263
15265
|
var value = data.s + data.c * ratio;
|
|
15264
15266
|
data.set(data.t, data.p, ~~(value + (value < 0 ? -0.5 : .5)) + data.u, data);
|
|
@@ -16558,7 +16560,8 @@ var CSSPlugin = {
|
|
|
16558
16560
|
cache,
|
|
16559
16561
|
smooth,
|
|
16560
16562
|
hasPriority,
|
|
16561
|
-
inlineProps
|
|
16563
|
+
inlineProps,
|
|
16564
|
+
finalTransformValue;
|
|
16562
16565
|
_pluginInitted || _initCore$1(); // we may call init() multiple times on the same plugin instance, like when adding special properties, so make sure we don't overwrite the revert data or inlineProps
|
|
16563
16566
|
|
|
16564
16567
|
this.styles = this.styles || _getStyleSaver$1(target);
|
|
@@ -16601,9 +16604,9 @@ var CSSPlugin = {
|
|
|
16601
16604
|
// colors don't have units
|
|
16602
16605
|
startUnit = getUnit(startValue);
|
|
16603
16606
|
endUnit = getUnit(endValue);
|
|
16607
|
+
endUnit ? startUnit !== endUnit && (startValue = _convertToUnit(target, p, startValue, endUnit) + endUnit) : startUnit && (endValue += startUnit);
|
|
16604
16608
|
}
|
|
16605
16609
|
|
|
16606
|
-
endUnit ? startUnit !== endUnit && (startValue = _convertToUnit(target, p, startValue, endUnit) + endUnit) : startUnit && (endValue += startUnit);
|
|
16607
16610
|
this.add(style, "setProperty", startValue, endValue, index, targets, 0, 0, p);
|
|
16608
16611
|
props.push(p);
|
|
16609
16612
|
inlineProps.push(p, 0, style[p]);
|
|
@@ -16647,9 +16650,18 @@ var CSSPlugin = {
|
|
|
16647
16650
|
|
|
16648
16651
|
if (isTransformRelated) {
|
|
16649
16652
|
this.styles.save(p);
|
|
16653
|
+
finalTransformValue = endValue; // this is always the same as endValue except when it's a var(--) value, in which case we need to calculate the end value.
|
|
16650
16654
|
|
|
16651
16655
|
if (type === "string" && endValue.substring(0, 6) === "var(--") {
|
|
16652
16656
|
endValue = _getComputedProperty(target, endValue.substring(4, endValue.indexOf(")")));
|
|
16657
|
+
|
|
16658
|
+
if (endValue.substring(0, 5) === "calc(") {
|
|
16659
|
+
var origPerspective = target.style.perspective;
|
|
16660
|
+
target.style.perspective = endValue;
|
|
16661
|
+
endValue = _getComputedProperty(target, "perspective");
|
|
16662
|
+
origPerspective ? target.style.perspective = origPerspective : _removeProperty(target, "perspective");
|
|
16663
|
+
}
|
|
16664
|
+
|
|
16653
16665
|
endNum = parseFloat(endValue);
|
|
16654
16666
|
}
|
|
16655
16667
|
|
|
@@ -16716,7 +16728,11 @@ var CSSPlugin = {
|
|
|
16716
16728
|
this._pt = new PropTween(this._pt, isTransformRelated ? cache : style, p, startNum, (relative ? _parseRelative(startNum, relative + endNum) : endNum) - startNum, !isTransformRelated && (endUnit === "px" || p === "zIndex") && vars.autoRound !== false ? _renderRoundedCSSProp : _renderCSSProp);
|
|
16717
16729
|
this._pt.u = endUnit || 0;
|
|
16718
16730
|
|
|
16719
|
-
if (
|
|
16731
|
+
if (isTransformRelated && finalTransformValue !== endValue) {
|
|
16732
|
+
this._pt.b = startValue;
|
|
16733
|
+
this._pt.e = finalTransformValue;
|
|
16734
|
+
this._pt.r = _renderCSSPropWithBeginningAndEnd;
|
|
16735
|
+
} else if (startUnit !== endUnit && endUnit !== "%") {
|
|
16720
16736
|
//when the tween goes all the way back to the beginning, we need to revert it to the OLD/ORIGINAL value (with those units). We record that as a "b" (beginning) property and point to a render method that handles that. (performance optimization)
|
|
16721
16737
|
this._pt.b = startValue;
|
|
16722
16738
|
this._pt.r = _renderCSSPropWithBeginning;
|
|
@@ -80731,7 +80747,7 @@ var libExports = /*@__PURE__*/ requireLib();
|
|
|
80731
80747
|
var HighlightJS = /*@__PURE__*/getDefaultExportFromCjs(libExports);
|
|
80732
80748
|
|
|
80733
80749
|
/*!
|
|
80734
|
-
* DrawSVGPlugin 3.
|
|
80750
|
+
* DrawSVGPlugin 3.14.2
|
|
80735
80751
|
* https://gsap.com
|
|
80736
80752
|
*
|
|
80737
80753
|
* @license Copyright 2008-2025, GreenSock. All rights reserved.
|
|
@@ -80930,7 +80946,7 @@ _parse = function _parse(value, length, defaultStart) {
|
|
|
80930
80946
|
};
|
|
80931
80947
|
|
|
80932
80948
|
var DrawSVGPlugin = {
|
|
80933
|
-
version: "3.
|
|
80949
|
+
version: "3.14.2",
|
|
80934
80950
|
name: "drawSVG",
|
|
80935
80951
|
register: function register(core) {
|
|
80936
80952
|
gsap = core;
|
|
@@ -81058,7 +81074,9 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81058
81074
|
super();
|
|
81059
81075
|
// Properties
|
|
81060
81076
|
this._data = { hints: {}, animations: {} };
|
|
81061
|
-
this._settings = {
|
|
81077
|
+
this._settings = {
|
|
81078
|
+
...DEFAULT_HINT_DESIGNER_SETTINGS,
|
|
81079
|
+
};
|
|
81062
81080
|
this._hintVariables = [];
|
|
81063
81081
|
// Custom zoom/pan state
|
|
81064
81082
|
this._zoomLevel = 1;
|
|
@@ -81143,7 +81161,9 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81143
81161
|
set hintVariables(value) {
|
|
81144
81162
|
this._hintVariables = value || [];
|
|
81145
81163
|
this.refreshVariablesTable();
|
|
81146
|
-
this.fireEvent("hintVariablesChange", {
|
|
81164
|
+
this.fireEvent("hintVariablesChange", {
|
|
81165
|
+
hintVariables: this._hintVariables,
|
|
81166
|
+
});
|
|
81147
81167
|
}
|
|
81148
81168
|
// ==================== RENDERING ====================
|
|
81149
81169
|
/**
|
|
@@ -81202,7 +81222,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81202
81222
|
// Hints dropdown
|
|
81203
81223
|
this._hintsDropdown = document.createElement("select");
|
|
81204
81224
|
this._hintsDropdown.className = "hints-dropdown";
|
|
81205
|
-
this._hintsDropdown.innerHTML =
|
|
81225
|
+
this._hintsDropdown.innerHTML =
|
|
81226
|
+
'<option value="">-- Select Hint --</option>';
|
|
81206
81227
|
toolbar.appendChild(this._hintsDropdown);
|
|
81207
81228
|
// Save button (accent)
|
|
81208
81229
|
const saveBtn = this.createButton("save-hint", "save", "Save hint");
|
|
@@ -81514,7 +81535,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81514
81535
|
// Animation dropdown
|
|
81515
81536
|
this._animationsDropdown = document.createElement("select");
|
|
81516
81537
|
this._animationsDropdown.className = "animations-dropdown";
|
|
81517
|
-
this._animationsDropdown.innerHTML =
|
|
81538
|
+
this._animationsDropdown.innerHTML =
|
|
81539
|
+
'<option value="">-- Select Animation --</option>';
|
|
81518
81540
|
animControls.appendChild(this._animationsDropdown);
|
|
81519
81541
|
// Load button
|
|
81520
81542
|
const loadAnimBtn = this.createButton("load-animation", "download-cloud", "Load animation code");
|
|
@@ -81542,10 +81564,14 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81542
81564
|
createHintVariablesList() {
|
|
81543
81565
|
const panel = document.createElement("div");
|
|
81544
81566
|
panel.className = "variables-panel resizable-panel";
|
|
81545
|
-
// Header
|
|
81567
|
+
// Header with warning icon placeholder
|
|
81546
81568
|
const header = document.createElement("div");
|
|
81547
81569
|
header.className = "panel-header";
|
|
81548
|
-
|
|
81570
|
+
const headerText = document.createElement("span");
|
|
81571
|
+
headerText.textContent = "Hint Variables";
|
|
81572
|
+
header.appendChild(headerText);
|
|
81573
|
+
// Store reference to header for adding warning icon
|
|
81574
|
+
this._variablesPanelHeader = header;
|
|
81549
81575
|
panel.appendChild(header);
|
|
81550
81576
|
// Toolbar
|
|
81551
81577
|
const toolbar = document.createElement("div");
|
|
@@ -81553,10 +81579,18 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81553
81579
|
const addVarBtn = this.createButton("add-variable", "plus-circle", "Add new variable");
|
|
81554
81580
|
addVarBtn.classList.add("btn-primary");
|
|
81555
81581
|
toolbar.appendChild(addVarBtn);
|
|
81582
|
+
const populateBtn = this.createButton("populate-from-hints", "download-cloud", "Populate from all hints");
|
|
81583
|
+
populateBtn.classList.add("btn-accent");
|
|
81584
|
+
toolbar.appendChild(populateBtn);
|
|
81556
81585
|
const deleteAllBtn = this.createButton("delete-all-vars", "trash-2", "Delete all variables");
|
|
81557
81586
|
deleteAllBtn.classList.add("btn-danger");
|
|
81558
81587
|
toolbar.appendChild(deleteAllBtn);
|
|
81559
81588
|
panel.appendChild(toolbar);
|
|
81589
|
+
// Validation message (initially hidden)
|
|
81590
|
+
this._variablesValidationMsg = document.createElement("div");
|
|
81591
|
+
this._variablesValidationMsg.className = "validation-message";
|
|
81592
|
+
this._variablesValidationMsg.style.display = "none";
|
|
81593
|
+
panel.appendChild(this._variablesValidationMsg);
|
|
81560
81594
|
// Content
|
|
81561
81595
|
const content = document.createElement("div");
|
|
81562
81596
|
content.className = "panel-content";
|
|
@@ -81579,7 +81613,12 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81579
81613
|
// Use feather.icons to get the SVG directly (for Shadow DOM compatibility)
|
|
81580
81614
|
const icon = featherExports.icons[iconName];
|
|
81581
81615
|
if (icon) {
|
|
81582
|
-
btn.innerHTML = icon.toSvg({
|
|
81616
|
+
btn.innerHTML = icon.toSvg({
|
|
81617
|
+
class: "feather-icon",
|
|
81618
|
+
width: 16,
|
|
81619
|
+
height: 16,
|
|
81620
|
+
"stroke-width": 2,
|
|
81621
|
+
});
|
|
81583
81622
|
}
|
|
81584
81623
|
else {
|
|
81585
81624
|
this._logger.warn("Feather icon not found:", iconName);
|
|
@@ -81649,14 +81688,14 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81649
81688
|
splitter.addEventListener("pointerdown", (e) => {
|
|
81650
81689
|
const startY = e.clientY;
|
|
81651
81690
|
const startHeightAbove = panelAbove.offsetHeight;
|
|
81652
|
-
const container = this._shadow.querySelector(
|
|
81691
|
+
const container = this._shadow.querySelector(".hint-designer-container");
|
|
81653
81692
|
if (!container)
|
|
81654
81693
|
return;
|
|
81655
81694
|
const onMove = (moveEvent) => {
|
|
81656
81695
|
const delta = moveEvent.clientY - startY;
|
|
81657
81696
|
const newHeightAbove = Math.max(300, startHeightAbove + delta);
|
|
81658
81697
|
// Determine which splitter this is based on the panel above
|
|
81659
|
-
const isTopSplitter = panelAbove.classList.contains(
|
|
81698
|
+
const isTopSplitter = panelAbove.classList.contains("top-panels-wrapper");
|
|
81660
81699
|
if (isTopSplitter) {
|
|
81661
81700
|
// Splitter 1: between top and properties
|
|
81662
81701
|
// Set top height, let properties and variables share remaining space
|
|
@@ -81665,7 +81704,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81665
81704
|
else {
|
|
81666
81705
|
// Splitter 2: between properties and variables
|
|
81667
81706
|
// Get top panel height and keep it fixed
|
|
81668
|
-
const topPanel = this._shadow.querySelector(
|
|
81707
|
+
const topPanel = this._shadow.querySelector(".top-panels-wrapper");
|
|
81669
81708
|
const topHeight = topPanel ? topPanel.offsetHeight : 300;
|
|
81670
81709
|
// Set top and properties heights, let variables fill remaining
|
|
81671
81710
|
container.style.gridTemplateRows = `${topHeight}px 6px ${newHeightAbove}px 6px minmax(200px, 1fr)`;
|
|
@@ -81723,6 +81762,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81723
81762
|
// Variables panel
|
|
81724
81763
|
this.addClickListener("delete-all-vars", () => this.deleteAllVariables());
|
|
81725
81764
|
this.addClickListener("add-variable", () => this.addVariable());
|
|
81765
|
+
this.addClickListener("populate-from-hints", () => this.populateVariablesFromHints());
|
|
81726
81766
|
// Word wrap toggles
|
|
81727
81767
|
this.addClickListener("toggle-svg-wrap", () => this.toggleSvgWordWrap());
|
|
81728
81768
|
this.addClickListener("toggle-js-wrap", () => this.toggleJsWordWrap());
|
|
@@ -81745,17 +81785,17 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81745
81785
|
* Initialize panning with mouse drag.
|
|
81746
81786
|
*/
|
|
81747
81787
|
initializePanning() {
|
|
81748
|
-
const panel = this._shadow.querySelector(
|
|
81788
|
+
const panel = this._shadow.querySelector(".svg-display-panel");
|
|
81749
81789
|
if (!panel)
|
|
81750
81790
|
return;
|
|
81751
|
-
panel.addEventListener(
|
|
81791
|
+
panel.addEventListener("mousedown", (e) => {
|
|
81752
81792
|
const mouseEvent = e;
|
|
81753
81793
|
this._isPanning = true;
|
|
81754
81794
|
this._lastPanX = mouseEvent.clientX;
|
|
81755
81795
|
this._lastPanY = mouseEvent.clientY;
|
|
81756
|
-
panel.style.cursor =
|
|
81796
|
+
panel.style.cursor = "grabbing";
|
|
81757
81797
|
});
|
|
81758
|
-
document.addEventListener(
|
|
81798
|
+
document.addEventListener("mousemove", (e) => {
|
|
81759
81799
|
if (!this._isPanning)
|
|
81760
81800
|
return;
|
|
81761
81801
|
const deltaX = e.clientX - this._lastPanX;
|
|
@@ -81766,24 +81806,24 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81766
81806
|
this._lastPanY = e.clientY;
|
|
81767
81807
|
this.updateSvgTransform();
|
|
81768
81808
|
});
|
|
81769
|
-
document.addEventListener(
|
|
81809
|
+
document.addEventListener("mouseup", () => {
|
|
81770
81810
|
if (this._isPanning) {
|
|
81771
81811
|
this._isPanning = false;
|
|
81772
81812
|
const panelEl = panel;
|
|
81773
|
-
panelEl.style.cursor =
|
|
81813
|
+
panelEl.style.cursor = "grab";
|
|
81774
81814
|
}
|
|
81775
81815
|
});
|
|
81776
81816
|
// Set initial cursor
|
|
81777
|
-
panel.style.cursor =
|
|
81817
|
+
panel.style.cursor = "grab";
|
|
81778
81818
|
}
|
|
81779
81819
|
/**
|
|
81780
81820
|
* Initialize zooming with mouse wheel.
|
|
81781
81821
|
*/
|
|
81782
81822
|
initializeWheelZoom() {
|
|
81783
|
-
const panel = this._shadow.querySelector(
|
|
81823
|
+
const panel = this._shadow.querySelector(".svg-display-panel");
|
|
81784
81824
|
if (!panel)
|
|
81785
81825
|
return;
|
|
81786
|
-
panel.addEventListener(
|
|
81826
|
+
panel.addEventListener("wheel", (e) => {
|
|
81787
81827
|
const wheelEvent = e;
|
|
81788
81828
|
wheelEvent.preventDefault();
|
|
81789
81829
|
// Determine zoom direction based on wheel delta
|
|
@@ -81838,7 +81878,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81838
81878
|
if (!this._hintsDropdown)
|
|
81839
81879
|
return;
|
|
81840
81880
|
const currentValue = this._hintsDropdown.value;
|
|
81841
|
-
this._hintsDropdown.innerHTML =
|
|
81881
|
+
this._hintsDropdown.innerHTML =
|
|
81882
|
+
'<option value="">-- Select Hint --</option>';
|
|
81842
81883
|
const hintIds = Object.keys(this._data.hints);
|
|
81843
81884
|
hintIds.forEach((hintId) => {
|
|
81844
81885
|
const option = document.createElement("option");
|
|
@@ -81860,7 +81901,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81860
81901
|
if (!this._animationsDropdown)
|
|
81861
81902
|
return;
|
|
81862
81903
|
const currentValue = this._animationsDropdown.value;
|
|
81863
|
-
this._animationsDropdown.innerHTML =
|
|
81904
|
+
this._animationsDropdown.innerHTML =
|
|
81905
|
+
'<option value="">-- Select Animation --</option>';
|
|
81864
81906
|
Object.keys(this._data.animations).forEach((animId) => {
|
|
81865
81907
|
const option = document.createElement("option");
|
|
81866
81908
|
option.value = animId;
|
|
@@ -81931,7 +81973,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81931
81973
|
if (this._jsTextarea) {
|
|
81932
81974
|
// If the ID is not found, use the template; otherwise use empty string
|
|
81933
81975
|
const animCode = this._data.animations[animId];
|
|
81934
|
-
this._jsTextarea.value =
|
|
81976
|
+
this._jsTextarea.value =
|
|
81977
|
+
animCode !== undefined ? animCode : NEW_ANIMATION_TEMPLATE;
|
|
81935
81978
|
this.highlightJs();
|
|
81936
81979
|
}
|
|
81937
81980
|
}
|
|
@@ -81988,6 +82031,49 @@ class GveHintDesigner extends HTMLElement {
|
|
|
81988
82031
|
if (this._embeddedJsCheckbox)
|
|
81989
82032
|
this._embeddedJsCheckbox.checked = false;
|
|
81990
82033
|
}
|
|
82034
|
+
/**
|
|
82035
|
+
* Validate SVG code for well-formedness and structure.
|
|
82036
|
+
* Returns an error message if validation fails, or null if valid.
|
|
82037
|
+
*/
|
|
82038
|
+
validateSvgCode(svgCode) {
|
|
82039
|
+
// Check if SVG code is empty
|
|
82040
|
+
if (!svgCode || !svgCode.trim()) {
|
|
82041
|
+
return "SVG code cannot be empty";
|
|
82042
|
+
}
|
|
82043
|
+
const trimmedCode = svgCode.trim();
|
|
82044
|
+
// Check that it starts with <g and ends with </g>
|
|
82045
|
+
if (!trimmedCode.startsWith("<g")) {
|
|
82046
|
+
return "SVG must start with a <g> element (e.g., <g> or <g ...>)";
|
|
82047
|
+
}
|
|
82048
|
+
if (!trimmedCode.endsWith("</g>")) {
|
|
82049
|
+
return "SVG must end with </g> (closing tag for the root <g> element)";
|
|
82050
|
+
}
|
|
82051
|
+
// Use DOMParser to validate XML well-formedness
|
|
82052
|
+
const parser = new DOMParser();
|
|
82053
|
+
const wrappedSvg = `<svg xmlns="http://www.w3.org/2000/svg">${svgCode}</svg>`;
|
|
82054
|
+
const doc = parser.parseFromString(wrappedSvg, "image/svg+xml");
|
|
82055
|
+
// Check for parsing errors
|
|
82056
|
+
const errorNode = doc.querySelector("parsererror");
|
|
82057
|
+
if (errorNode) {
|
|
82058
|
+
const errorText = errorNode.textContent || "Unknown XML parsing error";
|
|
82059
|
+
return `XML is not well-formed: ${errorText}`;
|
|
82060
|
+
}
|
|
82061
|
+
// Verify there is exactly one root <g> element
|
|
82062
|
+
const svgElement = doc.documentElement;
|
|
82063
|
+
const rootChildren = Array.from(svgElement.children);
|
|
82064
|
+
if (rootChildren.length === 0) {
|
|
82065
|
+
return "SVG must contain a <g> element";
|
|
82066
|
+
}
|
|
82067
|
+
if (rootChildren.length > 1) {
|
|
82068
|
+
return `SVG must have exactly one root <g> element, but found ${rootChildren.length} root elements. Wrap all content in a single <g> element.`;
|
|
82069
|
+
}
|
|
82070
|
+
const rootElement = rootChildren[0];
|
|
82071
|
+
if (rootElement.tagName.toLowerCase() !== "g") {
|
|
82072
|
+
return `Root element must be <g>, but found <${rootElement.tagName}>`;
|
|
82073
|
+
}
|
|
82074
|
+
// All validations passed
|
|
82075
|
+
return null;
|
|
82076
|
+
}
|
|
81991
82077
|
/**
|
|
81992
82078
|
* Add a new hint.
|
|
81993
82079
|
*/
|
|
@@ -82027,19 +82113,21 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82027
82113
|
// Validate SVG and JS
|
|
82028
82114
|
const svgCode = this._svgTextarea?.value || "";
|
|
82029
82115
|
const animationValue = this._jsTextarea?.value || "";
|
|
82116
|
+
// Validate SVG code for well-formedness and structure
|
|
82117
|
+
const svgValidationError = this.validateSvgCode(svgCode);
|
|
82118
|
+
if (svgValidationError) {
|
|
82119
|
+
this.showMessage(`SVG validation error: ${svgValidationError}`, "error");
|
|
82120
|
+
return; // Prevent saving on error
|
|
82121
|
+
}
|
|
82122
|
+
// Validate JS syntax if present
|
|
82030
82123
|
try {
|
|
82031
|
-
// Validate SVG (basic check)
|
|
82032
|
-
if (svgCode && !svgCode.trim().startsWith("<g")) {
|
|
82033
|
-
throw new Error("SVG must start with <g> element");
|
|
82034
|
-
}
|
|
82035
|
-
// Validate JS syntax if present (we'll do more specific validation below)
|
|
82036
82124
|
if (animationValue && !animationValue.trim().startsWith("#")) {
|
|
82037
82125
|
// Try to create a function to validate syntax
|
|
82038
82126
|
new Function("gsap", "targetEl", "rootEl", animationValue);
|
|
82039
82127
|
}
|
|
82040
82128
|
}
|
|
82041
82129
|
catch (err) {
|
|
82042
|
-
this.showMessage(`
|
|
82130
|
+
this.showMessage(`JS validation error: ${err}`, "error");
|
|
82043
82131
|
return; // Prevent saving on error
|
|
82044
82132
|
}
|
|
82045
82133
|
// Build hint object
|
|
@@ -82178,23 +82266,33 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82178
82266
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
82179
82267
|
const element = node;
|
|
82180
82268
|
const tagName = element.tagName.toLowerCase();
|
|
82181
|
-
const id = element.getAttribute(
|
|
82269
|
+
const id = element.getAttribute("id");
|
|
82182
82270
|
// Keep defs and grid-and-rulers, remove everything else
|
|
82183
|
-
if (tagName !==
|
|
82271
|
+
if (tagName !== "defs" && id !== "grid-and-rulers") {
|
|
82184
82272
|
nodesToRemove.push(node);
|
|
82185
82273
|
}
|
|
82186
82274
|
}
|
|
82187
82275
|
}
|
|
82188
|
-
nodesToRemove.forEach(node => this._svgDisplay.removeChild(node));
|
|
82276
|
+
nodesToRemove.forEach((node) => this._svgDisplay.removeChild(node));
|
|
82189
82277
|
// If grid and rulers don't exist yet, add them
|
|
82190
|
-
if (!this._svgDisplay.querySelector(
|
|
82278
|
+
if (!this._svgDisplay.querySelector("#grid-and-rulers")) {
|
|
82191
82279
|
this.addGridAndRulers(this._svgDisplay);
|
|
82192
82280
|
}
|
|
82193
|
-
if (!this._hintId
|
|
82281
|
+
if (!this._hintId) {
|
|
82194
82282
|
return;
|
|
82195
82283
|
}
|
|
82196
|
-
|
|
82197
|
-
let svgCode =
|
|
82284
|
+
// Get SVG code from textarea if it exists, otherwise from saved data
|
|
82285
|
+
let svgCode = this._svgTextarea?.value || "";
|
|
82286
|
+
// Fallback to saved data if textarea is empty and we have saved data
|
|
82287
|
+
if (!svgCode && this._data.hints[this._hintId]) {
|
|
82288
|
+
svgCode = this._data.hints[this._hintId].svg;
|
|
82289
|
+
}
|
|
82290
|
+
// If still no SVG code, return early
|
|
82291
|
+
if (!svgCode) {
|
|
82292
|
+
return;
|
|
82293
|
+
}
|
|
82294
|
+
// Validate variables before resolving them
|
|
82295
|
+
this.validateSvgVariables(svgCode);
|
|
82198
82296
|
// Resolve variables
|
|
82199
82297
|
svgCode = this.resolveVariables(svgCode);
|
|
82200
82298
|
try {
|
|
@@ -82244,13 +82342,103 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82244
82342
|
});
|
|
82245
82343
|
return resolved;
|
|
82246
82344
|
}
|
|
82345
|
+
/**
|
|
82346
|
+
* Extract variable names from SVG code (variables in {{...}} placeholders).
|
|
82347
|
+
*/
|
|
82348
|
+
extractVariablesFromSvg(svgCode) {
|
|
82349
|
+
const variablePattern = /\{\{([^}]+)\}\}/g;
|
|
82350
|
+
const variables = [];
|
|
82351
|
+
let match;
|
|
82352
|
+
while ((match = variablePattern.exec(svgCode)) !== null) {
|
|
82353
|
+
const varName = match[1].trim();
|
|
82354
|
+
if (varName && !variables.includes(varName)) {
|
|
82355
|
+
variables.push(varName);
|
|
82356
|
+
}
|
|
82357
|
+
}
|
|
82358
|
+
return variables;
|
|
82359
|
+
}
|
|
82360
|
+
/**
|
|
82361
|
+
* Validate SVG variables and update validation message.
|
|
82362
|
+
* Shows a warning if any variables used in SVG are not defined in hint variables.
|
|
82363
|
+
*/
|
|
82364
|
+
validateSvgVariables(svgCode) {
|
|
82365
|
+
if (!this._variablesValidationMsg || !this._variablesPanelHeader) {
|
|
82366
|
+
return;
|
|
82367
|
+
}
|
|
82368
|
+
// Extract variables from SVG
|
|
82369
|
+
const usedVariables = this.extractVariablesFromSvg(svgCode);
|
|
82370
|
+
if (usedVariables.length === 0) {
|
|
82371
|
+
// No variables used - hide validation message and warning icon
|
|
82372
|
+
this._variablesValidationMsg.style.display = "none";
|
|
82373
|
+
this.updateVariablesHeaderWarning(false);
|
|
82374
|
+
return;
|
|
82375
|
+
}
|
|
82376
|
+
// Get defined variable names
|
|
82377
|
+
const definedVariables = this._hintVariables.map((v) => v.name);
|
|
82378
|
+
// Find undefined variables
|
|
82379
|
+
const undefinedVariables = usedVariables.filter((v) => !definedVariables.includes(v));
|
|
82380
|
+
if (undefinedVariables.length === 0) {
|
|
82381
|
+
// All variables are defined - hide validation message and warning icon
|
|
82382
|
+
this._variablesValidationMsg.style.display = "none";
|
|
82383
|
+
this.updateVariablesHeaderWarning(false);
|
|
82384
|
+
return;
|
|
82385
|
+
}
|
|
82386
|
+
// Show validation message with list of undefined variables
|
|
82387
|
+
this._variablesValidationMsg.style.display = "block";
|
|
82388
|
+
this._variablesValidationMsg.innerHTML = `
|
|
82389
|
+
<strong>⚠️ Undefined Variables:</strong>
|
|
82390
|
+
<div style="margin-top: 0.5rem;">
|
|
82391
|
+
The following variables are used in the SVG code but not defined in Hint Variables:
|
|
82392
|
+
<ul style="margin: 0.5rem 0; padding-left: 1.5rem;">
|
|
82393
|
+
${undefinedVariables
|
|
82394
|
+
.map((v) => `<li><code>{{${v}}}</code></li>`)
|
|
82395
|
+
.join("")}
|
|
82396
|
+
</ul>
|
|
82397
|
+
<em>Add these variables to the list below to ensure the hint displays correctly.</em>
|
|
82398
|
+
</div>
|
|
82399
|
+
`;
|
|
82400
|
+
// Show warning icon in header
|
|
82401
|
+
this.updateVariablesHeaderWarning(true);
|
|
82402
|
+
}
|
|
82403
|
+
/**
|
|
82404
|
+
* Update warning icon in variables panel header.
|
|
82405
|
+
*/
|
|
82406
|
+
updateVariablesHeaderWarning(showWarning) {
|
|
82407
|
+
if (!this._variablesPanelHeader)
|
|
82408
|
+
return;
|
|
82409
|
+
// Remove existing warning icon if present
|
|
82410
|
+
const existingWarning = this._variablesPanelHeader.querySelector(".warning-icon");
|
|
82411
|
+
if (existingWarning) {
|
|
82412
|
+
existingWarning.remove();
|
|
82413
|
+
}
|
|
82414
|
+
if (showWarning) {
|
|
82415
|
+
// Add warning icon
|
|
82416
|
+
const warningIcon = document.createElement("span");
|
|
82417
|
+
warningIcon.className = "warning-icon";
|
|
82418
|
+
warningIcon.title = "Some variables used in SVG are not defined";
|
|
82419
|
+
const icon = featherExports.icons["alert-triangle"];
|
|
82420
|
+
if (icon) {
|
|
82421
|
+
warningIcon.innerHTML = icon.toSvg({
|
|
82422
|
+
class: "feather-icon",
|
|
82423
|
+
width: 16,
|
|
82424
|
+
height: 16,
|
|
82425
|
+
"stroke-width": 2,
|
|
82426
|
+
color: "#ff9800",
|
|
82427
|
+
});
|
|
82428
|
+
}
|
|
82429
|
+
else {
|
|
82430
|
+
warningIcon.textContent = "⚠️";
|
|
82431
|
+
}
|
|
82432
|
+
this._variablesPanelHeader.appendChild(warningIcon);
|
|
82433
|
+
}
|
|
82434
|
+
}
|
|
82247
82435
|
/**
|
|
82248
82436
|
* Play animation.
|
|
82249
82437
|
*/
|
|
82250
82438
|
playAnimation() {
|
|
82251
82439
|
this._logger.debug("Animation", "playAnimation called", {
|
|
82252
82440
|
hasTimeline: !!this._currentTimeline,
|
|
82253
|
-
isPlaying: this._isPlaying
|
|
82441
|
+
isPlaying: this._isPlaying,
|
|
82254
82442
|
});
|
|
82255
82443
|
if (this._currentTimeline) {
|
|
82256
82444
|
// If timeline exists, just play it
|
|
@@ -82288,7 +82476,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82288
82476
|
createTimeline() {
|
|
82289
82477
|
this._logger.debug("Animation", "createTimeline called", {
|
|
82290
82478
|
hasSvgDisplay: !!this._svgDisplay,
|
|
82291
|
-
hintId: this._hintId
|
|
82479
|
+
hintId: this._hintId,
|
|
82292
82480
|
});
|
|
82293
82481
|
if (!this._svgDisplay || !this._hintId || !this._data.hints[this._hintId]) {
|
|
82294
82482
|
this.showMessage("No hint to animate!", "error");
|
|
@@ -82302,11 +82490,16 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82302
82490
|
if (hint.animation.startsWith("#")) {
|
|
82303
82491
|
const animId = hint.animation.substring(1);
|
|
82304
82492
|
jsCode = this._data.animations[animId] || "";
|
|
82305
|
-
this._logger.debug("Animation", "Using referenced animation", {
|
|
82493
|
+
this._logger.debug("Animation", "Using referenced animation", {
|
|
82494
|
+
animId,
|
|
82495
|
+
hasCode: !!jsCode,
|
|
82496
|
+
});
|
|
82306
82497
|
}
|
|
82307
82498
|
else {
|
|
82308
82499
|
jsCode = hint.animation;
|
|
82309
|
-
this._logger.debug("Animation", "Using embedded animation", {
|
|
82500
|
+
this._logger.debug("Animation", "Using embedded animation", {
|
|
82501
|
+
codeLength: jsCode.length,
|
|
82502
|
+
});
|
|
82310
82503
|
}
|
|
82311
82504
|
}
|
|
82312
82505
|
if (!jsCode) {
|
|
@@ -82323,7 +82516,10 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82323
82516
|
if (!hintEl) {
|
|
82324
82517
|
throw new Error("No hint <g> element found in SVG");
|
|
82325
82518
|
}
|
|
82326
|
-
this._logger.debug("Animation", "Found hint element", {
|
|
82519
|
+
this._logger.debug("Animation", "Found hint element", {
|
|
82520
|
+
tagName: hintEl.tagName,
|
|
82521
|
+
id: hintEl.getAttribute("id"),
|
|
82522
|
+
});
|
|
82327
82523
|
// Set initial opacity to 0 (on style attribute)
|
|
82328
82524
|
hintEl.style.opacity = "0";
|
|
82329
82525
|
// Check if GSAP is available
|
|
@@ -82369,12 +82565,12 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82369
82565
|
}
|
|
82370
82566
|
this._logger.debug("Animation", "Animation function executed", {
|
|
82371
82567
|
resultType: typeof result,
|
|
82372
|
-
isPromise: result && typeof result.then ===
|
|
82373
|
-
isTimeline: result && typeof result.progress ===
|
|
82374
|
-
capturedTweensCount: capturedTweens.length
|
|
82568
|
+
isPromise: result && typeof result.then === "function",
|
|
82569
|
+
isTimeline: result && typeof result.progress === "function",
|
|
82570
|
+
capturedTweensCount: capturedTweens.length,
|
|
82375
82571
|
});
|
|
82376
82572
|
// Check what was returned
|
|
82377
|
-
if (result && typeof result.progress ===
|
|
82573
|
+
if (result && typeof result.progress === "function") {
|
|
82378
82574
|
// Direct timeline/tween return
|
|
82379
82575
|
this._currentTimeline = result;
|
|
82380
82576
|
this._currentTimeline.pause();
|
|
@@ -82384,7 +82580,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82384
82580
|
// Animation called gsap methods - create timeline with captured tweens
|
|
82385
82581
|
this._logger.debug("Animation", "Creating timeline from captured tweens", {
|
|
82386
82582
|
tweenCount: capturedTweens.length,
|
|
82387
|
-
tweenDurations: capturedTweens.map(t => t.duration())
|
|
82583
|
+
tweenDurations: capturedTweens.map((t) => t.duration()),
|
|
82388
82584
|
});
|
|
82389
82585
|
// The tweens have already started playing, so we need to:
|
|
82390
82586
|
// 1. Kill them to stop auto-playing
|
|
@@ -82399,14 +82595,14 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82399
82595
|
duration: duration,
|
|
82400
82596
|
totalDuration: totalDuration,
|
|
82401
82597
|
targets: tween.targets(),
|
|
82402
|
-
vars: tween.vars
|
|
82598
|
+
vars: tween.vars,
|
|
82403
82599
|
});
|
|
82404
82600
|
// Get the animation method that was used (to, from, fromTo)
|
|
82405
82601
|
const targets = tween.targets();
|
|
82406
82602
|
const vars = { ...tween.vars };
|
|
82407
82603
|
// Get the initial values if this was a fromTo or from tween
|
|
82408
82604
|
const isFromTo = tween._from !== undefined;
|
|
82409
|
-
const isFrom = !isFromTo && tween.vars.hasOwnProperty(
|
|
82605
|
+
const isFrom = !isFromTo && tween.vars.hasOwnProperty("startAt");
|
|
82410
82606
|
// Kill the original tween to stop it from playing
|
|
82411
82607
|
tween.kill();
|
|
82412
82608
|
// Recreate the tween in our timeline using the appropriate method
|
|
@@ -82425,7 +82621,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82425
82621
|
}
|
|
82426
82622
|
});
|
|
82427
82623
|
this._logger.debug("Animation", "Timeline built from tweens", {
|
|
82428
|
-
timelineDuration: this._currentTimeline.duration()
|
|
82624
|
+
timelineDuration: this._currentTimeline.duration(),
|
|
82429
82625
|
});
|
|
82430
82626
|
}
|
|
82431
82627
|
else {
|
|
@@ -82436,7 +82632,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82436
82632
|
this._logger.debug("Animation", "Timeline created", {
|
|
82437
82633
|
duration: this._currentTimeline.duration(),
|
|
82438
82634
|
progress: this._currentTimeline.progress(),
|
|
82439
|
-
paused: this._currentTimeline.paused()
|
|
82635
|
+
paused: this._currentTimeline.paused(),
|
|
82440
82636
|
});
|
|
82441
82637
|
// Check if timeline has duration
|
|
82442
82638
|
if (this._currentTimeline.duration() === 0) {
|
|
@@ -82448,7 +82644,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82448
82644
|
this._logger.debug("Animation", "Animation completed callback", {
|
|
82449
82645
|
finalProgress: this._currentTimeline.progress(),
|
|
82450
82646
|
finalTime: this._currentTimeline.time(),
|
|
82451
|
-
duration: this._currentTimeline.duration()
|
|
82647
|
+
duration: this._currentTimeline.duration(),
|
|
82452
82648
|
});
|
|
82453
82649
|
this._isPlaying = false;
|
|
82454
82650
|
if (this._playButton)
|
|
@@ -82464,7 +82660,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82464
82660
|
});
|
|
82465
82661
|
this.showMessage("", "");
|
|
82466
82662
|
this._logger.info("Animation", "Timeline created successfully", {
|
|
82467
|
-
duration: this._currentTimeline.duration()
|
|
82663
|
+
duration: this._currentTimeline.duration(),
|
|
82468
82664
|
});
|
|
82469
82665
|
}
|
|
82470
82666
|
catch (err) {
|
|
@@ -82483,7 +82679,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82483
82679
|
pauseAnimation() {
|
|
82484
82680
|
this._logger.debug("Animation", "pauseAnimation called", {
|
|
82485
82681
|
hasTimeline: !!this._currentTimeline,
|
|
82486
|
-
isPlaying: this._isPlaying
|
|
82682
|
+
isPlaying: this._isPlaying,
|
|
82487
82683
|
});
|
|
82488
82684
|
if (this._currentTimeline) {
|
|
82489
82685
|
this._currentTimeline.pause();
|
|
@@ -82494,7 +82690,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82494
82690
|
this._pauseButton.disabled = true;
|
|
82495
82691
|
this.stopProgressUpdate();
|
|
82496
82692
|
this._logger.debug("Animation", "Animation paused", {
|
|
82497
|
-
progress: this._currentTimeline.progress()
|
|
82693
|
+
progress: this._currentTimeline.progress(),
|
|
82498
82694
|
});
|
|
82499
82695
|
}
|
|
82500
82696
|
}
|
|
@@ -82504,7 +82700,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82504
82700
|
restartAnimation() {
|
|
82505
82701
|
this._logger.debug("Animation", "restartAnimation called", {
|
|
82506
82702
|
hasTimeline: !!this._currentTimeline,
|
|
82507
|
-
isPlaying: this._isPlaying
|
|
82703
|
+
isPlaying: this._isPlaying,
|
|
82508
82704
|
});
|
|
82509
82705
|
if (this._currentTimeline) {
|
|
82510
82706
|
this._logger.debug("Animation", "Restarting existing timeline");
|
|
@@ -82529,7 +82725,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82529
82725
|
this._logger.debug("Animation", "seekAnimation called", {
|
|
82530
82726
|
hasProgressBar: !!this._progressBar,
|
|
82531
82727
|
hasTimeline: !!this._currentTimeline,
|
|
82532
|
-
progressBarValue: this._progressBar?.value
|
|
82728
|
+
progressBarValue: this._progressBar?.value,
|
|
82533
82729
|
});
|
|
82534
82730
|
if (!this._progressBar)
|
|
82535
82731
|
return;
|
|
@@ -82547,7 +82743,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82547
82743
|
progressBarValue: this._progressBar.value,
|
|
82548
82744
|
calculatedProgress: progress,
|
|
82549
82745
|
wasPlaying: this._isPlaying,
|
|
82550
|
-
timelineDuration: this._currentTimeline.duration()
|
|
82746
|
+
timelineDuration: this._currentTimeline.duration(),
|
|
82551
82747
|
});
|
|
82552
82748
|
// Pause the timeline to prevent it from continuing to play
|
|
82553
82749
|
this._isPlaying;
|
|
@@ -82556,7 +82752,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82556
82752
|
this._currentTimeline.progress(progress);
|
|
82557
82753
|
this._logger.debug("Animation", "Seek completed", {
|
|
82558
82754
|
newProgress: this._currentTimeline.progress(),
|
|
82559
|
-
timelinePaused: this._currentTimeline.paused()
|
|
82755
|
+
timelinePaused: this._currentTimeline.paused(),
|
|
82560
82756
|
});
|
|
82561
82757
|
// Update playing state
|
|
82562
82758
|
this._isPlaying = false;
|
|
@@ -82580,7 +82776,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82580
82776
|
}
|
|
82581
82777
|
}, 50); // Update every 50ms
|
|
82582
82778
|
this._logger.debug("Animation", "Progress update started", {
|
|
82583
|
-
intervalId: this._progressUpdateInterval
|
|
82779
|
+
intervalId: this._progressUpdateInterval,
|
|
82584
82780
|
});
|
|
82585
82781
|
}
|
|
82586
82782
|
/**
|
|
@@ -82589,7 +82785,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82589
82785
|
stopProgressUpdate() {
|
|
82590
82786
|
if (this._progressUpdateInterval) {
|
|
82591
82787
|
this._logger.debug("Animation", "Stopping progress update", {
|
|
82592
|
-
intervalId: this._progressUpdateInterval
|
|
82788
|
+
intervalId: this._progressUpdateInterval,
|
|
82593
82789
|
});
|
|
82594
82790
|
clearInterval(this._progressUpdateInterval);
|
|
82595
82791
|
this._progressUpdateInterval = undefined;
|
|
@@ -82616,7 +82812,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82616
82812
|
if (!this._svgDisplay)
|
|
82617
82813
|
return;
|
|
82618
82814
|
// Get panel size to center the SVG
|
|
82619
|
-
const panel = this._shadow.querySelector(
|
|
82815
|
+
const panel = this._shadow.querySelector(".svg-display-panel");
|
|
82620
82816
|
if (panel) {
|
|
82621
82817
|
const panelWidth = panel.clientWidth;
|
|
82622
82818
|
const panelHeight = panel.clientHeight;
|
|
@@ -82647,8 +82843,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82647
82843
|
panY: this._panY,
|
|
82648
82844
|
zoomLevel: this._zoomLevel,
|
|
82649
82845
|
transformString,
|
|
82650
|
-
svgWidth: this._svgDisplay.getAttribute(
|
|
82651
|
-
svgHeight: this._svgDisplay.getAttribute(
|
|
82846
|
+
svgWidth: this._svgDisplay.getAttribute("width"),
|
|
82847
|
+
svgHeight: this._svgDisplay.getAttribute("height"),
|
|
82652
82848
|
svgBBox: this._svgDisplay.getBBox(),
|
|
82653
82849
|
svgBoundingClientRect: {
|
|
82654
82850
|
x: svgBoundingRect.x,
|
|
@@ -82658,18 +82854,18 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82658
82854
|
top: svgBoundingRect.top,
|
|
82659
82855
|
left: svgBoundingRect.left,
|
|
82660
82856
|
right: svgBoundingRect.right,
|
|
82661
|
-
bottom: svgBoundingRect.bottom
|
|
82662
|
-
}
|
|
82857
|
+
bottom: svgBoundingRect.bottom,
|
|
82858
|
+
},
|
|
82663
82859
|
});
|
|
82664
82860
|
// Apply transform: translate first, then scale from the SVG's own center
|
|
82665
82861
|
this._svgDisplay.style.transform = transformString;
|
|
82666
|
-
this._svgDisplay.style.transformOrigin =
|
|
82862
|
+
this._svgDisplay.style.transformOrigin = "0 0";
|
|
82667
82863
|
// Only apply transition during zoom, not during pan (to avoid sluggishness)
|
|
82668
82864
|
if (!this._isPanning) {
|
|
82669
|
-
this._svgDisplay.style.transition =
|
|
82865
|
+
this._svgDisplay.style.transition = "transform 0.15s ease-out";
|
|
82670
82866
|
}
|
|
82671
82867
|
else {
|
|
82672
|
-
this._svgDisplay.style.transition =
|
|
82868
|
+
this._svgDisplay.style.transition = "none";
|
|
82673
82869
|
}
|
|
82674
82870
|
}
|
|
82675
82871
|
/**
|
|
@@ -82689,7 +82885,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82689
82885
|
// Get the bounding box of the hint content
|
|
82690
82886
|
const bbox = hintContent.getBBox();
|
|
82691
82887
|
// Get the SVG display panel size
|
|
82692
|
-
const panel = this._shadow.querySelector(
|
|
82888
|
+
const panel = this._shadow.querySelector(".svg-display-panel");
|
|
82693
82889
|
if (!panel)
|
|
82694
82890
|
return;
|
|
82695
82891
|
const panelWidth = panel.clientWidth;
|
|
@@ -82710,8 +82906,8 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82710
82906
|
// We want this to be at the center of the panel: (panelWidth/2, panelHeight/2)
|
|
82711
82907
|
// So: panX + (bboxCenterX * scale) = panelWidth / 2
|
|
82712
82908
|
// panY + (bboxCenterY * scale) = panelHeight / 2
|
|
82713
|
-
const panX =
|
|
82714
|
-
const panY =
|
|
82909
|
+
const panX = panelWidth / 2 - bboxCenterX * scale;
|
|
82910
|
+
const panY = panelHeight / 2 - bboxCenterY * scale;
|
|
82715
82911
|
this._zoomLevel = scale;
|
|
82716
82912
|
this._panX = panX;
|
|
82717
82913
|
this._panY = panY;
|
|
@@ -82724,7 +82920,7 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82724
82920
|
bboxCenterX,
|
|
82725
82921
|
bboxCenterY,
|
|
82726
82922
|
panelWidth,
|
|
82727
|
-
panelHeight
|
|
82923
|
+
panelHeight,
|
|
82728
82924
|
});
|
|
82729
82925
|
}
|
|
82730
82926
|
catch (err) {
|
|
@@ -82737,13 +82933,13 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82737
82933
|
*/
|
|
82738
82934
|
toggleSvgWordWrap() {
|
|
82739
82935
|
this._svgWordWrapEnabled = !this._svgWordWrapEnabled;
|
|
82740
|
-
const wrapper = this._shadow.getElementById(
|
|
82936
|
+
const wrapper = this._shadow.getElementById("svg-wrapper");
|
|
82741
82937
|
if (wrapper) {
|
|
82742
82938
|
if (this._svgWordWrapEnabled) {
|
|
82743
|
-
wrapper.classList.add(
|
|
82939
|
+
wrapper.classList.add("word-wrap-enabled");
|
|
82744
82940
|
}
|
|
82745
82941
|
else {
|
|
82746
|
-
wrapper.classList.remove(
|
|
82942
|
+
wrapper.classList.remove("word-wrap-enabled");
|
|
82747
82943
|
}
|
|
82748
82944
|
}
|
|
82749
82945
|
this._logger.debug("Component", "SVG word wrap toggled", this._svgWordWrapEnabled);
|
|
@@ -82753,13 +82949,13 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82753
82949
|
*/
|
|
82754
82950
|
toggleJsWordWrap() {
|
|
82755
82951
|
this._jsWordWrapEnabled = !this._jsWordWrapEnabled;
|
|
82756
|
-
const wrapper = this._shadow.getElementById(
|
|
82952
|
+
const wrapper = this._shadow.getElementById("js-wrapper");
|
|
82757
82953
|
if (wrapper) {
|
|
82758
82954
|
if (this._jsWordWrapEnabled) {
|
|
82759
|
-
wrapper.classList.add(
|
|
82955
|
+
wrapper.classList.add("word-wrap-enabled");
|
|
82760
82956
|
}
|
|
82761
82957
|
else {
|
|
82762
|
-
wrapper.classList.remove(
|
|
82958
|
+
wrapper.classList.remove("word-wrap-enabled");
|
|
82763
82959
|
}
|
|
82764
82960
|
}
|
|
82765
82961
|
this._logger.debug("Component", "JS word wrap toggled", this._jsWordWrapEnabled);
|
|
@@ -82855,7 +83051,9 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82855
83051
|
}
|
|
82856
83052
|
this._hintVariables.push({ name, value: "" });
|
|
82857
83053
|
this.refreshVariablesTable();
|
|
82858
|
-
this.fireEvent("hintVariablesChange", {
|
|
83054
|
+
this.fireEvent("hintVariablesChange", {
|
|
83055
|
+
hintVariables: this._hintVariables,
|
|
83056
|
+
});
|
|
82859
83057
|
}
|
|
82860
83058
|
/**
|
|
82861
83059
|
* Delete a variable.
|
|
@@ -82863,7 +83061,9 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82863
83061
|
deleteVariable(index) {
|
|
82864
83062
|
this._hintVariables.splice(index, 1);
|
|
82865
83063
|
this.refreshVariablesTable();
|
|
82866
|
-
this.fireEvent("hintVariablesChange", {
|
|
83064
|
+
this.fireEvent("hintVariablesChange", {
|
|
83065
|
+
hintVariables: this._hintVariables,
|
|
83066
|
+
});
|
|
82867
83067
|
}
|
|
82868
83068
|
/**
|
|
82869
83069
|
* Edit a variable.
|
|
@@ -82874,7 +83074,9 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82874
83074
|
if (newValue !== null) {
|
|
82875
83075
|
variable.value = newValue;
|
|
82876
83076
|
this.refreshVariablesTable();
|
|
82877
|
-
this.fireEvent("hintVariablesChange", {
|
|
83077
|
+
this.fireEvent("hintVariablesChange", {
|
|
83078
|
+
hintVariables: this._hintVariables,
|
|
83079
|
+
});
|
|
82878
83080
|
}
|
|
82879
83081
|
}
|
|
82880
83082
|
/**
|
|
@@ -82886,7 +83088,61 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82886
83088
|
return;
|
|
82887
83089
|
this._hintVariables = [];
|
|
82888
83090
|
this.refreshVariablesTable();
|
|
82889
|
-
this.fireEvent("hintVariablesChange", {
|
|
83091
|
+
this.fireEvent("hintVariablesChange", {
|
|
83092
|
+
hintVariables: this._hintVariables,
|
|
83093
|
+
});
|
|
83094
|
+
}
|
|
83095
|
+
/**
|
|
83096
|
+
* Extract all variable names from all hints in data.
|
|
83097
|
+
* Returns a sorted array of unique variable names.
|
|
83098
|
+
*/
|
|
83099
|
+
extractAllVariablesFromHints() {
|
|
83100
|
+
const allVariables = new Set();
|
|
83101
|
+
// Iterate through all hints in data
|
|
83102
|
+
Object.values(this._data.hints).forEach((hint) => {
|
|
83103
|
+
if (hint.svg) {
|
|
83104
|
+
// Extract variables from this hint's SVG
|
|
83105
|
+
const variables = this.extractVariablesFromSvg(hint.svg);
|
|
83106
|
+
variables.forEach((varName) => allVariables.add(varName));
|
|
83107
|
+
}
|
|
83108
|
+
});
|
|
83109
|
+
// Convert to array and sort alphabetically
|
|
83110
|
+
return Array.from(allVariables).sort();
|
|
83111
|
+
}
|
|
83112
|
+
/**
|
|
83113
|
+
* Populate hint variables from all hints.
|
|
83114
|
+
* Extracts all variables from all hints' SVG code and merges them into hintVariables.
|
|
83115
|
+
* Only adds variables that don't already exist.
|
|
83116
|
+
*/
|
|
83117
|
+
populateVariablesFromHints() {
|
|
83118
|
+
// Extract all variables from hints
|
|
83119
|
+
const extractedVariables = this.extractAllVariablesFromHints();
|
|
83120
|
+
if (extractedVariables.length === 0) {
|
|
83121
|
+
this.showMessage("No variables found in hints", "info");
|
|
83122
|
+
return;
|
|
83123
|
+
}
|
|
83124
|
+
// Get existing variable names for quick lookup
|
|
83125
|
+
const existingNames = new Set(this._hintVariables.map((v) => v.name));
|
|
83126
|
+
// Add new variables (those not already in hintVariables)
|
|
83127
|
+
let addedCount = 0;
|
|
83128
|
+
extractedVariables.forEach((varName) => {
|
|
83129
|
+
if (!existingNames.has(varName)) {
|
|
83130
|
+
this._hintVariables.push({ name: varName, value: "" });
|
|
83131
|
+
addedCount++;
|
|
83132
|
+
}
|
|
83133
|
+
});
|
|
83134
|
+
// Refresh UI and notify
|
|
83135
|
+
this.refreshVariablesTable();
|
|
83136
|
+
this.fireEvent("hintVariablesChange", {
|
|
83137
|
+
hintVariables: this._hintVariables,
|
|
83138
|
+
});
|
|
83139
|
+
// Show feedback message
|
|
83140
|
+
if (addedCount === 0) {
|
|
83141
|
+
this.showMessage(`All ${extractedVariables.length} variable(s) already defined`, "info");
|
|
83142
|
+
}
|
|
83143
|
+
else {
|
|
83144
|
+
this.showMessage(`Added ${addedCount} new variable(s) from hints (${extractedVariables.length} total found)`, "success");
|
|
83145
|
+
}
|
|
82890
83146
|
}
|
|
82891
83147
|
/**
|
|
82892
83148
|
* Refresh the variables table.
|
|
@@ -82902,6 +83158,11 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82902
83158
|
cell.textContent = "No variables defined";
|
|
82903
83159
|
cell.style.fontStyle = "italic";
|
|
82904
83160
|
cell.style.color = "#999";
|
|
83161
|
+
// Re-validate SVG variables after clearing variables
|
|
83162
|
+
const svgCode = this._svgTextarea?.value || "";
|
|
83163
|
+
if (svgCode) {
|
|
83164
|
+
this.validateSvgVariables(svgCode);
|
|
83165
|
+
}
|
|
82905
83166
|
return;
|
|
82906
83167
|
}
|
|
82907
83168
|
this._hintVariables.forEach((variable, index) => {
|
|
@@ -82922,6 +83183,11 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82922
83183
|
const valueCell = row.insertCell();
|
|
82923
83184
|
valueCell.textContent = variable.value;
|
|
82924
83185
|
});
|
|
83186
|
+
// Re-validate SVG variables after updating the variables table
|
|
83187
|
+
const svgCode = this._svgTextarea?.value || "";
|
|
83188
|
+
if (svgCode) {
|
|
83189
|
+
this.validateSvgVariables(svgCode);
|
|
83190
|
+
}
|
|
82925
83191
|
}
|
|
82926
83192
|
/**
|
|
82927
83193
|
* Show a message in the message panel.
|
|
@@ -82942,16 +83208,18 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82942
83208
|
if (!this._svgTextarea || !this._svgHighlightContainer) {
|
|
82943
83209
|
this._logger.debug("Component", "Cannot highlight SVG - missing elements", {
|
|
82944
83210
|
hasTextarea: !!this._svgTextarea,
|
|
82945
|
-
hasContainer: !!this._svgHighlightContainer
|
|
83211
|
+
hasContainer: !!this._svgHighlightContainer,
|
|
82946
83212
|
});
|
|
82947
83213
|
return;
|
|
82948
83214
|
}
|
|
82949
83215
|
const code = this._svgTextarea.value;
|
|
82950
|
-
this._logger.debug("Component", "Highlighting SVG", {
|
|
83216
|
+
this._logger.debug("Component", "Highlighting SVG", {
|
|
83217
|
+
codeLength: code.length,
|
|
83218
|
+
});
|
|
82951
83219
|
try {
|
|
82952
83220
|
// Highlight as XML
|
|
82953
|
-
const highlighted = HighlightJS.highlight(code, { language:
|
|
82954
|
-
this._svgHighlightContainer.innerHTML = highlighted +
|
|
83221
|
+
const highlighted = HighlightJS.highlight(code, { language: "xml" }).value;
|
|
83222
|
+
this._svgHighlightContainer.innerHTML = highlighted + "\n";
|
|
82955
83223
|
this._logger.debug("Component", "SVG highlighted successfully");
|
|
82956
83224
|
}
|
|
82957
83225
|
catch (err) {
|
|
@@ -82969,16 +83237,20 @@ class GveHintDesigner extends HTMLElement {
|
|
|
82969
83237
|
if (!this._jsTextarea || !this._jsHighlightContainer) {
|
|
82970
83238
|
this._logger.debug("Component", "Cannot highlight JS - missing elements", {
|
|
82971
83239
|
hasTextarea: !!this._jsTextarea,
|
|
82972
|
-
hasContainer: !!this._jsHighlightContainer
|
|
83240
|
+
hasContainer: !!this._jsHighlightContainer,
|
|
82973
83241
|
});
|
|
82974
83242
|
return;
|
|
82975
83243
|
}
|
|
82976
83244
|
const code = this._jsTextarea.value;
|
|
82977
|
-
this._logger.debug("Component", "Highlighting JS", {
|
|
83245
|
+
this._logger.debug("Component", "Highlighting JS", {
|
|
83246
|
+
codeLength: code.length,
|
|
83247
|
+
});
|
|
82978
83248
|
try {
|
|
82979
83249
|
// Highlight as JavaScript
|
|
82980
|
-
const highlighted = HighlightJS.highlight(code, {
|
|
82981
|
-
|
|
83250
|
+
const highlighted = HighlightJS.highlight(code, {
|
|
83251
|
+
language: "javascript",
|
|
83252
|
+
}).value;
|
|
83253
|
+
this._jsHighlightContainer.innerHTML = highlighted + "\n";
|
|
82982
83254
|
this._logger.debug("Component", "JS highlighted successfully");
|
|
82983
83255
|
}
|
|
82984
83256
|
catch (err) {
|
|
@@ -83576,6 +83848,60 @@ class GveHintDesigner extends HTMLElement {
|
|
|
83576
83848
|
background: #ffcdd2;
|
|
83577
83849
|
}
|
|
83578
83850
|
|
|
83851
|
+
/* Validation Message */
|
|
83852
|
+
.validation-message {
|
|
83853
|
+
padding: 0.75rem;
|
|
83854
|
+
margin: 0.5rem;
|
|
83855
|
+
background: #fff3cd;
|
|
83856
|
+
border: 1px solid #ffc107;
|
|
83857
|
+
border-radius: 4px;
|
|
83858
|
+
color: #856404;
|
|
83859
|
+
font-size: 13px;
|
|
83860
|
+
line-height: 1.5;
|
|
83861
|
+
}
|
|
83862
|
+
|
|
83863
|
+
.validation-message strong {
|
|
83864
|
+
display: block;
|
|
83865
|
+
margin-bottom: 0.5rem;
|
|
83866
|
+
color: #ff9800;
|
|
83867
|
+
}
|
|
83868
|
+
|
|
83869
|
+
.validation-message code {
|
|
83870
|
+
background: #fff;
|
|
83871
|
+
padding: 0.2rem 0.4rem;
|
|
83872
|
+
border-radius: 3px;
|
|
83873
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
83874
|
+
font-size: 12px;
|
|
83875
|
+
border: 1px solid #e0e0e0;
|
|
83876
|
+
}
|
|
83877
|
+
|
|
83878
|
+
.validation-message ul {
|
|
83879
|
+
margin: 0.5rem 0;
|
|
83880
|
+
}
|
|
83881
|
+
|
|
83882
|
+
.validation-message li {
|
|
83883
|
+
margin: 0.25rem 0;
|
|
83884
|
+
}
|
|
83885
|
+
|
|
83886
|
+
.validation-message em {
|
|
83887
|
+
display: block;
|
|
83888
|
+
margin-top: 0.5rem;
|
|
83889
|
+
font-size: 12px;
|
|
83890
|
+
color: #666;
|
|
83891
|
+
}
|
|
83892
|
+
|
|
83893
|
+
/* Warning Icon in Panel Header */
|
|
83894
|
+
.warning-icon {
|
|
83895
|
+
display: inline-flex;
|
|
83896
|
+
align-items: center;
|
|
83897
|
+
margin-left: 0.5rem;
|
|
83898
|
+
color: #ff9800;
|
|
83899
|
+
}
|
|
83900
|
+
|
|
83901
|
+
.warning-icon .feather-icon {
|
|
83902
|
+
display: block;
|
|
83903
|
+
}
|
|
83904
|
+
|
|
83579
83905
|
/* Responsive layout - use nested grids for each column */
|
|
83580
83906
|
@media (min-width: 900px) {
|
|
83581
83907
|
.properties-panel .panel-content {
|