uivisor 0.2.1 → 0.2.2
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/dist/overlay/index.js +316 -148
- package/package.json +1 -1
package/dist/overlay/index.js
CHANGED
|
@@ -255,8 +255,8 @@ function suggestUtility(property, value) {
|
|
|
255
255
|
return `${sp}-[${n}px]`;
|
|
256
256
|
}
|
|
257
257
|
if (property === "line-height") {
|
|
258
|
-
const
|
|
259
|
-
const unitless = /^(\d*\.?\d+)$/.exec(
|
|
258
|
+
const t2 = value.trim();
|
|
259
|
+
const unitless = /^(\d*\.?\d+)$/.exec(t2);
|
|
260
260
|
if (unitless) {
|
|
261
261
|
const named = {
|
|
262
262
|
"1": "leading-none",
|
|
@@ -266,16 +266,16 @@ function suggestUtility(property, value) {
|
|
|
266
266
|
"1.625": "leading-relaxed",
|
|
267
267
|
"2": "leading-loose"
|
|
268
268
|
};
|
|
269
|
-
return named[String(parseFloat(unitless[1]))] ?? `leading-[${
|
|
269
|
+
return named[String(parseFloat(unitless[1]))] ?? `leading-[${t2}]`;
|
|
270
270
|
}
|
|
271
|
-
const n = px(
|
|
271
|
+
const n = px(t2);
|
|
272
272
|
if (n != null) return `leading-[${n}px]`;
|
|
273
|
-
return `leading-[${
|
|
273
|
+
return `leading-[${t2}]`;
|
|
274
274
|
}
|
|
275
275
|
if (property === "letter-spacing") {
|
|
276
|
-
const
|
|
277
|
-
if (
|
|
278
|
-
const em = /^(-?\d*\.?\d+)em$/.exec(
|
|
276
|
+
const t2 = value.trim();
|
|
277
|
+
if (t2 === "normal" || t2 === "0" || t2 === "0px" || t2 === "0em") return "tracking-normal";
|
|
278
|
+
const em = /^(-?\d*\.?\d+)em$/.exec(t2);
|
|
279
279
|
if (em) {
|
|
280
280
|
const named = {
|
|
281
281
|
"-0.05": "tracking-tighter",
|
|
@@ -284,9 +284,9 @@ function suggestUtility(property, value) {
|
|
|
284
284
|
"0.05": "tracking-wider",
|
|
285
285
|
"0.1": "tracking-widest"
|
|
286
286
|
};
|
|
287
|
-
return named[String(parseFloat(em[1]))] ?? `tracking-[${
|
|
287
|
+
return named[String(parseFloat(em[1]))] ?? `tracking-[${t2}]`;
|
|
288
288
|
}
|
|
289
|
-
return `tracking-[${
|
|
289
|
+
return `tracking-[${t2}]`;
|
|
290
290
|
}
|
|
291
291
|
if (property === "color" || property === "background-color") {
|
|
292
292
|
const hex = rgbToHex(value) ?? (value.startsWith("#") ? value : null);
|
|
@@ -340,11 +340,11 @@ function suggestUtility(property, value) {
|
|
|
340
340
|
};
|
|
341
341
|
if (SIZE_PREFIX[property]) {
|
|
342
342
|
const pre = SIZE_PREFIX[property];
|
|
343
|
-
const
|
|
344
|
-
if (
|
|
345
|
-
if (
|
|
346
|
-
const n = px(
|
|
347
|
-
if (n == null) return `${pre}-[${
|
|
343
|
+
const t2 = value.trim();
|
|
344
|
+
if (t2 === "auto") return `${pre}-auto`;
|
|
345
|
+
if (t2 === "100%") return `${pre}-full`;
|
|
346
|
+
const n = px(t2);
|
|
347
|
+
if (n == null) return `${pre}-[${t2}]`;
|
|
348
348
|
const scale = n / 4;
|
|
349
349
|
if (Number.isInteger(scale) && scale >= 0 && scale <= 96) return `${pre}-${scale}`;
|
|
350
350
|
return `${pre}-[${n}px]`;
|
|
@@ -424,6 +424,8 @@ var SECTIONS = [
|
|
|
424
424
|
label: "Display",
|
|
425
425
|
options: ["block", "inline-block", "inline", "flex", "inline-flex", "grid", "inline-grid", "none"]
|
|
426
426
|
},
|
|
427
|
+
// Justify / Align are handled by the bigger visual button-rows injected right
|
|
428
|
+
// below Display (flexControlsHtml) — not duplicated here as plain selects.
|
|
427
429
|
{
|
|
428
430
|
kind: "select",
|
|
429
431
|
css: "flex-direction",
|
|
@@ -431,20 +433,6 @@ var SECTIONS = [
|
|
|
431
433
|
options: ["row", "row-reverse", "column", "column-reverse"],
|
|
432
434
|
requires: "flexgrid"
|
|
433
435
|
},
|
|
434
|
-
{
|
|
435
|
-
kind: "select",
|
|
436
|
-
css: "justify-content",
|
|
437
|
-
label: "Justify",
|
|
438
|
-
options: ["normal", "flex-start", "center", "flex-end", "space-between", "space-around", "space-evenly"],
|
|
439
|
-
requires: "flexgrid"
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
kind: "select",
|
|
443
|
-
css: "align-items",
|
|
444
|
-
label: "Align",
|
|
445
|
-
options: ["normal", "stretch", "flex-start", "center", "flex-end", "baseline"],
|
|
446
|
-
requires: "flexgrid"
|
|
447
|
-
},
|
|
448
436
|
{
|
|
449
437
|
kind: "select",
|
|
450
438
|
css: "flex-wrap",
|
|
@@ -666,7 +654,7 @@ function buildDesignSystem(vars, rootPx = 16) {
|
|
|
666
654
|
});
|
|
667
655
|
}
|
|
668
656
|
const byCategory = {};
|
|
669
|
-
for (const
|
|
657
|
+
for (const t2 of tokens) (byCategory[t2.category] ||= []).push(t2);
|
|
670
658
|
for (const cat of Object.keys(byCategory)) {
|
|
671
659
|
byCategory[cat].sort(
|
|
672
660
|
(a, b) => a.px != null && b.px != null ? a.px - b.px : a.name.localeCompare(b.name)
|
|
@@ -679,22 +667,22 @@ function nearestToken(ds, category, target) {
|
|
|
679
667
|
if (!list || !list.length) return null;
|
|
680
668
|
if (target.value != null) {
|
|
681
669
|
const norm = (s) => {
|
|
682
|
-
const
|
|
683
|
-
return (rgbToHex(
|
|
670
|
+
const t2 = s.trim();
|
|
671
|
+
return (rgbToHex(t2) || t2).replace(/\s+/g, "").toLowerCase();
|
|
684
672
|
};
|
|
685
673
|
const want = norm(target.value);
|
|
686
|
-
const hit = list.find((
|
|
674
|
+
const hit = list.find((t2) => norm(t2.value) === want);
|
|
687
675
|
if (hit) return { token: hit, exact: true };
|
|
688
676
|
}
|
|
689
|
-
if (target.px != null && list.some((
|
|
677
|
+
if (target.px != null && list.some((t2) => t2.px != null)) {
|
|
690
678
|
let best = list[0];
|
|
691
679
|
let bestD = Infinity;
|
|
692
|
-
for (const
|
|
693
|
-
if (
|
|
694
|
-
const d = Math.abs(
|
|
680
|
+
for (const t2 of list) {
|
|
681
|
+
if (t2.px == null) continue;
|
|
682
|
+
const d = Math.abs(t2.px - target.px);
|
|
695
683
|
if (d < bestD) {
|
|
696
684
|
bestD = d;
|
|
697
|
-
best =
|
|
685
|
+
best = t2;
|
|
698
686
|
}
|
|
699
687
|
}
|
|
700
688
|
return { token: best, exact: bestD < 0.5 };
|
|
@@ -805,6 +793,115 @@ function mk(primaryMechanism, evidence, sourceClassNames) {
|
|
|
805
793
|
return { primaryMechanism, evidence, sourceClassNames };
|
|
806
794
|
}
|
|
807
795
|
|
|
796
|
+
// src/overlay/i18n.ts
|
|
797
|
+
var RU = {
|
|
798
|
+
// chrome / buttons
|
|
799
|
+
"Toggle uivisor (Alt+U)": "\u0412\u043A\u043B/\u0432\u044B\u043A\u043B uivisor (Alt+U)",
|
|
800
|
+
"Turn uivisor off (Alt+U)": "\u0412\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C uivisor (Alt+U)",
|
|
801
|
+
Close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C",
|
|
802
|
+
"Drag to resize": "\u041F\u043E\u0442\u044F\u043D\u0438\u0442\u0435, \u0447\u0442\u043E\u0431\u044B \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0448\u0438\u0440\u0438\u043D\u0443",
|
|
803
|
+
"Drag to change": "\u041F\u043E\u0442\u044F\u043D\u0438\u0442\u0435, \u0447\u0442\u043E\u0431\u044B \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C",
|
|
804
|
+
"Copy prompt for agent": "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u043C\u043F\u0442 \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u0430",
|
|
805
|
+
"Copy JSON": "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C JSON",
|
|
806
|
+
Reset: "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C",
|
|
807
|
+
"Revert tweaks on selected element": "\u041E\u0442\u043A\u0430\u0442\u0438\u0442\u044C \u043F\u0440\u0430\u0432\u043A\u0438 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0433\u043E \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430",
|
|
808
|
+
Clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
|
|
809
|
+
"Clear all": "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0432\u0441\u0451",
|
|
810
|
+
Unit: "\u0415\u0434\u0438\u043D\u0438\u0446\u0430",
|
|
811
|
+
Token: "\u0422\u043E\u043A\u0435\u043D",
|
|
812
|
+
"pick token": "\u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u043E\u043A\u0435\u043D",
|
|
813
|
+
Mixed: "\u0440\u0430\u0437\u043D\u044B\u0435",
|
|
814
|
+
"Edit each side individually": "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u0436\u0434\u0443\u044E \u0441\u0442\u043E\u0440\u043E\u043D\u0443 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E",
|
|
815
|
+
// apply-changes-to
|
|
816
|
+
"Apply changes to": "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u043A",
|
|
817
|
+
"This element": "\u042D\u0442\u043E\u043C\u0443 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0443",
|
|
818
|
+
"Only this one": "\u0422\u043E\u043B\u044C\u043A\u043E \u044D\u0442\u043E\u043C\u0443",
|
|
819
|
+
"All {n} like this": "\u0412\u0441\u0435\u043C \u0442\u0430\u043A\u0438\u043C ({n})",
|
|
820
|
+
"New class\u2026": "\u041D\u043E\u0432\u044B\u0439 \u043A\u043B\u0430\u0441\u0441\u2026",
|
|
821
|
+
"new class name": "\u0438\u043C\u044F \u043D\u043E\u0432\u043E\u0433\u043E \u043A\u043B\u0430\u0441\u0441\u0430",
|
|
822
|
+
"Create a new class instead of touching the existing ones": "\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043B\u0430\u0441\u0441 \u0432\u043C\u0435\u0441\u0442\u043E \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445",
|
|
823
|
+
// legend
|
|
824
|
+
file: "\u0438\u0437 \u0444\u0430\u0439\u043B\u0430",
|
|
825
|
+
edited: "\u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043E",
|
|
826
|
+
inherited: "\u043D\u0430\u0441\u043B\u0435\u0434\u0443\u0435\u0442\u0441\u044F",
|
|
827
|
+
auto: "\u0430\u0432\u0442\u043E",
|
|
828
|
+
// empty / hint
|
|
829
|
+
"Click any element in the frame to select it.": "\u041A\u043B\u0438\u043A\u043D\u0438\u0442\u0435 \u043F\u043E \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0443 \u0432\u043E \u0444\u0440\u0435\u0439\u043C\u0435, \u0447\u0442\u043E\u0431\u044B \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0435\u0433\u043E.",
|
|
830
|
+
"Click any element on the page to select it.": "\u041A\u043B\u0438\u043A\u043D\u0438\u0442\u0435 \u043F\u043E \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0443 \u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435, \u0447\u0442\u043E\u0431\u044B \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0435\u0433\u043E.",
|
|
831
|
+
"Alt+U toggles \xB7 Esc deselects \xB7 \u2318/Ctrl+Z undo, \u21E7 to redo. Tweaks stay in the browser \u2014 nothing is written to your code.": "Alt+U \u2014 \u0432\u043A\u043B/\u0432\u044B\u043A\u043B \xB7 Esc \u2014 \u0441\u043D\u044F\u0442\u044C \u0432\u044B\u0431\u043E\u0440 \xB7 \u2318/Ctrl+Z \u2014 \u043E\u0442\u043C\u0435\u043D\u0438\u0442\u044C, \u21E7 \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C. \u041F\u0440\u0430\u0432\u043A\u0438 \u0436\u0438\u0432\u0443\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u2014 \u0432 \u043A\u043E\u0434 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043F\u0438\u0448\u0435\u0442\u0441\u044F.",
|
|
832
|
+
// floating "all styles" readout
|
|
833
|
+
"all styles": "\u0432\u0441\u0435 \u0441\u0442\u0438\u043B\u0438",
|
|
834
|
+
computed: "\u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u043E",
|
|
835
|
+
// design system
|
|
836
|
+
"Design system": "\u0414\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0430",
|
|
837
|
+
"tokens detected": "\u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u043D\u0430\u0439\u0434\u0435\u043D\u043E",
|
|
838
|
+
// frame readout
|
|
839
|
+
editing: "\u043F\u0440\u0430\u0432\u0438\u043C",
|
|
840
|
+
"No breakpoint \u2014 applies to every size by default": "\u0411\u0435\u0437 \u0431\u0440\u0435\u0439\u043A\u043F\u043E\u0438\u043D\u0442\u0430 \u2014 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0435\u0442\u0441\u044F \u043A\u043E \u0432\u0441\u0435\u043C \u0440\u0430\u0437\u043C\u0435\u0440\u0430\u043C",
|
|
841
|
+
// toasts
|
|
842
|
+
"No tweaks recorded yet": "\u041F\u043E\u043A\u0430 \u043D\u0435\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0439 \u043F\u0440\u0430\u0432\u043A\u0438",
|
|
843
|
+
"Prompt copied \u2713": "\u041F\u0440\u043E\u043C\u043F\u0442 \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D \u2713",
|
|
844
|
+
"JSON copied \u2713": "JSON \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D \u2713",
|
|
845
|
+
"Nothing to undo": "\u041D\u0435\u0447\u0435\u0433\u043E \u043E\u0442\u043C\u0435\u043D\u044F\u0442\u044C",
|
|
846
|
+
"Undo \u21A9": "\u041E\u0442\u043C\u0435\u043D\u0435\u043D\u043E \u21A9",
|
|
847
|
+
"Nothing to redo": "\u041D\u0435\u0447\u0435\u0433\u043E \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044C",
|
|
848
|
+
"Redo \u21AA": "\u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u043E \u21AA",
|
|
849
|
+
// section titles
|
|
850
|
+
Layout: "\u0420\u0430\u0441\u043A\u043B\u0430\u0434\u043A\u0430",
|
|
851
|
+
Size: "\u0420\u0430\u0437\u043C\u0435\u0440",
|
|
852
|
+
Spacing: "\u041E\u0442\u0441\u0442\u0443\u043F\u044B",
|
|
853
|
+
Border: "\u0413\u0440\u0430\u043D\u0438\u0446\u0430",
|
|
854
|
+
Typography: "\u0422\u0438\u043F\u043E\u0433\u0440\u0430\u0444\u0438\u043A\u0430",
|
|
855
|
+
Fill: "\u0417\u0430\u043B\u0438\u0432\u043A\u0430",
|
|
856
|
+
// control labels
|
|
857
|
+
Display: "\u0422\u0438\u043F",
|
|
858
|
+
Direction: "\u041D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435",
|
|
859
|
+
Justify: "\u0420\u0430\u0441\u043F\u0440\u0435\u0434.",
|
|
860
|
+
Align: "\u0412\u044B\u0440\u0430\u0432\u043D\u0438\u0432.",
|
|
861
|
+
Wrap: "\u041F\u0435\u0440\u0435\u043D\u043E\u0441",
|
|
862
|
+
Width: "\u0428\u0438\u0440\u0438\u043D\u0430",
|
|
863
|
+
Height: "\u0412\u044B\u0441\u043E\u0442\u0430",
|
|
864
|
+
"Max W": "\u041C\u0430\u043A\u0441 \u0428",
|
|
865
|
+
"Min H": "\u041C\u0438\u043D \u0412",
|
|
866
|
+
Padding: "\u0412\u043D\u0443\u0442\u0440. \u043E\u0442\u0441\u0442\u0443\u043F",
|
|
867
|
+
Margin: "\u0412\u043D\u0435\u0448\u043D. \u043E\u0442\u0441\u0442\u0443\u043F",
|
|
868
|
+
Gap: "\u041F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u043A",
|
|
869
|
+
Radius: "\u0421\u043A\u0440\u0443\u0433\u043B\u0435\u043D\u0438\u0435",
|
|
870
|
+
Weight: "\u041D\u0430\u0441\u044B\u0449\u0435\u043D\u043D\u043E\u0441\u0442\u044C",
|
|
871
|
+
Line: "\u0412\u044B\u0441\u043E\u0442\u0430 \u0441\u0442\u0440\u043E\u043A\u0438",
|
|
872
|
+
Text: "\u0422\u0435\u043A\u0441\u0442",
|
|
873
|
+
Background: "\u0424\u043E\u043D"
|
|
874
|
+
};
|
|
875
|
+
var DICT = { en: {}, ru: RU };
|
|
876
|
+
function detect() {
|
|
877
|
+
try {
|
|
878
|
+
const saved = localStorage.getItem("uiv-lang");
|
|
879
|
+
if (saved === "en" || saved === "ru") return saved;
|
|
880
|
+
} catch {
|
|
881
|
+
}
|
|
882
|
+
try {
|
|
883
|
+
if (typeof navigator !== "undefined" && /^ru\b/i.test(navigator.language || "")) return "ru";
|
|
884
|
+
} catch {
|
|
885
|
+
}
|
|
886
|
+
return "en";
|
|
887
|
+
}
|
|
888
|
+
var lang = detect();
|
|
889
|
+
function getLang() {
|
|
890
|
+
return lang;
|
|
891
|
+
}
|
|
892
|
+
function setLang(next) {
|
|
893
|
+
lang = next;
|
|
894
|
+
try {
|
|
895
|
+
localStorage.setItem("uiv-lang", next);
|
|
896
|
+
} catch {
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
function t(key, vars) {
|
|
900
|
+
let out = DICT[lang][key] ?? key;
|
|
901
|
+
if (vars) for (const k of Object.keys(vars)) out = out.replace(`{${k}}`, String(vars[k]));
|
|
902
|
+
return out;
|
|
903
|
+
}
|
|
904
|
+
|
|
808
905
|
// src/overlay/prompt.ts
|
|
809
906
|
function collapseChanges(changes) {
|
|
810
907
|
const byBp = groupByBreakpoint(changes);
|
|
@@ -1027,12 +1124,12 @@ var INTERNAL_COMPONENTS = /* @__PURE__ */ new Set([
|
|
|
1027
1124
|
function isInternalName(name) {
|
|
1028
1125
|
return INTERNAL_COMPONENTS.has(name) || /(?:Boundary|Router)$/.test(name) || name.startsWith("_");
|
|
1029
1126
|
}
|
|
1030
|
-
function fiberName(
|
|
1031
|
-
if (typeof
|
|
1032
|
-
if (
|
|
1033
|
-
const inner =
|
|
1034
|
-
if (typeof inner === "function") return
|
|
1035
|
-
if (typeof
|
|
1127
|
+
function fiberName(t2) {
|
|
1128
|
+
if (typeof t2 === "function") return t2.displayName || t2.name || null;
|
|
1129
|
+
if (t2 && typeof t2 === "object") {
|
|
1130
|
+
const inner = t2.type || t2.render;
|
|
1131
|
+
if (typeof inner === "function") return t2.displayName || inner.displayName || inner.name || null;
|
|
1132
|
+
if (typeof t2.displayName === "string") return t2.displayName;
|
|
1036
1133
|
}
|
|
1037
1134
|
return null;
|
|
1038
1135
|
}
|
|
@@ -1203,22 +1300,23 @@ var CSS = (
|
|
|
1203
1300
|
border-bottom: 1px solid #242428; position: sticky; top: 0; z-index: 5; background: #141416;
|
|
1204
1301
|
}
|
|
1205
1302
|
.uiv-head b { font-size: 13px; color: #fafafa; letter-spacing: .2px; }
|
|
1206
|
-
.uiv-
|
|
1303
|
+
.uiv-lang { margin-left: auto; cursor: pointer; font-size: 10px; font-weight: 700; letter-spacing: .4px;
|
|
1304
|
+
padding: 2px 7px; border-radius: 6px; background: #1c1c20; border: 1px solid #313138; color: #a1a1aa; }
|
|
1305
|
+
.uiv-lang:hover { color: #fff; border-color: #4f46e5; background: #26262c; }
|
|
1306
|
+
.uiv-bp { font-size: 10px; padding: 2px 8px; border-radius: 999px;
|
|
1207
1307
|
background: #312e81; color: #c7d2fe; font-weight: 600; }
|
|
1208
1308
|
.uiv-x { cursor: pointer; color: #71717a; padding: 2px 4px; }
|
|
1209
1309
|
.uiv-x:hover { color: #fff; }
|
|
1210
1310
|
|
|
1211
1311
|
.uiv-sec { padding: 11px 13px; border-bottom: 1px solid #1f1f22; }
|
|
1212
1312
|
|
|
1213
|
-
/* ---- Framer-style
|
|
1214
|
-
.uiv-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
.uiv-
|
|
1220
|
-
.uiv-tbtn.on { background: #312e81; border-color: #4f46e5; color: #fff; }
|
|
1221
|
-
.uiv-tsep { width: 1px; height: 16px; background: #2a2a2e; }
|
|
1313
|
+
/* ---- Framer-style flex/grid alignment buttons (Justify / Align rows) ---- */
|
|
1314
|
+
.uiv-fbtns { display: flex; gap: 5px; }
|
|
1315
|
+
.uiv-fbtn { flex: 1; display: flex; align-items: center; justify-content: center; height: 30px;
|
|
1316
|
+
border-radius: 8px; background: #1c1c20; border: 1px solid #313138; color: #8b8b94;
|
|
1317
|
+
cursor: pointer; transition: background .12s ease, color .12s ease, border-color .12s ease; }
|
|
1318
|
+
.uiv-fbtn:hover { background: #26262c; color: #e4e4e7; border-color: #45454d; }
|
|
1319
|
+
.uiv-fbtn.on { background: #312e81; border-color: #6366f1; color: #fff; box-shadow: 0 0 0 1px #4f46e5 inset; }
|
|
1222
1320
|
.uiv-empty { color: #71717a; padding: 18px 12px; text-align: center; }
|
|
1223
1321
|
|
|
1224
1322
|
.uiv-meta { line-height: 1.5; }
|
|
@@ -1242,14 +1340,20 @@ var CSS = (
|
|
|
1242
1340
|
.uiv-chip.on, .uiv-clschip.on { background: #4f46e5; border-color: #6366f1; color: #fff; }
|
|
1243
1341
|
.uiv-bphint { margin-top: 7px; font-size: 10px; color: #71717a; line-height: 1.4; }
|
|
1244
1342
|
.uiv-bphint b { color: #c7d2fe; }
|
|
1343
|
+
/* "Apply changes to" dropdown (sits outside .uiv-ctl, so style it directly) */
|
|
1344
|
+
.uiv-targetsel { width: 100%; box-sizing: border-box; cursor: pointer;
|
|
1345
|
+
background: #1c1c20; border: 1px solid #313138; color: #fff;
|
|
1346
|
+
border-radius: 7px; padding: 7px 9px; font-size: 12px; outline: none; }
|
|
1347
|
+
.uiv-targetsel:hover { border-color: #45454d; }
|
|
1348
|
+
.uiv-targetsel:focus { border-color: #6366f1; }
|
|
1245
1349
|
.uiv-newclass {
|
|
1246
|
-
|
|
1247
|
-
border
|
|
1350
|
+
margin-top: 7px; box-sizing: border-box; width: 100%;
|
|
1351
|
+
border: 1px dashed #52525b; background: transparent; color: #e4e4e7;
|
|
1352
|
+
border-radius: 7px; padding: 6px 9px; font-size: 12px; outline: none;
|
|
1248
1353
|
font-family: ui-monospace, monospace;
|
|
1249
1354
|
}
|
|
1250
1355
|
.uiv-newclass::placeholder { color: #71717a; }
|
|
1251
1356
|
.uiv-newclass:focus { border-style: solid; border-color: #6366f1; color: #fff; }
|
|
1252
|
-
.uiv-newclass.on { border-style: solid; border-color: #22d3ee; color: #fff; }
|
|
1253
1357
|
|
|
1254
1358
|
/* ---- design-system indicator + token pickers ---- */
|
|
1255
1359
|
.uiv-dsbar { padding: 7px 12px; border-bottom: 1px solid #27272a;
|
|
@@ -1323,8 +1427,9 @@ var CSS = (
|
|
|
1323
1427
|
.uiv-acc:hover .uiv-chev { color: #818cf8; }
|
|
1324
1428
|
.uiv-acc:not(.collapsed) .uiv-chev { transform: rotate(90deg); }
|
|
1325
1429
|
|
|
1326
|
-
.uiv-ctl { display: grid; grid-template-columns:
|
|
1430
|
+
.uiv-ctl { display: grid; grid-template-columns: 84px 1fr 26px; gap: 8px;
|
|
1327
1431
|
align-items: center; margin-bottom: 7px; }
|
|
1432
|
+
.uiv-ctl > .clabel { overflow: hidden; text-overflow: ellipsis; }
|
|
1328
1433
|
.uiv-ctl:last-child { margin-bottom: 0; }
|
|
1329
1434
|
.uiv-ctl > .clabel { font-size: 11px; color: #a1a1aa; }
|
|
1330
1435
|
.uiv-ctl > .cfield { min-width: 0; }
|
|
@@ -1385,7 +1490,7 @@ var CSS = (
|
|
|
1385
1490
|
.uiv-jchg .bp { color: #818cf8; }
|
|
1386
1491
|
.uiv-jchg .tok { color: #4ade80; }
|
|
1387
1492
|
|
|
1388
|
-
.uiv-foot { display: flex; gap: 6px; padding: 10px 12px; position: sticky; bottom: 0;
|
|
1493
|
+
.uiv-foot { display: flex; gap: 6px; padding: 10px 12px; position: sticky; bottom: 0; z-index: 8;
|
|
1389
1494
|
background: #18181b; border-top: 1px solid #27272a; flex-wrap: wrap; }
|
|
1390
1495
|
.uiv-btn { flex: 1; cursor: pointer; border: 1px solid #3f3f46; background: #27272a;
|
|
1391
1496
|
color: #e4e4e7; border-radius: 7px; padding: 7px 8px; font-size: 11px; font-weight: 600;
|
|
@@ -1394,10 +1499,11 @@ var CSS = (
|
|
|
1394
1499
|
.uiv-btn.primary { background: #4f46e5; border-color: #6366f1; color: #fff; flex-basis: 100%; }
|
|
1395
1500
|
.uiv-btn.primary:hover { background: #4338ca; }
|
|
1396
1501
|
.uiv-btn.ghost { flex: 0 0 auto; }
|
|
1397
|
-
/* floating read-only "all styles" block
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1502
|
+
/* floating read-only "all styles" block \u2014 top-LEFT of the screen, its top edge on
|
|
1503
|
+
the same line as the breakpoint toolbar (which is centred up top). */
|
|
1504
|
+
.uiv-info { position: fixed; left: 14px; top: 8px; z-index: 2147483646;
|
|
1505
|
+
width: 216px; max-height: 84vh; overflow: auto; display: none;
|
|
1506
|
+
background: rgba(24,24,27,0.92); color: #e4e4e7;
|
|
1401
1507
|
border: 1px solid #3f3f46; border-radius: 10px; padding: 8px 10px;
|
|
1402
1508
|
font-size: 11px; box-shadow: 0 8px 28px rgba(0,0,0,0.4); }
|
|
1403
1509
|
.uiv-info.show { display: block; }
|
|
@@ -1620,32 +1726,33 @@ var Uivisor = class {
|
|
|
1620
1726
|
this.root.innerHTML = `
|
|
1621
1727
|
<style>${CSS}</style>
|
|
1622
1728
|
<div class="uiv-framewrap">
|
|
1623
|
-
<div class="uiv-framebar"><div class="uiv-framechips uiv-chips"></div><span class="uiv-framew">768px</span><span class="uiv-framex" title="Turn uivisor off (Alt+U)">\u2715</span></div>
|
|
1729
|
+
<div class="uiv-framebar"><div class="uiv-framechips uiv-chips"></div><span class="uiv-framew">768px</span><span class="uiv-framex" title="${escapeAttr(t("Turn uivisor off (Alt+U)"))}">\u2715</span></div>
|
|
1624
1730
|
<div class="uiv-framestage">
|
|
1625
1731
|
<div class="uiv-framehost">
|
|
1626
1732
|
<iframe class="uiv-frame" data-uiv-frame="1"></iframe>
|
|
1627
|
-
<div class="uiv-framehandle" title="Drag to resize"></div>
|
|
1733
|
+
<div class="uiv-framehandle" title="${escapeAttr(t("Drag to resize"))}"></div>
|
|
1628
1734
|
</div>
|
|
1629
1735
|
</div>
|
|
1630
1736
|
</div>
|
|
1631
1737
|
<div class="uiv-box hover"></div>
|
|
1632
1738
|
<div class="uiv-box sel"></div>
|
|
1633
1739
|
<div class="uiv-tag"></div>
|
|
1634
|
-
<div class="uiv-fab" title="Toggle uivisor (Alt+U)">\u25CE</div>
|
|
1740
|
+
<div class="uiv-fab" title="${escapeAttr(t("Toggle uivisor (Alt+U)"))}">\u25CE</div>
|
|
1635
1741
|
<div class="uiv-info"></div>
|
|
1636
1742
|
<div class="uiv-toast"></div>
|
|
1637
1743
|
<div class="uiv-panel">
|
|
1638
1744
|
<div class="uiv-head">
|
|
1639
1745
|
<b>uivisor</b>
|
|
1746
|
+
<button class="uiv-lang" title="Language / \u042F\u0437\u044B\u043A">${getLang().toUpperCase()}</button>
|
|
1640
1747
|
<span class="uiv-bp">base</span>
|
|
1641
|
-
<span class="uiv-x" title="Close">\u2715</span>
|
|
1748
|
+
<span class="uiv-x" title="${escapeAttr(t("Close"))}">\u2715</span>
|
|
1642
1749
|
</div>
|
|
1643
1750
|
<div class="uiv-body"></div>
|
|
1644
1751
|
<div class="uiv-foot">
|
|
1645
|
-
<button class="uiv-btn primary copy-prompt"
|
|
1646
|
-
<button class="uiv-btn copy-json"
|
|
1647
|
-
<button class="uiv-btn ghost reset" title="Revert tweaks on selected element"
|
|
1648
|
-
<button class="uiv-btn ghost clear" title="Clear all"
|
|
1752
|
+
<button class="uiv-btn primary copy-prompt">${t("Copy prompt for agent")}</button>
|
|
1753
|
+
<button class="uiv-btn copy-json">${t("Copy JSON")}</button>
|
|
1754
|
+
<button class="uiv-btn ghost reset" title="${escapeAttr(t("Revert tweaks on selected element"))}">${t("Reset")}</button>
|
|
1755
|
+
<button class="uiv-btn ghost clear" title="${escapeAttr(t("Clear all"))}">${t("Clear")}</button>
|
|
1649
1756
|
</div>
|
|
1650
1757
|
</div>
|
|
1651
1758
|
`;
|
|
@@ -1660,6 +1767,7 @@ var Uivisor = class {
|
|
|
1660
1767
|
this.frame = this.q(".uiv-frame");
|
|
1661
1768
|
this.fab.addEventListener("click", () => this.toggle());
|
|
1662
1769
|
this.q(".uiv-x").addEventListener("click", () => this.toggle(false));
|
|
1770
|
+
this.q(".uiv-lang").addEventListener("click", () => this.setLanguage(getLang() === "ru" ? "en" : "ru"));
|
|
1663
1771
|
this.q(".uiv-framex").addEventListener("click", () => this.toggle(false));
|
|
1664
1772
|
this.q(".copy-prompt").addEventListener("click", () => this.copyPrompt());
|
|
1665
1773
|
this.q(".copy-json").addEventListener("click", () => this.copyJSON());
|
|
@@ -1698,6 +1806,29 @@ var Uivisor = class {
|
|
|
1698
1806
|
isOurs(e) {
|
|
1699
1807
|
return e.composedPath().includes(this.host);
|
|
1700
1808
|
}
|
|
1809
|
+
/** Switch the UI language: persist it, refresh the static chrome built once in
|
|
1810
|
+
* mount() (buttons, titles, the toggle label) and re-render the live panel. */
|
|
1811
|
+
setLanguage(next) {
|
|
1812
|
+
setLang(next);
|
|
1813
|
+
this.q(".uiv-lang").textContent = next.toUpperCase();
|
|
1814
|
+
this.q(".uiv-x").setAttribute("title", t("Close"));
|
|
1815
|
+
this.q(".uiv-framex").setAttribute("title", t("Turn uivisor off (Alt+U)"));
|
|
1816
|
+
this.q(".uiv-framehandle").setAttribute("title", t("Drag to resize"));
|
|
1817
|
+
this.fab.setAttribute("title", t("Toggle uivisor (Alt+U)"));
|
|
1818
|
+
this.q(".copy-prompt").textContent = t("Copy prompt for agent");
|
|
1819
|
+
this.q(".copy-json").textContent = t("Copy JSON");
|
|
1820
|
+
const reset = this.q(".reset");
|
|
1821
|
+
reset.textContent = t("Reset");
|
|
1822
|
+
reset.setAttribute("title", t("Revert tweaks on selected element"));
|
|
1823
|
+
const clear = this.q(".clear");
|
|
1824
|
+
clear.textContent = t("Clear");
|
|
1825
|
+
clear.setAttribute("title", t("Clear all"));
|
|
1826
|
+
this.renderBody();
|
|
1827
|
+
if (this.responsive) {
|
|
1828
|
+
this.renderFrameBar();
|
|
1829
|
+
this.setFrameWidth(this.frameWidth);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1701
1832
|
// ---- enable / disable ----
|
|
1702
1833
|
toggle(force) {
|
|
1703
1834
|
this.enabled = force ?? !this.enabled;
|
|
@@ -1712,12 +1843,12 @@ var Uivisor = class {
|
|
|
1712
1843
|
this.scheduleBpRefresh();
|
|
1713
1844
|
if (!this.responsive) {
|
|
1714
1845
|
this.pickedBp = "base";
|
|
1715
|
-
this.frameWidth = this.
|
|
1846
|
+
this.frameWidth = this.baseFrameWidth();
|
|
1716
1847
|
this.toggleResponsive(true);
|
|
1717
1848
|
}
|
|
1718
1849
|
}
|
|
1719
1850
|
}
|
|
1720
|
-
/**
|
|
1851
|
+
/** The real window width — used as the desktop reference for a desktop-first base. */
|
|
1721
1852
|
defaultFrameWidth() {
|
|
1722
1853
|
return typeof window !== "undefined" ? window.innerWidth : 1280;
|
|
1723
1854
|
}
|
|
@@ -1737,6 +1868,21 @@ var Uivisor = class {
|
|
|
1737
1868
|
};
|
|
1738
1869
|
for (const d of [250, 900, 2200]) window.setTimeout(refresh, d);
|
|
1739
1870
|
}
|
|
1871
|
+
/** Frame width for the "all"/base chip — the screen the project's UNPREFIXED
|
|
1872
|
+
* (base) styles target, which depends on the cascade direction:
|
|
1873
|
+
* • mobile-first (min-width) → base is the SMALLEST view → a phone width;
|
|
1874
|
+
* • desktop-first (max-width) → base is the WIDEST view → a desktop width.
|
|
1875
|
+
* The EDIT SCOPE stays decoupled (a base edit applies at every size regardless). */
|
|
1876
|
+
baseFrameWidth() {
|
|
1877
|
+
const sys = this.bpSystem();
|
|
1878
|
+
const bps = sys.breakpoints;
|
|
1879
|
+
if (sys.dir === "min") {
|
|
1880
|
+
const firstBp = bps.length ? bps[0].minWidth : 640;
|
|
1881
|
+
return Math.min(390, firstBp - 1);
|
|
1882
|
+
}
|
|
1883
|
+
const lastBp = bps.length ? bps[bps.length - 1].minWidth : 1024;
|
|
1884
|
+
return Math.max(this.defaultFrameWidth(), lastBp + 80);
|
|
1885
|
+
}
|
|
1740
1886
|
// ---- responsive (virtual screen) mode ----
|
|
1741
1887
|
/** The document the inspector currently targets: the iframe in responsive mode. */
|
|
1742
1888
|
doc() {
|
|
@@ -1815,7 +1961,7 @@ var Uivisor = class {
|
|
|
1815
1961
|
this.frameWidth = Math.max(280, Math.min(2400, Math.round(w)));
|
|
1816
1962
|
const host = this.q(".uiv-framehost");
|
|
1817
1963
|
host.style.width = `${this.frameWidth}px`;
|
|
1818
|
-
this.q(".uiv-framew").textContent = `${this.frameWidth}px \xB7 editing ${this.bpLabel(this.scopeName())}`;
|
|
1964
|
+
this.q(".uiv-framew").textContent = `${this.frameWidth}px \xB7 ${t("editing")} ${this.bpLabel(this.scopeName())}`;
|
|
1819
1965
|
this.updateBp();
|
|
1820
1966
|
this.reposition();
|
|
1821
1967
|
}
|
|
@@ -1875,9 +2021,10 @@ var Uivisor = class {
|
|
|
1875
2021
|
this.reposition();
|
|
1876
2022
|
this.renderBody();
|
|
1877
2023
|
}
|
|
1878
|
-
/** Properties to snapshot on selection — the curated set the controls can edit
|
|
2024
|
+
/** Properties to snapshot on selection — the curated set the controls can edit,
|
|
2025
|
+
* plus the flex-alignment props handled by the visual button-rows. */
|
|
1879
2026
|
snapshotProps() {
|
|
1880
|
-
return ALL_CSS;
|
|
2027
|
+
return [.../* @__PURE__ */ new Set([...ALL_CSS, "justify-content", "align-items"])];
|
|
1881
2028
|
}
|
|
1882
2029
|
// ---- value helpers ----
|
|
1883
2030
|
st() {
|
|
@@ -1916,8 +2063,8 @@ var Uivisor = class {
|
|
|
1916
2063
|
tokenNameFor(css) {
|
|
1917
2064
|
const ch = this.effectiveChange(css);
|
|
1918
2065
|
if (!ch?.after.designToken) return null;
|
|
1919
|
-
const
|
|
1920
|
-
return
|
|
2066
|
+
const t2 = this.designSystem().tokens.find((x) => x.cssVar === ch.after.designToken);
|
|
2067
|
+
return t2 ? t2.name : ch.after.designToken;
|
|
1921
2068
|
}
|
|
1922
2069
|
liveNum(css) {
|
|
1923
2070
|
const v = this.liveVal(css).trim();
|
|
@@ -2174,8 +2321,8 @@ var Uivisor = class {
|
|
|
2174
2321
|
if (!this.selected) {
|
|
2175
2322
|
body.innerHTML = `
|
|
2176
2323
|
${this.breakpointBarHtml()}
|
|
2177
|
-
<div class="uiv-empty"
|
|
2178
|
-
<div class="uiv-hint"
|
|
2324
|
+
<div class="uiv-empty">${t(this.responsive ? "Click any element in the frame to select it." : "Click any element on the page to select it.")}</div>
|
|
2325
|
+
<div class="uiv-hint">${t("Alt+U toggles \xB7 Esc deselects \xB7 \u2318/Ctrl+Z undo, \u21E7 to redo. Tweaks stay in the browser \u2014 nothing is written to your code.")}</div>
|
|
2179
2326
|
${this.journalHtml()}
|
|
2180
2327
|
`;
|
|
2181
2328
|
if (this.responsive) this.renderFrameBar();
|
|
@@ -2192,7 +2339,6 @@ var Uivisor = class {
|
|
|
2192
2339
|
<div class="uiv-src">${escapeHtml(src)}</div>
|
|
2193
2340
|
<span class="uiv-mech">${st.record.styling.primaryMechanism}</span>
|
|
2194
2341
|
</div>
|
|
2195
|
-
${this.alignToolbarHtml()}
|
|
2196
2342
|
${this.dsIndicatorHtml()}
|
|
2197
2343
|
${this.breakpointBarHtml()}
|
|
2198
2344
|
${this.targetHtml(st)}
|
|
@@ -2208,7 +2354,7 @@ var Uivisor = class {
|
|
|
2208
2354
|
const ds = this.designSystem();
|
|
2209
2355
|
if (ds.source === "none") return "";
|
|
2210
2356
|
const cats = Object.keys(ds.byCategory).map((c) => `${ds.byCategory[c].length} ${c}`).join(" \xB7 ");
|
|
2211
|
-
return `<div class="uiv-dsbar" title="${escapeAttr(cats)}">\u25C6 Design system \xB7 ${ds.tokens.length} tokens detected</div>`;
|
|
2357
|
+
return `<div class="uiv-dsbar" title="${escapeAttr(cats)}">\u25C6 ${t("Design system")} \xB7 ${ds.tokens.length} ${t("tokens detected")}</div>`;
|
|
2212
2358
|
}
|
|
2213
2359
|
/** Longhand properties an authoring rule (or non-uivisor inline) sets on `el`.
|
|
2214
2360
|
* Reimplements getMatchedCSSRules over same-origin sheets (incl. matching
|
|
@@ -2275,7 +2421,7 @@ var Uivisor = class {
|
|
|
2275
2421
|
ctlLabel(label, props) {
|
|
2276
2422
|
const from = this.inheritedFrom(props);
|
|
2277
2423
|
const badge = from ? ` <span class="uiv-inh" title="inherited from ${escapeAttr(this.bpLabel(from))} \u2014 not set at this breakpoint">\u2923${escapeHtml(this.bpLabel(from))}</span>` : "";
|
|
2278
|
-
return `<span class="clabel">${label}${badge}</span>`;
|
|
2424
|
+
return `<span class="clabel">${escapeHtml(t(label))}${badge}</span>`;
|
|
2279
2425
|
}
|
|
2280
2426
|
/** Is any of `props` authored in the project CSS? For inherited properties we
|
|
2281
2427
|
* also walk ancestors (a body/parent font rule still counts as "from the file"). */
|
|
@@ -2309,10 +2455,10 @@ var Uivisor = class {
|
|
|
2309
2455
|
return /^#|rgb/.test(h) ? `<span class="uiv-sw" style="background:${h}"></span>${h}` : h;
|
|
2310
2456
|
};
|
|
2311
2457
|
const sides = (parts) => {
|
|
2312
|
-
const [
|
|
2313
|
-
if (
|
|
2314
|
-
if (
|
|
2315
|
-
return `${
|
|
2458
|
+
const [t2, r, b, l] = parts.map(g);
|
|
2459
|
+
if (t2 === r && r === b && b === l) return t2;
|
|
2460
|
+
if (t2 === b && r === l) return `${t2} ${r}`;
|
|
2461
|
+
return `${t2} ${r} ${b} ${l}`;
|
|
2316
2462
|
};
|
|
2317
2463
|
const px4 = (pre, suf = "") => [`${pre}-top${suf}`, `${pre}-right${suf}`, `${pre}-bottom${suf}`, `${pre}-left${suf}`];
|
|
2318
2464
|
const clip = (s, n = 30) => s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
|
|
@@ -2415,7 +2561,7 @@ var Uivisor = class {
|
|
|
2415
2561
|
info.innerHTML = "";
|
|
2416
2562
|
return;
|
|
2417
2563
|
}
|
|
2418
|
-
info.innerHTML = `<div class="uiv-info-h"
|
|
2564
|
+
info.innerHTML = `<div class="uiv-info-h">${t("all styles")} <span class="uiv-info-sub">${t("computed")}</span></div><div class="uiv-readout">${this.styleRows()}</div>`;
|
|
2419
2565
|
info.classList.add("show");
|
|
2420
2566
|
}
|
|
2421
2567
|
/** Display label for a breakpoint name — the unprefixed "base" scope reads "all"
|
|
@@ -2439,7 +2585,7 @@ var Uivisor = class {
|
|
|
2439
2585
|
const winBp = currentBreakpoint(sys).name;
|
|
2440
2586
|
const isActive = (n) => this.responsive ? n === this.scopeName() : n === winBp;
|
|
2441
2587
|
const chip = (n, on, title) => `<button class="uiv-chip${on ? " on" : ""}" data-bp="${n}" title="${escapeAttr(title)}">${this.bpIcon(n)}<span>${this.bpLabel(n)}</span></button>`;
|
|
2442
|
-
const all = chip("base", isActive("base"), "No breakpoint \u2014 applies to every size by default");
|
|
2588
|
+
const all = chip("base", isActive("base"), t("No breakpoint \u2014 applies to every size by default"));
|
|
2443
2589
|
const rest = sys.breakpoints.map((b) => chip(b.name, isActive(b.name), sys.dir === "min" ? `\u2265 ${b.minWidth}px` : `\u2264 ${b.minWidth}px`)).join("");
|
|
2444
2590
|
return all + rest;
|
|
2445
2591
|
}
|
|
@@ -2467,12 +2613,10 @@ var Uivisor = class {
|
|
|
2467
2613
|
const isNew = target.startsWith("new:");
|
|
2468
2614
|
const newName = isNew ? target.slice(4) : "";
|
|
2469
2615
|
const n = st.record.identity.instanceCount;
|
|
2470
|
-
const
|
|
2471
|
-
const
|
|
2472
|
-
const
|
|
2473
|
-
|
|
2474
|
-
const newInput = `<input class="uiv-newclass${isNew ? " on" : ""}" placeholder="+ new class" value="${escapeAttr(newName)}" title="Create a new class instead of touching the existing ones">`;
|
|
2475
|
-
return `<div class="uiv-sec"><div class="uiv-sectitle">Apply changes to</div><div class="uiv-chips">${allChip}${elChip}${classChips}${newInput}</div></div>`;
|
|
2616
|
+
const opt = (val, label) => `<option value="${escapeAttr(val)}"${target === val ? " selected" : ""}>${escapeHtml(label)}</option>`;
|
|
2617
|
+
const opts = (n > 1 ? opt("all", t("All {n} like this", { n })) : "") + opt("element", n > 1 ? t("Only this one") : t("This element")) + classes.map((c) => opt(c, `.${c}`)).join("") + `<option value="__new__"${isNew ? " selected" : ""}>${escapeHtml(`\uFF0B ${t("New class\u2026")}`)}</option>`;
|
|
2618
|
+
const newInput = isNew ? `<input class="uiv-newclass" placeholder="${escapeAttr(t("new class name"))}" value="${escapeAttr(newName)}" title="${escapeAttr(t("Create a new class instead of touching the existing ones"))}" spellcheck="false">` : "";
|
|
2619
|
+
return `<div class="uiv-sec"><div class="uiv-sectitle">${t("Apply changes to")}</div><div class="cfield"><select class="uiv-sel uiv-targetsel">${opts}</select></div>${newInput}</div>`;
|
|
2476
2620
|
}
|
|
2477
2621
|
/** Decide which controls are relevant to the selected element. */
|
|
2478
2622
|
context(el) {
|
|
@@ -2494,28 +2638,35 @@ var Uivisor = class {
|
|
|
2494
2638
|
}
|
|
2495
2639
|
/** Framer-style top alignment toolbar — justify (horizontal) + align (vertical)
|
|
2496
2640
|
* icon buttons. Shown for flex/grid containers (where they apply). */
|
|
2497
|
-
|
|
2641
|
+
/** Visual flex/grid alignment controls — bigger Framer-style icon buttons in two
|
|
2642
|
+
* labelled rows (Justify, Align). Injected right below the Display dropdown and
|
|
2643
|
+
* shown only for flex/grid containers; replaces the duplicate Justify/Align
|
|
2644
|
+
* selects entirely. Commits through the engine via the shared `.uiv-fbtn` binding. */
|
|
2645
|
+
flexControlsHtml() {
|
|
2498
2646
|
const el = this.selected;
|
|
2499
2647
|
if (!el || !this.context(el).flexGrid) return "";
|
|
2500
2648
|
const j = this.liveVal("justify-content").trim();
|
|
2501
2649
|
const a = this.liveVal("align-items").trim();
|
|
2502
|
-
const g = (r) => `<svg viewBox="0 0
|
|
2503
|
-
const JI =
|
|
2504
|
-
"flex-start"
|
|
2505
|
-
center
|
|
2506
|
-
"flex-end"
|
|
2507
|
-
"space-between"
|
|
2508
|
-
|
|
2509
|
-
const AI =
|
|
2510
|
-
"flex-start"
|
|
2511
|
-
center
|
|
2512
|
-
"flex-end"
|
|
2513
|
-
stretch
|
|
2650
|
+
const g = (r) => `<svg viewBox="0 0 18 18" width="17" height="17" fill="currentColor">${r}</svg>`;
|
|
2651
|
+
const JI = [
|
|
2652
|
+
["flex-start", g('<rect x="2" y="4" width="2.4" height="10" rx="1"/><rect x="5.6" y="4" width="2.4" height="10" rx="1"/>')],
|
|
2653
|
+
["center", g('<rect x="5" y="4" width="2.4" height="10" rx="1"/><rect x="10.6" y="4" width="2.4" height="10" rx="1"/>')],
|
|
2654
|
+
["flex-end", g('<rect x="10" y="4" width="2.4" height="10" rx="1"/><rect x="13.6" y="4" width="2.4" height="10" rx="1"/>')],
|
|
2655
|
+
["space-between", g('<rect x="2" y="4" width="2.4" height="10" rx="1"/><rect x="13.6" y="4" width="2.4" height="10" rx="1"/>')]
|
|
2656
|
+
];
|
|
2657
|
+
const AI = [
|
|
2658
|
+
["flex-start", g('<rect x="4" y="2" width="10" height="2.4" rx="1"/><rect x="4" y="5.6" width="10" height="2.4" rx="1"/>')],
|
|
2659
|
+
["center", g('<rect x="4" y="5" width="10" height="2.4" rx="1"/><rect x="4" y="10.6" width="10" height="2.4" rx="1"/>')],
|
|
2660
|
+
["flex-end", g('<rect x="4" y="10" width="10" height="2.4" rx="1"/><rect x="4" y="13.6" width="10" height="2.4" rx="1"/>')],
|
|
2661
|
+
["stretch", g('<rect x="4" y="2" width="10" height="14" rx="1"/>')]
|
|
2662
|
+
];
|
|
2663
|
+
const row = (label, prop, cur, entries) => {
|
|
2664
|
+
const btns = entries.map(
|
|
2665
|
+
([v, ic]) => `<button class="uiv-fbtn${cur === v ? " on" : ""}" data-prop="${prop}" data-val="${v}" title="${prop}: ${v}">${ic}</button>`
|
|
2666
|
+
).join("");
|
|
2667
|
+
return `<div class="uiv-ctl${this.controlStateClass([prop])}">${this.ctlLabel(label, [prop])}<div class="cfield uiv-fbtns">${btns}</div><span></span></div>`;
|
|
2514
2668
|
};
|
|
2515
|
-
|
|
2516
|
-
const jb = Object.entries(JI).map(([v, ic]) => btn("justify-content", v, ic, j)).join("");
|
|
2517
|
-
const ab = Object.entries(AI).map(([v, ic]) => btn("align-items", v, ic, a)).join("");
|
|
2518
|
-
return `<div class="uiv-toolbar"><div class="uiv-tgroup">${jb}</div><div class="uiv-tsep"></div><div class="uiv-tgroup">${ab}</div></div>`;
|
|
2669
|
+
return row("Justify", "justify-content", j, JI) + row("Align", "align-items", a, AI);
|
|
2519
2670
|
}
|
|
2520
2671
|
/** Figma/Framer-style nested box-model widget: MARGIN ring around a PADDING ring,
|
|
2521
2672
|
* with an editable number on each of the 8 sides. Commits via the engine. */
|
|
@@ -2531,11 +2682,11 @@ var Uivisor = class {
|
|
|
2531
2682
|
return `<input class="uiv-bm-i ${pos}${this.controlStateClass([css])}${tok ? " uiv-bm-tok" : ""}" data-css="${css}" value="${escapeAttr(val)}" title="${escapeAttr(title)}" inputmode="decimal" spellcheck="false">`;
|
|
2532
2683
|
};
|
|
2533
2684
|
const spaceTokens = this.designSystem().byCategory["spacing"] ?? [];
|
|
2534
|
-
const pop = spaceTokens.length ? `<div class="uiv-bm-pop" hidden><span class="uiv-bm-poplabel"
|
|
2685
|
+
const pop = spaceTokens.length ? `<div class="uiv-bm-pop" hidden><span class="uiv-bm-poplabel">${t("Token")}</span>` + spaceTokens.map((tok) => `<button class="uiv-bm-chip" data-var="${escapeAttr(tok.cssVar)}" title="${escapeAttr(tok.value)}">${escapeHtml(tok.name)} \xB7 ${escapeHtml(tok.value)}</button>`).join("") + `</div>` : "";
|
|
2535
2686
|
return `<div class="uiv-bm"><span class="uiv-bm-tag">MARGIN</span>` + side("margin-top", "bm-top") + side("margin-right", "bm-right") + side("margin-bottom", "bm-bottom") + side("margin-left", "bm-left") + `<div class="uiv-bm-pad"><span class="uiv-bm-tag">PADDING</span>` + side("padding-top", "bm-top") + side("padding-right", "bm-right") + side("padding-bottom", "bm-bottom") + side("padding-left", "bm-left") + `<div class="uiv-bm-content"></div></div></div>` + pop;
|
|
2536
2687
|
}
|
|
2537
2688
|
controlsHtml(ctx) {
|
|
2538
|
-
const legend = `<div class="uiv-leg"><span class="uiv-lg"
|
|
2689
|
+
const legend = `<div class="uiv-leg"><span class="uiv-lg">${t("file")}</span><span class="uiv-lg edit">${t("edited")}</span><span class="uiv-lg inh">${t("inherited")}</span><span class="uiv-lg auto">${t("auto")}</span></div>`;
|
|
2539
2690
|
const secs = SECTIONS.map((sec) => {
|
|
2540
2691
|
const controls = sec.controls.filter((c) => this.relevant(c, ctx));
|
|
2541
2692
|
if (!controls.length) return "";
|
|
@@ -2548,9 +2699,10 @@ var Uivisor = class {
|
|
|
2548
2699
|
if (isSpacing && c.kind === "box" && (c.key === "padding" || c.key === "margin")) continue;
|
|
2549
2700
|
const css = c.css;
|
|
2550
2701
|
if (c.kind === "len" && c.hideWhenAuto && css && !this.revealedCtls.has(css) && this.controlState([css]) === "auto") {
|
|
2551
|
-
adds.push(`<button class="uiv-addctl" data-css="${css}">+ ${escapeHtml(c.label)}</button>`);
|
|
2702
|
+
adds.push(`<button class="uiv-addctl" data-css="${css}">+ ${escapeHtml(t(c.label))}</button>`);
|
|
2552
2703
|
} else {
|
|
2553
2704
|
rows.push(this.controlRow(c));
|
|
2705
|
+
if (css === "display") rows.push(this.flexControlsHtml());
|
|
2554
2706
|
}
|
|
2555
2707
|
}
|
|
2556
2708
|
const addRow = adds.length ? `<div class="uiv-adds">${adds.join("")}</div>` : "";
|
|
@@ -2561,10 +2713,10 @@ var Uivisor = class {
|
|
|
2561
2713
|
/** A collapsible section header. Clicking it hides/shows the section's controls. */
|
|
2562
2714
|
accordionTitle(title) {
|
|
2563
2715
|
const collapsed = this.collapsedSecs.has(title);
|
|
2564
|
-
return `<button class="uiv-sectitle uiv-acc${collapsed ? " collapsed" : ""}" data-sec="${escapeAttr(title)}"><span class="uiv-chev">${ICONS.chevron}</span>${title}</button>`;
|
|
2716
|
+
return `<button class="uiv-sectitle uiv-acc${collapsed ? " collapsed" : ""}" data-sec="${escapeAttr(title)}"><span class="uiv-chev">${ICONS.chevron}</span>${escapeHtml(t(title))}</button>`;
|
|
2565
2717
|
}
|
|
2566
2718
|
numField(cssAttr, value, handle, changed, isSide, placeholder) {
|
|
2567
|
-
return `<div class="uiv-num${changed ? " changed" : ""}" data-css="${cssAttr}"><span class="uiv-scrub${isSide ? " txt" : ""}" title="Drag to change">${handle}</span><input type="number" value="${escapeAttr(value)}" placeholder="${escapeAttr(placeholder)}"></div>`;
|
|
2719
|
+
return `<div class="uiv-num${changed ? " changed" : ""}" data-css="${cssAttr}"><span class="uiv-scrub${isSide ? " txt" : ""}" title="${escapeAttr(t("Drag to change"))}">${handle}</span><input type="number" value="${escapeAttr(value)}" placeholder="${escapeAttr(placeholder)}"></div>`;
|
|
2568
2720
|
}
|
|
2569
2721
|
fontSizePx() {
|
|
2570
2722
|
const el = this.selected;
|
|
@@ -2619,10 +2771,24 @@ var Uivisor = class {
|
|
|
2619
2771
|
if (unit === "%") return px2 / fs * 100;
|
|
2620
2772
|
return px2;
|
|
2621
2773
|
}
|
|
2774
|
+
/** A dim value's own number + unit ('' = unitless, e.g. line-height: 1.5). */
|
|
2775
|
+
parseDim(v) {
|
|
2776
|
+
const m = /^(-?\d*\.?\d+)(px|em|rem|%)?$/.exec(v.trim());
|
|
2777
|
+
return m ? { num: parseFloat(m[1]), unit: m[2] ?? "" } : null;
|
|
2778
|
+
}
|
|
2622
2779
|
dimDisplay(c) {
|
|
2623
2780
|
const st = this.st();
|
|
2624
|
-
const computed = this.liveVal(c.css);
|
|
2625
|
-
const
|
|
2781
|
+
const computed = this.liveVal(c.css).trim();
|
|
2782
|
+
const native = this.parseDim(computed);
|
|
2783
|
+
const picked = st.dimUnit[c.css];
|
|
2784
|
+
if (picked != null) {
|
|
2785
|
+
const px3 = this.currentPx(c.css);
|
|
2786
|
+
if (px3 != null) return { num: String(round2(this.pxToUnit(px3, picked))), unit: picked, placeholder: computed || "\u2014" };
|
|
2787
|
+
}
|
|
2788
|
+
if (native && c.units.includes(native.unit)) {
|
|
2789
|
+
return { num: String(round2(native.num)), unit: native.unit, placeholder: computed || "\u2014" };
|
|
2790
|
+
}
|
|
2791
|
+
const unit = picked ?? c.defaultUnit;
|
|
2626
2792
|
const px2 = this.currentPx(c.css);
|
|
2627
2793
|
if (px2 == null) return { num: "", unit, placeholder: computed || "normal" };
|
|
2628
2794
|
return { num: String(round2(this.pxToUnit(px2, unit))), unit, placeholder: computed || "\u2014" };
|
|
@@ -2631,7 +2797,7 @@ var Uivisor = class {
|
|
|
2631
2797
|
const d = this.dimDisplay(c);
|
|
2632
2798
|
const changed = this.isChanged([c.css]);
|
|
2633
2799
|
const units = c.units.map((u) => `<option value="${u}"${u === d.unit ? " selected" : ""}>${UNIT_LABELS[u] ?? u}</option>`).join("");
|
|
2634
|
-
return `<div class="uiv-ctl${this.controlStateClass([c.css])}">${this.ctlLabel(c.label, [c.css])}<div class="cfield"><div class="uiv-num uiv-dim${changed ? " changed" : ""}" data-css="${c.css}"><span class="uiv-scrub" title="Drag to change">${c.icon}</span><input type="number" step="any" value="${escapeAttr(d.num)}" placeholder="${escapeAttr(d.placeholder)}"><select class="uiv-unit" title="Unit">${units}</select></div></div><span></span></div>`;
|
|
2800
|
+
return `<div class="uiv-ctl${this.controlStateClass([c.css])}">${this.ctlLabel(c.label, [c.css])}<div class="cfield"><div class="uiv-num uiv-dim${changed ? " changed" : ""}" data-css="${c.css}"><span class="uiv-scrub" title="${escapeAttr(t("Drag to change"))}">${c.icon}</span><input type="number" step="any" value="${escapeAttr(d.num)}" placeholder="${escapeAttr(d.placeholder)}"><select class="uiv-unit" title="${escapeAttr(t("Unit"))}">${units}</select></div></div><span></span></div>`;
|
|
2635
2801
|
}
|
|
2636
2802
|
/** A design-token picker row for a property, shown only when the project exposes
|
|
2637
2803
|
* tokens for that category. Picking a token applies its value + tags the prompt. */
|
|
@@ -2647,17 +2813,17 @@ var Uivisor = class {
|
|
|
2647
2813
|
(c) => c.property === css && c.after.designToken
|
|
2648
2814
|
);
|
|
2649
2815
|
if (cat === "color") {
|
|
2650
|
-
const swatches = list.map((
|
|
2651
|
-
const on = near?.exact && near.token.cssVar ===
|
|
2652
|
-
return `<button class="uiv-swatch${on ? " on" : ""}" data-css="${css}" data-var="${escapeAttr(
|
|
2816
|
+
const swatches = list.map((tok) => {
|
|
2817
|
+
const on = near?.exact && near.token.cssVar === tok.cssVar;
|
|
2818
|
+
return `<button class="uiv-swatch${on ? " on" : ""}" data-css="${css}" data-var="${escapeAttr(tok.cssVar)}" title="${escapeAttr(`${tok.name} \xB7 ${tok.value}`)}" style="background:${escapeAttr(tok.value)}"></button>`;
|
|
2653
2819
|
}).join("");
|
|
2654
|
-
return `<div class="uiv-ctl"><span class="clabel uiv-tlabel">${label}</span><div class="cfield uiv-swatches">${swatches}</div><span></span></div>`;
|
|
2820
|
+
return `<div class="uiv-ctl"><span class="clabel uiv-tlabel">${escapeHtml(t(label))}</span><div class="cfield uiv-swatches">${swatches}</div><span></span></div>`;
|
|
2655
2821
|
}
|
|
2656
|
-
const head = `<option value="">${near && !near.exact ? `\u2248 ${escapeHtml(near.token.name)} \xB7 pick token` :
|
|
2822
|
+
const head = `<option value="">${near && !near.exact ? `\u2248 ${escapeHtml(near.token.name)} \xB7 ${t("pick token")}` : `\u2014 ${t("pick token")} \u2014`}</option>`;
|
|
2657
2823
|
const opts = list.map(
|
|
2658
|
-
(
|
|
2824
|
+
(tok) => `<option value="${escapeAttr(tok.cssVar)}"${near?.exact && near.token.cssVar === tok.cssVar ? " selected" : ""}>${escapeHtml(`${tok.name} \xB7 ${tok.value}`)}</option>`
|
|
2659
2825
|
).join("");
|
|
2660
|
-
return `<div class="uiv-ctl"><span class="clabel uiv-tlabel">${label}</span><div class="cfield"><select class="uiv-sel uiv-tokensel${edited ? " changed" : ""}" data-css="${css}">${head}${opts}</select></div><span></span></div>`;
|
|
2826
|
+
return `<div class="uiv-ctl"><span class="clabel uiv-tlabel">${escapeHtml(t(label))}</span><div class="cfield"><select class="uiv-sel uiv-tokensel${edited ? " changed" : ""}" data-css="${css}">${head}${opts}</select></div><span></span></div>`;
|
|
2661
2827
|
}
|
|
2662
2828
|
controlRow(c) {
|
|
2663
2829
|
if (c.kind === "box") {
|
|
@@ -2665,7 +2831,7 @@ var Uivisor = class {
|
|
|
2665
2831
|
const info = this.numInfo(cssList);
|
|
2666
2832
|
const changed = this.isChanged(cssList);
|
|
2667
2833
|
const open = this.expanded.has(c.key);
|
|
2668
|
-
let html = `<div class="uiv-ctl${this.controlStateClass(cssList)}">` + this.ctlLabel(c.label, cssList) + `<div class="cfield">${this.numField(cssList.join(","), info.mixed ? "" : info.value, c.icon, changed, false, info.mixed ? "Mixed" : "\u2014")}</div><button class="uiv-expand${open ? " on" : ""}" data-key="${c.key}" title="Edit each side individually">${open ? ICONS.collapse : ICONS.expand}</button></div>`;
|
|
2834
|
+
let html = `<div class="uiv-ctl${this.controlStateClass(cssList)}">` + this.ctlLabel(c.label, cssList) + `<div class="cfield">${this.numField(cssList.join(","), info.mixed ? "" : info.value, c.icon, changed, false, info.mixed ? t("Mixed") : "\u2014")}</div><button class="uiv-expand${open ? " on" : ""}" data-key="${c.key}" title="${escapeAttr(t("Edit each side individually"))}">${open ? ICONS.collapse : ICONS.expand}</button></div>`;
|
|
2669
2835
|
if (open) {
|
|
2670
2836
|
html += `<div class="uiv-sides">` + c.sides.map((s) => {
|
|
2671
2837
|
const v = this.liveNum(s.css);
|
|
@@ -2702,7 +2868,7 @@ var Uivisor = class {
|
|
|
2702
2868
|
}
|
|
2703
2869
|
bindControls() {
|
|
2704
2870
|
const root = this.root;
|
|
2705
|
-
root.querySelectorAll(".uiv-
|
|
2871
|
+
root.querySelectorAll(".uiv-fbtn").forEach((node) => {
|
|
2706
2872
|
const btn = node;
|
|
2707
2873
|
const prop = btn.getAttribute("data-prop");
|
|
2708
2874
|
const val = btn.getAttribute("data-val");
|
|
@@ -2770,7 +2936,7 @@ var Uivisor = class {
|
|
|
2770
2936
|
const cssVar = btn.getAttribute("data-var");
|
|
2771
2937
|
btn.addEventListener("mousedown", (e) => {
|
|
2772
2938
|
e.preventDefault();
|
|
2773
|
-
const token = this.designSystem().tokens.find((
|
|
2939
|
+
const token = this.designSystem().tokens.find((t2) => t2.cssVar === cssVar);
|
|
2774
2940
|
if (token) this.applyToken(this.lastBmSide, token);
|
|
2775
2941
|
});
|
|
2776
2942
|
});
|
|
@@ -2826,7 +2992,7 @@ var Uivisor = class {
|
|
|
2826
2992
|
const css = sel.getAttribute("data-css");
|
|
2827
2993
|
sel.addEventListener("change", () => {
|
|
2828
2994
|
if (!sel.value) return;
|
|
2829
|
-
const token = this.designSystem().tokens.find((
|
|
2995
|
+
const token = this.designSystem().tokens.find((t2) => t2.cssVar === sel.value);
|
|
2830
2996
|
if (token) this.applyToken(css, token);
|
|
2831
2997
|
});
|
|
2832
2998
|
});
|
|
@@ -2835,7 +3001,7 @@ var Uivisor = class {
|
|
|
2835
3001
|
const css = btn.getAttribute("data-css");
|
|
2836
3002
|
const cssVar = btn.getAttribute("data-var");
|
|
2837
3003
|
btn.addEventListener("click", () => {
|
|
2838
|
-
const token = this.designSystem().tokens.find((
|
|
3004
|
+
const token = this.designSystem().tokens.find((t2) => t2.cssVar === cssVar);
|
|
2839
3005
|
if (token) this.applyToken(css, token);
|
|
2840
3006
|
});
|
|
2841
3007
|
});
|
|
@@ -2870,22 +3036,24 @@ var Uivisor = class {
|
|
|
2870
3036
|
const bp = btn.getAttribute("data-bp");
|
|
2871
3037
|
btn.addEventListener("click", () => {
|
|
2872
3038
|
this.pickedBp = bp;
|
|
2873
|
-
this.setFrameWidth(bp === "base" ? this.
|
|
3039
|
+
this.setFrameWidth(bp === "base" ? this.baseFrameWidth() : this.scopeWidth(bp));
|
|
2874
3040
|
this.reapplyScope();
|
|
2875
3041
|
this.renderBody();
|
|
2876
3042
|
});
|
|
2877
3043
|
});
|
|
2878
|
-
root.
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
btn.addEventListener("click", () => {
|
|
3044
|
+
const targetSel = root.querySelector(".uiv-targetsel");
|
|
3045
|
+
if (targetSel) {
|
|
3046
|
+
targetSel.addEventListener("change", () => {
|
|
2882
3047
|
const st = this.st();
|
|
2883
|
-
if (st
|
|
2884
|
-
|
|
3048
|
+
if (!st) return;
|
|
3049
|
+
const next = targetSel.value === "__new__" ? st.record.target.startsWith("new:") ? st.record.target : "new:" : targetSel.value;
|
|
3050
|
+
if (st.record.target !== next) this.pushHistory();
|
|
3051
|
+
st.record.target = next;
|
|
2885
3052
|
this.reapplyForTarget();
|
|
2886
3053
|
this.renderBody();
|
|
3054
|
+
if (next === "new:") this.root.querySelector(".uiv-newclass")?.focus();
|
|
2887
3055
|
});
|
|
2888
|
-
}
|
|
3056
|
+
}
|
|
2889
3057
|
root.querySelectorAll(".uiv-newclass").forEach((node) => {
|
|
2890
3058
|
const input = node;
|
|
2891
3059
|
input.addEventListener("change", () => {
|
|
@@ -3041,13 +3209,13 @@ var Uivisor = class {
|
|
|
3041
3209
|
}
|
|
3042
3210
|
async copyPrompt() {
|
|
3043
3211
|
const recs = this.records();
|
|
3044
|
-
if (!recs.length) return this.showToast("No tweaks recorded yet");
|
|
3212
|
+
if (!recs.length) return this.showToast(t("No tweaks recorded yet"));
|
|
3045
3213
|
await this.copy(renderPrompt(recs));
|
|
3046
|
-
this.showToast("Prompt copied \u2713");
|
|
3214
|
+
this.showToast(t("Prompt copied \u2713"));
|
|
3047
3215
|
}
|
|
3048
3216
|
async copyJSON() {
|
|
3049
3217
|
const recs = this.records();
|
|
3050
|
-
if (!recs.length) return this.showToast("No tweaks recorded yet");
|
|
3218
|
+
if (!recs.length) return this.showToast(t("No tweaks recorded yet"));
|
|
3051
3219
|
const spec = renderSpec(recs, {
|
|
3052
3220
|
url: location.href,
|
|
3053
3221
|
width: window.innerWidth,
|
|
@@ -3056,7 +3224,7 @@ var Uivisor = class {
|
|
|
3056
3224
|
now: (/* @__PURE__ */ new Date()).toISOString()
|
|
3057
3225
|
});
|
|
3058
3226
|
await this.copy(JSON.stringify(spec, null, 2));
|
|
3059
|
-
this.showToast("JSON copied \u2713");
|
|
3227
|
+
this.showToast(t("JSON copied \u2713"));
|
|
3060
3228
|
}
|
|
3061
3229
|
resetSelected() {
|
|
3062
3230
|
const el = this.selected;
|
|
@@ -3120,16 +3288,16 @@ var Uivisor = class {
|
|
|
3120
3288
|
this.renderBody();
|
|
3121
3289
|
}
|
|
3122
3290
|
undo() {
|
|
3123
|
-
if (!this.undoStack.length) return this.showToast("Nothing to undo");
|
|
3291
|
+
if (!this.undoStack.length) return this.showToast(t("Nothing to undo"));
|
|
3124
3292
|
this.redoStack.push(this.cloneSnap());
|
|
3125
3293
|
this.applySnap(this.undoStack.pop());
|
|
3126
|
-
this.showToast("Undo \u21A9");
|
|
3294
|
+
this.showToast(t("Undo \u21A9"));
|
|
3127
3295
|
}
|
|
3128
3296
|
redo() {
|
|
3129
|
-
if (!this.redoStack.length) return this.showToast("Nothing to redo");
|
|
3297
|
+
if (!this.redoStack.length) return this.showToast(t("Nothing to redo"));
|
|
3130
3298
|
this.undoStack.push(this.cloneSnap());
|
|
3131
3299
|
this.applySnap(this.redoStack.pop());
|
|
3132
|
-
this.showToast("Redo \u21AA");
|
|
3300
|
+
this.showToast(t("Redo \u21AA"));
|
|
3133
3301
|
}
|
|
3134
3302
|
async copy(text) {
|
|
3135
3303
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uivisor",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dev-only visual UI tweaker that turns mouse edits into a precise, breakpoint-aware prompt for your AI coding agent — without touching your source.",
|
|
6
6
|
"license": "MIT",
|