style(web): polish the chat, repo and shell surfaces
Tidy the pieces that made the workspace feel noisy: pins and member rows get lighter hover surfaces, the repo toolbar keeps its ref picker inside the page and hands the clone box to the title row, search and empty states share one look, and prose falls back to the shell's system font stack now that Geist is no longer loaded from Google.
ZhenYi committed
Modified web/src/app/styles/index.css web/src/app/styles/index.css +1 −1 View web/src/app/styles/index.css
@@ -114,7 +114,7 @@
114114 --color-shell-hairline: var(--shell-hairline);
115115
116116 --font-mono: "JetBrains Mono", ui-monospace, monospace;
117 --font-sans: "Geist", "Inter", "PingFang SC", "Microsoft YaHei", ui-sans-serif, system-ui, sans-serif;
117 --font-sans: BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, "Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", Arial, "PingFang SC", "Source Han Sans SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
118118
119119 --radius-card: 16px;
120120 --radius-field: 10px;
Modified web/src/app/styles/workspace.css web/src/app/styles/workspace.css +6 −1 View web/src/app/styles/workspace.css
@@ -135,11 +135,16 @@
135135 body:has(.chat-panel-resized) .global-search-trigger { display: none; }
136136 body:has(.chat-panel-resized) .workspace-main .chat-header { padding-right: 24px; }
137137}
138.global-search-overlay { animation: global-search-fade 140ms ease-out both; }
139.global-search-dialog { animation: global-search-pop 180ms cubic-bezier(.2, .8, .2, 1) both; transform-origin: 50% 0; }
140@keyframes global-search-fade { from { opacity: 0; } to { opacity: 1; } }
141@keyframes global-search-pop { from { opacity: 0; transform: translateY(-10px) scale(.985); } to { opacity: 1; transform: translateY(0) scale(1); } }
142@media (prefers-reduced-motion: reduce) { .global-search-overlay, .global-search-dialog { animation: none; } }
138143.workspace-mobile-bar, .workspace-drawer-close, .workspace-scrim { display: none; }
139144.workspace-skip { position: fixed; left: 12px; top: -80px; z-index: 100; padding: 10px 16px; border-radius: 10px; color: white; background: var(--shell-action); }
140145.workspace-skip:focus { top: 12px; }
141146.shell-top-bar { display: flex; align-items: center; gap: 12px; min-height: 76px; flex-shrink: 0; padding: 14px 24px; border-bottom: 1px solid var(--shell-hairline); }
142.shell-top-icon { display: grid; place-items: center; width: 38px; height: 38px; flex-shrink: 0; border: 1px solid var(--shell-hairline); border-radius: 12px; color: var(--shell-ink-muted); background: var(--shell-field); }
147.shell-top-icon { display: grid; place-items: center; width: 38px; height: 38px; flex-shrink: 0; border-radius: 12px; color: var(--shell-ink); background: transparent; }
143148.shell-top-icon svg { color: inherit; }
144149.shell-top-actions { display: flex; flex-shrink: 0; align-items: center; gap: 10px; color: var(--shell-ink-muted); }
145150.workspace-nav-row { position: relative; min-height: 32px; margin-bottom: 2px; gap: 10px; border-radius: 8px; transition: background 160ms, color 160ms; }
Modified web/src/entities/repo/ui/embed.css web/src/entities/repo/ui/embed.css +1 −1 View web/src/entities/repo/ui/embed.css
@@ -243,7 +243,7 @@
243243/* ---------- readme typography ------------------------------------------- */
244244.repo-embed .markdown-body,
245245.repo-embed [data-component='git-readme'] {
246 font-family: var(--font-sans, 'Geist', 'Inter', 'PingFang SC', 'Microsoft YaHei', ui-sans-serif, system-ui, sans-serif);
246 font-family: var(--font-sans, BlinkMacSystemFont, 'Segoe UI', system-ui, Roboto, 'Noto Sans', Ubuntu, Cantarell, 'Helvetica Neue', Arial, 'PingFang SC', 'Source Han Sans SC', 'Microsoft YaHei UI', 'Microsoft YaHei', 'Noto Sans CJK SC', sans-serif);
247247}
248248.repo-embed .markdown-body h1,
249249.repo-embed [data-component='git-readme'] h1 {
Modified web/src/features/chat/ui/chat-polish.css web/src/features/chat/ui/chat-polish.css +23 −10 View web/src/features/chat/ui/chat-polish.css
@@ -7,25 +7,28 @@
77 min-height: 76px;
88 align-items: center;
99 gap: 12px;
10 padding: 14px 24px;
10 /* 13px(而不是 14px):标题块 48 + 上下留白 26 + 底部 1px 线恰好 75,由
11 min-height 收到 76,与右侧面板头的 76 精确对齐。 */
12 padding: 13px 24px;
1113 border-bottom: 1px solid var(--shell-hairline);
1214 background: color-mix(in srgb, var(--shell-surface) 94%, var(--shell-field));
1315}
16/* 纯字形:无底色无边框,`#` 用主墨色(浅色主题下渲染为黑色)。38px 的占位
17 保持与两行标题的垂直对齐。 */
1418.chat-channel-icon {
1519 display: grid;
1620 width: 38px;
1721 height: 38px;
1822 flex: 0 0 auto;
1923 place-items: center;
20 border: 1px solid var(--shell-hairline);
2124 border-radius: 12px;
22 color: var(--shell-ink-muted);
23 background: var(--shell-field);
25 color: var(--shell-ink);
26 background: transparent;
2427}
2528.chat-heading { min-width: 0; flex: 1; }
2629.chat-topic { margin-top: 2px; overflow: hidden; color: var(--shell-ink-muted); font-size: 12px; line-height: 1.5; text-overflow: ellipsis; white-space: nowrap; }
2730.chat-header-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 4px; }
28.chat-header-actions > button, .chat-search-action, .chat-panel-close {
31.chat-header-actions > button, .chat-panel-close {
2932 display: inline-grid;
3033 width: 36px;
3134 height: 36px;
@@ -34,7 +37,7 @@
3437 color: var(--shell-ink-muted);
3538 transition: color 160ms, background 160ms;
3639}
37.chat-header-actions > button:hover, .chat-search-action:hover, .chat-panel-close:hover { color: var(--shell-ink); background: var(--shell-active); }
40.chat-header-actions > button:hover, .chat-panel-close:hover { color: var(--shell-ink); background: var(--shell-active); }
3841.chat-action-label { display: none; }
3942.chat-message-list { padding: 8px 12px 16px; scroll-padding-block: 20px; }
4043.chat-history-start { margin: 20px 8px 8px; color: var(--shell-ink-muted); font-size: 12px; text-align: center; }
@@ -95,8 +98,17 @@
9598.chat-panel-resize-handle::after { position: absolute; top: 50%; left: 5px; width: 2px; height: 44px; border-radius: 999px; background: var(--shell-focus); content: ''; opacity: 0; transform: translateY(-50%); transition: opacity 150ms; }
9699.chat-panel-resize-handle:hover::after, .chat-panel-resize-handle:focus-visible::after, .chat-panel-resizing .chat-panel-resize-handle::after { opacity: 1; }
97100.chat-panel-focus-scrim { position: absolute; z-index: 25; inset: 0; background: color-mix(in srgb, var(--shell-surface) 38%, transparent); backdrop-filter: blur(8px) saturate(.86); -webkit-backdrop-filter: blur(8px) saturate(.86); }
98.chat-panel-header { min-height: 60px; padding: 0 16px; }
99.chat-panel-empty { padding: 32px 20px; }
101.chat-panel-header { min-height: 76px; padding: 0 16px; }
102.chat-panel-empty { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 40px 24px; text-align: center; }
103.chat-panel-empty-icon {
104 display: grid;
105 width: 44px;
106 height: 44px;
107 place-items: center;
108 border-radius: 15px;
109 color: var(--shell-ink-muted);
110 background: var(--shell-field);
111}
100112.chat-popover { box-shadow: 0 14px 40px rgb(24 28 31 / 16%); }
101113.chat-popover button { cursor: pointer; }
102114
@@ -161,9 +173,10 @@
161173}
162174@media (max-width: 760px) {
163175 .chat-header { min-height: 68px; padding: 12px 16px; }
176 .chat-panel-header { min-height: 68px; }
164177 .chat-channel-icon { width: 34px; height: 34px; border-radius: 10px; }
165178 .chat-header-actions { gap: 1px; }
166 .chat-header-actions > button, .chat-search-action { width: 32px; height: 32px; }
179 .chat-header-actions > button { width: 32px; height: 32px; }
167180 .chat-message-list { padding: 6px 8px 12px; }
168181 .chat-message-row { gap: 10px; padding-left: 8px; padding-right: 8px; }
169182 .chat-message-toolbar { right: 8px; opacity: 1; pointer-events: auto; }
@@ -174,7 +187,7 @@
174187}
175188@media (max-width: 420px) {
176189 .chat-header { gap: 8px; padding: 10px 12px; }
177 .chat-header-actions > button, .chat-search-action { width: 30px; height: 30px; }
190 .chat-header-actions > button { width: 30px; height: 30px; }
178191}
179192@media (prefers-reduced-motion: reduce) {
180193 .chat-message-toolbar, .chat-send-button { transition: none; }
Modified web/src/features/repo-browse/ui/code-tab.tsx web/src/features/repo-browse/ui/code-tab.tsx +20 −11 View web/src/features/repo-browse/ui/code-tab.tsx
@@ -1,4 +1,4 @@
1import { useEffect, useMemo, useRef, useState } from 'react'
1import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
22import { ArrowLeft, ArrowUp, ChevronRight, Eye, File as FileIcon, FileCode, Folder, FolderGit2, History, Users } from 'lucide-react'
33import { useT } from '@/shared/i18n'
44import { fmtRelative, fmtTime, formatBytes, repoKey, shortSha, useAsync } from '@/shared/lib'
@@ -27,6 +27,7 @@
2727 repo: string
2828 rev: string
2929 repoDto: RepoDetail
30 refs?: ReactNode
3031 mode: 'html' | 'json'
3132 /** Directory being listed ('' = repo root). Owned by the route. */
3233 path: string
@@ -52,6 +53,7 @@
5253 repo,
5354 rev,
5455 repoDto,
56 refs,
5557 mode,
5658 path,
5759 file,
@@ -83,6 +85,7 @@
8385 if (file) {
8486 return (
8587 <FileView
88 refs={refs}
8689 space={space}
8790 repo={repo}
8891 rev={rev}
@@ -96,6 +99,7 @@
9699 }
97100 return (
98101 <DirectoryView
102 refs={refs}
99103 space={space}
100104 repo={repo}
101105 rev={rev}
@@ -109,6 +113,7 @@
109113/* ------------------------------------------------------------ directory -- */
110114
111115function DirectoryView({
116 refs,
112117 space,
113118 repo,
114119 rev,
@@ -122,20 +127,18 @@
122127 path: string
123128 mode: 'html' | 'json'
124129 routes: FragmentRoutes
130 refs?: ReactNode
125131}) {
126132 return (
127133 <div className="repo-code-view">
128134 <div className="repo-tree-card">
129 <div className="repo-directory-header flex flex-wrap items-center gap-2">
130 <div className="min-w-0 flex-1">
131 <Breadcrumbs path={path} onNavigate={routes.onNavigate} />
132 </div>
133 </div>
135 {refs ? <div className="repo-refs-row">{refs}</div> : null}
134136 <DirectoryCommitBar
135137 space={space}
136138 repo={repo}
137139 rev={rev}
138140 path={path}
141 onNavigate={routes.onNavigate}
139142 onOpenCommit={routes.onOpenCommit}
140143 onShowHistory={routes.onShowHistory}
141144 />
@@ -228,6 +231,7 @@
228231 repo,
229232 rev,
230233 path,
234 onNavigate,
231235 onOpenCommit,
232236 onShowHistory,
233237}: {
@@ -235,6 +239,7 @@
235239 repo: string
236240 rev: string
237241 path: string
242 onNavigate: (path: string) => void
238243 onOpenCommit: (sha: string) => void
239244 onShowHistory: (path: string) => void
240245}) {
@@ -247,12 +252,13 @@
247252 const commit = state.data?.commits?.[0]
248253 return (
249254 <div className="repo-commit-bar flex items-center gap-2">
255 <Breadcrumbs path={path} onNavigate={onNavigate} />
250256 {commit ? (
251257 <button
252258 type="button"
253259 onClick={() => onOpenCommit(commit.id)}
254260 title={commit.message}
255 className="repo-commit-bar-main flex min-w-0 flex-1 items-center gap-2.5 text-left"
261 className="repo-commit-bar-main ml-auto flex min-w-0 items-center gap-2.5 text-left"
256262 >
257263 <InitialAvatar name={commit.author_name || '?'} size={22} />
258264 <span className="shrink-0 text-[12.5px] font-medium">{commit.author_name || t('repo.commit.unknownAuthor')}</span>
@@ -407,7 +413,7 @@
407413const SANDBOX_CSS = `
408414*,*::before,*::after{box-sizing:border-box}
409415html,body{margin:0;padding:0;overflow:hidden}
410body{padding:24px 28px;background:var(--shell-surface,#fff);color:var(--shell-ink,#1c1e22);font-family:var(--font-sans,'Geist','Inter','PingFang SC','Microsoft YaHei',ui-sans-serif,system-ui,sans-serif);font-size:14px;line-height:1.85}
416body{padding:24px 28px;background:var(--shell-surface,#fff);color:var(--shell-ink,#1c1e22);font-family:var(--font-sans,BlinkMacSystemFont,'Segoe UI',system-ui,Roboto,'Noto Sans',Ubuntu,Cantarell,'Helvetica Neue',Arial,'PingFang SC','Source Han Sans SC','Microsoft YaHei UI','Microsoft YaHei','Noto Sans CJK SC',sans-serif);font-size:14px;line-height:1.85}
411417.repo-embed .markdown-body{max-width:900px;margin:0 auto}
412418.repo-embed .markdown-body a{color:var(--shell-ink);text-underline-offset:3px}
413419@media(max-width:600px){body{padding:18px}}
@@ -506,10 +512,10 @@
506512})()
507513`
508514
509/** The same Google-hosted webfonts the app shell loads, so README prose and
510 * code render in Geist / JetBrains Mono instead of the system fallback. */
515/** The same Google-hosted webfont the app shell loads, so README code renders
516 * in JetBrains Mono; prose follows the shell's system font stack. */
511517const README_FONTS_IMPORT =
512 '@import url("https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=JetBrains+Mono:wght@400;500;700;800&display=swap");'
518 '@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&display=swap");'
513519
514520function readmeDocument(bodyHtml: string): string {
515521 return `<!DOCTYPE html><html><head><meta charset="utf-8"><style>${README_FONTS_IMPORT}:root{${shellVarDeclarations()}}${embedCssText}${SANDBOX_CSS}</style></head><body class="repo-embed"><div class="markdown-body">${bodyHtml}</div><script>${SANDBOX_SCRIPT}</script></body></html>`
@@ -757,6 +763,7 @@
757763/* ---------------------------------------------------------------- file --- */
758764
759765function FileView({
766 refs,
760767 space,
761768 repo,
762769 rev,
@@ -772,6 +779,7 @@
772779 mode: 'html' | 'json'
773780 file: FileRef
774781 line?: number
782 refs?: ReactNode
775783 routes: FragmentRoutes
776784 onBack: () => void
777785}) {
@@ -791,6 +799,7 @@
791799 leaf={leaf}
792800 onNavigate={routes.onNavigate}
793801 />
802 {refs ? <div className="repo-refs-row">{refs}</div> : null}
794803 <div className="repo-file-toolbar flex flex-wrap items-center gap-2">
795804 <button
796805 type="button"
Modified web/src/features/search/ui/global-search-command.tsx web/src/features/search/ui/global-search-command.tsx +2 −2 View web/src/features/search/ui/global-search-command.tsx
@@ -218,12 +218,12 @@
218218 <kbd className="hidden shrink-0 rounded border border-shell-hairline bg-shell-field px-1.5 py-0.5 font-mono text-[10px] lg:block">⌘K</kbd>
219219 </button>
220220 {open ? (
221 <div className="fixed inset-0 z-50 flex items-start justify-center bg-black/35 p-4 pt-[10vh]" onMouseDown={() => setOpen(false)}>
221 <div className="global-search-overlay fixed inset-0 z-50 flex items-start justify-center bg-black/35 p-4 pt-[10vh]" onMouseDown={() => setOpen(false)}>
222222 <section
223223 role="dialog"
224224 aria-modal="true"
225225 aria-label={t('search.command.dialog')}
226 className="w-full max-w-2xl overflow-hidden rounded-xl border border-shell-hairline bg-shell-surface shadow-2xl"
226 className="global-search-dialog w-full max-w-2xl overflow-hidden rounded-xl border border-shell-hairline bg-shell-surface shadow-2xl"
227227 onMouseDown={event => event.stopPropagation()}
228228 >
229229 <div className="flex items-center gap-2 border-b border-shell-hairline px-3">
Modified web/src/pages/workspace/ui/repo/repo-polish.css web/src/pages/workspace/ui/repo/repo-polish.css +7 −1 View web/src/pages/workspace/ui/repo/repo-polish.css
@@ -1,6 +1,12 @@
11
22.repo-view-content { min-height: 0; padding-top: 4px; }
3.repo-refs-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 7px 12px; border-bottom: 1px solid var(--shell-hairline); background: color-mix(in srgb, var(--shell-field) 45%, var(--shell-surface)); }
4.repo-refs-row > .repo-refs { width: 100%; }
5.repo-refs-row > .repo-refs > button { min-height: 36px; border: 1px solid var(--shell-hairline); border-radius: 9px; background: var(--shell-field); }
36.repo-toolbar { background: var(--shell-surface); }
7.repo-toolbar-tabs { order: 1; padding-left: 0; border-left: 0; }
8.repo-toolbar-clone { order: 2; }
9.repo-toolbar-refs { order: 3; flex: 1 1 100%; }
410.repo-toolbar-refs > span,
511.repo-toolbar-refs > .repo-refs > button { min-height: 36px; border: 1px solid var(--shell-hairline); border-radius: 9px; background: var(--shell-field); }
612.repo-toolbar-tabs nav { box-shadow: 0 1px 2px rgb(24 28 31 / 2%); }
@@ -81,7 +87,7 @@
8187.repo-action-button.is-on { border-color: var(--shell-tile); background: var(--shell-active); }
8288.repo-action-button:disabled { opacity: 60%; }
8389.repo-commit-bar { min-height: 42px; padding: 7px 12px; border-bottom: 1px solid var(--shell-hairline); }
84.repo-commit-bar-main { margin-left: -6px; min-height: 28px; border-radius: 7px; padding: 2px 6px; transition: background 150ms; }
90.repo-commit-bar-main { min-height: 28px; border-radius: 7px; padding: 2px 6px; transition: background 150ms; }
8591.repo-commit-bar-main:hover { background: var(--shell-field); }
8692.repo-commit-history { border-radius: 7px; padding: 4px 8px; color: var(--shell-ink-muted); font-size: 12.5px; transition: color 150ms, background 150ms; }
8793.repo-commit-history:hover { color: var(--shell-ink); background: var(--shell-field); }
Modified web/src/pages/workspace/ui/repo/repo-view.tsx web/src/pages/workspace/ui/repo/repo-view.tsx +16 −16 View web/src/pages/workspace/ui/repo/repo-view.tsx
@@ -180,26 +180,26 @@
180180 )
181181 }
182182
183 const refsPicker = (
184 <RefPicker
185 space={spaceName}
186 repo={repoName}
187 rev={rev}
188 onRevChange={setRev}
189 branchesCount={repo.branches_count ?? 0}
190 tagsCount={repo.tags_count ?? 0}
191 commitsCount={repo.commits_count ?? 0}
192 onShowCommits={() => setTab('commits')}
193 />
194 )
183195 return (
184196 <RepoLayout
185197 {...shell}
186198 title={`${spaceName} / ${repo.name}`}
187199 topic={repo.description ?? undefined}
188 refsSlot={
189 <>
190 <RefPicker
191 space={spaceName}
192 repo={repoName}
193 rev={rev}
194 onRevChange={setRev}
195 branchesCount={repo.branches_count ?? 0}
196 tagsCount={repo.tags_count ?? 0}
197 commitsCount={repo.commits_count ?? 0}
198 onShowCommits={() => setTab('commits')}
199 />
200 <RepoCloneMenu targets={clones} space={spaceName} repo={repoName} rev={rev || repo.default_branch || ''} />
201 </>
202 }
200 refsSlot={refsPicker}
201 showRefs={tab !== 'code'}
202 clone={<RepoCloneMenu targets={clones} space={spaceName} repo={repoName} rev={rev || repo.default_branch || ''} />}
203203 activeTab={tab}
204204 onTabChange={setTab}
205205 canAdmin={canManageRepo}
@@ -237,6 +237,7 @@
237237 repo={repoName}
238238 rev={rev}
239239 repoDto={repo}
240 refs={refsPicker}
240241 mode={mode}
241242 path={path}
242243 file={file}
@@ -357,4 +358,3 @@
357358 </RepoLayout>
358359 )
359360}
360
Modified web/index.html web/index.html +1 −1 View web/index.html
@@ -18,7 +18,7 @@
1818 <link rel="preconnect" href="https://fonts.googleapis.com" />
1919 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
2020 <link
21 href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=JetBrains+Mono:wght@400;500;700;800&display=swap"
21 href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&display=swap"
2222 rel="stylesheet"
2323 />
2424 </head>