diff --git a/core/http/static/animations.css b/core/http/static/animations.css new file mode 100644 index 000000000000..c0d85eea5a0b --- /dev/null +++ b/core/http/static/animations.css @@ -0,0 +1,247 @@ +/* LocalAI Animation System */ +/* Purposeful animations with performance optimization */ + +/* Animation Keyframes */ +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes cardReveal { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInRight { + from { + opacity: 0; + transform: translateX(-20px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slideInLeft { + from { + opacity: 0; + transform: translateX(20px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +@keyframes glow { + 0%, 100% { + box-shadow: 0 0 8px rgba(56, 189, 248, 0.15); + } + 50% { + box-shadow: 0 0 12px rgba(56, 189, 248, 0.25); + } +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0.95); + } + to { + opacity: 1; + transform: scale(1); + } +} + +/* P2P/Network Specific Animations */ +@keyframes rotateCircleNodes { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +@keyframes shakeFlask { + 0%, 10% { transform: rotate(0deg); } + 20% { transform: rotate(-10deg); } + 30% { transform: rotate(10deg); } + 40% { transform: rotate(-8deg); } + 50% { transform: rotate(8deg); } + 60% { transform: rotate(-5deg); } + 70% { transform: rotate(5deg); } + 80% { transform: rotate(-2deg); } + 90% { transform: rotate(2deg); } + 100% { transform: rotate(0deg); } +} + +@keyframes nodeGlow { + 0% { left: -100%; } + 50% { left: 100%; } + 100% { left: 100%; } +} + +/* Animation Utility Classes */ +.fade-in { + animation: fadeIn var(--duration-fast) var(--ease-out); +} + +/* Transition Utility Classes */ +.transition-default { + transition: all var(--duration-fast) var(--ease-default); +} + +.transition-color { + transition: color var(--duration-fast) var(--ease-default); +} + +.transition-background { + transition: background-color var(--duration-fast) var(--ease-default); +} + +.fade-in-up { + animation: fadeInUp var(--duration-normal) var(--ease-out) backwards; +} + +.fade-in-down { + animation: fadeInDown var(--duration-normal) var(--ease-out) backwards; +} + +.slide-in-right { + animation: slideInRight var(--duration-normal) var(--ease-out) backwards; +} + +.slide-in-left { + animation: slideInLeft var(--duration-normal) var(--ease-out) backwards; +} + +.scale-in { + animation: scaleIn var(--duration-normal) var(--ease-out) backwards; +} + +/* Staggered Card Animations */ +.card-animate { + animation: cardReveal var(--duration-normal) var(--ease-out) backwards; +} + +.card-animate:nth-child(1) { animation-delay: 0ms; } +.card-animate:nth-child(2) { animation-delay: 50ms; } +.card-animate:nth-child(3) { animation-delay: 100ms; } +.card-animate:nth-child(4) { animation-delay: 150ms; } +.card-animate:nth-child(5) { animation-delay: 200ms; } +.card-animate:nth-child(6) { animation-delay: 250ms; } +.card-animate:nth-child(7) { animation-delay: 300ms; } +.card-animate:nth-child(8) { animation-delay: 350ms; } +.card-animate:nth-child(9) { animation-delay: 400ms; } +.card-animate:nth-child(10) { animation-delay: 450ms; } +.card-animate:nth-child(11) { animation-delay: 500ms; } +.card-animate:nth-child(12) { animation-delay: 550ms; } + +/* Hero Text Animation */ +.hero-title { + animation: fadeInUp var(--duration-normal) var(--ease-out) backwards; + animation-delay: 50ms; +} + +.hero-subtitle { + animation: fadeInUp var(--duration-normal) var(--ease-out) backwards; + animation-delay: 100ms; +} + +/* Navigation Animation */ +.nav-fade-in { + animation: fadeIn var(--duration-normal) var(--ease-out) backwards; + animation-delay: 0ms; +} + +/* Loading States - Minimal */ +.pulse-animation { + animation: pulse 1.5s var(--ease-in-out) infinite; +} + +.glow-animation { + animation: glow 1.5s var(--ease-in-out) infinite; +} + +/* Reduced Motion Support */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } + + .card-animate, + .fade-in-up, + .fade-in-down, + .slide-in-right, + .slide-in-left, + .scale-in, + .hero-title, + .hero-subtitle { + animation: none !important; + } +} + +/* Performance Optimization */ +.card-animate, +.fade-in-up, +.fade-in-down, +.slide-in-right, +.slide-in-left, +.scale-in { + will-change: transform, opacity; +} + +/* After animation completes, remove will-change */ +.card-animate.animation-complete, +.fade-in-up.animation-complete, +.fade-in-down.animation-complete, +.slide-in-right.animation-complete, +.slide-in-left.animation-complete, +.scale-in.animation-complete { + will-change: auto; +} + diff --git a/core/http/static/assets/jetbrains-mono-medium.ttf b/core/http/static/assets/jetbrains-mono-medium.ttf new file mode 100644 index 000000000000..51ccd916b8e4 Binary files /dev/null and b/core/http/static/assets/jetbrains-mono-medium.ttf differ diff --git a/core/http/static/assets/jetbrains-mono-regular.ttf b/core/http/static/assets/jetbrains-mono-regular.ttf new file mode 100644 index 000000000000..129e8825b1c3 Binary files /dev/null and b/core/http/static/assets/jetbrains-mono-regular.ttf differ diff --git a/core/http/static/assets/jetbrains-mono-semibold.ttf b/core/http/static/assets/jetbrains-mono-semibold.ttf new file mode 100644 index 000000000000..003757ef66b0 Binary files /dev/null and b/core/http/static/assets/jetbrains-mono-semibold.ttf differ diff --git a/core/http/static/assets/playfair-display-bold.ttf b/core/http/static/assets/playfair-display-bold.ttf new file mode 100644 index 000000000000..0af637249d9f Binary files /dev/null and b/core/http/static/assets/playfair-display-bold.ttf differ diff --git a/core/http/static/assets/playfair-display-regular.ttf b/core/http/static/assets/playfair-display-regular.ttf new file mode 100644 index 000000000000..4ee80fdecc38 Binary files /dev/null and b/core/http/static/assets/playfair-display-regular.ttf differ diff --git a/core/http/static/assets/playfair-display-semibold.ttf b/core/http/static/assets/playfair-display-semibold.ttf new file mode 100644 index 000000000000..784f2a52fbab Binary files /dev/null and b/core/http/static/assets/playfair-display-semibold.ttf differ diff --git a/core/http/static/assets/space-grotesk-bold.ttf b/core/http/static/assets/space-grotesk-bold.ttf new file mode 100644 index 000000000000..f4f80025b75c Binary files /dev/null and b/core/http/static/assets/space-grotesk-bold.ttf differ diff --git a/core/http/static/assets/space-grotesk-medium.ttf b/core/http/static/assets/space-grotesk-medium.ttf new file mode 100644 index 000000000000..6141a5846ffe Binary files /dev/null and b/core/http/static/assets/space-grotesk-medium.ttf differ diff --git a/core/http/static/assets/space-grotesk-regular.ttf b/core/http/static/assets/space-grotesk-regular.ttf new file mode 100644 index 000000000000..576f9b559440 Binary files /dev/null and b/core/http/static/assets/space-grotesk-regular.ttf differ diff --git a/core/http/static/assets/space-grotesk-semibold.ttf b/core/http/static/assets/space-grotesk-semibold.ttf new file mode 100644 index 000000000000..98cdfc620bc3 Binary files /dev/null and b/core/http/static/assets/space-grotesk-semibold.ttf differ diff --git a/core/http/static/components.css b/core/http/static/components.css new file mode 100644 index 000000000000..1ede880934d1 --- /dev/null +++ b/core/http/static/components.css @@ -0,0 +1,441 @@ +/* LocalAI Component Styles */ +/* Buttons, Cards, Inputs, Grid Pattern, Hero Sections */ + +/* ============================================ + Grid Pattern + ============================================ */ +.grid-pattern { + background-image: + linear-gradient(rgba(56, 189, 248, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(56, 189, 248, 0.03) 1px, transparent 1px); + background-size: 20px 20px; + background-position: 0 0, 0 0; +} + +@media (max-width: 640px) { + .grid-pattern { + background-image: + linear-gradient(rgba(56, 189, 248, 0.02) 1px, transparent 1px), + linear-gradient(90deg, rgba(56, 189, 248, 0.02) 1px, transparent 1px); + } +} + +/* ============================================ + Buttons + ============================================ */ +.btn-primary, +button.btn-primary, +a.btn-primary { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 12px 24px; + background: var(--color-primary); + color: var(--color-primary-text); + font-family: var(--font-body); + font-size: var(--text-base); + font-weight: var(--weight-medium); + border: none; + border-radius: var(--radius-md); + cursor: pointer; + transition: background-color var(--duration-fast) var(--ease-default); + text-decoration: none; + box-shadow: var(--shadow-none); +} + +.btn-primary:hover { + background: var(--color-primary-hover); + box-shadow: var(--shadow-subtle); +} + +.btn-primary:focus { + outline: none; + box-shadow: 0 0 0 2px var(--color-border-focus); +} + +.btn-primary:active { + background: var(--color-primary-active); +} + +.btn-primary:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn-secondary, +button.btn-secondary, +a.btn-secondary { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 12px 24px; + background: transparent; + color: var(--color-primary); + font-family: var(--font-body); + font-size: var(--text-base); + font-weight: var(--weight-medium); + border: 1px solid var(--color-border-default); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--duration-fast) var(--ease-default); + text-decoration: none; +} + +.btn-secondary:hover { + background: var(--color-primary-light); + border-color: var(--color-primary-border); +} + +.btn-secondary:focus { + outline: none; + box-shadow: 0 0 0 2px var(--color-border-focus); +} + +.btn-secondary:active { + background: var(--color-primary-light); +} + +.btn-secondary:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn-tertiary, +button.btn-tertiary, +a.btn-tertiary { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 12px 16px; + background: transparent; + color: var(--color-text-secondary); + font-family: var(--font-body); + font-size: var(--text-base); + font-weight: var(--weight-normal); + border: none; + border-radius: var(--radius-md); + cursor: pointer; + transition: color var(--duration-fast) var(--ease-default); + text-decoration: none; +} + +.btn-tertiary:hover { + color: var(--color-text-primary); + background: var(--color-bg-secondary); +} + +.btn-tertiary:focus { + outline: none; + box-shadow: 0 0 0 2px var(--color-border-focus); +} + +.btn-tertiary:active { + color: var(--color-text-primary); +} + +.btn-tertiary:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +/* ============================================ + Cards + ============================================ */ +.card { + background: var(--color-bg-secondary); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + padding: 24px; + box-shadow: var(--shadow-none); + transition: border-color var(--duration-normal) var(--ease-default); +} + +.card:hover { + border-color: var(--color-border-default); +} + +.card:focus-within { + outline: none; + box-shadow: 0 0 0 2px var(--color-border-focus); +} + +.card-active { + border-color: var(--color-primary-border); +} + +.card-elevated { + box-shadow: var(--shadow-subtle); +} + +.card-elevated:hover { + box-shadow: var(--shadow-sm); +} + +/* ============================================ + Input Fields + ============================================ */ +.input, +input[type="text"], +input[type="email"], +input[type="password"], +input[type="number"], +input[type="search"], +input[type="url"], +textarea, +select { + width: 100%; + padding: 0.75rem 1rem; + background: var(--color-bg-secondary); + color: var(--color-text-primary); + font-family: var(--font-body); + font-size: var(--text-base); + border: 1px solid var(--color-border-secondary); + border-radius: var(--radius-md); + transition: all var(--duration-fast) var(--ease-default); + outline: none; +} + +.input::placeholder, +input::placeholder, +textarea::placeholder { + color: var(--color-text-muted); +} + +.input:focus, +input:focus, +textarea:focus, +select:focus { + border-color: var(--color-primary-border); + box-shadow: 0 0 0 3px var(--color-primary-light); + outline: none; +} + +.input:disabled, +input:disabled, +textarea:disabled, +select:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Input States */ +.input-error, +input.input-error, +textarea.input-error { + border-color: var(--color-error); + box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2); +} + +.input-error:focus { + box-shadow: 0 0 0 3px var(--color-error-light); +} + +.input-success, +input.input-success, +textarea.input-success { + border-color: var(--color-success); + box-shadow: 0 0 0 2px var(--color-success-light); +} + +.input-success:focus { + box-shadow: 0 0 0 3px var(--color-success-light); +} + +/* ============================================ + Hero Sections + ============================================ */ +/* ============================================ + Hero Section - Minimal + ============================================ */ +.hero-section { + padding: 0.75rem 0; + margin-bottom: 1.5rem; +} + +.hero-content { + text-align: center; +} + +.hero-title { + font-family: var(--font-body); + font-size: var(--text-2xl); + font-weight: var(--weight-semibold); + line-height: var(--leading-tight); + color: var(--color-text-primary); + letter-spacing: -0.01em; + margin-bottom: 0.5rem; +} + +@media (max-width: 640px) { + .hero-title { + font-size: var(--text-xl); + } +} + +.hero-subtitle { + font-family: var(--font-body); + font-size: var(--text-sm); + font-weight: var(--weight-normal); + color: var(--color-text-secondary); + line-height: var(--leading-normal); + margin: 0; +} + +/* ============================================ + Icon Hover Effects + ============================================ */ +.icon-hover { + transition: all var(--duration-fast) var(--ease-default); + cursor: pointer; +} + +.icon-hover:hover { + transform: scale(1.1); + color: var(--color-primary); +} + +/* ============================================ + Status Badges + ============================================ */ +.badge { + display: inline-flex; + align-items: center; + padding: 4px 12px; + font-family: var(--font-body); + font-size: var(--text-xs); + font-weight: var(--weight-medium); + border-radius: var(--radius-full); + background: var(--color-bg-secondary); + color: var(--color-text-primary); + border: none; +} + +.badge-success { + background: var(--color-success-light); + color: var(--color-success); + border: none; +} + +.badge-warning { + background: var(--color-warning-light); + color: var(--color-warning); + border: none; +} + +.badge-error { + background: var(--color-error-light); + color: var(--color-error); + border: none; +} + +.badge-info { + background: var(--color-info-light); + color: var(--color-info); + border: none; +} + +.badge-gradient { + background: var(--gradient-primary); + color: #FFFFFF; + border: none; +} + +/* ============================================ + Navigation + ============================================ */ +.nav-link { + color: var(--color-text-secondary); + text-decoration: none; + transition: all var(--duration-fast) var(--ease-default); + padding: 0.5rem 1rem; + border-radius: var(--radius-md); +} + +.nav-link:hover { + color: var(--color-text-primary); + background: var(--color-bg-secondary); +} + +.nav-link-active { + color: var(--color-primary); + background: var(--color-primary-light); +} + +.nav-link-active:hover { + color: var(--color-primary-hover); +} + +/* ============================================ + P2P/Network Specific Components + ============================================ */ +.animation-container { + position: relative; + width: 100%; + height: 25vh; + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + background: linear-gradient(135deg, var(--color-bg-primary) 0%, var(--color-bg-secondary) 100%); +} + +.text-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + z-index: 1; +} + +.fa-circle-nodes { + animation: rotateCircleNodes 8s linear infinite; + display: inline-block; + filter: drop-shadow(0 0 8px var(--color-primary)); +} + +.fa-flask { + animation: shakeFlask 3s ease-in-out infinite; + transform-origin: bottom center; +} + +.active-node { + position: relative; + overflow: hidden; +} + +.active-node::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 2px; + background: linear-gradient(90deg, transparent, var(--color-primary), transparent); + animation: nodeGlow 3s ease-in-out infinite; +} + +/* ============================================ + Responsive Adjustments + ============================================ */ +@media (max-width: 640px) { + .btn-primary, + .btn-secondary, + .btn-tertiary { + padding: 0.625rem 1.25rem; + font-size: var(--text-sm); + } + + .card { + padding: 1rem; + } + + .hero-section { + padding: 0.5rem 0; + margin-bottom: 1rem; + } +} + diff --git a/core/http/static/general.css b/core/http/static/general.css index f3ef85739a72..f0de5397abc5 100644 --- a/core/http/static/general.css +++ b/core/http/static/general.css @@ -1,5 +1,5 @@ body { - font-family: 'Inter', sans-serif; + font-family: var(--font-body, 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif); } .chat-container { height: 90vh; display: flex; flex-direction: column; } .chat-messages { overflow-y: auto; flex-grow: 1; } @@ -79,3 +79,28 @@ li { li:last-child { margin-bottom: 0; /* Removes bottom margin from the last item */ } + +/* Scrollbar Styling - Minimal */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: var(--color-bg-primary); +} + +::-webkit-scrollbar-thumb { + background: var(--color-bg-secondary); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--color-primary); +} + +/* Firefox */ +* { + scrollbar-width: thin; + scrollbar-color: var(--color-bg-secondary) var(--color-bg-primary); +} diff --git a/core/http/static/theme.css b/core/http/static/theme.css new file mode 100644 index 000000000000..229987b33805 --- /dev/null +++ b/core/http/static/theme.css @@ -0,0 +1,113 @@ +/* LocalAI Theme - CSS Variables System */ +/* Based on logo color palette: cyan, teal, navy, purple */ + +:root { + /* Base Colors */ + --color-bg-primary: #0F172A; /* Deep navy background */ + --color-bg-secondary: #1E293B; /* Elevated surfaces */ + --color-bg-tertiary: #1E293B; /* Cards, panels */ + --color-bg-overlay: rgba(15, 23, 42, 0.8); /* Modals, overlays */ + + /* Brand Colors */ + --color-primary: #38BDF8; /* Cyan - primary actions */ + --color-primary-hover: #0EA5E9; /* Darker cyan on hover */ + --color-primary-active: #0284C7; /* Active state */ + --color-primary-text: #FFFFFF; /* Text on primary background */ + --color-primary-light: rgba(56, 189, 248, 0.08); /* Light cyan backgrounds (reduced) */ + --color-primary-border: rgba(56, 189, 248, 0.15); /* Cyan borders (reduced) */ + + --color-secondary: #14B8A6; /* Teal - secondary actions */ + --color-secondary-hover: #0D9488; /* Darker teal on hover */ + --color-secondary-light: rgba(20, 184, 166, 0.1); + + --color-accent: #8B5CF6; /* Purple - special states */ + --color-accent-hover: #7C3AED; /* Darker purple on hover */ + --color-accent-light: rgba(139, 92, 246, 0.1); + + --color-accent-purple: #A78BFA; /* Light purple for gradients */ + --color-accent-teal: #2DD4BF; /* Light teal for gradients */ + + /* Text Colors */ + --color-text-primary: #E5E7EB; /* Primary text */ + --color-text-secondary: #94A3B8; /* Secondary text */ + --color-text-muted: #64748B; /* Tertiary text */ + --color-text-disabled: #475569; /* Disabled text */ + --color-text-inverse: #0F172A; /* Text on light backgrounds */ + + /* Border Colors - Minimal System */ + --color-border-subtle: rgba(148, 163, 184, 0.08); /* Minimal borders */ + --color-border-default: rgba(148, 163, 184, 0.12); /* Default borders */ + --color-border-strong: rgba(56, 189, 248, 0.2); /* Focus borders */ + --color-border-divider: rgba(148, 163, 184, 0.06); /* Section dividers */ + --color-border-primary: rgba(56, 189, 248, 0.15); /* Primary borders (reduced opacity) */ + --color-border-secondary: rgba(148, 163, 184, 0.1); + --color-border-focus: rgba(56, 189, 248, 0.3); /* Focus borders (reduced) */ + + /* Status Colors */ + --color-success: #14B8A6; /* Use teal for success (aligned with logo) */ + --color-success-light: rgba(20, 184, 166, 0.1); + --color-warning: #F59E0B; + --color-warning-light: rgba(245, 158, 11, 0.1); + --color-error: #EF4444; + --color-error-light: rgba(239, 68, 68, 0.1); + --color-info: #38BDF8; /* Use cyan for info */ + --color-info-light: rgba(56, 189, 248, 0.1); + + /* Gradient Definitions */ + --gradient-primary: linear-gradient(135deg, #38BDF8 0%, #8B5CF6 50%, #14B8A6 100%); + --gradient-hero: linear-gradient(135deg, #0F172A 0%, #1E293B 50%, #0F172A 100%); + --gradient-card: linear-gradient(135deg, rgba(56, 189, 248, 0.05) 0%, rgba(139, 92, 246, 0.05) 100%); + --gradient-text: linear-gradient(135deg, #38BDF8 0%, #8B5CF6 50%, #14B8A6 100%); + + /* Shadows - Minimal System */ + --shadow-none: none; + --shadow-subtle: 0 1px 2px rgba(0, 0, 0, 0.1); + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12); + --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); + --shadow-glow: 0 0 0 1px rgba(56, 189, 248, 0.1), 0 0 8px rgba(56, 189, 248, 0.15); /* Minimal glow */ + + /* Animation Timing - Minimal */ + --duration-instant: 100ms; + --duration-fast: 150ms; + --duration-normal: 200ms; + --duration-slow: 300ms; + + /* Animation Easing */ + --ease-default: cubic-bezier(0.4, 0, 0.2, 1); + --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, 0.2, 1); + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + --ease-spring: cubic-bezier(0.68, -0.55, 0.265, 1.55); + + /* Spacing Scale (for reference, used via Tailwind) */ + --spacing-xs: 0.25rem; /* 4px */ + --spacing-sm: 0.5rem; /* 8px */ + --spacing-md: 1rem; /* 16px */ + --spacing-lg: 1.5rem; /* 24px */ + --spacing-xl: 2rem; /* 32px */ + --spacing-2xl: 3rem; /* 48px */ + --spacing-3xl: 4rem; /* 64px */ + + /* Border Radius */ + --radius-none: 0; + --radius-sm: 4px; + --radius-md: 6px; /* Updated per PRD */ + --radius-lg: 8px; + --radius-xl: 12px; + --radius-full: 9999px; + + /* Width System - Container Sizes */ + --width-xs: 20rem; /* 320px */ + --width-sm: 24rem; /* 384px */ + --width-md: 28rem; /* 448px */ + --width-lg: 32rem; /* 512px */ + --width-xl: 36rem; /* 576px */ + --width-2xl: 42rem; /* 672px */ + --width-3xl: 48rem; /* 768px */ + --width-4xl: 56rem; /* 896px */ + --width-5xl: 64rem; /* 1024px */ + --width-6xl: 72rem; /* 1152px */ + --width-7xl: 80rem; /* 1280px */ +} + diff --git a/core/http/static/typography.css b/core/http/static/typography.css new file mode 100644 index 000000000000..763c280377ee --- /dev/null +++ b/core/http/static/typography.css @@ -0,0 +1,195 @@ +/* LocalAI Typography System */ +/* Font-face declarations and typography variables */ + +/* Playfair Display - Display/Headline Font */ +@font-face { + font-family: 'Playfair Display'; + src: url('/static/assets/playfair-display-regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Playfair Display'; + src: url('/static/assets/playfair-display-semibold.ttf') format('truetype'); + font-weight: 600; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Playfair Display'; + src: url('/static/assets/playfair-display-bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +/* Space Grotesk - Body Font */ +@font-face { + font-family: 'Space Grotesk'; + src: url('/static/assets/space-grotesk-regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Space Grotesk'; + src: url('/static/assets/space-grotesk-medium.ttf') format('truetype'); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Space Grotesk'; + src: url('/static/assets/space-grotesk-semibold.ttf') format('truetype'); + font-weight: 600; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Space Grotesk'; + src: url('/static/assets/space-grotesk-bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +/* JetBrains Mono - Monospace Font */ +@font-face { + font-family: 'JetBrains Mono'; + src: url('/static/assets/jetbrains-mono-regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'JetBrains Mono'; + src: url('/static/assets/jetbrains-mono-medium.ttf') format('truetype'); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'JetBrains Mono'; + src: url('/static/assets/jetbrains-mono-semibold.ttf') format('truetype'); + font-weight: 600; + font-style: normal; + font-display: swap; +} + +:root { + /* Font Families */ + --font-display: 'Playfair Display', serif; + --font-body: 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif; + --font-mono: 'JetBrains Mono', 'Fira Code', monospace; + + /* Font Sizes */ + --text-xs: 0.75rem; /* 12px */ + --text-sm: 0.875rem; /* 14px */ + --text-base: 1rem; /* 16px */ + --text-lg: 1.125rem; /* 18px */ + --text-xl: 1.25rem; /* 20px */ + --text-2xl: 1.5rem; /* 24px */ + --text-3xl: 1.875rem; /* 30px */ + --text-4xl: 2.25rem; /* 36px */ + --text-5xl: 3rem; /* 48px */ + --text-6xl: 3.75rem; /* 60px */ + --text-7xl: 4.5rem; /* 72px */ + + /* Line Heights */ + --leading-tight: 1.25; + --leading-snug: 1.375; + --leading-normal: 1.5; + --leading-relaxed: 1.625; + --leading-loose: 2; + + /* Font Weights */ + --weight-light: 300; + --weight-normal: 400; + --weight-medium: 500; + --weight-semibold: 600; + --weight-bold: 700; + --weight-extrabold: 800; +} + +/* Base typography */ +body { + font-family: var(--font-body); + font-size: var(--text-base); + line-height: var(--leading-normal); + color: var(--color-text-primary); +} + +/* Headings */ +h1, .h1 { + font-family: var(--font-body); + font-size: var(--text-4xl); + font-weight: var(--weight-bold); + line-height: var(--leading-tight); + letter-spacing: -0.02em; +} + +h2, .h2 { + font-family: var(--font-body); + font-size: var(--text-3xl); + font-weight: var(--weight-semibold); + line-height: var(--leading-snug); + letter-spacing: -0.01em; +} + +h3, .h3 { + font-family: var(--font-body); + font-size: var(--text-2xl); + font-weight: var(--weight-semibold); + line-height: var(--leading-snug); +} + +h4, .h4 { + font-family: var(--font-body); + font-size: var(--text-xl); + font-weight: var(--weight-semibold); + line-height: var(--leading-normal); +} + +h5, .h5 { + font-family: var(--font-body); + font-size: var(--text-lg); + font-weight: var(--weight-medium); + line-height: var(--leading-normal); +} + +h6, .h6 { + font-family: var(--font-body); + font-size: var(--text-base); + font-weight: var(--weight-medium); + line-height: var(--leading-normal); +} + +/* Code and monospace */ +code, pre, kbd, samp { + font-family: var(--font-mono); + font-size: 0.9em; +} + +/* Responsive typography adjustments */ +@media (max-width: 640px) { + h1, .h1 { + font-size: var(--text-3xl); + } + + h2, .h2 { + font-size: var(--text-2xl); + } + + h3, .h3 { + font-size: var(--text-xl); + } +} + diff --git a/core/http/views/404.html b/core/http/views/404.html index 231d85b0e456..97761b58574d 100644 --- a/core/http/views/404.html +++ b/core/http/views/404.html @@ -14,10 +14,8 @@
The page you're looking for doesn't exist or has been moved
Live job status, reasoning traces, and execution details
+Live job status, reasoning traces, and execution details
The original prompt template from the task definition.
@@ -97,7 +96,7 @@The prompt with parameters substituted, as it was sent to the agent.
@@ -110,7 +109,7 @@Manage agent tasks and monitor job execution
+Manage agent tasks and monitor job execution
+
To use Agent Jobs, you need to install a model first. Agent Jobs require models with MCP (Model Context Protocol) configuration.
Browse and install pre-configured models
+Browse and install pre-configured models
Upload your own model files
+Upload your own model files
Use the API to download models programmatically
+Use the API to download models programmatically
Browse the Model Gallery
-Explore our curated collection of pre-configured models. Find models for chat, image generation, audio processing, and more.
+Browse the Model Gallery
+Explore our curated collection of pre-configured models. Find models for chat, image generation, audio processing, and more.
Install a Model
-Click on a model from the gallery to install it, or use the import feature to upload your own model files.
+Install a Model
+Click on a model from the gallery to install it, or use the import feature to upload your own model files.
Configure MCP
-After installing a model, configure MCP (Model Context Protocol) to enable Agent Jobs functionality.
+Configure MCP
+After installing a model, configure MCP (Model Context Protocol) to enable Agent Jobs functionality.
+
You have models installed, but none have MCP (Model Context Protocol) enabled. Agent Jobs require MCP to function.
-Edit a Model Configuration
-Click "Configure MCP" on any model above, or navigate to the model editor to add MCP configuration.
+Edit a Model Configuration
+Click "Configure MCP" on any model above, or navigate to the model editor to add MCP configuration.
Add MCP Configuration
-In the model YAML, add MCP server or stdio configuration. See the documentation for detailed examples.
+Add MCP Configuration
+In the model YAML, add MCP server or stdio configuration. See the documentation for detailed examples.
Save and Return
-After saving the MCP configuration, return to this page to create your first Agent Job task.
+Save and Return
+After saving the MCP configuration, return to this page to create your first Agent Job task.
| Name | -Model | -Cron | -Status | -Actions | +|||||
|---|---|---|---|---|---|---|---|---|---|
| Name | +Model | +Cron | +Status | +Actions | |||||
| - + | - - - + + - | Tasks | |||||||
| + | No tasks found. Create one | ||||||||