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
|
@@ -15,15 +15,14 @@ const reverseLines = (text) => text ? text.split("\n").reverse().join("\n") : ""
|
|
|
15
15
|
|
|
16
16
|
export function mount(slot) {
|
|
17
17
|
const source = textArea({ rows: 10, "aria-label": "Text", placeholder: "Type or paste text" });
|
|
18
|
-
const result = textArea({ rows: 10, readonly: true,
|
|
18
|
+
const result = textArea({ rows: 10, readonly: true, "aria-label": "Result" });
|
|
19
19
|
|
|
20
20
|
let mode = "chars";
|
|
21
21
|
const chips = chipRow(
|
|
22
22
|
[
|
|
23
23
|
{ value: "chars", label: "Characters" },
|
|
24
24
|
{ value: "words", label: "Words" },
|
|
25
|
-
{ value: "lines", label: "Lines" },
|
|
26
|
-
],
|
|
25
|
+
{ value: "lines", label: "Lines" }],
|
|
27
26
|
{ value: "chars", label: "Reverse by", onChange: (value) => { mode = value; run(); } }
|
|
28
27
|
);
|
|
29
28
|
|
|
@@ -40,8 +39,7 @@ export function mount(slot) {
|
|
|
40
39
|
stack(panel("Text", source), panel("Reverse by", chips)),
|
|
41
40
|
stack(panel("Result", result))
|
|
42
41
|
),
|
|
43
|
-
foot: actions(copyButton(() => result.value, "Copy result", "fill"))
|
|
44
|
-
});
|
|
42
|
+
foot: actions(copyButton(() => result.value, "Copy result", "fill"))});
|
|
45
43
|
slot.append(card.node);
|
|
46
44
|
run();
|
|
47
45
|
|
|
@@ -11,19 +11,19 @@ function parseTime(value) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const kvRow = (key, value) =>
|
|
14
|
-
el("div", { class: "
|
|
14
|
+
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));
|
|
15
15
|
|
|
16
16
|
export function mount(slot) {
|
|
17
17
|
const start = textInput({ type: "time", value: "09:00", "aria-label": "Start time" });
|
|
18
18
|
const end = textInput({ type: "time", value: "17:30", "aria-label": "End time" });
|
|
19
19
|
const breakMin = numberInput({ value: "30", min: "0", "aria-label": "Break in minutes" });
|
|
20
20
|
|
|
21
|
-
const result = el("span", { class: "
|
|
22
|
-
const tile = el("div", { class: "
|
|
23
|
-
const stats = el("div", { class: "
|
|
24
|
-
const minutesOut = el("span", { class: "
|
|
25
|
-
const decimalOut = el("span", { class: "
|
|
26
|
-
const kv = el("div", { class: "
|
|
21
|
+
const result = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
|
|
22
|
+
const tile = 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" }, "Duration"));
|
|
23
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, tile);
|
|
24
|
+
const minutesOut = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
25
|
+
const decimalOut = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
26
|
+
const kv = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" }, kvRow("Total minutes", minutesOut), kvRow("Decimal hours", decimalOut));
|
|
27
27
|
const error = notice("error");
|
|
28
28
|
let text = "";
|
|
29
29
|
|
|
@@ -72,8 +72,7 @@ export function mount(slot) {
|
|
|
72
72
|
stack(panel("Start", start), panel("End", end), panel("Break in minutes", breakMin), error),
|
|
73
73
|
stack(stats, panel("Breakdown", kv))
|
|
74
74
|
),
|
|
75
|
-
foot: actions(copyButton(() => text, "Copy result", "fill"))
|
|
76
|
-
});
|
|
75
|
+
foot: actions(copyButton(() => text, "Copy result", "fill"))});
|
|
77
76
|
slot.append(card.node);
|
|
78
77
|
run();
|
|
79
78
|
|
|
@@ -6,8 +6,7 @@ function relative(date) {
|
|
|
6
6
|
const abs = Math.abs(diff);
|
|
7
7
|
const units = [
|
|
8
8
|
["year", 31536000000], ["month", 2592000000], ["day", 86400000],
|
|
9
|
-
["hour", 3600000], ["minute", 60000], ["second", 1000]
|
|
10
|
-
];
|
|
9
|
+
["hour", 3600000], ["minute", 60000], ["second", 1000]];
|
|
11
10
|
for (const [unit, ms] of units) {
|
|
12
11
|
if (abs >= ms) {
|
|
13
12
|
const value = Math.round(abs / ms);
|
|
@@ -32,11 +31,11 @@ function parse(text) {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
const row = (key, value) =>
|
|
35
|
-
el("div", { class: "
|
|
34
|
+
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));
|
|
36
35
|
|
|
37
36
|
export function mount(slot) {
|
|
38
37
|
const source = textInput({ value: "1700000000", "aria-label": "Timestamp or date", placeholder: "1700000000 or 2026-01-01T00:00:00Z" });
|
|
39
|
-
const kv = el("div", { class: "
|
|
38
|
+
const kv = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" });
|
|
40
39
|
const error = notice("error");
|
|
41
40
|
let iso = "";
|
|
42
41
|
|
|
@@ -74,8 +73,7 @@ export function mount(slot) {
|
|
|
74
73
|
stack(panel("Timestamp or date", source), error),
|
|
75
74
|
stack(panel("Reading", kv))
|
|
76
75
|
),
|
|
77
|
-
foot: actions(nowButton, copyButton(() => iso, "Copy ISO 8601", "fill"))
|
|
78
|
-
});
|
|
76
|
+
foot: actions(nowButton, copyButton(() => iso, "Copy ISO 8601", "fill"))});
|
|
79
77
|
slot.append(card.node);
|
|
80
78
|
run();
|
|
81
79
|
|
|
@@ -18,8 +18,7 @@ const FALLBACK_ZONES = [
|
|
|
18
18
|
"Asia/Shanghai",
|
|
19
19
|
"Asia/Tokyo",
|
|
20
20
|
"Asia/Singapore",
|
|
21
|
-
"Australia/Sydney"
|
|
22
|
-
];
|
|
21
|
+
"Australia/Sydney"];
|
|
23
22
|
|
|
24
23
|
function zoneList() {
|
|
25
24
|
let zones = FALLBACK_ZONES;
|
|
@@ -68,8 +67,7 @@ function offsetMs(timeZone, date) {
|
|
|
68
67
|
day: "2-digit",
|
|
69
68
|
hour: "2-digit",
|
|
70
69
|
minute: "2-digit",
|
|
71
|
-
second: "2-digit"
|
|
72
|
-
});
|
|
70
|
+
second: "2-digit"});
|
|
73
71
|
for (const part of format.formatToParts(date)) parts[part.type] = part.value;
|
|
74
72
|
const hour = parts.hour === "24" ? 0 : Number(parts.hour);
|
|
75
73
|
const asUTC = Date.UTC(Number(parts.year), Number(parts.month) - 1, Number(parts.day), hour, Number(parts.minute), Number(parts.second));
|
|
@@ -85,7 +83,7 @@ function wallToInstant(day, time, timeZone) {
|
|
|
85
83
|
const pad = (n) => String(n).padStart(2, "0");
|
|
86
84
|
|
|
87
85
|
const kvRow = (key, value) =>
|
|
88
|
-
el("div", { class: "
|
|
86
|
+
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));
|
|
89
87
|
|
|
90
88
|
export function mount(slot) {
|
|
91
89
|
const zones = zoneList();
|
|
@@ -95,10 +93,10 @@ export function mount(slot) {
|
|
|
95
93
|
const fromZone = selectInput(zones, { value: Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC", "aria-label": "Source zone" });
|
|
96
94
|
const toZone = selectInput(zones, { value: "UTC", "aria-label": "Target zone" });
|
|
97
95
|
|
|
98
|
-
const target = el("span", { class: "
|
|
99
|
-
const utc = el("span", { class: "
|
|
100
|
-
const diff = el("span", { class: "
|
|
101
|
-
const kv = el("div", { class: "
|
|
96
|
+
const target = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
97
|
+
const utc = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
98
|
+
const diff = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
99
|
+
const kv = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" }, kvRow("Target time", target), kvRow("UTC", utc), kvRow("Offset", diff));
|
|
102
100
|
const error = notice("error");
|
|
103
101
|
let text = "";
|
|
104
102
|
|
|
@@ -127,8 +125,7 @@ export function mount(slot) {
|
|
|
127
125
|
month: "short",
|
|
128
126
|
year: "numeric",
|
|
129
127
|
hour: "2-digit",
|
|
130
|
-
minute: "2-digit"
|
|
131
|
-
}).format(instant);
|
|
128
|
+
minute: "2-digit"}).format(instant);
|
|
132
129
|
const utcText = `${instant.getUTCFullYear()}-${pad(instant.getUTCMonth() + 1)}-${pad(instant.getUTCDate())} ${pad(instant.getUTCHours())}:${pad(instant.getUTCMinutes())} UTC`;
|
|
133
130
|
const deltaHours = (offsetMs(toZone.value, instant) - offsetMs(fromZone.value, instant)) / 3600000;
|
|
134
131
|
const sign = deltaHours > 0 ? "+" : deltaHours < 0 ? "-" : "";
|
|
@@ -152,8 +149,7 @@ export function mount(slot) {
|
|
|
152
149
|
stack(panel("Date", date), panel("Time", time), panel("From", fromZone), panel("To", toZone), error),
|
|
153
150
|
stack(panel("Result", kv))
|
|
154
151
|
),
|
|
155
|
-
foot: actions(copyButton(() => text, "Copy result", "fill"))
|
|
156
|
-
});
|
|
152
|
+
foot: actions(copyButton(() => text, "Copy result", "fill"))});
|
|
157
153
|
slot.append(card.node);
|
|
158
154
|
run();
|
|
159
155
|
|
|
@@ -4,8 +4,8 @@ import { el, blank, bench, stack, panel, textArea, numberInput, copyButton, acti
|
|
|
4
4
|
const countWords = (text) => (text.trim() ? text.trim().split(/\s+/).length : 0);
|
|
5
5
|
|
|
6
6
|
function tile(label) {
|
|
7
|
-
const value = el("span", { class: "
|
|
8
|
-
const node = el("div", { class: "
|
|
7
|
+
const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0");
|
|
8
|
+
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));
|
|
9
9
|
node.set = (text) => { value.textContent = text; };
|
|
10
10
|
return node;
|
|
11
11
|
}
|
|
@@ -17,9 +17,9 @@ export function mount(slot) {
|
|
|
17
17
|
const titlesTile = tile("Titles");
|
|
18
18
|
const overTile = tile("Over the limit");
|
|
19
19
|
const longestTile = tile("Longest");
|
|
20
|
-
const stats = el("div", { class: "
|
|
20
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, titlesTile, overTile, longestTile);
|
|
21
21
|
|
|
22
|
-
const listWrap = el("div", { class: "
|
|
22
|
+
const listWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
23
23
|
let listText = "";
|
|
24
24
|
|
|
25
25
|
function run() {
|
|
@@ -42,7 +42,7 @@ export function mount(slot) {
|
|
|
42
42
|
el("th", {}, item.title),
|
|
43
43
|
el("td", {}, cap > 0 && item.chars > cap ? `${item.chars} over` : String(item.chars)),
|
|
44
44
|
el("td", {}, String(item.words))));
|
|
45
|
-
listWrap.replaceChildren(el("table", { class: "
|
|
45
|
+
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" },
|
|
46
46
|
el("thead", {}, el("tr", {}, el("th", {}, "Title"), el("th", {}, "Characters"), el("th", {}, "Words"))),
|
|
47
47
|
el("tbody", {}, ...rows)));
|
|
48
48
|
listText = items.map((item) => `${item.chars} characters, ${item.words} words ${item.title}`).join("\n");
|
|
@@ -56,8 +56,7 @@ export function mount(slot) {
|
|
|
56
56
|
stack(panel("Titles", source), panel("Character limit", limit)),
|
|
57
57
|
stack(stats, panel("By length", listWrap))
|
|
58
58
|
),
|
|
59
|
-
foot: actions(copyButton(() => listText, "Copy list", "fill"))
|
|
60
|
-
});
|
|
59
|
+
foot: actions(copyButton(() => listText, "Copy list", "fill"))});
|
|
61
60
|
slot.append(card.node);
|
|
62
61
|
run();
|
|
63
62
|
|
|
@@ -11,18 +11,18 @@ function describe(char) {
|
|
|
11
11
|
|
|
12
12
|
export function mount(slot) {
|
|
13
13
|
const source = textArea({ rows: 8, value: "mevebu", "aria-label": "Text" });
|
|
14
|
-
const scroll = el("div", { class: "
|
|
14
|
+
const scroll = el("div", { class: "max-h-80 overflow-auto" });
|
|
15
15
|
let rows = [];
|
|
16
16
|
|
|
17
17
|
function run() {
|
|
18
18
|
rows = Array.from(source.value).map(describe);
|
|
19
19
|
if (!rows.length) {
|
|
20
|
-
scroll.replaceChildren(el("p", { class: "
|
|
20
|
+
scroll.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Type or paste text."));
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
scroll.replaceChildren(el(
|
|
24
24
|
"table",
|
|
25
|
-
{ class: "
|
|
25
|
+
{ 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" },
|
|
26
26
|
el("thead", {}, el("tr", {},
|
|
27
27
|
el("th", {}, "Character"),
|
|
28
28
|
el("th", {}, "Code point"),
|
|
@@ -47,8 +47,7 @@ export function mount(slot) {
|
|
|
47
47
|
() => rows.map((entry) => `${entry.char}\t${entry.point}\t${entry.decimal}\t${entry.bytes}`).join("\n"),
|
|
48
48
|
"Copy table",
|
|
49
49
|
"fill"
|
|
50
|
-
))
|
|
51
|
-
});
|
|
50
|
+
))});
|
|
52
51
|
slot.append(card.node);
|
|
53
52
|
run();
|
|
54
53
|
|
|
@@ -4,23 +4,23 @@ import { el, textInput, notice, copyButton, bench, stack, panel, actions, toolca
|
|
|
4
4
|
const IPV4 = /^\d{1,3}(\.\d{1,3}){3}$/;
|
|
5
5
|
|
|
6
6
|
const kvRow = (key, value) =>
|
|
7
|
-
el("div", { class: "
|
|
7
|
+
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));
|
|
8
8
|
|
|
9
9
|
export function mount(slot) {
|
|
10
10
|
const source = textInput({ value: "https://example.com/login?next=/home", "aria-label": "URL" });
|
|
11
|
-
const scheme = el("span", { class: "
|
|
12
|
-
const host = el("span", { class: "
|
|
13
|
-
const port = el("span", { class: "
|
|
14
|
-
const path = el("span", { class: "
|
|
11
|
+
const scheme = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
12
|
+
const host = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
13
|
+
const port = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
14
|
+
const path = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
15
15
|
const kv = el(
|
|
16
16
|
"div",
|
|
17
|
-
{ class: "
|
|
17
|
+
{ class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
|
|
18
18
|
kvRow("Scheme", scheme),
|
|
19
19
|
kvRow("Host", host),
|
|
20
20
|
kvRow("Port", port),
|
|
21
21
|
kvRow("Path", path)
|
|
22
22
|
);
|
|
23
|
-
const flags = el("div", { class: "
|
|
23
|
+
const flags = el("div", { class: "grid content-start gap-4" });
|
|
24
24
|
const error = notice("error");
|
|
25
25
|
let summary = "";
|
|
26
26
|
|
|
@@ -86,8 +86,7 @@ export function mount(slot) {
|
|
|
86
86
|
),
|
|
87
87
|
stack(kv, panel("Checks", flags))
|
|
88
88
|
),
|
|
89
|
-
foot: actions(copyButton(() => summary, "Copy host", "fill"))
|
|
90
|
-
});
|
|
89
|
+
foot: actions(copyButton(() => summary, "Copy host", "fill"))});
|
|
91
90
|
slot.append(card.node);
|
|
92
91
|
run();
|
|
93
92
|
|
|
@@ -2,32 +2,32 @@
|
|
|
2
2
|
import { el, bench, stack, panel, textInput, notice, copyButton, actions, toolcard } from "../core.js";
|
|
3
3
|
|
|
4
4
|
const kvRow = (key, value) =>
|
|
5
|
-
el("div", { class: "
|
|
5
|
+
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));
|
|
6
6
|
|
|
7
7
|
export function mount(slot) {
|
|
8
8
|
const source = textInput({ value: "https://example.com:8443/blog/post?utm_source=news&page=2#top", "aria-label": "URL" });
|
|
9
9
|
const error = notice("error");
|
|
10
10
|
|
|
11
|
-
const protocol = el("span", { class: "
|
|
12
|
-
const host = el("span", { class: "
|
|
13
|
-
const port = el("span", { class: "
|
|
14
|
-
const path = el("span", { class: "
|
|
15
|
-
const hash = el("span", { class: "
|
|
11
|
+
const protocol = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
12
|
+
const host = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
13
|
+
const port = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
14
|
+
const path = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
15
|
+
const hash = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
16
16
|
const kv = el(
|
|
17
17
|
"div",
|
|
18
|
-
{ class: "
|
|
18
|
+
{ class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
|
|
19
19
|
kvRow("Protocol", protocol),
|
|
20
20
|
kvRow("Host", host),
|
|
21
21
|
kvRow("Port", port),
|
|
22
22
|
kvRow("Path", path),
|
|
23
23
|
kvRow("Hash", hash)
|
|
24
24
|
);
|
|
25
|
-
const tableWrap = el("div", { class: "
|
|
25
|
+
const tableWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
26
26
|
let paramsText = "";
|
|
27
27
|
|
|
28
28
|
function clear() {
|
|
29
29
|
for (const node of [protocol, host, port, path, hash]) node.textContent = "-";
|
|
30
|
-
tableWrap.replaceChildren(el("p", { class: "
|
|
30
|
+
tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "No query parameters."));
|
|
31
31
|
paramsText = "";
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -49,13 +49,13 @@ export function mount(slot) {
|
|
|
49
49
|
hash.textContent = url.hash || "-";
|
|
50
50
|
const params = [...url.searchParams];
|
|
51
51
|
if (!params.length) {
|
|
52
|
-
tableWrap.replaceChildren(el("p", { class: "
|
|
52
|
+
tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "No query parameters."));
|
|
53
53
|
paramsText = "";
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
tableWrap.replaceChildren(el(
|
|
57
57
|
"table",
|
|
58
|
-
{ class: "
|
|
58
|
+
{ 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" },
|
|
59
59
|
el("thead", {}, el("tr", {}, el("th", {}, "Key"), el("th", {}, "Value"))),
|
|
60
60
|
el("tbody", {}, ...params.map(([key, value]) => el("tr", {}, el("td", {}, key), el("td", {}, value))))
|
|
61
61
|
));
|
|
@@ -72,8 +72,7 @@ export function mount(slot) {
|
|
|
72
72
|
foot: actions(
|
|
73
73
|
copyButton(() => source.value.trim(), "Copy URL"),
|
|
74
74
|
copyButton(() => paramsText, "Copy params", "fill")
|
|
75
|
-
)
|
|
76
|
-
});
|
|
75
|
+
)});
|
|
77
76
|
slot.append(card.node);
|
|
78
77
|
run();
|
|
79
78
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { el, bench, stack, panel, textArea, copyButton, actions, toolcard } from "../core.js";
|
|
3
3
|
|
|
4
4
|
function tile(label) {
|
|
5
|
-
const value = el("span", { class: "
|
|
6
|
-
const node = el("div", { class: "
|
|
5
|
+
const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0");
|
|
6
|
+
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));
|
|
7
7
|
node.set = (text) => { value.textContent = text; };
|
|
8
8
|
return node;
|
|
9
9
|
}
|
|
@@ -22,7 +22,7 @@ export function mount(slot) {
|
|
|
22
22
|
const pointTile = tile("Code points");
|
|
23
23
|
const byteTile = tile("UTF-8 bytes");
|
|
24
24
|
const unitTile = tile("UTF-16 units");
|
|
25
|
-
const stats = el("div", { class: "
|
|
25
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, characterTile, pointTile, byteTile, unitTile);
|
|
26
26
|
|
|
27
27
|
let counts = { characters: 0, points: 0, bytes: 0, units: 0 };
|
|
28
28
|
|
|
@@ -31,8 +31,7 @@ export function mount(slot) {
|
|
|
31
31
|
`${counts.characters} characters`,
|
|
32
32
|
`${counts.points} code points`,
|
|
33
33
|
`${counts.bytes} UTF-8 bytes`,
|
|
34
|
-
`${counts.units} UTF-16 units
|
|
35
|
-
].join("\n");
|
|
34
|
+
`${counts.units} UTF-16 units`].join("\n");
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
function run() {
|
|
@@ -41,8 +40,7 @@ export function mount(slot) {
|
|
|
41
40
|
characters: graphemes(text),
|
|
42
41
|
points: Array.from(text).length,
|
|
43
42
|
bytes: new TextEncoder().encode(text).length,
|
|
44
|
-
units: text.length
|
|
45
|
-
};
|
|
43
|
+
units: text.length};
|
|
46
44
|
characterTile.set(String(counts.characters));
|
|
47
45
|
pointTile.set(String(counts.points));
|
|
48
46
|
byteTile.set(String(counts.bytes));
|
|
@@ -56,8 +54,7 @@ export function mount(slot) {
|
|
|
56
54
|
stack(panel("Text", source)),
|
|
57
55
|
stack(stats)
|
|
58
56
|
),
|
|
59
|
-
foot: actions(copyButton(summary, "Copy counts", "fill"))
|
|
60
|
-
});
|
|
57
|
+
foot: actions(copyButton(summary, "Copy counts", "fill"))});
|
|
61
58
|
slot.append(card.node);
|
|
62
59
|
run();
|
|
63
60
|
|
|
@@ -12,8 +12,7 @@ const VERSIONS = [
|
|
|
12
12
|
{ value: "v1", label: "v1" },
|
|
13
13
|
{ value: "v6", label: "v6" },
|
|
14
14
|
{ value: "nil", label: "Nil" },
|
|
15
|
-
{ value: "max", label: "Max" }
|
|
16
|
-
];
|
|
15
|
+
{ value: "max", label: "Max" }];
|
|
17
16
|
|
|
18
17
|
const toHex = (bytes) => [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
19
18
|
const group = (hex) => `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
@@ -105,8 +104,7 @@ export function mount(slot) {
|
|
|
105
104
|
onChange: (value) => {
|
|
106
105
|
version = value;
|
|
107
106
|
generate();
|
|
108
|
-
}
|
|
109
|
-
});
|
|
107
|
+
}});
|
|
110
108
|
|
|
111
109
|
function totalCount() {
|
|
112
110
|
return Math.max(1, Math.min(1000, parseInt(countField.value || "1", 10) || 1));
|
|
@@ -122,8 +120,7 @@ export function mount(slot) {
|
|
|
122
120
|
count: String(total),
|
|
123
121
|
caps: capsBox.input.checked,
|
|
124
122
|
noHyphens: hyphensBox.input.checked,
|
|
125
|
-
version
|
|
126
|
-
});
|
|
123
|
+
version});
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
const generateButton = button("Generate", { icon: "refresh-cw", kind: "fill" });
|
|
@@ -156,11 +153,10 @@ export function mount(slot) {
|
|
|
156
153
|
|
|
157
154
|
const card = toolcard({
|
|
158
155
|
body: bench(
|
|
159
|
-
stack(panel("Version", versions), panel("How many", countField), el("div", { class: "
|
|
156
|
+
stack(panel("Version", versions), panel("How many", countField), el("div", { class: "flex flex-wrap gap-1.5" }, capsBox, hyphensBox)),
|
|
160
157
|
result
|
|
161
158
|
),
|
|
162
|
-
foot: actions(copyButton, jsonButton, saveButton, generateButton)
|
|
163
|
-
});
|
|
159
|
+
foot: actions(copyButton, jsonButton, saveButton, generateButton)});
|
|
164
160
|
slot.append(card.node);
|
|
165
161
|
generate();
|
|
166
162
|
|
|
@@ -8,8 +8,8 @@ function parse(text) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function mount(slot) {
|
|
11
|
-
const left = textInput({ value: "1.2.0",
|
|
12
|
-
const right = textInput({ value: "1.1.5",
|
|
11
|
+
const left = textInput({ value: "1.2.0", mono: true, "aria-label": "First version" });
|
|
12
|
+
const right = textInput({ value: "1.1.5", mono: true, "aria-label": "Second version" });
|
|
13
13
|
const error = notice("error");
|
|
14
14
|
const out = output({ rows: 8 });
|
|
15
15
|
let text = "";
|
|
@@ -59,8 +59,7 @@ export function mount(slot) {
|
|
|
59
59
|
stack(panel("First version", left), panel("Second version", right), error),
|
|
60
60
|
stack(panel("Comparison", out))
|
|
61
61
|
),
|
|
62
|
-
foot: actions(copyButton(() => text, "Copy comparison", "fill"))
|
|
63
|
-
});
|
|
62
|
+
foot: actions(copyButton(() => text, "Copy comparison", "fill"))});
|
|
64
63
|
slot.append(card.node);
|
|
65
64
|
run();
|
|
66
65
|
|
|
@@ -7,8 +7,8 @@ const clock = (seconds) => {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
function tile(label) {
|
|
10
|
-
const value = el("span", { class: "
|
|
11
|
-
const node = el("div", { class: "
|
|
10
|
+
const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0:00");
|
|
11
|
+
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));
|
|
12
12
|
node.set = (text) => { value.textContent = text; };
|
|
13
13
|
return node;
|
|
14
14
|
}
|
|
@@ -22,7 +22,7 @@ export function mount(slot) {
|
|
|
22
22
|
const wordsTile = tile("Words");
|
|
23
23
|
const speakTile = tile("Speaking");
|
|
24
24
|
const totalTile = tile("With pauses");
|
|
25
|
-
const stats = el("div", { class: "
|
|
25
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, wordsTile, speakTile, totalTile);
|
|
26
26
|
const note = notice("note");
|
|
27
27
|
note.write("Speaking rates vary by person and script.");
|
|
28
28
|
|
|
@@ -42,8 +42,7 @@ export function mount(slot) {
|
|
|
42
42
|
summary = [
|
|
43
43
|
`${words} words`,
|
|
44
44
|
`Speaking ${clock(speaking)} at ${wpm} words per minute`,
|
|
45
|
-
`Total ${clock(total)} with ${pauseSeconds} seconds of pause per minute
|
|
46
|
-
].join("\n");
|
|
45
|
+
`Total ${clock(total)} with ${pauseSeconds} seconds of pause per minute`].join("\n");
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
source.addEventListener("input", run);
|
|
@@ -61,8 +60,7 @@ export function mount(slot) {
|
|
|
61
60
|
),
|
|
62
61
|
stack(stats, note)
|
|
63
62
|
),
|
|
64
|
-
foot: actions(copyButton(() => summary, "Copy estimate", "fill"))
|
|
65
|
-
});
|
|
63
|
+
foot: actions(copyButton(() => summary, "Copy estimate", "fill"))});
|
|
66
64
|
slot.append(card.node);
|
|
67
65
|
run();
|
|
68
66
|
|
|
@@ -11,8 +11,7 @@ const UNITS = [
|
|
|
11
11
|
{ value: "cup", label: "Cup", factor: 0.2365882365 },
|
|
12
12
|
{ value: "pt", label: "Pint", factor: 0.473176473 },
|
|
13
13
|
{ value: "qt", label: "Quart", factor: 0.946352946 },
|
|
14
|
-
{ value: "gal", label: "Gallon", factor: 3.785411784 }
|
|
15
|
-
];
|
|
14
|
+
{ value: "gal", label: "Gallon", factor: 3.785411784 }];
|
|
16
15
|
|
|
17
16
|
const byId = Object.fromEntries(UNITS.map((unit) => [unit.value, unit]));
|
|
18
17
|
const options = UNITS.map(({ value, label }) => ({ value, label }));
|
|
@@ -29,11 +28,11 @@ export function mount(slot) {
|
|
|
29
28
|
const value = numberInput({ value: "1", step: "any", "aria-label": "Value" });
|
|
30
29
|
const from = selectInput(options, { value: "l", "aria-label": "From unit" });
|
|
31
30
|
const to = selectInput(options, { value: "gal", "aria-label": "To unit" });
|
|
32
|
-
const result = el("span", { class: "
|
|
33
|
-
const stats = el("div", { class: "
|
|
34
|
-
const factor = el("p", { class: "
|
|
31
|
+
const result = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
|
|
32
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, el("span", { class: "text-2xs font-semibold text-ink-3" }, "Result"), result));
|
|
33
|
+
const factor = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
|
|
35
34
|
const error = notice("error");
|
|
36
|
-
const scroll = el("div", { class: "
|
|
35
|
+
const scroll = el("div", { class: "max-h-80 overflow-auto" });
|
|
37
36
|
let text = "";
|
|
38
37
|
|
|
39
38
|
function run() {
|
|
@@ -53,7 +52,7 @@ export function mount(slot) {
|
|
|
53
52
|
const out = (n * a.factor) / b.factor;
|
|
54
53
|
result.textContent = `${fmt(out)} ${b.value}`;
|
|
55
54
|
factor.textContent = `1 ${a.value} = ${fmt(a.factor / b.factor)} ${b.value}`;
|
|
56
|
-
scroll.replaceChildren(el("table", { class: "
|
|
55
|
+
scroll.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", {}, "Unit"), el("th", {}, "Value"))),
|
|
58
57
|
el("tbody", {}, ...UNITS.map((unit) => el("tr", {},
|
|
59
58
|
el("td", {}, unit.label),
|
|
@@ -77,8 +76,7 @@ export function mount(slot) {
|
|
|
77
76
|
stack(panel("Value", value), panel("From", from), panel("To", to), error),
|
|
78
77
|
stack(panel("Result", stats), factor, panel("All units", scroll))
|
|
79
78
|
),
|
|
80
|
-
foot: actions(swap, copyButton(() => text, "Copy result", "fill"))
|
|
81
|
-
});
|
|
79
|
+
foot: actions(swap, copyButton(() => text, "Copy result", "fill"))});
|
|
82
80
|
slot.append(card.node);
|
|
83
81
|
run();
|
|
84
82
|
|
|
@@ -11,8 +11,8 @@ export function mount(slot) {
|
|
|
11
11
|
let day = Number.isInteger(saved.day) && saved.day >= 0 && saved.day < 7 ? saved.day : 0;
|
|
12
12
|
|
|
13
13
|
const entry = textInput({ placeholder: "New item", "aria-label": "New item" });
|
|
14
|
-
const listWrap = el("div", { class: "
|
|
15
|
-
const stats = el("div", { class: "
|
|
14
|
+
const listWrap = 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 dayChips = chipRow(DAYS.map((label, value) => ({ value, label })), {
|
|
18
18
|
value: day,
|
|
@@ -21,15 +21,14 @@ export function mount(slot) {
|
|
|
21
21
|
day = next;
|
|
22
22
|
save();
|
|
23
23
|
render();
|
|
24
|
-
}
|
|
25
|
-
});
|
|
24
|
+
}});
|
|
26
25
|
|
|
27
26
|
const addButton = button("Add", { icon: "plus", kind: "fill" });
|
|
28
27
|
const copyWeek = copyButton(() => weekText(), "Copy week");
|
|
29
28
|
|
|
30
|
-
const tile = (key, value) => el("div", { class: "
|
|
31
|
-
el("span", { class: "
|
|
32
|
-
el("span", { class: "
|
|
29
|
+
const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
|
|
30
|
+
el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
|
|
31
|
+
el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
33
32
|
|
|
34
33
|
const save = () => writePin(PIN, { day, days });
|
|
35
34
|
|
|
@@ -53,7 +52,7 @@ export function mount(slot) {
|
|
|
53
52
|
save();
|
|
54
53
|
render();
|
|
55
54
|
});
|
|
56
|
-
return el("div", { class: "
|
|
55
|
+
return el("div", { class: "flex min-w-0 flex-wrap items-center gap-2" }, box, remove);
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
function renderStats() {
|
|
@@ -90,8 +89,7 @@ export function mount(slot) {
|
|
|
90
89
|
stack(panel("Day", dayChips), panel("New item", entry)),
|
|
91
90
|
stack(stats, panel("Items", listWrap))
|
|
92
91
|
),
|
|
93
|
-
foot: actions(copyWeek, addButton)
|
|
94
|
-
});
|
|
92
|
+
foot: actions(copyWeek, addButton)});
|
|
95
93
|
slot.append(card.node);
|
|
96
94
|
render();
|
|
97
95
|
|