mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
Overhaul: real metrics, Git integration UI, open-source hygiene, root cleanup
Backend: - GET /services/:id/metrics with real Docker container stats - DELETE /git/providers/:id and GET repo branches endpoint Frontend: - Service detail shows real telemetry or honest empty states - Live status distinguishes idle/polling/reconnecting - Git providers section in Settings; repo+branch pickers in Add Service - Real logo, compact Projects header, canvas fitView fix - index.css deduplicated (1725 -> 1384 lines) - Fixed smoke tests, lint errors, ToastProvider/context unification Repo hygiene: - Added LICENSE (MIT), CONTRIBUTING.md, SECURITY.md; rewrote README - Untracked .env.prod and data/letsencrypt secrets; fixed .gitignore - Removed legacy root src/internal/cmd and stale configs/docs/artifacts - Moved guides and design references under docs/ Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
355a97bab4
commit
9f3b196032
499 files changed
+4471
-94235
No files matched your search
+77
-351
@@ -84,6 +84,76 @@
|
||||
--bg-0: var(--bg-void);
|
||||
--bg-1: var(--bg-base);
|
||||
--bg-2: var(--bg-surface);
|
||||
--bg-primary: var(--bg-base);
|
||||
}
|
||||
|
||||
:root[data-theme='light'] {
|
||||
--bg-void: #f4f6fb;
|
||||
--bg-base: #ffffff;
|
||||
--bg-surface: #eef1f7;
|
||||
--bg-elevated: #ffffff;
|
||||
--bg-overlay: #ffffff;
|
||||
|
||||
--surface-card: #ffffff;
|
||||
--surface-card-hover: #eef1f7;
|
||||
--surface-muted: rgba(17, 18, 23, 0.05);
|
||||
--surface-glass: rgba(255, 255, 255, 0.72);
|
||||
--surface-base: #ffffff;
|
||||
|
||||
--text-primary: #151821;
|
||||
--text-secondary: #4f5668;
|
||||
--text-tertiary: #7b8498;
|
||||
--text-muted: #7b8498;
|
||||
|
||||
--accent-primary: #d92d64;
|
||||
--accent-primary-soft: rgba(217, 45, 100, 0.12);
|
||||
--accent-primary-glow: rgba(217, 45, 100, 0.22);
|
||||
--accent-secondary: #7357d8;
|
||||
--accent-tertiary: #2f67d8;
|
||||
|
||||
--success: #168a55;
|
||||
--success-soft: rgba(22, 138, 85, 0.12);
|
||||
--success-glow: rgba(22, 138, 85, 0.2);
|
||||
|
||||
--warning: #c7511f;
|
||||
--warning-soft: rgba(199, 81, 31, 0.12);
|
||||
--warning-glow: rgba(199, 81, 31, 0.2);
|
||||
|
||||
--error: #c9362b;
|
||||
--error-soft: rgba(201, 54, 43, 0.12);
|
||||
--error-glow: rgba(201, 54, 43, 0.2);
|
||||
|
||||
--info: #2f67d8;
|
||||
--info-soft: rgba(47, 103, 216, 0.12);
|
||||
|
||||
--border-subtle: rgba(21, 24, 33, 0.1);
|
||||
--border-default: rgba(21, 24, 33, 0.16);
|
||||
--border-strong: rgba(217, 45, 100, 0.35);
|
||||
--border-glow: rgba(217, 45, 100, 0.45);
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(17, 18, 23, 0.08);
|
||||
--shadow-md: 0 4px 12px rgba(17, 18, 23, 0.1);
|
||||
--shadow-lg: 0 8px 30px rgba(17, 18, 23, 0.12);
|
||||
--shadow-xl: 0 16px 48px rgba(17, 18, 23, 0.16);
|
||||
--shadow-glow: 0 0 20px var(--accent-primary-glow);
|
||||
--shadow-glow-lg: 0 0 40px var(--accent-primary-glow);
|
||||
|
||||
--text: var(--text-primary);
|
||||
--text-dim: var(--text-secondary);
|
||||
--line: var(--border-default);
|
||||
--line-strong: var(--border-strong);
|
||||
--accent: var(--accent-primary);
|
||||
--accent-soft: var(--accent-primary-soft);
|
||||
--ok: var(--success);
|
||||
--warn: var(--warning);
|
||||
--bad: var(--error);
|
||||
--surface: var(--bg-elevated);
|
||||
--surface-soft: var(--surface-card);
|
||||
--surface-muted: var(--bg-surface);
|
||||
--bg-0: var(--bg-void);
|
||||
--bg-1: var(--bg-base);
|
||||
--bg-2: var(--bg-surface);
|
||||
--bg-primary: var(--bg-base);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -100,7 +170,7 @@ body,
|
||||
body {
|
||||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||
color: var(--text-primary);
|
||||
background: #16171c;
|
||||
background: var(--bg-void);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -115,7 +185,7 @@ body {
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
background: #16171c;
|
||||
background: var(--bg-void);
|
||||
}
|
||||
|
||||
/* Ambient glow effects for premium depth */
|
||||
@@ -162,56 +232,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutRight {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Animations from self.html */
|
||||
@keyframes fadeUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(12px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Live pulse animation for status indicators */
|
||||
@keyframes livePulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
|
||||
.live-pulse {
|
||||
animation: livePulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Subtle glow pulse for active elements */
|
||||
@keyframes glowPulse {
|
||||
0%, 100% {
|
||||
@@ -226,22 +246,6 @@ body {
|
||||
animation: glowPulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Slide in from right - for toasts and modals */
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-slide-in-right {
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* Fade in scale - for modals and overlays */
|
||||
@keyframes fadeInScale {
|
||||
from {
|
||||
@@ -270,28 +274,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutRight {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
@@ -365,177 +347,6 @@ textarea {
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* Card icon - matching self.html */
|
||||
.card-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.card-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
stroke: #9295a4;
|
||||
fill: none;
|
||||
stroke-width: 1.8;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* Arrow button - matching self.html */
|
||||
.arrow-btn {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 9px;
|
||||
background: #e8316a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: box-shadow 0.15s, transform 0.15s;
|
||||
}
|
||||
|
||||
.arrow-btn:hover {
|
||||
transform: scale(1.07);
|
||||
}
|
||||
|
||||
.arrow-btn svg {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
stroke: white;
|
||||
fill: none;
|
||||
stroke-width: 2.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* Pill group - matching self.html */
|
||||
.pill-group {
|
||||
display: flex;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pill {
|
||||
padding: 5px 14px;
|
||||
font-size: 12.5px;
|
||||
font-weight: 500;
|
||||
color: #6b6e7d;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pill.active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #e8e9f0;
|
||||
}
|
||||
|
||||
.pill:hover:not(.active) {
|
||||
color: #9295a4;
|
||||
}
|
||||
|
||||
/* Flag - matching self.html */
|
||||
.flag {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* Stat dot - matching self.html */
|
||||
.stat-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Cache segment - matching self.html */
|
||||
.cache-seg {
|
||||
height: 32px;
|
||||
transition: opacity 0.2s, filter 0.2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cache-seg:hover {
|
||||
filter: brightness(1.15);
|
||||
}
|
||||
|
||||
/* Speed row - matching self.html */
|
||||
.speed-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.speed-row svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke: currentColor;
|
||||
fill: none;
|
||||
stroke-width: 2.5;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
/* Live indicator - matching self.html */
|
||||
.live-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #3dd68c;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 6px;
|
||||
animation: pulse-dot 2s infinite;
|
||||
}
|
||||
|
||||
.live-dot.stopped {
|
||||
background: #6b6e7d;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
/* Badge - matching self.html */
|
||||
.badge-active {
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(61, 214, 140, 0.15);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.7px;
|
||||
color: #3dd68c;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.3s;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.badge-stopped {
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.7px;
|
||||
color: #6b6e7d;
|
||||
text-transform: uppercase;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Subtle grid background - Railway-style dots */
|
||||
.subtle-grid {
|
||||
background-image:
|
||||
@@ -589,18 +400,7 @@ textarea {
|
||||
100% { transform: scale(2); opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes pulse-dot {
|
||||
0% { box-shadow: 0 0 0 0 rgba(61, 214, 140, 0.7); }
|
||||
70% { box-shadow: 0 0 0 6px rgba(61, 214, 140, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(61, 214, 140, 0); }
|
||||
}
|
||||
|
||||
/* Card animations - matching self.html */
|
||||
@keyframes fadeUp {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.animate-fade-up {
|
||||
animation: fadeUp 0.4s ease both;
|
||||
}
|
||||
@@ -718,17 +518,6 @@ textarea {
|
||||
100% { background-position: 200% 0; }
|
||||
}
|
||||
|
||||
.shimmer {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0.03) 25%,
|
||||
rgba(255, 255, 255, 0.08) 50%,
|
||||
rgba(255, 255, 255, 0.03) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
/* Hover lift effect for cards */
|
||||
.hover-lift {
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
@@ -778,18 +567,6 @@ textarea {
|
||||
animation: gradient-rotate 3s ease infinite;
|
||||
}
|
||||
|
||||
/* Ripple effect for buttons */
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ripple-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -1073,8 +850,8 @@ textarea {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: 10px;
|
||||
padding: 0 12px;
|
||||
height: 34px;
|
||||
@@ -1084,7 +861,7 @@ textarea {
|
||||
.search-box svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
stroke: #6b6e7d;
|
||||
stroke: var(--text-tertiary);
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
@@ -1095,14 +872,14 @@ textarea {
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: #9295a4;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
width: 100%;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.search-box input::placeholder {
|
||||
color: #6b6e7d;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
/* Tab - self.html exact match */
|
||||
@@ -1172,47 +949,6 @@ textarea {
|
||||
color: #9295a4;
|
||||
}
|
||||
|
||||
/* Arrow Button - self.html style (pink circular) */
|
||||
.arrow-btn {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 9px;
|
||||
background: var(--accent-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: box-shadow 0.15s, transform 0.15s;
|
||||
}
|
||||
|
||||
.arrow-btn:hover {
|
||||
transform: scale(1.07);
|
||||
}
|
||||
|
||||
.arrow-btn svg {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
stroke: white;
|
||||
fill: none;
|
||||
stroke-width: 2.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* Live Dot Pulse - self.html style */
|
||||
@keyframes pulse-dot {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(61, 214, 140, 0.7);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 6px rgba(61, 214, 140, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(61, 214, 140, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.live-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
@@ -1489,16 +1225,6 @@ textarea {
|
||||
animation: ripple 0.4s ease-out;
|
||||
}
|
||||
|
||||
/* Shimmer loading effect */
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
.shimmer {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
|
||||
Reference in new issue
Block a user