diff --git a/locales/de.json b/locales/de.json index db847811..7ed6fb3f 100644 --- a/locales/de.json +++ b/locales/de.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "Nach Modell gruppieren", "groupByModelHelp": "Wenn aktiviert, wird nur die neueste Version jedes CivitAI-Modells als einzelne Karte angezeigt. Ältere Versionen werden ausgeblendet.", + "stickyControls": "Aktionsleiste sichtbar halten", + "stickyControlsHelp": "Wenn aktiviert, bleibt die Aktionsleiste (Aktualisieren, Herunterladen usw.) beim Scrollen zusammen mit der Breadcrumb-Navigation oben angeheftet.", "displayDensity": "Anzeige-Dichte", "displayDensityOptions": { "default": "Standard", diff --git a/locales/en.json b/locales/en.json index cd684e19..c0a7f850 100644 --- a/locales/en.json +++ b/locales/en.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "Group by Model", "groupByModelHelp": "When enabled, only the latest version of each CivitAI model is shown as a single card. Older versions are hidden.", + "stickyControls": "Keep Action Bar Visible", + "stickyControlsHelp": "When enabled, the action bar (Refresh, Download, etc.) stays pinned at the top while scrolling, together with the breadcrumb navigation.", "displayDensity": "Display Density", "displayDensityOptions": { "default": "Default", diff --git a/locales/es.json b/locales/es.json index 3050e768..6ab4159f 100644 --- a/locales/es.json +++ b/locales/es.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "Agrupar por modelo", "groupByModelHelp": "Cuando está activado, solo se muestra la versión más reciente de cada modelo de CivitAI como una tarjeta única. Las versiones anteriores están ocultas.", + "stickyControls": "Mantener visible la barra de acciones", + "stickyControlsHelp": "Cuando está activado, la barra de acciones (Actualizar, Descargar, etc.) permanece fijada en la parte superior al desplazarse, junto con la navegación por rutas.", "displayDensity": "Densidad de visualización", "displayDensityOptions": { "default": "Predeterminado", diff --git a/locales/fr.json b/locales/fr.json index cfa6c535..57dbe4bd 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "Grouper par modèle", "groupByModelHelp": "Lorsque activé, seule la version la plus récente de chaque modèle CivitAI s'affiche sous forme de carte unique. Les versions plus anciennes sont masquées.", + "stickyControls": "Garder la barre d'actions visible", + "stickyControlsHelp": "Lorsque activé, la barre d'actions (Actualiser, Télécharger, etc.) reste épinglée en haut lors du défilement, avec la navigation par fil d'Ariane.", "displayDensity": "Densité d'affichage", "displayDensityOptions": { "default": "Par défaut", diff --git a/locales/he.json b/locales/he.json index 093a47ab..8d4c96af 100644 --- a/locales/he.json +++ b/locales/he.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "קיבוץ לפי מודל", "groupByModelHelp": "כאשר מופעל, רק הגרסה העדכנית ביותר של כל מודל CivitAI מוצגת ככרטיס בודד. גרסאות ישנות יותר מוסתרות.", + "stickyControls": "השארת סרגל הפעולות גלוי", + "stickyControlsHelp": "כאשר מופעל, סרגל הפעולות (רענון, הורדה וכו') נשאר מוצמד לחלק העליון בעת גלילה, יחד עם ניווט פירורי הלחם.", "displayDensity": "צפיפות תצוגה", "displayDensityOptions": { "default": "ברירת מחדל", diff --git a/locales/ja.json b/locales/ja.json index e8370aa8..4493c43e 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "モデルでグループ化", "groupByModelHelp": "有効にすると、各CivitAIモデルの最新バージョンのみが1枚のカードとして表示され、古いバージョンは非表示になります。", + "stickyControls": "アクションバーを常に表示", + "stickyControlsHelp": "有効にすると、アクションバー(更新、ダウンロードなど)がスクロール時にパンくずナビゲーションと一緒に画面上部に固定されます。", "displayDensity": "表示密度", "displayDensityOptions": { "default": "デフォルト", diff --git a/locales/ko.json b/locales/ko.json index 4d827d77..2c90b946 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "모델별 그룹화", "groupByModelHelp": "활성화하면 각 CivitAI 모델의 최신 버전만 단일 카드로 표시되며, 이전 버전은 숨겨집니다.", + "stickyControls": "작업 표시줄 항상 표시", + "stickyControlsHelp": "활성화하면 작업 표시줄(새로고침, 다운로드 등)이 스크롤 시 브레드크럼 내비게이션과 함께 상단에 고정됩니다.", "displayDensity": "표시 밀도", "displayDensityOptions": { "default": "기본", diff --git a/locales/ru.json b/locales/ru.json index 7a18a688..7a5acb2c 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "Группировать по модели", "groupByModelHelp": "При включении отображается только последняя версия каждой модели CivitAI в виде одной карточки. Старые версии скрыты.", + "stickyControls": "Держать панель действий видимой", + "stickyControlsHelp": "При включении панель действий (Обновить, Загрузить и т. д.) остаётся закреплённой вверху при прокрутке вместе с навигацией по папкам.", "displayDensity": "Плотность отображения", "displayDensityOptions": { "default": "По умолчанию", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 877a0839..5a635214 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "按模型分组", "groupByModelHelp": "开启后,每个 CivitAI 模型仅显示最新版本的单张卡片,旧版本将被隐藏。", + "stickyControls": "保持操作栏可见", + "stickyControlsHelp": "开启后,操作栏(刷新、下载等)会在滚动时与路径导航一起固定在页面顶部。", "displayDensity": "显示密度", "displayDensityOptions": { "default": "默认", diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 366f8d73..e3e88d16 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -484,6 +484,8 @@ "layoutSettings": { "groupByModel": "按模型分組", "groupByModelHelp": "啟用後,每個 CivitAI 模型僅顯示最新版本的單張卡片,舊版本將被隱藏。", + "stickyControls": "保持操作列可見", + "stickyControlsHelp": "啟用後,操作列(重新整理、下載等)會在捲動時與麵包屑導覽一起固定在頁面頂端。", "displayDensity": "顯示密度", "displayDensityOptions": { "default": "預設", diff --git a/py/services/settings_manager.py b/py/services/settings_manager.py index 8d46539c..08d71ac0 100644 --- a/py/services/settings_manager.py +++ b/py/services/settings_manager.py @@ -116,6 +116,7 @@ DEFAULT_SETTINGS: Dict[str, Any] = { "backup_retention_count": 5, "use_new_license_icons": True, "group_by_model": False, + "sticky_controls": False, # AI / LLM provider configuration (BYOK) "llm_provider": "openai", # "openai" | "ollama" | "custom" "llm_api_key": "", diff --git a/static/css/layout.css b/static/css/layout.css index dec8e473..dae1d564 100644 --- a/static/css/layout.css +++ b/static/css/layout.css @@ -25,6 +25,23 @@ box-shadow: var(--shadow-xs); } +/* Wrapper around the controls bar and breadcrumb nav. With the sticky-controls + setting off it is transparent to layout (display: contents), preserving the + original behavior (only the breadcrumb stays visible). When enabled, the whole + wrapper sticks as one unit so the two bars can never drift apart. */ +.sticky-topbar { + display: contents; +} + +body.sticky-controls .sticky-topbar { + display: block; + position: sticky; + top: 0; + z-index: calc(var(--z-header) - 1); + background: var(--bg-color); + box-shadow: var(--shadow-xs); +} + /* Responsive container for larger screens */ @media (min-width: 2150px) { .container { diff --git a/static/js/managers/SettingsManager.js b/static/js/managers/SettingsManager.js index 5a196bed..fa2239bb 100644 --- a/static/js/managers/SettingsManager.js +++ b/static/js/managers/SettingsManager.js @@ -1047,6 +1047,12 @@ export class SettingsManager { groupByModelCheckbox.checked = !!state.global.settings.group_by_model; } + // Set sticky controls + const stickyControlsCheckbox = document.getElementById('stickyControls'); + if (stickyControlsCheckbox) { + stickyControlsCheckbox.checked = !!state.global.settings.sticky_controls; + } + // Set model name display setting const modelNameDisplaySelect = document.getElementById('modelNameDisplay'); if (modelNameDisplaySelect) { @@ -3396,6 +3402,10 @@ export class SettingsManager { const groupByModel = !!state.global.settings.group_by_model; document.body.classList.toggle('group-by-model', groupByModel); + // Apply sticky controls mode (keeps the action bar visible while scrolling) + const stickyControls = !!state.global.settings.sticky_controls; + document.body.classList.toggle('sticky-controls', stickyControls); + } } diff --git a/static/js/state/index.js b/static/js/state/index.js index dc7815e1..af73d4c9 100644 --- a/static/js/state/index.js +++ b/static/js/state/index.js @@ -59,6 +59,7 @@ const DEFAULT_SETTINGS_BASE = Object.freeze({ strip_lora_on_copy: false, use_new_license_icons: true, group_by_model: false, + sticky_controls: false, llm_provider: 'openai', llm_api_key: '', llm_api_base: '', diff --git a/templates/checkpoints.html b/templates/checkpoints.html index db87e1ed..9f1d265f 100644 --- a/templates/checkpoints.html +++ b/templates/checkpoints.html @@ -54,8 +54,10 @@ {% endblock %} {% block content %} +
{% include 'components/controls.html' %} {% include 'components/breadcrumb.html' %} +
{% include 'components/duplicates_banner.html' %} {% include 'components/folder_sidebar.html' %} diff --git a/templates/components/modals/settings/interface.html b/templates/components/modals/settings/interface.html index a8477576..56f7c042 100644 --- a/templates/components/modals/settings/interface.html +++ b/templates/components/modals/settings/interface.html @@ -79,6 +79,9 @@ {{ sm.setting_toggle('groupByModel', 'group_by_model', 'settings.layoutSettings.groupByModel', 'settings.layoutSettings.groupByModelHelp') }} + + {{ sm.setting_toggle('stickyControls', 'sticky_controls', 'settings.layoutSettings.stickyControls', 'settings.layoutSettings.stickyControlsHelp') }} + {{ sm.setting_select('cardInfoDisplay', 'card_info_display', 'settings.layoutSettings.cardInfoDisplay', [ ('always', 'settings.layoutSettings.cardInfoDisplayOptions.always'), ('hover', 'settings.layoutSettings.cardInfoDisplayOptions.hover'), diff --git a/templates/embeddings.html b/templates/embeddings.html index 3416b2e8..9c8de0e3 100644 --- a/templates/embeddings.html +++ b/templates/embeddings.html @@ -53,8 +53,10 @@ {% endblock %} {% block content %} +
{% include 'components/controls.html' %} {% include 'components/breadcrumb.html' %} +
{% include 'components/duplicates_banner.html' %} {% include 'components/folder_sidebar.html' %} diff --git a/templates/loras.html b/templates/loras.html index e9d58564..7c2daa83 100644 --- a/templates/loras.html +++ b/templates/loras.html @@ -8,8 +8,10 @@ {% block init_check_url %}/api/loras/list?page=1&page_size=1{% endblock %} {% block content %} +
{% include 'components/controls.html' %} {% include 'components/breadcrumb.html' %} +
{% include 'components/duplicates_banner.html' %} {% include 'components/folder_sidebar.html' %} diff --git a/templates/recipes.html b/templates/recipes.html index a847f2bb..b8c4dd6a 100644 --- a/templates/recipes.html +++ b/templates/recipes.html @@ -64,10 +64,12 @@ {% block init_check_url %}/api/recipes?page=1&page_size=1{% endblock %} {% block content %} - + +
{% include 'components/controls.html' %} {% include 'components/breadcrumb.html' %} +