Settings: Add sticky save bar for controlled instance configuration #42

Closed
opened 2026-06-27 15:41:16 +02:00 by bullitt · 1 comment
Owner

Problem

The "Save Settings" button is placed at the bottom of the page, below all scraper cards, the MQTT card, and above only the Activity log. With 4+ carrier scraper cards, the button is far below the fold. Users changing only MQTT settings (near the bottom of scrapers but above save) still have to scroll to find save.

Implementation

File: frontend/src/pages/Settings.tsx

Replace the current save button div:

<div className="flex items-center gap-3">
  <Button onClick={handleSave} disabled={saving}>
    {saving ? "Saving..." : "Save Settings"}
  </Button>
  {saved && <span className="text-sm text-emerald-600">Settings saved!</span>}
</div>

With a sticky bottom bar visible only when there are unsaved changes, OR always visible as a fixed bar:

{/* Sticky save bar */}
<div className="sticky bottom-0 -mx-4 md:-mx-6 px-4 md:px-6 py-3 bg-background/95 backdrop-blur border-t border-border flex items-center justify-between z-10">
  <span className="text-xs text-muted-foreground">
    {scraperStatus?.last_cycle_at && `Last cycle: ${new Date(scraperStatus.last_cycle_at).toLocaleTimeString()}`}
  </span>
  <div className="flex items-center gap-3">
    {saved && <span className="text-sm text-emerald-600">Saved</span>}
    <Button onClick={handleSave} disabled={saving}>
      {saving ? "Saving…" : "Save Settings"}
    </Button>
  </div>
</div>

The -mx / px trick extends the bar edge-to-edge within the max-width container. bg-background/95 backdrop-blur gives it the translucent panel feel common in shadcn apps.

Remove the now-redundant standalone save button div and the scraperStatus?.last_cycle_at paragraph below it (move that info into the sticky bar).

Acceptance criteria

  • Save button is always visible without scrolling (sticky bottom)
  • Bar spans full page width within the content column
  • "Last cycle" info is shown in the bar
  • "Saved ✓" confirmation appears in the bar

Brand identity alignment

Saving settings is an instance-control action. It should remain reachable and clearly tied to configuration state without becoming visually loud.

Brand-compliant implementation notes

  • Use a sticky neutral bar with subtle border and backdrop; avoid heavy shadow or bright fill.
  • Include system context such as Last sync cycle or Unsaved changes when available.
  • Save remains the primary action in this bar; secondary state text stays muted.
  • Ensure the sticky bar does not cover content on mobile or conflict with mobile navigation.

Additional acceptance criteria

  • The save action is always reachable during settings changes.
  • The bar communicates control state calmly and precisely.
  • The interaction preserves accessible focus order and does not rely on animation.

Migrated from GitHub issue #21: https://github.com/bullitt186/trackbox/issues/21
Original author: @bullitt186
Original created: 2026-06-27T13:25:29Z
Original labels: ux

## Problem The "Save Settings" button is placed at the bottom of the page, below all scraper cards, the MQTT card, and above only the Activity log. With 4+ carrier scraper cards, the button is far below the fold. Users changing only MQTT settings (near the bottom of scrapers but above save) still have to scroll to find save. ## Implementation File: `frontend/src/pages/Settings.tsx` Replace the current save button div: ```tsx <div className="flex items-center gap-3"> <Button onClick={handleSave} disabled={saving}> {saving ? "Saving..." : "Save Settings"} </Button> {saved && <span className="text-sm text-emerald-600">Settings saved!</span>} </div> ``` With a sticky bottom bar visible only when there are unsaved changes, OR always visible as a fixed bar: ```tsx {/* Sticky save bar */} <div className="sticky bottom-0 -mx-4 md:-mx-6 px-4 md:px-6 py-3 bg-background/95 backdrop-blur border-t border-border flex items-center justify-between z-10"> <span className="text-xs text-muted-foreground"> {scraperStatus?.last_cycle_at && `Last cycle: ${new Date(scraperStatus.last_cycle_at).toLocaleTimeString()}`} </span> <div className="flex items-center gap-3"> {saved && <span className="text-sm text-emerald-600">Saved</span>} <Button onClick={handleSave} disabled={saving}> {saving ? "Saving…" : "Save Settings"} </Button> </div> </div> ``` The `-mx` / `px` trick extends the bar edge-to-edge within the max-width container. `bg-background/95 backdrop-blur` gives it the translucent panel feel common in shadcn apps. Remove the now-redundant standalone save button div and the `scraperStatus?.last_cycle_at` paragraph below it (move that info into the sticky bar). ## Acceptance criteria - Save button is always visible without scrolling (sticky bottom) - Bar spans full page width within the content column - "Last cycle" info is shown in the bar - "Saved ✓" confirmation appears in the bar ## Brand identity alignment Saving settings is an instance-control action. It should remain reachable and clearly tied to configuration state without becoming visually loud. ## Brand-compliant implementation notes - Use a sticky neutral bar with subtle border and backdrop; avoid heavy shadow or bright fill. - Include system context such as `Last sync cycle` or `Unsaved changes` when available. - Save remains the primary action in this bar; secondary state text stays muted. - Ensure the sticky bar does not cover content on mobile or conflict with mobile navigation. ## Additional acceptance criteria - The save action is always reachable during settings changes. - The bar communicates control state calmly and precisely. - The interaction preserves accessible focus order and does not rely on animation. --- Migrated from GitHub issue #21: https://github.com/bullitt186/trackbox/issues/21 Original author: @bullitt186 Original created: 2026-06-27T13:25:29Z Original labels: ux
bullitt changed title from Settings: Add sticky save bar so 'Save Settings' is always reachable to Settings: Add sticky save bar for controlled instance configuration 2026-06-27 15:46:22 +02:00
Author
Owner

Implemented in commit bd6b0e7. Moved the Save button, saved confirmation, and last cycle timestamp into a sticky bottom bar (sticky bottom-0 with bg-background/95 backdrop-blur and a top border). The bar spans the full content width. Last cycle info is on the left; Save button is on the right. The main content area has pb-24 to avoid overlap. The save action is always accessible without scrolling.

Implemented in commit bd6b0e7. Moved the Save button, saved confirmation, and last cycle timestamp into a sticky bottom bar (`sticky bottom-0` with `bg-background/95 backdrop-blur` and a top border). The bar spans the full content width. Last cycle info is on the left; Save button is on the right. The main content area has `pb-24` to avoid overlap. The save action is always accessible without scrolling.
Sign in to join this conversation.
No labels
arch
harness
security
ux
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bullitt/trackbox#42
No description provided.