feat(web): polish the WASM site - UX, help, parsing, assets

- About panel (collapsible, closed by default with a pulsing "Help" badge)
  explaining the tool; the `help` command now prints a full command reference
  instead of "HELP" (benefits the CLI too).
- Live generation as you type; Store button; masked output that stays mono-width
  (gen masks only the password column, never the header); command history with
  Up/Down (persisted); console auto-scroll; Export fixed (uses `dump`); Import.
- Name field normalizes to its canonical parsed form on blur; quick-gen and Store
  resolve the real entry name, so a leading prefix like `*P0 test1` is handled
  correctly (new hel_parse / hel_parse_name wasm helpers).
- Parser: prefix-only forms now parse with defaults - `*P0 test1` ->
  `*P0 test1 R 99 <today>`, `*P0 test1 R`, `*P0 test1 20R` - via new qpname/npname
  rules mirroring qname/nname; the fully-qualified form is unchanged.
- Favicons + web app manifest + enso asset; pkg rebuilt.
This commit is contained in:
Oleksandr Kozachuk
2026-06-08 20:11:24 +02:00
parent 03c5dadccb
commit 3031105000
17 changed files with 503 additions and 98 deletions
+23
View File
@@ -23,6 +23,29 @@ pub fn hel_command(cmd: String) -> String {
lkprint.out.output().join("\n")
}
/// Parse a password spec (e.g. `exa91` or `exa91 20R 99 2020-01-01`) and return
/// the canonical normalized form hel actually uses (name + mode + seq + date +
/// comment), without touching state. Returns the input unchanged if it does not
/// parse. Used by the UI to rewrite the name field on blur.
#[wasm_bindgen]
pub fn hel_parse(spec: String) -> String {
match command_parser::name(&spec) {
Ok(p) => p.to_string().trim().to_string(),
Err(_) => spec,
}
}
/// Parse a spec and return just the entry name hel resolves it to. Handles a
/// leading prefix (e.g. `*P0 test1 …` → `test1`), which a naive first-token
/// split would get wrong. Falls back to the first whitespace token.
#[wasm_bindgen]
pub fn hel_parse_name(spec: String) -> String {
match command_parser::name(&spec) {
Ok(p) => p.name,
Err(_) => spec.split_whitespace().next().unwrap_or("").to_string(),
}
}
/// Run a whole multi-line script (every `add …` line, `set …`, etc.) against the
/// shared state in one call. Used to bulk-import a pasted catalog (e.g. the text
/// of the Notion page) and to load the persisted catalog from localStorage.