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.
- package/mevebu/app/mevebu.js +260 -208
- package/mevebu/app/tailwind.css +1639 -2077
- package/mevebu/app/tailwind.src.css +155 -1120
- package/mevebu/index.html +2 -2
- package/mevebu/libs/js/core.js +236 -96
- package/mevebu/libs/js/registry.js +11 -11
- 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 +31 -11
- 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 +11 -12
- 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 +6 -10
- 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 +23 -17
- 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 +7 -9
- 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 +20 -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/lorem-ipsum.js +4 -2
- 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-encoder.js +4 -2
- package/mevebu/libs/js/tools/url-inspector.js +9 -11
- 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 +107 -15
- 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
|
@@ -32,13 +32,13 @@ function toHsl({ r, g, b }) {
|
|
|
32
32
|
|
|
33
33
|
export function mount(slot) {
|
|
34
34
|
const picker = colorInput({ value: "#f5b942", "aria-label": "Pick a color" });
|
|
35
|
-
const hexInput = textInput({ value: "#F5B942",
|
|
36
|
-
const swatch = el("div", { class: "
|
|
35
|
+
const hexInput = textInput({ value: "#F5B942", mono: true, "aria-label": "Hex value" });
|
|
36
|
+
const swatch = el("div", { class: "h-14 rounded-r1 border border-orbit-hard bg-deck-2" });
|
|
37
37
|
const error = notice("error");
|
|
38
38
|
let current = "#f5b942";
|
|
39
39
|
|
|
40
40
|
const readonly = (label) => {
|
|
41
|
-
const field = textInput({ readonly: true,
|
|
41
|
+
const field = textInput({ readonly: true, mono: true, "aria-label": `${label}, press to copy` });
|
|
42
42
|
const wrap = panel(label, field);
|
|
43
43
|
wrap.style.cursor = "pointer";
|
|
44
44
|
wrap.addEventListener("click", async () => {
|
|
@@ -82,8 +82,7 @@ export function mount(slot) {
|
|
|
82
82
|
foot: actions(
|
|
83
83
|
copyButton(() => `--color: ${current};`, "Copy CSS"),
|
|
84
84
|
copyButton(() => current, "Copy hex", "fill")
|
|
85
|
-
)
|
|
86
|
-
});
|
|
85
|
+
)});
|
|
87
86
|
slot.append(card.node);
|
|
88
87
|
read("#F5B942", false);
|
|
89
88
|
|
|
@@ -19,7 +19,7 @@ export function mount(slot) {
|
|
|
19
19
|
{ value: "Idea", label: "Status", onChange: (next) => { status = next; } }
|
|
20
20
|
);
|
|
21
21
|
|
|
22
|
-
const listWrap = el("div", { class: "
|
|
22
|
+
const listWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
23
23
|
const addButton = button("Add", { icon: "plus", kind: "fill" });
|
|
24
24
|
|
|
25
25
|
const save = () => writePin(PIN, { entries });
|
|
@@ -46,7 +46,7 @@ export function mount(slot) {
|
|
|
46
46
|
el("td", {}, entry.platform || ""),
|
|
47
47
|
el("td", {}, entry.status),
|
|
48
48
|
el("td", {}, removeButton(entry))));
|
|
49
|
-
listWrap.replaceChildren(el("table", { class: "
|
|
49
|
+
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" },
|
|
50
50
|
el("thead", {}, el("tr", {},
|
|
51
51
|
el("th", {}, "Date"), el("th", {}, "Topic"), el("th", {}, "Platform"), el("th", {}, "Status"), el("th", {}, ""))),
|
|
52
52
|
el("tbody", {}, ...rows)));
|
|
@@ -100,8 +100,7 @@ export function mount(slot) {
|
|
|
100
100
|
downloadButton(() => csv(), "content-calendar.csv", "Save CSV", "text/csv"),
|
|
101
101
|
downloadButton(() => markdown(), "content-calendar.md", "Save Markdown", "text/markdown"),
|
|
102
102
|
addButton
|
|
103
|
-
)
|
|
104
|
-
});
|
|
103
|
+
)});
|
|
105
104
|
slot.append(card.node);
|
|
106
105
|
render();
|
|
107
106
|
|
|
@@ -31,19 +31,19 @@ export function mount(slot) {
|
|
|
31
31
|
const bgPicker = colorInput({ value: "#ffffff", "aria-label": "Background color" });
|
|
32
32
|
|
|
33
33
|
const kvRow = (key) => {
|
|
34
|
-
const value = el("span", { class: "
|
|
35
|
-
return { v: value, node: el("div", { class: "
|
|
34
|
+
const value = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
35
|
+
return { v: value, node: 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), value) };
|
|
36
36
|
};
|
|
37
37
|
const ratioRow = kvRow("Contrast ratio");
|
|
38
38
|
const normalAA = kvRow("Normal text AA");
|
|
39
39
|
const normalAAA = kvRow("Normal text AAA");
|
|
40
40
|
const largeAA = kvRow("Large text AA");
|
|
41
41
|
const largeAAA = kvRow("Large text AAA");
|
|
42
|
-
const list = el("div", { class: "
|
|
42
|
+
const list = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" }, ratioRow.node, normalAA.node, normalAAA.node, largeAA.node, largeAAA.node);
|
|
43
43
|
|
|
44
44
|
const sample = el(
|
|
45
45
|
"div",
|
|
46
|
-
{ class: "
|
|
46
|
+
{ class: "w-full rounded-lg border border-orbit bg-deck px-[18px] py-4" },
|
|
47
47
|
el("p", { style: "margin:0 0 8px;font-size:20px;font-weight:700" }, "Large text sample"),
|
|
48
48
|
el("p", { style: "margin:0;font-size:15px" }, "Normal text sample for the contrast reading.")
|
|
49
49
|
);
|
|
@@ -82,8 +82,7 @@ export function mount(slot) {
|
|
|
82
82
|
stack(panel("Text color", textPicker), panel("Background color", bgPicker)),
|
|
83
83
|
stack(sample, list)
|
|
84
84
|
),
|
|
85
|
-
foot: actions(swap, copyButton(() => reading, "Copy result", "fill"))
|
|
86
|
-
});
|
|
85
|
+
foot: actions(swap, copyButton(() => reading, "Copy result", "fill"))});
|
|
87
86
|
slot.append(card.node);
|
|
88
87
|
update();
|
|
89
88
|
|
|
@@ -38,8 +38,7 @@ const FIELDS = [
|
|
|
38
38
|
["hour", "Hour", "0-23", "*"],
|
|
39
39
|
["day", "Day of month", "1-31", "*"],
|
|
40
40
|
["month", "Month", "1-12", "*"],
|
|
41
|
-
["weekday", "Day of week", "0-6", "*"]
|
|
42
|
-
];
|
|
41
|
+
["weekday", "Day of week", "0-6", "*"]];
|
|
43
42
|
|
|
44
43
|
export function mount(slot) {
|
|
45
44
|
const inputs = {};
|
|
@@ -49,8 +48,8 @@ export function mount(slot) {
|
|
|
49
48
|
return panel(label, input, hint);
|
|
50
49
|
});
|
|
51
50
|
|
|
52
|
-
const expression = textInput({ readonly: true,
|
|
53
|
-
const reading = el("p", { class: "
|
|
51
|
+
const expression = textInput({ readonly: true, mono: true, "aria-label": "Cron expression" });
|
|
52
|
+
const reading = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
|
|
54
53
|
const error = notice("error");
|
|
55
54
|
|
|
56
55
|
function run() {
|
|
@@ -80,8 +79,7 @@ export function mount(slot) {
|
|
|
80
79
|
stack(...controls, error),
|
|
81
80
|
stack(panel("Expression", expression), panel("Reading", reading))
|
|
82
81
|
),
|
|
83
|
-
foot: actions(reset, copyButton(() => expression.value, "Copy expression", "fill"))
|
|
84
|
-
});
|
|
82
|
+
foot: actions(reset, copyButton(() => expression.value, "Copy expression", "fill"))});
|
|
85
83
|
slot.append(card.node);
|
|
86
84
|
run();
|
|
87
85
|
|
|
@@ -3,11 +3,11 @@ import { el, bench, stack, rangeInput, output, copyButton, actions, toolcard } f
|
|
|
3
3
|
|
|
4
4
|
function slider(label, { min, max, step, value, unit }) {
|
|
5
5
|
const input = rangeInput({ min, max, step, value, "aria-label": label });
|
|
6
|
-
const val = el("span", { class: "
|
|
6
|
+
const val = el("span", { class: "text-end font-mono text-2xs text-ink-2" }, `${value}${unit}`);
|
|
7
7
|
const node = el(
|
|
8
8
|
"div",
|
|
9
|
-
{ class: "
|
|
10
|
-
el("span", { class: "
|
|
9
|
+
{ class: "grid items-center gap-2.5 [grid-template-columns:88px_minmax(0,1fr)_62px] max-[45rem]:[grid-template-columns:minmax(0,1fr)_62px]" },
|
|
10
|
+
el("span", { class: "text-2xs font-semibold text-ink-2 max-[45rem]:col-span-2" }, label),
|
|
11
11
|
input,
|
|
12
12
|
val
|
|
13
13
|
);
|
|
@@ -24,7 +24,7 @@ export function mount(slot) {
|
|
|
24
24
|
|
|
25
25
|
const sample = el(
|
|
26
26
|
"div",
|
|
27
|
-
{ class: "
|
|
27
|
+
{ class: "w-full rounded-lg border border-orbit bg-deck px-[18px] py-4" },
|
|
28
28
|
el("p", { style: "margin:0" }, "The quick brown fox jumps over the lazy dog.")
|
|
29
29
|
);
|
|
30
30
|
const code = output();
|
|
@@ -55,8 +55,7 @@ export function mount(slot) {
|
|
|
55
55
|
stack(min, preferred, max),
|
|
56
56
|
stack(sample, code)
|
|
57
57
|
),
|
|
58
|
-
foot: actions(copyButton(() => `font-size: ${clampValue()};`, "Copy CSS", "fill"))
|
|
59
|
-
});
|
|
58
|
+
foot: actions(copyButton(() => `font-size: ${clampValue()};`, "Copy CSS", "fill"))});
|
|
60
59
|
slot.append(card.node);
|
|
61
60
|
update();
|
|
62
61
|
|
|
@@ -44,17 +44,15 @@ function format(css, size) {
|
|
|
44
44
|
}
|
|
45
45
|
const rest = clean(buffer);
|
|
46
46
|
if (rest) push(rest);
|
|
47
|
-
return lines.join("\n").replace(/\n{3
|
|
47
|
+
return lines.join("\n").replace(/\n{3}/g, "\n\n").trim();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export function mount(slot) {
|
|
51
51
|
const source = textArea({
|
|
52
52
|
rows: 12,
|
|
53
|
-
class: "mvb-in mvb-in--area mvb-in--mono",
|
|
54
53
|
"aria-label": "CSS",
|
|
55
|
-
value: ".card{color:red;padding:10px 12px}.card:hover{color:blue}"
|
|
56
|
-
});
|
|
57
|
-
const result = textArea({ rows: 12, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Formatted CSS" });
|
|
54
|
+
value: ".card{color:red;padding:10px 12px}.card:hover{color:blue}"});
|
|
55
|
+
const result = textArea({ rows: 12, readonly: true, "aria-label": "Formatted CSS" });
|
|
58
56
|
let size = "2";
|
|
59
57
|
|
|
60
58
|
const chips = chipRow(
|
|
@@ -73,8 +71,7 @@ export function mount(slot) {
|
|
|
73
71
|
stack(panel("Indent", chips), panel("CSS", source)),
|
|
74
72
|
stack(panel("Formatted", result))
|
|
75
73
|
),
|
|
76
|
-
foot: actions(copyButton(() => result.value, "Copy CSS", "fill"))
|
|
77
|
-
});
|
|
74
|
+
foot: actions(copyButton(() => result.value, "Copy CSS", "fill"))});
|
|
78
75
|
slot.append(card.node);
|
|
79
76
|
run();
|
|
80
77
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// Lay out a CSS grid: columns, rows and gaps with a live preview.
|
|
2
2
|
import { el, bench, stack, panel, numberInput, rangeInput, output, copyButton, actions, toolcard } from "../core.js";
|
|
3
3
|
|
|
4
|
-
const CELL = "min-height:32px;background:var(--
|
|
4
|
+
const CELL = "min-height:32px;background:var(--jade-soft);border:1px solid var(--jade);border-radius:6px";
|
|
5
5
|
|
|
6
6
|
function slider(label, value) {
|
|
7
7
|
const input = rangeInput({ min: 0, max: 48, value, "aria-label": label });
|
|
8
|
-
const val = el("span", { class: "
|
|
8
|
+
const val = el("span", { class: "text-end font-mono text-2xs text-ink-2" }, `${value}px`);
|
|
9
9
|
const node = el(
|
|
10
10
|
"div",
|
|
11
|
-
{ class: "
|
|
12
|
-
el("span", { class: "
|
|
11
|
+
{ class: "grid items-center gap-2.5 [grid-template-columns:88px_minmax(0,1fr)_62px] max-[45rem]:[grid-template-columns:minmax(0,1fr)_62px]" },
|
|
12
|
+
el("span", { class: "text-2xs font-semibold text-ink-2 max-[45rem]:col-span-2" }, label),
|
|
13
13
|
input,
|
|
14
14
|
val
|
|
15
15
|
);
|
|
@@ -62,10 +62,9 @@ export function mount(slot) {
|
|
|
62
62
|
const card = toolcard({
|
|
63
63
|
body: bench(
|
|
64
64
|
stack(panel("Columns", columns), panel("Rows", rows), columnGap, rowGap),
|
|
65
|
-
stack(el("div", { class: "
|
|
65
|
+
stack(el("div", { class: "grid min-h-40 place-items-center overflow-hidden rounded-r1 border border-orbit bg-deck-2 p-[22px]" }, grid), code)
|
|
66
66
|
),
|
|
67
|
-
foot: actions(copyButton(() => code.textContent, "Copy CSS", "fill"))
|
|
68
|
-
});
|
|
67
|
+
foot: actions(copyButton(() => code.textContent, "Copy CSS", "fill"))});
|
|
69
68
|
slot.append(card.node);
|
|
70
69
|
update();
|
|
71
70
|
|
|
@@ -4,7 +4,7 @@ import { el, bench, stack, panel, textArea, switchControl, copyButton, actions,
|
|
|
4
4
|
const bytes = (text) => new TextEncoder().encode(text).length;
|
|
5
5
|
|
|
6
6
|
const tile = (key, value) =>
|
|
7
|
-
el("div", { class: "
|
|
7
|
+
el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, value), el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
8
8
|
|
|
9
9
|
function minify(css, stripComments) {
|
|
10
10
|
let out = "";
|
|
@@ -55,12 +55,10 @@ function minify(css, stripComments) {
|
|
|
55
55
|
export function mount(slot) {
|
|
56
56
|
const source = textArea({
|
|
57
57
|
rows: 12,
|
|
58
|
-
class: "mvb-in mvb-in--area mvb-in--mono",
|
|
59
58
|
"aria-label": "CSS",
|
|
60
|
-
value: "/* card */\n.card {\n color: red;\n padding: 10px 12px;\n}"
|
|
61
|
-
});
|
|
62
|
-
const
|
|
63
|
-
const stats = el("div", { class: "mvb-stats" });
|
|
59
|
+
value: "/* card */\n.card {\n color: red;\n padding: 10px 12px;\n}"});
|
|
60
|
+
const result = textArea({ rows: 12, readonly: true, "aria-label": "Minified CSS" });
|
|
61
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
|
|
64
62
|
let stripComments = true;
|
|
65
63
|
|
|
66
64
|
const comments = switchControl("Remove comments", { checked: true });
|
|
@@ -87,8 +85,7 @@ export function mount(slot) {
|
|
|
87
85
|
stack(panel("Options", comments), panel("CSS", source)),
|
|
88
86
|
stack(panel("Minified", result), stats)
|
|
89
87
|
),
|
|
90
|
-
foot: actions(copyButton(() => result.value, "Copy CSS", "fill"))
|
|
91
|
-
});
|
|
88
|
+
foot: actions(copyButton(() => result.value, "Copy CSS", "fill"))});
|
|
92
89
|
slot.append(card.node);
|
|
93
90
|
run();
|
|
94
91
|
|
|
@@ -62,7 +62,7 @@ function coerce(value) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function mount(slot) {
|
|
65
|
-
const source = textArea({ rows: 12,
|
|
65
|
+
const source = textArea({ rows: 12, "aria-label": "CSV", placeholder: "name,role\nAda,engineer" });
|
|
66
66
|
const typedBox = checkbox("Typed values", { checked: true });
|
|
67
67
|
const result = output({ rows: 12 });
|
|
68
68
|
const error = notice("error");
|
|
@@ -103,8 +103,7 @@ export function mount(slot) {
|
|
|
103
103
|
stack(panel("CSV", source), panel(null, typedBox), error),
|
|
104
104
|
stack(panel("JSON", result))
|
|
105
105
|
),
|
|
106
|
-
foot: actions(copyButton(() => current, "Copy JSON", "fill"))
|
|
107
|
-
});
|
|
106
|
+
foot: actions(copyButton(() => current, "Copy JSON", "fill"))});
|
|
108
107
|
slot.append(card.node);
|
|
109
108
|
run();
|
|
110
109
|
|
|
@@ -53,27 +53,26 @@ function detectDelimiter(text) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function tile(label) {
|
|
56
|
-
const value = el("span", { class: "
|
|
57
|
-
const node = el("div", { class: "
|
|
56
|
+
const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0");
|
|
57
|
+
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));
|
|
58
58
|
node.set = (text) => { value.textContent = text; };
|
|
59
59
|
return node;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export function mount(slot) {
|
|
63
|
-
const source = textArea({ rows: 12,
|
|
63
|
+
const source = textArea({ rows: 12, "aria-label": "CSV", placeholder: "Paste CSV here" });
|
|
64
64
|
const delimiter = selectInput([
|
|
65
65
|
{ value: "auto", label: "Auto" },
|
|
66
66
|
{ value: ",", label: "Comma" },
|
|
67
67
|
{ value: ";", label: "Semicolon" },
|
|
68
68
|
{ value: "\t", label: "Tab" },
|
|
69
|
-
{ value: "|", label: "Pipe" },
|
|
70
|
-
], { value: "auto", "aria-label": "Delimiter" });
|
|
69
|
+
{ value: "|", label: "Pipe" }], { value: "auto", "aria-label": "Delimiter" });
|
|
71
70
|
const file = fileInput({ accept: ".csv,.tsv,.txt,text/csv", "aria-label": "CSV file" });
|
|
72
71
|
|
|
73
|
-
const tableWrap = el("div", { class: "
|
|
72
|
+
const tableWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
74
73
|
const rowsTile = tile("Rows");
|
|
75
74
|
const colsTile = tile("Columns");
|
|
76
|
-
const stats = el("div", { class: "
|
|
75
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, rowsTile, colsTile);
|
|
77
76
|
const error = notice("error");
|
|
78
77
|
let current = [];
|
|
79
78
|
|
|
@@ -82,7 +81,7 @@ export function mount(slot) {
|
|
|
82
81
|
const text = source.value;
|
|
83
82
|
if (!text.trim()) {
|
|
84
83
|
current = [];
|
|
85
|
-
tableWrap.replaceChildren(el("p", { class: "
|
|
84
|
+
tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Paste CSV or choose a file."));
|
|
86
85
|
rowsTile.set("0");
|
|
87
86
|
colsTile.set("0");
|
|
88
87
|
return;
|
|
@@ -97,7 +96,7 @@ export function mount(slot) {
|
|
|
97
96
|
}
|
|
98
97
|
rowsTile.set(String(body.length));
|
|
99
98
|
colsTile.set(String(header.length));
|
|
100
|
-
tableWrap.replaceChildren(el("table", { class: "
|
|
99
|
+
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" },
|
|
101
100
|
el("thead", {}, el("tr", {}, ...header.map((cell, i) => el("th", {}, cell || `Column ${i + 1}`)))),
|
|
102
101
|
el("tbody", {}, ...body.map((row) => el("tr", {}, ...header.map((_, i) => el("td", {}, row[i] ?? "")))))
|
|
103
102
|
));
|
|
@@ -121,8 +120,7 @@ export function mount(slot) {
|
|
|
121
120
|
stack(panel("CSV", source), panel("Delimiter", delimiter), panel("CSV file", file), error),
|
|
122
121
|
stack(stats, panel("Table", tableWrap))
|
|
123
122
|
),
|
|
124
|
-
foot: actions(clearButton, copyButton(() => current.map((row) => row.join("\t")).join("\n"), "Copy table", "fill"))
|
|
125
|
-
});
|
|
123
|
+
foot: actions(clearButton, copyButton(() => current.map((row) => row.join("\t")).join("\n"), "Copy table", "fill"))});
|
|
126
124
|
slot.append(card.node);
|
|
127
125
|
run();
|
|
128
126
|
|
|
@@ -12,8 +12,7 @@ const LOCALES = [
|
|
|
12
12
|
{ value: "id-ID", label: "Indonesian" },
|
|
13
13
|
{ value: "hi-IN", label: "Hindi" },
|
|
14
14
|
{ value: "ja-JP", label: "Japanese" },
|
|
15
|
-
{ value: "pt-BR", label: "Portuguese (Brazil)" }
|
|
16
|
-
];
|
|
15
|
+
{ value: "pt-BR", label: "Portuguese (Brazil)" }];
|
|
17
16
|
|
|
18
17
|
function format(locale, currency, value) {
|
|
19
18
|
try {
|
|
@@ -28,9 +27,9 @@ export function mount(slot) {
|
|
|
28
27
|
const currency = selectInput(CURRENCIES, { value: "USD", "aria-label": "Currency" });
|
|
29
28
|
const locale = selectInput(LOCALES, { value: "en-US", "aria-label": "Locale" });
|
|
30
29
|
|
|
31
|
-
const amount = el("span", { class: "
|
|
32
|
-
const readout = el("div", { class: "
|
|
33
|
-
el("div", { class: "
|
|
30
|
+
const amount = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
|
|
31
|
+
const readout = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" },
|
|
32
|
+
el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, amount, el("span", { class: "text-2xs font-semibold text-ink-3" }, "Formatted")));
|
|
34
33
|
|
|
35
34
|
const note = notice("note");
|
|
36
35
|
note.write("The amount is formatted, not converted. No exchange rate is applied.");
|
|
@@ -58,8 +57,7 @@ export function mount(slot) {
|
|
|
58
57
|
),
|
|
59
58
|
stack(readout, note)
|
|
60
59
|
),
|
|
61
|
-
foot: actions(copyButton(() => formatted, "Copy amount", "fill"))
|
|
62
|
-
});
|
|
60
|
+
foot: actions(copyButton(() => formatted, "Copy amount", "fill"))});
|
|
63
61
|
slot.append(card.node);
|
|
64
62
|
run();
|
|
65
63
|
|
|
@@ -21,20 +21,20 @@ export function mount(slot) {
|
|
|
21
21
|
let list = Array.isArray(saved) ? saved : [];
|
|
22
22
|
|
|
23
23
|
const title = textInput({ placeholder: "Activity", "aria-label": "Activity" });
|
|
24
|
-
const start = el("input", { class: "
|
|
25
|
-
const end = el("input", { class: "
|
|
24
|
+
const start = el("input", { class: "min-w-0 rounded-r1 border border-orbit bg-deck text-ink transition-[border-color,box-shadow] duration-150 placeholder:text-ink-3 hover:border-orbit-hard focus:border-jade focus:outline-none focus:ring-3 focus:ring-jade-soft w-full min-h-[var(--ctl)] px-3 py-2.5 text-base", type: "time", value: "09:00", "aria-label": "Start time" });
|
|
25
|
+
const end = el("input", { class: "min-w-0 rounded-r1 border border-orbit bg-deck text-ink transition-[border-color,box-shadow] duration-150 placeholder:text-ink-3 hover:border-orbit-hard focus:border-jade focus:outline-none focus:ring-3 focus:ring-jade-soft w-full min-h-[var(--ctl)] px-3 py-2.5 text-base", type: "time", value: "10:00", "aria-label": "End time" });
|
|
26
26
|
|
|
27
|
-
const listWrap = el("div", { class: "
|
|
28
|
-
const stats = el("div", { class: "
|
|
27
|
+
const listWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
28
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
|
|
29
29
|
const overlapNote = notice("error");
|
|
30
30
|
const error = notice("error");
|
|
31
31
|
|
|
32
32
|
const addButton = button("Add", { icon: "plus", kind: "fill" });
|
|
33
33
|
const clearButton = button("Clear day", { icon: "trash" });
|
|
34
34
|
|
|
35
|
-
const tile = (key, value) => el("div", { class: "
|
|
36
|
-
el("span", { class: "
|
|
37
|
-
el("span", { class: "
|
|
35
|
+
const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
|
|
36
|
+
el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
|
|
37
|
+
el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
|
|
38
38
|
|
|
39
39
|
const save = () => writePin(PIN, list);
|
|
40
40
|
|
|
@@ -69,7 +69,7 @@ export function mount(slot) {
|
|
|
69
69
|
el("td", {}, flagged.has(item.id) ? "Overlap" : ""),
|
|
70
70
|
el("td", {}, removeButton(item))
|
|
71
71
|
));
|
|
72
|
-
listWrap.replaceChildren(el("table", { class: "
|
|
72
|
+
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" },
|
|
73
73
|
el("thead", {}, el("tr", {},
|
|
74
74
|
el("th", {}, "Start"), el("th", {}, "End"), el("th", {}, "Activity"),
|
|
75
75
|
el("th", {}, "Length"), el("th", {}, "Note"), el("th", {}, ""))),
|
|
@@ -113,8 +113,7 @@ export function mount(slot) {
|
|
|
113
113
|
),
|
|
114
114
|
stack(stats, panel("Day", listWrap), overlapNote)
|
|
115
115
|
),
|
|
116
|
-
foot: actions(clearButton, addButton)
|
|
117
|
-
});
|
|
116
|
+
foot: actions(clearButton, addButton)});
|
|
118
117
|
slot.append(card.node);
|
|
119
118
|
render();
|
|
120
119
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Masks emails, card numbers and phone numbers in pasted text.
|
|
2
2
|
import { el, textArea, output, toggleRow, copyButton, bench, stack, panel, actions, toolcard } from "../core.js";
|
|
3
3
|
|
|
4
|
-
const EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2
|
|
5
|
-
const CARD = /\b\d[\d -]{11
|
|
6
|
-
const PHONE = /\b\+?\d[\d ().-]{5
|
|
4
|
+
const EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2}/g;
|
|
5
|
+
const CARD = /\b\d[\d -]{11}\d\b/g;
|
|
6
|
+
const PHONE = /\b\+?\d[\d ().-]{5}\d\b/g;
|
|
7
7
|
|
|
8
8
|
function maskDigits(value, keep) {
|
|
9
9
|
const digits = value.replace(/\D/g, "");
|
|
@@ -28,8 +28,7 @@ export function mount(slot) {
|
|
|
28
28
|
const kinds = toggleRow([
|
|
29
29
|
{ value: "email", label: "Email" },
|
|
30
30
|
{ value: "card", label: "Card number" },
|
|
31
|
-
{ value: "phone", label: "Phone number" }
|
|
32
|
-
]);
|
|
31
|
+
{ value: "phone", label: "Phone number" }]);
|
|
33
32
|
|
|
34
33
|
function run() {
|
|
35
34
|
const on = kinds.values();
|
|
@@ -55,13 +54,12 @@ export function mount(slot) {
|
|
|
55
54
|
body: bench(
|
|
56
55
|
stack(
|
|
57
56
|
panel("Values", source),
|
|
58
|
-
panel("
|
|
59
|
-
el("p", { class: "
|
|
57
|
+
panel("What to mask", kinds),
|
|
58
|
+
el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Pattern matching can miss a value, so check the result before sharing.")
|
|
60
59
|
),
|
|
61
60
|
stack(panel("Masked", result))
|
|
62
61
|
),
|
|
63
|
-
foot: actions(copyButton(() => result.textContent, "Copy masked", "fill"))
|
|
64
|
-
});
|
|
62
|
+
foot: actions(copyButton(() => result.textContent, "Copy masked", "fill"))});
|
|
65
63
|
slot.append(card.node);
|
|
66
64
|
run();
|
|
67
65
|
|
|
@@ -10,8 +10,7 @@ const UNITS = [
|
|
|
10
10
|
{ value: "KiB", label: "Kibibyte", factor: 1024 },
|
|
11
11
|
{ value: "MiB", label: "Mebibyte", factor: 1048576 },
|
|
12
12
|
{ value: "GiB", label: "Gibibyte", factor: 1073741824 },
|
|
13
|
-
{ value: "TiB", label: "Tebibyte", factor: 1099511627776 }
|
|
14
|
-
];
|
|
13
|
+
{ value: "TiB", label: "Tebibyte", factor: 1099511627776 }];
|
|
15
14
|
|
|
16
15
|
const byId = Object.fromEntries(UNITS.map((unit) => [unit.value, unit]));
|
|
17
16
|
const options = UNITS.map(({ value, label }) => ({ value, label }));
|
|
@@ -28,13 +27,13 @@ export function mount(slot) {
|
|
|
28
27
|
const value = numberInput({ value: "1", step: "any", "aria-label": "Value" });
|
|
29
28
|
const from = selectInput(options, { value: "MB", "aria-label": "From unit" });
|
|
30
29
|
const to = selectInput(options, { value: "MiB", "aria-label": "To unit" });
|
|
31
|
-
const result = el("span", { class: "
|
|
32
|
-
const stats = el("div", { class: "
|
|
33
|
-
const factor = el("p", { class: "
|
|
30
|
+
const result = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
|
|
31
|
+
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));
|
|
32
|
+
const factor = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
|
|
34
33
|
const scaleNote = notice("note");
|
|
35
34
|
scaleNote.write("KB is 1000 bytes, KiB is 1024 bytes.");
|
|
36
35
|
const error = notice("error");
|
|
37
|
-
const scroll = el("div", { class: "
|
|
36
|
+
const scroll = el("div", { class: "max-h-80 overflow-auto" });
|
|
38
37
|
let text = "";
|
|
39
38
|
|
|
40
39
|
function run() {
|
|
@@ -54,7 +53,7 @@ export function mount(slot) {
|
|
|
54
53
|
const out = (n * a.factor) / b.factor;
|
|
55
54
|
result.textContent = `${fmt(out)} ${b.value}`;
|
|
56
55
|
factor.textContent = `1 ${a.value} = ${fmt(a.factor / b.factor)} ${b.value}`;
|
|
57
|
-
scroll.replaceChildren(el("table", { class: "
|
|
56
|
+
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" },
|
|
58
57
|
el("thead", {}, el("tr", {}, el("th", {}, "Unit"), el("th", {}, "Value"))),
|
|
59
58
|
el("tbody", {}, ...UNITS.map((unit) => el("tr", {},
|
|
60
59
|
el("td", {}, unit.label),
|
|
@@ -78,8 +77,7 @@ export function mount(slot) {
|
|
|
78
77
|
stack(panel("Value", value), panel("From", from), panel("To", to), scaleNote, error),
|
|
79
78
|
stack(panel("Result", stats), factor, panel("All units", scroll))
|
|
80
79
|
),
|
|
81
|
-
foot: actions(swap, copyButton(() => text, "Copy result", "fill"))
|
|
82
|
-
});
|
|
80
|
+
foot: actions(swap, copyButton(() => text, "Copy result", "fill"))});
|
|
83
81
|
slot.append(card.node);
|
|
84
82
|
run();
|
|
85
83
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { el, bench, stack, panel, textArea, selectInput, textInput, notice, 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
|
}
|
|
@@ -17,16 +17,15 @@ export function mount(slot) {
|
|
|
17
17
|
{ value: "number", label: "Number" },
|
|
18
18
|
{ value: "minlength", label: "Minimum length" },
|
|
19
19
|
{ value: "maxlength", label: "Maximum length" },
|
|
20
|
-
{ value: "regex", label: "Regex" },
|
|
21
|
-
], { value: "email", "aria-label": "Rule" });
|
|
20
|
+
{ value: "regex", label: "Regex" }], { value: "email", "aria-label": "Rule" });
|
|
22
21
|
const setting = textInput({ "aria-label": "Rule setting", placeholder: "Number" });
|
|
23
22
|
const settingField = panel("Setting", setting);
|
|
24
23
|
|
|
25
|
-
const tableWrap = el("div", { class: "
|
|
24
|
+
const tableWrap = el("div", { class: "max-h-80 overflow-auto" });
|
|
26
25
|
const totalTile = tile("Total");
|
|
27
26
|
const validTile = tile("Valid");
|
|
28
27
|
const invalidTile = tile("Invalid");
|
|
29
|
-
const stats = el("div", { class: "
|
|
28
|
+
const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, totalTile, validTile, invalidTile);
|
|
30
29
|
const error = notice("error");
|
|
31
30
|
let failing = [];
|
|
32
31
|
|
|
@@ -72,11 +71,11 @@ export function mount(slot) {
|
|
|
72
71
|
failing = failures;
|
|
73
72
|
|
|
74
73
|
if (!values.length) {
|
|
75
|
-
tableWrap.replaceChildren(el("p", { class: "
|
|
74
|
+
tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Paste one value per line."));
|
|
76
75
|
} else if (!failures.length) {
|
|
77
|
-
tableWrap.replaceChildren(el("p", { class: "
|
|
76
|
+
tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Every value passes."));
|
|
78
77
|
} else {
|
|
79
|
-
tableWrap.replaceChildren(el("table", { class: "
|
|
78
|
+
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" },
|
|
80
79
|
el("thead", {}, el("tr", {}, el("th", {}, "#"), el("th", {}, "Value"), el("th", {}, "Reason"))),
|
|
81
80
|
el("tbody", {}, ...failures.map((row) => el("tr", {},
|
|
82
81
|
el("th", {}, String(row.line)),
|
|
@@ -100,8 +99,7 @@ export function mount(slot) {
|
|
|
100
99
|
stack(panel("Values", source), panel("Rule", rule), settingField, error),
|
|
101
100
|
stack(stats, panel("Failed rows", tableWrap))
|
|
102
101
|
),
|
|
103
|
-
foot: actions(copyButton(() => failing.map((row) => row.value).join("\n"), "Copy failing values", "fill"))
|
|
104
|
-
});
|
|
102
|
+
foot: actions(copyButton(() => failing.map((row) => row.value).join("\n"), "Copy failing values", "fill"))});
|
|
105
103
|
slot.append(card.node);
|
|
106
104
|
run();
|
|
107
105
|
|
|
@@ -30,18 +30,18 @@ function calendarDiff(from, to) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const kvRow = (key, value) =>
|
|
33
|
-
el("div", { class: "
|
|
33
|
+
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));
|
|
34
34
|
|
|
35
35
|
export function mount(slot) {
|
|
36
36
|
const start = textInput({ type: "date", value: "2026-01-01", "aria-label": "Start date" });
|
|
37
37
|
const end = textInput({ type: "date", value: "2026-12-31", "aria-label": "End date" });
|
|
38
38
|
const includeEnd = checkbox("Include the end date", { checked: false });
|
|
39
|
-
const days = el("span", { class: "
|
|
40
|
-
const weeks = el("span", { class: "
|
|
41
|
-
const calendar = el("span", { class: "
|
|
39
|
+
const days = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
40
|
+
const weeks = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
41
|
+
const calendar = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
|
|
42
42
|
const kv = el(
|
|
43
43
|
"div",
|
|
44
|
-
{ class: "
|
|
44
|
+
{ class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" },
|
|
45
45
|
kvRow("Total days", days),
|
|
46
46
|
kvRow("Weeks", weeks),
|
|
47
47
|
kvRow("Calendar gap", calendar)
|
|
@@ -89,8 +89,7 @@ export function mount(slot) {
|
|
|
89
89
|
stack(panel("Start", start), panel("End", end), includeEnd, error),
|
|
90
90
|
stack(panel("Difference", kv))
|
|
91
91
|
),
|
|
92
|
-
foot: actions(copyButton(() => text, "Copy result", "fill"))
|
|
93
|
-
});
|
|
92
|
+
foot: actions(copyButton(() => text, "Copy result", "fill"))});
|
|
94
93
|
slot.append(card.node);
|
|
95
94
|
run();
|
|
96
95
|
|