diff --git a/README.md b/README.md index f99cd06..1978622 100644 --- a/README.md +++ b/README.md @@ -4,5 +4,4 @@ This is the frontend of a web wrapper for Coop Clouds abra CLI, letting users se ## Still a work in progess! -## This is built with react, typescript, scss, and vite - +## This is built with react, typescript, scss, and vite \ No newline at end of file diff --git a/src/assets/scss/_global.scss b/src/assets/scss/_global.scss index 9ee2cf2..9fbde7a 100644 --- a/src/assets/scss/_global.scss +++ b/src/assets/scss/_global.scss @@ -1,3 +1,6 @@ +@use './variables' as *; +@use './mixins' as *; + body { margin: 0; padding: 0; @@ -9,3 +12,262 @@ body { width: 100%; min-height: 100vh; } + +// global page layout styles +.page-wrapper { + min-height: 100vh; + background-color: $bg-secondary; +} + +.page-content { + max-width: 1600px; + margin: 0 auto; + padding: $spacing-2xl $spacing-xl; + + @media (max-width: 768px) { + padding: $spacing-xl $spacing-md; + } +} + +.page-header { + margin-bottom: $spacing-2xl; + + h1 { + font-size: $font-size-3xl; + margin: 0 0 $spacing-sm; + color: $text-primary; + } + + .subtitle { + font-size: $font-size-lg; + color: $text-secondary; + margin: 0; + } +} + +// global state styles +.loading, +.error { + text-align: center; + padding: $spacing-3xl; + font-size: $font-size-lg; +} + +.loading { + color: $text-secondary; +} + +.error { + color: $error; +} + +// Stats grid and cards +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: $spacing-lg; + margin-bottom: $spacing-2xl; +} + +.stat-card { + @include card; + display: flex; + align-items: center; + gap: $spacing-lg; + padding: $spacing-xl; + transition: transform $transition-base, box-shadow $transition-base; + + &:hover { + transform: translateY(-2px); + box-shadow: $shadow-lg; + } + + // Modifier classes for colored borders + &.upgrade { + border-left: 4px solid $primary-light; + } + + &.chaos { + border-left: 4px solid $primary-dark; + } + + &.primary { + border-left: 4px solid $primary; + } + + .stat-icon { + font-size: 2rem; + } + + .stat-info { + flex: 1; + + .stat-number { + font-size: $font-size-3xl; + font-weight: $font-weight-bold; + color: $text-primary; + margin: 0; + line-height: 1; + } + + .stat-label { + font-size: $font-size-sm; + color: $text-secondary; + margin: $spacing-xs 0 0; + text-transform: uppercase; + letter-spacing: 0.5px; + } + } +} + +// Filters component +.filters { + @include card; + display: flex; + gap: $spacing-md; + flex-wrap: wrap; + margin-bottom: $spacing-xl; + + @media (max-width: 768px) { + flex-direction: column; + } + + .search-input { + background-color: $bg-primary; + flex: 1; + min-width: 250px; + padding: $spacing-sm $spacing-md; + border: 2px solid $border-color; + border-radius: $radius-md; + font-size: $font-size-base; + transition: border-color $transition-base; + color: $text-primary; + + &::placeholder { + color: $text-muted; + } + + &:focus { + outline: none; + border-color: $primary; + } + } + + select { + padding: $spacing-sm $spacing-md; + border: 2px solid $border-color; + border-radius: $radius-md; + font-size: $font-size-base; + background-color: $bg-primary; + color: $text-primary; + cursor: pointer; + transition: border-color $transition-base; + + &:focus { + outline: none; + border-color: $primary; + } + } + + .checkbox-filter { + display: flex; + align-items: center; + gap: $spacing-sm; + cursor: pointer; + user-select: none; + + input[type="checkbox"] { + cursor: pointer; + width: 18px; + height: 18px; + } + + span { + font-size: $font-size-sm; + color: $text-primary; + } + } +} + +// Status badges +.status-badge { + display: inline-block; + padding: $spacing-xs $spacing-sm; + border-radius: $radius-full; + font-size: $font-size-xs; + font-weight: $font-weight-semibold; + text-transform: capitalize; + + &.status-deployed { + background-color: rgba($success, 0.1); + color: $success; + } + + &.status-stopped { + background-color: rgba($text-muted, 0.1); + color: $text-muted; + } + + &.status-error { + background-color: rgba($error, 0.1); + color: $error; + } +} + +// global badge styles +.recipe-badge, +.server-badge { + display: inline-block; + padding: $spacing-xs $spacing-sm; + border-radius: $radius-sm; + font-size: $font-size-sm; + font-weight: $font-weight-medium; +} + +.recipe-badge { + background-color: rgba($info, 0.1); + color: $info; +} + +.server-badge { + background-color: rgba($text-secondary, 0.1); + color: $text-secondary; +} + +// Results count +.results-count { + text-align: center; + color: $text-secondary; + font-size: $font-size-sm; + padding: $spacing-md; +} + +// No results message +.no-results { + @include card; + text-align: center; + padding: $spacing-3xl; + color: $text-secondary; + grid-column: 1 / -1; +} + +// Navigation link button (for clickable cards) +.nav-link { + all: unset; + cursor: pointer; + width: 100%; + display: block; + + &:focus-visible { + outline: 2px solid $primary; + outline-offset: 2px; + border-radius: $radius-md; + } +} + +.bland-button { + background: none; + border: none; + padding: 0; + margin: 0; +} diff --git a/src/assets/scss/_mixins.scss b/src/assets/scss/_mixins.scss index a280288..ab73615 100644 --- a/src/assets/scss/_mixins.scss +++ b/src/assets/scss/_mixins.scss @@ -45,7 +45,7 @@ // Gradient background @mixin gradient-primary { - background: linear-gradient(135deg, $primary 0%, $primary-dark 100%); + background: linear-gradient(135deg, $primary 0%, $primary-light 100%); } // Truncate text diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss index 5902d3c..0201eba 100644 --- a/src/assets/scss/_variables.scss +++ b/src/assets/scss/_variables.scss @@ -1,6 +1,7 @@ // Colors $primary: #EFEFEF; -$primary-dark: #ff4f88; +$primary-dark: #6A9CFF; +$primary-light: #ff4f88; $secondary: #363636; $success: #10b981; diff --git a/src/components/Header/_Header.scss b/src/components/Header/_Header.scss index 4de3fe8..9b8f02b 100644 --- a/src/components/Header/_Header.scss +++ b/src/components/Header/_Header.scss @@ -2,7 +2,7 @@ @use '../../assets/scss/mixins' as *; .layout-header { - background-color: $primary-dark; + background-color: $primary-light; color: $text-primary; padding: $spacing-lg 0; box-shadow: $shadow-lg; diff --git a/src/index.scss b/src/index.scss index 940ad45..f13b8e4 100644 --- a/src/index.scss +++ b/src/index.scss @@ -1,15 +1,18 @@ @use './assets/scss/variables' as *; @use './assets/scss/mixins' as *; +@use './assets/scss/global' as *; + +// Global root styles :root { line-height: 1.5; font-weight: 400; font-family: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', - 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', - 'Helvetica Neue', sans-serif; + 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', + 'Helvetica Neue', sans-serif; color-scheme: light dark; color: $text-primary; - background-color: $primary; + background-color: $bg-primary; font-synthesis: none; text-rendering: optimizeLegibility; @@ -17,13 +20,9 @@ -moz-osx-font-smoothing: grayscale; } -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; +// Global element resets +* { + box-sizing: border-box; } body { @@ -32,51 +31,63 @@ body { min-height: 100vh; } -h1 { - font-size: 3.2em; - line-height: 1.1; - font-family: 'Lora', serif; +// Global link styles +a { + font-weight: 500; + color: $primary; + text-decoration: none; + transition: color $transition-base; + + &:hover { + color: $primary-light; + } +} + +// Global heading styles +h1, h2, h3, h4, h5, h6 { color: $text-primary; + margin: 0; } +h1 { + font-size: $font-size-3xl; + line-height: 1.1; +} + +h2 { + font-size: $font-size-2xl; + line-height: 1.2; +} + +h3 { + font-size: $font-size-xl; + line-height: 1.3; +} + +// Global button styles button { - border-radius: 8px; + border-radius: $radius-md; border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; + padding: $spacing-sm $spacing-lg; + font-size: $font-size-base; + font-weight: $font-weight-medium; font-family: inherit; - background-color: $primary-dark; + background-color: $primary; + color: white; cursor: pointer; - transition: border-color 0.25s; -} -.bland-button{ - border-radius: 8px; - border: 0px; - padding: 0em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} + transition: all $transition-base; -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: $primary; + &:hover { + background-color: $primary-light; } - a:hover { - color: #747bff; + + &:focus-visible { + outline: 2px solid $primary; + outline-offset: 2px; } - button { - background-color: $primary; + + &:disabled { + opacity: 0.5; + cursor: not-allowed; } } diff --git a/src/routes/Authenticated/Apps/App.scss b/src/routes/Authenticated/Apps/App.scss index a43aa8a..17a4c7a 100644 --- a/src/routes/Authenticated/Apps/App.scss +++ b/src/routes/Authenticated/Apps/App.scss @@ -253,7 +253,7 @@ } .domain-link { - color: #0066cc; + color: $primary-dark; text-decoration: none; font-size: 14px; diff --git a/src/routes/Authenticated/Apps/Apps.scss b/src/routes/Authenticated/Apps/Apps.scss index c32afa4..b1fdd1c 100644 --- a/src/routes/Authenticated/Apps/Apps.scss +++ b/src/routes/Authenticated/Apps/Apps.scss @@ -1,149 +1,17 @@ @use '../../../assets/scss/variables' as *; @use '../../../assets/scss/mixins' as *; +@use '../../../assets/scss/global' as *; +// Extend global page wrapper .apps-page { - min-height: 100vh; - background-color: $bg-secondary; + @extend .page-wrapper; } .apps-content { - max-width: 1600px; - margin: 0 auto; - padding: $spacing-2xl $spacing-xl; - - @media (max-width: 768px) { - padding: $spacing-xl $spacing-md; - } -} - -.page-header { - margin-bottom: $spacing-2xl; - - h1 { - font-size: $font-size-3xl; - margin: 0 0 $spacing-sm; - color: $text-primary; - } - - .subtitle { - font-size: $font-size-lg; - color: $text-secondary; - margin: 0; - } -} - -.stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: $spacing-lg; - margin-bottom: $spacing-2xl; -} - -.stat-card { - @include card; - display: flex; - align-items: center; - gap: $spacing-lg; - padding: $spacing-xl; - transition: transform $transition-base, box-shadow $transition-base; - - &:hover { - transform: translateY(-2px); - box-shadow: $shadow-lg; - } - - &.upgrade { - border-left: 4px solid $warning; - } - - &.chaos { - border-left: 4px solid $info; - } - - .stat-icon { - font-size: 2rem; - } - - .stat-info { - .stat-number { - font-size: $font-size-3xl; - font-weight: $font-weight-bold; - color: $text-primary; - margin: 0; - line-height: 1; - } - - .stat-label { - font-size: $font-size-sm; - color: $text-secondary; - margin: $spacing-xs 0 0; - text-transform: uppercase; - letter-spacing: 0.5px; - } - } -} - -.filters { - @include card; - display: flex; - gap: $spacing-md; - flex-wrap: wrap; - margin-bottom: $spacing-xl; - - @media (max-width: 768px) { - flex-direction: column; - } - - .search-input { - flex: 1; - min-width: 250px; - padding: $spacing-sm $spacing-md; - border: 2px solid $border-color; - border-radius: $radius-md; - font-size: $font-size-base; - transition: border-color $transition-base; - - &:focus { - outline: none; - border-color: $primary; - } - } - - select { - padding: $spacing-sm $spacing-md; - border: 2px solid $border-color; - border-radius: $radius-md; - font-size: $font-size-base; - background-color: white; - cursor: pointer; - transition: border-color $transition-base; - - &:focus { - outline: none; - border-color: $primary; - } - } - - .checkbox-filter { - display: flex; - align-items: center; - gap: $spacing-sm; - cursor: pointer; - user-select: none; - - input[type="checkbox"] { - cursor: pointer; - width: 18px; - height: 18px; - } - - span { - font-size: $font-size-sm; - color: $text-primary; - } - } + @extend .page-content; } +// Apps table specific styles .apps-table-container { @include card; overflow-x: auto; @@ -197,6 +65,7 @@ } } +// App table cell styles .app-name-cell { .app-name { font-weight: $font-weight-medium; @@ -204,39 +73,20 @@ } } -.recipe-badge { - display: inline-block; - padding: $spacing-xs $spacing-sm; - background-color: rgba($info, 0.1); - // color: darken($info, 20%); - border-radius: $radius-sm; - font-size: $font-size-sm; - font-weight: $font-weight-medium; -} - .domain-link { color: $primary; text-decoration: none; transition: color $transition-base; &:hover { - color: $primary-dark; + color: $primary-light; text-decoration: underline; } } .no-domain { color: $text-muted; -} - -.server-badge { - display: inline-block; - padding: $spacing-xs $spacing-sm; - background-color: rgba($text-secondary, 0.1); - color: $text-secondary; - border-radius: $radius-sm; - font-size: $font-size-sm; - font-weight: $font-weight-medium; + font-style: italic; } .version-cell { @@ -247,6 +97,7 @@ .version { font-family: monospace; font-size: $font-size-sm; + color: $text-primary; } .chaos-badge, @@ -255,40 +106,19 @@ } } -.status-badge { - display: inline-block; - padding: $spacing-xs $spacing-sm; - border-radius: $radius-full; - font-size: $font-size-xs; - font-weight: $font-weight-semibold; - text-transform: capitalize; - - &.status-deployed { - background-color: rgba($success, 0.1); - // color: darken($success, 20%); - } - - &.status-stopped { - background-color: rgba($text-muted, 0.1); - color: $text-muted; - } - - &.status-error { - background-color: rgba($error, 0.1); - // color: darken($error, 10%); - } -} - +// Action buttons .actions { display: flex; gap: $spacing-sm; .action-btn { + background: none; border: 1px solid $border-color; padding: $spacing-xs $spacing-sm; border-radius: $radius-sm; cursor: pointer; font-size: $font-size-base; + color: $text-primary; transition: all $transition-base; &:hover { @@ -298,28 +128,7 @@ &.upgrade { border-color: $warning; + color: $warning; } } } - -.results-count { - text-align: center; - color: $text-secondary; - font-size: $font-size-sm; - padding: $spacing-md; -} - -.loading, -.error { - text-align: center; - padding: $spacing-3xl; - font-size: $font-size-lg; -} - -.loading { - color: $text-secondary; -} - -.error { - color: $error; -} \ No newline at end of file diff --git a/src/routes/Authenticated/Dashboard/Dashboard.tsx b/src/routes/Authenticated/Dashboard/Dashboard.tsx index 96b3317..3788542 100644 --- a/src/routes/Authenticated/Dashboard/Dashboard.tsx +++ b/src/routes/Authenticated/Dashboard/Dashboard.tsx @@ -51,6 +51,10 @@ export const Dashboard: React.FC = () => { fetchData(); }, [isMockMode]); + // Calculate stats + const deployedAppsCount = apps.filter(a => a.status === 'deployed').length; + const serversWithAppsCount = new Set(apps.map(a => a.server)).size; + if (loading) { return (
@@ -77,7 +81,9 @@ export const Dashboard: React.FC = () => {
-

Dashboard

+
+

Dashboard

+
@@ -95,7 +101,7 @@ export const Dashboard: React.FC = () => {

Servers

{servers.length}

- {servers.length} connected + {serversWithAppsCount} connected

@@ -105,7 +111,11 @@ export const Dashboard: React.FC = () => {

Recent Applications

{apps.slice(0, 5).map((app, index) => ( -
navigate(`/apps/${app.server}/${app.appName}`)}> +
navigate(`/apps/${app.server}/${app.appName}`)} + >

{app.appName}

{app.domain || 'No domain'}

@@ -121,4 +131,4 @@ export const Dashboard: React.FC = () => {
); -}; \ No newline at end of file +}; diff --git a/src/routes/Authenticated/Dashboard/_Dashboard.scss b/src/routes/Authenticated/Dashboard/_Dashboard.scss index e6e8130..8032066 100644 --- a/src/routes/Authenticated/Dashboard/_Dashboard.scss +++ b/src/routes/Authenticated/Dashboard/_Dashboard.scss @@ -1,83 +1,23 @@ @use '../../../assets/scss/variables' as *; @use '../../../assets/scss/mixins' as *; +@use '../../../assets/scss/global' as *; +// Extend global page wrapper .dashboard-page { - min-height: 100vh; - background-color: $bg-secondary; + @extend .page-wrapper; } .dashboard-content { - max-width: 1400px; - margin: 0 auto; - padding: $spacing-2xl $spacing-xl; - - @media (max-width: 768px) { - padding: $spacing-xl $spacing-md; - } - - h2 { - margin: 0 0 $spacing-2xl; - font-size: $font-size-3xl; - color: $text-primary; - } -} - -.loading, .error { - text-align: center; - padding: $spacing-3xl; - font-size: $font-size-lg; - color: $text-secondary; -} - -.error { - color: $error; -} - -.stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: $spacing-lg; - margin-bottom: $spacing-2xl; -} - -.stat-card { - @include card; - border-left: 4px solid $primary; - transition: transform $transition-base, box-shadow $transition-base; - - &:hover { - transform: translateY(-2px); - box-shadow: $shadow-lg; - } - - h3 { - margin: 0 0 $spacing-md; - color: $text-secondary; - font-size: $font-size-sm; - text-transform: uppercase; - letter-spacing: 0.5px; - font-weight: $font-weight-semibold; - } - - .stat-number { - margin: 0 0 $spacing-sm; - font-size: $font-size-3xl; - font-weight: $font-weight-bold; - color: $text-primary; - line-height: 1; - } - - .stat-label { - margin: 0; - color: $text-muted; - font-size: $font-size-sm; - } + @extend .page-content; } +// Dashboard-specific styles .recent-apps { + margin-bottom: $spacing-2xl; + h3 { - margin: 0 0 $spacing-lg; font-size: $font-size-2xl; + margin: 0 0 $spacing-lg; color: $text-primary; } } @@ -90,19 +30,20 @@ .app-item { @include card; - padding: $spacing-lg; display: flex; justify-content: space-between; align-items: center; transition: transform $transition-base, box-shadow $transition-base; + cursor: pointer; &:hover { transform: translateY(-2px); box-shadow: $shadow-lg; - cursor: pointer; } .app-info { + flex: 1; + h4 { margin: 0 0 $spacing-xs; font-size: $font-size-lg; @@ -111,26 +52,16 @@ } .app-domain { - margin: 0; + margin: 0 0 $spacing-xs; color: $text-muted; font-size: $font-size-sm; } - } - .status-badge { - @include status-badge($success); - text-transform: capitalize; - - &.status-running { - @include status-badge($success); - } - - &.status-stopped { - @include status-badge($text-muted); - } - - &.status-error { - @include status-badge($error); + .app-server { + margin: 0; + font-size: $font-size-sm; + color: $text-secondary; + font-family: monospace; } } -} \ No newline at end of file +} diff --git a/src/routes/Authenticated/Servers/Server.scss b/src/routes/Authenticated/Servers/Server.scss index 08560b7..aba923f 100644 --- a/src/routes/Authenticated/Servers/Server.scss +++ b/src/routes/Authenticated/Servers/Server.scss @@ -50,7 +50,7 @@ transition: color $transition-base; &:hover { - color: $primary-dark; + color: $primary-light; text-decoration: underline; } } @@ -128,8 +128,8 @@ border-color: $primary; &:hover:not(:disabled) { - background: $primary-dark; - border-color: $primary-dark; + background: $primary-light; + border-color: $primary-light; } } @@ -189,7 +189,7 @@ display: inline-block; padding: $spacing-xs $spacing-sm; background: rgba($primary, 0.1); - color: $primary-dark; + color: $primary-light; border-radius: $radius-sm; font-size: $font-size-xs; font-weight: $font-weight-medium; diff --git a/src/routes/Authenticated/Servers/Servers.scss b/src/routes/Authenticated/Servers/Servers.scss index a4577f9..d7224ae 100644 --- a/src/routes/Authenticated/Servers/Servers.scss +++ b/src/routes/Authenticated/Servers/Servers.scss @@ -1,130 +1,17 @@ @use '../../../assets/scss/variables' as *; @use '../../../assets/scss/mixins' as *; +@use '../../../assets/scss/global' as *; +// Extend global page wrapper .servers-page { - min-height: 100vh; - background-color: $bg-secondary; + @extend .page-wrapper; } .servers-content { - max-width: 1600px; - margin: 0 auto; - padding: $spacing-2xl $spacing-xl; - - @media (max-width: 768px) { - padding: $spacing-xl $spacing-md; - } -} - -.page-header { - margin-bottom: $spacing-2xl; - - h1 { - font-size: $font-size-3xl; - margin: 0 0 $spacing-sm; - color: $text-primary; - } - - .subtitle { - font-size: $font-size-lg; - color: $text-secondary; - margin: 0; - } -} - -.stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: $spacing-lg; - margin-bottom: $spacing-2xl; -} - -.stat-card { - @include card; - display: flex; - align-items: center; - gap: $spacing-lg; - padding: $spacing-xl; - transition: transform $transition-base, box-shadow $transition-base; - - &:hover { - transform: translateY(-2px); - box-shadow: $shadow-lg; - } - - &.upgrade { - border-left: 4px solid $warning; - } - - &.chaos { - border-left: 4px solid $info; - } - - .stat-icon { - font-size: 2rem; - } - - .stat-info { - .stat-number { - font-size: $font-size-3xl; - font-weight: $font-weight-bold; - color: $text-primary; - margin: 0; - line-height: 1; - } - - .stat-label { - font-size: $font-size-sm; - color: $text-secondary; - margin: $spacing-xs 0 0; - text-transform: uppercase; - letter-spacing: 0.5px; - } - } -} - -.filters { - @include card; - display: flex; - gap: $spacing-md; - flex-wrap: wrap; - margin-bottom: $spacing-xl; - - @media (max-width: 768px) { - flex-direction: column; - } - - .search-input { - flex: 1; - min-width: 250px; - padding: $spacing-sm $spacing-md; - border: 2px solid $border-color; - border-radius: $radius-md; - font-size: $font-size-base; - transition: border-color $transition-base; - - &:focus { - outline: none; - border-color: $primary; - } - } - - select { - padding: $spacing-sm $spacing-md; - border: 2px solid $border-color; - border-radius: $radius-md; - font-size: $font-size-base; - background-color: white; - cursor: pointer; - transition: border-color $transition-base; - - &:focus { - outline: none; - border-color: $primary; - } - } + @extend .page-content; } +// Servers grid .servers-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); @@ -136,6 +23,7 @@ } } +// Server card .server-card { @include card; display: flex; @@ -202,6 +90,7 @@ border-bottom: none; } + // Highlighted rows &.highlight { background-color: rgba($warning, 0.05); padding: $spacing-sm $spacing-md; @@ -211,12 +100,10 @@ border-bottom: none; .stat-label { - // color: darken($warning, 10%); font-weight: $font-weight-semibold; } .stat-value { - // color: darken($warning, 10%); font-weight: $font-weight-bold; } } @@ -229,12 +116,10 @@ padding-right: calc($spacing-xl + $spacing-md); .stat-label { - // color: darken($info, 10%); font-weight: $font-weight-semibold; } .stat-value { - // color: darken($info, 10%); font-weight: $font-weight-bold; } } @@ -269,6 +154,7 @@ flex: 1; padding: $spacing-sm $spacing-md; border: 2px solid $border-color; + background: none; color: $text-primary; border-radius: $radius-md; font-size: $font-size-sm; @@ -277,17 +163,19 @@ transition: all $transition-base; &:hover { - background-color: $primary-dark; + background-color: rgba($primary, 0.1); + border-color: $primary; transform: translateY(-1px); } &.primary { + background-color: $primary; color: white; border-color: $primary; &:hover { - background-color: $primary-dark; - border-color: $primary-dark; + background-color: $primary-light; + border-color: $primary-light; } } } @@ -304,42 +192,13 @@ .alert-icon { font-size: $font-size-lg; + color: $warning; } .alert-text { font-size: $font-size-sm; - // color: darken($warning, 20%); + color: $text-primary; font-weight: $font-weight-medium; } } } - -.no-results { - @include card; - text-align: center; - padding: $spacing-3xl; - color: $text-secondary; - grid-column: 1 / -1; -} - -.results-count { - text-align: center; - color: $text-secondary; - font-size: $font-size-sm; - padding: $spacing-md; -} - -.loading, -.error { - text-align: center; - padding: $spacing-3xl; - font-size: $font-size-lg; -} - -.loading { - color: $text-secondary; -} - -.error { - color: $error; -} \ No newline at end of file diff --git a/src/routes/Login/LoginForm.scss b/src/routes/Login/LoginForm.scss index 2b7580a..90e259b 100644 --- a/src/routes/Login/LoginForm.scss +++ b/src/routes/Login/LoginForm.scss @@ -6,7 +6,7 @@ min-height: 100vh; width: 100%; // @include gradient-primary; - background-color: $primary-dark; + background-color: $primary-light; position: fixed; top: 0; left: 0; diff --git a/src/services/example abra app ls.json b/src/services/mock-apps.json similarity index 100% rename from src/services/example abra app ls.json rename to src/services/mock-apps.json diff --git a/src/services/example abra server ls.json b/src/services/mock-servers.json similarity index 100% rename from src/services/example abra server ls.json rename to src/services/mock-servers.json diff --git a/src/services/mockApi.ts b/src/services/mockApi.ts index 0d12c80..7e52479 100644 --- a/src/services/mockApi.ts +++ b/src/services/mockApi.ts @@ -1,150 +1,6 @@ - import type { AbraServer, ServerAppsResponse } from '../types'; - -// Mock data matching real API structure -export const mockAppsData: ServerAppsResponse = { - "mydomain.com": { - apps: [ - { - server: "mydomain.com", - recipe: "nextcloud", - appName: "nc.mydomain.com", - domain: "nc.mydomain.com", - status: "deployed", - chaos: "false", - chaosVersion: "unknown", - version: "12.0.1+31.0.6-fpm", - upgrade: "latest" - }, - { - server: "mydomain.com", - recipe: "traefik", - appName: "traefik.mydomain.com", - domain: "traefik.mydomain.com", - status: "deployed", - chaos: "false", - chaosVersion: "unknown", - version: "3.4.2+v3.4.5", - upgrade: "3.6.2+v3.4.5\n3.6.1+v3.4.5" - }, - { - server: "mydomain.com", - recipe: "authentik", - appName: "accounts.mydomain.com", - domain: "accounts.mydomain.com", - status: "deployed", - chaos: "false", - chaosVersion: "unknown", - version: "7.4.0+2025.6.3", - upgrade: "9.0.1+2025.8.1\n9.0.0+2025.8.1\n8.0.0+2025.8.1\n7.4.1+2025.6.4" - }, - { - server: "mydomain.com", - recipe: "backup-bot-two", - appName: "backup.mydomain.com", - domain: "", - status: "deployed", - chaos: "false", - chaosVersion: "2.3.0+2.3.0-beta", - version: "2.3.0+2.3.0-beta", - upgrade: "latest" - }, - { - server: "mydomain.com", - recipe: "collabora", - appName: "docs.mydomain.com", - domain: "docs.mydomain.com", - status: "deployed", - chaos: "false", - chaosVersion: "3.2.0+24.04.12.3.1", - version: "3.2.0+24.04.12.3.1", - upgrade: "4.0.0+25.04.4.1.1\n3.3.0+24.04.13.3.1" - }, - { - server: "myotherdomain.com", - recipe: "traefik", - appName: "traefik.myotherdomain.com", - domain: "traefik.myotherdomain.com", - status: "deployed", - chaos: "false", - chaosVersion: "unknown", - version: "3.4.2+v3.4.5", - upgrade: "3.6.2+v3.4.5\n3.6.1+v3.4.5\n3.6.0+v3.4.5\n3.5.0+v3.4.5" - } - ], - appCount: 3, - versionCount: 3, - unversionedCount: 0, - latestCount: 1, - upgradeCount: 2 - }, - "test.coop": { - apps: [ - { - server: "test.coop", - recipe: "cryptpad", - appName: "cryptpad.test.coop", - domain: "cryptpad.test.coop", - status: "deployed", - chaos: "true", - chaosVersion: "cb2a47fb", - version: "0.4.0+version-2024.3.0", - upgrade: "latest" - }, - { - server: "test.coop", - recipe: "mobilizon", - appName: "events.test.coop", - domain: "events.test.coop", - status: "deployed", - chaos: "true", - chaosVersion: "f8f874a5", - version: "0.2.1+5.1.2", - upgrade: "latest" - } - ], - appCount: 2, - versionCount: 2, - unversionedCount: 0, - latestCount: 2, - upgradeCount: 0 - } -}; - -export const mockServers: AbraServer[] = [ - { - name: 'test.coop', - host: 'test.coop', - }, - { - "host": "mydomain.com", - "name": "mydomain.com" - }, - { - "host": "coop.test.org", - "name": "coop.test.org" - }, - { - "host": "internal.website.com", - "name": "internal.website.com" - }, - { - "host": "internal.server.net", - "name": "internal.server.net" - }, - { - "host": "internal.intranet.site.com", - "name": "internal.intranet.site.com" - }, - { - "host": "internal.test.org", - "name": "internal.test.org" - }, - { - "host": "orgsite.org", - "name": "orgsite.org" - } -]; +import appsData from './mock-apps.json'; +import serversData from './mock-servers.json'; // Simulate API delay const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); @@ -152,12 +8,12 @@ const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); export const mockApiService = { async getAppsGrouped(): Promise { await delay(500); - return mockAppsData; + return appsData as ServerAppsResponse; }, async getServers(): Promise { await delay(300); - return mockServers; + return serversData as AbraServer[]; }, async deployApp(appName: string): Promise { diff --git a/src/types/index.ts b/src/types/index.ts index 3b9a88b..a3ab2ac 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -24,7 +24,7 @@ export interface AbraApp { recipe: string; appName: string; domain: string; - status: string; + status: 'deployed' | 'stopped' | 'unknown'; chaos: string; chaosVersion: string; version: string;