diff --git a/frontend/agentic-seek-front/public/favicon.ico b/frontend/agentic-seek-front/public/favicon.ico
index a11777c..01673a0 100644
Binary files a/frontend/agentic-seek-front/public/favicon.ico and b/frontend/agentic-seek-front/public/favicon.ico differ
diff --git a/frontend/agentic-seek-front/public/logo192.png b/frontend/agentic-seek-front/public/logo192.png
index fc44b0a..58782a2 100644
Binary files a/frontend/agentic-seek-front/public/logo192.png and b/frontend/agentic-seek-front/public/logo192.png differ
diff --git a/frontend/agentic-seek-front/public/logo512.png b/frontend/agentic-seek-front/public/logo512.png
deleted file mode 100644
index a4e47a6..0000000
Binary files a/frontend/agentic-seek-front/public/logo512.png and /dev/null differ
diff --git a/frontend/agentic-seek-front/src/App.css b/frontend/agentic-seek-front/src/App.css
index b43c965..6b4028b 100644
--- a/frontend/agentic-seek-front/src/App.css
+++ b/frontend/agentic-seek-front/src/App.css
@@ -4,37 +4,272 @@
box-sizing: border-box;
}
+html,
+body,
+#root {
+ height: 100%;
+ overflow: hidden;
+}
+
body {
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
- background-color: #0f172a; /* darkBackground */
- color: #f8fafc; /* darkText */
+ font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ sans-serif;
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
+ color: #f8fafc;
overflow-x: hidden;
+ min-height: 100vh;
}
.app {
- min-height: 100vh;
+ height: 100vh;
display: flex;
flex-direction: column;
+ background-color: var(--background);
+ color: var(--foreground);
+ overflow: hidden;
}
.header {
- padding: 10px 16px;
- background-color: #1e293b; /* darkCard */
- border-bottom: 1px solid #334155; /* darkBorder */
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 1rem 2rem;
+ border-bottom: 1px solid var(--border);
+ background-color: var(--background);
+ flex-shrink: 0;
+ height: 70px;
+}
+
+.header::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, var(--accent), transparent);
+}
+
+.header-brand {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+.logo-container {
+ position: relative;
display: flex;
align-items: center;
justify-content: center;
}
+.logo-icon {
+ width: 36px;
+ height: 36px;
+ transition: all 0.3s ease;
+}
+
+.logo-pulse {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 36px;
+ height: 36px;
+ border: 2px solid var(--accent);
+ border-radius: 50%;
+ opacity: 0;
+ animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+ 0% {
+ transform: translate(-50%, -50%) scale(1);
+ opacity: 0.7;
+ }
+ 70% {
+ transform: translate(-50%, -50%) scale(1.4);
+ opacity: 0;
+ }
+ 100% {
+ transform: translate(-50%, -50%) scale(1.4);
+ opacity: 0;
+ }
+}
+
+.brand-text {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+
.header h1 {
font-size: 1.5rem;
- font-weight: 600;
- letter-spacing: 0.5px;
- color: #f8fafc; /* darkText */
+ font-weight: 700;
+ color: var(--foreground);
margin: 0;
}
+.brand-subtitle {
+ font-size: 0.75rem;
+ color: var(--muted-foreground);
+ font-weight: 500;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+.header-status {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.status-indicator {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 12px;
+ border-radius: 20px;
+ background-color: var(--muted);
+ border: 1px solid var(--border);
+ transition: all 0.3s ease;
+}
+
+.status-indicator.online {
+ background-color: rgba(34, 197, 94, 0.1);
+ border-color: rgba(34, 197, 94, 0.3);
+}
+
+.status-indicator.offline {
+ background-color: rgba(239, 68, 68, 0.1);
+ border-color: rgba(239, 68, 68, 0.3);
+}
+
+.status-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background-color: var(--muted-foreground);
+ transition: all 0.3s ease;
+}
+
+.status-indicator.online .status-dot {
+ background-color: #22c55e;
+ box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);
+ animation: statusPulse 2s infinite;
+}
+
+.status-indicator.offline .status-dot {
+ background-color: #ef4444;
+}
+
+@keyframes statusPulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ transform: scale(1);
+ }
+ 50% {
+ opacity: 0.7;
+ transform: scale(1.2);
+ }
+}
+
+.status-text {
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: var(--foreground);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.header-actions {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.action-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-width: 44px;
+ height: 44px;
+ padding: 0 12px;
+ border-radius: 12px;
+ border: 1px solid var(--border);
+ background: var(--card);
+ color: var(--foreground);
+ text-decoration: none;
+ font-size: 0.875rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.action-button::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(255, 255, 255, 0.1),
+ transparent
+ );
+ transition: left 0.5s ease;
+}
+
+.action-button:hover::before {
+ left: 100%;
+}
+
+.action-button:hover {
+ background: var(--muted);
+ color: var(--foreground);
+ transform: translateY(-2px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
+ border-color: var(--border);
+}
+
+.action-button.github-link:hover {
+ background: #24292e;
+ border-color: #24292e;
+ color: white;
+ box-shadow: 0 8px 25px rgba(36, 41, 46, 0.3);
+}
+
+.action-text {
+ font-size: 0.8rem;
+ font-weight: 600;
+ display: none;
+}
+
+@media (min-width: 768px) {
+ .action-text {
+ display: block;
+ }
+
+ .action-button {
+ min-width: auto;
+ padding: 0 16px;
+ }
+}
+
+.main {
+ flex: 1;
+ padding: 1rem 2rem;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
.section-tabs {
display: flex;
gap: 8px;
@@ -65,17 +300,11 @@ body {
color: #f8fafc; /* darkText */
}
-.main {
- flex: 1;
- padding: 16px;
- width: 100%;
-}
-
.app-sections {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 16px;
- height: calc(100vh - 80px);
+ display: flex;
+ gap: 1rem;
+ height: 100%;
+ overflow: hidden;
}
.left-panel,
@@ -83,7 +312,8 @@ body {
background-color: #1e293b; /* darkCard */
border: 1px solid #334155; /* darkBorder */
border-radius: 8px;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
display: flex;
flex-direction: column;
overflow: hidden;
@@ -98,32 +328,68 @@ body {
.task-section,
.chat-section,
.computer-section {
- background-color: #1e293b; /* darkCard */
- border: 1px solid #334155; /* darkBorder */
- border-radius: 8px;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
- padding: 16px;
+ background: var(--card);
+ backdrop-filter: blur(20px);
+ border: 1px solid var(--border);
+ border-radius: 16px;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
+ padding: 24px;
display: flex;
flex-direction: column;
overflow: hidden;
+ position: relative;
+ height: 100%;
+ width: 100%;
+}
+
+.task-section::before,
+.chat-section::before,
+.computer-section::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(96, 165, 250, 0.5),
+ transparent
+ );
}
.task-section h2,
.chat-section h2,
.computer-section h2 {
- font-size: 1.1rem;
+ font-size: 1.25rem;
font-weight: 600;
- color: #cbd5e1; /* darkTextSecondary */
- margin-bottom: 12px;
- letter-spacing: 0.5px;
- border-bottom: 1px solid #334155; /* darkBorder */
- padding-bottom: 8px;
+ color: var(--foreground);
+ margin-bottom: 20px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.task-section h2::before {
+ content: "💼";
+ font-size: 1.1rem;
+}
+
+.chat-section h2::before {
+ content: "💬";
+ font-size: 1.1rem;
+}
+
+.computer-section h2::before {
+ content: "🖥️";
+ font-size: 1.1rem;
}
.task-details {
flex: 1;
overflow-y: auto;
- background-color: #2d3748; /* Slightly lighter than darkCard */
+ background-color: var(--muted);
border-radius: 8px;
padding: 16px;
margin-top: 12px;
@@ -136,14 +402,14 @@ body {
display: flex;
justify-content: center;
align-items: flex-start;
- background-color: #2d3748; /* Slightly lighter than darkCard */
+ background-color: var(--muted);
border-radius: 8px;
padding: 16px;
}
.screenshot-container img {
max-width: 100%;
- border: 1px solid #4a5568; /* Medium gray */
+ border: 1px solid var(--border);
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
@@ -152,7 +418,7 @@ body {
.right-panel h2 {
font-size: 1.1rem;
font-weight: 600;
- color: #cbd5e1; /* darkTextSecondary */
+ color: var(--foreground);
margin-bottom: 8px;
letter-spacing: 1px;
}
@@ -160,342 +426,355 @@ body {
.messages {
flex: 1;
overflow-y: auto;
- padding: 12px 8px;
display: flex;
flex-direction: column;
- gap: 12px;
- margin-bottom: 8px;
+ gap: 1rem;
+ margin-bottom: 1rem;
+ padding-right: 0.5rem;
+ min-height: 0;
}
-/* Message header layout */
-.message-header {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 8px;
+.messages::-webkit-scrollbar {
+ width: 6px;
}
-.reasoning-toggle {
- background: rgba(255, 255, 255, 0.1);
- border: 1px solid rgba(255, 255, 255, 0.2);
- border-radius: 4px;
- color: #fff;
- padding: 4px 8px;
- font-size: 12px;
- cursor: pointer;
- transition: all 0.2s ease;
- display: flex;
- align-items: center;
- gap: 4px;
- align-self: flex-start;
+.messages::-webkit-scrollbar-track {
+ background: var(--muted);
+ border-radius: 3px;
}
-.reasoning-toggle:hover {
- background: rgba(255, 255, 255, 0.2);
- border-color: rgba(255, 255, 255, 0.3);
-}
-
-.reasoning-toggle:active {
- transform: translateY(1px);
-}
-
-/* Reasoning content container */
-.reasoning-content {
- margin-top: 12px;
- padding: 12px;
- background: rgba(0, 0, 0, 0.2);
- border-left: 3px solid rgba(255, 255, 255, 0.3);
- border-radius: 0 4px 4px 0;
- font-size: 0.9em;
- line-height: 1.4;
-}
-
-.reasoning-content h1,
-.reasoning-content h2,
-.reasoning-content h3,
-.reasoning-content h4,
-.reasoning-content h5,
-.reasoning-content h6 {
- font-size: 1em;
- margin: 8px 0 4px 0;
- color: rgba(255, 255, 255, 0.9);
-}
-
-.reasoning-content p {
- margin: 6px 0;
- color: rgba(255, 255, 255, 0.8);
-}
-
-/* Alternative light theme styles */
-.message.user-message .reasoning-toggle {
- background: rgba(0, 0, 0, 0.05);
- border-color: rgba(0, 0, 0, 0.1);
- color: #333;
-}
-
-.message.user-message .reasoning-toggle:hover {
- background: rgba(0, 0, 0, 0.1);
- border-color: rgba(0, 0, 0, 0.2);
-}
-
-.message.user-message .reasoning-content {
- background: rgba(0, 0, 0, 0.03);
- border-left-color: rgba(0, 0, 0, 0.2);
-}
-
-.message.user-message .reasoning-content p {
- color: rgba(0, 0, 0, 0.7);
+.messages::-webkit-scrollbar-thumb {
+ background: var(--muted-foreground);
+ border-radius: 3px;
}
.placeholder {
text-align: center;
- color: #64748b; /* lighter gray */
- margin-top: 20px;
- font-style: italic;
+ color: var(--muted-foreground);
+ margin: 2rem 0;
+ font-size: 0.875rem;
}
.message {
max-width: 85%;
- padding: 12px 16px;
- border-radius: 12px;
- font-size: 0.95rem;
+ padding: 0.75rem 1rem;
+ border-radius: 8px;
+ font-size: 0.875rem;
line-height: 1.5;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ position: relative;
+ animation: messageSlide 0.3s ease-out;
}
-.messages::-webkit-scrollbar,
-.content::-webkit-scrollbar {
- width: 6px;
-}
-
-.messages::-webkit-scrollbar-track,
-.content::-webkit-scrollbar-track {
- background: #2d3748; /* Slightly lighter than darkCard */
- border-radius: 8px;
-}
-
-.messages::-webkit-scrollbar-thumb,
-.content::-webkit-scrollbar-thumb {
- background: #4a5568; /* Medium gray */
- border-radius: 8px;
-}
-
-.messages::-webkit-scrollbar-thumb:hover,
-.content::-webkit-scrollbar-thumb:hover {
- background: #718096; /* Lighter gray on hover */
+@keyframes messageSlide {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
.user-message {
- background-color: #0066cc; /* primary */
- color: #ffffff; /* white */
+ background-color: var(--accent);
+ color: var(--accent-foreground);
align-self: flex-end;
- border-top-right-radius: 4px;
}
.agent-message {
- background-color: #2d3748; /* Slightly lighter than darkCard */
- color: #f8fafc; /* darkText */
+ background-color: var(--muted);
+ color: var(--foreground);
align-self: flex-start;
- border-top-left-radius: 4px;
+ border: 1px solid var(--border);
}
.error-message {
- background-color: #dc3545; /* error */
- color: #ffffff; /* white */
+ background-color: var(--destructive);
+ color: var(--destructive-foreground);
align-self: flex-start;
- border-top-left-radius: 4px;
+}
+
+.message-header {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ margin-bottom: 0.5rem;
}
.agent-name {
- display: block;
- font-size: 0.8rem;
- color: #cbd5e1; /* darkTextSecondary */
- margin-bottom: 4px;
+ font-size: 0.75rem;
+ color: var(--muted-foreground);
font-weight: 500;
}
+.reasoning-toggle {
+ background-color: var(--secondary);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ color: var(--secondary-foreground);
+ padding: 0.25rem 0.5rem;
+ font-size: 0.75rem;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ width: fit-content;
+}
+
+.reasoning-toggle:hover {
+ background-color: var(--muted);
+}
+
+.reasoning-content {
+ margin-top: 0.75rem;
+ padding: 0.75rem;
+ background-color: var(--secondary);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ font-size: 0.8rem;
+}
+
.loading-animation {
text-align: center;
- color: #cbd5e1; /* darkTextSecondary */
- padding: 8px 0;
- font-size: 0.9rem;
- font-style: italic;
- border-top: 1px solid #334155; /* darkBorder */
- margin-bottom: 8px;
+ color: var(--muted-foreground);
+ padding: 0.75rem;
+ font-size: 0.875rem;
+ border-top: 1px solid var(--border);
+ flex-shrink: 0;
}
.input-form {
display: flex;
- gap: 8px;
- margin-top: 8px;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.75rem 1rem;
+ background-color: var(--card);
+ border-radius: 24px;
+ border: 1px solid var(--border);
+ flex-shrink: 0;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ transition: all 0.2s ease;
+}
+
+.input-form:focus-within {
+ border-color: var(--accent);
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.input-form input {
flex: 1;
- padding: 12px 16px;
+ padding: 0.75rem 1rem;
font-size: 0.95rem;
- background-color: #2d3748; /* Slightly lighter than darkCard */
- border: 1px solid #4a5568; /* Medium gray */
- color: #f8fafc; /* darkText */
- border-radius: 8px;
- outline: none;
- transition: all 0.2s ease;
-}
-
-.input-form input:focus {
- border-color: #0066cc; /* primary */
- box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.2); /* primary with opacity */
-}
-
-.input-form button {
- padding: 12px 20px;
- font-size: 0.95rem;
- background-color: #0066cc; /* primary */
- color: #ffffff; /* white */
+ background-color: transparent;
border: none;
- border-radius: 8px;
+ color: var(--foreground);
+ border-radius: 20px;
+ outline: none;
+ font-family: inherit;
+}
+
+.input-form input::placeholder {
+ color: var(--muted-foreground);
+}
+
+.input-form .action-buttons {
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+}
+
+.input-form .icon-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ background-color: var(--foreground);
+ color: var(--background);
+ border: none;
+ border-radius: 50%;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
-.input-form button:hover {
- background-color: #004c99; /* primaryDark */
+.input-form .icon-button:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ background-color: var(--muted-foreground);
}
-.input-form button:disabled {
- background-color: #4a5568; /* Medium gray */
- opacity: 0.7;
+.input-form .icon-button:disabled {
+ opacity: 0.5;
cursor: not-allowed;
+ transform: none;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
-.right-panel {
- padding: 16px;
+.input-form .icon-button.stop-button {
+ background-color: var(--destructive);
+ color: var(--destructive-foreground);
+}
+
+.input-form .icon-button.stop-button:hover {
+ background-color: #dc2626;
}
.view-selector {
display: flex;
- gap: 8px;
- margin-bottom: 16px;
+ gap: 0.25rem;
+ margin-bottom: 1rem;
+ padding: 0.25rem;
+ background-color: var(--muted);
+ border-radius: 8px;
+ flex-shrink: 0;
}
.view-selector button {
- padding: 10px 16px;
- font-size: 0.9rem;
- background-color: #2d3748; /* Slightly lighter than darkCard */
- color: #cbd5e1; /* darkTextSecondary */
- border: 1px solid #4a5568; /* Medium gray */
- border-radius: 8px;
+ padding: 0.5rem 1rem;
+ font-size: 0.875rem;
+ background-color: transparent;
+ color: var(--muted-foreground);
+ border: none;
+ border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
+ flex: 1;
}
.view-selector button.active {
- background-color: #0066cc; /* primary */
- color: #ffffff; /* white */
- border-color: #0066cc; /* primary */
+ background-color: var(--background);
+ color: var(--foreground);
}
.view-selector button:hover:not(.active) {
- background-color: #4a5568; /* Medium gray */
- color: #f8fafc; /* darkText */
-}
-
-.view-selector button:disabled {
- background-color: #4a5568; /* Medium gray */
- opacity: 0.5;
- cursor: not-allowed;
+ color: var(--foreground);
}
.content {
flex: 1;
overflow-y: auto;
- padding: 8px 0;
- margin-top: 8px;
+ min-height: 0;
+}
+
+.content::-webkit-scrollbar {
+ width: 6px;
+}
+
+.content::-webkit-scrollbar-track {
+ background: var(--muted);
+ border-radius: 3px;
+}
+
+.content::-webkit-scrollbar-thumb {
+ background: var(--muted-foreground);
+ border-radius: 3px;
}
.blocks {
display: flex;
flex-direction: column;
- gap: 16px;
+ gap: 1rem;
}
.block {
- background-color: #2d3748; /* Slightly lighter than darkCard */
- padding: 16px;
- border: 1px solid #4a5568; /* Medium gray */
+ background-color: var(--card);
+ padding: 1rem;
+ border: 1px solid var(--border);
border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.block-tool,
.block-feedback,
-.block-success {
- font-size: 0.9rem;
- margin-bottom: 8px;
- color: #cbd5e1; /* darkTextSecondary */
-}
-
-.block-tool {
- font-weight: 600;
- color: #0066cc; /* primary */
+.block-success,
+.block-failure {
+ font-size: 0.875rem;
+ margin-bottom: 0.5rem;
+ font-weight: 500;
}
.block-success {
- color: #28a745; /* success */
+ color: #22c55e;
}
.block-failure {
- color: #d21b0b; /* success */
+ color: #ef4444;
+}
+
+.block-failure::before {
+ content: "❌";
+}
+
+.block-feedback {
+ color: #cbd5e1;
+}
+
+.block-feedback::before {
+ content: "💬";
}
.block pre {
- background-color: #1a202c; /* Darker than darkCard */
- padding: 12px;
- border-radius: 6px;
+ background: var(--muted);
+ padding: 16px;
+ border-radius: 8px;
font-size: 0.85rem;
white-space: pre-wrap;
word-break: break-all;
- color: #e2e8f0; /* Light gray */
- margin: 8px 0;
- font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+ color: var(--muted-foreground);
+ margin: 12px 0;
+ font-family: "JetBrains Mono", "Fira Code", "Menlo", monospace;
+ border-left: 3px solid var(--muted-foreground);
+ overflow-x: auto;
}
.screenshot {
- margin-top: 8px;
display: flex;
justify-content: center;
align-items: center;
+ padding: 20px;
+ background: var(--muted);
+ border-radius: 12px;
+ border: 1px solid var(--border);
}
.screenshot img {
max-width: 100%;
- border: 1px solid #4a5568; /* Medium gray */
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ border: 2px solid var(--border);
+ border-radius: 12px;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
+ transition: all 0.3s ease;
+}
+
+.screenshot img:hover {
+ transform: scale(1.02);
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
}
.error {
- color: #dc3545; /* error */
+ color: var(--destructive-foreground);
font-size: 0.9rem;
- margin-bottom: 12px;
- padding: 8px 12px;
- background-color: rgba(220, 53, 69, 0.1); /* error with opacity */
- border-radius: 6px;
- border-left: 3px solid #dc3545; /* error */
+ margin-bottom: 16px;
+ padding: 12px 16px;
+ background: rgba(239, 68, 68, 0.1);
+ border-radius: 8px;
+ border-left: 3px solid var(--destructive);
+ display: flex;
+ align-items: center;
+ gap: 8px;
}
-@media (max-width: 1024px) {
- .app-sections {
- grid-template-columns: 1fr 1fr;
- grid-template-rows: auto 1fr;
+.error::before {
+ content: "⚠️";
+}
+
+@media (max-width: 1200px) {
+ .main {
+ padding: 24px;
}
- .task-section {
- grid-column: 1 / -1;
+ .app-sections {
+ gap: 24px;
}
}
@@ -504,26 +783,49 @@ body {
padding: 16px;
}
- .app-sections {
- grid-template-columns: 1fr;
- height: auto;
- gap: 16px;
- }
-
- .task-section,
.chat-section,
.computer-section {
- height: calc(33vh - 60px);
- min-height: 300px;
+ height: 50vh;
+ min-height: 400px;
+ }
+
+ .header {
+ padding: 0.75rem 1.25rem;
}
.header h1 {
- font-size: 1.5rem;
+ font-size: 1.75rem;
}
- .input-form button {
+ .message {
+ max-width: 90%;
padding: 12px 16px;
}
+
+ .view-selector button {
+ padding: 10px 16px;
+ font-size: 0.85rem;
+ }
+
+ .input-form {
+ padding: 0.75rem 1rem;
+ border-radius: 20px;
+ }
+
+ .input-form input {
+ padding: 0.75rem;
+ font-size: 0.9rem;
+ }
+
+ .input-form .icon-button {
+ width: 36px;
+ height: 36px;
+ }
+
+ .input-form .icon-button.stop-button {
+ width: 36px;
+ height: 36px;
+ }
}
@media (max-width: 480px) {
@@ -531,35 +833,46 @@ body {
padding: 12px;
}
- .message {
- max-width: 90%;
- padding: 10px 12px;
- }
-
- .view-selector button {
- padding: 8px 12px;
- font-size: 0.85rem;
- }
-
- .task-section,
.chat-section,
.computer-section {
+ padding: 16px;
+ min-height: 350px;
+ }
+
+ .header h1 {
+ font-size: 1.5rem;
+ }
+
+ .message {
+ padding: 10px 14px;
+ font-size: 0.9rem;
+ }
+
+ .block {
+ padding: 16px;
+ }
+
+ .block pre {
+ font-size: 0.8rem;
padding: 12px;
}
.input-form {
- margin-top: 8px;
+ padding: 0.5rem 0.75rem;
}
- .header h1 {
- font-size: 1.3rem;
+ .input-form input {
+ padding: 0.5rem 0.75rem;
+ font-size: 0.85rem;
}
- .task-section h2,
- .chat-section h2,
- .computer-section h2 {
- font-size: 1rem;
- margin-bottom: 8px;
- padding-bottom: 6px;
+ .input-form .icon-button {
+ width: 34px;
+ height: 34px;
}
-}
\ No newline at end of file
+
+ .input-form .icon-button.stop-button {
+ width: 34px;
+ height: 34px;
+ }
+}
diff --git a/frontend/agentic-seek-front/src/App.js b/frontend/agentic-seek-front/src/App.js
index b456e79..6222e11 100644
--- a/frontend/agentic-seek-front/src/App.js
+++ b/frontend/agentic-seek-front/src/App.js
@@ -1,329 +1,418 @@
-import React, { useState, useEffect, useRef } from 'react';
-import ReactMarkdown from 'react-markdown';
-import axios from 'axios';
-import './App.css';
-import { colors } from './colors';
+import React, { useState, useEffect, useRef, useCallback } from "react";
+import ReactMarkdown from "react-markdown";
+import axios from "axios";
+import "./App.css";
+import { ThemeToggle } from "./components/ThemeToggle";
+import { ResizableLayout } from "./components/ResizableLayout";
+import faviconPng from "./logo.png";
+
+const BACKEND_URL = process.env.REACT_APP_BACKEND_URL || 'http://localhost:7777';
+console.log("Using backend URL:", BACKEND_URL);
-const BACKEND_URL = 'http://localhost:7777' || process.env.REACT_APP_BACKEND_URL;
-console.log('Using backend URL:', BACKEND_URL);
function App() {
- const [query, setQuery] = useState('');
- const [messages, setMessages] = useState([]);
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
- const [currentView, setCurrentView] = useState('blocks');
- const [responseData, setResponseData] = useState(null);
- const [isOnline, setIsOnline] = useState(false);
- const [status, setStatus] = useState('Agents ready');
- const [expandedReasoning, setExpandedReasoning] = useState(new Set());
- const messagesEndRef = useRef(null);
+ const [query, setQuery] = useState("");
+ const [messages, setMessages] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [currentView, setCurrentView] = useState("blocks");
+ const [responseData, setResponseData] = useState(null);
+ const [isOnline, setIsOnline] = useState(false);
+ const [status, setStatus] = useState("Agents ready");
+ const [expandedReasoning, setExpandedReasoning] = useState(new Set());
+ const messagesEndRef = useRef(null);
- useEffect(() => {
- const intervalId = setInterval(() => {
- checkHealth();
- fetchLatestAnswer();
- fetchScreenshot();
- }, 3000);
- return () => clearInterval(intervalId);
- }, [messages]);
+ const fetchLatestAnswer = useCallback(async () => {
+ try {
+ const res = await axios.get(`${BACKEND_URL}/latest_answer`);
+ const data = res.data;
- const checkHealth = async () => {
- try {
- await axios.get(`${BACKEND_URL}/health`);
- setIsOnline(true);
- console.log('System is online');
- } catch {
- setIsOnline(false);
- console.log('System is offline');
- }
- };
-
- const fetchScreenshot = async () => {
- try {
- const timestamp = new Date().getTime();
- const res = await axios.get(`${BACKEND_URL}/screenshots/updated_screen.png?timestamp=${timestamp}`, {
- responseType: 'blob'
- });
- console.log('Screenshot fetched successfully');
- const imageUrl = URL.createObjectURL(res.data);
- setResponseData((prev) => {
- if (prev?.screenshot && prev.screenshot !== 'placeholder.png') {
- URL.revokeObjectURL(prev.screenshot);
- }
- return {
- ...prev,
- screenshot: imageUrl,
- screenshotTimestamp: new Date().getTime()
- };
- });
- } catch (err) {
- console.error('Error fetching screenshot:', err);
- setResponseData((prev) => ({
- ...prev,
- screenshot: 'placeholder.png',
- screenshotTimestamp: new Date().getTime()
- }));
- }
- };
-
- const normalizeAnswer = (answer) => {
- return answer
- .trim()
- .toLowerCase()
- .replace(/\s+/g, ' ')
- .replace(/[.,!?]/g, '')
- };
-
- const scrollToBottom = () => {
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
- };
-
- const toggleReasoning = (messageIndex) => {
- setExpandedReasoning(prev => {
- const newSet = new Set(prev);
- if (newSet.has(messageIndex)) {
- newSet.delete(messageIndex);
- } else {
- newSet.add(messageIndex);
- }
- return newSet;
- });
- };
-
- const fetchLatestAnswer = async () => {
- try {
- const res = await axios.get(`${BACKEND_URL}/latest_answer`);
- const data = res.data;
-
- updateData(data);
- if (!data.answer || data.answer.trim() === '') {
- return;
- }
- const normalizedNewAnswer = normalizeAnswer(data.answer);
- const answerExists = messages.some(
- (msg) => normalizeAnswer(msg.content) === normalizedNewAnswer
- );
- if (!answerExists) {
- setMessages((prev) => [
- ...prev,
- {
- type: 'agent',
- content: data.answer,
- reasoning: data.reasoning,
- agentName: data.agent_name,
- status: data.status,
- uid: data.uid,
- },
- ]);
- setStatus(data.status);
- scrollToBottom();
- } else {
- console.log('Duplicate answer detected, skipping:', data.answer);
- }
- } catch (error) {
- console.error('Error fetching latest answer:', error);
- }
- };
-
- const updateData = (data) => {
- setResponseData((prev) => ({
- ...prev,
- blocks: data.blocks || prev.blocks || null,
- done: data.done,
- answer: data.answer,
- agent_name: data.agent_name,
+ updateData(data);
+ if (!data.answer || data.answer.trim() === "") {
+ return;
+ }
+ const normalizedNewAnswer = normalizeAnswer(data.answer);
+ const answerExists = messages.some(
+ (msg) => normalizeAnswer(msg.content) === normalizedNewAnswer
+ );
+ if (!answerExists) {
+ setMessages((prev) => [
+ ...prev,
+ {
+ type: "agent",
+ content: data.answer,
+ reasoning: data.reasoning,
+ agentName: data.agent_name,
status: data.status,
uid: data.uid,
- }));
- };
-
- const handleStop = async (e) => {
- e.preventDefault();
- checkHealth();
- setIsLoading(false);
- setError(null);
- try {
- const res = await axios.get(`${BACKEND_URL}/stop`);
- setStatus("Requesting stop...");
- } catch (err) {
- console.error('Error stopping the agent:', err);
- }
+ },
+ ]);
+ setStatus(data.status);
+ scrollToBottom();
+ } else {
+ console.log("Duplicate answer detected, skipping:", data.answer);
+ }
+ } catch (error) {
+ console.error("Error fetching latest answer:", error);
}
+ }, [messages]);
- const handleSubmit = async (e) => {
- e.preventDefault();
- checkHealth();
- if (!query.trim()) {
- console.log('Empty query');
- return;
+ useEffect(() => {
+ const intervalId = setInterval(() => {
+ checkHealth();
+ fetchLatestAnswer();
+ fetchScreenshot();
+ }, 3000);
+ return () => clearInterval(intervalId);
+ }, [fetchLatestAnswer]);
+
+ const checkHealth = async () => {
+ try {
+ await axios.get(`${BACKEND_URL}/health`);
+ setIsOnline(true);
+ console.log("System is online");
+ } catch {
+ setIsOnline(false);
+ console.log("System is offline");
+ }
+ };
+
+ const fetchScreenshot = async () => {
+ try {
+ const timestamp = new Date().getTime();
+ const res = await axios.get(
+ `${BACKEND_URL}/screenshots/updated_screen.png?timestamp=${timestamp}`,
+ {
+ responseType: "blob",
}
- setMessages((prev) => [...prev, { type: 'user', content: query }]);
- setIsLoading(true);
- setError(null);
-
- try {
- console.log('Sending query:', query);
- setQuery('waiting for response...');
- const res = await axios.post(`${BACKEND_URL}/query`, {
- query,
- tts_enabled: false
- });
- setQuery('Enter your query...');
- console.log('Response:', res.data);
- const data = res.data;
- updateData(data);
- } catch (err) {
- console.error('Error:', err);
- setError('Failed to process query.');
- setMessages((prev) => [
- ...prev,
- { type: 'error', content: 'Error: Unable to get a response.' },
- ]);
- } finally {
- console.log('Query completed');
- setIsLoading(false);
- setQuery('');
+ );
+ console.log("Screenshot fetched successfully");
+ const imageUrl = URL.createObjectURL(res.data);
+ setResponseData((prev) => {
+ if (prev?.screenshot && prev.screenshot !== "placeholder.png") {
+ URL.revokeObjectURL(prev.screenshot);
}
- };
+ return {
+ ...prev,
+ screenshot: imageUrl,
+ screenshotTimestamp: new Date().getTime(),
+ };
+ });
+ } catch (err) {
+ console.error("Error fetching screenshot:", err);
+ setResponseData((prev) => ({
+ ...prev,
+ screenshot: "placeholder.png",
+ screenshotTimestamp: new Date().getTime(),
+ }));
+ }
+ };
- const handleGetScreenshot = async () => {
- try {
- setCurrentView('screenshot');
- } catch (err) {
- setError('Browser not in use');
- }
- };
+ const normalizeAnswer = (answer) => {
+ return answer
+ .trim()
+ .toLowerCase()
+ .replace(/\s+/g, " ")
+ .replace(/[.,!?]/g, "");
+ };
- return (
-
-
-
-
-
-
Chat Interface
-
- {messages.length === 0 ? (
-
No messages yet. Type below to start!
- ) : (
- messages.map((msg, index) => (
-
-
- {msg.type === 'agent' && (
-
{msg.agentName}
- )}
- {msg.type === 'agent' && msg.reasoning && expandedReasoning.has(index) && (
-
- {msg.reasoning}
-
- )}
- {msg.type === 'agent' && (
-
- )}
-
-
- {msg.content}
-
-
- ))
- )}
-
-
- {isOnline &&
{status}
}
- {!isLoading && !isOnline &&
System offline. Deploy backend first.
}
-
-
+ const scrollToBottom = () => {
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+ };
-
-
Computer View
-
-
-
-
-
- {error &&
{error}
}
- {currentView === 'blocks' ? (
-
- {responseData && responseData.blocks && Object.values(responseData.blocks).length > 0 ? (
- Object.values(responseData.blocks).map((block, index) => (
-
-
Tool: {block.tool_type}
-
{block.block}
-
Feedback: {block.feedback}
- {block.success ? (
-
Success
- ) : (
-
Failure
- )}
-
- ))
- ) : (
-
-
Tool: No tool in use
-
No file opened
-
- )}
-
- ) : (
-
-

{
- e.target.src = 'placeholder.png';
- console.error('Failed to load screenshot');
- }}
- key={responseData?.screenshotTimestamp || 'default'}
- />
-
- )}
-
-
-
-
+ const toggleReasoning = (messageIndex) => {
+ setExpandedReasoning((prev) => {
+ const newSet = new Set(prev);
+ if (newSet.has(messageIndex)) {
+ newSet.delete(messageIndex);
+ } else {
+ newSet.add(messageIndex);
+ }
+ return newSet;
+ });
+ };
+
+ const updateData = (data) => {
+ setResponseData((prev) => ({
+ ...prev,
+ blocks: data.blocks || prev.blocks || null,
+ done: data.done,
+ answer: data.answer,
+ agent_name: data.agent_name,
+ status: data.status,
+ uid: data.uid,
+ }));
+ };
+
+ const handleStop = async (e) => {
+ e.preventDefault();
+ checkHealth();
+ setIsLoading(false);
+ setError(null);
+ try {
+ await axios.get(`${BACKEND_URL}/stop`);
+ setStatus("Requesting stop...");
+ } catch (err) {
+ console.error("Error stopping the agent:", err);
+ }
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ checkHealth();
+ if (!query.trim()) {
+ console.log("Empty query");
+ return;
+ }
+ setMessages((prev) => [...prev, { type: "user", content: query }]);
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ console.log("Sending query:", query);
+ setQuery("waiting for response...");
+ const res = await axios.post(`${BACKEND_URL}/query`, {
+ query,
+ tts_enabled: false,
+ });
+ setQuery("Enter your query...");
+ console.log("Response:", res.data);
+ const data = res.data;
+ updateData(data);
+ } catch (err) {
+ console.error("Error:", err);
+ setError("Failed to process query.");
+ setMessages((prev) => [
+ ...prev,
+ { type: "error", content: "Error: Unable to get a response." },
+ ]);
+ } finally {
+ console.log("Query completed");
+ setIsLoading(false);
+ setQuery("");
+ }
+ };
+
+ const handleGetScreenshot = async () => {
+ try {
+ setCurrentView("screenshot");
+ } catch (err) {
+ setError("Browser not in use");
+ }
+ };
+
+ return (
+
+
+
+
+

+
+
+
AgenticSeek
+
- );
+
+
+
+
+ {isOnline ? "Online" : "Offline"}
+
+
+
+
+
+
+
+
+
Chat Interface
+
+ {messages.length === 0 ? (
+
+ No messages yet. Type below to start!
+
+ ) : (
+ messages.map((msg, index) => (
+
+
+ {msg.type === "agent" && (
+
{msg.agentName}
+ )}
+ {msg.type === "agent" &&
+ msg.reasoning &&
+ expandedReasoning.has(index) && (
+
+ {msg.reasoning}
+
+ )}
+ {msg.type === "agent" && (
+
+ )}
+
+
+ {msg.content}
+
+
+ ))
+ )}
+
+
+ {isOnline &&
{status}
}
+ {!isLoading && !isOnline && (
+
+ System offline. Deploy backend first.
+
+ )}
+
+
+
+
+
Computer View
+
+
+
+
+
+ {error &&
{error}
}
+ {currentView === "blocks" ? (
+
+ {responseData &&
+ responseData.blocks &&
+ Object.values(responseData.blocks).length > 0 ? (
+ Object.values(responseData.blocks).map((block, index) => (
+
+
Tool: {block.tool_type}
+
{block.block}
+
+ Feedback: {block.feedback}
+
+ {block.success ? (
+
Success
+ ) : (
+
Failure
+ )}
+
+ ))
+ ) : (
+
+
Tool: No tool in use
+
No file opened
+
+ )}
+
+ ) : (
+
+

{
+ e.target.src = "placeholder.png";
+ console.error("Failed to load screenshot");
+ }}
+ key={responseData?.screenshotTimestamp || "default"}
+ />
+
+ )}
+
+
+
+
+
+ );
}
-export default App;
\ No newline at end of file
+export default App;
diff --git a/frontend/agentic-seek-front/src/colors.js b/frontend/agentic-seek-front/src/colors.js
index 7141ca4..a012414 100644
--- a/frontend/agentic-seek-front/src/colors.js
+++ b/frontend/agentic-seek-front/src/colors.js
@@ -1,63 +1,64 @@
export const colors = {
- // Primary colors
- primary: '#0066cc',
- primaryLight: '#e6f2ff',
- primaryDark: '#004c99',
-
- // Secondary colors
- secondary: '#6c757d',
- secondaryLight: '#f8f9fa',
- secondaryDark: '#343a40',
-
+ // Primary colors - matching the dashboard theme
+ primary: "#2563eb",
+ primaryLight: "#dbeafe",
+ primaryDark: "#1d4ed8",
+
+ // Secondary colors - modern grays
+ secondary: "#64748b",
+ secondaryLight: "#f1f5f9",
+ secondaryDark: "#1e293b",
+
// Accent colors
- accent: '#ff9500',
- accentLight: '#fff4e6',
- accentDark: '#cc7a00',
-
+ accent: "#f59e0b",
+ accentLight: "#fef3c7",
+ accentDark: "#d97706",
+
// Status colors
- success: '#28a745',
- successLight: '#e8f5e9',
- warning: '#ffc107',
- warningLight: '#fff9e6',
- error: '#dc3545',
- errorLight: '#ffebee',
- info: '#17a2b8',
- infoLight: '#e3f2fd',
-
- // Neutral colors
- white: '#ffffff',
- gray100: '#f8f9fa',
- gray200: '#e9ecef',
- gray300: '#dee2e6',
- gray400: '#ced4da',
- gray500: '#adb5bd',
- gray600: '#6c757d',
- gray700: '#495057',
- gray800: '#343a40',
- gray900: '#212529',
- black: '#000000',
-
+ success: "#10b981",
+ successLight: "#d1fae5",
+ warning: "#f59e0b",
+ warningLight: "#fef3c7",
+ error: "#ef4444",
+ errorLight: "#fee2e2",
+ info: "#06b6d4",
+ infoLight: "#cffafe",
+
+ // Neutral colors - modern palette
+ white: "#ffffff",
+ gray50: "#f8fafc",
+ gray100: "#f1f5f9",
+ gray200: "#e2e8f0",
+ gray300: "#cbd5e1",
+ gray400: "#94a3b8",
+ gray500: "#64748b",
+ gray600: "#475569",
+ gray700: "#334155",
+ gray800: "#1e293b",
+ gray900: "#0f172a",
+ black: "#000000",
+
// Text colors
- textPrimary: '#212529',
- textSecondary: '#6c757d',
- textDisabled: '#adb5bd',
-
+ textPrimary: "#0f172a",
+ textSecondary: "#64748b",
+ textDisabled: "#94a3b8",
+
// Background colors
- background: '#f8f8f8',
- card: '#ffffff',
-
+ background: "#f8fafc",
+ card: "#ffffff",
+
// Border colors
- border: '#dee2e6',
- divider: '#e9ecef',
-
+ border: "#e2e8f0",
+ divider: "#f1f5f9",
+
// Transparent colors
- transparent: 'transparent',
- semiTransparent: 'rgba(0, 0, 0, 0.5)',
-
+ transparent: "transparent",
+ semiTransparent: "rgba(15, 23, 42, 0.6)",
+
// Dark theme colors
- darkBackground: '#0f172a',
- darkCard: '#1e293b',
- darkBorder: '#334155',
- darkText: '#f8fafc',
- darkTextSecondary: '#cbd5e1',
+ darkBackground: "#0f172a",
+ darkCard: "#1e293b",
+ darkBorder: "#334155",
+ darkText: "#f8fafc",
+ darkTextSecondary: "#cbd5e1",
};
diff --git a/frontend/agentic-seek-front/src/components/ResizableLayout.css b/frontend/agentic-seek-front/src/components/ResizableLayout.css
new file mode 100644
index 0000000..7422666
--- /dev/null
+++ b/frontend/agentic-seek-front/src/components/ResizableLayout.css
@@ -0,0 +1,69 @@
+.resizable-container {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.resizable-left,
+.resizable-right {
+ height: 100%;
+ overflow: hidden;
+ min-width: 0;
+}
+
+.resize-handle {
+ width: 8px;
+ background-color: transparent;
+ cursor: col-resize;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 2px;
+ transition: background-color 0.2s ease;
+ position: relative;
+ flex-shrink: 0;
+}
+
+.resize-handle:hover {
+ background-color: var(--accent);
+}
+
+.resize-handle-line {
+ width: 2px;
+ height: 40px;
+ background-color: var(--border);
+ border-radius: 1px;
+ transition: all 0.2s ease;
+}
+
+.resize-handle:hover .resize-handle-line {
+ background-color: var(--accent-foreground);
+ height: 60px;
+}
+
+.resizable-container.dragging .resize-handle {
+ background-color: var(--accent);
+}
+
+.resizable-container.dragging .resize-handle-line {
+ background-color: var(--accent-foreground);
+ height: 100vh;
+}
+
+/* Mobile responsiveness */
+@media (max-width: 768px) {
+ .resizable-container {
+ flex-direction: column;
+ }
+
+ .resizable-left,
+ .resizable-right {
+ width: 100% !important;
+ height: 50vh;
+ }
+
+ .resize-handle {
+ display: none;
+ }
+}
diff --git a/frontend/agentic-seek-front/src/components/ResizableLayout.js b/frontend/agentic-seek-front/src/components/ResizableLayout.js
new file mode 100644
index 0000000..ecdb38f
--- /dev/null
+++ b/frontend/agentic-seek-front/src/components/ResizableLayout.js
@@ -0,0 +1,70 @@
+import React, { useState, useRef, useCallback } from "react";
+import "./ResizableLayout.css";
+
+export const ResizableLayout = ({ children, initialLeftWidth = 50 }) => {
+ const [leftWidth, setLeftWidth] = useState(initialLeftWidth);
+ const [isDragging, setIsDragging] = useState(false);
+ const containerRef = useRef(null);
+
+ const handleMouseDown = useCallback((e) => {
+ e.preventDefault();
+ setIsDragging(true);
+ }, []);
+
+ const handleMouseMove = useCallback(
+ (e) => {
+ if (!isDragging || !containerRef.current) return;
+
+ const containerRect = containerRef.current.getBoundingClientRect();
+ const newLeftWidth =
+ ((e.clientX - containerRect.left) / containerRect.width) * 100;
+
+ // Constrain between 20% and 80%
+ const constrainedWidth = Math.max(20, Math.min(80, newLeftWidth));
+ setLeftWidth(constrainedWidth);
+ },
+ [isDragging]
+ );
+
+ const handleMouseUp = useCallback(() => {
+ setIsDragging(false);
+ }, []);
+
+ React.useEffect(() => {
+ if (isDragging) {
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ document.body.style.cursor = "col-resize";
+ document.body.style.userSelect = "none";
+ } else {
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+ document.body.style.cursor = "";
+ document.body.style.userSelect = "";
+ }
+
+ return () => {
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+ document.body.style.cursor = "";
+ document.body.style.userSelect = "";
+ };
+ }, [isDragging, handleMouseMove, handleMouseUp]);
+
+ return (
+
+
+ {children[0]}
+
+
+
+ {children[1]}
+
+
+ );
+};
diff --git a/frontend/agentic-seek-front/src/components/ThemeToggle.js b/frontend/agentic-seek-front/src/components/ThemeToggle.js
new file mode 100644
index 0000000..25514af
--- /dev/null
+++ b/frontend/agentic-seek-front/src/components/ThemeToggle.js
@@ -0,0 +1,34 @@
+import React from "react";
+import { useTheme } from "../contexts/ThemeContext";
+
+export const ThemeToggle = () => {
+ const { isDark, toggleTheme } = useTheme();
+
+ return (
+
+ );
+};
diff --git a/frontend/agentic-seek-front/src/contexts/ThemeContext.js b/frontend/agentic-seek-front/src/contexts/ThemeContext.js
new file mode 100644
index 0000000..5814683
--- /dev/null
+++ b/frontend/agentic-seek-front/src/contexts/ThemeContext.js
@@ -0,0 +1,34 @@
+import React, { createContext, useContext, useState, useEffect } from "react";
+
+const ThemeContext = createContext();
+
+export const ThemeProvider = ({ children }) => {
+ const [isDark, setIsDark] = useState(() => {
+ const saved = localStorage.getItem("theme");
+ return saved ? saved === "dark" : true; // Default to dark
+ });
+
+ useEffect(() => {
+ localStorage.setItem("theme", isDark ? "dark" : "light");
+ document.documentElement.setAttribute(
+ "data-theme",
+ isDark ? "dark" : "light"
+ );
+ }, [isDark]);
+
+ const toggleTheme = () => setIsDark(!isDark);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useTheme = () => {
+ const context = useContext(ThemeContext);
+ if (!context) {
+ throw new Error("useTheme must be used within ThemeProvider");
+ }
+ return context;
+};
diff --git a/frontend/agentic-seek-front/src/index.js b/frontend/agentic-seek-front/src/index.js
index 5851d84..25ce631 100644
--- a/frontend/agentic-seek-front/src/index.js
+++ b/frontend/agentic-seek-front/src/index.js
@@ -1,10 +1,14 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import App from './App';
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+import { ThemeProvider } from "./contexts/ThemeContext";
+import "./styles/globals.css";
-const root = ReactDOM.createRoot(document.getElementById('root'));
+const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
-
+
+
+
-);
\ No newline at end of file
+);
diff --git a/frontend/agentic-seek-front/src/logo.png b/frontend/agentic-seek-front/src/logo.png
new file mode 100644
index 0000000..58782a2
Binary files /dev/null and b/frontend/agentic-seek-front/src/logo.png differ
diff --git a/frontend/agentic-seek-front/src/logo.svg b/frontend/agentic-seek-front/src/logo.svg
deleted file mode 100644
index 9dfc1c0..0000000
--- a/frontend/agentic-seek-front/src/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/agentic-seek-front/src/styles/globals.css b/frontend/agentic-seek-front/src/styles/globals.css
new file mode 100644
index 0000000..7ea7709
--- /dev/null
+++ b/frontend/agentic-seek-front/src/styles/globals.css
@@ -0,0 +1,217 @@
+:root {
+ --background: hsl(0 0% 100%);
+ --foreground: hsl(222.2 47.4% 11.2%);
+ --muted: hsl(210 40% 96.1%);
+ --muted-foreground: hsl(215.4 16.3% 46.9%);
+ --popover: hsl(0 0% 100%);
+ --popover-foreground: hsl(222.2 47.4% 11.2%);
+ --card: hsl(0 0% 100%);
+ --card-foreground: hsl(222.2 47.4% 11.2%);
+ --border: hsl(214.3 31.8% 91.4%);
+ --input: hsl(214.3 31.8% 91.4%);
+ --primary: hsl(222.2 47.4% 11.2%);
+ --primary-foreground: hsl(210 40% 98%);
+ --secondary: hsl(210 40% 96.1%);
+ --secondary-foreground: hsl(222.2 47.4% 11.2%);
+ --accent: hsl(210 40% 96.1%);
+ --accent-foreground: hsl(222.2 47.4% 11.2%);
+ --destructive: hsl(0 100% 50%);
+ --destructive-foreground: hsl(210 40% 98%);
+ --ring: hsl(215 20.2% 65.1%);
+ --radius: 0.5rem;
+}
+
+.dark {
+ --background: hsl(224 71% 4%);
+ --foreground: hsl(213 31% 91%);
+ --muted: hsl(223 47% 11%);
+ --muted-foreground: hsl(215.4 16.3% 56.9%);
+ --popover: hsl(224 71% 4%);
+ --popover-foreground: hsl(215 20.2% 65.1%);
+ --card: hsl(224 71% 4%);
+ --card-foreground: hsl(213 31% 91%);
+ --border: hsl(216 34% 17%);
+ --input: hsl(216 34% 17%);
+ --primary: hsl(210 40% 98%);
+ --primary-foreground: hsl(222.2 47.4% 1.2%);
+ --secondary: hsl(222.2 47.4% 11.2%);
+ --secondary-foreground: hsl(210 40% 98%);
+ --accent: hsl(216 34% 17%);
+ --accent-foreground: hsl(210 40% 98%);
+ --destructive: hsl(0 63% 31%);
+ --destructive-foreground: hsl(210 40% 98%);
+ --ring: hsl(216 34% 17%);
+ --radius: 0.5rem;
+}
+
+[data-theme="dark"] {
+ --background: #0a0a0a;
+ --foreground: #fafafa;
+ --card: #1a1a1a;
+ --card-foreground: #fafafa;
+ --popover: #1a1a1a;
+ --popover-foreground: #fafafa;
+ --primary: #fafafa;
+ --primary-foreground: #0a0a0a;
+ --secondary: #2a2a2a;
+ --secondary-foreground: #fafafa;
+ --muted: #1e1e1e;
+ --muted-foreground: #a1a1aa;
+ --accent: #6b7280;
+ --accent-foreground: #ffffff;
+ --destructive: #ef4444;
+ --destructive-foreground: #ffffff;
+ --border: #333333;
+ --input: #333333;
+ --ring: #6b7280;
+}
+
+[data-theme="light"] {
+ --background: #ffffff;
+ --foreground: #0a0a0a;
+ --card: #ffffff;
+ --card-foreground: #0a0a0a;
+ --popover: #ffffff;
+ --popover-foreground: #0a0a0a;
+ --primary: #0a0a0a;
+ --primary-foreground: #ffffff;
+ --secondary: #f5f5f5;
+ --secondary-foreground: #0a0a0a;
+ --muted: #f5f5f5;
+ --muted-foreground: #737373;
+ --accent: #6b7280;
+ --accent-foreground: #ffffff;
+ --destructive: #ef4444;
+ --destructive-foreground: #ffffff;
+ --border: #e5e5e5;
+ --input: #e5e5e5;
+ --ring: #6b7280;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--background);
+ color: var(--foreground);
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
+ sans-serif;
+ transition: background-color 0.3s ease, color 0.3s ease;
+ margin: 0;
+ padding: 0;
+ height: 100vh;
+ overflow: hidden;
+}
+
+html,
+body,
+#root {
+ height: 100%;
+ overflow: hidden;
+}
+
+.theme-toggle {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-width: 44px;
+ height: 44px;
+ padding: 0 12px;
+ border-radius: 12px;
+ border: 1px solid var(--border);
+ background: var(--card);
+ color: var(--foreground);
+ text-decoration: none;
+ font-size: 0.875rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.theme-toggle::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(255, 255, 255, 0.1),
+ transparent
+ );
+ transition: left 0.5s ease;
+}
+
+.theme-toggle:hover::before {
+ left: 100%;
+}
+
+.theme-toggle:hover {
+ background: #24292e;
+ border-color: #24292e;
+ color: white;
+ transform: translateY(-2px);
+ box-shadow: 0 8px 25px rgba(36, 41, 46, 0.3);
+}
+
+.github-link {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-width: 44px;
+ height: 44px;
+ padding: 0 12px;
+ border-radius: 12px;
+ border: 1px solid var(--border);
+ background: var(--card);
+ color: var(--foreground);
+ text-decoration: none;
+ font-size: 0.875rem;
+ font-weight: 500;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.github-link::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(255, 255, 255, 0.1),
+ transparent
+ );
+ transition: left 0.5s ease;
+}
+
+.github-link:hover::before {
+ left: 100%;
+}
+
+.github-link:hover {
+ background: #24292e;
+ border-color: #24292e;
+ color: white;
+ transform: translateY(-2px);
+ box-shadow: 0 8px 25px rgba(36, 41, 46, 0.3);
+}
+
+.header-actions {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}