diff --git a/src/styles/abstracts/_animations.scss b/src/styles/abstracts/_animations.scss new file mode 100644 index 0000000..825ce0f --- /dev/null +++ b/src/styles/abstracts/_animations.scss @@ -0,0 +1,12 @@ +/* + Animations +*/ + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/src/styles/abstracts/_fonts.scss b/src/styles/abstracts/_fonts.scss index ddae046..9159530 100644 --- a/src/styles/abstracts/_fonts.scss +++ b/src/styles/abstracts/_fonts.scss @@ -3,11 +3,8 @@ */ @font-face { - font-family: 'Satoshi'; - src: - url('../assets/fonts/Satoshi.ttf') format('ttf'), - url('../assets/fonts/Roboto.ttf') format('ttf'), - url('../assets/fonts/WorkSans.ttf') format('ttf'); + font-family: 'Roboto'; + src: url('../assets/fonts/Roboto.ttf') format('truetype'); font-weight: 400; font-style: normal; font-display: swap; diff --git a/src/styles/abstracts/_index.scss b/src/styles/abstracts/_index.scss index 876a379..8c297df 100644 --- a/src/styles/abstracts/_index.scss +++ b/src/styles/abstracts/_index.scss @@ -1,3 +1,4 @@ +@forward './animations'; @forward './fonts'; @forward './layout'; @forward './mixins'; diff --git a/src/styles/abstracts/_layout.scss b/src/styles/abstracts/_layout.scss index edc7116..06ec38a 100644 --- a/src/styles/abstracts/_layout.scss +++ b/src/styles/abstracts/_layout.scss @@ -14,20 +14,6 @@ bottom: 0; background-color: var(--primary-bg); position: relative; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: - radial-gradient(circle at 20% 30%, rgba(var(--primary-color), 0.05) 0%, transparent 70%), - radial-gradient(circle at 80% 70%, rgba(var(--cream-color), 0.05) 0%, transparent 70%); - pointer-events: none; - z-index: var(--z-bg); - } } // Main content area @@ -50,10 +36,8 @@ margin: 2rem auto; max-width: 600px; border-radius: var(--radius-lg); - background-color: rgba(var(--danger), 0.05); - border: 1px solid rgb(var(--danger), 0.2); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); - backdrop-filter: blur(5px); + background-color: color-mix(in srgb, var(--danger) 6%, var(--elevated-bg)); + border: 1px solid color-mix(in srgb, var(--danger) 25%, var(--border-soft)); text-align: center; h2 { @@ -90,12 +74,10 @@ border-radius: var(--radius-sm); font-weight: 600; letter-spacing: 0.5px; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); - transition: all var(--duration-normal) var(--easing-ease-out); + transition: background-color var(--duration-normal) var(--easing-ease-out); &:hover { - transform: translateY(-2px); - box-shadow: 0 6px 14px rgba(var(--primary-color), 0.4); + background-color: color-mix(in srgb, black 8%, var(--primary-color)); } } } @@ -110,10 +92,8 @@ margin: 2rem auto; max-width: 600px; border-radius: var(--radius-lg); - background-color: rgba(var(--danger), 0.05); - border: 1px solid rgb(var(--danger), 0.2); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); - backdrop-filter: blur(5px); + background-color: color-mix(in srgb, var(--danger) 6%, var(--elevated-bg)); + border: 1px solid color-mix(in srgb, var(--danger) 25%, var(--border-soft)); text-align: center; h3 { @@ -137,12 +117,10 @@ border-radius: var(--radius-sm); font-weight: 600; letter-spacing: 0.5px; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); - transition: all var(--duration-normal) var(--easing-ease-out); + transition: background-color var(--duration-normal) var(--easing-ease-out); &:hover { - transform: translateY(-2px); - box-shadow: 0 6px 14px rgba(var(--primary-color), 0.4); + background-color: color-mix(in srgb, black 8%, var(--primary-color)); } } } diff --git a/src/styles/abstracts/_mixins.scss b/src/styles/abstracts/_mixins.scss index 0202e22..197a86d 100644 --- a/src/styles/abstracts/_mixins.scss +++ b/src/styles/abstracts/_mixins.scss @@ -20,42 +20,11 @@ flex-direction: column; } -// Glass effect for overlay -@mixin glass-overlay($opacity: 0.7) { - background-color: rgba(var(--primary-bg), var(--opacity)); - backdrop-filter: blur(8px); - border: 1px solid rgba(255, 255, 255, 0.05); -} - -@mixin gradient-bg($start-color, $end-color, $direction: 135deg) { - background: linear-gradient($direction, $start-color, $end-color); -} - // Basic transition @mixin transition-standard { transition: all var(--duration-normal) var(--easing-ease-out); } -@mixin shadow-standard { - box-shadow: var(--shadow-standard); -} - -@mixin shadow-hover { - box-shadow: var(--shadow-hover); -} - -@mixin text-shadow { - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.7); -} - -// Simple animation for hover -@mixin hover-lift { - &:hover { - transform: translateY(-5px); - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5); - } -} - // Responsive mixins @mixin media-sm { @media (min-width: 576px) { @@ -81,13 +50,12 @@ } } -// Card base styling -@mixin card { - background-color: var(--secondary-bg); - border-radius: var(--radius-sm); - @include shadow-standard; - overflow: hidden; - position: relative; +// Sets the rendered size of a .spinner-ring SVG (see _loading.scss) the +// ring geometry is fixed by its viewBox, so the stroke scales +// proportionally with whatever size is set here. +@mixin spinner-size($size) { + width: $size; + height: $size; } // Custom scrollbar @@ -97,7 +65,7 @@ } &::-webkit-scrollbar-track { - background: rgba(var(--primary-bg), 0.5); + background: var(--primary-bg); border-radius: 10px; } diff --git a/src/styles/abstracts/_variables.scss b/src/styles/abstracts/_variables.scss index 71a5a79..7659903 100644 --- a/src/styles/abstracts/_variables.scss +++ b/src/styles/abstracts/_variables.scss @@ -34,16 +34,12 @@ --bold: 700; --extrabold: 800; - --family: 'Satoshi'; - // Shadows --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.3); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -4px rgba(0, 0, 0, 0.3); --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.3), 0 8px 10px -6px rgba(0, 0, 0, 0.3); --shadow-inner: inset 0 2px 4px rgba(0, 0, 0, 0.3); - --shadow-standard: 0 10px 25px rgba(0, 0, 0, 0.5); - --shadow-hover: 0 15px 30px rgba(0, 0, 0, 0.7); // Z-index levels --z-bg: 0; @@ -52,11 +48,3 @@ --z-modal: 1000; --z-tooltip: 1500; } - -// Color variables for SCSS usage -$success-color: #55e07a; -$danger-color: #ff5252; -$primary-color: #4a76c4; -$cream-color: #9b7dff; -$smoke-color: #fbb13c; -$warning-color: #fbb13c; diff --git a/src/styles/components/buttons/_action_button.scss b/src/styles/components/buttons/_action_button.scss index 1f2b9bd..3da7553 100644 --- a/src/styles/components/buttons/_action_button.scss +++ b/src/styles/components/buttons/_action_button.scss @@ -24,8 +24,6 @@ &:hover { background-color: var(--success-light); - transform: translateY(-2px) scale(1.02); - box-shadow: 0px 0px 12px rgba(140, 200, 147, 0.3); } } @@ -34,22 +32,13 @@ &:hover { background-color: var(--danger-light); - transform: translateY(-2px) scale(1.02); - box-shadow: 0px 0px 12px rgba(217, 107, 107, 0.3); } } - &:active { - transform: scale(0.97); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); - } - &:disabled { opacity: 0.7; cursor: not-allowed; background-color: var(--disabled); - transform: none; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); position: relative; overflow: hidden; @@ -85,20 +74,11 @@ &:hover { background-color: rgba(255, 255, 255, 0.3); - transform: translateY(-2px); - box-shadow: 0 7px 15px rgba(0, 0, 0, 0.3); - } - - &:active { - transform: translateY(0); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } &:disabled { opacity: 0.5; cursor: not-allowed; - transform: none; - box-shadow: none; } // Settings icon button variant &.settings-icon-button { diff --git a/src/styles/components/buttons/_animated_checkbox.scss b/src/styles/components/buttons/_animated_checkbox.scss index be4812e..7fdc078 100644 --- a/src/styles/components/buttons/_animated_checkbox.scss +++ b/src/styles/components/buttons/_animated_checkbox.scss @@ -40,7 +40,6 @@ &.checked { background-color: var(--primary-color, #ffc896); border-color: var(--primary-color, #ffc896); - box-shadow: 0 0 10px rgba(255, 200, 150, 0.2); } .checkbox-icon { diff --git a/src/styles/components/buttons/_button.scss b/src/styles/components/buttons/_button.scss index 2cf5bd2..016c022 100644 --- a/src/styles/components/buttons/_button.scss +++ b/src/styles/components/buttons/_button.scss @@ -14,25 +14,12 @@ white-space: nowrap; border-radius: var(--radius-sm); cursor: pointer; - transition: all var(--duration-normal) var(--easing-ease-out); - - // Default states - &:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-hover); - } - - &:active { - transform: translateY(0); - box-shadow: var(--shadow-standard); - } + transition: background-color var(--duration-normal) var(--easing-ease-out); &:disabled, &.disabled { - opacity: 0.7; + opacity: 0.55; cursor: not-allowed; - transform: none !important; - box-shadow: var(--shadow-standard) !important; } // Sizing @@ -54,14 +41,30 @@ gap: 0.6rem; } - // Variants + // Icon-only buttons are square, regardless of size + &.btn-icon-only.btn-sm { + padding: 0.45rem; + } + + &.btn-icon-only.btn-md { + padding: 0.6rem; + } + + &.btn-icon-only.btn-lg { + padding: 0.75rem; + } + + // Variants - flat fill, a plain darken/lighten on hover, no lift or glow &.btn-primary { background-color: var(--primary-color); color: var(--text-heavy); - &:hover { - background-color: var(--primary-color); - box-shadow: 0 6px 14px rgba(var(--primary-color), 0.3); + &:hover:not(:disabled) { + background-color: color-mix(in srgb, black 8%, var(--primary-color)); + } + + &:active:not(:disabled) { + background-color: color-mix(in srgb, black 14%, var(--primary-color)); } } @@ -69,9 +72,12 @@ background-color: var(--border-soft); color: var(--text-primary); - &:hover { + &:hover:not(:disabled) { background-color: var(--border); - box-shadow: 0 6px 14px rgba(0, 0, 0, 0.3); + } + + &:active:not(:disabled) { + background-color: color-mix(in srgb, black 10%, var(--border)); } } @@ -79,9 +85,8 @@ background-color: var(--success); color: var(--text-heavy); - &:hover { - background-color: var(--success-light); - box-shadow: 0 6px 14px rgba(var(--success), 0.3); + &:hover:not(:disabled) { + background-color: color-mix(in srgb, black 8%, var(--success)); } } @@ -89,9 +94,8 @@ background-color: var(--danger); color: var(--text-heavy); - &:hover { - background-color: var(--danger-light); - box-shadow: 0 6px 14px rgba(var(--danger), 0.3); + &:hover:not(:disabled) { + background-color: color-mix(in srgb, black 8%, var(--danger)); } } @@ -99,9 +103,8 @@ background-color: var(--warning); color: var(--text-heavy); - &:hover { - background-color: var(--warning-light); - box-shadow: 0 6px 14px rgba(var(--warning), 0.3); + &:hover:not(:disabled) { + background-color: color-mix(in srgb, black 8%, var(--warning)); } } @@ -115,13 +118,10 @@ position: relative; margin-right: 0.5rem; - .spinner { + .spinner-ring { width: 100%; height: 100%; - border: 2px solid rgba(255, 255, 255, 0.3); - border-top-color: currentColor; - border-radius: 50%; - animation: spin 0.8s linear infinite; + color: inherit; } } @@ -151,42 +151,18 @@ } } -// Animation for spinner -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - // Rating button on game card .rate-button { svg { color: var(--elevated-bg); - transition: transform var(--duration-normal) var(--easing-ease-out); } &:hover { background-color: rgba(255, 255, 255, 0.28); - transform: translateY(-2px); - box-shadow: 0 7px 15px rgba(0, 0, 0, 0.25); - - svg { - transform: scale(1.1); - } - } - - &:active { - transform: translateY(0); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } &:disabled { opacity: 0.4; cursor: not-allowed; - transform: none; - box-shadow: none; } } diff --git a/src/styles/components/common/_dropdown.scss b/src/styles/components/common/_dropdown.scss index ffdf66b..162a81b 100644 --- a/src/styles/components/common/_dropdown.scss +++ b/src/styles/components/common/_dropdown.scss @@ -62,7 +62,6 @@ &:focus { outline: none; border-color: var(--primary-color); - box-shadow: 0 0 0 2px rgba(var(--primary-color), 0.2); } &:disabled { @@ -117,7 +116,7 @@ } &.selected { - background-color: rgba(var(--primary-color), 0.2); + background-color: color-mix(in srgb, var(--primary-color) 16%, transparent); color: var(--primary-color); } diff --git a/src/styles/components/common/_entry_list.scss b/src/styles/components/common/_entry_list.scss new file mode 100644 index 0000000..42120b5 --- /dev/null +++ b/src/styles/components/common/_entry_list.scss @@ -0,0 +1,130 @@ +@use '../../themes/index' as *; +@use '../../abstracts/index' as *; + +/* + EntryList - generic add/remove list of string entries (e.g. file paths). + The input row (manual entry + browse button) is pinned below the + scrollable entries area, so it's always visible regardless of how many + entries there are. +*/ + +.entry-list-error { + color: var(--danger); + background-color: var(--danger-soft); + border: 1px solid var(--danger-light); + border-radius: var(--radius-sm); + padding: 0.75rem 1rem; + margin-bottom: 1rem; + font-size: 0.9rem; +} + +.entry-list { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +// Scrolls once entries exceed a handful of rows the input row below stays +// put since it lives outside this scrolling box. +.entry-list-scroll-area { + max-height: 260px; + overflow-y: auto; + @include custom-scrollbar; +} + +.entry-list-empty { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 2rem 1rem; + color: var(--text-soft); + background-color: var(--tertiary-bg); + border: 1px solid var(--border-soft); + border-radius: var(--radius-md); + + .icon { + opacity: 0.5; + margin-bottom: 0.75rem; + } + + p { + margin: 0; + } +} + +.entry-list-items { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.entry-list-item { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + background-color: var(--tertiary-bg); + border: 1px solid var(--border-soft); + border-radius: var(--radius-sm); + + .entry-list-item-icon { + flex-shrink: 0; + color: var(--text-secondary); + } + + .entry-list-remove-button { + flex-shrink: 0; + } +} + +// Truncate from the START so the end of a long path stays visible the +// classic RTL trick: flipping the box's inline direction moves where the +// overflow ellipsis lands, while individual LTR characters still render +// left-to-right within it. +.entry-list-item-text { + flex: 1; + min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + direction: rtl; + text-align: left; + font-family: monospace; + font-size: 0.9rem; + color: var(--text-primary); +} + +.entry-list-input-row { + display: flex; + align-items: center; + gap: 0.5rem; + flex-shrink: 0; +} + +.entry-list-input { + flex: 1; + min-width: 0; + background-color: var(--tertiary-bg); + border: 1px solid var(--border-soft); + border-radius: var(--radius-sm); + color: var(--text-primary); + padding: 0.7rem 1rem; + font-size: 0.9rem; + font-family: monospace; + transition: all var(--duration-normal) var(--easing-ease-out); + + &:focus { + border-color: var(--primary-color); + outline: none; + } + + &::placeholder { + color: var(--text-soft); + font-family: sans-serif; + } +} + +.entry-list-browse-button { + flex-shrink: 0; +} diff --git a/src/styles/components/common/_index.scss b/src/styles/components/common/_index.scss index 44e5985..b874963 100644 --- a/src/styles/components/common/_index.scss +++ b/src/styles/components/common/_index.scss @@ -2,3 +2,4 @@ @forward './progress_bar'; @forward './dropdown'; @forward './votes_display'; +@forward './entry_list'; diff --git a/src/styles/components/common/_loading.scss b/src/styles/components/common/_loading.scss index 097ef9f..2789a78 100644 --- a/src/styles/components/common/_loading.scss +++ b/src/styles/components/common/_loading.scss @@ -13,9 +13,7 @@ // Size variations &.loading-small { .loading-spinner { - width: 20px; - height: 20px; - border-width: 2px; + @include spinner-size(20px); } .loading-dots { @@ -29,18 +27,11 @@ font-size: 0.8rem; margin-top: 0.5rem; } - - .progress-bar-container { - height: 6px; - width: 100px; - } } &.loading-medium { .loading-spinner { - width: 30px; - height: 30px; - border-width: 3px; + @include spinner-size(30px); } .loading-dots { @@ -54,18 +45,11 @@ font-size: 0.9rem; margin-top: 0.75rem; } - - .progress-bar-container { - height: 8px; - width: 200px; - } } &.loading-large { .loading-spinner { - width: 50px; - height: 50px; - border-width: 4px; + @include spinner-size(50px); } .loading-dots { @@ -79,20 +63,42 @@ font-size: 1.1rem; margin-top: 1rem; } - - .progress-bar-container { - height: 10px; - width: 300px; - } } } -// Spinner styles -.loading-spinner { - border-radius: 50%; - border: 3px solid rgba(255, 255, 255, 0.1); - border-top-color: var(--primary-color); - animation: spin 1s linear infinite; +// Windows/Fluent-style ring spinner - an SVG circle with an animated +// stroke-dasharray + rotation, rather than a CSS conic-gradient mask. +// Sizing is set per-context (see above); the ring geometry (viewBox + +// circle radius) is fixed, so the stroke scales with it automatically. +.spinner-ring { + overflow: visible; + color: var(--primary-color); + + circle { + fill: none; + stroke: currentColor; + stroke-width: 1.5px; + stroke-linecap: round; + transform-origin: 50% 50%; + animation: spinner-dash 2s linear infinite; + } +} + +@keyframes spinner-dash { + 0% { + stroke-dasharray: 0.01px, 43.97px; + transform: rotate(0deg); + } + + 50% { + stroke-dasharray: 21.99px, 21.99px; + transform: rotate(450deg); + } + + 100% { + stroke-dasharray: 0.01px, 43.97px; + transform: rotate(1080deg); + } } // Loading dots animation @@ -115,49 +121,12 @@ } } -// Progress bar styles -.loading-progress { - display: flex; - flex-direction: column; - align-items: center; - width: 100%; -} - -.progress-bar-container { - background-color: var(--border-soft); - border-radius: 4px; - overflow: hidden; - width: 100%; - margin-bottom: 0.5rem; -} - -.progress-bar { - height: 100%; - background-color: var(--primary-color); - border-radius: 4px; - transition: width 0.3s ease; -} - -.progress-percentage { - font-size: 0.8rem; - color: var(--text-secondary); -} - .loading-message { color: var(--text-secondary); text-align: center; } -// Animations -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - +// Animation @keyframes bounce { 0%, 80%, diff --git a/src/styles/components/common/_progress_bar.scss b/src/styles/components/common/_progress_bar.scss index b47c18e..083db7d 100644 --- a/src/styles/components/common/_progress_bar.scss +++ b/src/styles/components/common/_progress_bar.scss @@ -21,15 +21,6 @@ background: var(--primary-color); border-radius: 4px; overflow: hidden; - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3); -} - -.progress-fill { - height: 100%; - background: var(--primary-color); - transition: width 0.3s ease; - border-radius: 4px; - position: relative; } .progress-text { diff --git a/src/styles/components/dialogs/_api_settings_dialog.scss b/src/styles/components/dialogs/_api_settings_dialog.scss new file mode 100644 index 0000000..c541646 --- /dev/null +++ b/src/styles/components/dialogs/_api_settings_dialog.scss @@ -0,0 +1,67 @@ +@use '../../themes/index' as *; +@use '../../abstracts/index' as *; + +/* + API Settings Dialog styles - shared by any unlocker's config dialog + (SmokeAPI, ScreamAPI, ...) +*/ + +.dialog-subtitle { + color: var(--text-secondary); + font-weight: 500; + margin-top: 0.25rem; + font-weight: normal; +} + +.api-settings-content { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.settings-options { + display: flex; + flex-direction: column; + gap: 1.5rem; + transition: opacity var(--duration-normal) var(--easing-ease-out); + + &.disabled { + opacity: 0.4; + pointer-events: none; + } +} + +.settings-section { + display: flex; + flex-direction: column; + gap: 1rem; + + h4 { + font-size: 1rem; + font-weight: 600; + color: var(--text-primary); + margin: 0; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--border-soft); + } +} + +.checkbox-option { + padding: 0.5rem 0; + + &:not(:last-child) { + border-bottom: 1px solid var(--border-soft); + } + + .animated-checkbox { + width: 100%; + + .checkbox-content { + flex: 1; + } + + .checkbox-sublabel { + margin-top: 0.25rem; + } + } +} diff --git a/src/styles/components/dialogs/_dlc_dialog.scss b/src/styles/components/dialogs/_dlc_dialog.scss index e4ff838..9c68059 100644 --- a/src/styles/components/dialogs/_dlc_dialog.scss +++ b/src/styles/components/dialogs/_dlc_dialog.scss @@ -132,13 +132,8 @@ flex-direction: column; gap: 1rem; - .loading-spinner { - width: 40px; - height: 40px; - border: 3px solid rgba(255, 255, 255, 0.1); - border-top-color: var(--primary-color); - border-radius: 50%; - animation: spin 1s linear infinite; + .spinner-ring { + @include spinner-size(40px); } p { @@ -254,16 +249,7 @@ margin: 0; } -// Loading animations -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - +// Loading animation @keyframes loading-pulse { 0% { background-position: 200% 50%; diff --git a/src/styles/components/dialogs/_index.scss b/src/styles/components/dialogs/_index.scss index 8d758cb..4f47b9c 100644 --- a/src/styles/components/dialogs/_index.scss +++ b/src/styles/components/dialogs/_index.scss @@ -1,8 +1,7 @@ @forward './dialog'; @forward './dlc_dialog'; @forward './progress_dialog'; -@forward './settings_dialog'; -@forward './smokeapi_settings_dialog'; +@forward './api_settings_dialog'; @forward './conflict_dialog'; @forward './disclaimer_dialog'; @forward './unlocker_selection_dialog'; diff --git a/src/styles/components/dialogs/_progress_dialog.scss b/src/styles/components/dialogs/_progress_dialog.scss index 1ac5067..8024797 100644 --- a/src/styles/components/dialogs/_progress_dialog.scss +++ b/src/styles/components/dialogs/_progress_dialog.scss @@ -15,13 +15,11 @@ margin-bottom: 0.5rem; } -.progress-bar { +.progress-dialog-fill { height: 100%; background-color: var(--primary-color); border-radius: 4px; transition: width 0.3s ease; - background: var(--primary-color); - box-shadow: 0px 0px 6px rgba(245, 150, 130, 0.3); } .progress-percentage { diff --git a/src/styles/components/dialogs/_rating_dialog.scss b/src/styles/components/dialogs/_rating_dialog.scss index 4b6dab6..87fe2e9 100644 --- a/src/styles/components/dialogs/_rating_dialog.scss +++ b/src/styles/components/dialogs/_rating_dialog.scss @@ -40,7 +40,7 @@ font-size: 0.95rem; font-weight: var(--bold); cursor: pointer; - transition: all var(--duration-normal) var(--easing-ease-out); + transition: background-color var(--duration-normal) var(--easing-ease-out); color: var(--text-heavy); &--worked { @@ -48,8 +48,6 @@ &:hover:not(:disabled) { background-color: var(--success-light); - transform: translateY(-2px); - box-shadow: 0 6px 14px rgba(140, 200, 147, 0.3); } } @@ -58,19 +56,12 @@ &:hover:not(:disabled) { background-color: var(--danger-light); - transform: translateY(-2px); - box-shadow: 0 6px 14px rgba(217, 107, 107, 0.3); } } - &:active:not(:disabled) { - transform: scale(0.97); - } - &:disabled { opacity: 0.6; cursor: not-allowed; - transform: none; } } diff --git a/src/styles/components/games/_gamecard.scss b/src/styles/components/games/_gamecard.scss index 8957a4d..4a9113b 100644 --- a/src/styles/components/games/_gamecard.scss +++ b/src/styles/components/games/_gamecard.scss @@ -11,8 +11,12 @@ border-radius: var(--radius-lg); overflow: hidden; will-change: opacity, transform; - box-shadow: var(--shadow-standard); - transition: all var(--duration-normal) var(--easing-ease-out); + border: 1px solid var(--border-soft); + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25); + transition: + transform var(--duration-normal) var(--easing-ease-out), + box-shadow var(--duration-normal) var(--easing-ease-out), + border-color var(--duration-normal) var(--easing-ease-out); transform-origin: center; // Simple image loading animation @@ -20,52 +24,69 @@ animation: fadeIn 0.5s forwards; } -// Hover effects for the card +// Hover effects for the card a small lift, plus a soft ambient glow in +// whatever status color is most relevant (installed unlocker takes +// priority over the base native/proton badge), and each badge itself picks +// up a matching glow too. .game-item-card:hover { - transform: translateY(-8px) scale(1.02); - box-shadow: var(--shadow-hover); + transform: translateY(-3px); + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.3); + border-color: var(--border); z-index: 5; + &:has(.status-badge.native) { + box-shadow: + 0 6px 18px rgba(0, 0, 0, 0.3), + 0 0 24px rgba(140, 200, 147, 0.25); + } + + &:has(.status-badge.proton) { + box-shadow: + 0 6px 18px rgba(0, 0, 0, 0.3), + 0 0 24px rgba(255, 200, 150, 0.25); + } + + &:has(.status-badge.cream) { + box-shadow: + 0 6px 18px rgba(0, 0, 0, 0.3), + 0 0 24px rgba(128, 180, 255, 0.3); + } + + &:has(.status-badge.smoke) { + box-shadow: + 0 6px 18px rgba(0, 0, 0, 0.3), + 0 0 24px rgba(255, 240, 150, 0.3); + } + + // Epic's own badge color is near-black, so it needs a lighter stand-in + // to actually read as a glow + &:has(.status-badge.epic) { + box-shadow: + 0 6px 18px rgba(0, 0, 0, 0.3), + 0 0 24px rgba(120, 140, 165, 0.3); + } + .status-badge.native { - box-shadow: 0 0 10px rgba(85, 224, 122, 0.5); + box-shadow: 0 0 10px rgba(140, 200, 147, 0.5); } .status-badge.proton { - box-shadow: 0 0 10px rgba(255, 201, 150, 0.5); + box-shadow: 0 0 10px rgba(255, 200, 150, 0.5); } .status-badge.cream { - box-shadow: 0 0 10px rgba(128, 181, 255, 0.5); + box-shadow: 0 0 10px rgba(128, 180, 255, 0.5); } .status-badge.smoke { - box-shadow: 0 0 10px rgba(255, 239, 150, 0.5); + box-shadow: 0 0 10px rgba(255, 240, 150, 0.5); } .status-badge.epic { - box-shadow: 0 0 10px rgba(15, 25, 35, 0.5); + box-shadow: 0 0 10px rgba(120, 140, 165, 0.5); } } -// Special styling for cards with different statuses -.game-item-card:has(.status-badge.cream) { - box-shadow: - var(--shadow-standard), - 0 0 15px rgba(128, 181, 255, 0.15); -} - -.game-item-card:has(.status-badge.smoke) { - box-shadow: - var(--shadow-standard), - 0 0 15px rgba(255, 239, 150, 0.15); -} - -.game-item-card:has(.status-badge.epic) { - box-shadow: - var(--shadow-standard), - 0 0 15px rgba(15, 25, 35, 0.15); -} - // Game item overlay .game-item-overlay { position: absolute; @@ -85,9 +106,6 @@ padding: 1rem; box-sizing: border-box; font-weight: var(--bold); - font-family: var(--family); - -webkit-font-smoothing: subpixel-antialiased; - text-rendering: geometricPrecision; color: var(--text-heavy); z-index: 1; } @@ -108,13 +126,8 @@ border-radius: 4px; font-size: 0.75rem; font-weight: var(--bold); - font-family: var(--family); - -webkit-font-smoothing: subpixel-antialiased; - text-rendering: geometricPrecision; color: var(--text-heavy); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); - transition: all var(--duration-normal) var(--easing-ease-out); - border: 1px solid rgba(255, 255, 255, 0.1); + transition: box-shadow var(--duration-normal) var(--easing-ease-out); } .status-badge.native { @@ -152,8 +165,6 @@ font-size: 1.6rem; font-weight: var(--bold); margin: 0; - -webkit-font-smoothing: subpixel-antialiased; - text-rendering: geometricPrecision; transform: translateZ(0); will-change: opacity, transform; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8); diff --git a/src/styles/components/games/_gamelist.scss b/src/styles/components/games/_gamelist.scss index 562990c..02d0689 100644 --- a/src/styles/components/games/_gamelist.scss +++ b/src/styles/components/games/_gamelist.scss @@ -17,26 +17,20 @@ h2 { font-size: 1.4rem; font-weight: 700; - margin-bottom: 1.5rem; color: var(--text-primary); - letter-spacing: 0.5px; - position: relative; - display: inline-block; - padding-bottom: 0.5rem; - - &:after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 3px; - background: linear-gradient(90deg, var(--primary-color), transparent); - border-radius: 3px; - } + letter-spacing: 0.3px; } } +.game-list-header { + display: flex; + align-items: center; + justify-content: space-between; + padding-bottom: 0.9rem; + margin-bottom: 1.25rem; + border-bottom: 1px solid var(--border-dark); +} + // Game grid .game-grid { display: grid; @@ -63,25 +57,8 @@ color: var(--text-secondary); text-align: center; border-radius: var(--radius-lg); - background-color: rgba(255, 255, 255, 0.03); - box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.2); - backdrop-filter: blur(5px); -} - -.loading-indicator { - position: relative; - overflow: hidden; - - &:after { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 50%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent); - animation: loading-shimmer 2s infinite; - } + background-color: var(--tertiary-bg); + border: 1px solid var(--border-soft); } // Responsive adjustments @@ -111,20 +88,19 @@ width: 44px; height: 44px; border-radius: 50%; - background: linear-gradient( - 135deg, - var(--primary-color), - color-mix(in srgb, black 10%, var(--primary-color)) - ); - color: var(--text-primary); + background-color: var(--primary-color); + color: var(--text-heavy); display: flex; align-items: center; justify-content: center; cursor: pointer; - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); + border: 1px solid var(--border-soft); opacity: 0; - transform: translateY(20px); - transition: all var(--duration-normal) var(--easing-ease-out); + transform: translateY(10px); + transition: + background-color var(--duration-normal) var(--easing-ease-out), + opacity var(--duration-normal) var(--easing-ease-out), + transform var(--duration-normal) var(--easing-ease-out); z-index: var(--z-header); &.visible { @@ -133,18 +109,6 @@ } &:hover { - transform: translateY(-5px); - box-shadow: 0 8px 20px rgba(var(--primary-color), 0.4); - } - - &:active { - transform: translateY(0); - } -} - -// Loading shimmer animation -@keyframes loading-shimmer { - to { - left: 100%; + background-color: color-mix(in srgb, black 8%, var(--primary-color)); } } diff --git a/src/styles/components/layout/_header.scss b/src/styles/components/layout/_header.scss index 9059207..de1ba94 100644 --- a/src/styles/components/layout/_header.scss +++ b/src/styles/components/layout/_header.scss @@ -1,17 +1,16 @@ @use '../../themes/index' as *; @use '../../abstracts/index' as *; -/* +/* Header component styles */ .app-header { display: flex; align-items: center; justify-content: space-between; - padding: 1rem 2rem; - background-color: var(--tertiary-bg); - border-bottom: 1px solid rgba(255, 255, 255, 0.07); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); + padding: 0 2rem; + background-color: var(--secondary-bg); + border-bottom: 1px solid var(--border-dark); position: relative; z-index: var(--z-header); height: var(--header-height); @@ -19,47 +18,19 @@ .app-title { display: flex; align-items: center; - gap: 0.75rem; + gap: 0.65rem; h1 { - font-size: 1.5rem; + font-size: 1.25rem; font-weight: 600; color: var(--text-primary); - letter-spacing: 0.5px; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.7); + letter-spacing: 0.2px; } .app-logo-icon { color: var(--primary-color); - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); } } - - &::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 3px; - background: linear-gradient( - 90deg, - var(--cream-color), - var(--primary-color), - var(--smoke-color) - ); - opacity: 0.7; - } - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent); - } } .header-controls { @@ -75,30 +46,28 @@ .search-icon { position: absolute; - left: 0.8rem; - color: rgba(255, 255, 255, 0.4); + left: 0.85rem; + color: var(--text-muted); pointer-events: none; } } .search-input { - background-color: var(--border-dark); + background-color: var(--tertiary-bg); border: 1px solid var(--border-soft); - border-radius: 4px; + border-radius: var(--radius-md); color: var(--text-primary); - padding: 0.6rem 1rem 0.6rem 2.5rem; + padding: 0.55rem 1rem 0.55rem 2.6rem; font-size: 0.9rem; - transition: all var(--duration-normal) var(--easing-ease-out); - box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.2); - min-width: 200px; + transition: + border-color var(--duration-normal) var(--easing-ease-out), + background-color var(--duration-normal) var(--easing-ease-out); + min-width: 220px; &:focus { border-color: var(--primary-color); - background-color: rgba(255, 255, 255, 0.1); + background-color: var(--secondary-bg); outline: none; - box-shadow: - 0 0 0 2px rgba(var(--primary-color), 0.3), - inset 0 2px 5px rgba(0, 0, 0, 0.2); & + .search-icon { color: var(--primary-color); @@ -106,6 +75,6 @@ } &::placeholder { - color: rgba(255, 255, 255, 0.4); + color: var(--text-muted); } } diff --git a/src/styles/components/layout/_index.scss b/src/styles/components/layout/_index.scss index 4e5889e..565bbb4 100644 --- a/src/styles/components/layout/_index.scss +++ b/src/styles/components/layout/_index.scss @@ -1,4 +1,3 @@ -@forward './background'; @forward './header'; @forward './loading_screen'; @forward './sidebar'; diff --git a/src/styles/components/layout/_loading_screen.scss b/src/styles/components/layout/_loading_screen.scss index ebe13d7..766293c 100644 --- a/src/styles/components/layout/_loading_screen.scss +++ b/src/styles/components/layout/_loading_screen.scss @@ -29,20 +29,14 @@ margin-bottom: 2rem; font-weight: var(--bold); color: var(--primary-color); - text-shadow: 0 2px 10px rgba(var(--primary-color), 0.4); } .loading-animation { margin: 1rem 0; - // Spinner styles - thicker border - .loading-spinner { - width: 50px; - height: 50px; - border-radius: 50%; - border: 6px solid rgba(255, 255, 255, 0.1); - border-top-color: var(--primary-color); - animation: spin 1s linear infinite; + // Spinner styles - thicker ring + .spinner-ring { + @include spinner-size(56px); } } @@ -68,7 +62,7 @@ transition: all 0.3s ease; &.active { - background-color: rgba(var(--primary-color-rgb), 0.1); + background-color: color-mix(in srgb, var(--primary-color) 10%, transparent); .status-step { color: var(--primary-color); diff --git a/src/styles/components/layout/_sidebar.scss b/src/styles/components/layout/_sidebar.scss index 569649b..045462f 100644 --- a/src/styles/components/layout/_sidebar.scss +++ b/src/styles/components/layout/_sidebar.scss @@ -1,15 +1,14 @@ @use '../../themes/index' as *; @use '../../abstracts/index' as *; -/* +/* Sidebar component styles */ .sidebar { width: var(--sidebar-width); min-width: var(--sidebar-width); background-color: var(--secondary-bg); - border-right: 1px solid rgba(255, 255, 255, 0.05); - box-shadow: inset -5px 0 15px rgba(0, 0, 0, 0.2); + border-right: 1px solid var(--border-dark); padding: 1.5rem 1rem; display: flex; flex-direction: column; @@ -21,13 +20,13 @@ .sidebar-header { margin-bottom: 1.5rem; + padding: 0 0.5rem; h2 { color: var(--text-primary); - font-size: 1.1rem; + font-size: 1.05rem; font-weight: 600; - letter-spacing: 0.5px; - opacity: 0.9; + letter-spacing: 0.2px; } } @@ -37,14 +36,13 @@ .sidebar-section-label { display: block; - font-size: 0.65rem; - font-weight: 700; - letter-spacing: 1px; + font-size: 0.68rem; + font-weight: 600; + letter-spacing: 0.6px; text-transform: uppercase; - color: var(--text-secondary); - opacity: 0.6; + color: var(--text-muted); padding: 0 1rem; - margin-bottom: 0.25rem; + margin-bottom: 0.35rem; } .sidebar-section .filter-list { @@ -56,34 +54,33 @@ margin-bottom: 0; li { - transition: all var(--duration-normal) var(--easing-ease-out); - border-radius: var(--radius-sm); - padding: 0.7rem 1rem; - margin-bottom: 0.3rem; + transition: + background-color var(--duration-normal) var(--easing-ease-out), + color var(--duration-normal) var(--easing-ease-out); + border-radius: var(--radius-md); + padding: 0.65rem 1rem; + margin-bottom: 0.15rem; font-weight: 500; + color: var(--text-secondary); cursor: pointer; &:hover { - background-color: rgba(255, 255, 255, 0.07); + background-color: var(--tertiary-bg); + color: var(--text-primary); } &.active { - background: linear-gradient( - 135deg, - var(--primary-color), - color-mix(in srgb, black 10%, var(--primary-color)) - ); - box-shadow: 0 4px 10px rgba(var(--primary-color), 0.3); - color: var(--elevated-bg); + background-color: color-mix(in srgb, var(--primary-color) 16%, transparent); + color: var(--primary-color); .filter-icon { - color: var(--elevated-bg); + color: var(--primary-color); } } - // Ensure icons are white when not active + // Ensure icons follow the resting text color when not active &:not(.active) .filter-icon { - color: var(--text-primary); + color: var(--text-secondary); } } } @@ -98,37 +95,6 @@ } } -.settings-button { - margin-top: auto; - - &.btn.btn-secondary { - background-color: transparent; - border: 1px solid transparent; - color: var(--text-secondary); - - &:hover { - background-color: rgba(255, 255, 255, 0.07); - color: var(--text-primary); - border-color: var(--border-soft); - transform: none; - box-shadow: none; - } - - &:active { - transform: scale(0.98); - } - - .settings-icon { - transition: transform 0.3s ease; - color: inherit; - } - - &:hover .settings-icon { - transform: rotate(45deg); - } - } -} - // App logo styles .app-logo { display: flex; @@ -139,6 +105,39 @@ width: 28px; height: 28px; fill: var(--text-primary); - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); + } +} + +// Pinned to the bottom of the sidebar via margin-top: auto - version/build +// and a repo link, so this doesn't need its own page-section anymore +.sidebar-footer { + margin-top: auto; + padding: 0.85rem 1rem 0.25rem; + border-top: 1px solid var(--border-dark); + display: flex; + align-items: center; + justify-content: space-between; +} + +.sidebar-footer-info { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.78rem; + color: var(--text-muted); +} + +.sidebar-footer-version { + font-family: monospace; +} + +.sidebar-footer-link { + font-size: 0.78rem; + color: var(--text-secondary); + text-decoration: none; + transition: color var(--duration-normal) var(--easing-ease-out); + + &:hover { + color: var(--primary-color); } } diff --git a/src/styles/components/notifications/_toast.scss b/src/styles/components/notifications/_toast.scss index f9d20cb..0a280f0 100644 --- a/src/styles/components/notifications/_toast.scss +++ b/src/styles/components/notifications/_toast.scss @@ -197,26 +197,3 @@ } } } - -// Animations for toast -@keyframes toast-in { - from { - opacity: 0; - transform: translateY(30px) scale(0.9); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -@keyframes toast-out { - from { - opacity: 1; - transform: translateY(0) scale(1); - } - to { - opacity: 0; - transform: translateY(-30px) scale(0.9); - } -} diff --git a/src/styles/components/pages/_index.scss b/src/styles/components/pages/_index.scss new file mode 100644 index 0000000..8954582 --- /dev/null +++ b/src/styles/components/pages/_index.scss @@ -0,0 +1,2 @@ +@forward './shared'; +@forward './overview'; diff --git a/src/styles/components/pages/_overview.scss b/src/styles/components/pages/_overview.scss new file mode 100644 index 0000000..be7d0d0 --- /dev/null +++ b/src/styles/components/pages/_overview.scss @@ -0,0 +1,263 @@ +@use '../../themes/index' as *; +@use '../../abstracts/index' as *; + +/* + Overview page - a hero row for the two library totals, a Native/Proton + composition bar for the Steam library, and secondary stats as compact + chips (rather than one long row of identical boxes). +*/ + +.overview-section-label { + display: block; + font-size: 0.68rem; + font-weight: 600; + letter-spacing: 0.6px; + text-transform: uppercase; + color: var(--text-muted); +} + +// Hero numbers - the two headline totals +.stat-hero { + display: flex; + align-items: center; + gap: 2.5rem; +} + +.stat-hero-item { + display: flex; + flex-direction: column; + gap: 0.15rem; +} + +.stat-hero-value { + font-size: 2.75rem; + font-weight: 800; + line-height: 1; + color: var(--text-primary); +} + +.stat-hero-label { + font-size: 0.85rem; + color: var(--text-secondary); +} + +.stat-hero-divider { + width: 1px; + height: 42px; + background-color: var(--border-soft); +} + +// Native/Proton composition bar for the Steam library +.library-composition { + display: flex; + flex-direction: column; + gap: 0.6rem; + max-width: 640px; +} + +.composition-bar { + display: flex; + width: 100%; + height: 10px; + border-radius: 99px; + overflow: hidden; + background-color: var(--tertiary-bg); +} + +.composition-segment { + height: 100%; + transition: width 0.4s ease; + + &.native { + background-color: var(--native); + } + + &.proton { + background-color: var(--proton); + } +} + +.composition-legend { + display: flex; + gap: 1.5rem; +} + +.legend-item { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; +} + +.legend-dot { + width: 8px; + height: 8px; + border-radius: 50%; + + &.native { + background-color: var(--native); + } + + &.proton { + background-color: var(--proton); + } +} + +.legend-label { + color: var(--text-secondary); +} + +.legend-value { + color: var(--text-primary); + font-weight: 600; +} + +// Secondary stats as compact pill chips +.stat-chips { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.stat-chip { + display: inline-flex; + align-items: center; + gap: 0.6rem; + padding: 0.6rem 1rem; + background-color: var(--elevated-bg); + border: 1px solid var(--border-soft); + border-radius: 99px; + + .stat-chip-icon { + color: var(--icon-secondary); + } + + .stat-chip-value { + font-weight: 700; + color: var(--text-primary); + } + + .stat-chip-label { + font-size: 0.85rem; + color: var(--text-secondary); + } +} + +// Two side-by-side cards (Recent Activity / System) filling out the rest +// of the page stacks on narrow windows. +.overview-columns { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + + .page-section { + flex: 1; + min-width: 280px; + max-width: none; + } +} + +.activity-feed { + display: flex; + flex-direction: column; + gap: 0.5rem; + max-height: 260px; + overflow-y: auto; + @include custom-scrollbar; +} + +.activity-item { + display: flex; + align-items: center; + gap: 0.65rem; + padding: 0.5rem 0; + + &:not(:last-child) { + border-bottom: 1px solid var(--border-soft); + } +} + +.activity-item-dot { + width: 7px; + height: 7px; + border-radius: 50%; + flex-shrink: 0; + + &--install { + background-color: var(--success); + } + + &--uninstall { + background-color: var(--danger); + } + + &--update { + background-color: var(--info); + } +} + +.activity-item-message { + flex: 1; + min-width: 0; + font-size: 0.85rem; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.activity-item-time { + font-size: 0.75rem; + color: var(--text-muted); + flex-shrink: 0; +} + +// System spec sheet - a colored accent bar per field instead of plain +// label/value rows, with the value given real typographic weight +.system-specs { + display: flex; + flex-direction: column; + gap: 1.1rem; +} + +.system-spec { + display: flex; + flex-direction: column; + gap: 0.2rem; + padding-left: 0.85rem; + border-left: 3px solid var(--border-soft); + + &--os { + border-left-color: var(--info); + } + + &--cpu { + border-left-color: var(--success); + } + + &--gpu { + border-left-color: var(--primary-color); + } +} + +.system-spec-label { + font-size: 0.68rem; + font-weight: 600; + letter-spacing: 0.6px; + text-transform: uppercase; + color: var(--text-muted); +} + +.system-spec-value { + font-size: 1rem; + font-weight: 600; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.system-spec-sub { + font-size: 0.78rem; + color: var(--text-muted); +} diff --git a/src/styles/components/pages/_shared.scss b/src/styles/components/pages/_shared.scss new file mode 100644 index 0000000..d00d44b --- /dev/null +++ b/src/styles/components/pages/_shared.scss @@ -0,0 +1,134 @@ +@use '../../themes/index' as *; +@use '../../abstracts/index' as *; + +/* + Shared layout for top-level pages reached via the sidebar (Overview, + Settings) - same container treatment as .game-list so switching between + them feels consistent. +*/ +.overview-page, +.settings-page { + padding: 1.5rem; + flex: 1; + overflow-y: auto; + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + gap: 1.5rem; + @include custom-scrollbar; + + h2 { + font-size: 1.4rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: 0.3px; + padding-bottom: 0.9rem; + margin-bottom: 0.25rem; + border-bottom: 1px solid var(--border-dark); + } +} + +// A titled subsection within a page (distinct from dialogs' .settings-section, +// which is sized for a modal rather than a full page). Rendered as a single +// unified card, the heading, description, and body content all live inside +// the same container instead of the body floating below on its own. +.page-section { + background-color: var(--elevated-bg); + border: 1px solid var(--border-soft); + border-radius: var(--radius-lg); + padding: 1.5rem; + max-width: 640px; + + h4 { + font-size: 1.1rem; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 0.4rem; + } + + .page-section-description { + color: var(--text-secondary); + font-size: 0.9rem; + margin-bottom: 1.25rem; + line-height: 1.4; + } +} + +// Danger Zone - a page-section with a subtle danger-tinted border instead +// of the default neutral one, so it reads as "be careful here" without +// resorting to a loud red banner +.page-section.danger-zone { + border-color: color-mix(in srgb, var(--danger) 30%, var(--border-soft)); + + h4 { + color: var(--danger-light); + } +} + +.danger-zone-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.85rem 0; + + &:not(:last-child) { + border-bottom: 1px solid var(--border-soft); + } +} + +.danger-zone-row-text { + display: flex; + flex-direction: column; + gap: 0.15rem; + min-width: 0; +} + +.danger-zone-row-label { + font-weight: 500; + color: var(--text-primary); + font-size: 0.9rem; +} + +.danger-zone-row-description { + font-size: 0.8rem; + color: var(--text-muted); +} + +.app-info { + .info-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.6rem 0; + + &:not(:last-child) { + border-bottom: 1px solid var(--border-soft); + } + + .info-label { + font-weight: 500; + color: var(--text-secondary); + font-size: 0.9rem; + } + + .info-value { + color: var(--text-primary); + font-size: 0.9rem; + font-family: monospace; + } + + .info-link { + color: var(--primary-color); + text-decoration: none; + font-size: 0.9rem; + transition: color 0.2s ease; + + &:hover { + color: var(--secondary-color); + text-decoration: underline; + } + } + } +} diff --git a/src/styles/main.scss b/src/styles/main.scss index eefaa3d..a0450dc 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -20,6 +20,9 @@ /* Dialog components */ @use 'components/dialogs/index' as *; +/* Page components (Overview, Settings) */ +@use 'components/pages/index' as *; + /* Notification components */ @use 'components/notifications/index' as *; @@ -28,6 +31,3 @@ /* Common components */ @use 'components/common/index' as *; - -/* Page-specific styles */ -//@use 'pages/home';