max / goingson
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
6 files changed,
+106 insertions,
-32 deletions
| @@ -3444,9 +3444,9 @@ | |||
| 3444 | 3444 | ||
| 3445 | 3445 | [[package]] | |
| 3446 | 3446 | name = "makeover-build" | |
| 3447 | - | version = "0.55.0" | |
| 3447 | + | version = "0.56.0" | |
| 3448 | 3448 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3449 | - | checksum = "725a4e9fad30d4d9fa840c408a70dfea583f0d5ada611a95a131a63429b4391a" | |
| 3449 | + | checksum = "56c8903ef617932723aea44f7ada31c7ce4f89d008e8d25ebaee956b2258bb91" | |
| 3450 | 3450 | dependencies = [ | |
| 3451 | 3451 | "makeover", | |
| 3452 | 3452 | "makeover-geometry", | |
| @@ -3462,9 +3462,9 @@ | |||
| 3462 | 3462 | ||
| 3463 | 3463 | [[package]] | |
| 3464 | 3464 | name = "makeover-layout" | |
| 3465 | - | version = "0.36.0" | |
| 3465 | + | version = "0.37.0" | |
| 3466 | 3466 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3467 | - | checksum = "9ffed28fd6f311d8603b9fe02cffc14bacf29b840c486f84e8ff4866a4748514" | |
| 3467 | + | checksum = "369bc3c3e0ee91d24b3552f48f1ecb1764bca953725fb817df33b2dc80f2d34f" | |
| 3468 | 3468 | ||
| 3469 | 3469 | [[package]] | |
| 3470 | 3470 | name = "makeover-timing" | |
| @@ -3477,9 +3477,9 @@ | |||
| 3477 | 3477 | ||
| 3478 | 3478 | [[package]] | |
| 3479 | 3479 | name = "makeover-touch" | |
| 3480 | - | version = "0.26.0" | |
| 3480 | + | version = "0.27.0" | |
| 3481 | 3481 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3482 | - | checksum = "941676f114fdb8b8e2dbd2e35dd0149d409212982b37139de831d9865f664d77" | |
| 3482 | + | checksum = "b180e22917189e05d291bfec0e930b5e6c2952dc7bf6e2f7a2262b903431cc72" | |
| 3483 | 3483 | dependencies = [ | |
| 3484 | 3484 | "makeover-geometry", | |
| 3485 | 3485 | "makeover-layout", | |
| @@ -3487,9 +3487,9 @@ | |||
| 3487 | 3487 | ||
| 3488 | 3488 | [[package]] | |
| 3489 | 3489 | name = "makeover-tui" | |
| 3490 | - | version = "0.36.0" | |
| 3490 | + | version = "0.37.0" | |
| 3491 | 3491 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3492 | - | checksum = "6ecee186af0fc104be9237defc437be2bfd8512cf5064ba0ff7a9298b01de081" | |
| 3492 | + | checksum = "b5e2ea93b84f2cb85fde760d360ff4c095320db242a0d0c08cbaf2f396a8de8e" | |
| 3493 | 3493 | dependencies = [ | |
| 3494 | 3494 | "makeover", | |
| 3495 | 3495 | "makeover-layout", | |
| @@ -3499,9 +3499,9 @@ | |||
| 3499 | 3499 | ||
| 3500 | 3500 | [[package]] | |
| 3501 | 3501 | name = "makeover-webview" | |
| 3502 | - | version = "0.62.0" | |
| 3502 | + | version = "0.63.0" | |
| 3503 | 3503 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3504 | - | checksum = "546fb283399000bcd303b1d4d59b7d4c560eea8d6c40c4bed172f0c32a50c8e1" | |
| 3504 | + | checksum = "9149f06aa7b8f4660609a680169d76075d91def63c23127bd84af9b183be22fa" | |
| 3505 | 3505 | dependencies = [ | |
| 3506 | 3506 | "makeover-geometry", | |
| 3507 | 3507 | "makeover-layout", | |
| @@ -4717,7 +4717,7 @@ | |||
| 4717 | 4717 | ||
| 4718 | 4718 | [[package]] | |
| 4719 | 4719 | name = "quasi-http" | |
| 4720 | - | version = "0.71.0" | |
| 4720 | + | version = "0.72.0" | |
| 4721 | 4721 | dependencies = [ | |
| 4722 | 4722 | "form_urlencoded", | |
| 4723 | 4723 | "http", | |
| @@ -4726,7 +4726,7 @@ | |||
| 4726 | 4726 | ||
| 4727 | 4727 | [[package]] | |
| 4728 | 4728 | name = "quasi-notifs" | |
| 4729 | - | version = "0.71.0" | |
| 4729 | + | version = "0.72.0" | |
| 4730 | 4730 | dependencies = [ | |
| 4731 | 4731 | "quasi-router", | |
| 4732 | 4732 | "synckit-config", | |
| @@ -4734,14 +4734,14 @@ | |||
| 4734 | 4734 | ||
| 4735 | 4735 | [[package]] | |
| 4736 | 4736 | name = "quasi-router" | |
| 4737 | - | version = "0.71.0" | |
| 4737 | + | version = "0.72.0" | |
| 4738 | 4738 | dependencies = [ | |
| 4739 | 4739 | "makeover-layout", | |
| 4740 | 4740 | ] | |
| 4741 | 4741 | ||
| 4742 | 4742 | [[package]] | |
| 4743 | 4743 | name = "quasi-tauri" | |
| 4744 | - | version = "0.71.0" | |
| 4744 | + | version = "0.72.0" | |
| 4745 | 4745 | dependencies = [ | |
| 4746 | 4746 | "http", | |
| 4747 | 4747 | "quasi-http", | |
| @@ -4751,7 +4751,7 @@ | |||
| 4751 | 4751 | ||
| 4752 | 4752 | [[package]] | |
| 4753 | 4753 | name = "quasi-type" | |
| 4754 | - | version = "0.1.0" | |
| 4754 | + | version = "0.1.1" | |
| 4755 | 4755 | dependencies = [ | |
| 4756 | 4756 | "brotli", | |
| 4757 | 4757 | "font-types", | |
| @@ -4767,7 +4767,7 @@ | |||
| 4767 | 4767 | ||
| 4768 | 4768 | [[package]] | |
| 4769 | 4769 | name = "quasi-webview" | |
| 4770 | - | version = "0.71.0" | |
| 4770 | + | version = "0.72.0" | |
| 4771 | 4771 | dependencies = [ | |
| 4772 | 4772 | "docengine", | |
| 4773 | 4773 | "makeover-layout", | |
| @@ -8506,15 +8506,15 @@ | |||
| 8506 | 8506 | ||
| 8507 | 8507 | [[patch.unused]] | |
| 8508 | 8508 | name = "quasi-axum" | |
| 8509 | - | version = "0.71.0" | |
| 8509 | + | version = "0.72.0" | |
| 8510 | 8510 | ||
| 8511 | 8511 | [[patch.unused]] | |
| 8512 | 8512 | name = "quasi-basics" | |
| 8513 | - | version = "0.71.0" | |
| 8513 | + | version = "0.72.0" | |
| 8514 | 8514 | ||
| 8515 | 8515 | [[patch.unused]] | |
| 8516 | 8516 | name = "quasi-immediate" | |
| 8517 | - | version = "0.71.0" | |
| 8517 | + | version = "0.72.0" | |
| 8518 | 8518 | ||
| 8519 | 8519 | [[patch.unused]] | |
| 8520 | 8520 | name = "quasi-store" |
| @@ -105,7 +105,7 @@ | |||
| 105 | 105 | notify = "8.2" | |
| 106 | 106 | notify-debouncer-mini = "0.7" | |
| 107 | 107 | makeover = "3.0" | |
| 108 | - | makeover-tui = "0.36.0" | |
| 108 | + | makeover-tui = "0.37.0" | |
| 109 | 109 | toml = "1.1" | |
| 110 | 110 | ||
| 111 | 111 | # Enums |
| @@ -18,25 +18,25 @@ | |||
| 18 | 18 | # Materialises all three generated files: themes/, geometry.css, layout.css, | |
| 19 | 19 | # and holds both drift checks this build.rs used to carry itself: touch density | |
| 20 | 20 | # as of 0.17, breakpoints as of 0.18. | |
| 21 | - | makeover-build = "0.55.0" | |
| 21 | + | makeover-build = "0.56.0" | |
| 22 | 22 | # Cuts the two house faces into frontend/fonts/. A git dependency because | |
| 23 | 23 | # quasi-type is `publish = false`, which is also why makeover-build cannot do | |
| 24 | 24 | # this and only emits the CSS that fetches the result. The rev is the one | |
| 25 | 25 | # shop's `shop-font`, Balanced Breakfast and Alloy's `QUASI_TYPE_REV` name: the | |
| 26 | 26 | # house face is one face, so they move together or a user sees two Quasi Monos. | |
| 27 | - | quasi-type = { git = "https://makenot.work/git/max/quasi-type.git", version = "0.1", rev = "e40330602e68fbdd2a9d2917bdec33a7ce573a1f" } | |
| 27 | + | quasi-type = { git = "https://makenot.work/git/max/quasi-type.git", version = "0.1.1", rev = "e57a57f35563252b5ed00a8caf1262517f3d51f4" } | |
| 28 | 28 | # The table CSS is generated here too: the columns are this app's, so the | |
| 29 | 29 | # shared helper cannot know them, but the tracks and the narrowing rules come | |
| 30 | 30 | # from the description rather than from hand-written nth-child cuts. | |
| 31 | - | makeover-webview = "0.62.0" | |
| 32 | - | makeover-layout = "0.36.0" | |
| 31 | + | makeover-webview = "0.63.0" | |
| 32 | + | makeover-layout = "0.37.0" | |
| 33 | 33 | # Width. Direct rather than through makeover-webview, because the narrow table | |
| 34 | 34 | # pass keys off SizeClass::Compact and a boundary reached transitively is a | |
| 35 | 35 | # boundary nobody pinned. | |
| 36 | 36 | makeover-geometry = "0.7" | |
| 37 | 37 | # Only to write its selection and clock scripts into the frontend. Those two are | |
| 38 | 38 | # the whole of `frontend/js/` since the swap. | |
| 39 | - | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.71" } | |
| 39 | + | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.72" } | |
| 40 | 40 | ||
| 41 | 41 | [dependencies] | |
| 42 | 42 | goingson-core = { workspace = true } | |
| @@ -54,10 +54,10 @@ | |||
| 54 | 54 | # dependency's source even with the feature off -- so a public clone could not | |
| 55 | 55 | # build at all against a URL it could not reach. quasi went public that day and | |
| 56 | 56 | # the URL moved here with it. | |
| 57 | - | quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.71" } | |
| 58 | - | quasi-http = { git = "https://makenot.work/git/max/quasi.git", version = "0.71" } | |
| 59 | - | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.71" } | |
| 60 | - | quasi-tauri = { git = "https://makenot.work/git/max/quasi.git", version = "0.71" } | |
| 57 | + | quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.72" } | |
| 58 | + | quasi-http = { git = "https://makenot.work/git/max/quasi.git", version = "0.72" } | |
| 59 | + | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.72" } | |
| 60 | + | quasi-tauri = { git = "https://makenot.work/git/max/quasi.git", version = "0.72" } | |
| 61 | 61 | ||
| 62 | 62 | # The notification declaration, and it is NOT behind the `quasi` feature: the | |
| 63 | 63 | # watcher is desktop app behaviour rather than a described screen, and the | |
| @@ -74,7 +74,7 @@ | |||
| 74 | 74 | # before it has ported its screens cannot take it. `notifications::Notifier` is | |
| 75 | 75 | # the eight lines meanwhile, and it goes when the flip makes quasi-router | |
| 76 | 76 | # unconditional here. | |
| 77 | - | quasi-notifs = { git = "https://makenot.work/git/max/quasi.git", version = "0.71", features = ["synckit", "describe"] } | |
| 77 | + | quasi-notifs = { git = "https://makenot.work/git/max/quasi.git", version = "0.72", features = ["synckit", "describe"] } | |
| 78 | 78 | ||
| 79 | 79 | # Tauri | |
| 80 | 80 | tauri = { workspace = true, features = ["image-png", "devtools"] } | |
| @@ -139,8 +139,8 @@ | |||
| 139 | 139 | # The forms emitter and the description it renders. Runtime deps, not build: | |
| 140 | 140 | # form markup depends on the value, the error and the options at the moment a | |
| 141 | 141 | # modal opens, so it cannot be materialised the way the stylesheet is. | |
| 142 | - | makeover-webview = "0.62.0" | |
| 143 | - | makeover-layout = "0.36.0" | |
| 142 | + | makeover-webview = "0.63.0" | |
| 143 | + | makeover-layout = "0.37.0" | |
| 144 | 144 | # Browser opening | |
| 145 | 145 | open = { workspace = true } | |
| 146 | 146 |
| @@ -616,6 +616,7 @@ | |||
| 616 | 616 | ("quasi-copy.js", quasi_webview::COPY_JS), | |
| 617 | 617 | ("quasi-repeat.js", quasi_webview::REPEAT_JS), | |
| 618 | 618 | ("quasi-awaiting.js", quasi_webview::AWAITING_JS), | |
| 619 | + | ("quasi-instant.js", quasi_webview::INSTANT_JS), | |
| 619 | 620 | ] { | |
| 620 | 621 | fs::write(frontend.join("js").join(name), source) | |
| 621 | 622 | .unwrap_or_else(|error| panic!("write js/{name}: {error}")); |
| @@ -224,6 +224,12 @@ | |||
| 224 | 224 | // would be inventing a question the app never asked. | |
| 225 | 225 | upper_name: None, | |
| 226 | 226 | extended: spec.extended, | |
| 227 | + | // makeover-layout 0.37.0's instant flag, on the same footing again: | |
| 228 | + | // the JS form spec has no way to say a datetime is submitted as the | |
| 229 | + | // moment it names, and this runtime form posts to Tauri commands | |
| 230 | + | // rather than to a route storing an instant. Saying it here would | |
| 231 | + | // convert a value nothing asked to have converted. | |
| 232 | + | as_instant: false, | |
| 227 | 233 | }; | |
| 228 | 234 | ||
| 229 | 235 | let value = match kind { |
| @@ -1,0 +1,67 @@ | |||
| 1 | + | // Submitting the moment a reader meant, rather than the words they typed. | |
| 2 | + | // | |
| 3 | + | // A `datetime-local` box asks for a time the way a person says one -- "the 14th | |
| 4 | + | // at half past two" -- and that names a different moment in Denver than it does | |
| 5 | + | // in Berlin. A route storing an instant needs the moment, and nothing in HTML | |
| 6 | + | // converts one to the other: the box submits the characters. So somebody | |
| 7 | + | // converts, and in this renderer that is here. | |
| 8 | + | // | |
| 9 | + | // It is here rather than above the renderer because the browser is the only | |
| 10 | + | // party that knows what "your computer's time zone" means. A description cannot | |
| 11 | + | // answer it; a server can only guess; a terminal and an egui host would each | |
| 12 | + | // answer it their own way. `makeover_layout::Field::as_instant` is the | |
| 13 | + | // description saying it wants the conversion and declining to say how, and this | |
| 14 | + | // file is the how for one host. | |
| 15 | + | // | |
| 16 | + | // It reads one attribute the form renderer writes, `data-instant`, and it is | |
| 17 | + | // the whole of the per-app publish-at plumbing this stack exists to delete. The | |
| 18 | + | // MNW server carried its own copy under a private `data-config` vocabulary. | |
| 19 | + | (() => { | |
| 20 | + | "use strict"; | |
| 21 | + | ||
| 22 | + | // The mark makeover-webview puts on a datetime input whose description | |
| 23 | + | // asked for an instant. Only that kind is marked: a date and a time are | |
| 24 | + | // each half a moment and cannot name one on their own. | |
| 25 | + | const MARK = "data-instant"; | |
| 26 | + | ||
| 27 | + | /** | |
| 28 | + | * The absolute instant a local wall-clock string names, as RFC 3339. | |
| 29 | + | * | |
| 30 | + | * `new Date(v)` reads a bare `YYYY-MM-DDTHH:mm` in the browser's own zone, | |
| 31 | + | * which is exactly the reading wanted. A value the browser cannot parse is | |
| 32 | + | * left alone rather than replaced with `Invalid Date`: an unparseable value | |
| 33 | + | * is a validation failure the route should see and answer, and rewriting it | |
| 34 | + | * here would turn a legible error into an unreadable one. | |
| 35 | + | */ | |
| 36 | + | const instant = (local) => { | |
| 37 | + | const at = new Date(local); | |
| 38 | + | return Number.isNaN(at.getTime()) ? null : at.toISOString(); | |
| 39 | + | }; | |
| 40 | + | ||
| 41 | + | // Rewrite on the way out, on the request htmx is about to make, so nothing | |
| 42 | + | // the reader can see changes: the box keeps showing the time they typed and | |
| 43 | + | // the wire carries the moment it names. | |
| 44 | + | // | |
| 45 | + | // The walk is over the submitting element's own marked inputs rather than | |
| 46 | + | // over the document, so a page with two forms on it converts the one being | |
| 47 | + | // submitted. `htmx:config:request` is htmx 4's name; 2.x spelled it | |
| 48 | + | // `htmx:configRequest`. | |
| 49 | + | document.body.addEventListener("htmx:config:request", (event) => { | |
| 50 | + | const source = event.detail?.ctx?.sourceElement; | |
| 51 | + | const body = event.detail?.ctx?.request?.body; | |
| 52 | + | if (!source?.querySelectorAll || !body) return; | |
| 53 | + | ||
| 54 | + | const marked = | |
| 55 | + | source.matches?.(`[${MARK}]`) === true | |
| 56 | + | ? [source] | |
| 57 | + | : source.querySelectorAll(`[${MARK}]`); | |
| 58 | + | for (const input of marked) { | |
| 59 | + | const name = input.getAttribute("name"); | |
| 60 | + | if (!name) continue; | |
| 61 | + | const local = body.get(name); | |
| 62 | + | if (typeof local !== "string" || !local) continue; | |
| 63 | + | const moment = instant(local); | |
| 64 | + | if (moment !== null) body.set(name, moment); | |
| 65 | + | } | |
| 66 | + | }); | |
| 67 | + | })(); |