chore: mini-openclaw 初始版本
Next.js 前端 + FastAPI/LangChain 后端透明 agent平台 - 含 .gitignore, 敏感文件(sessions数据/.env/venv等)已排除 - 待后续添加 trajectory 自进化机制
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--bg-primary: #f5f5f7;
|
||||
--text-primary: #1d1d1f;
|
||||
--text-secondary: #86868b;
|
||||
--accent: #002fa7;
|
||||
--accent-light: #e8edff;
|
||||
--accent-orange: #ff6723;
|
||||
}
|
||||
|
||||
html, body { height: 100%; overflow: hidden; }
|
||||
|
||||
body {
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", "Segoe UI", Roboto, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ── Layered background ─────────────────────────────── */
|
||||
.app-bg {
|
||||
background:
|
||||
radial-gradient(ellipse 80% 50% at 50% -10%, rgba(0, 47, 167, 0.05) 0%, transparent 60%),
|
||||
radial-gradient(ellipse 50% 40% at 100% 100%, rgba(255, 103, 35, 0.03) 0%, transparent 50%),
|
||||
linear-gradient(180deg, #f8f8fa 0%, #f0f0f3 100%);
|
||||
}
|
||||
|
||||
/* ── Glass variants ─────────────────────────────────── */
|
||||
.glass-nav {
|
||||
background: rgba(255,255,255,0.78);
|
||||
backdrop-filter: blur(40px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(40px) saturate(180%);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
.glass-panel {
|
||||
background: rgba(255,255,255,0.68);
|
||||
backdrop-filter: blur(28px) saturate(160%);
|
||||
-webkit-backdrop-filter: blur(28px) saturate(160%);
|
||||
}
|
||||
|
||||
.glass-input {
|
||||
background: rgba(255,255,255,0.72);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(0,0,0,0.06);
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* ── Scrollbar ──────────────────────────────────────── */
|
||||
::-webkit-scrollbar { width: 5px; height: 5px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.10); border-radius: 10px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.18); }
|
||||
|
||||
/* ── Scroll shadow overlay (top/bottom) ─────────────── */
|
||||
.scroll-shadow {
|
||||
position: relative;
|
||||
}
|
||||
.scroll-shadow::before,
|
||||
.scroll-shadow::after {
|
||||
content: '';
|
||||
position: absolute; left: 0; right: 0; height: 24px;
|
||||
pointer-events: none; z-index: 2;
|
||||
}
|
||||
.scroll-shadow::before {
|
||||
top: 0;
|
||||
background: linear-gradient(to bottom, rgba(245,245,247,0.8), transparent);
|
||||
}
|
||||
.scroll-shadow::after {
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(245,245,247,0.8), transparent);
|
||||
}
|
||||
|
||||
/* ── Markdown ───────────────────────────────────────── */
|
||||
.markdown-content h1 { font-size: 1.35em; font-weight: 700; margin: 0.5em 0 0.3em; }
|
||||
.markdown-content h2 { font-size: 1.15em; font-weight: 600; margin: 0.4em 0 0.3em; }
|
||||
.markdown-content h3 { font-size: 1.05em; font-weight: 600; margin: 0.3em 0 0.2em; }
|
||||
.markdown-content p { margin: 0.35em 0; line-height: 1.65; color: #333; }
|
||||
.markdown-content ul, .markdown-content ol { padding-left: 1.5em; margin: 0.35em 0; }
|
||||
.markdown-content li { margin: 0.1em 0; line-height: 1.6; }
|
||||
.markdown-content code {
|
||||
background: rgba(0,47,167,0.06); padding: 0.1em 0.35em; border-radius: 4px;
|
||||
font-size: 0.87em; font-family: "SF Mono","JetBrains Mono","Fira Code",Consolas,monospace;
|
||||
}
|
||||
.markdown-content pre {
|
||||
background: #1a1a2e; color: #d4d4e8; padding: 0.85em 1em; border-radius: 10px;
|
||||
overflow-x: auto; margin: 0.5em 0; font-size: 0.87em;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.10);
|
||||
}
|
||||
.markdown-content pre code { background: none; padding: 0; color: inherit; font-size: 1em; }
|
||||
.markdown-content blockquote {
|
||||
border-left: 3px solid var(--accent); padding-left: 1em; color: var(--text-secondary);
|
||||
margin: 0.5em 0; font-style: italic;
|
||||
}
|
||||
|
||||
/* ── Animations ─────────────────────────────────────── */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(4px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
@keyframes fadeInScale {
|
||||
from { opacity: 0; transform: scale(0.97); }
|
||||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
.animate-fade-in { animation: fadeIn 0.2s ease-out; }
|
||||
.animate-fade-in-scale { animation: fadeInScale 0.2s ease-out; }
|
||||
|
||||
@keyframes pulse-dot {
|
||||
0%, 100% { opacity: 0.2; transform: scale(0.8); }
|
||||
50% { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
.typing-dot { animation: pulse-dot 1.4s ease-in-out infinite; }
|
||||
.typing-dot:nth-child(2) { animation-delay: 0.2s; }
|
||||
.typing-dot:nth-child(3) { animation-delay: 0.4s; }
|
||||
|
||||
/* ── Resize Handle ──────────────────────────────────── */
|
||||
.resize-handle {
|
||||
width: 5px;
|
||||
cursor: col-resize;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
.resize-handle:hover .resize-handle-line,
|
||||
.resize-handle:active .resize-handle-line {
|
||||
opacity: 1;
|
||||
}
|
||||
.resize-handle-line {
|
||||
width: 2px;
|
||||
height: 32px;
|
||||
border-radius: 1px;
|
||||
background: rgba(0,0,0,0.12);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
/* ── Panel transitions ──────────────────────────────── */
|
||||
.panel-transition {
|
||||
transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* ── Raw Message Viewer ─────────────────────────────── */
|
||||
.raw-message-viewer {
|
||||
font-family: "SF Mono","JetBrains Mono","Fira Code",Consolas,monospace;
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.raw-message-viewer .msg-system {
|
||||
color: #86868b;
|
||||
}
|
||||
.raw-message-viewer .msg-user {
|
||||
color: #002fa7;
|
||||
}
|
||||
.raw-message-viewer .msg-assistant {
|
||||
color: #16a34a;
|
||||
}
|
||||
.raw-message-viewer .msg-role {
|
||||
font-weight: 600;
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.raw-message-viewer .msg-content {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(0,0,0,0.02);
|
||||
margin-bottom: 8px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "mini OpenClaw",
|
||||
description: "A lightweight, transparent AI Agent system",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<body className="antialiased">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { AppProvider, useApp } from "@/lib/store";
|
||||
import Navbar from "@/components/layout/Navbar";
|
||||
import Sidebar from "@/components/layout/Sidebar";
|
||||
import ChatPanel from "@/components/chat/ChatPanel";
|
||||
import InspectorPanel from "@/components/editor/InspectorPanel";
|
||||
import ResizeHandle from "@/components/layout/ResizeHandle";
|
||||
|
||||
const MIN_SIDEBAR = 200;
|
||||
const MIN_INSPECTOR = 280;
|
||||
const MIN_CHAT = 360;
|
||||
|
||||
function MainLayout() {
|
||||
const {
|
||||
sidebarOpen,
|
||||
inspectorOpen,
|
||||
sidebarWidth,
|
||||
setSidebarWidth,
|
||||
inspectorWidth,
|
||||
setInspectorWidth,
|
||||
} = useApp();
|
||||
|
||||
const handleSidebarResize = useCallback(
|
||||
(delta: number) => {
|
||||
setSidebarWidth((prev: number) => Math.max(MIN_SIDEBAR, prev + delta));
|
||||
},
|
||||
[setSidebarWidth]
|
||||
);
|
||||
|
||||
const handleInspectorResize = useCallback(
|
||||
(delta: number) => {
|
||||
setInspectorWidth((prev: number) => Math.max(MIN_INSPECTOR, prev + delta));
|
||||
},
|
||||
[setInspectorWidth]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-screen flex flex-col app-bg">
|
||||
<Navbar />
|
||||
|
||||
{/* Content area — flexbox layout with resizable panels */}
|
||||
<div className="flex-1 flex overflow-hidden">
|
||||
{/* Left sidebar */}
|
||||
<div
|
||||
className="glass-panel border-r border-black/[0.06] shrink-0 panel-transition overflow-hidden"
|
||||
style={{ width: sidebarOpen ? sidebarWidth : 0 }}
|
||||
>
|
||||
<div style={{ width: sidebarWidth, minWidth: MIN_SIDEBAR }} className="h-full">
|
||||
<Sidebar />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Left resize handle */}
|
||||
{sidebarOpen && (
|
||||
<ResizeHandle onResize={handleSidebarResize} direction="left" />
|
||||
)}
|
||||
|
||||
{/* Chat — fills remaining space */}
|
||||
<div className="flex-1 overflow-hidden" style={{ minWidth: MIN_CHAT }}>
|
||||
<ChatPanel />
|
||||
</div>
|
||||
|
||||
{/* Right resize handle */}
|
||||
{inspectorOpen && (
|
||||
<ResizeHandle onResize={handleInspectorResize} direction="right" />
|
||||
)}
|
||||
|
||||
{/* Right inspector */}
|
||||
<div
|
||||
className="glass-panel border-l border-black/[0.06] shrink-0 panel-transition overflow-hidden"
|
||||
style={{ width: inspectorOpen ? inspectorWidth : 0 }}
|
||||
>
|
||||
<div style={{ width: inspectorWidth, minWidth: MIN_INSPECTOR }} className="h-full">
|
||||
<InspectorPanel />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<AppProvider>
|
||||
<MainLayout />
|
||||
</AppProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user