diff --git a/frontend/src/App.css b/frontend/src/App.css new file mode 100644 index 0000000..2eebdde --- /dev/null +++ b/frontend/src/App.css @@ -0,0 +1,557 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --color-primary: #2563eb; + --color-secondary: #64748b; + --color-success: #10b981; + --color-danger: #ef4444; + --color-warning: #f59e0b; + --color-bg-dark: #0f172a; + --color-bg-light: #f8fafc; + --color-border: #e2e8f0; + --color-text-dark: #1e293b; + --color-text-light: #64748b; + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + --spacing-xs: 4px; + --spacing-sm: 8px; + --spacing-md: 16px; + --spacing-lg: 24px; + --spacing-xl: 32px; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + background-color: var(--color-bg-light); + color: var(--color-text-dark); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* App Layout */ +.app-container { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: var(--color-bg-light); +} + +.app-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-lg); + background: linear-gradient(135deg, var(--color-primary) 0%, #1d4ed8 100%); + color: white; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.header-content h1 { + font-size: 1.75rem; + font-weight: 700; + margin-bottom: var(--spacing-xs); +} + +.header-content p { + font-size: 0.875rem; + opacity: 0.9; +} + +.system-status { + display: flex; + align-items: center; + gap: var(--spacing-md); + font-size: 0.875rem; +} + +.status-indicator { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: rgba(255, 255, 255, 0.3); +} + +.status-indicator.running { + background-color: #10b981; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0% { + opacity: 1; + } + 50% { + opacity: 0.5; + } + 100% { + opacity: 1; + } +} + +/* Main Content */ +.app-main { + display: flex; + flex: 1; + overflow: hidden; + gap: 1px; + background: var(--color-border); +} + +.sidebar { + width: 320px; + background: white; + border-right: 1px solid var(--color-border); + overflow-y: auto; + padding: var(--spacing-lg); + display: flex; + flex-direction: column; + gap: var(--spacing-md); +} + +.btn { + padding: var(--spacing-md) var(--spacing-lg); + border: none; + border-radius: var(--radius-md); + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: var(--spacing-sm); +} + +.btn-primary { + background: var(--color-primary); + color: white; +} + +.btn-primary:hover { + background: #1d4ed8; + box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3); +} + +.btn-secondary { + background: var(--color-secondary); + color: white; +} + +.btn-secondary:hover { + background: #475569; +} + +.btn-success { + background: var(--color-success); + color: white; +} + +.btn-success:hover { + background: #059669; +} + +.btn-danger { + background: var(--color-danger); + color: white; +} + +.btn-danger:hover { + background: #dc2626; +} + +.btn-create { + width: 100%; + justify-content: center; + font-size: 1rem; +} + +.btn:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.tasks-list { + flex: 1; + overflow-y: auto; +} + +.tasks-list h2 { + font-size: 0.875rem; + font-weight: 700; + text-transform: uppercase; + color: var(--color-text-light); + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-lg); +} + +.task-item { + padding: var(--spacing-md); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + cursor: pointer; + transition: all 0.2s ease; + margin-bottom: var(--spacing-sm); +} + +.task-item:hover { + border-color: var(--color-primary); + background: rgba(37, 99, 235, 0.03); +} + +.task-item.active { + border-color: var(--color-primary); + background: rgba(37, 99, 235, 0.08); +} + +.task-item-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: var(--spacing-md); + margin-bottom: var(--spacing-sm); +} + +.task-item h3 { + font-size: 0.875rem; + font-weight: 600; + flex: 1; +} + +.status-badge { + padding: 2px 8px; + border-radius: var(--radius-sm); + color: white; + font-size: 0.75rem; + font-weight: 600; + text-transform: capitalize; + white-space: nowrap; +} + +.task-schedule { + font-size: 0.75rem; + color: var(--color-text-light); + margin-bottom: 4px; +} + +.task-last-run { + font-size: 0.75rem; + color: var(--color-text-light); +} + +.empty-state { + padding: var(--spacing-lg); + text-align: center; + color: var(--color-text-light); + font-size: 0.875rem; +} + +/* Content Area */ +.content { + flex: 1; + overflow-y: auto; + background: white; + padding: var(--spacing-xl); +} + +.form-container { + max-width: 600px; +} + +.form-container h2 { + font-size: 1.5rem; + margin-bottom: var(--spacing-lg); +} + +.task-form { + display: flex; + flex-direction: column; + gap: var(--spacing-lg); +} + +.form-group { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); +} + +.form-group label { + font-weight: 600; + font-size: 0.875rem; + color: var(--color-text-dark); +} + +.form-group input, +.form-group textarea, +.form-group select { + padding: var(--spacing-md); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + font-size: 0.875rem; + font-family: inherit; + transition: border-color 0.2s; +} + +.form-group input:focus, +.form-group textarea:focus, +.form-group select:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-lg); +} + +.form-group.checkbox { + flex-direction: row; + align-items: center; + gap: var(--spacing-md); +} + +.form-group.checkbox input { + width: auto; +} + +.form-actions { + display: flex; + gap: var(--spacing-md); + margin-top: var(--spacing-lg); +} + +.form-actions button { + flex: 1; +} + +/* Task Detail */ +.task-detail { + display: flex; + flex-direction: column; + gap: var(--spacing-lg); +} + +.task-detail-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + border-bottom: 1px solid var(--color-border); + padding-bottom: var(--spacing-lg); +} + +.task-detail-header h2 { + font-size: 1.75rem; +} + +.task-actions { + display: flex; + gap: var(--spacing-md); +} + +.task-meta { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--spacing-lg); + padding: var(--spacing-lg); + background: var(--color-bg-light); + border-radius: var(--radius-md); +} + +.meta-item { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); +} + +.meta-item .label { + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + color: var(--color-text-light); +} + +.meta-item .value { + font-size: 0.875rem; + font-weight: 600; +} + +.task-section { + border-top: 1px solid var(--color-border); + padding-top: var(--spacing-lg); +} + +.task-section h3 { + font-size: 1rem; + margin-bottom: var(--spacing-md); +} + +.prompt-display { + background: var(--color-bg-light); + padding: var(--spacing-md); + border-radius: var(--radius-md); + overflow-x: auto; + border: 1px solid var(--color-border); + font-size: 0.875rem; + line-height: 1.5; +} + +/* Run History */ +.runs-list { + display: flex; + flex-direction: column; + gap: var(--spacing-md); +} + +.run-item { + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + padding: var(--spacing-md); +} + +.run-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--spacing-md); +} + +.run-status { + padding: 4px 12px; + border-radius: var(--radius-sm); + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; +} + +.run-status.completed { + background: rgba(16, 185, 129, 0.2); + color: var(--color-success); +} + +.run-status.failed { + background: rgba(239, 68, 68, 0.2); + color: var(--color-danger); +} + +.run-status.running { + background: rgba(37, 99, 235, 0.2); + color: var(--color-primary); +} + +.run-time { + font-size: 0.75rem; + color: var(--color-text-light); +} + +.run-item details { + cursor: pointer; +} + +.run-item summary { + padding: var(--spacing-sm); + cursor: pointer; + font-weight: 600; + font-size: 0.875rem; +} + +.run-item pre { + background: var(--color-bg-light); + padding: var(--spacing-md); + border-radius: var(--radius-md); + overflow-x: auto; + font-size: 0.75rem; + margin-top: var(--spacing-sm); + border: 1px solid var(--color-border); +} + +.run-item pre.error { + border-left: 3px solid var(--color-danger); +} + +/* Empty States */ +.empty-state-main { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100%; + gap: var(--spacing-md); + color: var(--color-text-light); + text-align: center; +} + +.empty-state-main h2 { + font-size: 1.25rem; + color: var(--color-text-dark); +} + +.empty { + padding: var(--spacing-lg); + text-align: center; + color: var(--color-text-light); + font-size: 0.875rem; +} + +/* Scrollbar Styling */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: var(--color-border); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #cbd5e1; +} + +/* Responsive */ +@media (max-width: 768px) { + .app-main { + flex-direction: column; + } + + .sidebar { + width: 100%; + border-right: none; + border-bottom: 1px solid var(--color-border); + max-height: 50vh; + } + + .content { + padding: var(--spacing-lg); + } + + .task-detail-header { + flex-direction: column; + gap: var(--spacing-md); + } + + .task-actions { + width: 100%; + } + + .task-actions button { + flex: 1; + } + + .form-row { + grid-template-columns: 1fr; + } +}