Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions frontend/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,16 @@
{:else}
<div class="flex flex-col min-h-screen bg-bg-default dark:bg-dark-bg-default pt-16">
<Header/>
<div class="flex-grow flex flex-col">
<ToastContainer/>
<main class="flex-grow">
{#if !authInitialized}
<div class="flex items-center justify-center min-h-[50vh]">
<Spinner size="large" />
</div>
{:else}
<Router base="/" {routes} />
{/if}
</main>
</div>
<ToastContainer/>
<main class="flex-grow">
{#if !authInitialized}
<div class="flex items-center justify-center min-h-[50vh]">
<Spinner size="large" />
</div>
{:else}
<Router base="/" {routes} />
{/if}
</main>
<Footer/>
</div>
{/if}
35 changes: 25 additions & 10 deletions frontend/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@

--color-code-bg: #0f172a;

/* Surface tokens for layered UI */
--color-surface-overlay: #ffffff;
--color-dark-surface-overlay: #1f2937;

/* Interactive states */
--color-interactive-hover: #f9fafb;
--color-dark-interactive-hover: #374151;

/* Skeleton/loading states */
--color-skeleton: #e5e7eb;
--color-dark-skeleton: #374151;

/* Tooltip */
--color-tooltip-bg: #111827;
--color-tooltip-fg: #ffffff;

/* Font Families */
--font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
--font-mono: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
Expand Down Expand Up @@ -413,13 +429,6 @@
Editor Component Styles
========================================================================== */

/* Bare input (no border/background) for inline editing */
.form-input-bare {
@apply bg-transparent border-0 focus:ring-0 w-full text-sm font-medium
text-fg-default dark:text-dark-fg-default
placeholder-fg-muted dark:placeholder-dark-fg-muted;
}

/* Output container for code execution results */
.output-container {
@apply bg-bg-alt dark:bg-dark-bg-alt border border-border-default
Expand All @@ -440,7 +449,13 @@
.output-pre,
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: #9ca3af #e5e7eb; /* neutral-400 neutral-200 */
scrollbar-color: var(--color-fg-subtle) var(--color-skeleton);
}

:is(.dark .output-content),
:is(.dark .output-pre),
:is(.dark .custom-scrollbar) {
scrollbar-color: var(--color-dark-fg-subtle) var(--color-dark-skeleton);
}

.output-content::-webkit-scrollbar,
Expand Down Expand Up @@ -501,7 +516,7 @@

/* Small input variant for admin tables */
.input-sm {
@apply px-2 py-1 text-sm border border-gray-300 dark:border-gray-600
rounded bg-white dark:bg-gray-700 text-fg-default dark:text-dark-fg-default;
@apply px-2 py-1 text-sm border border-border-input dark:border-dark-border-input
rounded bg-surface-overlay dark:bg-dark-surface-overlay text-fg-default dark:text-dark-fg-default;
}
}
2 changes: 1 addition & 1 deletion frontend/src/components/ErrorDisplay.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
</button>
<button
onclick={goHome}
class="flex-1 btn py-2.5 text-sm font-medium bg-bg-default dark:bg-dark-bg-default border border-border-default dark:border-dark-border-default text-fg-default dark:text-dark-fg-default hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
class="flex-1 btn py-2.5 text-sm font-medium bg-bg-default dark:bg-dark-bg-default border border-border-default dark:border-dark-border-default text-fg-default dark:text-dark-fg-default hover:bg-interactive-hover dark:hover:bg-dark-interactive-hover transition-colors"
>
Go to Home
</button>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Footer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
const githubIcon = `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/></svg>`;
</script>

<footer class="relative z-30 bg-bg-alt dark:bg-dark-bg-alt border-t border-border-default dark:border-dark-border-default">
<div class="app-container py-12">
<footer class="relative z-30 mt-8 pt-8 pb-6 bg-bg-alt dark:bg-dark-bg-alt border-t border-border-default dark:border-dark-border-default">
<div class="app-container py-6">

<div class="grid grid-cols-1 md:grid-cols-12 gap-8 mb-8">

Expand Down
25 changes: 9 additions & 16 deletions frontend/src/components/NotificationCenter.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
}

const priorityColors = {
low: 'text-gray-600 dark:text-gray-400',
low: 'text-fg-muted dark:text-dark-fg-muted',
medium: 'text-blue-600 dark:text-blue-400',
high: 'text-orange-600 dark:text-orange-400',
urgent: 'text-red-600 dark:text-red-400'
Expand Down Expand Up @@ -212,7 +212,7 @@
}
</script>

<div class="relative">
<div class="relative z-40">
<button
onclick={toggleDropdown}
class="btn btn-ghost btn-icon relative"
Expand All @@ -228,10 +228,10 @@

{#if showDropdown}
<div
class="absolute right-0 mt-2 w-96 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-50"
class="absolute right-0 mt-2 w-96 bg-surface-overlay dark:bg-dark-surface-overlay rounded-lg shadow-lg border border-border-default dark:border-dark-border-default z-50"
transition:fly={{ y: -10, duration: 200 }}
>
<div class="p-4 border-b border-gray-200 dark:border-gray-700">
<div class="p-4 border-b border-border-default dark:border-dark-border-default">
<div class="flex justify-between items-center">
<h3 class="font-semibold text-lg">Notifications</h3>
{#if $unreadCount > 0}
Expand All @@ -251,13 +251,13 @@
<span class="loading loading-spinner loading-sm"></span>
</div>
{:else if $notifications.length === 0}
<div class="p-8 text-center text-gray-500">
<div class="p-8 text-center text-fg-muted dark:text-dark-fg-muted">
No notifications yet
</div>
{:else}
{#each $notifications as notification}
<div
class="p-4 border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors"
class="p-4 border-b border-border-default/50 dark:border-dark-border-default hover:bg-interactive-hover dark:hover:bg-dark-interactive-hover cursor-pointer transition-colors"
class:bg-blue-50={notification.status !== 'read'}
class:dark:bg-blue-900={notification.status !== 'read'}
onclick={() => {
Expand Down Expand Up @@ -297,10 +297,10 @@
<p class="font-medium text-sm">
{notification.subject}
</p>
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
<p class="text-sm text-fg-muted dark:text-dark-fg-muted mt-1">
{notification.body}
</p>
<p class="text-xs text-gray-500 dark:text-gray-500 mt-2">
<p class="text-xs text-fg-subtle dark:text-dark-fg-subtle mt-2">
{formatTime(notification.created_at)}
</p>
</div>
Expand All @@ -313,7 +313,7 @@
{/if}
</div>

<div class="p-3 border-t border-gray-200 dark:border-gray-700">
<div class="p-3 border-t border-border-default dark:border-dark-border-default">
<button
onclick={() => {
showDropdown = false;
Expand All @@ -327,10 +327,3 @@
</div>
{/if}
</div>

<style>
/* Ensure dropdown is above other content */
.relative {
z-index: 40;
}
</style>
2 changes: 1 addition & 1 deletion frontend/src/components/Spinner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
primary: 'text-primary dark:text-primary-light',
white: 'text-white',
current: 'text-current',
muted: 'text-gray-400 dark:text-gray-500'
muted: 'text-fg-subtle dark:text-dark-fg-subtle'
};

let sizeClass = $derived(sizeClasses[size] || sizeClasses.medium);
Expand Down
51 changes: 4 additions & 47 deletions frontend/src/components/ToastContainer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
});

function getToastClasses(type: ToastType): string {
const base = "toast";
const base = "toast-item";
switch (type) {
case 'success':
return `${base} bg-green-50 border-green-200 text-green-800 dark:bg-green-950 dark:border-green-800 dark:text-green-200`;
Expand Down Expand Up @@ -101,7 +101,7 @@
}

function getTimerClasses(type: ToastType): string {
const base = "timer";
const base = "toast-timer";
switch (type) {
case 'success': return `${base} bg-green-300 dark:bg-green-600`;
case 'error': return `${base} bg-red-300 dark:bg-red-600`;
Expand All @@ -112,7 +112,7 @@
}
</script>

<div class="toasts-container">
<div class="toast-container">
{#each toastList as toast (toast.id)}
<div
role="alert"
Expand Down Expand Up @@ -149,47 +149,4 @@
{/if}
</div>
{/each}
</div>

<style>
.toasts-container {
position: fixed;
top: 5rem;
right: 1.5rem;
z-index: 100;
width: 100%;
max-width: 24rem;
pointer-events: none;
}

.toast {
position: relative;
display: flex;
align-items: flex-start;
padding: 1rem;
margin-bottom: 0.75rem;
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
overflow: hidden;
pointer-events: auto;
border-width: 1px;
}

.timer {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
transform-origin: left;
transition: transform 0.1s linear;
}

@media (max-width: 640px) {
.toasts-container {
top: 4.5rem;
left: 1rem;
right: 1rem;
max-width: none;
}
}
</style>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ const iconTestCases = [
];

const priorityTestCases = [
{ severity: 'low' as const, css: '.text-gray-600' },
{ severity: 'low' as const, css: '.text-fg-muted' },
{ severity: 'medium' as const, css: '.text-blue-600' },
{ severity: 'high' as const, css: '.text-orange-600' },
{ severity: 'urgent' as const, css: '.text-red-600' },
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/__tests__/Spinner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('Spinner', () => {
{ color: 'primary', expectedClass: 'text-primary' },
{ color: 'white', expectedClass: 'text-white' },
{ color: 'current', expectedClass: 'text-current' },
{ color: 'muted', expectedClass: 'text-gray-400' },
{ color: 'muted', expectedClass: 'text-fg-subtle' },
] as const)('applies $expectedClass for color="$color"', ({ color, expectedClass }) => {
render(Spinner, { props: { color } });
expect(getSpinner().classList.contains(expectedClass)).toBe(true);
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/__tests__/ToastContainer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('ToastContainer', () => {
describe('rendering', () => {
it('renders empty container when no toasts', () => {
const { container } = render(ToastContainer);
const toastContainer = container.querySelector('.toasts-container');
const toastContainer = container.querySelector('.toast-container');
expect(toastContainer).toBeInTheDocument();
expect(toastContainer?.children.length).toBe(0);
});
Expand Down Expand Up @@ -83,11 +83,11 @@ describe('ToastContainer', () => {
addToast('Timed toast', 'info');

await waitFor(() => {
const timer = screen.getByRole('alert').querySelector('.timer');
const timer = screen.getByRole('alert').querySelector('.toast-timer');
expect(timer).toBeInTheDocument();
});

const timer = screen.getByRole('alert').querySelector('.timer') as HTMLElement;
const timer = screen.getByRole('alert').querySelector('.toast-timer') as HTMLElement;
await vi.advanceTimersByTimeAsync(1000);

await waitFor(() => { expect(timer.style.transform).toContain('scaleX'); });
Expand Down Expand Up @@ -194,8 +194,8 @@ describe('ToastContainer', () => {

// Both toasts should have progress bars
const alerts = screen.getAllByRole('alert');
expect(alerts[0].querySelector('.timer')).toBeInTheDocument();
expect(alerts[1].querySelector('.timer')).toBeInTheDocument();
expect(alerts[0].querySelector('.toast-timer')).toBeInTheDocument();
expect(alerts[1].querySelector('.toast-timer')).toBeInTheDocument();
});

it('cleans up timers on unmount', async () => {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/routes/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@
<input type="file" accept=".py,text/x-python" bind:this={fileInput} class="hidden" onchange={handleFileUpload}/>

<div class="editor-grid-container space-y-4 md:space-y-0 md:gap-6" in:fade={{ duration: 300 }}>
<header class="editor-header flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div class="editor-header flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<h2 class="text-xl sm:text-2xl font-semibold text-fg-default dark:text-dark-fg-default whitespace-nowrap">
Code Editor
</h2>
Expand Down Expand Up @@ -846,7 +846,7 @@
{:else if apiError && !k8sLimits}
<p class="text-xs text-red-600 dark:text-red-400">{apiError}</p>
{/if}
</header>
</div>

<div class="editor-main-code flex flex-col rounded-lg overflow-hidden shadow-md border border-border-default dark:border-dark-border-default">
<div class="editor-toolbar flex items-center justify-between px-3 py-1 bg-bg-default dark:bg-dark-bg-default border-b border-border-default dark:border-dark-border-default shrink-0">
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/routes/Home.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
</script>

{#if ready}
<div class="overflow-x-hidden">
<div>

<!-- HERO SECTION - Enhanced responsiveness -->
<section class="hero-section relative isolate bg-bg-default dark:bg-dark-bg-default min-h-[80vh] flex items-center justify-center px-4 sm:px-6 lg:px-8 xl:px-12 2xl:px-20">
<section class="hero-section relative isolate overflow-x-clip bg-bg-default dark:bg-dark-bg-default min-h-[80vh] flex items-center justify-center px-4 sm:px-6 lg:px-8 xl:px-12 2xl:px-20">
<div class="relative z-10 text-center w-full -mt-4 sm:-mt-6">
<div class="hero-animate-flyIn" style="--fly-y: -20px; --fly-delay: 100ms;">
<h1 class="mx-auto max-w-full xl:max-w-7xl text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl:text-7xl font-bold tracking-tight text-fg-default dark:text-dark-fg-default leading-tight! px-2 sm:px-4">
Expand Down
9 changes: 1 addition & 8 deletions frontend/src/routes/Notifications.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@

// New unified notification rendering: derive icons from tags and colors from severity
const severityColors: Record<string, string> = {
low: 'text-gray-600 dark:text-gray-400',
low: 'text-fg-muted dark:text-dark-fg-muted',
medium: 'text-blue-600 dark:text-blue-400',
high: 'text-orange-600 dark:text-orange-400',
urgent: 'text-red-600 dark:text-red-400'
Expand Down Expand Up @@ -274,10 +274,3 @@
{/if}
</div>
</div>

<style>
/* Ensure dropdown is above other content */
.relative {
z-index: 40;
}
</style>
Loading
Loading