Commit 70a7b700 authored by Vũ Hoàng Anh's avatar Vũ Hoàng Anh

feat(ui): redesign prompt manager + cookbook SVG icons + markdown styling

- Rewrite manage_prompt.css: larger fonts (14-16px), premium card layout, better spacing
- Cookbook sidebar: replace emoji with color-coded SVG Lucide icons per group
- Cookbook CSS: add proper pre/code/blockquote/heading styling for markdown content
- Support separator groups (no recipes) in sidebar navigation
- Add mermaid diagram container styles
- Light theme support for code blocks
parent 7aae58aa
...@@ -553,3 +553,189 @@ pre { ...@@ -553,3 +553,189 @@ pre {
gap: 16px; gap: 16px;
} }
} }
/* ═══ Markdown Content Enhancements ═══ */
/* ASCII art / preformatted blocks — preserve box-drawing chars */
.recipe-content pre {
background: #0d1117;
color: #e6edf3;
border: 1px solid var(--cb-border);
border-radius: 10px;
padding: 20px 24px;
font-family: 'JetBrains Mono', 'Consolas', 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
overflow-x: auto;
white-space: pre;
word-break: normal;
margin: 20px 0;
tab-size: 4;
}
body.light-theme .recipe-content pre {
background: #f6f8fa;
color: #24292f;
border-color: #d0d7de;
}
/* Inline code */
.recipe-content code {
background: rgba(59,130,246,0.08);
color: var(--cb-accent);
padding: 2px 7px;
border-radius: 5px;
font-family: 'JetBrains Mono', 'Consolas', monospace;
font-size: 0.88em;
font-weight: 500;
}
.recipe-content pre code {
background: none;
color: inherit;
padding: 0;
border-radius: 0;
font-size: inherit;
}
/* Blockquotes */
.recipe-content blockquote {
border-left: 4px solid var(--cb-accent);
background: rgba(59,130,246,0.05);
margin: 20px 0;
padding: 16px 20px;
border-radius: 0 10px 10px 0;
color: var(--cb-text);
font-size: 15px;
line-height: 1.7;
}
.recipe-content blockquote p {
margin: 0;
}
/* Headings inside markdown */
.recipe-content .text-block h1 {
font-size: 28px;
font-weight: 800;
margin: 40px 0 16px;
padding-bottom: 10px;
border-bottom: 2px solid var(--cb-border);
}
.recipe-content .text-block h2 {
font-size: 22px;
font-weight: 700;
margin: 36px 0 14px;
padding-bottom: 8px;
border-bottom: 1px solid var(--cb-border);
}
.recipe-content .text-block h3 {
font-size: 18px;
font-weight: 700;
margin: 28px 0 12px;
color: var(--cb-accent);
}
.recipe-content .text-block h4 {
font-size: 16px;
font-weight: 600;
margin: 24px 0 10px;
color: var(--cb-text-muted);
}
/* Lists */
.recipe-content .text-block ul,
.recipe-content .text-block ol {
padding-left: 24px;
margin: 12px 0;
}
.recipe-content .text-block li {
margin-bottom: 6px;
line-height: 1.7;
font-size: 15px;
}
/* Horizontal rules */
.recipe-content hr {
border: none;
border-top: 1px solid var(--cb-border);
margin: 32px 0;
}
/* Images */
.recipe-content .text-block img {
max-width: 100%;
border-radius: 10px;
border: 1px solid var(--cb-border);
margin: 16px 0;
}
/* ═══ Sidebar SVG Group Icons ═══ */
.nav-group-title {
display: flex;
align-items: center;
gap: 8px;
}
.nav-group-title .group-icon {
width: 18px;
height: 18px;
flex-shrink: 0;
opacity: 0.7;
}
.nav-group-title:hover .group-icon {
opacity: 1;
}
/* Separator group styling */
.nav-group-separator {
padding: 18px 20px 6px;
font-size: 10px;
font-weight: 800;
letter-spacing: 0.12em;
color: var(--cb-accent);
border-top: 1px solid var(--cb-border);
margin-top: 8px;
}
.nav-group-separator:first-child {
border-top: none;
margin-top: 0;
}
/* ═══ Mermaid diagram containers ═══ */
.recipe-content .mermaid {
background: rgba(255,255,255,0.03);
border: 1px solid var(--cb-border);
border-radius: 10px;
padding: 20px;
margin: 20px 0;
text-align: center;
overflow-x: auto;
}
body.light-theme .recipe-content .mermaid {
background: #ffffff;
}
/* ═══ Strong / Bold emphasis ═══ */
.recipe-content .text-block strong {
font-weight: 700;
color: var(--cb-text);
}
/* ═══ Links ═══ */
.recipe-content .text-block a {
color: var(--cb-accent);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 0.2s;
}
.recipe-content .text-block a:hover {
border-bottom-color: var(--cb-accent);
}
...@@ -58,16 +58,61 @@ document.addEventListener('DOMContentLoaded', async () => { ...@@ -58,16 +58,61 @@ document.addEventListener('DOMContentLoaded', async () => {
console.error('Failed to load registry:', err); console.error('Failed to load registry:', err);
} }
// SVG Icon Map for sidebar group titles
const GROUP_ICONS = {
'AI Chatbot': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>',
'Kiến trúc': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#8b5cf6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>',
'Tư vấn': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>',
'Phối đồ': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ec4899" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.38 3.46L16 2 12 5.5 8 2l-4.38 1.46a2 2 0 0 0-1.34 2.23l2.1 14.32A2 2 0 0 0 6.35 21.5h11.3a2 2 0 0 0 1.97-1.49l2.1-14.32a2 2 0 0 0-1.34-2.23z"/></svg>',
'Event': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f97316" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/></svg>',
'AI Core': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#06b6d4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a4 4 0 0 0-4 4v2H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2h-2V6a4 4 0 0 0-4-4z"/><circle cx="12" cy="14" r="2"/></svg>',
'Tool': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>',
'SCALE': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>',
'Cá nhân': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#a855f7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>',
'Voice': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>',
'Đo lường': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>',
'EXPERIMENTAL': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#eab308" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6v7l4 8H5l4-8V3z"/><line x1="8" y1="3" x2="16" y2="3"/></svg>',
'Data': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>',
'Social': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>',
'Testing': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6v7l4 8H5l4-8V3z"/><line x1="8" y1="3" x2="16" y2="3"/></svg>',
'Hạ tầng': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',
'Feedback': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f472b6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>',
};
function getGroupIcon(groupName) {
for (const [key, svg] of Object.entries(GROUP_ICONS)) {
if (groupName.includes(key)) return svg;
}
return '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>';
}
function cleanGroupName(name) {
// Remove emoji and special separator chars
return name.replace(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}\u{1F000}-\u{1FFFF}]/gu, '')
.replace(/━+/g, '').replace(/\s+/g, ' ').trim();
}
// 2. Render Sidebar // 2. Render Sidebar
function renderSidebar(data) { function renderSidebar(data) {
recipeNav.innerHTML = ''; recipeNav.innerHTML = '';
data.groups.forEach(group => { data.groups.forEach(group => {
// Check if this is a separator group (no recipes, just a label)
const cleanName = cleanGroupName(group.name);
if (group.recipes.length === 0) {
const sepEl = document.createElement('div');
sepEl.className = 'nav-group-separator';
sepEl.textContent = cleanName;
recipeNav.appendChild(sepEl);
return;
}
const groupEl = document.createElement('div'); const groupEl = document.createElement('div');
groupEl.className = 'nav-group'; groupEl.className = 'nav-group';
const titleEl = document.createElement('div'); const titleEl = document.createElement('div');
titleEl.className = 'nav-group-title'; titleEl.className = 'nav-group-title';
titleEl.innerHTML = `<span>${group.name}</span> <span class="toggle-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></span>`; const iconSvg = getGroupIcon(group.name);
titleEl.innerHTML = `<span class="group-icon">${iconSvg}</span><span>${cleanName}</span> <span class="toggle-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></span>`;
const listEl = document.createElement('ul'); const listEl = document.createElement('ul');
listEl.className = 'recipe-list'; listEl.className = 'recipe-list';
......
/* ═══════════════════════════════════════════════════════════ /* ═══════════════════════════════════════════════════════════
Prompt Manager — Page-specific Styles Prompt Manager — Premium Redesign
Consistent with Canifa AI Lab CSS system (Premium Dark) Consistent with Canifa AI Lab CSS system
═══════════════════════════════════════════════════════════ */ ═══════════════════════════════════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
:root { :root {
--bg: #ffffff; /* background */ --bg: #f8f7f4;
--s: #f8f7f4; /* surface */ --s: #ffffff;
--b: #e7e5e2; /* border */ --b: #e7e5e2;
--t: #1c1917; /* text primary */ --t: #1c1917;
--m: #78716c; /* text muted */ --m: #78716c;
--primary: #3b5998; --primary: #3b5998;
--primary-hover: #2d4a7a;
--primary-light: #eef1f8;
--gold: #b45309;
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'Consolas', monospace;
} }
body { body {
background-color: var(--bg); background-color: var(--bg);
color: var(--t); color: var(--t);
margin: 0; margin: 0;
font-family: var(--font-sans, 'Inter', sans-serif); font-family: var(--font-sans);
font-size: 14px;
line-height: 1.6;
} }
/* ── Icons & Animations ── */ /* ── Icons & Animations ── */
.icon-xs { width: 12px; height: 12px; } .icon-xs { width: 14px; height: 14px; }
.icon-sm { width: 16px; height: 16px; } .icon-sm { width: 18px; height: 18px; }
.icon-md { width: 20px; height: 20px; } .icon-md { width: 22px; height: 22px; }
.icon-xl { width: 32px; height: 32px; } .icon-xl { width: 36px; height: 36px; }
.text-primary { color: var(--primary); } .text-primary { color: var(--primary); }
.spinner { animation: spin 1s linear infinite; } .spinner { animation: spin 1s linear infinite; }
@keyframes spin { 100% { transform: rotate(360deg); } } @keyframes spin { 100% { transform: rotate(360deg); } }
@keyframes fadeUp { @keyframes fadeUp {
from { opacity: 0; transform: translateY(10px); } from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); } to { opacity: 1; transform: translateY(0); }
} }
/* ── Shell & Body Layout ── */ /* ── Shell & Body Layout ── */
.shell { .shell {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
} }
.body { .body {
flex: 1; flex: 1;
display: grid; display: grid;
grid-template-columns: 280px 1fr 320px; grid-template-columns: 300px 1fr 340px;
gap: 0; gap: 0;
overflow: hidden; overflow: hidden;
min-height: 0; min-height: 0;
} }
/* ── Panels ── */ /* ── Panels ── */
.panel { .panel {
display: flex; flex-direction: column; display: flex;
overflow: hidden; background: var(--s); flex-direction: column;
overflow: hidden;
background: var(--s);
}
.panel-left {
border-right: 1px solid var(--b);
background: var(--s);
}
.panel-right {
border-left: 1px solid var(--b);
background: var(--bg);
}
.panel-center {
background: var(--bg);
} }
.panel-left { border-right: 1px solid var(--b); background: var(--bg); }
.panel-right { border-left: 1px solid var(--b); background: var(--s); }
.panel-center { background: var(--bg); }
.panel-header { .panel-header {
padding: 12px 14px; border-bottom: 1px solid var(--b); padding: 16px 18px;
flex-shrink: 0; border-bottom: 1px solid var(--b);
flex-shrink: 0;
} }
.panel-header-flex { .panel-header-flex {
display: flex; justify-content: space-between; align-items: center; display: flex;
justify-content: space-between;
align-items: center;
} }
.panel-brand { .panel-brand {
display: flex; align-items: center; gap: 8px; color: var(--t); font-weight: 600; font-size: 14px; display: flex;
align-items: center;
gap: 10px;
color: var(--t);
font-weight: 700;
font-size: 16px;
} }
.panel-actions { .panel-actions {
display: flex; align-items: center; gap: 6px; display: flex;
align-items: center;
gap: 8px;
} }
.panel-section { .panel-section {
border-bottom: 1px solid var(--b); border-bottom: 1px solid var(--b);
padding: 10px 14px; padding: 14px 18px;
} }
.search-section { .search-section {
padding: 10px 14px; padding: 14px 18px;
} }
.section-title { .section-title {
font-size: 11px; font-weight: 700; text-transform: uppercase; font-size: 12px;
letter-spacing: .06em; color: var(--m); font-weight: 700;
margin-bottom: 8px; text-transform: uppercase;
letter-spacing: .08em;
color: var(--m);
margin-bottom: 10px;
} }
.split-title { .split-title {
display: flex; justify-content: space-between; align-items: center; display: flex;
justify-content: space-between;
align-items: center;
} }
/* ── Status Dot & Langfuse ── */ /* ── Status Dot & Langfuse ── */
.status-dot { .status-dot {
width: 8px; height: 8px; border-radius: 50%; width: 10px;
transition: background .3s; display: inline-block; height: 10px;
border-radius: 50%;
transition: background .3s;
display: inline-block;
} }
.status-dot.online { background: #34D399; box-shadow: 0 0 6px rgba(52,211,153,.5); } .status-dot.online { background: #16a34a; box-shadow: 0 0 8px rgba(22,163,106,.4); }
.status-dot.offline { background: #EF4444; } .status-dot.offline { background: #dc2626; }
.status-dot.checking { background: #FBBF24; animation: pulse 1.2s infinite; } .status-dot.checking { background: #ca8a04; animation: pulse 1.2s infinite; }
@keyframes pulse { 0%,100%{opacity:1;} 50%{opacity:.5;} } @keyframes pulse { 0%,100%{opacity:1;} 50%{opacity:.4;} }
.lf-status-wrap { .lf-status-wrap {
display: flex; align-items: center; gap: 4px; display: flex;
align-items: center;
gap: 6px;
} }
.lf-status-text { font-size: 10px; color: var(--m); } .lf-status-text { font-size: 12px; color: var(--m); }
.lf-count-text { color: #a78bfa; font-size: 10px; } .lf-count-text { color: var(--primary); font-size: 12px; font-weight: 600; }
/* ── Module List ── */ /* ── Module List ── */
.module-list { .module-list {
flex: 1; overflow-y: auto; padding: 8px; flex: 1;
overflow-y: auto;
padding: 10px;
} }
.list-loading { .list-loading {
display: flex; justify-content: center; padding: 20px; display: flex;
justify-content: center;
padding: 24px;
} }
.module-item { .module-item {
padding: 10px 12px; border-radius: 10px; margin-bottom: 4px; padding: 14px 16px;
cursor: pointer; transition: all .15s; border-radius: 12px;
border: 1px solid transparent; margin-bottom: 6px;
display: flex; flex-direction: column; gap: 6px; cursor: pointer;
transition: all .2s ease;
border: 1px solid transparent;
display: flex;
flex-direction: column;
gap: 8px;
}
.module-item:hover {
background: var(--bg);
border-color: var(--b);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.module-item.active {
border-color: var(--primary);
background: var(--primary-light);
box-shadow: 0 2px 12px rgba(59,89,152,0.08);
} }
.module-item:hover { background: var(--s); }
.module-item.active { border-color: var(--b); background: var(--s); }
.module-name { .module-name {
font-size: 13px; font-weight: 600; color: var(--t); font-size: 14px;
display: flex; align-items: center; gap: 6px; font-weight: 600;
color: var(--t);
display: flex;
align-items: center;
gap: 8px;
} }
.module-type-badge { .module-type-badge {
font-size: 10px; font-weight: 700; padding: 2px 6px; font-size: 10px;
border-radius: 10px; text-transform: uppercase; font-weight: 700;
letter-spacing: .04em; padding: 3px 8px;
border-radius: 12px;
text-transform: uppercase;
letter-spacing: .04em;
} }
.type-system { background: rgba(59,130,246,.15); color: #60a5fa; } .type-system { background: rgba(59,89,152,.12); color: var(--primary); }
.type-tool { background: rgba(249,115,22,.15); color: #fb923c; } .type-tool { background: rgba(180,83,9,.12); color: var(--gold); }
.module-meta { .module-meta {
display: flex; align-items: center; gap: 6px; display: flex;
font-size: 11px; color: var(--m); align-items: center;
gap: 8px;
font-size: 12px;
color: var(--m);
} }
.env-pill { .env-pill {
font-size: 10px; font-weight: 700; padding: 2px 7px; font-size: 11px;
border-radius: 10px; letter-spacing: .03em; font-weight: 700;
} padding: 3px 10px;
.pill-dev { background: rgba(5,150,105,.2); color: #34d399; } border-radius: 12px;
.pill-prod { background: rgba(220,38,38,.15); color: #ef4444; } letter-spacing: .03em;
}
.pill-dev { background: rgba(22,163,106,.12); color: #16a34a; }
.pill-prod { background: rgba(220,38,38,.1); color: #dc2626; }
.pill-none { background: var(--b); color: var(--m); font-style: italic; } .pill-none { background: var(--b); color: var(--m); font-style: italic; }
.pill-synced { background: rgba(29,78,216,.2); color: #60a5fa; } .pill-synced { background: rgba(37,99,235,.1); color: #2563eb; }
.pill-unsynced { background: rgba(146,64,14,.2); color: #fbbf24; } .pill-unsynced { background: rgba(202,138,4,.12); color: #ca8a04; }
.sync-indicator { .sync-indicator {
margin-left: auto; margin-left: auto;
font-size: 11px; font-weight: 600; font-size: 12px;
font-weight: 600;
} }
.sync-yes { color: #34d399; } .sync-yes { color: #16a34a; }
.sync-no { color: #f87171; } .sync-no { color: #dc2626; }
/* ── Search & Stats ── */ /* ── Search & Stats ── */
.search-bar-pm { .search-bar-pm {
position: relative; display: flex; align-items: center; position: relative;
display: flex;
align-items: center;
} }
.search-icon { .search-icon {
position: absolute; left: 10px; color: var(--m); position: absolute;
left: 12px;
color: var(--m);
} }
.search-input { .search-input {
width: 100%; padding: 8px 12px 8px 32px; font-size: 12px; width: 100%;
border: 1px solid var(--b); background: var(--bg); color: var(--t); padding: 10px 14px 10px 36px;
border-radius: 6px; outline: none; transition: border-color .2s; font-size: 14px;
border: 1px solid var(--b);
background: var(--bg);
color: var(--t);
border-radius: 10px;
outline: none;
transition: border-color .2s, box-shadow .2s;
font-family: var(--font-sans);
}
.search-input:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(59,89,152,0.08);
} }
.search-input:focus { border-color: var(--primary); }
.stats-row { .stats-row {
display: flex; justify-content: space-between; margin-top: 10px; font-size: 11px; color: var(--m); display: flex;
justify-content: space-between;
margin-top: 12px;
font-size: 13px;
color: var(--m);
} }
.stat-val-text { color: var(--t); } .stat-val-text { color: var(--t); font-weight: 600; }
.stat-sync-text { color: #34d399; } .stat-sync-text { color: #16a34a; font-weight: 600; }
/* ── Detail Area ── */ /* ── Detail Area ── */
.detail-area { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; height: 100%; } .detail-area {
flex: 1;
overflow-y: auto;
padding: 28px;
display: flex;
flex-direction: column;
height: 100%;
}
.centered-empty { .centered-empty {
margin: auto; text-align: center; color: var(--m); margin: auto;
display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center;
} color: var(--m);
.empty-icon-lg { width: 48px; height: 48px; opacity: 0.5; margin-bottom: 16px; } display: flex;
.empty-title { font-size: 16px; font-weight: 600; color: var(--t); margin-bottom: 8px; } flex-direction: column;
.empty-desc { font-size: 13px; } justify-content: center;
align-items: center;
}
.empty-icon-lg { width: 56px; height: 56px; opacity: 0.4; margin-bottom: 20px; color: var(--primary); }
.empty-title { font-size: 18px; font-weight: 700; color: var(--t); margin-bottom: 10px; }
.empty-desc { font-size: 14px; line-height: 1.6; max-width: 320px; }
.detail-header { .detail-header {
display: flex; justify-content: space-between; align-items: center; display: flex;
margin-bottom: 16px; padding-bottom: 12px; justify-content: space-between;
border-bottom: 1px solid var(--b); align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid var(--b);
} }
.detail-title { .detail-title {
font-size: 18px; font-weight: 700; color: var(--t); font-size: 20px;
font-weight: 700;
color: var(--t);
} }
.detail-actions { display: flex; gap: 6px; } .detail-actions { display: flex; gap: 8px; }
/* ── Detail Buttons ── */ /* ── Detail Buttons ── */
.tb-btn { .tb-btn {
padding: 6px; border-radius: 8px; border: 1px solid transparent; padding: 8px;
background: transparent; color: var(--m); font-size: 12px; border-radius: 10px;
cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all .15s; border: 1px solid var(--b);
background: var(--s);
color: var(--m);
font-size: 13px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all .2s;
}
.tb-btn:hover {
background: var(--primary-light);
color: var(--primary);
border-color: var(--primary);
} }
.tb-btn:hover { background: var(--b); color: var(--t); }
.detail-btn { .detail-btn {
padding: 6px 14px; border-radius: 8px; padding: 8px 18px;
font-size: 12px; font-weight: 600; cursor: pointer; border-radius: 10px;
border: 1px solid var(--b); background: var(--s); color: var(--t); font-size: 13px;
transition: all .15s; display: flex; align-items: center; gap: 6px; font-weight: 600;
} cursor: pointer;
.detail-btn:hover { background: var(--b); } border: 1px solid var(--b);
.detail-btn.primary { background: #6D28D9; color: #fff; border-color: #6D28D9; } background: var(--s);
.detail-btn.primary:hover { background: #5B21B6; } color: var(--t);
.detail-btn.success { background: #059669; color: #fff; border-color: #059669; } transition: all .2s;
.detail-btn.success:hover { background: #047857; } display: flex;
align-items: center;
gap: 8px;
font-family: var(--font-sans);
}
.detail-btn:hover { background: var(--bg); border-color: var(--m); }
.detail-btn.primary { background: var(--primary); color: #fff; border-color: var(--primary); }
.detail-btn.primary:hover { background: var(--primary-hover); }
.detail-btn.success { background: #16a34a; color: #fff; border-color: #16a34a; }
.detail-btn.success:hover { background: #15803d; }
.detail-btn.outline { background: transparent; border-color: var(--b); } .detail-btn.outline { background: transparent; border-color: var(--b); }
.detail-btn.outline:hover { background: var(--b); } .detail-btn.outline:hover { background: var(--bg); border-color: var(--m); }
/* ── Environment Cards ── */ /* ── Environment Cards ── */
.env-cards { .env-cards {
display: grid; grid-template-columns: 1fr 1fr; display: grid;
gap: 14px; margin-bottom: 16px; grid-template-columns: 1fr 1fr;
gap: 18px;
margin-bottom: 20px;
} }
.env-card { .env-card {
background: var(--bg); border: 1px solid var(--b); border-radius: 12px; background: var(--s);
padding: 16px; position: relative; overflow: hidden; border: 1px solid var(--b);
border-radius: 14px;
padding: 20px;
position: relative;
overflow: hidden;
transition: box-shadow .2s;
}
.env-card:hover {
box-shadow: 0 4px 16px rgba(0,0,0,0.06);
} }
.env-card::before { .env-card::before {
content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
} }
.env-card.dev::before { background: linear-gradient(90deg, #059669, #34d399); } .env-card.dev::before { background: linear-gradient(90deg, #16a34a, #4ade80); }
.env-card.prod::before { background: linear-gradient(90deg, #dc2626, #ef4444); } .env-card.prod::before { background: linear-gradient(90deg, #dc2626, #f87171); }
.env-card-header { .env-card-header {
display: flex; justify-content: space-between; align-items: center; display: flex;
margin-bottom: 10px; justify-content: space-between;
align-items: center;
margin-bottom: 12px;
} }
.env-card-title { .env-card-title {
font-size: 13px; font-weight: 700; text-transform: uppercase; font-size: 13px;
letter-spacing: .05em; font-weight: 700;
text-transform: uppercase;
letter-spacing: .06em;
} }
.env-card.dev .env-card-title { color: #34d399; } .env-card.dev .env-card-title { color: #16a34a; }
.env-card.prod .env-card-title { color: #ef4444; } .env-card.prod .env-card-title { color: #dc2626; }
.env-card-meta { .env-card-meta {
display: flex; flex-direction: column; gap: 4px; display: flex;
font-size: 12px; color: var(--m); flex-direction: column;
gap: 6px;
font-size: 13px;
color: var(--m);
} }
.env-card-meta strong { color: var(--t); font-weight: 600; } .env-card-meta strong { color: var(--t); font-weight: 600; }
.env-content-preview { .env-content-preview {
background: #f8fafc; border-radius: 8px; padding: 16px 20px; background: var(--bg);
font-size: 13px; font-family: 'Consolas', 'Courier New', var(--font-mono, monospace); border-radius: 10px;
color: #0f172a; line-height: 1.7; margin-top: 10px; padding: 18px 22px;
max-height: 350px; overflow-y: auto; font-size: 13px;
white-space: pre-wrap; word-break: break-word; border: 1px solid var(--b); font-family: var(--font-mono);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.02); color: var(--t);
line-height: 1.8;
margin-top: 12px;
max-height: 350px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-word;
border: 1px solid var(--b);
} }
.env-empty { .env-empty {
padding: 24px; text-align: center; color: var(--m); padding: 28px;
font-size: 12px; font-style: italic; text-align: center;
color: var(--m);
font-size: 13px;
font-style: italic;
} }
/* ── History Panel ── */ /* ── History Panel ── */
#history-panel, #langfuse-panel { #history-panel, #langfuse-panel {
overflow-y: auto; padding: 0 4px; overflow-y: auto;
padding: 0 6px;
} }
.history-item { .history-item {
padding: 10px 12px; border-radius: 8px; margin-bottom: 6px; font-size: 12px; padding: 12px 14px;
border: 1px solid var(--b); background: var(--bg); border-radius: 10px;
cursor: pointer; transition: all .12s; margin-bottom: 8px;
font-size: 13px;
border: 1px solid var(--b);
background: var(--s);
cursor: pointer;
transition: all .15s;
}
.history-item:hover {
background: var(--primary-light);
border-color: var(--primary);
transform: translateY(-1px);
} }
.history-item:hover { background: var(--s); border-color: var(--m); }
.history-head { .history-head {
display: flex; justify-content: space-between; align-items: center; margin-bottom: 3px; display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
} }
.history-ver { font-weight: 700; color: var(--t); font-size: 13px; } .history-ver { font-weight: 700; color: var(--t); font-size: 14px; }
.history-env { font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 8px; } .history-env { font-size: 10px; font-weight: 700; padding: 3px 8px; border-radius: 10px; }
.history-meta { color: var(--m); font-size: 10px; } .history-meta { color: var(--m); font-size: 11px; }
/* ── Langfuse Items ── */ /* ── Langfuse Items ── */
.lf-item { .lf-item {
padding: 8px 10px; border-radius: 8px; margin-bottom: 6px; padding: 10px 12px;
border: 1px solid var(--b); background: var(--bg); font-size: 11px; border-radius: 10px;
} margin-bottom: 8px;
.lf-item-name { font-weight: 600; color: var(--t); margin-bottom: 4px; } border: 1px solid var(--b);
.lf-item-meta { color: var(--m); font-size: 10px; } background: var(--s);
font-size: 13px;
}
.lf-item-name { font-weight: 600; color: var(--t); margin-bottom: 6px; }
.lf-item-meta { color: var(--m); font-size: 11px; }
.lf-label { .lf-label {
display: inline-block; font-size: 9px; font-weight: 700; display: inline-block;
padding: 2px 6px; border-radius: 8px; font-size: 10px;
background: rgba(220,38,38,.15); color: #ef4444; margin-right: 4px; font-weight: 700;
padding: 2px 8px;
border-radius: 10px;
background: rgba(220,38,38,.1);
color: #dc2626;
margin-right: 6px;
} }
/* ── Modal Overlay ── */ /* ── Modal Overlay ── */
.modal-overlay { .modal-overlay {
position: fixed; inset: 0; z-index: 1000; position: fixed;
background: rgba(0,0,0,0.4); backdrop-filter: blur(4px); inset: 0;
display: none; justify-content: center; align-items: center; z-index: 1000;
background: rgba(0,0,0,0.3);
backdrop-filter: blur(8px);
display: none;
justify-content: center;
align-items: center;
} }
.modal-overlay.open { display: flex; } .modal-overlay.open { display: flex; }
.modal-box { .modal-box {
background: var(--s); border-radius: 14px; border: 1px solid var(--b); background: var(--s);
box-shadow: 0 20px 60px rgba(0,0,0,.5); border-radius: 16px;
display: flex; flex-direction: column; border: 1px solid var(--b);
max-height: 90vh; width: 600px; box-shadow: 0 24px 80px rgba(0,0,0,0.12);
animation: fadeUp .2s ease; display: flex;
} flex-direction: column;
.modal-box.modal-lg { width: 900px; } max-height: 90vh;
width: 600px;
animation: fadeUp .25s ease;
}
.modal-box.modal-lg { width: 940px; }
.modal-head { .modal-head {
display: flex; justify-content: space-between; align-items: center; display: flex;
padding: 16px 20px; border-bottom: 1px solid var(--b); justify-content: space-between;
align-items: center;
padding: 18px 24px;
border-bottom: 1px solid var(--b);
} }
.modal-head-title { .modal-head-title {
display: flex; align-items: center; gap: 8px; display: flex;
align-items: center;
gap: 10px;
} }
.modal-head h3 { font-size: 15px; font-weight: 700; margin: 0; color: var(--t); } .modal-head h3 { font-size: 16px; font-weight: 700; margin: 0; color: var(--t); }
.modal-close { .modal-close {
width: 28px; height: 28px; border-radius: 8px; border: none; width: 32px;
background: var(--bg); cursor: pointer; font-size: 14px; color: var(--m); height: 32px;
display: flex; align-items: center; justify-content: center; transition: all .15s; border-radius: 10px;
} border: 1px solid var(--b);
.modal-close:hover { background: rgba(239,68,68,.2); color: #ef4444; } background: var(--bg);
.modal-body { flex: 1; overflow-y: auto; padding: 16px 20px; } cursor: pointer;
font-size: 15px;
color: var(--m);
display: flex;
align-items: center;
justify-content: center;
transition: all .2s;
}
.modal-close:hover { background: rgba(220,38,38,.08); color: #dc2626; border-color: #dc2626; }
.modal-body { flex: 1; overflow-y: auto; padding: 20px 24px; }
.bg-dark { background: var(--bg); } .bg-dark { background: var(--bg); }
.modal-foot { .modal-foot {
padding: 12px 20px; border-top: 1px solid var(--b); padding: 14px 24px;
display: flex; justify-content: flex-end; gap: 8px; border-top: 1px solid var(--b);
display: flex;
justify-content: flex-end;
gap: 10px;
} }
/* ── Diff Viewer ── */ /* ── Diff Viewer ── */
.diff-wrapper { .diff-wrapper {
display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 20px;
} }
.diff-box { .diff-box {
flex: 1; min-width: 300px; flex: 1;
display: flex; flex-direction: column; border: 1px solid var(--b); border-radius: 8px; overflow: hidden; min-width: 300px;
background: #ffffff; box-shadow: 0 4px 20px rgba(0,0,0,0.05); display: flex;
flex-direction: column;
border: 1px solid var(--b);
border-radius: 12px;
overflow: hidden;
background: var(--s);
box-shadow: 0 2px 12px rgba(0,0,0,0.04);
} }
.diff-header { .diff-header {
padding: 10px 16px; font-size: 12px; font-family: 'Consolas', monospace; font-weight: 600; padding: 12px 18px;
display: flex; align-items: center; justify-content: space-between; font-size: 13px;
border-bottom: 1px solid var(--b); font-family: var(--font-mono);
background: #f1f5f9; color: #475569; font-weight: 600;
} display: flex;
.dev-header { background: #ecfdf5; color: #059669; border-bottom-color: #a7f3d0; } align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--b);
background: var(--bg);
color: var(--m);
}
.dev-header { background: #ecfdf5; color: #16a34a; border-bottom-color: #bbf7d0; }
.prod-header { background: #fef2f2; color: #dc2626; border-bottom-color: #fecaca; } .prod-header { background: #fef2f2; color: #dc2626; border-bottom-color: #fecaca; }
.diff-header-title { display: flex; align-items: center; gap: 6px; } .diff-header-title { display: flex; align-items: center; gap: 8px; }
.diff-content { .diff-content {
padding: 20px; padding: 22px;
font-family: 'Consolas', 'Courier New', var(--font-mono, monospace); font-family: var(--font-mono);
font-size: 13px; line-height: 1.7; color: #0f172a; font-size: 13px;
white-space: pre-wrap; word-break: break-word; line-height: 1.8;
max-height: 60vh; overflow-y: auto; margin: 0; flex: 1; color: var(--t);
white-space: pre-wrap;
word-break: break-word;
max-height: 60vh;
overflow-y: auto;
margin: 0;
flex: 1;
} }
/* ── Editor ── */ /* ── Editor ── */
.editor-notes-wrap { margin-bottom: 12px; } .editor-notes-wrap { margin-bottom: 14px; }
.editor-notes-input { .editor-notes-input {
width: 100%; padding: 10px 14px; font-size: 13px; width: 100%;
border: 1px solid var(--b); background: var(--bg); color: var(--t); padding: 12px 16px;
border-radius: 8px; outline: none; transition: border-color .2s; font-size: 14px;
border: 1px solid var(--b);
background: var(--bg);
color: var(--t);
border-radius: 10px;
outline: none;
transition: border-color .2s, box-shadow .2s;
font-family: var(--font-sans);
}
.editor-notes-input:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(59,89,152,0.08);
} }
.editor-notes-input:focus { border-color: var(--primary); }
.editor-textarea { .editor-textarea {
width: 100%; min-height: 400px; padding: 16px; width: 100%;
border: 1px solid var(--b); border-radius: 10px; min-height: 420px;
font-family: 'Consolas', 'Courier New', var(--font-mono, monospace); padding: 18px;
font-size: 14px; line-height: 1.7; border: 1px solid var(--b);
color: #0f172a; background: #f8fafc; border-radius: 12px;
resize: vertical; outline: none; transition: border-color .15s; font-family: var(--font-mono);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.02); font-size: 14px;
} line-height: 1.8;
.editor-textarea:focus { border-color: var(--primary); } color: var(--t);
background: var(--bg);
resize: vertical;
outline: none;
transition: border-color .2s, box-shadow .2s;
}
.editor-textarea:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(59,89,152,0.08);
}
.editor-stats { .editor-stats {
display: flex; gap: 16px; margin-top: 8px; font-size: 12px; color: var(--m); display: flex;
gap: 20px;
margin-top: 10px;
font-size: 13px;
color: var(--m);
} }
.editor-stat-item { display: flex; align-items: center; gap: 4px; } .editor-stat-item { display: flex; align-items: center; gap: 6px; }
/* ── Loading Overlay ── */ /* ── Loading Overlay ── */
.loading-overlay { .loading-overlay {
display: none; position: absolute; inset: 0; background: rgba(255,255,255,0.8); display: none;
backdrop-filter: blur(4px); z-index: 9999; position: absolute;
flex-direction: column; justify-content: center; align-items: center; inset: 0;
background: rgba(248,247,244,0.85);
backdrop-filter: blur(6px);
z-index: 9999;
flex-direction: column;
justify-content: center;
align-items: center;
} }
.loading-overlay.active { display: flex; } .loading-overlay.active { display: flex; }
.loading-title { .loading-title {
color: var(--t); font-size: 16px; margin: 0 0 8px 0; font-weight: 600; color: var(--t);
font-size: 17px;
margin: 0 0 8px 0;
font-weight: 700;
} }
/* ── Toast ── */ /* ── Toast ── */
.notif { .notif {
position: fixed; bottom: -50px; left: 50%; transform: translateX(-50%); position: fixed;
background: #1e293b; color: #fff; padding: 10px 20px; border-radius: 8px; bottom: -50px;
font-size: 13px; font-weight: 500; box-shadow: 0 4px 12px rgba(0,0,0,.3); left: 50%;
transition: all .3s; z-index: 10000; opacity: 0; pointer-events: none; border: 1px solid var(--b); transform: translateX(-50%);
} background: var(--t);
.notif.show { bottom: 20px; opacity: 1; } color: var(--bg);
padding: 12px 24px;
border-radius: 12px;
font-size: 14px;
font-weight: 500;
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
transition: all .3s;
z-index: 10000;
opacity: 0;
pointer-events: none;
border: 1px solid var(--b);
}
.notif.show { bottom: 24px; opacity: 1; }
/* ── Responsive ── */ /* ── Responsive ── */
@media (max-width: 1200px) { @media (max-width: 1200px) {
.body { grid-template-columns: 240px 1fr 280px; } .body { grid-template-columns: 260px 1fr 300px; }
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.body { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; } .body { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; }
.panel-left, .panel-right { border: none; border-bottom: 1px solid var(--b); max-height: 300px; } .panel-left, .panel-right { border: none; border-bottom: 1px solid var(--b); max-height: 300px; }
} }
$env:PORT=8000; .\ds2api.exe
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment