From e6f159bbea50cee20bbfc6bc7a54a9e101b7d02b Mon Sep 17 00:00:00 2001 From: Matt Beaudoin Date: Fri, 15 May 2026 20:00:29 -0700 Subject: [PATCH] first big style pass, consolidate to mixins --- src/assets/scss/_mixins.scss | 69 ++++++++++++++++++++++++++++ src/routes/Apps/App.scss | 20 +------- src/routes/Apps/Apps.scss | 55 +++------------------- src/routes/Apps/Apps.tsx | 23 +++++----- src/routes/Dashboard/_Dashboard.scss | 1 - src/routes/Recipes/Recipes.scss | 19 ++------ src/routes/Servers/Server.scss | 20 +------- src/routes/Servers/Servers.scss | 21 ++------- src/routes/Servers/Servers.tsx | 24 +--------- 9 files changed, 98 insertions(+), 154 deletions(-) diff --git a/src/assets/scss/_mixins.scss b/src/assets/scss/_mixins.scss index bbbe9ce..e5189ee 100644 --- a/src/assets/scss/_mixins.scss +++ b/src/assets/scss/_mixins.scss @@ -28,6 +28,16 @@ padding: $spacing-xl; } +// Ensure cards occupy consistent vertical space and can stretch horizontally +@mixin card-dimensions($min-width: 320px, $min-height: 180px) { + min-width: $min-width; + min-height: $min-height; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; +} + /// Standard vertical stack for card-style list rows (dashboard recent apps, server detail apps, etc.) @mixin card-list-vertical($gap: $spacing-md) { display: flex; @@ -141,4 +151,63 @@ font-weight: $font-weight-semibold; background-color: rgba($color, 0.1); // color: darken($color, 20%); +} + +// Compact chip used for stat chips and small interactive chips +@mixin chip( + $bg: white, + $border-color: $border-color, + $radius: $radius-md, + $padding: $spacing-md $spacing-lg, + $gap: $spacing-md, + $hover-translate: -2px, + $hover-shadow: $shadow-sm, + $font-size: $font-size-base +) { + display: flex; + align-items: center; + gap: $gap; + padding: $padding; + background: $bg; + border: 2px solid $border-color; + border-radius: $radius; + cursor: pointer; + transition: all $transition-base; + font-size: $font-size; + + &:hover:not(:disabled) { + border-color: $primary; + transform: translateY($hover-translate); + box-shadow: $hover-shadow; + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } +} + +// Reusable action button styles; accepts border width and radius +@mixin action-btn($border-width: 1px, $radius: $radius-sm, $padding: $spacing-xs $spacing-md, $font-size: $font-size-sm) { + background: none; + border: $border-width solid $border-color; + padding: $padding; + border-radius: $radius; + cursor: pointer; + font-size: $font-size; + color: $text-primary; + font-weight: $font-weight-medium; + transition: all $transition-base; + + &:hover { + background-color: rgba($primary, 0.05); + color: $text-primary; + transform: translateY(-1px); + border-color: $primary; + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } } \ No newline at end of file diff --git a/src/routes/Apps/App.scss b/src/routes/Apps/App.scss index c0b528b..aa45b8f 100644 --- a/src/routes/Apps/App.scss +++ b/src/routes/Apps/App.scss @@ -47,25 +47,7 @@ // Action buttons .action-btn { - padding: $spacing-sm $spacing-lg; - border: 2px solid $border-color; - border-radius: $radius-md; - font-size: $font-size-sm; - font-weight: $font-weight-medium; - cursor: pointer; - transition: all $transition-base; - background: white; - color: $text-primary; - - &:disabled { - opacity: 0.6; - cursor: not-allowed; - } - - &:hover:not(:disabled) { - transform: translateY(-1px); - box-shadow: $shadow-md; - } + @include action-btn(2px, $radius-md, $spacing-sm $spacing-lg, $font-size-sm); &.primary { background: $primary; diff --git a/src/routes/Apps/Apps.scss b/src/routes/Apps/Apps.scss index b3b966d..78bb452 100644 --- a/src/routes/Apps/Apps.scss +++ b/src/routes/Apps/Apps.scss @@ -21,31 +21,12 @@ } .stat-chip { - display: flex; - align-items: center; - gap: $spacing-sm; - padding: $spacing-sm $spacing-md; - background: white; - border: 2px solid $border-color; - border-radius: $radius-md; - cursor: pointer; - transition: all $transition-base; - font-size: $font-size-base; - - &:hover:not(:disabled) { - border-color: $primary; - transform: translateY(-2px); - box-shadow: $shadow-sm; - } - - &:disabled { - opacity: 0.5; - cursor: not-allowed; - } + @include chip(); &.active { - border-color: $primary; - background: rgba($primary, 0.05); + border-color: $primary-dark; + background: $bg-primary; + box-shadow: 0 0 0 3px rgba($primary-dark, 0.08); } .stat-label { @@ -63,23 +44,7 @@ } } -.reset-filters-btn { - padding: $spacing-sm $spacing-md; - background: $bg-secondary; - border: 2px solid $border-color; - border-radius: $radius-md; - cursor: pointer; - transition: all $transition-base; - font-size: $font-size-sm; - font-weight: $font-weight-medium; - color: $text-secondary; - - &:hover { - background: white; - color: $text-primary; - border-color: $primary; - } -} +/* reset-filters-btn removed — outline on stat-chip indicates active filters */ // Apps table specific styles .apps-table-container { @@ -181,15 +146,7 @@ gap: $spacing-sm; .action-btn { - background: none; - border: 1px solid $border-color; - padding: $spacing-xs $spacing-md; - border-radius: $radius-sm; - cursor: pointer; - font-size: $font-size-sm; - color: $text-primary; - font-weight: $font-weight-medium; - transition: all $transition-base; + @include action-btn(1px, $radius-sm, $spacing-xs $spacing-md, $font-size-sm); &:hover { background-color: $primary; diff --git a/src/routes/Apps/Apps.tsx b/src/routes/Apps/Apps.tsx index 9ca5703..b49d4c5 100644 --- a/src/routes/Apps/Apps.tsx +++ b/src/routes/Apps/Apps.tsx @@ -94,19 +94,19 @@ export const Apps: React.FC = () => { setShowUpgradesOnly(false); }; - const toggleUpgrades = () => setShowUpgradesOnly(prev => !prev); - const toggleChaos = () => setShowChaosOnly(prev => !prev); - - // Show only apps that need upgrades - const filterByUpgrades = () => { - setShowUpgradesOnly(true); - setFilterStatus('all'); + const toggleUpgrades = () => { + setShowUpgradesOnly(!showUpgradesOnly); + if (!showUpgradesOnly) { + setFilterStatus('all'); + setShowChaosOnly(false); + } }; - // Show only chaos apps - const filterByChaos = () => { - setFilterStatus('chaos'); - setShowUpgradesOnly(false); + const toggleChaos = () => { + const newChaosState = !showChaosOnly; + setShowChaosOnly(newChaosState); + setFilterStatus(newChaosState ? 'chaos' : 'all'); + if (newChaosState) setShowUpgradesOnly(false); }; if (loading) { @@ -150,7 +150,6 @@ export const Apps: React.FC = () => { Apps {stats.total} - - - {(searchTerm || sortBy !== 'name' || showUpgradesOnly) && ( - - )} + {/* Clear filters button removed — use stat-chip outlines for active filters */} {/* Filters */}