feat: integration search bar
This commit is contained in:
1 parent
a8fea8d900
commit
25d9c30b8a
22 files changed
+2558
-41
No files matched your search
@@ -114,3 +114,51 @@ New group "Search and sharing" after Articles, in the sidebar index and the mobi
|
||||
- GET /v1/article/{id}/seo: the resolved SEO object. Fields: title, description, canonical_url, robots, og{type,title,description,url,site_name,image,image_alt,locale}, twitter{card,title,description,image,image_alt}, image{url,alt,source}, authors[{name,url,same_as}], published_at, modified_at, fallbacks, json_ld. Drafts answer 404 to anonymous callers.
|
||||
- GET /v1/site/{key}/sitemap?page=&size=: yes, shown per site by key. Items: { url, modified_at, noindex }. Total in X-Total-Count. Sizes 25, 50, 100, 500, default 100. Errors: 400 "The request cannot be processed due to a mismatch in the format of the body." (same text as the other routes; bad `page` or `size`), 401, 404 `site_not_found` (unknown site key; this is the body the API returns, shown as a code and not rewritten as prose).
|
||||
PATCH /v1/article/{id} lists the new optional fields (slug, excerpt, seo_title, seo_description, cover_image_id, cover_image_alt, social_title, social_description, social_image_id, canonical_url, noindex, seo_dismissed). The 403 row of the HTTP status table adds: site SEO defaults are owner only; article SEO fields need only the right to edit the article.
|
||||
|
||||
|
||||
## Search (jump-to palette)
|
||||
Board: group "Integration", states 8a to 8h, desktop 1440×900 and mobile 390×844, light and dark. Search never hides or filters the page. It only jumps, so find-in-page and deep links keep working.
|
||||
|
||||
### Behaviour
|
||||
- Trigger, desktop: a field-style button in the page header, right of the title block, 320×36. Placeholder "Search the API reference…", "/" key hint. Mobile: 44×44 icon button right of "Jump to", inside the sticky bar. Opens with "/" (when focus is not in an input), Ctrl+K and Cmd+K. Both shortcuts are announced with aria-keyshortcuts.
|
||||
- Palette: modal, 720 px wide, 96 px from the top, on the existing overlay. Mobile: full-screen sheet with a "Cancel" button (44 px) in the input row. Focus goes to the input; on close it returns to the trigger.
|
||||
- Groups: "Endpoints" (max 6 rows, then "N more endpoints. Keep typing to narrow the list."), then "Sections". Empty query: one group "Suggested" with 5 rows.
|
||||
- Match: every space-separated term must appear (case-insensitive substring) in method, path, description or access chip, or in a request field name, or in an error code or message. Rows matched only in a field or error show a second line ("Body field", "Query parameter" or "Error") with the match. Terms are highlighted with --rc-sand / --rc-on-sand. Rows matched in the path or description sort first.
|
||||
- Selecting: Enter or click closes the palette, scrolls to the card (or section heading), expands the card, moves focus to the card button, and flashes the row (--rc-sand fill, 2 px --ui-primary ring, 1.5 s, then the open-card fill). With prefers-reduced-motion the flash is a static ring with no fade. The index active item updates through the existing scroll-spy. The URL hash becomes #ep-<id> so the result can be shared.
|
||||
- Keys: Up and Down move (wrap), Enter opens, Esc closes, Home and End go to the first and last row. Typing resets the selection to the first row.
|
||||
- Roles: input role="combobox" with aria-expanded, aria-controls, aria-autocomplete="list", aria-activedescendant; list role="listbox"; groups role="group" with aria-labelledby; rows role="option" with aria-selected and a full aria-label (method, path, description, access). A polite live region announces the count.
|
||||
|
||||
### Row anatomy
|
||||
- Endpoint: method badge (existing colours), mono path 13/500, one-line description (ellipsis), access chip. Session-only: dashed muted badge, 400 weight path, dashed chip with lock icon, text --ui-text-muted.
|
||||
- Section: icon in the badge column (hash, or lock for Session only), title 500, muted description.
|
||||
- Selected: --ui-bg-elevated with a 2 px --ui-primary bar on the left (same as the section index active item). Hover: --ui-bg-elevated.
|
||||
- Mobile rows: 56 px min height, badge and path on line 1, chip then description on line 2.
|
||||
|
||||
### Copy per state
|
||||
| # | State | Copy |
|
||||
|---|---|---|
|
||||
| 8a | Trigger focused | Placeholder "Search the API reference…"; key hint "/"; aria-label "Search the API reference" |
|
||||
| 8b | Open, empty | Input placeholder "Search the API reference…"; group "Suggested": Authentication ("Public access and API keys"), POST /v1/media/ ("Upload an image (multipart)." Verified user), Errors ("Status codes and messages"), GET /v1/article/ ("List articles, one page at a time." Public), PATCH /v1/user/me ("Update my profile." Verified user); footer "↑↓ Move", "↵ Open", "Esc Close", count "5 suggestions"; live "5 suggestions" |
|
||||
| 8c | Typing "media" | Groups "Endpoints" (6 media routes) and "Sections" (Media, "6 routes"); count and live "7 results" |
|
||||
| 8d | "404", third row selected | Endpoints list the six first 404 routes with an "Error" line, for example "404 Article not found"; Sections: Errors ("Status codes and messages"); "6 more endpoints. Keep typing to narrow the list."; count "13 results"; live "13 results, showing 7" |
|
||||
| 8e | "keep_id" | POST /v1/media/merge, "Merge identical copies into one image.", Verified user, line "Body field keep_id"; "1 result" |
|
||||
| 8f | "login" | POST /v1/auth/login, "Log in", chip "Session only" (lock); Section "Session only", "12 routes, not available to API keys"; "2 results" |
|
||||
| 8g | No results | No match for "xyz". Try a path, a method or a status code like 404. Count "0 results"; live "No results" |
|
||||
| 8h | After selecting | Page only: POST /v1/media/merge expanded and highlighted; index and Jump to read "Media" |
|
||||
|
||||
### Nuxt UI v4 mapping
|
||||
- Trigger: UButton variant="outline" color="neutral" with a UIcon and UKbd (desktop); UButton icon-only (mobile). Shortcut: defineShortcuts({ '/': open, meta_k: open, ctrl_k: open }).
|
||||
- Palette: UModal (fullscreen on mobile via the fullscreen prop) wrapping UCommandPalette with :groups, v-model:search-term, placeholder, :close (mobile "Cancel"). Fuse options off for the endpoint group (our own multi-field match), highlight via the #item-label and #item-description slots. UCommandPalette provides the combobox and listbox roles, aria-activedescendant and arrow-key handling.
|
||||
- Rows: custom #item slot with UBadge (method, access chip), mono path, UIcon (lock, hash). Footer: #footer slot with UKbd for ↑ ↓ ↵ Esc. Empty: #empty slot. Live region: a visually hidden element with aria-live="polite".
|
||||
- Flash: a CSS class on the EndpointCard row driven by a ref; uses var(--rc-sand) and var(--ui-primary) only.
|
||||
|
||||
### Assumptions to confirm
|
||||
- Search is client-side over a static index built from the same data as the cards (method, path, first sentence of the description, access, request fields, error codes and messages). It does not search code samples, prose or response examples.
|
||||
- Matching is substring per term, not fuzzy ("mdia" does not match "media").
|
||||
- The palette shows the first sentence of each endpoint description, not the full text.
|
||||
- Endpoints are capped at 6 rows with a count line; sections are never capped.
|
||||
- Recent searches are left out. Open question: store the last 3 queries in localStorage?
|
||||
- "/" is ignored while a text field has focus. Cmd+K on this route does not clash with any back-office shortcut (to confirm).
|
||||
- The search trigger scrolls away with the header on desktop. Open question: keep it sticky next to the section index?
|
||||
- Highlight uses --rc-sand on --rc-on-sand. On the selected row (--ui-bg-elevated) the two tones are close; the dark text keeps contrast. No new token is needed.
|
||||
- The 1.5 s flash duration and the #ep-<id> hash are proposals.
|
||||
Reference in new issue
Block a user