mevebu 1.3.0 → 1.4.1
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/mevebu/app/mevebu.js +260 -208
- package/mevebu/app/tailwind.css +1658 -2079
- package/mevebu/app/tailwind.src.css +161 -1127
- package/mevebu/index.html +2 -2
- package/mevebu/libs/js/core.js +245 -96
- package/mevebu/libs/js/tools/abstract-checklist.js +5 -7
- package/mevebu/libs/js/tools/add-subtract-days.js +9 -11
- package/mevebu/libs/js/tools/age-calculator.js +7 -8
- package/mevebu/libs/js/tools/api-request-builder.js +3 -4
- package/mevebu/libs/js/tools/area-converter.js +7 -9
- package/mevebu/libs/js/tools/aspect-ratio.js +8 -9
- package/mevebu/libs/js/tools/average-calculator.js +4 -5
- package/mevebu/libs/js/tools/base64.js +2 -3
- package/mevebu/libs/js/tools/binary-calculator.js +6 -7
- package/mevebu/libs/js/tools/border-radius.js +7 -9
- package/mevebu/libs/js/tools/box-shadow.js +6 -7
- package/mevebu/libs/js/tools/break-even.js +4 -5
- package/mevebu/libs/js/tools/business-days.js +7 -8
- package/mevebu/libs/js/tools/canonical-tag.js +5 -6
- package/mevebu/libs/js/tools/caption-counter.js +5 -7
- package/mevebu/libs/js/tools/case-converter.js +10 -11
- package/mevebu/libs/js/tools/case-inspector.js +14 -16
- package/mevebu/libs/js/tools/cash-denomination.js +7 -8
- package/mevebu/libs/js/tools/cash-flow.js +7 -8
- package/mevebu/libs/js/tools/cert-expiry.js +5 -7
- package/mevebu/libs/js/tools/changelog-generator.js +4 -6
- package/mevebu/libs/js/tools/character-counter.js +10 -13
- package/mevebu/libs/js/tools/checklist.js +6 -7
- package/mevebu/libs/js/tools/citation-number-check.js +10 -13
- package/mevebu/libs/js/tools/coin-flip.js +9 -11
- package/mevebu/libs/js/tools/color-converter.js +6 -7
- package/mevebu/libs/js/tools/color-palette.js +6 -8
- package/mevebu/libs/js/tools/color-picker.js +4 -5
- package/mevebu/libs/js/tools/content-calendar.js +3 -4
- package/mevebu/libs/js/tools/contrast-checker.js +5 -6
- package/mevebu/libs/js/tools/cron-builder.js +4 -6
- package/mevebu/libs/js/tools/css-clamp.js +5 -6
- package/mevebu/libs/js/tools/css-formatter.js +4 -7
- package/mevebu/libs/js/tools/css-grid.js +6 -7
- package/mevebu/libs/js/tools/css-minifier.js +5 -8
- package/mevebu/libs/js/tools/csv-to-json.js +2 -3
- package/mevebu/libs/js/tools/csv-viewer.js +9 -11
- package/mevebu/libs/js/tools/currency-format.js +5 -7
- package/mevebu/libs/js/tools/daily-planner.js +9 -10
- package/mevebu/libs/js/tools/data-masker.js +6 -8
- package/mevebu/libs/js/tools/data-storage.js +7 -9
- package/mevebu/libs/js/tools/data-validator.js +9 -11
- package/mevebu/libs/js/tools/date-difference.js +6 -7
- package/mevebu/libs/js/tools/date-format.js +11 -13
- package/mevebu/libs/js/tools/delimiter-converter.js +3 -5
- package/mevebu/libs/js/tools/discount-calculator.js +4 -5
- package/mevebu/libs/js/tools/doi-resolver.js +4 -5
- package/mevebu/libs/js/tools/env-formatter.js +3 -6
- package/mevebu/libs/js/tools/equation-formatter.js +5 -9
- package/mevebu/libs/js/tools/expense-split.js +6 -7
- package/mevebu/libs/js/tools/fake-data.js +8 -13
- package/mevebu/libs/js/tools/find-replace.js +3 -5
- package/mevebu/libs/js/tools/flashcard-creator.js +9 -10
- package/mevebu/libs/js/tools/font-pairing.js +6 -8
- package/mevebu/libs/js/tools/fraction-calculator.js +10 -13
- package/mevebu/libs/js/tools/git-command-builder.js +11 -22
- package/mevebu/libs/js/tools/gpa-calculator.js +8 -10
- package/mevebu/libs/js/tools/grade-calculator.js +7 -8
- package/mevebu/libs/js/tools/gradient-generator.js +10 -12
- package/mevebu/libs/js/tools/habit-tracker.js +8 -9
- package/mevebu/libs/js/tools/hash-generator.js +3 -5
- package/mevebu/libs/js/tools/hashtag-formatter.js +6 -8
- package/mevebu/libs/js/tools/hmac-generator.js +3 -5
- package/mevebu/libs/js/tools/hpp-calculator.js +4 -5
- package/mevebu/libs/js/tools/html-entity.js +2 -3
- package/mevebu/libs/js/tools/html-formatter.js +3 -6
- package/mevebu/libs/js/tools/http-status.js +5 -7
- package/mevebu/libs/js/tools/inventory-quantity.js +7 -8
- package/mevebu/libs/js/tools/json-formatter.js +3 -6
- package/mevebu/libs/js/tools/json-minifier.js +5 -8
- package/mevebu/libs/js/tools/json-to-csv.js +3 -5
- package/mevebu/libs/js/tools/json-to-typescript.js +2 -5
- package/mevebu/libs/js/tools/json-validator.js +2 -3
- package/mevebu/libs/js/tools/jwt-decoder.js +6 -7
- package/mevebu/libs/js/tools/jwt-expiry.js +5 -6
- package/mevebu/libs/js/tools/jwt-generator.js +4 -6
- package/mevebu/libs/js/tools/length-converter.js +7 -9
- package/mevebu/libs/js/tools/license-reference.js +10 -13
- package/mevebu/libs/js/tools/line-counter.js +5 -7
- package/mevebu/libs/js/tools/list-difference.js +5 -7
- package/mevebu/libs/js/tools/list-merger.js +4 -5
- package/mevebu/libs/js/tools/locale-number.js +5 -8
- package/mevebu/libs/js/tools/markdown-preview.js +5 -8
- package/mevebu/libs/js/tools/markdown-table.js +5 -7
- package/mevebu/libs/js/tools/markup-calculator.js +4 -5
- package/mevebu/libs/js/tools/meeting-agenda.js +8 -9
- package/mevebu/libs/js/tools/meta-preview.js +12 -13
- package/mevebu/libs/js/tools/meta-tags.js +6 -7
- package/mevebu/libs/js/tools/mime-types.js +5 -7
- package/mevebu/libs/js/tools/name-picker.js +2 -3
- package/mevebu/libs/js/tools/number-base-converter.js +9 -12
- package/mevebu/libs/js/tools/password-generator.js +9 -12
- package/mevebu/libs/js/tools/password-strength.js +21 -25
- package/mevebu/libs/js/tools/percent-to-fraction.js +6 -7
- package/mevebu/libs/js/tools/percentage-calculator.js +6 -9
- package/mevebu/libs/js/tools/percentage-change.js +4 -5
- package/mevebu/libs/js/tools/permutation-combination.js +9 -12
- package/mevebu/libs/js/tools/prefix-suffix.js +2 -3
- package/mevebu/libs/js/tools/priority-matrix.js +6 -10
- package/mevebu/libs/js/tools/profit-margin.js +4 -5
- package/mevebu/libs/js/tools/qr-generator.js +3 -4
- package/mevebu/libs/js/tools/qr-scanner.js +11 -12
- package/mevebu/libs/js/tools/quadratic-solver.js +7 -8
- package/mevebu/libs/js/tools/query-builder.js +2 -3
- package/mevebu/libs/js/tools/quiz-formatter.js +4 -6
- package/mevebu/libs/js/tools/ratio-calculator.js +7 -8
- package/mevebu/libs/js/tools/readability.js +12 -15
- package/mevebu/libs/js/tools/reading-time.js +5 -7
- package/mevebu/libs/js/tools/reference-completeness.js +6 -8
- package/mevebu/libs/js/tools/regex-tester.js +7 -10
- package/mevebu/libs/js/tools/remove-duplicate-lines.js +2 -3
- package/mevebu/libs/js/tools/remove-extra-spaces.js +3 -5
- package/mevebu/libs/js/tools/robots-txt.js +3 -4
- package/mevebu/libs/js/tools/roman-numeral-converter.js +6 -8
- package/mevebu/libs/js/tools/sales-commission.js +8 -9
- package/mevebu/libs/js/tools/scientific-calculator.js +10 -14
- package/mevebu/libs/js/tools/scientific-notation.js +8 -9
- package/mevebu/libs/js/tools/script-planner.js +8 -10
- package/mevebu/libs/js/tools/selling-price.js +4 -5
- package/mevebu/libs/js/tools/semver-helper.js +3 -5
- package/mevebu/libs/js/tools/sentence-length.js +9 -10
- package/mevebu/libs/js/tools/sequence-analyzer.js +7 -8
- package/mevebu/libs/js/tools/sitemap-xml.js +4 -7
- package/mevebu/libs/js/tools/slug-converter.js +3 -5
- package/mevebu/libs/js/tools/slug-preview.js +6 -7
- package/mevebu/libs/js/tools/sort-lines.js +3 -5
- package/mevebu/libs/js/tools/speed-converter.js +7 -9
- package/mevebu/libs/js/tools/spin-wheel.js +19 -17
- package/mevebu/libs/js/tools/sql-formatter.js +5 -9
- package/mevebu/libs/js/tools/sql-minifier.js +5 -8
- package/mevebu/libs/js/tools/standard-deviation.js +6 -9
- package/mevebu/libs/js/tools/stopwatch.js +4 -6
- package/mevebu/libs/js/tools/study-schedule.js +8 -9
- package/mevebu/libs/js/tools/subtitle-formatter.js +10 -11
- package/mevebu/libs/js/tools/table-to-markdown.js +8 -12
- package/mevebu/libs/js/tools/tax-calculator.js +4 -5
- package/mevebu/libs/js/tools/temperature-converter.js +8 -11
- package/mevebu/libs/js/tools/text-diff.js +11 -7
- package/mevebu/libs/js/tools/text-direction.js +3 -5
- package/mevebu/libs/js/tools/text-reverser.js +3 -5
- package/mevebu/libs/js/tools/time-duration.js +8 -9
- package/mevebu/libs/js/tools/timestamp-converter.js +4 -6
- package/mevebu/libs/js/tools/timezone-converter.js +9 -13
- package/mevebu/libs/js/tools/title-length.js +6 -7
- package/mevebu/libs/js/tools/unicode-inspector.js +4 -5
- package/mevebu/libs/js/tools/url-inspector.js +8 -9
- package/mevebu/libs/js/tools/url-parser.js +12 -13
- package/mevebu/libs/js/tools/utf8-bytes.js +6 -9
- package/mevebu/libs/js/tools/uuid-generator.js +5 -9
- package/mevebu/libs/js/tools/version-compare.js +3 -4
- package/mevebu/libs/js/tools/video-duration.js +5 -7
- package/mevebu/libs/js/tools/volume-converter.js +7 -9
- package/mevebu/libs/js/tools/weekly-planner.js +8 -10
- package/mevebu/libs/js/tools/weight-converter.js +7 -9
- package/mevebu/libs/js/tools/weighted-average.js +4 -5
- package/mevebu/libs/js/tools/word-counter.js +10 -13
- package/mevebu/libs/js/tools/word-limit.js +4 -5
- package/mevebu/libs/js/tools/yaml-formatter.js +6 -7
- package/package.json +1 -1
|
@@ -8,15 +8,13 @@ const GREEK = {
|
|
|
8
8
|
theta: "θ", iota: "ι", kappa: "κ", lambda: "λ", mu: "μ", nu: "ν", xi: "ξ",
|
|
9
9
|
pi: "π", rho: "ρ", sigma: "σ", tau: "τ", phi: "φ", chi: "χ", psi: "ψ", omega: "ω",
|
|
10
10
|
Gamma: "Γ", Delta: "Δ", Theta: "Θ", Lambda: "Λ", Xi: "Ξ", Pi: "Π", Sigma: "Σ",
|
|
11
|
-
Phi: "Φ", Psi: "Ψ", Omega: "Ω"
|
|
12
|
-
};
|
|
11
|
+
Phi: "Φ", Psi: "Ψ", Omega: "Ω"};
|
|
13
12
|
const SYMBOLS = {
|
|
14
13
|
times: "×", cdot: "·", div: "÷", pm: "±", mp: "∓", le: "≤", leq: "≤",
|
|
15
14
|
ge: "≥", geq: "≥", ne: "≠", neq: "≠", approx: "≈", equiv: "≡", infty: "∞",
|
|
16
15
|
sum: "Σ", prod: "Π", int: "∫", partial: "∂", nabla: "∇", rightarrow: "→",
|
|
17
16
|
to: "→", leftarrow: "←", Rightarrow: "⇒", Leftarrow: "⇐", leftrightarrow: "↔",
|
|
18
|
-
in: "∈", notin: "∉", forall: "∀", exists: "∃", angle: "∠", degree: "°"
|
|
19
|
-
};
|
|
17
|
+
in: "∈", notin: "∉", forall: "∀", exists: "∃", angle: "∠", degree: "°"};
|
|
20
18
|
|
|
21
19
|
const superscript = (value) => [...value].map((char) => SUP[char] ?? char).join("");
|
|
22
20
|
const subscript = (value) => [...value].map((char) => SUB[char] ?? char).join("");
|
|
@@ -43,9 +41,8 @@ export function mount(slot) {
|
|
|
43
41
|
rows: 12,
|
|
44
42
|
value: "x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}",
|
|
45
43
|
"aria-label": "LaTeX",
|
|
46
|
-
placeholder: "\\frac{a}{b}"
|
|
47
|
-
});
|
|
48
|
-
const result = el("pre", { class: "mvb-out" });
|
|
44
|
+
placeholder: "\\frac{a}{b}"});
|
|
45
|
+
const result = el("pre", { class: "m-0 max-h-[340px] w-full overflow-auto rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3 font-mono text-sm leading-normal whitespace-pre-wrap [overflow-wrap:anywhere]" });
|
|
49
46
|
const note = notice("note");
|
|
50
47
|
note.write("Plain text preview, not rendered math.");
|
|
51
48
|
|
|
@@ -60,8 +57,7 @@ export function mount(slot) {
|
|
|
60
57
|
stack(panel("LaTeX", source)),
|
|
61
58
|
stack(panel("Preview", result), note)
|
|
62
59
|
),
|
|
63
|
-
foot: actions(copyButton(() => source.value, "Copy LaTeX", "fill"))
|
|
64
|
-
});
|
|
60
|
+
foot: actions(copyButton(() => source.value, "Copy LaTeX", "fill"))});
|
|
65
61
|
slot.append(card.node);
|
|
66
62
|
run();
|
|
67
63
|
|
|
@@ -18,7 +18,7 @@ export function mount(slot) {
|
|
|
18
18
|
{ value: mode, label: "Mode", onChange: (next) => { mode = next; save(); run(); } }
|
|
19
19
|
);
|
|
20
20
|
const sharesField = panel("Shares", shares);
|
|
21
|
-
const result = el("div", { class: "
|
|
21
|
+
const result = el("div", { class: "max-h-80 overflow-auto" });
|
|
22
22
|
const error = notice("error");
|
|
23
23
|
const remainder = notice("warn");
|
|
24
24
|
let text = "";
|
|
@@ -34,7 +34,7 @@ export function mount(slot) {
|
|
|
34
34
|
const names = people.value.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
35
35
|
const amount = Number(total.value);
|
|
36
36
|
if (!names.length || total.value.trim() === "" || !Number.isFinite(amount) || amount < 0) {
|
|
37
|
-
result.replaceChildren(el("p", { class: "
|
|
37
|
+
result.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Add a total and one name per line."));
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -42,12 +42,12 @@ export function mount(slot) {
|
|
|
42
42
|
if (mode === "custom") {
|
|
43
43
|
weights = shares.value.split("\n").map((line) => line.trim()).filter(Boolean).map(Number);
|
|
44
44
|
if (weights.length !== names.length || weights.some((w) => !Number.isFinite(w) || w < 0)) {
|
|
45
|
-
result.replaceChildren(el("p", { class: "
|
|
45
|
+
result.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Add one share for each name."));
|
|
46
46
|
error.write("Add one share for each name.");
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
if (weights.reduce((a, b) => a + b, 0) <= 0) {
|
|
50
|
-
result.replaceChildren(el("p", { class: "
|
|
50
|
+
result.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Add one share for each name."));
|
|
51
51
|
error.write("The shares add up to zero.");
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
@@ -60,7 +60,7 @@ export function mount(slot) {
|
|
|
60
60
|
const paid = rounded.reduce((a, b) => a + b, 0);
|
|
61
61
|
const leftover = Math.round((amount - paid) * 100) / 100;
|
|
62
62
|
|
|
63
|
-
result.replaceChildren(el("table", { class: "
|
|
63
|
+
result.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
|
|
64
64
|
el("thead", {}, el("tr", {}, el("th", {}, "Person"), el("th", {}, "Amount"))),
|
|
65
65
|
el("tbody", {}, ...names.map((name, i) => el("tr", {},
|
|
66
66
|
el("th", {}, name),
|
|
@@ -79,8 +79,7 @@ export function mount(slot) {
|
|
|
79
79
|
stack(panel("Total", total), panel("Mode", modeChips), panel("People", people), sharesField, error),
|
|
80
80
|
stack(panel("Each person", result), remainder)
|
|
81
81
|
),
|
|
82
|
-
foot: actions(copyButton(() => text, "Copy split", "fill"))
|
|
83
|
-
});
|
|
82
|
+
foot: actions(copyButton(() => text, "Copy split", "fill"))});
|
|
84
83
|
slot.append(card.node);
|
|
85
84
|
run();
|
|
86
85
|
|
|
@@ -7,8 +7,7 @@ const LAST = ["Ortega", "Wijaya", "Santos", "Kimura", "Novak", "Haddad", "Silva"
|
|
|
7
7
|
const PLACES = [
|
|
8
8
|
["Jakarta", "ID", "+62"], ["Bandung", "ID", "+62"], ["Madrid", "ES", "+34"], ["Barcelona", "ES", "+34"],
|
|
9
9
|
["Austin", "US", "+1"], ["Seattle", "US", "+1"], ["Berlin", "DE", "+49"], ["Munich", "DE", "+49"],
|
|
10
|
-
["Osaka", "JP", "+81"], ["Tokyo", "JP", "+81"], ["Recife", "BR", "+55"], ["Lagos", "NG", "+234"]
|
|
11
|
-
];
|
|
10
|
+
["Osaka", "JP", "+81"], ["Tokyo", "JP", "+81"], ["Recife", "BR", "+55"], ["Lagos", "NG", "+234"]];
|
|
12
11
|
const pick = (list) => list[randomInt(list.length)];
|
|
13
12
|
|
|
14
13
|
function person(id) {
|
|
@@ -23,8 +22,7 @@ function person(id) {
|
|
|
23
22
|
phone: `${code} ${700 + randomInt(300)} ${1000000 + randomInt(8999999)}`,
|
|
24
23
|
city,
|
|
25
24
|
country,
|
|
26
|
-
card: `4${String(randomInt(1000)).padStart(3, "0")} … ${1000 + randomInt(9000)}
|
|
27
|
-
};
|
|
25
|
+
card: `4${String(randomInt(1000)).padStart(3, "0")} … ${1000 + randomInt(9000)}`};
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export function mount(slot) {
|
|
@@ -34,12 +32,11 @@ export function mount(slot) {
|
|
|
34
32
|
[
|
|
35
33
|
{ value: "json", label: "JSON" },
|
|
36
34
|
{ value: "csv", label: "CSV" },
|
|
37
|
-
{ value: "table", label: "Table" },
|
|
38
|
-
],
|
|
35
|
+
{ value: "table", label: "Table" }],
|
|
39
36
|
{ value: "json", label: "Format", onChange: (value) => { format = value; render(); } }
|
|
40
37
|
);
|
|
41
38
|
const text = output({ rows: 14 });
|
|
42
|
-
const table = el("div", { class: "
|
|
39
|
+
const table = el("div", { class: "max-h-80 overflow-auto" });
|
|
43
40
|
let rows = [];
|
|
44
41
|
|
|
45
42
|
function totalCount() {
|
|
@@ -51,8 +48,7 @@ export function mount(slot) {
|
|
|
51
48
|
const columns = Object.keys(rows[0] ?? {});
|
|
52
49
|
return [
|
|
53
50
|
columns.join("\t"),
|
|
54
|
-
...rows.map((row) => columns.map((key) => String(row[key])).join("\t"))
|
|
55
|
-
].join("\n");
|
|
51
|
+
...rows.map((row) => columns.map((key) => String(row[key])).join("\t"))].join("\n");
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
function render() {
|
|
@@ -75,7 +71,7 @@ export function mount(slot) {
|
|
|
75
71
|
}
|
|
76
72
|
const head = el("tr");
|
|
77
73
|
for (const key of columns) head.append(el("th", {}, key));
|
|
78
|
-
table.replaceChildren(el("table", { class: "
|
|
74
|
+
table.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" }, el("thead", {}, head), body));
|
|
79
75
|
}
|
|
80
76
|
}
|
|
81
77
|
|
|
@@ -106,10 +102,9 @@ export function mount(slot) {
|
|
|
106
102
|
const card = toolcard({
|
|
107
103
|
body: bench(
|
|
108
104
|
stack(panel("Format", chips), panel("Records", countField)),
|
|
109
|
-
el("div", { class: "
|
|
105
|
+
el("div", { class: "grid content-start gap-4" }, text, table)
|
|
110
106
|
),
|
|
111
|
-
foot: actions(copyButton, saveButton, againButton)
|
|
112
|
-
});
|
|
107
|
+
foot: actions(copyButton, saveButton, againButton)});
|
|
113
108
|
slot.append(card.node);
|
|
114
109
|
render();
|
|
115
110
|
|
|
@@ -9,9 +9,8 @@ export function mount(slot) {
|
|
|
9
9
|
const replaceField = textInput({ placeholder: "Replace with", "aria-label": "Replace with" });
|
|
10
10
|
const options = toggleRow([
|
|
11
11
|
{ value: "regex", label: "Regex", checked: false },
|
|
12
|
-
{ value: "ignore", label: "Ignore case", checked: false }
|
|
13
|
-
|
|
14
|
-
const result = textArea({ rows: 9, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Result" });
|
|
12
|
+
{ value: "ignore", label: "Ignore case", checked: false }]);
|
|
13
|
+
const result = textArea({ rows: 9, readonly: true, "aria-label": "Result" });
|
|
15
14
|
const error = notice("error");
|
|
16
15
|
const countNote = notice("note");
|
|
17
16
|
|
|
@@ -77,8 +76,7 @@ export function mount(slot) {
|
|
|
77
76
|
stack(panel("Text", source), panel("Find", findField), panel("Replace with", replaceField), options, error, countNote),
|
|
78
77
|
stack(panel("Result", result))
|
|
79
78
|
),
|
|
80
|
-
foot: actions(copyButton(() => result.value, "Copy result"), replaceOneButton, replaceAllButton)
|
|
81
|
-
});
|
|
79
|
+
foot: actions(copyButton(() => result.value, "Copy result"), replaceOneButton, replaceAllButton)});
|
|
82
80
|
slot.append(card.node);
|
|
83
81
|
run();
|
|
84
82
|
|
|
@@ -12,10 +12,10 @@ export function mount(slot) {
|
|
|
12
12
|
|
|
13
13
|
const question = textInput({ placeholder: "Question", "aria-label": "Question" });
|
|
14
14
|
const answer = textArea({ rows: 3, placeholder: "Answer", "aria-label": "Answer" });
|
|
15
|
-
const listWrap = el("div", { class: "
|
|
16
|
-
const stats = el("div", { class: "
|
|
17
|
-
const face = el("pre", { class: "
|
|
18
|
-
const faceLabel = el("span", { class: "
|
|
15
|
+
const listWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
16
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
|
|
17
|
+
const face = el("pre", { class: "m-0 max-h-[340px] w-full overflow-auto rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3 font-mono text-sm leading-normal whitespace-pre-wrap [overflow-wrap:anywhere]" });
|
|
18
|
+
const faceLabel = el("span", { class: "text-sm font-semibold text-ink-2" }, "Question");
|
|
19
19
|
|
|
20
20
|
const addButton = button("Add card", { icon: "plus", kind: "fill" });
|
|
21
21
|
const flipButton = button("Flip", { icon: "arrow-left-right" });
|
|
@@ -23,9 +23,9 @@ export function mount(slot) {
|
|
|
23
23
|
const nextButton = button("Next");
|
|
24
24
|
|
|
25
25
|
const save = () => writePin(PIN, cards);
|
|
26
|
-
const tile = (key, value) => el("div", { class: "
|
|
27
|
-
el("span", { class: "
|
|
28
|
-
el("span", { class: "
|
|
26
|
+
const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
|
|
27
|
+
el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
|
|
28
|
+
el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
29
29
|
|
|
30
30
|
const textExport = () =>
|
|
31
31
|
cards.map((card, i) => `${i + 1}. Q: ${card.question}\n A: ${card.answer}`).join("\n\n");
|
|
@@ -52,7 +52,7 @@ export function mount(slot) {
|
|
|
52
52
|
const card = cards[index];
|
|
53
53
|
faceLabel.textContent = flipped ? "Answer" : "Question";
|
|
54
54
|
face.textContent = flipped ? card.answer : card.question;
|
|
55
|
-
listWrap.replaceChildren(el("table", { class: "
|
|
55
|
+
listWrap.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
|
|
56
56
|
el("tbody", {}, ...cards.map((entry, i) => el("tr", {},
|
|
57
57
|
el("th", {}, `${i + 1}. ${entry.question}`),
|
|
58
58
|
el("td", {}, removeButton(entry)))))));
|
|
@@ -106,8 +106,7 @@ export function mount(slot) {
|
|
|
106
106
|
copyButton(() => textExport(), "Copy text"),
|
|
107
107
|
downloadButton(() => jsonExport(), "flashcards.json", "Save JSON", "application/json"),
|
|
108
108
|
addButton
|
|
109
|
-
)
|
|
110
|
-
});
|
|
109
|
+
)});
|
|
111
110
|
slot.append(card.node);
|
|
112
111
|
render();
|
|
113
112
|
|
|
@@ -12,16 +12,15 @@ const FONTS = [
|
|
|
12
12
|
{ value: 'Palatino, "Palatino Linotype", serif', label: "Palatino" },
|
|
13
13
|
{ value: "Garamond, Georgia, serif", label: "Garamond" },
|
|
14
14
|
{ value: '"Courier New", Courier, monospace', label: "Courier New" },
|
|
15
|
-
{ value: "ui-monospace, SFMono-Regular, Menlo, monospace", label: "Mono" }
|
|
16
|
-
];
|
|
15
|
+
{ value: "ui-monospace, SFMono-Regular, Menlo, monospace", label: "Mono" }];
|
|
17
16
|
|
|
18
17
|
function slider(label, { min, max, step, value, unit }) {
|
|
19
18
|
const input = rangeInput({ min, max, step, value, "aria-label": label });
|
|
20
|
-
const val = el("span", { class: "
|
|
19
|
+
const val = el("span", { class: "text-end font-mono text-2xs text-ink-2" }, `${value}${unit}`);
|
|
21
20
|
const node = el(
|
|
22
21
|
"div",
|
|
23
|
-
{ class: "
|
|
24
|
-
el("span", { class: "
|
|
22
|
+
{ class: "grid items-center gap-2.5 [grid-template-columns:88px_minmax(0,1fr)_62px] max-[45rem]:[grid-template-columns:minmax(0,1fr)_62px]" },
|
|
23
|
+
el("span", { class: "text-2xs font-semibold text-ink-2 max-[45rem]:col-span-2" }, label),
|
|
25
24
|
input,
|
|
26
25
|
val
|
|
27
26
|
);
|
|
@@ -46,7 +45,7 @@ export function mount(slot) {
|
|
|
46
45
|
|
|
47
46
|
const heading = el("h2", { style: "margin:0 0 8px" }, "Heading sample");
|
|
48
47
|
const para = el("p", { style: "margin:0" }, "Body text sample. The quick brown fox jumps over the lazy dog.");
|
|
49
|
-
const sample = el("div", { class: "
|
|
48
|
+
const sample = el("div", { class: "w-full rounded-lg border border-orbit bg-deck px-[18px] py-4" }, heading, para);
|
|
50
49
|
const code = output();
|
|
51
50
|
|
|
52
51
|
function css() {
|
|
@@ -77,8 +76,7 @@ export function mount(slot) {
|
|
|
77
76
|
stack(panel("Heading font", headingFont), panel("Body font", bodyFont), headingSize, bodySize, lineHeight, panel("Heading weight", weightChips)),
|
|
78
77
|
stack(sample, code)
|
|
79
78
|
),
|
|
80
|
-
foot: actions(copyButton(css, "Copy CSS", "fill"))
|
|
81
|
-
});
|
|
79
|
+
foot: actions(copyButton(css, "Copy CSS", "fill"))});
|
|
82
80
|
slot.append(card.node);
|
|
83
81
|
update();
|
|
84
82
|
|
|
@@ -17,19 +17,19 @@ function fmt(n) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const kvRow = (key, value) =>
|
|
20
|
-
el("div", { class: "
|
|
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 n1 = numberInput({ value: "1", "aria-label": "First numerator" });
|
|
24
24
|
const d1 = numberInput({ value: "2", "aria-label": "First denominator" });
|
|
25
25
|
const n2 = numberInput({ value: "1", "aria-label": "Second numerator" });
|
|
26
26
|
const d2 = numberInput({ value: "3", "aria-label": "Second denominator" });
|
|
27
|
-
const resultRow = el("span", { class: "
|
|
28
|
-
const decimalRow = el("span", { class: "
|
|
29
|
-
const mixedRow = el("span", { class: "
|
|
27
|
+
const resultRow = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
28
|
+
const decimalRow = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
29
|
+
const mixedRow = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
30
30
|
const kv = el(
|
|
31
31
|
"div",
|
|
32
|
-
{ class: "
|
|
32
|
+
{ class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
|
|
33
33
|
kvRow("Fraction", resultRow),
|
|
34
34
|
kvRow("Decimal", decimalRow),
|
|
35
35
|
kvRow("Mixed number", mixedRow)
|
|
@@ -95,16 +95,14 @@ export function mount(slot) {
|
|
|
95
95
|
{ value: "+", label: "+" },
|
|
96
96
|
{ value: "-", label: "-" },
|
|
97
97
|
{ value: "x", label: "x" },
|
|
98
|
-
{ value: "/", label: "/" },
|
|
99
|
-
],
|
|
98
|
+
{ value: "/", label: "/" }],
|
|
100
99
|
{
|
|
101
100
|
value: op,
|
|
102
101
|
label: "Operation",
|
|
103
102
|
onChange: (value) => {
|
|
104
103
|
op = value;
|
|
105
104
|
run();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
105
|
+
}}
|
|
108
106
|
);
|
|
109
107
|
|
|
110
108
|
for (const input of [n1, d1, n2, d2]) input.addEventListener("input", run);
|
|
@@ -112,15 +110,14 @@ export function mount(slot) {
|
|
|
112
110
|
const card = toolcard({
|
|
113
111
|
body: bench(
|
|
114
112
|
stack(
|
|
115
|
-
panel("First fraction", el("div", { class: "
|
|
113
|
+
panel("First fraction", el("div", { class: "flex min-w-0 flex-wrap items-center gap-2" }, n1, d1)),
|
|
116
114
|
panel("Operation", chips),
|
|
117
|
-
panel("Second fraction", el("div", { class: "
|
|
115
|
+
panel("Second fraction", el("div", { class: "flex min-w-0 flex-wrap items-center gap-2" }, n2, d2)),
|
|
118
116
|
error
|
|
119
117
|
),
|
|
120
118
|
stack(panel("Result", kv))
|
|
121
119
|
),
|
|
122
|
-
foot: actions(copyButton(() => text, "Copy fraction", "fill"))
|
|
123
|
-
});
|
|
120
|
+
foot: actions(copyButton(() => text, "Copy fraction", "fill"))});
|
|
124
121
|
slot.append(card.node);
|
|
125
122
|
run();
|
|
126
123
|
|
|
@@ -7,56 +7,46 @@ const OPERATIONS = {
|
|
|
7
7
|
clone: {
|
|
8
8
|
label: "Clone a repository",
|
|
9
9
|
fields: [["url", "Repository URL", "https://github.com/user/repo.git"], ["directory", "Directory (optional)", ""]],
|
|
10
|
-
build: (v) => `git clone ${quote(v.url)}${v.directory ? ` ${quote(v.directory)}` : ""}
|
|
11
|
-
},
|
|
10
|
+
build: (v) => `git clone ${quote(v.url)}${v.directory ? ` ${quote(v.directory)}` : ""}`},
|
|
12
11
|
switch: {
|
|
13
12
|
label: "Switch branch",
|
|
14
13
|
fields: [["branch", "Branch", "main"]],
|
|
15
|
-
build: (v) => `git switch ${quote(v.branch)}
|
|
16
|
-
},
|
|
14
|
+
build: (v) => `git switch ${quote(v.branch)}`},
|
|
17
15
|
pull: {
|
|
18
16
|
label: "Pull",
|
|
19
17
|
fields: [["remote", "Remote", "origin"], ["branch", "Branch (optional)", ""]],
|
|
20
|
-
build: (v) => `git pull ${quote(v.remote)}${v.branch ? ` ${quote(v.branch)}` : ""}
|
|
21
|
-
},
|
|
18
|
+
build: (v) => `git pull ${quote(v.remote)}${v.branch ? ` ${quote(v.branch)}` : ""}`},
|
|
22
19
|
commit: {
|
|
23
20
|
label: "Commit",
|
|
24
21
|
fields: [["message", "Message", "Fix the thing"], ["files", "Paths (optional)", ""]],
|
|
25
|
-
build: (v) => `git commit -m ${quote(v.message)}${v.files ? ` ${v.files}` : ""}
|
|
26
|
-
},
|
|
22
|
+
build: (v) => `git commit -m ${quote(v.message)}${v.files ? ` ${v.files}` : ""}`},
|
|
27
23
|
push: {
|
|
28
24
|
label: "Push",
|
|
29
25
|
fields: [["remote", "Remote", "origin"], ["branch", "Branch", "main"]],
|
|
30
|
-
build: (v) => `git push ${quote(v.remote)} ${quote(v.branch)}
|
|
31
|
-
},
|
|
26
|
+
build: (v) => `git push ${quote(v.remote)} ${quote(v.branch)}`},
|
|
32
27
|
"push-force": {
|
|
33
28
|
label: "Force push",
|
|
34
29
|
fields: [["remote", "Remote", "origin"], ["branch", "Branch", "main"]],
|
|
35
30
|
build: (v) => `git push --force-with-lease ${quote(v.remote)} ${quote(v.branch)}`,
|
|
36
|
-
destructive: "Force push can overwrite commits on the remote.",
|
|
37
|
-
},
|
|
31
|
+
destructive: "Force push can overwrite commits on the remote."},
|
|
38
32
|
merge: {
|
|
39
33
|
label: "Merge",
|
|
40
34
|
fields: [["branch", "Branch", "feature"]],
|
|
41
|
-
build: (v) => `git merge ${quote(v.branch)}
|
|
42
|
-
},
|
|
35
|
+
build: (v) => `git merge ${quote(v.branch)}`},
|
|
43
36
|
rebase: {
|
|
44
37
|
label: "Rebase",
|
|
45
38
|
fields: [["branch", "Branch", "main"]],
|
|
46
|
-
build: (v) => `git rebase ${quote(v.branch)}
|
|
47
|
-
},
|
|
39
|
+
build: (v) => `git rebase ${quote(v.branch)}`},
|
|
48
40
|
reset: {
|
|
49
41
|
label: "Reset hard",
|
|
50
42
|
fields: [["ref", "Commit or ref", "HEAD~1"]],
|
|
51
43
|
build: (v) => `git reset --hard ${quote(v.ref)}`,
|
|
52
|
-
destructive: "Reset hard discards uncommitted work."
|
|
53
|
-
},
|
|
54
|
-
};
|
|
44
|
+
destructive: "Reset hard discards uncommitted work."}};
|
|
55
45
|
|
|
56
46
|
export function mount(slot) {
|
|
57
47
|
const options = Object.entries(OPERATIONS).map(([value, config]) => ({ value, label: config.label }));
|
|
58
48
|
const operationSelect = selectInput(options, { value: "clone", "aria-label": "Operation" });
|
|
59
|
-
const fieldsHost = el("div", { class: "
|
|
49
|
+
const fieldsHost = el("div", { class: "grid content-start gap-4" });
|
|
60
50
|
const result = output({ rows: 4 });
|
|
61
51
|
const warn = notice("warn");
|
|
62
52
|
const values = {};
|
|
@@ -89,8 +79,7 @@ export function mount(slot) {
|
|
|
89
79
|
stack(panel("Operation", operationSelect), fieldsHost, warn),
|
|
90
80
|
stack(panel("Command", result))
|
|
91
81
|
),
|
|
92
|
-
foot: actions(copyButton(() => result.textContent, "Copy command", "fill"))
|
|
93
|
-
});
|
|
82
|
+
foot: actions(copyButton(() => result.textContent, "Copy command", "fill"))});
|
|
94
83
|
slot.append(card.node);
|
|
95
84
|
paintFields();
|
|
96
85
|
|
|
@@ -7,8 +7,7 @@ const SCALE = [
|
|
|
7
7
|
["A+", 4.0], ["A", 4.0], ["A-", 3.7],
|
|
8
8
|
["B+", 3.3], ["B", 3.0], ["B-", 2.7],
|
|
9
9
|
["C+", 2.3], ["C", 2.0], ["C-", 1.7],
|
|
10
|
-
["D+", 1.3], ["D", 1.0], ["F", 0.0]
|
|
11
|
-
];
|
|
10
|
+
["D+", 1.3], ["D", 1.0], ["F", 0.0]];
|
|
12
11
|
const POINTS = new Map(SCALE);
|
|
13
12
|
|
|
14
13
|
function fmt(n) {
|
|
@@ -23,15 +22,15 @@ export function mount(slot) {
|
|
|
23
22
|
const name = textInput({ placeholder: "Course", "aria-label": "Course" });
|
|
24
23
|
const credits = numberInput({ min: "0", step: "0.5", placeholder: "Credits", "aria-label": "Credits" });
|
|
25
24
|
const grade = selectInput(SCALE.map(([label]) => ({ value: label, label })), { value: "A", "aria-label": "Grade" });
|
|
26
|
-
const listWrap = el("div", { class: "
|
|
27
|
-
const stats = el("div", { class: "
|
|
25
|
+
const listWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
26
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
|
|
28
27
|
|
|
29
28
|
const addButton = button("Add", { icon: "plus", kind: "fill" });
|
|
30
29
|
|
|
31
30
|
const save = () => writePin(PIN, list);
|
|
32
|
-
const tile = (key, value) => el("div", { class: "
|
|
33
|
-
el("span", { class: "
|
|
34
|
-
el("span", { class: "
|
|
31
|
+
const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
|
|
32
|
+
el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
|
|
33
|
+
el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
35
34
|
|
|
36
35
|
const totals = () => {
|
|
37
36
|
const totalCredits = list.reduce((sum, item) => sum + item.credits, 0);
|
|
@@ -53,7 +52,7 @@ export function mount(slot) {
|
|
|
53
52
|
if (!list.length) {
|
|
54
53
|
listWrap.replaceChildren(blank("graduation-cap", "No courses yet."));
|
|
55
54
|
} else {
|
|
56
|
-
listWrap.replaceChildren(el("table", { class: "
|
|
55
|
+
listWrap.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
|
|
57
56
|
el("thead", {}, el("tr", {}, el("th", {}, "Course"), el("th", {}, "Credits"), el("th", {}, "Grade"), el("th", {}, ""))),
|
|
58
57
|
el("tbody", {}, ...list.map((item) => el("tr", {},
|
|
59
58
|
el("th", {}, item.name),
|
|
@@ -89,8 +88,7 @@ export function mount(slot) {
|
|
|
89
88
|
foot: actions(copyButton(() => {
|
|
90
89
|
const { totalCredits, gpa } = totals();
|
|
91
90
|
return gpa == null ? "" : `GPA ${fmt(gpa)}, credits ${fmt(totalCredits)}`;
|
|
92
|
-
}, "Copy result"), addButton)
|
|
93
|
-
});
|
|
91
|
+
}, "Copy result"), addButton)});
|
|
94
92
|
slot.append(card.node);
|
|
95
93
|
render();
|
|
96
94
|
|
|
@@ -15,16 +15,16 @@ export function mount(slot) {
|
|
|
15
15
|
const name = textInput({ placeholder: "Component", "aria-label": "Component" });
|
|
16
16
|
const score = numberInput({ min: "0", max: "100", placeholder: "Score", "aria-label": "Score" });
|
|
17
17
|
const weight = numberInput({ min: "0", max: "100", placeholder: "Weight", "aria-label": "Weight" });
|
|
18
|
-
const listWrap = el("div", { class: "
|
|
19
|
-
const stats = el("div", { class: "
|
|
18
|
+
const listWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
19
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
|
|
20
20
|
const weightNote = notice("warn");
|
|
21
21
|
|
|
22
22
|
const addButton = button("Add", { icon: "plus", kind: "fill" });
|
|
23
23
|
|
|
24
24
|
const save = () => writePin(PIN, list);
|
|
25
|
-
const tile = (key, value) => el("div", { class: "
|
|
26
|
-
el("span", { class: "
|
|
27
|
-
el("span", { class: "
|
|
25
|
+
const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
|
|
26
|
+
el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
|
|
27
|
+
el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
28
28
|
|
|
29
29
|
const totalWeight = () => list.reduce((sum, item) => sum + item.weight, 0);
|
|
30
30
|
const grade = () => {
|
|
@@ -47,7 +47,7 @@ export function mount(slot) {
|
|
|
47
47
|
if (!list.length) {
|
|
48
48
|
listWrap.replaceChildren(blank("graduation-cap", "No components yet."));
|
|
49
49
|
} else {
|
|
50
|
-
listWrap.replaceChildren(el("table", { class: "
|
|
50
|
+
listWrap.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
|
|
51
51
|
el("thead", {}, el("tr", {}, el("th", {}, "Component"), el("th", {}, "Score"), el("th", {}, "Weight"), el("th", {}, ""))),
|
|
52
52
|
el("tbody", {}, ...list.map((item) => el("tr", {},
|
|
53
53
|
el("th", {}, item.name),
|
|
@@ -90,8 +90,7 @@ export function mount(slot) {
|
|
|
90
90
|
foot: actions(copyButton(() => {
|
|
91
91
|
const result = grade();
|
|
92
92
|
return result == null ? "" : `Grade ${fmt(result)}, total weight ${fmt(totalWeight())}%`;
|
|
93
|
-
}, "Copy result"), addButton)
|
|
94
|
-
});
|
|
93
|
+
}, "Copy result"), addButton)});
|
|
95
94
|
slot.append(card.node);
|
|
96
95
|
render();
|
|
97
96
|
|
|
@@ -6,11 +6,10 @@ export function mount(slot) {
|
|
|
6
6
|
let angle = 90;
|
|
7
7
|
const stops = [
|
|
8
8
|
{ color: "#f5b942", pos: 0 },
|
|
9
|
-
{ color: "#8a2be2", pos: 100 }
|
|
10
|
-
];
|
|
9
|
+
{ color: "#8a2be2", pos: 100 }];
|
|
11
10
|
|
|
12
|
-
const stopsBox = el("div", { class: "
|
|
13
|
-
const previewBox = el("div", { class: "
|
|
11
|
+
const stopsBox = el("div", { class: "grid content-start gap-4" });
|
|
12
|
+
const previewBox = el("div", { class: "grid h-[120px] w-[min(200px,100%)] place-items-center bg-jade text-2xs text-on-jade" });
|
|
14
13
|
const code = output();
|
|
15
14
|
|
|
16
15
|
function gradientCss() {
|
|
@@ -30,7 +29,7 @@ export function mount(slot) {
|
|
|
30
29
|
|
|
31
30
|
const range = rangeInput({ min: 0, max: 100, value: stop.pos, "aria-label": "Stop position" });
|
|
32
31
|
range.style.flex = "1";
|
|
33
|
-
const val = el("span", { class: "
|
|
32
|
+
const val = el("span", { class: "text-end font-mono text-2xs text-ink-2" }, `${stop.pos}%`);
|
|
34
33
|
range.addEventListener("input", () => {
|
|
35
34
|
stop.pos = parseInt(range.value, 10) || 0;
|
|
36
35
|
val.textContent = `${stop.pos}%`;
|
|
@@ -45,7 +44,7 @@ export function mount(slot) {
|
|
|
45
44
|
update();
|
|
46
45
|
});
|
|
47
46
|
|
|
48
|
-
return el("div", { class: "
|
|
47
|
+
return el("div", { class: "flex min-w-0 flex-wrap items-center gap-2" }, picker, range, val, remove);
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
function paintStops() {
|
|
@@ -63,11 +62,11 @@ export function mount(slot) {
|
|
|
63
62
|
});
|
|
64
63
|
|
|
65
64
|
const angleInput = rangeInput({ min: 0, max: 360, value: angle, "aria-label": "Angle" });
|
|
66
|
-
const angleVal = el("span", { class: "
|
|
65
|
+
const angleVal = el("span", { class: "text-end font-mono text-2xs text-ink-2" }, `${angle}deg`);
|
|
67
66
|
const angleRow = el(
|
|
68
67
|
"div",
|
|
69
|
-
{ class: "
|
|
70
|
-
el("span", { class: "
|
|
68
|
+
{ class: "grid items-center gap-2.5 [grid-template-columns:88px_minmax(0,1fr)_62px] max-[45rem]:[grid-template-columns:minmax(0,1fr)_62px]" },
|
|
69
|
+
el("span", { class: "text-2xs font-semibold text-ink-2 max-[45rem]:col-span-2" }, "Angle"),
|
|
71
70
|
angleInput,
|
|
72
71
|
angleVal
|
|
73
72
|
);
|
|
@@ -85,10 +84,9 @@ export function mount(slot) {
|
|
|
85
84
|
const card = toolcard({
|
|
86
85
|
body: bench(
|
|
87
86
|
stack(panel("Type", typeChips), angleRow, panel("Color stops", stopsBox), addStop),
|
|
88
|
-
stack(el("div", { class: "
|
|
87
|
+
stack(el("div", { class: "grid min-h-40 place-items-center overflow-hidden rounded-r1 border border-orbit bg-deck-2 p-[22px]" }, previewBox), code)
|
|
89
88
|
),
|
|
90
|
-
foot: actions(copyButton(() => `background: ${gradientCss()};`, "Copy CSS", "fill"))
|
|
91
|
-
});
|
|
89
|
+
foot: actions(copyButton(() => `background: ${gradientCss()};`, "Copy CSS", "fill"))});
|
|
92
90
|
slot.append(card.node);
|
|
93
91
|
paintStops();
|
|
94
92
|
update();
|
|
@@ -11,15 +11,15 @@ export function mount(slot) {
|
|
|
11
11
|
let list = Array.isArray(saved) ? saved : [];
|
|
12
12
|
|
|
13
13
|
const name = textInput({ placeholder: "Habit", "aria-label": "Habit" });
|
|
14
|
-
const tableWrap = el("div", { class: "
|
|
15
|
-
const stats = el("div", { class: "
|
|
14
|
+
const tableWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
15
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
|
|
16
16
|
|
|
17
17
|
const addButton = button("Add", { icon: "plus", kind: "fill" });
|
|
18
18
|
const clearWeek = button("Clear week", { icon: "trash" });
|
|
19
19
|
|
|
20
|
-
const tile = (key, value) => el("div", { class: "
|
|
21
|
-
el("span", { class: "
|
|
22
|
-
el("span", { class: "
|
|
20
|
+
const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
|
|
21
|
+
el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
|
|
22
|
+
el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
23
23
|
|
|
24
24
|
const save = () => writePin(PIN, list);
|
|
25
25
|
const today = todayIndex();
|
|
@@ -57,7 +57,7 @@ export function mount(slot) {
|
|
|
57
57
|
|
|
58
58
|
function render() {
|
|
59
59
|
if (!list.length) {
|
|
60
|
-
tableWrap.replaceChildren(el("p", { class: "
|
|
60
|
+
tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "No habits yet."));
|
|
61
61
|
} else {
|
|
62
62
|
const head = el("tr", {},
|
|
63
63
|
el("th", {}, "Habit"),
|
|
@@ -73,7 +73,7 @@ export function mount(slot) {
|
|
|
73
73
|
el("td", {}, String(streak(habit))),
|
|
74
74
|
el("td", {}, removeButton(habit))
|
|
75
75
|
));
|
|
76
|
-
tableWrap.replaceChildren(el("table", { class: "
|
|
76
|
+
tableWrap.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
|
|
77
77
|
el("thead", {}, head),
|
|
78
78
|
el("tbody", {}, ...rows)
|
|
79
79
|
));
|
|
@@ -109,8 +109,7 @@ export function mount(slot) {
|
|
|
109
109
|
stack(panel("Habit", name)),
|
|
110
110
|
stack(stats, panel("Week", tableWrap))
|
|
111
111
|
),
|
|
112
|
-
foot: actions(clearWeek, addButton)
|
|
113
|
-
});
|
|
112
|
+
foot: actions(clearWeek, addButton)});
|
|
114
113
|
slot.append(card.node);
|
|
115
114
|
render();
|
|
116
115
|
|