mevebu 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/mevebu/app/mevebu.js +260 -208
  2. package/mevebu/app/tailwind.css +1639 -2077
  3. package/mevebu/app/tailwind.src.css +155 -1120
  4. package/mevebu/index.html +2 -2
  5. package/mevebu/libs/js/core.js +236 -96
  6. package/mevebu/libs/js/registry.js +11 -11
  7. package/mevebu/libs/js/tools/abstract-checklist.js +5 -7
  8. package/mevebu/libs/js/tools/add-subtract-days.js +9 -11
  9. package/mevebu/libs/js/tools/age-calculator.js +7 -8
  10. package/mevebu/libs/js/tools/api-request-builder.js +3 -4
  11. package/mevebu/libs/js/tools/area-converter.js +7 -9
  12. package/mevebu/libs/js/tools/aspect-ratio.js +8 -9
  13. package/mevebu/libs/js/tools/average-calculator.js +4 -5
  14. package/mevebu/libs/js/tools/base64.js +31 -11
  15. package/mevebu/libs/js/tools/binary-calculator.js +6 -7
  16. package/mevebu/libs/js/tools/border-radius.js +7 -9
  17. package/mevebu/libs/js/tools/box-shadow.js +6 -7
  18. package/mevebu/libs/js/tools/break-even.js +4 -5
  19. package/mevebu/libs/js/tools/business-days.js +7 -8
  20. package/mevebu/libs/js/tools/canonical-tag.js +5 -6
  21. package/mevebu/libs/js/tools/caption-counter.js +5 -7
  22. package/mevebu/libs/js/tools/case-converter.js +11 -12
  23. package/mevebu/libs/js/tools/case-inspector.js +14 -16
  24. package/mevebu/libs/js/tools/cash-denomination.js +7 -8
  25. package/mevebu/libs/js/tools/cash-flow.js +7 -8
  26. package/mevebu/libs/js/tools/cert-expiry.js +6 -10
  27. package/mevebu/libs/js/tools/changelog-generator.js +4 -6
  28. package/mevebu/libs/js/tools/character-counter.js +10 -13
  29. package/mevebu/libs/js/tools/checklist.js +6 -7
  30. package/mevebu/libs/js/tools/citation-number-check.js +10 -13
  31. package/mevebu/libs/js/tools/coin-flip.js +9 -11
  32. package/mevebu/libs/js/tools/color-converter.js +23 -17
  33. package/mevebu/libs/js/tools/color-palette.js +6 -8
  34. package/mevebu/libs/js/tools/color-picker.js +4 -5
  35. package/mevebu/libs/js/tools/content-calendar.js +3 -4
  36. package/mevebu/libs/js/tools/contrast-checker.js +5 -6
  37. package/mevebu/libs/js/tools/cron-builder.js +4 -6
  38. package/mevebu/libs/js/tools/css-clamp.js +5 -6
  39. package/mevebu/libs/js/tools/css-formatter.js +4 -7
  40. package/mevebu/libs/js/tools/css-grid.js +6 -7
  41. package/mevebu/libs/js/tools/css-minifier.js +5 -8
  42. package/mevebu/libs/js/tools/csv-to-json.js +2 -3
  43. package/mevebu/libs/js/tools/csv-viewer.js +9 -11
  44. package/mevebu/libs/js/tools/currency-format.js +5 -7
  45. package/mevebu/libs/js/tools/daily-planner.js +9 -10
  46. package/mevebu/libs/js/tools/data-masker.js +7 -9
  47. package/mevebu/libs/js/tools/data-storage.js +7 -9
  48. package/mevebu/libs/js/tools/data-validator.js +9 -11
  49. package/mevebu/libs/js/tools/date-difference.js +6 -7
  50. package/mevebu/libs/js/tools/date-format.js +11 -13
  51. package/mevebu/libs/js/tools/delimiter-converter.js +3 -5
  52. package/mevebu/libs/js/tools/discount-calculator.js +4 -5
  53. package/mevebu/libs/js/tools/doi-resolver.js +4 -5
  54. package/mevebu/libs/js/tools/env-formatter.js +3 -6
  55. package/mevebu/libs/js/tools/equation-formatter.js +5 -9
  56. package/mevebu/libs/js/tools/expense-split.js +6 -7
  57. package/mevebu/libs/js/tools/fake-data.js +20 -13
  58. package/mevebu/libs/js/tools/find-replace.js +3 -5
  59. package/mevebu/libs/js/tools/flashcard-creator.js +9 -10
  60. package/mevebu/libs/js/tools/font-pairing.js +6 -8
  61. package/mevebu/libs/js/tools/fraction-calculator.js +10 -13
  62. package/mevebu/libs/js/tools/git-command-builder.js +11 -22
  63. package/mevebu/libs/js/tools/gpa-calculator.js +8 -10
  64. package/mevebu/libs/js/tools/grade-calculator.js +7 -8
  65. package/mevebu/libs/js/tools/gradient-generator.js +10 -12
  66. package/mevebu/libs/js/tools/habit-tracker.js +8 -9
  67. package/mevebu/libs/js/tools/hash-generator.js +3 -5
  68. package/mevebu/libs/js/tools/hashtag-formatter.js +6 -8
  69. package/mevebu/libs/js/tools/hmac-generator.js +3 -5
  70. package/mevebu/libs/js/tools/hpp-calculator.js +4 -5
  71. package/mevebu/libs/js/tools/html-entity.js +2 -3
  72. package/mevebu/libs/js/tools/html-formatter.js +3 -6
  73. package/mevebu/libs/js/tools/http-status.js +5 -7
  74. package/mevebu/libs/js/tools/inventory-quantity.js +7 -8
  75. package/mevebu/libs/js/tools/json-formatter.js +3 -6
  76. package/mevebu/libs/js/tools/json-minifier.js +5 -8
  77. package/mevebu/libs/js/tools/json-to-csv.js +3 -5
  78. package/mevebu/libs/js/tools/json-to-typescript.js +2 -5
  79. package/mevebu/libs/js/tools/json-validator.js +2 -3
  80. package/mevebu/libs/js/tools/jwt-decoder.js +6 -7
  81. package/mevebu/libs/js/tools/jwt-expiry.js +5 -6
  82. package/mevebu/libs/js/tools/jwt-generator.js +4 -6
  83. package/mevebu/libs/js/tools/length-converter.js +7 -9
  84. package/mevebu/libs/js/tools/license-reference.js +10 -13
  85. package/mevebu/libs/js/tools/line-counter.js +5 -7
  86. package/mevebu/libs/js/tools/list-difference.js +5 -7
  87. package/mevebu/libs/js/tools/list-merger.js +4 -5
  88. package/mevebu/libs/js/tools/locale-number.js +5 -8
  89. package/mevebu/libs/js/tools/lorem-ipsum.js +4 -2
  90. package/mevebu/libs/js/tools/markdown-preview.js +5 -8
  91. package/mevebu/libs/js/tools/markdown-table.js +5 -7
  92. package/mevebu/libs/js/tools/markup-calculator.js +4 -5
  93. package/mevebu/libs/js/tools/meeting-agenda.js +8 -9
  94. package/mevebu/libs/js/tools/meta-preview.js +12 -13
  95. package/mevebu/libs/js/tools/meta-tags.js +6 -7
  96. package/mevebu/libs/js/tools/mime-types.js +5 -7
  97. package/mevebu/libs/js/tools/name-picker.js +2 -3
  98. package/mevebu/libs/js/tools/number-base-converter.js +9 -12
  99. package/mevebu/libs/js/tools/password-generator.js +9 -12
  100. package/mevebu/libs/js/tools/password-strength.js +21 -25
  101. package/mevebu/libs/js/tools/percent-to-fraction.js +6 -7
  102. package/mevebu/libs/js/tools/percentage-calculator.js +6 -9
  103. package/mevebu/libs/js/tools/percentage-change.js +4 -5
  104. package/mevebu/libs/js/tools/permutation-combination.js +9 -12
  105. package/mevebu/libs/js/tools/prefix-suffix.js +2 -3
  106. package/mevebu/libs/js/tools/priority-matrix.js +6 -10
  107. package/mevebu/libs/js/tools/profit-margin.js +4 -5
  108. package/mevebu/libs/js/tools/qr-generator.js +3 -4
  109. package/mevebu/libs/js/tools/qr-scanner.js +11 -12
  110. package/mevebu/libs/js/tools/quadratic-solver.js +7 -8
  111. package/mevebu/libs/js/tools/query-builder.js +2 -3
  112. package/mevebu/libs/js/tools/quiz-formatter.js +4 -6
  113. package/mevebu/libs/js/tools/ratio-calculator.js +7 -8
  114. package/mevebu/libs/js/tools/readability.js +12 -15
  115. package/mevebu/libs/js/tools/reading-time.js +5 -7
  116. package/mevebu/libs/js/tools/reference-completeness.js +6 -8
  117. package/mevebu/libs/js/tools/regex-tester.js +7 -10
  118. package/mevebu/libs/js/tools/remove-duplicate-lines.js +2 -3
  119. package/mevebu/libs/js/tools/remove-extra-spaces.js +3 -5
  120. package/mevebu/libs/js/tools/robots-txt.js +3 -4
  121. package/mevebu/libs/js/tools/roman-numeral-converter.js +6 -8
  122. package/mevebu/libs/js/tools/sales-commission.js +8 -9
  123. package/mevebu/libs/js/tools/scientific-calculator.js +10 -14
  124. package/mevebu/libs/js/tools/scientific-notation.js +8 -9
  125. package/mevebu/libs/js/tools/script-planner.js +8 -10
  126. package/mevebu/libs/js/tools/selling-price.js +4 -5
  127. package/mevebu/libs/js/tools/semver-helper.js +3 -5
  128. package/mevebu/libs/js/tools/sentence-length.js +9 -10
  129. package/mevebu/libs/js/tools/sequence-analyzer.js +7 -8
  130. package/mevebu/libs/js/tools/sitemap-xml.js +4 -7
  131. package/mevebu/libs/js/tools/slug-converter.js +3 -5
  132. package/mevebu/libs/js/tools/slug-preview.js +6 -7
  133. package/mevebu/libs/js/tools/sort-lines.js +3 -5
  134. package/mevebu/libs/js/tools/speed-converter.js +7 -9
  135. package/mevebu/libs/js/tools/spin-wheel.js +19 -17
  136. package/mevebu/libs/js/tools/sql-formatter.js +5 -9
  137. package/mevebu/libs/js/tools/sql-minifier.js +5 -8
  138. package/mevebu/libs/js/tools/standard-deviation.js +6 -9
  139. package/mevebu/libs/js/tools/stopwatch.js +4 -6
  140. package/mevebu/libs/js/tools/study-schedule.js +8 -9
  141. package/mevebu/libs/js/tools/subtitle-formatter.js +10 -11
  142. package/mevebu/libs/js/tools/table-to-markdown.js +8 -12
  143. package/mevebu/libs/js/tools/tax-calculator.js +4 -5
  144. package/mevebu/libs/js/tools/temperature-converter.js +8 -11
  145. package/mevebu/libs/js/tools/text-diff.js +11 -7
  146. package/mevebu/libs/js/tools/text-direction.js +3 -5
  147. package/mevebu/libs/js/tools/text-reverser.js +3 -5
  148. package/mevebu/libs/js/tools/time-duration.js +8 -9
  149. package/mevebu/libs/js/tools/timestamp-converter.js +4 -6
  150. package/mevebu/libs/js/tools/timezone-converter.js +9 -13
  151. package/mevebu/libs/js/tools/title-length.js +6 -7
  152. package/mevebu/libs/js/tools/unicode-inspector.js +4 -5
  153. package/mevebu/libs/js/tools/url-encoder.js +4 -2
  154. package/mevebu/libs/js/tools/url-inspector.js +9 -11
  155. package/mevebu/libs/js/tools/url-parser.js +12 -13
  156. package/mevebu/libs/js/tools/utf8-bytes.js +6 -9
  157. package/mevebu/libs/js/tools/uuid-generator.js +107 -15
  158. package/mevebu/libs/js/tools/version-compare.js +3 -4
  159. package/mevebu/libs/js/tools/video-duration.js +5 -7
  160. package/mevebu/libs/js/tools/volume-converter.js +7 -9
  161. package/mevebu/libs/js/tools/weekly-planner.js +8 -10
  162. package/mevebu/libs/js/tools/weight-converter.js +7 -9
  163. package/mevebu/libs/js/tools/weighted-average.js +4 -5
  164. package/mevebu/libs/js/tools/word-counter.js +10 -13
  165. package/mevebu/libs/js/tools/word-limit.js +4 -5
  166. package/mevebu/libs/js/tools/yaml-formatter.js +6 -7
  167. package/package.json +1 -1
@@ -5,8 +5,7 @@ const BASES = [
5
5
  { value: "2", label: "Binary" },
6
6
  { value: "8", label: "Octal" },
7
7
  { value: "10", label: "Decimal" },
8
- { value: "16", label: "Hex" },
9
- ];
8
+ { value: "16", label: "Hex" }];
10
9
 
11
10
  const PATTERNS = { 2: /^[01]+$/, 8: /^[0-7]+$/, 10: /^[0-9]+$/, 16: /^[0-9a-f]+$/ };
12
11
  const PREFIX = { 2: "0b", 8: "0o", 10: "", 16: "0x" };
@@ -23,17 +22,17 @@ function parseInBase(text, base) {
23
22
  }
24
23
 
25
24
  const kvRow = (key, value) =>
26
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), el("span", { class: "mvb-kv__v" }, value));
25
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, key), el("span", { class: "wrap-anywhere font-mono text-2xs" }, value));
27
26
 
28
27
  export function mount(slot) {
29
28
  const source = textInput({ value: "255", "aria-label": "Number", placeholder: "255" });
30
- const binary = el("span", { class: "mvb-kv__v" }, "-");
31
- const octal = el("span", { class: "mvb-kv__v" }, "-");
32
- const decimal = el("span", { class: "mvb-kv__v" }, "-");
33
- const hex = el("span", { class: "mvb-kv__v" }, "-");
29
+ const binary = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
30
+ const octal = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
31
+ const decimal = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
32
+ const hex = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
34
33
  const kv = el(
35
34
  "div",
36
- { class: "mvb-kv" },
35
+ { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
37
36
  kvRow("Binary", binary),
38
37
  kvRow("Octal", octal),
39
38
  kvRow("Decimal", decimal),
@@ -76,8 +75,7 @@ export function mount(slot) {
76
75
  onChange: (value) => {
77
76
  base = value;
78
77
  run();
79
- },
80
- });
78
+ }});
81
79
 
82
80
  source.addEventListener("input", run);
83
81
 
@@ -86,8 +84,7 @@ export function mount(slot) {
86
84
  stack(panel("Number", source), panel("Input base", chips), error),
87
85
  stack(panel("In every base", kv))
88
86
  ),
89
- foot: actions(copyButton(() => text, "Copy all", "fill")),
90
- });
87
+ foot: actions(copyButton(() => text, "Copy all", "fill"))});
91
88
  slot.append(card.node);
92
89
  run();
93
90
 
@@ -5,12 +5,11 @@ const SETS = {
5
5
  lower: "abcdefghijklmnopqrstuvwxyz",
6
6
  upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
7
7
  digits: "0123456789",
8
- symbols: "!@#$%^&*()-_=+[]{};:,.<>?",
9
- };
8
+ symbols: "!@#$%^&*()-_=+[]{};:,.<>?"};
10
9
 
11
10
  export function mount(slot) {
12
11
  const lengthField = rangeInput({ min: "6", max: "64", value: "16", "aria-label": "Length" });
13
- const lengthLabel = el("span", { class: "mvb-field__label" });
12
+ const lengthLabel = el("span", { class: "text-sm font-semibold text-ink-2" });
14
13
 
15
14
  function showLength() {
16
15
  lengthLabel.textContent = `Length: ${lengthField.value}`;
@@ -20,11 +19,10 @@ export function mount(slot) {
20
19
  { value: "lower", label: "a to z" },
21
20
  { value: "upper", label: "A to Z" },
22
21
  { value: "digits", label: "0 to 9" },
23
- { value: "symbols", label: "Symbols" },
24
- ]);
22
+ { value: "symbols", label: "Symbols" }]);
25
23
 
26
- const secret = textInput({ class: "mvb-in mvb-in--mono", readonly: true, "aria-label": "Password", placeholder: "Press Generate" });
27
- const meter = el("div", { class: "mvb-meter", role: "img", "aria-label": "Strength" }, el("div", { class: "mvb-meter__fill" }));
24
+ const secret = textInput({ mono: true, readonly: true, "aria-label": "Password", placeholder: "Press Generate" });
25
+ const meter = el("div", { class: "h-2 overflow-hidden rounded-full bg-deck-2", role: "img", "aria-label": "Strength" }, el("div", { class: "h-full w-0 rounded-full bg-orbit-hard transition-[width,background-color] duration-150 data-[level=weak]:bg-danger data-[level=ok]:bg-star data-[level=strong]:bg-jade" }));
28
26
  const strength = notice("note");
29
27
  const error = notice("error");
30
28
 
@@ -37,11 +35,11 @@ export function mount(slot) {
37
35
 
38
36
  function draw() {
39
37
  const source = pool();
40
- const fill = meter.querySelector(".mvb-meter__fill");
38
+ const fill = meter.firstElementChild;
41
39
  if (!source) {
42
40
  secret.value = "";
43
41
  fill.style.width = "0%";
44
- fill.className = "mvb-meter__fill";
42
+ delete fill.dataset.level;
45
43
  meter.setAttribute("aria-label", "Strength");
46
44
  strength.write("");
47
45
  error.write("Pick at least one group above.");
@@ -65,7 +63,7 @@ export function mount(slot) {
65
63
  const bits = Math.round(length * Math.log2(source.length));
66
64
  const word = bits < 50 ? "weak" : bits < 90 ? "good" : "strong";
67
65
  fill.style.width = `${Math.min(100, (bits / 128) * 100)}%`;
68
- fill.className = `mvb-meter__fill ${bits < 50 ? "mvb-weak" : bits < 90 ? "mvb-ok" : "mvb-strong"}`;
66
+ fill.dataset.level = bits < 50 ? "weak" : bits < 90 ? "ok" : "strong";
69
67
  // The bar is colour only, so the reading it stands for also goes on the bar itself.
70
68
  meter.setAttribute("aria-label", `Strength: ${bits} bits, ${word}`);
71
69
  strength.write(`${bits} bits, ${word}.`);
@@ -84,8 +82,7 @@ export function mount(slot) {
84
82
  stack(panel(lengthLabel, lengthField), groups, error),
85
83
  stack(panel("Password", secret), meter, strength)
86
84
  ),
87
- foot: actions(copyButton, generateButton),
88
- });
85
+ foot: actions(copyButton, generateButton)});
89
86
  slot.append(card.node);
90
87
  draw();
91
88
 
@@ -3,24 +3,21 @@ import { el, icon, passwordInput, button, bench, stack, panel, notice, copyButto
3
3
 
4
4
  const COMMON = new Set([
5
5
  "password", "123456", "123456789", "qwerty", "letmein", "admin", "welcome",
6
- "iloveyou", "monkey", "dragon", "abc123", "111111", "000000", "passw0rd",
7
- ]);
6
+ "iloveyou", "monkey", "dragon", "abc123", "111111", "000000", "passw0rd"]);
8
7
 
9
8
  const GROUPS = [
10
9
  { test: (value) => /[a-z]/.test(value) },
11
10
  { test: (value) => /[A-Z]/.test(value) },
12
11
  { test: (value) => /[0-9]/.test(value) },
13
- { test: (value) => /[^A-Za-z0-9]/.test(value) },
14
- ];
12
+ { test: (value) => /[^A-Za-z0-9]/.test(value) }];
15
13
 
16
14
  const LEVELS = [
17
- { name: "Very weak", cls: "mvb-weak" },
18
- { name: "Weak", cls: "mvb-weak" },
19
- { name: "Fair", cls: "mvb-ok" },
20
- { name: "Good", cls: "mvb-ok" },
21
- { name: "Strong", cls: "mvb-strong" },
22
- { name: "Very strong", cls: "mvb-strong" },
23
- ];
15
+ { name: "Very weak", key: "weak" },
16
+ { name: "Weak", key: "weak" },
17
+ { name: "Fair", key: "ok" },
18
+ { name: "Good", key: "ok" },
19
+ { name: "Strong", key: "strong" },
20
+ { name: "Very strong", key: "strong" }];
24
21
 
25
22
  function analyze(value) {
26
23
  const length = value.length;
@@ -35,7 +32,7 @@ function analyze(value) {
35
32
  const hints = [];
36
33
  if (length < 12) hints.push("Use at least 12 characters.");
37
34
  if (groups < 3) hints.push("Mix upper case, lower case, digits and symbols.");
38
- if (/(.)\1{2,}/.test(value)) {
35
+ if (/(.)\1{2}/.test(value)) {
39
36
  score -= 1;
40
37
  hints.push("Repeated characters are easy to guess.");
41
38
  }
@@ -47,17 +44,17 @@ function analyze(value) {
47
44
  }
48
45
 
49
46
  const kvRow = (key, value) =>
50
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), el("span", { class: "mvb-kv__v" }, value));
47
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, key), el("span", { class: "wrap-anywhere font-mono text-2xs" }, value));
51
48
 
52
49
  export function mount(slot) {
53
50
  const field = passwordInput({ autocomplete: "off", "aria-label": "Password", placeholder: "Type a password" });
54
51
  const showButton = button("Show", { icon: "eye" });
55
- const meter = el("div", { class: "mvb-meter", role: "img", "aria-label": "Strength" }, el("div", { class: "mvb-meter__fill" }));
56
- const label = el("p", { class: "mvb-note text-[1.0625rem] font-bold text-ink" });
57
- const lengthValue = el("span", { class: "mvb-kv__v" }, "-");
58
- const groupsValue = el("span", { class: "mvb-kv__v" }, "-");
59
- const kv = el("div", { class: "mvb-kv" }, kvRow("Length", lengthValue), kvRow("Character groups", groupsValue));
60
- const hints = el("div", { class: "mvb-stack" });
52
+ const meter = el("div", { class: "h-2 overflow-hidden rounded-full bg-deck-2", role: "img", "aria-label": "Strength" }, el("div", { class: "h-full w-0 rounded-full bg-orbit-hard transition-[width,background-color] duration-150 data-[level=weak]:bg-danger data-[level=ok]:bg-star data-[level=strong]:bg-jade" }));
53
+ const label = el("p", { class: "border-s-[3px] border-transparent ps-2 text-md font-bold text-ink" });
54
+ const lengthValue = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
55
+ const groupsValue = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
56
+ const kv = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" }, kvRow("Length", lengthValue), kvRow("Character groups", groupsValue));
57
+ const hints = el("div", { class: "grid content-start gap-4" });
61
58
  const status = notice("note");
62
59
  let report = "";
63
60
 
@@ -69,11 +66,11 @@ export function mount(slot) {
69
66
 
70
67
  function run() {
71
68
  const value = field.value;
72
- const fill = meter.querySelector(".mvb-meter__fill");
69
+ const fill = meter.firstElementChild;
73
70
  hints.replaceChildren();
74
71
  if (!value) {
75
72
  fill.style.width = "0%";
76
- fill.className = "mvb-meter__fill";
73
+ delete fill.dataset.level;
77
74
  label.textContent = "";
78
75
  meter.setAttribute("aria-label", "Strength");
79
76
  lengthValue.textContent = "-";
@@ -85,7 +82,7 @@ export function mount(slot) {
85
82
  const { score, groups, length, hints: why } = analyze(value);
86
83
  const level = LEVELS[score];
87
84
  fill.style.width = `${(score / 5) * 100}%`;
88
- fill.className = `mvb-meter__fill ${level.cls}`;
85
+ fill.dataset.level = level.key;
89
86
  label.textContent = level.name;
90
87
  // The bar is colour only, so the reading it stands for also goes on the bar itself.
91
88
  meter.setAttribute("aria-label", `Strength: ${level.name}`);
@@ -104,11 +101,10 @@ export function mount(slot) {
104
101
 
105
102
  const card = toolcard({
106
103
  body: bench(
107
- stack(panel("Password", el("div", { class: "mvb-secret" }, field, showButton))),
104
+ stack(panel("Password", el("div", { class: "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2" }, field, showButton))),
108
105
  stack(meter, label, kv, hints, status)
109
106
  ),
110
- foot: actions(copyButton(() => report, "Copy report", "fill")),
111
- });
107
+ foot: actions(copyButton(() => report, "Copy report", "fill"))});
112
108
  slot.append(card.node);
113
109
  run();
114
110
 
@@ -17,16 +17,16 @@ function fmt(n) {
17
17
  }
18
18
 
19
19
  const kvRow = (key, value) =>
20
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), el("span", { class: "mvb-kv__v" }, value));
20
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, key), el("span", { class: "wrap-anywhere font-mono text-2xs" }, value));
21
21
 
22
22
  export function mount(slot) {
23
23
  const source = textInput({ value: "12.5", "aria-label": "Percent", placeholder: "12.5" });
24
- const fraction = el("span", { class: "mvb-kv__v" }, "-");
25
- const decimal = el("span", { class: "mvb-kv__v" }, "-");
26
- const mixed = el("span", { class: "mvb-kv__v" }, "-");
24
+ const fraction = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
25
+ const decimal = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
26
+ const mixed = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
27
27
  const kv = el(
28
28
  "div",
29
- { class: "mvb-kv" },
29
+ { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
30
30
  kvRow("Fraction", fraction),
31
31
  kvRow("Decimal", decimal),
32
32
  kvRow("Mixed number", mixed)
@@ -85,8 +85,7 @@ export function mount(slot) {
85
85
  stack(panel("Percent", source), error),
86
86
  stack(panel("Result", kv))
87
87
  ),
88
- foot: actions(copyButton(() => text, "Copy fraction", "fill")),
89
- });
88
+ foot: actions(copyButton(() => text, "Copy fraction", "fill"))});
90
89
  slot.append(card.node);
91
90
  run();
92
91
 
@@ -9,17 +9,16 @@ function fmt(n) {
9
9
  export function mount(slot) {
10
10
  const modes = [
11
11
  { value: "of", label: "Percent of a value" },
12
- { value: "is", label: "Value as a percent" },
13
- ];
12
+ { value: "is", label: "Value as a percent" }];
14
13
  const labelA = el("span", {}, "Percent");
15
14
  const labelB = el("span", {}, "Value");
16
15
  const a = numberInput({ value: "15", "aria-label": "First value" });
17
16
  const b = numberInput({ value: "200", "aria-label": "Second value" });
18
- const result = el("span", { class: "mvb-stat__v" }, "-");
17
+ const result = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
19
18
  const stats = el(
20
19
  "div",
21
- { class: "mvb-stats" },
22
- el("div", { class: "mvb-stat" }, result, el("span", { class: "mvb-stat__k" }, "Result"))
20
+ { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" },
21
+ el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, result, el("span", { class: "text-2xs font-semibold text-ink-3" }, "Result"))
23
22
  );
24
23
  const error = notice("error");
25
24
  let mode = "of";
@@ -63,8 +62,7 @@ export function mount(slot) {
63
62
  mode = value;
64
63
  relabel();
65
64
  run();
66
- },
67
- });
65
+ }});
68
66
 
69
67
  a.addEventListener("input", run);
70
68
  b.addEventListener("input", run);
@@ -74,8 +72,7 @@ export function mount(slot) {
74
72
  stack(panel("Mode", chips), panel(labelA, a), panel(labelB, b), error),
75
73
  stack(stats)
76
74
  ),
77
- foot: actions(copyButton(() => text, "Copy result", "fill")),
78
- });
75
+ foot: actions(copyButton(() => text, "Copy result", "fill"))});
79
76
  slot.append(card.node);
80
77
  relabel();
81
78
  run();
@@ -6,8 +6,8 @@ function fmt(n) {
6
6
  }
7
7
 
8
8
  function tile(label) {
9
- const value = el("span", { class: "mvb-stat__v" }, "-");
10
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
9
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
10
+ const node = el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, value, el("span", { class: "text-2xs font-semibold text-ink-3" }, label));
11
11
  node.set = (text) => { value.textContent = text; };
12
12
  return node;
13
13
  }
@@ -18,7 +18,7 @@ export function mount(slot) {
18
18
  const change = tile("Change");
19
19
  const difference = tile("Difference");
20
20
  const direction = tile("Direction");
21
- const stats = el("div", { class: "mvb-stats" }, change, difference, direction);
21
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, change, difference, direction);
22
22
  const error = notice("error");
23
23
  let text = "";
24
24
 
@@ -59,8 +59,7 @@ export function mount(slot) {
59
59
  stack(panel("Starting value", start), panel("Ending value", end), error),
60
60
  stack(stats)
61
61
  ),
62
- foot: actions(copyButton(() => text, "Copy result", "fill")),
63
- });
62
+ foot: actions(copyButton(() => text, "Copy result", "fill"))});
64
63
  slot.append(card.node);
65
64
  run();
66
65
 
@@ -6,8 +6,8 @@ function fmt(n) {
6
6
  }
7
7
 
8
8
  function tile(label) {
9
- const value = el("span", { class: "mvb-stat__v" }, "-");
10
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
9
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
10
+ const node = el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, value, el("span", { class: "text-2xs font-semibold text-ink-3" }, label));
11
11
  node.set = (text) => { value.textContent = text; };
12
12
  return node;
13
13
  }
@@ -16,12 +16,12 @@ export function mount(slot) {
16
16
  const nInput = numberInput({ value: "5", min: "0", step: "1", "aria-label": "n" });
17
17
  const rInput = numberInput({ value: "3", min: "0", step: "1", "aria-label": "r" });
18
18
  const count = tile("Result");
19
- const stats = el("div", { class: "mvb-stats" }, count);
20
- const formulaRow = el("span", { class: "mvb-kv__v" }, "-");
19
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, count);
20
+ const formulaRow = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
21
21
  const kv = el(
22
22
  "div",
23
- { class: "mvb-kv" },
24
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, "Formula"), formulaRow)
23
+ { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
24
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, "Formula"), formulaRow)
25
25
  );
26
26
  const error = notice("error");
27
27
  let mode = "npr";
@@ -75,16 +75,14 @@ export function mount(slot) {
75
75
  const chips = chipRow(
76
76
  [
77
77
  { value: "npr", label: "Permutation nPr" },
78
- { value: "ncr", label: "Combination nCr" },
79
- ],
78
+ { value: "ncr", label: "Combination nCr" }],
80
79
  {
81
80
  value: mode,
82
81
  label: "Mode",
83
82
  onChange: (value) => {
84
83
  mode = value;
85
84
  run();
86
- },
87
- }
85
+ }}
88
86
  );
89
87
 
90
88
  nInput.addEventListener("input", run);
@@ -95,8 +93,7 @@ export function mount(slot) {
95
93
  stack(panel("n", nInput), panel("r", rInput), panel("Mode", chips), error),
96
94
  stack(stats, panel("Working", kv))
97
95
  ),
98
- foot: actions(copyButton(() => text, "Copy result", "fill")),
99
- });
96
+ foot: actions(copyButton(() => text, "Copy result", "fill"))});
100
97
  slot.append(card.node);
101
98
  run();
102
99
 
@@ -6,7 +6,7 @@ export function mount(slot) {
6
6
  const prefixField = textInput({ placeholder: "Prefix", "aria-label": "Prefix" });
7
7
  const suffixField = textInput({ placeholder: "Suffix", "aria-label": "Suffix" });
8
8
  const numbering = checkbox("Numbering", { checked: false });
9
- const result = textArea({ rows: 11, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Result" });
9
+ const result = textArea({ rows: 11, readonly: true, "aria-label": "Result" });
10
10
 
11
11
  function run() {
12
12
  const text = source.value;
@@ -35,8 +35,7 @@ export function mount(slot) {
35
35
  ),
36
36
  stack(panel("Result", result))
37
37
  ),
38
- foot: actions(copyButton(() => result.value, "Copy result", "fill")),
39
- });
38
+ foot: actions(copyButton(() => result.value, "Copy result", "fill"))});
40
39
  slot.append(card.node);
41
40
  run();
42
41
 
@@ -6,8 +6,7 @@ const QUADRANTS = [
6
6
  { id: "do", name: "Do now" },
7
7
  { id: "schedule", name: "Schedule" },
8
8
  { id: "delegate", name: "Delegate" },
9
- { id: "drop", name: "Drop" },
10
- ];
9
+ { id: "drop", name: "Drop" }];
11
10
 
12
11
  export function mount(slot) {
13
12
  const PIN = "priority-matrix";
@@ -17,8 +16,7 @@ export function mount(slot) {
17
16
  const task = textInput({ placeholder: "Task", "aria-label": "Task" });
18
17
  const quadrant = selectInput(QUADRANTS.map((q) => ({ value: q.id, label: q.name })), {
19
18
  value: "do",
20
- "aria-label": "Quadrant",
21
- });
19
+ "aria-label": "Quadrant"});
22
20
 
23
21
  const matrix = stack();
24
22
 
@@ -39,8 +37,7 @@ export function mount(slot) {
39
37
  const text = el("span", {}, item.text);
40
38
  const move = selectInput(QUADRANTS.map((q) => ({ value: q.id, label: q.name })), {
41
39
  value: item.q,
42
- "aria-label": `Move ${item.text}`,
43
- });
40
+ "aria-label": `Move ${item.text}`});
44
41
  move.addEventListener("change", () => {
45
42
  item.q = move.value;
46
43
  save();
@@ -52,12 +49,12 @@ export function mount(slot) {
52
49
  save();
53
50
  render();
54
51
  });
55
- return el("div", { class: "mvb-row" }, text, move, remove);
52
+ return el("div", { class: "flex min-w-0 flex-wrap items-center gap-2" }, text, move, remove);
56
53
  }
57
54
 
58
55
  function quadrantBox(q) {
59
56
  const items = list.filter((item) => item.q === q.id);
60
- const body = items.length ? stack(...items.map(taskRow)) : el("span", { class: "mvb-note" }, "Empty");
57
+ const body = items.length ? stack(...items.map(taskRow)) : el("span", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Empty");
61
58
  return panel(`${q.name} (${items.length})`, body);
62
59
  }
63
60
 
@@ -89,8 +86,7 @@ export function mount(slot) {
89
86
  stack(panel("Task", task), panel("Quadrant", quadrant)),
90
87
  matrix
91
88
  ),
92
- foot: actions(copyMatrix, addButton),
93
- });
89
+ foot: actions(copyMatrix, addButton)});
94
90
  slot.append(card.node);
95
91
  render();
96
92
 
@@ -6,8 +6,8 @@ function fmt(n) {
6
6
  }
7
7
 
8
8
  function tile(label) {
9
- const value = el("span", { class: "mvb-stat__v" }, "-");
10
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
9
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
10
+ const node = el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, value, el("span", { class: "text-2xs font-semibold text-ink-3" }, label));
11
11
  node.set = (text) => { value.textContent = text; };
12
12
  return node;
13
13
  }
@@ -18,7 +18,7 @@ export function mount(slot) {
18
18
  const profit = tile("Profit");
19
19
  const margin = tile("Margin");
20
20
  const markup = tile("Markup");
21
- const stats = el("div", { class: "mvb-stats" }, profit, margin, markup);
21
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, profit, margin, markup);
22
22
  const error = notice("error");
23
23
  let text = "";
24
24
 
@@ -58,8 +58,7 @@ export function mount(slot) {
58
58
  stack(panel("Cost", cost), panel("Selling price", price), error),
59
59
  stack(stats)
60
60
  ),
61
- foot: actions(copyButton(() => text, "Copy result", "fill")),
62
- });
61
+ foot: actions(copyButton(() => text, "Copy result", "fill"))});
63
62
  slot.append(card.node);
64
63
  run();
65
64
 
@@ -6,8 +6,8 @@ import qrcode from "../vendor/qrcode-generator.mjs";
6
6
  export function mount(slot) {
7
7
  const content = textArea({ rows: 4, value: "https://mevebu.app", "aria-label": "Text or link", placeholder: "Text or link" });
8
8
  const sizeField = numberInput({ value: "256", min: "120", max: "1024", step: "8", "aria-label": "Size in pixels" });
9
- const canvas = el("canvas", { class: "mvb-qrcode", role: "img", "aria-label": "QR code" });
10
- const reading = el("p", { class: "mvb-note" });
9
+ const canvas = el("canvas", { class: "h-auto w-[min(300px,100%)] [image-rendering:pixelated]", role: "img", "aria-label": "QR code" });
10
+ const reading = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
11
11
  const error = notice("error");
12
12
  let svg = "";
13
13
 
@@ -86,8 +86,7 @@ export function mount(slot) {
86
86
  stack(panel("Text or link", content), panel("Size in pixels", sizeField), error),
87
87
  stack(panel("Preview", canvas), reading)
88
88
  ),
89
- foot: actions(copyButton, svgButton, pngButton),
90
- });
89
+ foot: actions(copyButton, svgButton, pngButton)});
91
90
  slot.append(card.node);
92
91
  render();
93
92
 
@@ -19,9 +19,9 @@ function loadJsQR() {
19
19
  }
20
20
 
21
21
  export function mount(slot) {
22
- const video = el("video", { class: "mvb-qrview", playsinline: true, muted: true, hidden: true });
22
+ const video = el("video", { class: "w-[min(420px,100%)] rounded-r2 border border-orbit-hard bg-black", playsinline: true, muted: true, hidden: true });
23
23
  const fileField = el("input", { type: "file", accept: "image/*", hidden: true, "aria-label": "Image file" });
24
- const status = el("p", { class: "mvb-note" });
24
+ const status = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
25
25
  const found = output({ rows: 3 });
26
26
  const error = notice("error");
27
27
 
@@ -32,15 +32,15 @@ export function mount(slot) {
32
32
  const paint = scratch.getContext("2d", { willReadFrequently: true });
33
33
 
34
34
  const startButton = button("Start camera", { icon: "camera", kind: "fill" });
35
- const stopButton = el("button", { class: "mvb-btn mvb-btn--plain", type: "button", hidden: true }, icon("video-off"), el("span", {}, "Stop"));
35
+ const stopButton = el("button", { class: "inline-flex min-h-[var(--ctl)] cursor-pointer items-center justify-center gap-2 rounded-r1 border px-4 text-sm font-semibold whitespace-nowrap no-underline transition-[background-color,border-color,color,transform] duration-150 active:scale-[0.97] disabled:cursor-not-allowed disabled:opacity-45 border-orbit bg-deck text-ink hover:border-orbit-hard hover:bg-deck-2", type: "button", hidden: true }, icon("video-off"), el("span", {}, "Stop"));
36
36
  const uploadButton = button("Choose an image", { icon: "upload" });
37
37
  const copyButton = button("Copy", { icon: "copy" });
38
- const openWrap = el("span", { class: "mvb-row" });
38
+ const openWrap = el("span", { class: "flex min-w-0 flex-wrap items-center gap-2" });
39
39
 
40
40
  const drop = el(
41
41
  "div",
42
- { class: "mvb-drop", role: "button", tabindex: "0", "aria-label": "Drop an image here or choose one" },
43
- icon("image-up", "mvb-ico mvb-ico--lg"),
42
+ { class: "grid cursor-pointer justify-items-center gap-2 rounded-r2 border border-dashed border-orbit-hard px-4 py-7 text-sm text-ink-3 transition-colors duration-150 hover:border-jade hover:bg-jade-soft data-[drag]:border-jade data-[drag]:bg-jade-soft", role: "button", tabindex: "0", "aria-label": "Drop an image here or choose one" },
43
+ icon("image-up", "size-[26px] flex-none"),
44
44
  el("p", {}, "Drop an image here, or choose one.")
45
45
  );
46
46
 
@@ -50,7 +50,7 @@ export function mount(slot) {
50
50
  error.write("");
51
51
  openWrap.replaceChildren();
52
52
  if (/^https?:\/\//i.test(text.trim())) {
53
- openWrap.append(el("a", { class: "mvb-btn mvb-btn--plain", href: text.trim(), target: "_blank", rel: "noopener" },
53
+ openWrap.append(el("a", { class: "inline-flex min-h-[var(--ctl)] cursor-pointer items-center justify-center gap-2 rounded-r1 border px-4 text-sm font-semibold whitespace-nowrap no-underline transition-[background-color,border-color,color,transform] duration-150 active:scale-[0.97] disabled:cursor-not-allowed disabled:opacity-45 border-orbit bg-deck text-ink hover:border-orbit-hard hover:bg-deck-2", href: text.trim(), target: "_blank", rel: "noopener" },
54
54
  icon("external-link"), el("span", {}, "Open link")));
55
55
  }
56
56
  toast("Found");
@@ -159,12 +159,12 @@ export function mount(slot) {
159
159
  });
160
160
  drop.addEventListener("dragover", (event) => {
161
161
  event.preventDefault();
162
- drop.classList.add("mvb-drag");
162
+ drop.dataset.drag = "";
163
163
  });
164
- drop.addEventListener("dragleave", () => drop.classList.remove("mvb-drag"));
164
+ drop.addEventListener("dragleave", () => delete drop.dataset.drag);
165
165
  drop.addEventListener("drop", (event) => {
166
166
  event.preventDefault();
167
- drop.classList.remove("mvb-drag");
167
+ delete drop.dataset.drag;
168
168
  if (event.dataTransfer.files[0]) scanFile(event.dataTransfer.files[0]);
169
169
  });
170
170
  copyButton.addEventListener("click", async () => {
@@ -180,8 +180,7 @@ export function mount(slot) {
180
180
  stack(video, drop, fileField, status, error),
181
181
  panel("Decoded", found)
182
182
  ),
183
- foot: actions(openWrap, copyButton),
184
- });
183
+ foot: actions(openWrap, copyButton)});
185
184
  slot.append(card.node);
186
185
 
187
186
  return { unmount: stop };
@@ -6,19 +6,19 @@ function fmt(n) {
6
6
  }
7
7
 
8
8
  const kvRow = (key, value) =>
9
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), el("span", { class: "mvb-kv__v" }, value));
9
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, key), el("span", { class: "wrap-anywhere font-mono text-2xs" }, value));
10
10
 
11
11
  export function mount(slot) {
12
12
  const a = numberInput({ value: "1", "aria-label": "Coefficient a" });
13
13
  const b = numberInput({ value: "-3", "aria-label": "Coefficient b" });
14
14
  const c = numberInput({ value: "2", "aria-label": "Coefficient c" });
15
- const discriminant = el("span", { class: "mvb-kv__v" }, "-");
16
- const root1 = el("span", { class: "mvb-kv__v" }, "-");
17
- const root2 = el("span", { class: "mvb-kv__v" }, "-");
18
- const nature = el("span", { class: "mvb-kv__v" }, "-");
15
+ const discriminant = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
16
+ const root1 = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
17
+ const root2 = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
18
+ const nature = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
19
19
  const kv = el(
20
20
  "div",
21
- { class: "mvb-kv" },
21
+ { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
22
22
  kvRow("Discriminant", discriminant),
23
23
  kvRow("Root 1", root1),
24
24
  kvRow("Root 2", root2),
@@ -82,8 +82,7 @@ export function mount(slot) {
82
82
  stack(panel("a", a), panel("b", b), panel("c", c), error),
83
83
  stack(panel("Solution", kv))
84
84
  ),
85
- foot: actions(copyButton(() => text, "Copy roots", "fill")),
86
- });
85
+ foot: actions(copyButton(() => text, "Copy roots", "fill"))});
87
86
  slot.append(card.node);
88
87
  run();
89
88
 
@@ -13,7 +13,7 @@ const isUrl = (value) => {
13
13
 
14
14
  export function mount(slot) {
15
15
  const base = textInput({ value: "https://example.com/search", "aria-label": "Base URL" });
16
- const params = textArea({ rows: 8, class: "mvb-in mvb-in--area mvb-in--mono", value: "q=hello world\npage=2", placeholder: "q=hello world\npage=2", "aria-label": "Parameters" });
16
+ const params = textArea({ rows: 8, value: "q=hello world\npage=2", placeholder: "q=hello world\npage=2", "aria-label": "Parameters" });
17
17
  const encode = checkbox("Encode values", { checked: true });
18
18
  const result = output({ rows: 4 });
19
19
  const error = notice("error");
@@ -60,8 +60,7 @@ export function mount(slot) {
60
60
  stack(panel("Base URL", base), panel("Parameters", params), encode, error),
61
61
  stack(panel("URL", result))
62
62
  ),
63
- foot: actions(copyButton(() => result.textContent, "Copy URL", "fill")),
64
- });
63
+ foot: actions(copyButton(() => result.textContent, "Copy URL", "fill"))});
65
64
  slot.append(card.node);
66
65
  build();
67
66