diff --git a/client/src/components/layout/AppShell.tsx b/client/src/components/layout/AppShell.tsx
index f0e4ae0..b696b18 100644
--- a/client/src/components/layout/AppShell.tsx
+++ b/client/src/components/layout/AppShell.tsx
@@ -1,13 +1,15 @@
/**
- * AppShell — 3-Spalten-Layout
- * Bloomberg Terminal × Raumschiff-Brücke
- *
- * Layout: Sidebar (160px) | Content (flex-grow) | CoPilot (320px)
+ * AppShell — Responsive Layout
+ * Desktop: Sidebar (160px) | Content | CoPilot (320px)
+ * Mobile: Top-Bar | Content | Bottom-Nav + Slide-up CoPilot
*/
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import { Sidebar } from './Sidebar';
+import { BottomNav } from './BottomNav';
import { CoPilotPanel } from './CoPilotPanel';
+import { CoPilotSheet } from './CoPilotSheet';
+import { Sparkles, Menu } from 'lucide-react';
interface AppShellProps {
children: React.ReactNode;
@@ -15,113 +17,170 @@ interface AppShellProps {
}
export function AppShell({ children, currentPath }: AppShellProps) {
- const [copilotOpen, setCopilotOpen] = useState(true);
+ const [copilotOpen, setCopilotOpen] = useState(false);
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
+ const [isMobile, setIsMobile] = useState(false);
+
+ useEffect(() => {
+ const check = () => setIsMobile(window.innerWidth < 1024);
+ check();
+ window.addEventListener('resize', check);
+ return () => window.removeEventListener('resize', check);
+ }, []);
+
+ // Desktop: Co-Pilot default open
+ useEffect(() => {
+ if (!isMobile) setCopilotOpen(true);
+ else setCopilotOpen(false);
+ }, [isMobile]);
return (
-
- {/* Left Sidebar Navigation */}
-
-
- {/* Main Content Area */}
-
- {/* Top Bar */}
-
-
-
+ {/* Mobile: Hamburger */}
+ {isMobile && (
+
- ›
-
- Social Command Center
+
+
+ )}
+
+ ATLAS OS
+
+ ›
+
+ Social
+
+
+
+ {/* Right: Status + Clock + CoPilot Toggle */}
+
+
-
-
- {/* System Status */}
-
-
-
+
+
+
+ {/* Co-Pilot Toggle */}
+
+
+
+
+ {/* ── MAIN BODY ── */}
+
+ {/* Desktop Sidebar */}
+ {!isMobile && (
+
+ )}
+
+ {/* Mobile Slide-out Sidebar */}
+ {isMobile && mobileMenuOpen && (
+ <>
+
setMobileMenuOpen(false)}
/>
-
- {/* Live Clock */}
-
-
-
-
- {/* Co-Pilot Toggle */}
-
-
- {/* Page Content */}
-
- {children}
-
-
-
- {/* Right Co-Pilot Panel */}
- {copilotOpen && (
-
setCopilotOpen(false)} />
+
+
+ {/* Desktop Co-Pilot Panel */}
+ {!isMobile && copilotOpen && (
+ setCopilotOpen(false)} />
+ )}
+
+
+ {/* ── MOBILE BOTTOM NAV ── */}
+ {isMobile && (
+
+ )}
+
+ {/* ── MOBILE CO-PILOT SHEET ── */}
+ {isMobile && (
+
setCopilotOpen(false)} />
)}
);
}
-function LiveClock() {
+function LiveClock({ className = '' }: { className?: string }) {
const [time, setTime] = useState(new Date());
-
- // Update every second
- useState(() => {
+
+ useEffect(() => {
const interval = setInterval(() => setTime(new Date()), 1000);
return () => clearInterval(interval);
- });
-
+ }, []);
+
return (
-
{time.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
diff --git a/client/src/components/layout/BottomNav.tsx b/client/src/components/layout/BottomNav.tsx
new file mode 100644
index 0000000..7636e8e
--- /dev/null
+++ b/client/src/components/layout/BottomNav.tsx
@@ -0,0 +1,84 @@
+/**
+ * BottomNav — Mobile Bottom Navigation
+ * Zeigt die 5 wichtigsten Seiten als Icons
+ * "Mehr" öffnet das volle Menü
+ */
+
+import { Link } from 'wouter';
+import {
+ LayoutDashboard,
+ Zap,
+ FileEdit,
+ Calendar,
+ BarChart2,
+} from 'lucide-react';
+
+interface BottomNavProps {
+ currentPath: string;
+}
+
+const primaryNav = [
+ { label: 'War Room', path: '/', icon: LayoutDashboard },
+ { label: 'Signale', path: '/signals', icon: Zap },
+ { label: 'Drafts', path: '/drafts', icon: FileEdit },
+ { label: 'Kalender', path: '/calendar', icon: Calendar },
+ { label: 'Analytics', path: '/analytics', icon: BarChart2 },
+];
+
+export function BottomNav({ currentPath }: BottomNavProps) {
+ return (
+
+ );
+}
diff --git a/client/src/components/layout/CoPilotSheet.tsx b/client/src/components/layout/CoPilotSheet.tsx
new file mode 100644
index 0000000..e94ce16
--- /dev/null
+++ b/client/src/components/layout/CoPilotSheet.tsx
@@ -0,0 +1,71 @@
+/**
+ * CoPilotSheet — Mobile Slide-up Sheet für den Co-Pilot
+ * Öffnet von unten als Overlay auf Mobile
+ */
+
+import { useEffect, useRef } from 'react';
+import { CoPilotPanel } from './CoPilotPanel';
+
+interface CoPilotSheetProps {
+ open: boolean;
+ onClose: () => void;
+}
+
+export function CoPilotSheet({ open, onClose }: CoPilotSheetProps) {
+ const overlayRef = useRef(null);
+
+ // Prevent body scroll when open
+ useEffect(() => {
+ if (open) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = '';
+ }
+ return () => { document.body.style.overflow = ''; };
+ }, [open]);
+
+ if (!open) return null;
+
+ return (
+ <>
+ {/* Backdrop */}
+
+
+ {/* Sheet */}
+
+ {/* Drag Handle */}
+
+
+ {/* Co-Pilot Panel — full height */}
+
+
+
+
+ >
+ );
+}
diff --git a/client/src/components/layout/Sidebar.tsx b/client/src/components/layout/Sidebar.tsx
index 2ee7be2..f35b66e 100644
--- a/client/src/components/layout/Sidebar.tsx
+++ b/client/src/components/layout/Sidebar.tsx
@@ -48,9 +48,10 @@ const systemNav: NavItem[] = [
interface SidebarProps {
currentPath: string;
+ onNavigate?: () => void;
}
-export function Sidebar({ currentPath }: SidebarProps) {
+export function Sidebar({ currentPath, onNavigate }: SidebarProps) {
return (
@@ -99,7 +100,7 @@ export function Sidebar({ currentPath }: SidebarProps) {
Content
{contentNav.map(item => (
-
+
))}
@@ -108,7 +109,7 @@ export function Sidebar({ currentPath }: SidebarProps) {
{/* System Section */}
{systemNav.map(item => (
-
+
))}
@@ -170,7 +171,7 @@ export function Sidebar({ currentPath }: SidebarProps) {
);
}
-function NavLink({ item, currentPath }: { item: NavItem; currentPath: string }) {
+function NavLink({ item, currentPath, onNavigate }: { item: NavItem; currentPath: string; onNavigate?: () => void }) {
const isActive = item.path === '/'
? currentPath === '/'
: currentPath.startsWith(item.path);
@@ -179,7 +180,7 @@ function NavLink({ item, currentPath }: { item: NavItem; currentPath: string })
return (
-
+
{item.label}
diff --git a/client/src/index.css b/client/src/index.css
index 5f4a5ea..bbfa663 100644
--- a/client/src/index.css
+++ b/client/src/index.css
@@ -491,3 +491,155 @@
animation: none;
}
}
+
+/* ── Mobile Animations ── */
+@keyframes slideInLeft {
+ from { transform: translateX(-100%); opacity: 0; }
+ to { transform: translateX(0); opacity: 1; }
+}
+@keyframes slideInUp {
+ from { transform: translateY(100%); opacity: 0; }
+ to { transform: translateY(0); opacity: 1; }
+}
+
+/* ── Mobile Responsive Overrides ── */
+@media (max-width: 1023px) {
+ /* KPI Cards — horizontal scroll on mobile */
+ .atlas-kpi-grid {
+ display: flex !important;
+ overflow-x: auto !important;
+ gap: 0.75rem !important;
+ padding-bottom: 0.5rem !important;
+ scrollbar-width: none !important;
+ -ms-overflow-style: none !important;
+ }
+ .atlas-kpi-grid::-webkit-scrollbar { display: none; }
+ .atlas-kpi-grid > * {
+ flex-shrink: 0 !important;
+ min-width: 160px !important;
+ }
+
+ /* Tables — horizontal scroll */
+ .atlas-table-container {
+ overflow-x: auto !important;
+ -webkit-overflow-scrolling: touch !important;
+ }
+
+ /* Page padding — tighter on mobile */
+ .atlas-page {
+ padding: 1rem !important;
+ }
+
+ /* Charts — full width */
+ .atlas-chart-grid {
+ grid-template-columns: 1fr !important;
+ }
+
+ /* Signal Cards — single column */
+ .atlas-signal-grid {
+ grid-template-columns: 1fr !important;
+ }
+
+ /* Campaign Cards — single column */
+ .atlas-campaign-grid {
+ grid-template-columns: 1fr !important;
+ }
+
+ /* Draft Studio — stacked layout */
+ .atlas-draft-layout {
+ flex-direction: column !important;
+ }
+ .atlas-draft-editor {
+ width: 100% !important;
+ max-height: 50vh !important;
+ overflow-y: auto !important;
+ }
+ .atlas-draft-preview {
+ width: 100% !important;
+ }
+
+ /* Calendar — compact */
+ .atlas-calendar-grid {
+ font-size: 0.7rem !important;
+ }
+ .atlas-calendar-cell {
+ min-height: 60px !important;
+ padding: 0.25rem !important;
+ }
+
+ /* Co-Pilot Panel — full width on mobile (via Sheet) */
+ .atlas-copilot-desktop {
+ display: none !important;
+ }
+
+ /* Top bar breadcrumb — compact */
+ .atlas-topbar-breadcrumb {
+ display: none !important;
+ }
+
+ /* Sidebar — hidden on mobile (use BottomNav) */
+ .atlas-sidebar-desktop {
+ display: none !important;
+ }
+}
+
+/* ── Touch Optimizations ── */
+@media (hover: none) and (pointer: coarse) {
+ /* Larger tap targets */
+ .atlas-nav-item {
+ min-height: 44px !important;
+ padding: 0.625rem 0.75rem !important;
+ }
+ button {
+ min-height: 36px;
+ }
+ /* Remove hover states that don't apply on touch */
+ .atlas-nav-item:hover {
+ background: transparent !important;
+ }
+ .atlas-nav-item.active {
+ background: oklch(0.82 0.18 210 / 0.1) !important;
+ }
+}
+
+/* ── KPI horizontal scroll on mobile ── */
+.atlas-kpi-scroll {
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+}
+.atlas-kpi-scroll::-webkit-scrollbar { display: none; }
+.atlas-kpi-scroll > * {
+ min-width: 150px;
+}
+
+/* ── Tables: horizontal scroll wrapper ── */
+.atlas-table-scroll {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+}
+.atlas-table-scroll table {
+ min-width: 600px;
+}
+
+/* ── Page padding responsive ── */
+@media (max-width: 640px) {
+ .p-5 { padding: 0.875rem !important; }
+ .p-4 { padding: 0.75rem !important; }
+ .space-y-5 > * + * { margin-top: 0.875rem !important; }
+ .space-y-4 > * + * { margin-top: 0.75rem !important; }
+
+ /* Header: hide subtitle on very small screens */
+ .atlas-page-subtitle {
+ display: none;
+ }
+
+ /* Compact header on mobile */
+ .atlas-page-header {
+ flex-direction: column !important;
+ align-items: flex-start !important;
+ gap: 0.5rem !important;
+ }
+ .atlas-page-header > div:last-child {
+ flex-wrap: wrap;
+ }
+}
diff --git a/client/src/pages/Analytics.tsx b/client/src/pages/Analytics.tsx
index 3dc7471..c3bc630 100644
--- a/client/src/pages/Analytics.tsx
+++ b/client/src/pages/Analytics.tsx
@@ -106,7 +106,7 @@ export default function Analytics() {
{/* KPI Bar */}
-
+
{[
{ label: 'Reichweite gesamt', value: '2,48 Mio.', trend: '↑ 28%', color: '#60a5fa', icon: '👥' },
{ label: 'Engagement-Rate', value: '4,32 %', trend: '↑ 15%', color: '#e1306c', icon: '❤️' },
@@ -126,9 +126,9 @@ export default function Analytics() {
{/* Charts Row */}
-
+
{/* Performance über Zeit */}
-
+
Performance über Zeit
@@ -202,9 +202,9 @@ export default function Analytics() {
{/* Content Performance Table + Funnel */}
-
+
{/* Table */}
-
+
Content Performance
@@ -214,7 +214,7 @@ export default function Analytics() {
-
+
{['Inhalt', 'Plattform', 'Impressionen', 'Engagement', 'Klicks', 'Umsatz'].map(h => (
diff --git a/client/src/pages/Approvals.tsx b/client/src/pages/Approvals.tsx
index ab9a7b5..23e5d71 100644
--- a/client/src/pages/Approvals.tsx
+++ b/client/src/pages/Approvals.tsx
@@ -81,7 +81,7 @@ export default function Approvals() {
{/* KPI Bar */}
-
+
{[
{ label: 'Offene Freigaben', value: '48', trend: '↑ 12% vs. gestern', color: '#a78bfa' },
{ label: 'Dringend', value: '7', trend: '↑ 75% vs. gestern', color: '#ef4444' },
@@ -131,7 +131,7 @@ export default function Approvals() {
Freigaben-Queue (48)
-
+
{['Priorität', 'Vorschau', 'Titel', 'Plattform', 'Produkt', 'Affiliate', 'Geplant für', 'Erstellt von', 'Status', 'Aktionen'].map(h => (
diff --git a/client/src/pages/Calendar.tsx b/client/src/pages/Calendar.tsx
index e3d9477..9b17fee 100644
--- a/client/src/pages/Calendar.tsx
+++ b/client/src/pages/Calendar.tsx
@@ -125,7 +125,7 @@ export default function Calendar() {
{/* KPI Bar */}
-
+
{[
{ label: 'Geplante Beiträge', value: '24', trend: '↑ 14% vs. letzte Woche', color: '#60a5fa' },
{ label: 'Ausstehende Freigaben', value: '7', trend: '↑ 2 vs. letzte Woche', color: '#a78bfa' },
diff --git a/client/src/pages/Campaigns.tsx b/client/src/pages/Campaigns.tsx
index dbdb2b5..37065df 100644
--- a/client/src/pages/Campaigns.tsx
+++ b/client/src/pages/Campaigns.tsx
@@ -82,7 +82,7 @@ export default function Campaigns() {
{/* KPI Bar */}
-
+
{[
{ label: 'Aktive Kampagnen', value: '12', trend: '↑ 20% vs. letzte Woche', color: '#60a5fa' },
{ label: 'Geplante Assets', value: '86', trend: '↑ 16% vs. letzte Woche', color: '#a78bfa' },
@@ -103,7 +103,7 @@ export default function Campaigns() {
Kampagnen-Übersicht
-
+
{CAMPAIGNS.map(c => (
diff --git a/client/src/pages/Drafts.tsx b/client/src/pages/Drafts.tsx
index 3ea851e..80bb0e0 100644
--- a/client/src/pages/Drafts.tsx
+++ b/client/src/pages/Drafts.tsx
@@ -187,7 +187,7 @@ export default function Drafts() {
-
+
Campaign
@@ -260,7 +260,7 @@ export default function Drafts() {
{/* Freigabe Status */}
-
+
Status
Entwurf
diff --git a/client/src/pages/Products.tsx b/client/src/pages/Products.tsx
index bd7f790..9c6ed7e 100644
--- a/client/src/pages/Products.tsx
+++ b/client/src/pages/Products.tsx
@@ -74,7 +74,7 @@ export default function Products() {
{/* KPI Bar */}
-
+
{[
{ label: 'Produkte aktiv', value: '156', trend: '↑ 12% vs. letzte Woche', color: '#60a5fa' },
{ label: 'Mit Affiliate-Link', value: '128', trend: '↑ 18% vs. letzte Woche', color: '#a78bfa' },
@@ -124,7 +124,7 @@ export default function Products() {
{/* Product Table */}
-
+
{['Produkt', 'Kategorie', 'Preis', 'Händler', 'Verfügbarkeit', 'Content Score ⓘ', 'Affiliate', 'Aktionen'].map(h => (
diff --git a/client/src/pages/Settings.tsx b/client/src/pages/Settings.tsx
index f18a78a..c583d67 100644
--- a/client/src/pages/Settings.tsx
+++ b/client/src/pages/Settings.tsx
@@ -68,7 +68,7 @@ export default function Settings() {
{/* KPI Bar */}
-
+
{[
{ label: 'Verbundene Kanäle', value: '5 / 5', sub: 'Alle Systeme verbunden', color: '#10b981' },
{ label: 'Integrationen aktiv', value: '6 / 8', sub: '75% aktiv', color: '#a78bfa' },
@@ -102,7 +102,7 @@ export default function Settings() {
{/* Content Grid */}
-
+
{/* Verbundene Kanäle */}
@@ -194,7 +194,7 @@ export default function Settings() {
Branding & Assets
-
+
Logo (Standard)
@@ -290,7 +290,7 @@ export default function Settings() {
System-Health & Sync-Status
-
+
{HEALTH_ITEMS.map(item => (
diff --git a/client/src/pages/Signals.tsx b/client/src/pages/Signals.tsx
index 44f4c6c..d0038ec 100644
--- a/client/src/pages/Signals.tsx
+++ b/client/src/pages/Signals.tsx
@@ -165,7 +165,7 @@ export default function Signals() {
{/* Signal Cards Grid */}
-
+
{filtered.map((signal, i) => (
{/* KPI Cards */}
-
+
}
iconBg="oklch(0.6 0.15 250 / 0.15)"
@@ -290,7 +290,7 @@ export default function WarRoom() {
-
+
{SIGNAL_CARDS.map((card, i) => (
{/* Bottom Row: Pipeline + Kanal-Status */}
-