|
|
@@ -20,30 +20,34 @@
|
|
|
}
|
|
|
|
|
|
:root {
|
|
|
- --bg-base: #f4f7f9;
|
|
|
+ --bg-base: #f8fafc;
|
|
|
--bg-sidebar: #ffffff;
|
|
|
--bg-nav: #ffffff;
|
|
|
--bg-card: #ffffff;
|
|
|
- --bg-hover: #f8fafc;
|
|
|
- --bg-active: #eef6ff;
|
|
|
- --border: #e2e8f0;
|
|
|
- --border-dark: #d1d5db;
|
|
|
+ --bg-hover: rgba(42, 139, 242, 0.05);
|
|
|
+ --bg-active: rgba(42, 139, 242, 0.1);
|
|
|
+ --border: #edf2f7;
|
|
|
+ --border-dark: #e2e8f0;
|
|
|
--text-primary: #1e293b;
|
|
|
- --text-secondary: #475569;
|
|
|
+ --text-secondary: #64748b;
|
|
|
--text-muted: #94a3b8;
|
|
|
--accent: #2a8bf2;
|
|
|
- --radius: 4px;
|
|
|
- --sidebar-w: 240px;
|
|
|
- --nav-h: 60px;
|
|
|
+ --radius-sm: 6px;
|
|
|
+ --radius-md: 12px;
|
|
|
+ --radius-lg: 16px;
|
|
|
+ --sidebar-w: 260px;
|
|
|
+ --nav-h: 64px;
|
|
|
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
|
|
|
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
|
}
|
|
|
|
|
|
body {
|
|
|
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
|
|
+ font-family: 'Outfit', 'Inter', -apple-system, sans-serif;
|
|
|
background: var(--bg-base);
|
|
|
color: var(--text-primary);
|
|
|
height: 100vh;
|
|
|
overflow: hidden;
|
|
|
- line-height: 1.5;
|
|
|
+ line-height: 1.6;
|
|
|
}
|
|
|
|
|
|
/* --- Global Layout --- */
|
|
|
@@ -57,21 +61,33 @@
|
|
|
.navbar {
|
|
|
height: var(--nav-h);
|
|
|
background: var(--bg-nav);
|
|
|
- border-bottom: 2px solid #edeff2;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- padding: 0 40px;
|
|
|
+ padding: 0 32px;
|
|
|
z-index: 100;
|
|
|
flex-shrink: 0;
|
|
|
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);
|
|
|
}
|
|
|
|
|
|
.nav-logo {
|
|
|
font-size: 20px;
|
|
|
- font-weight: 700;
|
|
|
- color: #2c3e50;
|
|
|
- margin-right: 60px;
|
|
|
+ font-weight: 800;
|
|
|
+ color: #0f172a;
|
|
|
+ margin-right: 48px;
|
|
|
white-space: nowrap;
|
|
|
- letter-spacing: 0.5px;
|
|
|
+ letter-spacing: -0.5px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nav-logo::before {
|
|
|
+ content: '';
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ background: linear-gradient(135deg, var(--accent), #6366f1);
|
|
|
+ border-radius: 8px;
|
|
|
}
|
|
|
|
|
|
.nav-menu {
|
|
|
@@ -87,18 +103,19 @@
|
|
|
height: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- padding: 0 4px;
|
|
|
+ padding: 0 16px;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.nav-item::after {
|
|
|
content: '';
|
|
|
position: absolute;
|
|
|
- bottom: -2px;
|
|
|
- left: -4px;
|
|
|
- right: -4px;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
height: 3px;
|
|
|
background: var(--accent);
|
|
|
+ border-radius: 3px 3px 0 0;
|
|
|
}
|
|
|
|
|
|
/* --- Main Content Layout --- */
|
|
|
@@ -114,65 +131,63 @@
|
|
|
background: var(--bg-sidebar);
|
|
|
border-right: 1px solid var(--border);
|
|
|
overflow-y: auto;
|
|
|
- padding: 12px;
|
|
|
- }
|
|
|
-
|
|
|
- .sidebar-group {
|
|
|
- margin-bottom: 8px;
|
|
|
- border: 1px solid #edeff2;
|
|
|
- border-radius: 4px;
|
|
|
- overflow: hidden;
|
|
|
+ padding: 24px 12px;
|
|
|
}
|
|
|
|
|
|
- .sidebar-tag {
|
|
|
- font-size: 20px;
|
|
|
+ .sidebar-title {
|
|
|
+ font-size: 11px;
|
|
|
font-weight: 700;
|
|
|
- padding: 8px 16px;
|
|
|
- text-transform: lowercase;
|
|
|
- width: 100%;
|
|
|
- border-bottom: 1px solid #edeff2;
|
|
|
- }
|
|
|
-
|
|
|
- .tag-how {
|
|
|
- background: #dcfce7;
|
|
|
- color: #166534;
|
|
|
- }
|
|
|
-
|
|
|
- .tag-what {
|
|
|
- background: #fef3c7;
|
|
|
- color: #92400e;
|
|
|
+ color: var(--text-muted);
|
|
|
+ padding: 8px 12px;
|
|
|
+ text-transform: uppercase;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ margin-bottom: 4px;
|
|
|
}
|
|
|
|
|
|
.sidebar-list {
|
|
|
list-style: none;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
}
|
|
|
|
|
|
.sidebar-item {
|
|
|
- padding: 10px 16px;
|
|
|
+ padding: 12px 16px;
|
|
|
font-size: 14px;
|
|
|
- color: #4b5563;
|
|
|
+ color: var(--text-secondary);
|
|
|
cursor: pointer;
|
|
|
display: flex;
|
|
|
- justify-content: center;
|
|
|
align-items: center;
|
|
|
- transition: all 0.2s;
|
|
|
- border-bottom: 1px solid #f1f5f9;
|
|
|
+ gap: 12px;
|
|
|
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
+ border-radius: var(--radius-md);
|
|
|
+ border: none;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
|
|
|
- .sidebar-item:last-child {
|
|
|
- border-bottom: none;
|
|
|
+ .sidebar-item .s-icon {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ opacity: 0.7;
|
|
|
}
|
|
|
|
|
|
.sidebar-item:hover {
|
|
|
background: var(--bg-hover);
|
|
|
color: var(--text-primary);
|
|
|
+ transform: translateX(4px);
|
|
|
}
|
|
|
|
|
|
.sidebar-item.active {
|
|
|
- background: #ffffff;
|
|
|
+ background: var(--bg-active);
|
|
|
color: var(--accent);
|
|
|
font-weight: 600;
|
|
|
- box-shadow: inset 4px 0 0 var(--accent);
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sidebar-item.active .s-icon {
|
|
|
+ opacity: 1;
|
|
|
+ color: var(--accent);
|
|
|
}
|
|
|
|
|
|
/* --- Content Area --- */
|
|
|
@@ -180,38 +195,51 @@
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
overflow: hidden;
|
|
|
+ padding: 24px 32px;
|
|
|
}
|
|
|
|
|
|
.table-container {
|
|
|
flex: 1;
|
|
|
overflow: auto;
|
|
|
- padding: 24px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: var(--radius-lg);
|
|
|
+ box-shadow: var(--shadow);
|
|
|
+ border: 1px solid var(--border);
|
|
|
}
|
|
|
|
|
|
.records-table {
|
|
|
width: 100%;
|
|
|
- border-collapse: collapse;
|
|
|
- background: #ffffff;
|
|
|
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
+ border-collapse: separate;
|
|
|
+ border-spacing: 0;
|
|
|
min-width: 1000px;
|
|
|
}
|
|
|
|
|
|
.records-table thead th {
|
|
|
- background: #eff2f5;
|
|
|
- color: #1e293b;
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 600;
|
|
|
+ background: #f8fafc;
|
|
|
+ color: var(--text-secondary);
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 700;
|
|
|
+ text-transform: uppercase;
|
|
|
+ letter-spacing: 0.5px;
|
|
|
text-align: left;
|
|
|
- padding: 12px 16px;
|
|
|
- border: 1px solid var(--border-dark);
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 10;
|
|
|
}
|
|
|
|
|
|
.records-table td {
|
|
|
- padding: 12px 16px;
|
|
|
- border: 1px solid var(--border-dark);
|
|
|
- vertical-align: middle;
|
|
|
+ padding: 20px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ vertical-align: top;
|
|
|
font-size: 14px;
|
|
|
- color: #334155;
|
|
|
+ color: var(--text-primary);
|
|
|
+ transition: background 0.15s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .records-table tr:last-child td {
|
|
|
+ border-bottom: none;
|
|
|
}
|
|
|
|
|
|
.records-table tr:hover td {
|
|
|
@@ -219,24 +247,34 @@
|
|
|
}
|
|
|
|
|
|
.id-col {
|
|
|
- width: 120px;
|
|
|
- font-family: monospace;
|
|
|
- color: var(--text-muted);
|
|
|
+ width: 100px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .commit-badge {
|
|
|
+ font-family: 'JetBrains Mono', monospace;
|
|
|
+ background: #f1f5f9;
|
|
|
+ color: var(--text-secondary);
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: var(--radius-sm);
|
|
|
+ font-size: 12px;
|
|
|
+ display: inline-block;
|
|
|
}
|
|
|
|
|
|
.msg-col {
|
|
|
- width: 300px;
|
|
|
- font-weight: 500;
|
|
|
+ width: 260px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #0f172a;
|
|
|
}
|
|
|
|
|
|
/* Bubble Tree Hierarchical Styles */
|
|
|
.bubble-tree {
|
|
|
background: #ffffff;
|
|
|
- border: 1px solid var(--border-dark);
|
|
|
- border-radius: 4px;
|
|
|
- padding: 4px;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: var(--radius-md);
|
|
|
+ padding: 8px;
|
|
|
min-height: 48px;
|
|
|
- min-width: 200px;
|
|
|
+ min-width: 220px;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
|
|
|
}
|
|
|
|
|
|
.fg-header {
|
|
|
@@ -470,14 +508,7 @@
|
|
|
<div class="main-container">
|
|
|
<aside class="sidebar">
|
|
|
<div id="sidebarContent">
|
|
|
- <div class="sidebar-group">
|
|
|
- <div class="sidebar-tag tag-how">how</div>
|
|
|
- <ul class="sidebar-list" id="howList"></ul>
|
|
|
- </div>
|
|
|
- <div class="sidebar-group">
|
|
|
- <div class="sidebar-tag tag-what">what</div>
|
|
|
- <ul class="sidebar-list" id="whatList"></ul>
|
|
|
- </div>
|
|
|
+ <ul class="sidebar-list" id="stageList"></ul>
|
|
|
</div>
|
|
|
</aside>
|
|
|
|
|
|
@@ -498,6 +529,11 @@
|
|
|
folder: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>',
|
|
|
download: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>',
|
|
|
chevron: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>',
|
|
|
+ // Stage icons
|
|
|
+ topic: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"></path><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path></svg>',
|
|
|
+ what: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path></svg>',
|
|
|
+ craft: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"></path><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path><path d="M2 2l7.5 1.5"></path><path d="M14 11l5 5"></path></svg>',
|
|
|
+ gear: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><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 .33-1.82 1.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 1.82.33H9a1.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"></path></svg>',
|
|
|
};
|
|
|
|
|
|
const PAGE_SIZE = 20;
|
|
|
@@ -540,14 +576,33 @@
|
|
|
}
|
|
|
|
|
|
function renderSidebar() {
|
|
|
- const howL = $('howList'), whatL = $('whatList');
|
|
|
- howL.innerHTML = ''; whatL.innerHTML = '';
|
|
|
- S.stages.forEach(st => {
|
|
|
+ const list = $('stageList');
|
|
|
+ list.innerHTML = '';
|
|
|
+
|
|
|
+ const STAGE_ORDER = ['how选题', 'what选题', 'what创作', 'what制作'];
|
|
|
+ const STAGE_ICONS = {
|
|
|
+ 'how选题': IC.topic,
|
|
|
+ 'what选题': IC.what,
|
|
|
+ 'what创作': IC.craft,
|
|
|
+ 'what制作': IC.gear
|
|
|
+ };
|
|
|
+
|
|
|
+ const sortedStages = [...S.stages].sort((a, b) => {
|
|
|
+ const idxA = STAGE_ORDER.indexOf(a.name);
|
|
|
+ const idxB = STAGE_ORDER.indexOf(b.name);
|
|
|
+ if (idxA !== -1 && idxB !== -1) return idxA - idxB;
|
|
|
+ if (idxA !== -1) return -1;
|
|
|
+ if (idxB !== -1) return 1;
|
|
|
+ return a.name.localeCompare(b.name);
|
|
|
+ });
|
|
|
+
|
|
|
+ sortedStages.forEach(st => {
|
|
|
const li = document.createElement('li');
|
|
|
li.className = 'sidebar-item';
|
|
|
- li.innerHTML = `${esc(st.name.split('/').pop())}`;
|
|
|
+ const icon = STAGE_ICONS[st.name] || IC.file;
|
|
|
+ li.innerHTML = `<span class="s-icon">${icon}</span>${esc(st.name)}`;
|
|
|
li.onclick = () => selectStage(li, st.name);
|
|
|
- (st.name.toLowerCase().includes('how') || st.name.toLowerCase().includes('test') ? howL : whatL).appendChild(li);
|
|
|
+ list.appendChild(li);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -604,7 +659,7 @@
|
|
|
|
|
|
S.records.forEach(r => {
|
|
|
h += `<tr>
|
|
|
- <td class="id-col">${esc(r.commit_id.substring(0, 8))}</td>
|
|
|
+ <td class="id-col"><span class="commit-badge">${esc(r.commit_id.substring(0, 8))}</span></td>
|
|
|
<td class="msg-col">${esc(r.commit_message || '无描述')}</td>`;
|
|
|
|
|
|
sortedIn.forEach(l => {
|