refactor(web): replace entry global header with sidebar brand + reorder bottom chips

Pre-existing layout: a global \`AppChromeHeader\` strip sat across the
whole top of EntryView (logo + settings gear), then a 2-column body
below it. Visual mass concentrated in a thin horizontal bar that did
not relate to the page's column structure, and the settings gear
duplicated the bottom Local-CLI chip.

New layout matches the two-column "brand-in-sidebar + tabs-in-main"
pattern: the brand block lives at the top of \`.entry-side\` (left
column), the right tabs live at the top of \`.entry-main\`, and the
vertical divider between them is the only horizontal seam.

EntryView:

- Drop \`<AppChromeHeader actions={avatarMenu} />\` from EntryView's
  render — the home page no longer renders the global chrome strip.
  (ProjectView still uses AppChromeHeader for back-nav / file
  actions, so the component itself stays in the codebase.)
- Add a sidebar brand block inside \`.entry-side\` using the
  already-defined \`.entry-brand\` / \`.entry-brand-mark\` /
  \`.entry-brand-title\` classes that were sitting dead in
  index.css.
- Reorder \`.entry-side-foot\` chips so that the env-critical
  Local CLI row sits on top of the row, with the secondary
  toggles (language picker, pet adoption, X follow icon) compact
  on a second row. The Follow @nexudotio chip drops its text
  label and becomes icon-only — pure marketing content, so it no
  longer earns a full-width pill.
- Settings access moves entirely to the Local CLI chip's existing
  click handler; the top-right gear is gone (it was a duplicate).

CSS:

- \`.entry-shell\` grid: \`auto 1fr\` → \`1fr\` (no header row).
- \`.entry-side\` background: \`var(--bg-panel)\` → \`transparent\`,
  so the sidebar shares the page beige and only the New-prototype
  card reads as white. Removes the "everything on the left is on
  one big white sheet" feeling.
- \`.entry-brand\` gets \`padding: 24px 20px 18px\` so the logo +
  title block has breathing room at the top of the sidebar.
- \`.entry-brand-mark\` width/height \`44 → 34\`. The previous
  44px gradient ring was visually heavier than the title text it
  sat next to.
- \`.entry-brand-title\` weight \`600 → 450\`, color
  \`var(--text-strong)\` → \`var(--text)\`. Serif title still
  reads as the page anchor without the chunky "bold black" stamp.
- \`.entry-brand-actions\` added for future right-aligned actions
  (carries no actual content in this commit — kept so re-adding a
  settings/avatar entry point doesn't need new CSS).
- \`.entry-side-foot .foot-pill\` slim pass: padding
  \`4px 10px → 3px 8px\`, font \`11.5px → 10.5px\`, gap \`6 → 5\`,
  plus \`justify-content: center\` and \`min-height: 24px\` so the
  icon-only Follow pill stays the same height as the text pills
  next to it.
This commit is contained in:
SidQin-cyber
2026-05-12 12:11:40 +08:00
parent 13dc8a654e
commit 5fe5721cba
2 changed files with 46 additions and 30 deletions
+29 -21
View File
@@ -469,7 +469,6 @@ export function EntryView({
return ( return (
<div className="entry-shell"> <div className="entry-shell">
<AppChromeHeader actions={avatarMenu} />
<div <div
className={`entry${petRailHidden ? '' : ' has-pet-rail'}`} className={`entry${petRailHidden ? '' : ' has-pet-rail'}`}
style={{ style={{
@@ -479,6 +478,16 @@ export function EntryView({
}} }}
> >
<aside className="entry-side" style={{ width: sidebarWidth }}> <aside className="entry-side" style={{ width: sidebarWidth }}>
<div className="entry-brand">
<span className="entry-brand-mark" aria-hidden>
<img src="/app-icon.svg" alt="" className="brand-mark-img" draggable={false} />
</span>
<div className="entry-brand-text">
<div className="entry-brand-title-row">
<span className="entry-brand-title">{t('app.brand')}</span>
</div>
</div>
</div>
<NewProjectPanel <NewProjectPanel
skills={skills} skills={skills}
designSystems={designSystems} designSystems={designSystems}
@@ -496,7 +505,26 @@ export function EntryView({
loading={skillsLoading || designSystemsLoading} loading={skillsLoading || designSystemsLoading}
/> />
<div className="entry-side-foot"> <div className="entry-side-foot">
<button
type="button"
className="foot-pill foot-pill-env"
onClick={() => onOpenSettings()}
aria-label={t('settings.envConfigure')}
title={t('settings.envConfigure')}
>
<Icon name="settings" size={12} />
<span>
{config.mode === 'daemon'
? t('settings.localCli')
: apiProtocolLabel(config.apiProtocol)}
</span>
<span style={{ color: 'var(--text-faint)' }}>·</span>
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 180 }}>
{envMetaLine}
</span>
</button>
<div className="entry-side-foot-row"> <div className="entry-side-foot-row">
<LanguageMenu />
<button <button
type="button" type="button"
className={`foot-pill pet-pill${config.pet?.adopted ? '' : ' pet-pill-fresh'}`} className={`foot-pill pet-pill${config.pet?.adopted ? '' : ' pet-pill-fresh'}`}
@@ -530,28 +558,8 @@ export function EntryView({
aria-label="Follow @nexudotio on X" aria-label="Follow @nexudotio on X"
> >
<Icon name="external-link" size={12} /> <Icon name="external-link" size={12} />
<span className="foot-pill-follow-label">Follow @nexudotio</span>
</a> </a>
</div> </div>
<button
type="button"
className="foot-pill"
onClick={() => onOpenSettings()}
aria-label={t('settings.envConfigure')}
title={t('settings.envConfigure')}
>
<Icon name="settings" size={12} />
<span>
{config.mode === 'daemon'
? t('settings.localCli')
: apiProtocolLabel(config.apiProtocol)}
</span>
<span style={{ color: 'var(--text-faint)' }}>·</span>
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 180 }}>
{envMetaLine}
</span>
</button>
<LanguageMenu />
</div> </div>
<button <button
type="button" type="button"
+17 -9
View File
@@ -3656,7 +3656,7 @@ code {
============================================================ */ ============================================================ */
.entry-shell { .entry-shell {
display: grid; display: grid;
grid-template-rows: auto 1fr; grid-template-rows: 1fr;
height: 100vh; height: 100vh;
min-height: 0; min-height: 0;
background: var(--bg); background: var(--bg);
@@ -3672,7 +3672,7 @@ code {
.entry-side { .entry-side {
border-right: 1px solid var(--border); border-right: 1px solid var(--border);
background: var(--bg-panel); background: transparent;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -3681,10 +3681,16 @@ code {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
padding: 24px 20px 18px;
}
.entry-brand-actions {
margin-left: auto;
display: inline-flex;
align-items: center;
} }
.entry-brand-mark { .entry-brand-mark {
width: 44px; width: 34px;
height: 44px; height: 34px;
border-radius: 50%; border-radius: 50%;
background: linear-gradient(135deg, var(--accent-tint) 0%, var(--accent-soft) 100%); background: linear-gradient(135deg, var(--accent-tint) 0%, var(--accent-soft) 100%);
color: var(--accent); color: var(--accent);
@@ -3711,11 +3717,11 @@ code {
} }
.entry-brand-title { .entry-brand-title {
font-family: var(--serif); font-family: var(--serif);
font-weight: 600; font-weight: 450;
font-size: 22px; font-size: 22px;
letter-spacing: -0.015em; letter-spacing: -0.015em;
line-height: 1; line-height: 1;
color: var(--text-strong); color: var(--text);
} }
.entry-brand-pill { .entry-brand-pill {
font-size: 10.5px; font-size: 10.5px;
@@ -4792,12 +4798,14 @@ code {
.entry-side-foot .foot-pill { .entry-side-foot .foot-pill {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 6px; justify-content: center;
padding: 4px 10px; gap: 5px;
padding: 3px 8px;
min-height: 24px;
background: var(--bg-subtle); background: var(--bg-subtle);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-pill); border-radius: var(--radius-pill);
font-size: 11.5px; font-size: 10.5px;
color: var(--text-muted); color: var(--text-muted);
align-self: flex-start; align-self: flex-start;
cursor: pointer; cursor: pointer;