@zmzai/theme 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/brand/brand-lockup/BrandLockup.tsx +61 -0
- package/src/brand/brand-lockup/index.ts +2 -0
- package/src/brand/index.ts +1 -0
- package/src/components/app-shell/AppShell.tsx +7 -3
- package/src/components/navbar/Navbar.tsx +3 -8
- package/src/components/page-header/PageHeader.tsx +14 -7
package/package.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn";
|
|
4
|
+
import { Logo } from "../logo";
|
|
5
|
+
import { Wordmark } from "../wordmark";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* BrandLockup — 全站统一的品牌锁标:云朵 Logo + ZMZAI wordmark + 子站标。
|
|
9
|
+
*
|
|
10
|
+
* 背景(2026-08-31):theme 有两套骨架,品牌区 API 不对称 ——
|
|
11
|
+
* Navbar 内置 Logo + Wordmark,AppShell 的 brand 只吃 {label, suffix} 文本。
|
|
12
|
+
* 结果走 Navbar 的站(Folio / Quill / Index / auth)有云朵标,
|
|
13
|
+
* 走 AppShell 的站(Tome / Plate / Margin)没有。抽成一处,谁都不许自造。
|
|
14
|
+
*
|
|
15
|
+
* 纪律(BRAND §7.7):
|
|
16
|
+
* · 云朵 Logo 只出现在品牌锁标里,不单独当装饰散落在页面各处
|
|
17
|
+
* · 子站标是站点对外的品牌名(书写系列),不是技术仓库名
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <BrandLockup sublabel="tome" /> // 白底(默认)
|
|
21
|
+
* <BrandLockup sublabel="auth" tone="dark" /> // 墨底叙事区
|
|
22
|
+
*/
|
|
23
|
+
export interface BrandLockupProps {
|
|
24
|
+
/** 云朵标直径(px),默认 22 —— 全站统一,不要按场景私调 */
|
|
25
|
+
logoSize?: number;
|
|
26
|
+
/** wordmark 字号(px),默认 16 */
|
|
27
|
+
markSize?: number;
|
|
28
|
+
/** ZMZAI 后的子站标,如 "tome" / "quill" / "auth" */
|
|
29
|
+
sublabel?: string;
|
|
30
|
+
/** 墨底载体:云朵标反白、文字转暗底配色,默认 "light" */
|
|
31
|
+
tone?: "light" | "dark";
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function BrandLockup({
|
|
36
|
+
logoSize = 22,
|
|
37
|
+
markSize = 16,
|
|
38
|
+
sublabel,
|
|
39
|
+
tone = "light",
|
|
40
|
+
className,
|
|
41
|
+
}: BrandLockupProps) {
|
|
42
|
+
const dark = tone === "dark";
|
|
43
|
+
return (
|
|
44
|
+
<span
|
|
45
|
+
className={cn(
|
|
46
|
+
"inline-flex items-center gap-2 select-none",
|
|
47
|
+
dark && "text-dark-ink",
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
<Logo size={logoSize} inverted={dark} />
|
|
52
|
+
<Wordmark
|
|
53
|
+
size={markSize}
|
|
54
|
+
sublabel={sublabel}
|
|
55
|
+
// 墨底时压掉 Wordmark 子标自带的 text-ink-3(暗底上不可读)。
|
|
56
|
+
// 任意变体选择器特异性高于单类名,能可靠覆盖。
|
|
57
|
+
className={dark ? "[&>span]:text-dark-ink/45" : undefined}
|
|
58
|
+
/>
|
|
59
|
+
</span>
|
|
60
|
+
);
|
|
61
|
+
}
|
package/src/brand/index.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
import type { ComponentType, ReactNode } from "react";
|
|
5
5
|
|
|
6
|
+
import { BrandLockup } from "../../brand/brand-lockup";
|
|
7
|
+
|
|
6
8
|
import { Badge } from "../badge/Badge";
|
|
7
9
|
import { Icon, type IconName } from "../icon/Icon";
|
|
8
10
|
import { CommandPalette, type AppPaletteItem } from "./CommandPalette";
|
|
@@ -130,9 +132,11 @@ export function AppShell({
|
|
|
130
132
|
}, [hasPalette]);
|
|
131
133
|
|
|
132
134
|
const brandBlock = (
|
|
133
|
-
<Link href={brand.href ?? "/"} className="flex
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
<Link href={brand.href ?? "/"} className="flex flex-col gap-1 px-2">
|
|
136
|
+
{/* 品牌区统一走 BrandLockup(2026-08-31 抽出,与 Navbar 共用一份锁标)。
|
|
137
|
+
label 同时是顶栏兜底标题与子站标,两处语义一致。 */}
|
|
138
|
+
<BrandLockup sublabel={brand.label} />
|
|
139
|
+
{brand.suffix ? <span className="font-mono text-[10px] text-ink-3">{brand.suffix}</span> : null}
|
|
136
140
|
</Link>
|
|
137
141
|
);
|
|
138
142
|
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { type ReactNode, useEffect, useState } from "react";
|
|
4
4
|
import { cn } from "../../utils/cn";
|
|
5
|
-
import {
|
|
6
|
-
import { Wordmark } from "../../brand/wordmark";
|
|
5
|
+
import { BrandLockup } from "../../brand/brand-lockup";
|
|
7
6
|
import { Icon } from "../icon/Icon";
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -66,12 +65,8 @@ export function Navbar({ sublabel, brand, children, actions, badge, brandHref, m
|
|
|
66
65
|
return () => window.removeEventListener("keydown", onKey);
|
|
67
66
|
}, [open]);
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<Logo size={22} />
|
|
72
|
-
<Wordmark size={16} sublabel={sublabel} />
|
|
73
|
-
</span>
|
|
74
|
-
);
|
|
68
|
+
// 品牌区统一走 BrandLockup(2026-08-31 抽出,与 AppShell 共用一份锁标)
|
|
69
|
+
const brandNode = brand ?? <BrandLockup sublabel={sublabel} />;
|
|
75
70
|
const nav = children ? (
|
|
76
71
|
<nav
|
|
77
72
|
className="flex min-w-0 items-center gap-1 overflow-x-auto"
|
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
* · 描述统一 text-sm text-ink-2 —— ink-3 只有 3.69:1,副文案不用它
|
|
16
16
|
*
|
|
17
17
|
* v0.9.5 追加 centered(居中 Hero,/quill 首页用)。
|
|
18
|
+
*
|
|
19
|
+
* v0.9.7 page 变体改版(用户定案 2026-08-31,与 BRAND 戒律 14 同步):
|
|
20
|
+
* · 眉标改 mono 小写间距体(原 sans semibold)—— 等宽小标是全站通用的小节语言
|
|
21
|
+
* · 标题从 text-2xl 提到 text-3xl,font-semibold → font-bold —— 衬线的视觉
|
|
22
|
+
* 体量比无衬线小,不放大反而显得比原来弱
|
|
23
|
+
* · 图标从 text-ink 降到 text-ink-2 —— 图标是辅助信息,不该跟标题同权重
|
|
24
|
+
* · 描述加 max-w-2xl + leading-7 —— 衬线大标题下的 sans 正文要更松才不挤
|
|
18
25
|
*/
|
|
19
26
|
|
|
20
27
|
import type { ReactNode } from "react";
|
|
@@ -93,19 +100,19 @@ export function PageHeader({
|
|
|
93
100
|
<header className={`flex flex-wrap items-end justify-between gap-3 ${className}`}>
|
|
94
101
|
<div className="min-w-0">
|
|
95
102
|
{eyebrow ? (
|
|
96
|
-
<small className="mb-1 block
|
|
103
|
+
<small className="mb-1.5 block font-mono text-[11px] uppercase tracking-[0.16em] text-ink-3">
|
|
97
104
|
{eyebrow}
|
|
98
105
|
</small>
|
|
99
106
|
) : null}
|
|
100
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
101
|
-
{icon ? <Icon name={icon} size={20} className="shrink-0 text-ink" /> : null}
|
|
102
|
-
<h1
|
|
103
|
-
className={`font-serif text-2xl font-semibold tracking-tight text-ink ${titleClassName}`}
|
|
104
|
-
>
|
|
107
|
+
<div className="flex min-w-0 items-center gap-2.5">
|
|
108
|
+
{icon ? <Icon name={icon} size={20} strokeWidth={1.5} className="shrink-0 text-ink-2" /> : null}
|
|
109
|
+
<h1 className={`font-serif text-3xl font-bold leading-[1.2] tracking-tight text-ink ${titleClassName}`}>
|
|
105
110
|
{title}
|
|
106
111
|
</h1>
|
|
107
112
|
</div>
|
|
108
|
-
{description ?
|
|
113
|
+
{description ? (
|
|
114
|
+
<p className="mt-2.5 max-w-2xl text-sm leading-7 text-ink-2">{description}</p>
|
|
115
|
+
) : null}
|
|
109
116
|
</div>
|
|
110
117
|
{actions ? <div className="flex flex-wrap items-center gap-2">{actions}</div> : null}
|
|
111
118
|
</header>
|