50 Commits
Author SHA1 Message Date
Will Miao 965bfd33cd feat(controls): keep model counts readable in large libraries
Counts in the filter panel chips (base models, tags, model types), the All Types
dropdown and the Refresh scope rows were rendered as raw digits, so a library with
10k+ models turned every chip into a five digit pill that dominated the row it sat
in — and the Refresh menu grouped its numbers while the filter panel did not.

One formatter now renders all of them (`formatCount`): exact and locale-grouped
below 10,000, abbreviated to three significant digits above it, and abbreviated
only where the locale's Intl compact form is a real unit and narrower than the
plain number — German keeps 18.475 instead of the rounded 18.500, Russian keeps
18 475 instead of the wider 18,5 тыс.

Their hover text is always present and always exact ({name} — {count} models, and
... recipes on the Recipes page): an affordance that only exists above a threshold
is undiscoverable, and the tooltip is also what reveals a chip label that CSS has
ellipsized.

Chips gain a two-slot layout (the name ellipsizes, the count keeps a tabular
right-aligned slot) so a long tag name can no longer push the count out of the
chip; Refresh rows move from float:right to a flex row, which keeps the counts in
a right-hand column and lets a long root label ellipsize. The All Types group
tooltip moves onto its trigger so it stops leaking onto the menu options.

The two new strings ship as [TODO: Translate] placeholders in the nine locales;
the translation pass is the next commit.
2026-10-18 18:34:16 +08:00
Will Miao 3d65e044f8 feat(controls): add model sub-type quick-switch dropdown to the controls bar
Single-select Model Type dropdown next to the sort control on the loras,
checkpoints and other pages (hidden when only one sub-type exists).
Selection maps to filters.modelTypes, persists via the existing filter
storage, and stays in sync with the filter panel's multi-select chips.
2026-10-18 16:16:59 +08:00
Will Miao c0165919b3 fix(theme): readable on-accent text color and unified accent aliases
Solid-accent buttons used the page text color (--lora-text) or white,
which falls below WCAG AA on the mid-bright accent (L 52-72%) in every
theme/preset — e.g. ~1.7:1 in dark+solarized, making primary buttons
hard to read. Add --color-accent-contrast (dark, low-chroma, same hue,
derived per preset) aliased as --text-on-accent, and switch ~90
accent-background selectors (primary/confirm buttons, nav items, chips,
badges, checkmarks) to it.

Also define the previously dangling --lora-accent-l/c/h, --lora-accent-hover
and --lora-accent-light aliases (fixing ~40 dead declarations), replace the
hardcoded rgba(--lora-accent-rgb, 79 70 229) fallbacks with oklch channel
syntax, and add the missing margin above .template-custom-input in
settings.
2026-10-10 20:41:10 +08:00
Will Miao 470d85cca6 feat(scanner): scan a single root and keep unreachable entries (#1108)
Refreshing had no way to say "scan only this drive": a user with three external
drives had to spin all of them up for every refresh, and switching a drive off
made the next refresh treat its whole library as deleted (rows pruned from the
memory cache and the SQLite cache, preview_url stripped on the next scroll).

Backend (py/services/model_scanner.py, py/config.py):
* ReconcileScope(roots, folder) + _reconcile_cache(scope=...): files inside the
  scope reconcile normally, everything outside is neither re-read nor removed.
  The folder half is plumbing for the sidebar entry in the next change.
* Path-level pruning guard: cached entries under a path this walk could not
  read are kept and reported instead of removed. Sources: a configured root that
  is not reachable (drive switched off while LM runs), a directory os.walk
  failed to enter (permissions / I/O error / Windows junction to an offline
  drive), and a known first-level symlink whose target is gone
  (Config.iter_path_mappings()).
* The recorded folder list is unioned instead of replaced whenever the scan did
  not verify every root, so a scoped scan cannot empty the sidebar.
* _reconcile_cache returns a summary (added / removed / repaired /
  scanned_roots / skipped_roots / unavailable_paths / kept_unreachable),
  exposed as ModelScanner.last_reconcile_summary, returned by
  BaseModelService.scan_models() and broadcast in the completed WS payload.
* _root_display_labels(): set-aware labels ("G: loras", "usb/loras") grown
  leftwards with real parent segments until unique, shared by the walk-progress
  line and the roots API.
* GET /scan accepts repeated `roots` (400 for unknown roots, 400 combined with
  full_rebuild=true); GET /roots gains root_details (label / reachable / cached
  count) while `roots` stays a plain path list for existing callers.
* serve_preview: a 404 no longer clears the cached preview_url when the file's
  own directory is unreachable - browsing the grid with a drive off used to
  strip preview references from the persistent cache.

Frontend:
* Refresh ▾ gains a "Scan one folder" section listing the page's roots with
  their cached counts; offline roots stay clickable and explain themselves; rows
  are wired by delegation (new static/js/components/controls/ScanScopeMenu.js).
* A scoped scan reports "Scanned <root>: N new, M removed"; a scan that kept
  entries reports "<N> models kept: <paths> not reachable".
* registerAPI() now injects the two cross-page passthroughs (fetchModelRoots and
  an argument-forwarding refreshModels) so a page facade cannot drop them: the
  first version rendered an empty menu and would have run a full refresh.
* createToastElement whitelists toast types, so a wrong `type` argument degrades
  to the info style instead of rendering an unstyled box.

Verified in a sandbox instance with three roots: a scoped scan walks only the
requested root (progress roots=0/1, 240 files); a full refresh with one root
offline reports kept_unreachable=60 and leaves all 420 models cached; /roots
reports the offline root with its cached count. 3699 passed, 7 skipped;
frontend 1488 passed (148 files); vue widgets 96 passed.
2026-10-07 15:01:26 +08:00
Will Miao 37f2cba72d fix(ui): wrap toolbar controls by available space, not viewport width
The action bar forced .controls-right (Doctor) onto its own full-width row
below 1500px. On high-DPI displays a maximized window reports a CSS viewport
of ~1280-1440px, so the Doctor button wrapped even with ~500px of free space
next to the action buttons.

- .actions / .action-buttons now wrap only on real overflow (flex-wrap plus
  min-width: 0) instead of a viewport breakpoint.
- .controls-right relies on its auto margin to stay right-aligned on either
  row, so the width: 100% + margin-top: 8px override is gone.
- Lower the button min-width floor from 100px to 90px; the old floor alone
  made the row overflow the 1400px container at wide viewports.
- The <=1500px breakpoint now only tightens the buttons (min-width: 0,
  padding, gap) and no longer forces a wrap; drop the no-op 0.8em font-size
  override (base is already 0.85em).
- Keep the stacked mobile layout below 768px.

Verified in headless Chrome against the real stylesheet: one row with the
Doctor button inline down to 1200px (down to 1000px for shorter locales),
right-aligned wrap only when the content genuinely does not fit, and no
horizontal overflow at any width.
2026-09-13 08:42:43 +08:00
Will Miao 121d8d5cea fix(ui): lighten toolbar shortcut keycaps and fix contrast on active buttons 2026-09-05 00:21:11 +08:00
Will Miao ec147bd677 feat(ui): add setting to keep the action bar visible while scrolling (#1095)
Adds a 'Keep Action Bar Visible' toggle (default off) under
Settings > Interface > Layout Settings. When enabled, the controls bar
(Refresh, Download, etc.) and the breadcrumb nav are wrapped in a shared
sticky container (.sticky-topbar) so both stay pinned as one unit; when
disabled, the wrapper is display: contents and the original behavior
(only the breadcrumb stays visible) is preserved.
2026-09-04 23:53:27 +08:00
Will Miao 726fc178f1 feat(ui): add R/F/D action shortcuts and unify keycap hint style
- Bind R=refresh, F=fetch metadata, D=download in PageControls via
  eventManager (plain letters only, skipped while typing or when a
  modal is open); triggers reuse the buttons' existing click handlers
- Show key-hint chips on the refresh/fetch/download/bulk toolbar
  buttons; convert the bulk chip to a semantic <kbd>
- Redesign shortcut hints as a neutral theme-adaptive keycap:
  --shortcut-* variables in base.css now derive from --text-muted
  with a bottom-edge shadow, shared by the toolbar chips, the header
  search cue, the help-modal cheat sheet, and onboarding key hints
- Add shared isTypingContext() helper to uiHelpers
- Add an Actions group (R/F/D) to the Shortcuts cheat-sheet tab

Verified with vitest (926 passing, incl. 6 new shortcut cases) and a
sandboxed E2E run in real Chrome (light/dark rendering, hover state,
'?' opening the Shortcuts tab, clean console)
2026-09-03 19:10:16 +08:00
Will Miao 658f88ca48 feat(recipes): add toolbar toggle and settings preview for masonry layout 2026-08-16 15:23:30 +08:00
Will Miao d2d109a69c feat(ui): replace native sort select with custom dropdown sized to selected text 2026-06-26 09:53:04 +08:00
Will Miao 7a71b34b54 feat(vlm): sort versions by newest first in VLM view, with disabled sort dropdown
When viewing all versions of a model (VLM mode via 'x versions' button):
- Backend always sorts by version ID descending, ignoring current sort_by
- A temporary 'Newest version first' option is injected into the sort
  dropdown (removed on exit, not a permanent option)
- The sort dropdown is disabled (greyed out) while VLM is active
- On clearing VLM, the previous sort preference is restored and the
  dropdown re-enabled
- Handles stale VLM state (e.g. after page reload with leftover session)
- Covers all three model page types: loras, checkpoints, embeddings

Also fixes review nits:
- Correct i18n call pattern (defaultValue in options object)
- Shared _restoreSortAfterVlm() helper to avoid triple duplication
2026-06-24 16:25:14 +08:00
Will Miao 18577fa336 refactor(phase-4): standardize remaining transitions and box-shadows
- Replace all remaining 'transition: all' with specific token-based transitions
- Replace 80+ hardcoded box-shadow rgba values with semantic tokens
- Add new tokens: --shadow-side, --shadow-elevated, --shadow-dialog, --shadow-inset-top
- Update dark theme overrides for new shadow tokens
- 32 files changed, net +8 lines (more consistent, less duplication)
2026-06-09 14:27:53 +08:00
Will Miao 5797ce9408 feat(phase-4): visual polish — font stack, shadow system, transitions, micro-interactions
Phase 4: Visual Polish

4.1 Font Stack Upgrade:
- Add --font-display token for headings
- Replace all hardcoded font-family: monospace with var(--font-mono)
- Replace hardcoded 'Segoe UI' stack with var(--font-body)

4.2 Shadow Elevation System:
- Add --shadow-2xl, --shadow-card/dropdown/modal/toast/header/dark-lg tokens
- Replace hardcoded shadows in header, menu, banner, shared, recipe-modal,
  progress-panel, import-modal, alphabet-bar with semantic tokens
- Add dark theme shadow overrides with increased opacity

4.3 Transitions & Micro-interactions:
- Replace transition: all with specified properties (performance)
- Use --transition-fast/base/slow tokens instead of hardcoded 0.2s/0.3s
- Add :active scale feedback to modal buttons
- Enhance card hover with box-shadow + border-color lift

4.4 Dark Theme Refinement:
- Elevated shadow opacity for dark theme visibility

4.5 Density:
- Standardize container padding with --space-2 token

21 files changed
2026-06-09 14:07:36 +08:00
Will Miao eb22054580 fix: add --surface-subtle token, restore info grouping, and apply theme-aware favorite color
- Add --surface-subtle (oklch 3% opacity) to replace rgba(0,0,0,0.03)
- Fix info items, creator-info, civitai-view, modal-send-btn, header-actions
  to use --surface-subtle instead of --surface-hover
- Keep true hover states on --surface-hover
- Use light #d4a017 / dark #ffc107 for --favorite-color based on theme
- Replace hardcoded #ffc107 and #d4a017 with var(--favorite-color)
2026-06-09 09:27:11 +08:00
Will Miao 08afb05ece refactor: normalize components in Phase 2
- Unify button styles (padding, gap, border-radius, hover states) in _base.css
- Fix .secondary-btn syntax error (extra space in var())
- Remove duplicated .card-actions in card.css
- Replace hardcoded #f0f0f0 with --surface-hover token
- Replace #ffc107 with accessible #d4a017 for favorite stars
- Replace hardcoded rgba shadows with semantic --shadow-* tokens in layout.css
- Replace hardcoded rgba(0,0,0,0.03)/rgba(255,255,255,0.03) with --surface-hover
- Remove redundant [data-theme=dark] overrides by using theme-aware tokens
- Replace .dropdown-main hardcoded border with --border-color token
2026-06-09 09:26:28 +08:00
Will Miao e23d803ecf fix(layout): ensure refresh split-button dropdown renders above breadcrumb nav 2026-05-03 18:14:54 +08:00
Will Miao 502b7eab31 fix(layout): correct breadcrumb sticky behavior and controls wrapping overflow
- Extract breadcrumb from controls template into sibling component
- Fix breadcrumb sticky positioning (top: 0, z-index: calc(--z-header - 1))
- Add 1500px breakpoint to wrap controls-right and prevent overflow
- Adjust breadcrumb padding-bottom to cover controls-right area when sticky
2026-05-01 22:53:40 +08:00
Will Miao 4ef750b206 feat: improve dropdown menu responsiveness
Update dropdown menu CSS to use max-content and max() function for better responsive behavior. Replace fixed min-width with dynamic width calculation to ensure proper content fitting across different screen sizes while maintaining dropdown functionality.
2025-10-29 16:06:08 +08:00
Will Miao e10717dcda feat(ui): improve update controls styling and error handling
- Add disabled and loading states for control group buttons with appropriate cursor and opacity styling
- Enhance dropdown toggle active state styling for update filter group
- Improve dropdown toggle layout with flex centering
- Add disabled state styling for dropdown items
- Refactor model update check to use shared helper function, removing redundant success handling and simplifying error flow
- Maintain existing functionality while improving user experience and code maintainability
2025-10-29 14:38:11 +08:00
Will Miao b10bcf7e78 feat: add update availability filter to model list
Add a new filter option to show only models with available updates across all supported languages. This includes:

- Adding "updates" filter translations in all locale files (de, en, es, fr, he, ja, ko)
- Extending BaseModelApiClient to handle update_available_only query parameter
- Implementing update filter button in PageControls component with event listeners
- Adding corresponding CSS styles for active filter state

The feature allows users to quickly identify and focus on models that have updates available, improving the update management workflow.
2025-10-29 07:32:53 +08:00
Will Miao f6bd48cfcd feat: Update box-shadow for header and adjust controls styling for improved layout 2025-08-27 15:43:44 +08:00
Will Miao 01843b8f2b feat: Update media query breakpoints from 2000px to 2150px for improved responsiveness across components 2025-08-27 09:54:08 +08:00
Will Miao a98e26139f feat: Implement auto-hide functionality for sidebar and update controls layout 2025-08-26 17:57:59 +08:00
Will Miao d7949fbc30 feat: Enhance sidebar navigation with dropdowns and refactor breadcrumb structure 2025-08-26 16:44:01 +08:00
Will Miao 4dc80e7f6e feat: Implement sidebar navigation with folder tree and controls 2025-08-26 10:33:46 +08:00
Will Miao e8ccdabe6c refactor: Enhance sorting functionality and UI for model selection, including legacy format conversion 2025-07-24 09:26:15 +08:00
Will Miao eccfa0ca54 feat: Add keyboard shortcuts for bulk operations and enhance shortcut key styling 2025-07-22 19:14:36 +08:00
Will Miao 63dc5c2bdb fix: change overflow-y property to scroll for consistent vertical scrolling behavior 2025-06-27 11:44:43 +08:00
Will Miao ceacac75e0 Increase minimum width of dropdown menu for improved usability 2025-05-29 15:55:14 +08:00
Will Miao bae66f94e8 Add full rebuild option to model refresh functionality and enhance dropdown controls 2025-05-29 15:51:45 +08:00
Will Miao 488654abc8 Improve card layout responsiveness and scrolling behavior 2025-05-18 07:49:39 +08:00
Will Miao 2ba7a0ceba Add keyboard navigation support and related styles for enhanced user experience 2025-05-15 20:17:57 +08:00
Will Miao 925ad7b3e0 Add user-select: none to prevent text selection on cards and control elements 2025-05-15 05:36:56 +08:00
Will Miao 8546cfe714 checkpoint 2025-05-12 10:25:58 +08:00
Will Miao 61f723a1f5 feat: add back-to-top button and update its positioning 2025-04-30 14:46:43 +08:00
Will Miao 51a6374c33 feat: add favorites filtering functionality across models and UI components 2025-04-25 17:55:33 +08:00
Will Miao 43e3d0552e style: Update filter indicator and button styles for improved UI consistency
feat: Add pulse animation to filter indicators in Lora and recipe management
refactor: Change filter-active button to a div for better semantic structure
2025-04-08 13:45:15 +08:00
Will Miao dd81c86540 Enhance folder tag functionality and layout; update styles for action buttons and toggle behavior 2025-03-13 21:23:24 +08:00
Will Miao 0b0caa1142 Fix layout 2025-03-13 20:37:23 +08:00
Will Miao e7233c147d checkpoint 2025-03-13 15:04:18 +08:00
Will Miao 14aef237a9 Add interactive thumbnail strip for bulk LoRA selection 2025-03-07 15:36:07 +08:00
Will Miao 0c4914909a Add bulk operation 2025-03-07 13:15:39 +08:00
Will Miao 2e47b30ed5 Refactor layout.css 2025-03-07 09:23:11 +08:00
Will Miao 5e6cce936d Add update notifications 2025-03-05 22:03:54 +08:00
Will Miao 493dff5c19 Add support modal and toggle button for user feedback and support 2025-03-05 20:47:17 +08:00
Will Miao f614dbf700 Add filters - base model only for now 2025-03-05 19:53:52 +08:00
Will Miao c17f2c885a Add filters - checkpoint 2025-03-05 19:07:11 +08:00
Will Miao 6f48762110 Fix issue with incomplete display caused by too many folders 2025-02-28 21:37:00 +08:00
Will Miao 832abd743c Refactor css checkpoint2 2025-02-17 21:27:55 +08:00
Will Miao 2fc7235537 Refactor css checkpoint 2025-02-17 19:21:40 +08:00