@q1travel/design-system 0.2.0 → 0.3.1
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/.agents/skills/product-design/AGENTS.md +9 -0
- package/.agents/skills/product-design/SKILL.md +63 -0
- package/.agents/skills/product-design/exemplars/README.md +12 -0
- package/.agents/skills/product-design/references/copy.md +7 -0
- package/.agents/skills/product-design/references/coverage-gaps.md +9 -0
- package/.agents/skills/product-design/references/glossary.md +5 -0
- package/.agents/skills/product-design/references/interface-quality.md +7 -0
- package/.agents/skills/product-design/references/patterns.md +13 -0
- package/.agents/skills/product-design/references/product-judgment.md +7 -0
- package/.agents/skills/product-design/references/resilience.md +13 -0
- package/.agents/skills/product-design/references/review-geist.md +94 -0
- package/.agents/skills/product-design/references/rules.md +17 -0
- package/.agents/skills/product-design/references/surfaces-forms.md +14 -0
- package/.agents/skills/product-design/references/surfaces-overlays.md +12 -0
- package/.agents/skills/product-design/references/surfaces.md +14 -0
- package/bin/q1-design.mjs +464 -0
- package/contracts/design-engineering-principles.md +39 -0
- package/contracts/design.dark.md +333 -0
- package/contracts/design.md +333 -0
- package/contracts/icon-system.md +77 -0
- package/contracts/implementation-map.md +29 -0
- package/contracts/interface-guidelines.md +122 -0
- package/contracts/token-naming.md +82 -0
- package/{dist → dist-pkg}/design-system.d.ts +2 -2
- package/{dist → dist-pkg}/design-system.js +630 -628
- package/{dist → dist-pkg}/style.css +76 -78
- package/package.json +19 -9
- package/tooling/README.md +9 -0
- package/tooling/scripts/evals/fixtures.json +7 -0
- package/tooling/scripts/evals/rules-checklist.json +23 -0
- package/tooling/scripts/evals/transition-all/after/example.css +4 -0
- package/tooling/scripts/evals/transition-all/before/example.css +4 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* q1travel design system — 发布样式(tokens + 字体兜底 + foundations + components)。构建产物,勿手改。 */
|
|
2
2
|
:root {
|
|
3
|
-
/*
|
|
4
|
-
color-scheme: light;
|
|
3
|
+
/* color-scheme 不在此声明:tokens.css 随包发布,全局副作用交消费方应用掌管(门户侧在 global.css)。 */
|
|
5
4
|
--q1-color-background-100: #ffffff;
|
|
6
5
|
--q1-color-background-200: #fafafa;
|
|
7
6
|
--q1-color-gray-100: #f2f2f2;
|
|
@@ -206,7 +205,6 @@
|
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
:root[data-theme='dark'] {
|
|
209
|
-
color-scheme: dark;
|
|
210
208
|
/* 画布抬灰(对标 Geist 暗色 #0a0a0a):表面自带浮起感,纯黑仅留给 background-200 底壳。 */
|
|
211
209
|
--q1-color-background-100: #0a0a0a;
|
|
212
210
|
--q1-color-background-200: #000000;
|
|
@@ -340,7 +338,7 @@
|
|
|
340
338
|
|
|
341
339
|
|
|
342
340
|
|
|
343
|
-
.sr-only {
|
|
341
|
+
.q1-sr-only {
|
|
344
342
|
position: absolute;
|
|
345
343
|
width: 1px;
|
|
346
344
|
height: 1px;
|
|
@@ -956,7 +954,7 @@
|
|
|
956
954
|
color: var(--q1-color-status-danger);
|
|
957
955
|
}
|
|
958
956
|
|
|
959
|
-
.kbd {
|
|
957
|
+
.q1-kbd {
|
|
960
958
|
display: inline-flex;
|
|
961
959
|
align-items: center;
|
|
962
960
|
justify-content: center;
|
|
@@ -972,7 +970,7 @@
|
|
|
972
970
|
line-height: 1;
|
|
973
971
|
}
|
|
974
972
|
|
|
975
|
-
.kbd--small {
|
|
973
|
+
.q1-kbd--small {
|
|
976
974
|
min-width: 20px;
|
|
977
975
|
height: 20px;
|
|
978
976
|
padding: 0 4px;
|
|
@@ -2230,14 +2228,14 @@ a.breadcrumb__link:hover {
|
|
|
2230
2228
|
padding-right: 48px;
|
|
2231
2229
|
}
|
|
2232
2230
|
|
|
2233
|
-
.tabs-
|
|
2231
|
+
.tabs-root {
|
|
2234
2232
|
border: 1px solid var(--q1-color-border);
|
|
2235
2233
|
border-radius: var(--q1-radius-3);
|
|
2236
2234
|
background: var(--q1-color-bg-panel);
|
|
2237
2235
|
padding: var(--q1-space-6);
|
|
2238
2236
|
}
|
|
2239
2237
|
|
|
2240
|
-
/* 分段控件 Switch(对标 Geist Switch):一组互斥选项,选中段抬起;底层 sr-only 单选组,方向键原生可用。 */
|
|
2238
|
+
/* 分段控件 Switch(对标 Geist Switch):一组互斥选项,选中段抬起;底层 q1-sr-only 单选组,方向键原生可用。 */
|
|
2241
2239
|
.switch-control {
|
|
2242
2240
|
display: inline-flex;
|
|
2243
2241
|
align-items: center;
|
|
@@ -2308,7 +2306,7 @@ a.breadcrumb__link:hover {
|
|
|
2308
2306
|
align-items: center;
|
|
2309
2307
|
}
|
|
2310
2308
|
|
|
2311
|
-
.tabs-
|
|
2309
|
+
.tabs-root {
|
|
2312
2310
|
display: grid;
|
|
2313
2311
|
gap: var(--q1-space-4);
|
|
2314
2312
|
}
|
|
@@ -2419,7 +2417,7 @@ a.breadcrumb__link:hover {
|
|
|
2419
2417
|
padding-inline: 10px;
|
|
2420
2418
|
}
|
|
2421
2419
|
|
|
2422
|
-
/* 带 tooltip 的禁用 tab 外层包了一个 span:真正的 flex item 是它而不是内层 button,
|
|
2420
|
+
/* 带 q1-tooltip 的禁用 tab 外层包了一个 span:真正的 flex item 是它而不是内层 button,
|
|
2423
2421
|
基础规则里固定 flex: none,这里要覆盖成跟裸 tab 一样按比例伸展,否则窄屏下完全不随宽度变化
|
|
2424
2422
|
(实测:加了这条后仍比裸 tab 窄约 10-20px,是嵌套 flex 容器的已知残留误差,量级上远好于
|
|
2425
2423
|
修复前的 flex: none,暂不继续深挖)。 */
|
|
@@ -3624,7 +3622,7 @@ a.breadcrumb__link:hover {
|
|
|
3624
3622
|
}
|
|
3625
3623
|
|
|
3626
3624
|
/* 外层只负责宽度约束与视觉样式;实际的 head/tail flex 布局交给 __visual——
|
|
3627
|
-
sr-only 完整文本节点与 __visual 是并列的两个子节点,sr-only 绝对定位不占布局空间。 */
|
|
3625
|
+
q1-sr-only 完整文本节点与 __visual 是并列的两个子节点,q1-sr-only 绝对定位不占布局空间。 */
|
|
3628
3626
|
.middle-truncate {
|
|
3629
3627
|
display: block;
|
|
3630
3628
|
min-width: 0;
|
|
@@ -4229,120 +4227,120 @@ a.breadcrumb__link:hover {
|
|
|
4229
4227
|
color: var(--q1-tone-fg-danger);
|
|
4230
4228
|
}
|
|
4231
4229
|
|
|
4232
|
-
.card {
|
|
4230
|
+
.q1-card {
|
|
4233
4231
|
border: 1px solid var(--q1-color-border);
|
|
4234
4232
|
border-radius: var(--q1-radius-3);
|
|
4235
4233
|
background: var(--q1-color-bg-panel);
|
|
4236
4234
|
max-width: 400px;
|
|
4237
4235
|
}
|
|
4238
4236
|
|
|
4239
|
-
.card__text {
|
|
4237
|
+
.q1-card__text {
|
|
4240
4238
|
margin: 0;
|
|
4241
4239
|
padding: var(--q1-space-4);
|
|
4242
4240
|
font-size: 14px;
|
|
4243
4241
|
color: var(--q1-color-text-secondary);
|
|
4244
4242
|
}
|
|
4245
4243
|
|
|
4246
|
-
.card--hover {
|
|
4244
|
+
.q1-card--hover {
|
|
4247
4245
|
cursor: pointer;
|
|
4248
4246
|
transition: transform 0.15s ease;
|
|
4249
4247
|
}
|
|
4250
4248
|
|
|
4251
4249
|
@media (prefers-reduced-motion: no-preference) {
|
|
4252
|
-
.card--hover:hover {
|
|
4250
|
+
.q1-card--hover:hover {
|
|
4253
4251
|
transform: translateY(-2px);
|
|
4254
4252
|
}
|
|
4255
4253
|
}
|
|
4256
4254
|
|
|
4257
|
-
.card--hover:hover {
|
|
4255
|
+
.q1-card--hover:hover {
|
|
4258
4256
|
border-color: var(--q1-color-border-strong);
|
|
4259
4257
|
box-shadow: 0 6px 18px color-mix(in srgb, var(--q1-color-mask-opaque) 12%, transparent);
|
|
4260
4258
|
}
|
|
4261
4259
|
|
|
4262
|
-
.card--secondary {
|
|
4260
|
+
.q1-card--secondary {
|
|
4263
4261
|
background: var(--q1-color-bg-subtle);
|
|
4264
4262
|
}
|
|
4265
4263
|
|
|
4266
4264
|
/* 分段卡片给容器 16px 内边距(对齐 Geist p-4):section 随之内缩,分隔线不贯满卡片边、左端对齐文字。
|
|
4267
4265
|
这是分隔线"内缩"的来源——不是给线加 inset,而是容器留边、section 无水平 padding,线随 section 内缩。 */
|
|
4268
|
-
.card--divided {
|
|
4266
|
+
.q1-card--divided {
|
|
4269
4267
|
padding: var(--q1-space-4);
|
|
4270
4268
|
}
|
|
4271
4269
|
|
|
4272
|
-
.card--divided .card__section {
|
|
4270
|
+
.q1-card--divided .q1-card__section {
|
|
4273
4271
|
/* 竖排段:只留垂直 padding(对齐 Geist py-2),水平交给容器内边距,分隔线因此内缩对齐文字。 */
|
|
4274
4272
|
padding: var(--q1-space-2) 0;
|
|
4275
4273
|
font-size: 14px;
|
|
4276
4274
|
color: var(--q1-color-text-primary);
|
|
4277
4275
|
}
|
|
4278
4276
|
|
|
4279
|
-
.card--divided .card__section + .card__section {
|
|
4277
|
+
.q1-card--divided .q1-card__section + .q1-card__section {
|
|
4280
4278
|
border-top: 1px solid var(--q1-color-border);
|
|
4281
4279
|
}
|
|
4282
4280
|
|
|
4283
4281
|
/* 横向铺开(direction="row"):段横向排布;等分占位,窄屏也不挤成一条缝。
|
|
4284
|
-
特异性用 .card.card--row(0,2,0) 压过可点卡片的 a.card(0,1,1),否则 <a> 卡片的 display:block 会把 flex 打回竖排。 */
|
|
4285
|
-
.card.card--row {
|
|
4282
|
+
特异性用 .q1-card.q1-card--row(0,2,0) 压过可点卡片的 a.q1-card(0,1,1),否则 <a> 卡片的 display:block 会把 flex 打回竖排。 */
|
|
4283
|
+
.q1-card.q1-card--row {
|
|
4286
4284
|
display: flex;
|
|
4287
4285
|
/* 横排指标块并列需要空间,解除默认 400px 限宽,充满容器(对齐 Geist 横排充满 demo 框)。 */
|
|
4288
4286
|
max-width: none;
|
|
4289
4287
|
}
|
|
4290
4288
|
|
|
4291
|
-
.card--row .card__section {
|
|
4289
|
+
.q1-card--row .q1-card__section {
|
|
4292
4290
|
flex: 1 1 0;
|
|
4293
4291
|
}
|
|
4294
4292
|
|
|
4295
|
-
.card--divided.card--row .card__section {
|
|
4293
|
+
.q1-card--divided.q1-card--row .q1-card__section {
|
|
4296
4294
|
/* 横排段:垂直 padding 归 0(内缩交给容器)、水平 8px 给文字到竖线的间距(对齐 Geist row section 0 8px)。 */
|
|
4297
4295
|
padding: 0 var(--q1-space-2);
|
|
4298
4296
|
}
|
|
4299
4297
|
|
|
4300
|
-
.card--divided.card--row .card__section + .card__section {
|
|
4298
|
+
.q1-card--divided.q1-card--row .q1-card__section + .q1-card__section {
|
|
4301
4299
|
border-top: none;
|
|
4302
4300
|
border-left: 1px solid var(--q1-color-border);
|
|
4303
4301
|
}
|
|
4304
4302
|
|
|
4305
4303
|
/* 指标块:数字 + 标签垂直堆叠,横排铺开成仪表盘式 KPI 概览——横排分段放并列指标才填得满、才有意义。 */
|
|
4306
|
-
.card__metric {
|
|
4304
|
+
.q1-card__metric {
|
|
4307
4305
|
display: flex;
|
|
4308
4306
|
flex-direction: column;
|
|
4309
4307
|
gap: var(--q1-space-1);
|
|
4310
4308
|
}
|
|
4311
4309
|
|
|
4312
|
-
.card__metric-value {
|
|
4310
|
+
.q1-card__metric-value {
|
|
4313
4311
|
font-size: 20px;
|
|
4314
4312
|
font-weight: 600;
|
|
4315
4313
|
line-height: 1.2;
|
|
4316
4314
|
color: var(--q1-color-text-primary);
|
|
4317
4315
|
}
|
|
4318
4316
|
|
|
4319
|
-
.card__metric-label {
|
|
4317
|
+
.q1-card__metric-label {
|
|
4320
4318
|
font-size: 12px;
|
|
4321
4319
|
color: var(--q1-color-text-secondary);
|
|
4322
4320
|
}
|
|
4323
4321
|
|
|
4324
4322
|
/* 常驻柔和投影(对齐 Geist shadow):贴地薄影 + 扩散软影两层,让卡片浮于背景。 */
|
|
4325
|
-
.card--shadow {
|
|
4323
|
+
.q1-card--shadow {
|
|
4326
4324
|
box-shadow:
|
|
4327
4325
|
0 1px 2px color-mix(in srgb, var(--q1-color-shadow) 6%, transparent),
|
|
4328
4326
|
0 8px 24px color-mix(in srgb, var(--q1-color-shadow) 8%, transparent);
|
|
4329
4327
|
}
|
|
4330
4328
|
|
|
4331
4329
|
/* 无框卡片(bordered={false}):去边框,靠底色/投影表达边界(对齐 Geist border 可选)。 */
|
|
4332
|
-
.card--borderless {
|
|
4330
|
+
.q1-card--borderless {
|
|
4333
4331
|
border-color: transparent;
|
|
4334
4332
|
}
|
|
4335
4333
|
|
|
4336
4334
|
/* 整卡可点(传 href → <a>):去链接默认样式、继承文本色,补键盘焦点环让其可达。 */
|
|
4337
|
-
a.card {
|
|
4335
|
+
a.q1-card {
|
|
4338
4336
|
display: block;
|
|
4339
4337
|
text-decoration: none;
|
|
4340
4338
|
color: inherit;
|
|
4341
4339
|
}
|
|
4342
4340
|
|
|
4343
|
-
/* 可点卡片焦点环用 outline 独立层:不占 box-shadow,避免顶掉 .card--shadow 的常驻投影;
|
|
4341
|
+
/* 可点卡片焦点环用 outline 独立层:不占 box-shadow,避免顶掉 .q1-card--shadow 的常驻投影;
|
|
4344
4342
|
且 outline 在 forced-colors 强制颜色模式仍可见(box-shadow 在该模式不渲染)。 */
|
|
4345
|
-
a.card:focus-visible {
|
|
4343
|
+
a.q1-card:focus-visible {
|
|
4346
4344
|
outline: 2px solid var(--q1-color-primary-700);
|
|
4347
4345
|
outline-offset: 2px;
|
|
4348
4346
|
}
|
|
@@ -5524,11 +5522,11 @@ a.card:focus-visible {
|
|
|
5524
5522
|
background: color-mix(in srgb, var(--q1-color-green-700) 16%, transparent);
|
|
5525
5523
|
color: var(--q1-color-green-700);
|
|
5526
5524
|
}
|
|
5527
|
-
.tooltip {
|
|
5525
|
+
.q1-tooltip {
|
|
5528
5526
|
position: relative;
|
|
5529
5527
|
display: inline-flex;
|
|
5530
5528
|
}
|
|
5531
|
-
.tooltip__trigger {
|
|
5529
|
+
.q1-tooltip__trigger {
|
|
5532
5530
|
min-width: 56px;
|
|
5533
5531
|
padding: var(--q1-space-2) var(--q1-space-4);
|
|
5534
5532
|
border: 1px solid var(--q1-color-border-strong);
|
|
@@ -5539,11 +5537,11 @@ a.card:focus-visible {
|
|
|
5539
5537
|
font-size: 14px;
|
|
5540
5538
|
cursor: default;
|
|
5541
5539
|
}
|
|
5542
|
-
.tooltip__trigger:focus-visible {
|
|
5540
|
+
.q1-tooltip__trigger:focus-visible {
|
|
5543
5541
|
outline: none;
|
|
5544
5542
|
box-shadow: var(--q1-shadow-focus);
|
|
5545
5543
|
}
|
|
5546
|
-
.tooltip__bubble {
|
|
5544
|
+
.q1-tooltip__bubble {
|
|
5547
5545
|
position: fixed;
|
|
5548
5546
|
z-index: 1000;
|
|
5549
5547
|
width: max-content;
|
|
@@ -5558,11 +5556,11 @@ a.card:focus-visible {
|
|
|
5558
5556
|
pointer-events: none;
|
|
5559
5557
|
transition: opacity 0.12s ease, transform 0.12s ease;
|
|
5560
5558
|
}
|
|
5561
|
-
.tooltip__bubble--open {
|
|
5559
|
+
.q1-tooltip__bubble--open {
|
|
5562
5560
|
opacity: 1;
|
|
5563
5561
|
}
|
|
5564
5562
|
/* caret 指示箭头 */
|
|
5565
|
-
.tooltip__bubble::after {
|
|
5563
|
+
.q1-tooltip__bubble::after {
|
|
5566
5564
|
content: '';
|
|
5567
5565
|
position: absolute;
|
|
5568
5566
|
width: 8px;
|
|
@@ -5571,66 +5569,66 @@ a.card:focus-visible {
|
|
|
5571
5569
|
transform: rotate(45deg);
|
|
5572
5570
|
}
|
|
5573
5571
|
/* 方位:仅入场位移;坐标由 JS 以 fixed 视口坐标给出,箭头用 --tt-caret 绝对定位 */
|
|
5574
|
-
.tooltip__bubble--top {
|
|
5572
|
+
.q1-tooltip__bubble--top {
|
|
5575
5573
|
transform: translateY(4px);
|
|
5576
5574
|
}
|
|
5577
|
-
.tooltip__bubble--top.tooltip__bubble--open {
|
|
5575
|
+
.q1-tooltip__bubble--top.q1-tooltip__bubble--open {
|
|
5578
5576
|
transform: translateY(0);
|
|
5579
5577
|
}
|
|
5580
|
-
.tooltip__bubble--top::after {
|
|
5578
|
+
.q1-tooltip__bubble--top::after {
|
|
5581
5579
|
top: 100%;
|
|
5582
5580
|
left: var(--tt-caret, 50%);
|
|
5583
5581
|
margin-left: -4px;
|
|
5584
5582
|
margin-top: -4px;
|
|
5585
5583
|
}
|
|
5586
|
-
.tooltip__bubble--bottom {
|
|
5584
|
+
.q1-tooltip__bubble--bottom {
|
|
5587
5585
|
transform: translateY(-4px);
|
|
5588
5586
|
}
|
|
5589
|
-
.tooltip__bubble--bottom.tooltip__bubble--open {
|
|
5587
|
+
.q1-tooltip__bubble--bottom.q1-tooltip__bubble--open {
|
|
5590
5588
|
transform: translateY(0);
|
|
5591
5589
|
}
|
|
5592
|
-
.tooltip__bubble--bottom::after {
|
|
5590
|
+
.q1-tooltip__bubble--bottom::after {
|
|
5593
5591
|
bottom: 100%;
|
|
5594
5592
|
left: var(--tt-caret, 50%);
|
|
5595
5593
|
margin-left: -4px;
|
|
5596
5594
|
margin-bottom: -4px;
|
|
5597
5595
|
}
|
|
5598
|
-
.tooltip__bubble--left {
|
|
5596
|
+
.q1-tooltip__bubble--left {
|
|
5599
5597
|
transform: translateX(4px);
|
|
5600
5598
|
}
|
|
5601
|
-
.tooltip__bubble--left.tooltip__bubble--open {
|
|
5599
|
+
.q1-tooltip__bubble--left.q1-tooltip__bubble--open {
|
|
5602
5600
|
transform: translateX(0);
|
|
5603
5601
|
}
|
|
5604
|
-
.tooltip__bubble--left::after {
|
|
5602
|
+
.q1-tooltip__bubble--left::after {
|
|
5605
5603
|
left: 100%;
|
|
5606
5604
|
top: var(--tt-caret, 50%);
|
|
5607
5605
|
margin-top: -4px;
|
|
5608
5606
|
margin-left: -4px;
|
|
5609
5607
|
}
|
|
5610
|
-
.tooltip__bubble--right {
|
|
5608
|
+
.q1-tooltip__bubble--right {
|
|
5611
5609
|
transform: translateX(-4px);
|
|
5612
5610
|
}
|
|
5613
|
-
.tooltip__bubble--right.tooltip__bubble--open {
|
|
5611
|
+
.q1-tooltip__bubble--right.q1-tooltip__bubble--open {
|
|
5614
5612
|
transform: translateX(0);
|
|
5615
5613
|
}
|
|
5616
|
-
.tooltip__bubble--right::after {
|
|
5614
|
+
.q1-tooltip__bubble--right::after {
|
|
5617
5615
|
right: 100%;
|
|
5618
5616
|
top: var(--tt-caret, 50%);
|
|
5619
5617
|
margin-top: -4px;
|
|
5620
5618
|
margin-right: -4px;
|
|
5621
5619
|
}
|
|
5622
|
-
.tooltip__bubble--no-tip::after {
|
|
5620
|
+
.q1-tooltip__bubble--no-tip::after {
|
|
5623
5621
|
display: none;
|
|
5624
5622
|
}
|
|
5625
|
-
.tooltip__bubble--center {
|
|
5623
|
+
.q1-tooltip__bubble--center {
|
|
5626
5624
|
text-align: center;
|
|
5627
5625
|
}
|
|
5628
5626
|
@media (prefers-reduced-motion: reduce) {
|
|
5629
|
-
.tooltip__bubble {
|
|
5627
|
+
.q1-tooltip__bubble {
|
|
5630
5628
|
transition: opacity 0.12s ease;
|
|
5631
5629
|
}
|
|
5632
5630
|
}
|
|
5633
|
-
.toast-region {
|
|
5631
|
+
.q1-toast-region {
|
|
5634
5632
|
position: fixed;
|
|
5635
5633
|
right: var(--q1-space-6);
|
|
5636
5634
|
bottom: var(--q1-space-6);
|
|
@@ -5639,7 +5637,7 @@ a.card:focus-visible {
|
|
|
5639
5637
|
width: min(420px, calc(100vw - 2 * var(--q1-space-6)));
|
|
5640
5638
|
height: var(--toast-stack-h, 0px);
|
|
5641
5639
|
}
|
|
5642
|
-
.toast {
|
|
5640
|
+
.q1-toast {
|
|
5643
5641
|
position: absolute;
|
|
5644
5642
|
right: 0;
|
|
5645
5643
|
bottom: 0;
|
|
@@ -5660,58 +5658,58 @@ a.card:focus-visible {
|
|
|
5660
5658
|
transform: translateY(calc(var(--depth, 0) * -14px)) scale(calc(1 - var(--depth, 0) * 0.06));
|
|
5661
5659
|
opacity: calc(1 - max(0, var(--depth, 0) - 2));
|
|
5662
5660
|
}
|
|
5663
|
-
.toast-region[data-expanded='true'] .toast {
|
|
5661
|
+
.q1-toast-region[data-expanded='true'] .q1-toast {
|
|
5664
5662
|
transform: translateY(var(--y, 0px)) scale(1);
|
|
5665
5663
|
opacity: 1;
|
|
5666
5664
|
}
|
|
5667
|
-
/* 状态 toast:实心 tone 底色 + 浅色文字(对标 Geist 的 success/warning/error) */
|
|
5668
|
-
.toast--success,
|
|
5669
|
-
.toast--warning,
|
|
5670
|
-
.toast--error {
|
|
5665
|
+
/* 状态 q1-toast:实心 tone 底色 + 浅色文字(对标 Geist 的 success/warning/error) */
|
|
5666
|
+
.q1-toast--success,
|
|
5667
|
+
.q1-toast--warning,
|
|
5668
|
+
.q1-toast--error {
|
|
5671
5669
|
color: var(--q1-color-mask-opaque);
|
|
5672
5670
|
box-shadow:
|
|
5673
5671
|
0 6px 16px -4px color-mix(in srgb, var(--q1-color-mask-opaque) 28%, transparent),
|
|
5674
5672
|
0 16px 30px -10px color-mix(in srgb, var(--q1-color-mask-opaque) 20%, transparent);
|
|
5675
5673
|
}
|
|
5676
|
-
.toast--success {
|
|
5674
|
+
.q1-toast--success {
|
|
5677
5675
|
background: var(--q1-color-green-600);
|
|
5678
5676
|
}
|
|
5679
|
-
.toast--warning {
|
|
5677
|
+
.q1-toast--warning {
|
|
5680
5678
|
background: var(--q1-color-amber-600);
|
|
5681
5679
|
}
|
|
5682
|
-
.toast--error {
|
|
5680
|
+
.q1-toast--error {
|
|
5683
5681
|
background: var(--q1-color-red-600);
|
|
5684
5682
|
}
|
|
5685
|
-
.toast__icon {
|
|
5683
|
+
.q1-toast__icon {
|
|
5686
5684
|
flex: none;
|
|
5687
5685
|
}
|
|
5688
|
-
.toast__body {
|
|
5686
|
+
.q1-toast__body {
|
|
5689
5687
|
flex: 1 1 auto;
|
|
5690
5688
|
min-width: 0;
|
|
5691
5689
|
}
|
|
5692
|
-
.toast__title {
|
|
5690
|
+
.q1-toast__title {
|
|
5693
5691
|
margin: 0;
|
|
5694
5692
|
font-size: 14px;
|
|
5695
5693
|
font-weight: 500;
|
|
5696
5694
|
}
|
|
5697
|
-
.toast__description {
|
|
5695
|
+
.q1-toast__description {
|
|
5698
5696
|
margin: 4px 0 0;
|
|
5699
5697
|
font-size: 14px;
|
|
5700
5698
|
color: currentColor;
|
|
5701
5699
|
opacity: 0.74;
|
|
5702
5700
|
}
|
|
5703
|
-
.toast__description a {
|
|
5701
|
+
.q1-toast__description a {
|
|
5704
5702
|
color: inherit;
|
|
5705
5703
|
opacity: 1;
|
|
5706
5704
|
text-decoration: underline;
|
|
5707
5705
|
text-underline-offset: 2px;
|
|
5708
5706
|
}
|
|
5709
|
-
.toast__description a:focus-visible {
|
|
5707
|
+
.q1-toast__description a:focus-visible {
|
|
5710
5708
|
outline: none;
|
|
5711
5709
|
box-shadow: var(--q1-shadow-focus);
|
|
5712
5710
|
border-radius: 2px;
|
|
5713
5711
|
}
|
|
5714
|
-
.toast__action {
|
|
5712
|
+
.q1-toast__action {
|
|
5715
5713
|
flex: none;
|
|
5716
5714
|
align-self: center;
|
|
5717
5715
|
padding: var(--q1-space-1) var(--q1-space-3);
|
|
@@ -5724,15 +5722,15 @@ a.card:focus-visible {
|
|
|
5724
5722
|
font-weight: 500;
|
|
5725
5723
|
cursor: pointer;
|
|
5726
5724
|
}
|
|
5727
|
-
.toast__action:hover {
|
|
5725
|
+
.q1-toast__action:hover {
|
|
5728
5726
|
background: color-mix(in srgb, currentColor 12%, transparent);
|
|
5729
5727
|
}
|
|
5730
|
-
.toast__action:focus-visible,
|
|
5731
|
-
.toast__close:focus-visible {
|
|
5728
|
+
.q1-toast__action:focus-visible,
|
|
5729
|
+
.q1-toast__close:focus-visible {
|
|
5732
5730
|
outline: none;
|
|
5733
5731
|
box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 55%, transparent);
|
|
5734
5732
|
}
|
|
5735
|
-
.toast__close {
|
|
5733
|
+
.q1-toast__close {
|
|
5736
5734
|
flex: none;
|
|
5737
5735
|
display: grid;
|
|
5738
5736
|
place-items: center;
|
|
@@ -5745,15 +5743,15 @@ a.card:focus-visible {
|
|
|
5745
5743
|
opacity: 0.7;
|
|
5746
5744
|
cursor: pointer;
|
|
5747
5745
|
}
|
|
5748
|
-
.toast__close:hover {
|
|
5746
|
+
.q1-toast__close:hover {
|
|
5749
5747
|
opacity: 1;
|
|
5750
5748
|
background: color-mix(in srgb, currentColor 12%, transparent);
|
|
5751
5749
|
}
|
|
5752
5750
|
@media (prefers-reduced-motion: no-preference) {
|
|
5753
|
-
.toast {
|
|
5751
|
+
.q1-toast {
|
|
5754
5752
|
transition: transform 0.32s cubic-bezier(0.25, 0.75, 0.6, 0.98), opacity 0.28s ease;
|
|
5755
5753
|
}
|
|
5756
|
-
.toast-region {
|
|
5754
|
+
.q1-toast-region {
|
|
5757
5755
|
transition: height 0.32s cubic-bezier(0.25, 0.75, 0.6, 0.98);
|
|
5758
5756
|
}
|
|
5759
5757
|
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q1travel/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/design-system.js",
|
|
7
|
-
"module": "./dist/design-system.js",
|
|
8
|
-
"types": "./dist/design-system.d.ts",
|
|
6
|
+
"main": "./dist-pkg/design-system.js",
|
|
7
|
+
"module": "./dist-pkg/design-system.js",
|
|
8
|
+
"types": "./dist-pkg/design-system.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"q1-design": "bin/q1-design.mjs"
|
|
11
|
+
},
|
|
9
12
|
"exports": {
|
|
10
13
|
".": {
|
|
11
|
-
"types": "./dist/design-system.d.ts",
|
|
12
|
-
"import": "./dist/design-system.js"
|
|
14
|
+
"types": "./dist-pkg/design-system.d.ts",
|
|
15
|
+
"import": "./dist-pkg/design-system.js"
|
|
13
16
|
},
|
|
14
|
-
"./style.css": "./dist/style.css"
|
|
17
|
+
"./style.css": "./dist-pkg/style.css",
|
|
18
|
+
"./contracts/*": "./contracts/*",
|
|
19
|
+
"./package.json": "./package.json"
|
|
15
20
|
},
|
|
16
21
|
"files": [
|
|
17
|
-
"dist"
|
|
22
|
+
"dist-pkg",
|
|
23
|
+
"contracts",
|
|
24
|
+
".agents",
|
|
25
|
+
"tooling",
|
|
26
|
+
"bin"
|
|
18
27
|
],
|
|
19
28
|
"sideEffects": [
|
|
20
29
|
"*.css"
|
|
@@ -29,7 +38,8 @@
|
|
|
29
38
|
"check": "npm run build && npm run check:shell && npm run check:browser",
|
|
30
39
|
"build:lib": "vite build --config vite.lib.config.ts",
|
|
31
40
|
"build:style": "node scripts/build-style.mjs",
|
|
32
|
-
"build:pkg": "npm run build:lib && npm run build:style"
|
|
41
|
+
"build:pkg": "npm run build:lib && npm run build:style",
|
|
42
|
+
"prepack": "npm run build:pkg"
|
|
33
43
|
},
|
|
34
44
|
"dependencies": {
|
|
35
45
|
"lucide-react": "^0.468.0"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# tooling/scripts/evals
|
|
2
|
+
|
|
3
|
+
产品设计框架的确定性工具层(规则 + eval)。
|
|
4
|
+
|
|
5
|
+
- `evals/rules-checklist.json` —— 稳定 ID 规则清单(`Q1-DS-*`);`kind=deterministic` 可静态强制,`kind=judgment` 留给 product-design skill / Review。
|
|
6
|
+
- `evals/fixtures.json` —— eval fixture 索引。
|
|
7
|
+
- `evals/<fixture>/{before,after}/` —— 每条规则的前后态样例,用来测 skill / linter 是否产出预期改动。
|
|
8
|
+
|
|
9
|
+
**现状**:`q1-design lint` 已实现 `Q1-DS-001`(`--ds-*`)/`Q1-DS-401`(`transition: all`)/`Q1-DS-501`(裸颜色字面量)三条纯机械规则;`q1-design eval` 已实现,对每个 fixture 校验 before 命中且 after 零命中。其余 `kind=deterministic` 规则(含判断成分)与全部 `kind=judgment` 规则待后续批次。见 `../.agents/skills/product-design/references/coverage-gaps.md`。
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "eval 种子:每个 fixture 引一条规则,给 before/after 两态,用来测 skill/linter 是否产出预期改动。runner 即 `q1-design eval`(bin/q1-design.mjs,已实现);expectedHits 为 before 的精确命中数,after 恒 0。",
|
|
3
|
+
"version": 0,
|
|
4
|
+
"fixtures": [
|
|
5
|
+
{ "id": "transition-all", "rule": "Q1-DS-401", "dir": "transition-all", "summary": "transition: all → 只过渡具体属性", "expectedHits": 1 }
|
|
6
|
+
]
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "q1travel 产品设计确定性规则清单。每条带稳定 ID + canonical 出处。kind=deterministic 的可由 linter 静态强制;kind=judgment 的留给 product-design skill / Review。linter CLI 与 eval runner 已实现:`q1-design lint`(Q1-DS-001/401/501)与 `q1-design eval`(bin/q1-design.mjs);覆盖缺口见 ../../../.agents/skills/product-design/references/coverage-gaps.md。",
|
|
3
|
+
"version": 0,
|
|
4
|
+
"idScheme": {
|
|
5
|
+
"0xx": "token 与事实源",
|
|
6
|
+
"1xx": "交互与命中区",
|
|
7
|
+
"2xx": "表单",
|
|
8
|
+
"3xx": "内容与可访问性",
|
|
9
|
+
"4xx": "动效",
|
|
10
|
+
"5xx": "主题"
|
|
11
|
+
},
|
|
12
|
+
"rules": [
|
|
13
|
+
{ "id": "Q1-DS-001", "title": "新代码用 --q1-*,不用 --ds-*", "source": "contracts/token-naming.md", "severity": "error", "kind": "deterministic", "detect": "新增/改动代码里出现 --ds-* 声明或作为新决策源名", "fix": "改用 --q1-* canonical token" },
|
|
14
|
+
{ "id": "Q1-DS-101", "title": "导航用原生 link、动作用原生 button", "source": "contracts/interface-guidelines.md#interactions", "severity": "error", "kind": "judgment", "detect": "用 div/span + onClick 承载导航或动作", "fix": "导航用 <a href>,动作用 <button>" },
|
|
15
|
+
{ "id": "Q1-DS-102", "title": "命中区 ≥24px(触摸 44px)", "source": "contracts/interface-guidelines.md#interactions", "severity": "warn", "kind": "judgment", "detect": "可点击元素视觉/命中区小于 24px 且未扩大命中区", "fix": "min-width/height + 负 margin 扩大命中区,不撑高容器" },
|
|
16
|
+
{ "id": "Q1-DS-301", "title": "icon-only 控件必须有可访问名", "source": "contracts/interface-guidelines.md#content-and-accessibility", "severity": "error", "kind": "judgment", "detect": "只含图标的 button/link 无 aria-label / 可访问名", "fix": "补 aria-label 或视觉隐藏文本" },
|
|
17
|
+
{ "id": "Q1-DS-401", "title": "禁用 transition: all", "source": "contracts/interface-guidelines.md#animation", "severity": "error", "kind": "deterministic", "detect": "CSS 出现 `transition: all` 或 `transition-property: all`", "fix": "只列需要过渡的具体属性(opacity / transform)" },
|
|
18
|
+
{ "id": "Q1-DS-402", "title": "必须 honor prefers-reduced-motion", "source": "contracts/interface-guidelines.md#animation", "severity": "warn", "kind": "judgment", "detect": "有非平凡动效但无 prefers-reduced-motion 兜底", "fix": "加 @media (prefers-reduced-motion: reduce) 降级" },
|
|
19
|
+
{ "id": "Q1-DS-403", "title": "只动 opacity / transform", "source": "contracts/interface-guidelines.md#animation", "severity": "warn", "kind": "deterministic", "detect": "transition/animation 作用于非 opacity/transform 属性且无书面理由", "fix": "改用 opacity/transform,或记书面理由" },
|
|
20
|
+
{ "id": "Q1-DS-501", "title": "主题用 token,不用页面局部颜色常量", "source": "contracts/interface-guidelines.md#theming", "severity": "error", "kind": "deterministic", "detect": "组件 CSS 出现裸 hex / rgba() 颜色字面量", "fix": "改用 --q1-color-* / 语义 token;需要混色用 color-mix" },
|
|
21
|
+
{ "id": "Q1-DS-502", "title": "native select 显式设前景/背景", "source": "contracts/interface-guidelines.md#theming", "severity": "warn", "kind": "judgment", "detect": "样式化的 <select> 未显式设 color / background", "fix": "显式设 select 的 fg/bg 以匹配当前主题" }
|
|
22
|
+
]
|
|
23
|
+
}
|