@gemboss/ui 0.6.0 → 0.6.2
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/README.md +2 -0
- package/catalog/index.html +1 -1
- package/gemboss-ui.css +20 -10
- package/package.json +1 -1
- package/src/app-shell.css +14 -6
- package/src/assistant/dock.ts +22 -0
- package/src/assistant/provider.tsx +5 -2
- package/src/kit-plain.css +3 -1
- package/src/kit-plain.js +7 -1
- package/src/ui.css +1 -1
package/README.md
CHANGED
|
@@ -301,6 +301,8 @@ const open = dock.presentation !== "hidden";
|
|
|
301
301
|
- `placement="topbar"`: a 44×44 icon button, left of the account chip, ≤760px only. The label stays the accessible name.
|
|
302
302
|
- No provider and no state: pass `hidden` while your assistant is open.
|
|
303
303
|
- The shortcut is a hint only: the surface owns the key binding.
|
|
304
|
+
- The phone topbar (≤760px) gives in this order when it is short: the search (to a 96px floor), then the brand name
|
|
305
|
+
(ellipsis). The actions never shrink, so the account chip stays on screen (0.6.1; `topbar.test.tsx`).
|
|
304
306
|
- 0.6.0, not a patch: an existing `<AssistantLauncher>` call changes meaning (no longer fixed; the default copy is the
|
|
305
307
|
rail one, hidden on phones). A surface on `^0.5.x` must move to `^0.6.0` in the same PR that places the two copies.
|
|
306
308
|
|
package/catalog/index.html
CHANGED
|
@@ -27,7 +27,7 @@ body{margin:0;background:var(--gemboss-app-bg,#f1f1f1);color:var(--gemboss-text)
|
|
|
27
27
|
@media (max-width:760px){.cat{grid-template-columns:1fr;padding:16px}.cat-nav{position:static;flex-direction:row;flex-wrap:wrap}}
|
|
28
28
|
</style></head><body>
|
|
29
29
|
<div class="cat"><nav class="cat-nav" aria-label="Mục"><a href="#tokens">Token</a><a href="#buttons">Nút</a><a href="#fields">Ô nhập</a><a href="#choice">Tab, nhóm nút, thẻ</a><a href="#surfaces">Thẻ, số liệu, bảng, trạng thái trống</a><a href="#report">Báo cáo</a><a href="#resizer">Thanh kéo giữa hai cột</a><a href="#modal">Hộp thoại, toast, menu (JS thuần)</a><a href="#shell">Khung app</a><a href="#auth">Đăng nhập</a><a href="#chat">Thân chat</a><a href="#assistant">Trợ lý: cột phiên</a><a href="#icons">Icon</a></nav>
|
|
30
|
-
<main><header class="cat-head"><h1>@gemboss/ui 0.6.
|
|
30
|
+
<main><header class="cat-head"><h1>@gemboss/ui 0.6.2</h1><p>Ngôn ngữ thiết kế chung của các công cụ GemBoss. Markup dưới mỗi ví dụ là đúng thứ package render ra; bề mặt không dùng React (HTML tĩnh, Python) chép markup này và nạp <code>gemboss-ui.css</code>. Dựng từ gemboss <code>4397bdb795d6</code>.</p></header>
|
|
31
31
|
<section id="tokens"><h2>Token</h2><p>Đổi giao diện một bề mặt bằng cách đặt lại token, không viết đè class. Tên và giá trị đọc thẳng từ gemboss-ui.css.</p><div class="cat-swatches"><div class="cat-swatch"><i style="background:var(--gemboss-primary)"></i><code>--gemboss-primary</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-primary-dark)"></i><code>--gemboss-primary-dark</code><span>#000000</span></div><div class="cat-swatch"><i style="background:var(--gemboss-primary-soft)"></i><code>--gemboss-primary-soft</code><span>#f2f3f5</span></div><div class="cat-swatch"><i style="background:var(--gemboss-accent)"></i><code>--gemboss-accent</code><span>#5661f5</span></div><div class="cat-swatch"><i style="background:var(--gemboss-accent-strong)"></i><code>--gemboss-accent-strong</code><span>#3a44de</span></div><div class="cat-swatch"><i style="background:var(--gemboss-accent-soft)"></i><code>--gemboss-accent-soft</code><span>#eef0fe</span></div><div class="cat-swatch"><i style="background:var(--gemboss-text-strong)"></i><code>--gemboss-text-strong</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-text)"></i><code>--gemboss-text</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-text-muted)"></i><code>--gemboss-text-muted</code><span>#686b71</span></div><div class="cat-swatch"><i style="background:var(--gemboss-surface)"></i><code>--gemboss-surface</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-canvas)"></i><code>--gemboss-canvas</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-preview-canvas)"></i><code>--gemboss-preview-canvas</code><span>#eceef1</span></div><div class="cat-swatch"><i style="background:var(--gemboss-rail-bg)"></i><code>--gemboss-rail-bg</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-panel-bg)"></i><code>--gemboss-panel-bg</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-divider)"></i><code>--gemboss-divider</code><span>#e5e7ea</span></div><div class="cat-swatch"><i style="background:var(--gemboss-divider-soft)"></i><code>--gemboss-divider-soft</code><span>#edeff2</span></div><div class="cat-swatch"><i style="background:var(--gemboss-hover)"></i><code>--gemboss-hover</code><span>#eceef2</span></div><div class="cat-swatch"><i style="background:var(--gemboss-active-bg)"></i><code>--gemboss-active-bg</code><span>#f0f1f4</span></div><div class="cat-swatch"><i style="background:var(--gemboss-active-fg)"></i><code>--gemboss-active-fg</code><span>#1b1c1e</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger)"></i><code>--gemboss-danger</code><span>#d72c0d</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger-strong)"></i><code>--gemboss-danger-strong</code><span>#b42318</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger-soft)"></i><code>--gemboss-danger-soft</code><span>#fff0e9</span></div><div class="cat-swatch"><i style="background:var(--gemboss-danger-border)"></i><code>--gemboss-danger-border</code><span>#f5c9bc</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success)"></i><code>--gemboss-success</code><span>#007f5f</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success-strong)"></i><code>--gemboss-success-strong</code><span>#0a6a4c</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success-soft)"></i><code>--gemboss-success-soft</code><span>#e3f1df</span></div><div class="cat-swatch"><i style="background:var(--gemboss-success-border)"></i><code>--gemboss-success-border</code><span>#b7dfcd</span></div><div class="cat-swatch"><i style="background:var(--gemboss-warning)"></i><code>--gemboss-warning</code><span>#9a6700</span></div><div class="cat-swatch"><i style="background:var(--gemboss-warning-soft)"></i><code>--gemboss-warning-soft</code><span>#fff8e0</span></div><div class="cat-swatch"><i style="background:var(--gemboss-warning-border)"></i><code>--gemboss-warning-border</code><span>#f5d569</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-bg)"></i><code>--gemboss-dark-bg</code><span>#0a0a0c</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-rail)"></i><code>--gemboss-dark-rail</code><span>#0e0e11</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-surface)"></i><code>--gemboss-dark-surface</code><span>#16161a</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-surface-2)"></i><code>--gemboss-dark-surface-2</code><span>#1e1e24</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-divider)"></i><code>--gemboss-dark-divider</code><span>#2a2a31</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-text)"></i><code>--gemboss-dark-text</code><span>#ededf0</span></div><div class="cat-swatch"><i style="background:var(--gemboss-dark-muted)"></i><code>--gemboss-dark-muted</code><span>#9a9aa4</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-bg)"></i><code>--gemboss-field-bg</code><span>#fdfdfd</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-bg-hover)"></i><code>--gemboss-field-bg-hover</code><span>#fafafa</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-ink)"></i><code>--gemboss-field-ink</code><span>#303030</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-placeholder)"></i><code>--gemboss-field-placeholder</code><span>#616161</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-line)"></i><code>--gemboss-field-line</code><span>#8a8a8a</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-line-hover)"></i><code>--gemboss-field-line-hover</code><span>#616161</span></div><div class="cat-swatch"><i style="background:var(--gemboss-field-line-active)"></i><code>--gemboss-field-line-active</code><span>#1a1a1a</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-ink)"></i><code>--gemboss-chip-ink</code><span>#303633</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-line)"></i><code>--gemboss-chip-line</code><span>#cfd6ce</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-line-hover)"></i><code>--gemboss-chip-line-hover</code><span>#aab4ad</span></div><div class="cat-swatch"><i style="background:var(--gemboss-chip-bg-hover)"></i><code>--gemboss-chip-bg-hover</code><span>#f6f7f5</span></div><div class="cat-swatch"><i style="background:var(--gemboss-on-primary)"></i><code>--gemboss-on-primary</code><span>#ffffff</span></div><div class="cat-swatch"><i style="background:var(--gemboss-app-bg)"></i><code>--gemboss-app-bg</code><span>#ffffff</span></div></div><table class="ui-table cat-scale"><thead><tr><th>Token</th><th>Giá trị</th><th>Mẫu</th></tr></thead><tbody><tr><td><code>--gemboss-fs-micro</code></td><td>11px</td><td style="font-size:var(--gemboss-fs-micro)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-caption</code></td><td>12px</td><td style="font-size:var(--gemboss-fs-caption)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-body</code></td><td>14px</td><td style="font-size:var(--gemboss-fs-body)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-body-lg</code></td><td>16px</td><td style="font-size:var(--gemboss-fs-body-lg)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-h3</code></td><td>16px</td><td style="font-size:var(--gemboss-fs-h3)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-h2</code></td><td>20px</td><td style="font-size:var(--gemboss-fs-h2)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-h1</code></td><td>24px</td><td style="font-size:var(--gemboss-fs-h1)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-fs-display</code></td><td>30px</td><td style="font-size:var(--gemboss-fs-display)">Ngôn ngữ thiết kế chung</td></tr><tr><td><code>--gemboss-radius-xs</code></td><td>4px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-xs)"></i></td></tr><tr><td><code>--gemboss-radius-sm</code></td><td>6px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-sm)"></i></td></tr><tr><td><code>--gemboss-radius-md</code></td><td>8px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-md)"></i></td></tr><tr><td><code>--gemboss-radius-lg</code></td><td>12px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-lg)"></i></td></tr><tr><td><code>--gemboss-radius-xl</code></td><td>16px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-xl)"></i></td></tr><tr><td><code>--gemboss-radius-2xl</code></td><td>20px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-2xl)"></i></td></tr><tr><td><code>--gemboss-radius-full</code></td><td>999px</td><td><i class="cat-radius" style="border-radius:var(--gemboss-radius-full)"></i></td></tr><tr><td><code>--gemboss-shadow-resting</code></td><td class="cat-small">0 1px 2px rgba(31, 30, 29, 0.04), 0 2px 6px rgba(31, 30, 29, 0.06)</td><td><i class="cat-radius" style="box-shadow:var(--gemboss-shadow-resting);border:0"></i></td></tr><tr><td><code>--gemboss-shadow-raised</code></td><td class="cat-small">0 4px 16px rgba(31, 30, 29, 0.10)</td><td><i class="cat-radius" style="box-shadow:var(--gemboss-shadow-raised);border:0"></i></td></tr><tr><td><code>--gemboss-shadow-overlay</code></td><td class="cat-small">0 16px 48px rgba(31, 30, 29, 0.18)</td><td><i class="cat-radius" style="box-shadow:var(--gemboss-shadow-overlay);border:0"></i></td></tr></tbody></table></section>
|
|
32
32
|
<section id="buttons"><h2>Nút</h2><p>Một lớp <code>ui-btn</code>, ba biến thể, tông đỏ, một cỡ nhỏ. Cao 32px dưới chuột (bằng ô nhập và ô chọn), 44px dưới ngón tay và ở khổ điện thoại, cỡ nhỏ cũng vậy. Dùng được trên <code><button></code> lẫn <code><a></code> (căn giữa sẵn).</p><figure class="cat-demo"><figcaption>Mặc định · chính · ghost · nhỏ · tắt</figcaption><div class="cat-live"><div class="cat-row"><button type="button" class="ui-btn">Lưu nháp</button><button type="button" class="ui-btn ui-btn--primary">Xuất bản</button><button type="button" class="ui-btn ui-btn--ghost">Huỷ</button><button type="button" class="ui-btn ui-btn--sm">Nhỏ</button><button type="button" class="ui-btn ui-btn--primary" disabled>Đang lưu…</button><a class="ui-btn" href="#buttons">Link dạng nút</a></div></div><details class="cat-code"><summary>Markup</summary><pre><code><div class="cat-row">
|
|
33
33
|
<button type="button" class="ui-btn">Lưu nháp</button>
|
package/gemboss-ui.css
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* GemBoss admin design system — GENERATED — do not edit; regenerate from gemboss:
|
|
3
3
|
* node apps/admin/scripts/export-ui-css.mjs --out <path> (npm run export:ui-css)
|
|
4
|
-
* gemboss commit:
|
|
5
|
-
* sources sha256:
|
|
4
|
+
* gemboss commit: 4397bdb795d6d122d2384e14f9538dceceb82e9e
|
|
5
|
+
* sources sha256: bea19a3043c91b979b8550aa0844ef1f9b09ec145cf1a037be3a9e66ce7f516b
|
|
6
6
|
* contents: 1 allow-listed rule from apps/admin/src/app/globals.css + packages/ui/src/gemboss-tokens.css
|
|
7
7
|
* (verbatim) + packages/ui/src/ui.css (verbatim) + packages/ui/src/gemboss-field.css (verbatim)
|
|
8
8
|
* + 181 rules from packages/ui/src/shell.css (the shared shell)
|
|
@@ -432,7 +432,7 @@ a.ui-metric:focus-visible { outline: 2px solid var(--ui-focus); outline-offset:
|
|
|
432
432
|
/* ── Thông báo: `<div class="ui-notice ui-notice--warning">…</div>`. Lỗi tải, cảnh báo cấu hình, việc cần người
|
|
433
433
|
làm. Mỗi tông mang màu chữ riêng (nền tông luôn sáng, kể cả trong admin tối). Không có tông = ghi chú trung tính.
|
|
434
434
|
role="status"/"alert" CHỈ khi thông báo xuất hiện sau khi trang đã tải (vùng live); có sẵn lúc tải thì không role. */
|
|
435
|
-
.ui-notice { padding: 12px 16px; border-radius: var(--ui-radius-md); border: 1px solid var(--ui-border); background: var(--ui-surface-2); color: var(--ui-text); font-size: var(--ui-fs-body); }
|
|
435
|
+
.ui-notice { padding: 12px 16px; border-radius: var(--ui-radius-md); border: 1px solid var(--ui-border); background: var(--ui-surface-2); color: var(--ui-text); font-size: var(--ui-fs-body); overflow-wrap: anywhere; } /* a URL or key in a notice wraps instead of being cut by its card (gemwatcher Pulse, 0.6.2) */
|
|
436
436
|
.ui-notice--warning { background: var(--gemboss-warning-soft); border-color: var(--gemboss-warning-border); color: var(--gemboss-warning); }
|
|
437
437
|
.ui-notice--danger { background: var(--gemboss-danger-soft); border-color: var(--gemboss-danger-border); color: var(--gemboss-danger-strong); }
|
|
438
438
|
.ui-notice--success { background: var(--gemboss-success-soft); border-color: var(--gemboss-success-border); color: var(--gemboss-success-strong); }
|
|
@@ -2032,14 +2032,22 @@ body.gemboss-assistant-unread .gnav-item.gnav-assistant::after {
|
|
|
2032
2032
|
.gemboss-topbar-center { display: flex; justify-content: center; min-width: 0; }
|
|
2033
2033
|
.gemboss-topbar-end { display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 0; }
|
|
2034
2034
|
@media (max-width: 760px) {
|
|
2035
|
-
/* The topbar is one flex row here: the middle slot takes what is left.
|
|
2036
|
-
|
|
2035
|
+
/* The topbar is one flex row here: the middle slot takes what is left. Basis 0, not auto: with `auto` the search's own
|
|
2036
|
+
* width (up to 520px) was its claim, so the other slots had to give way to it (0.6.0 pinned them instead, see below). With
|
|
2037
|
+
* 0 it only takes what the others leave, down to a 96px floor: an input with its icon still reads as search. */
|
|
2038
|
+
.gemboss-topbar-center { flex: 1 1 0; min-width: 96px; justify-content: flex-start; }
|
|
2039
|
+
.gemboss-topbar-center:empty { min-width: 0; }
|
|
2037
2040
|
/* No actions: the empty slot would still take one flex `gap` (8px) off the search at 320px. */
|
|
2038
2041
|
.gemboss-topbar-end:empty { display: none; }
|
|
2039
|
-
/*
|
|
2040
|
-
*
|
|
2041
|
-
*
|
|
2042
|
-
|
|
2042
|
+
/* The actions never give: with `min-width: 0` the slot shrank and its buttons (justify flex-end) spilled LEFT over the
|
|
2043
|
+
* search (assistant + account, 15px over partner-radar's search at 320 and 360, 0.6.0).
|
|
2044
|
+
* The start slot gives LAST, after the search reaches its floor: the brand name ellipsizes (.gb-brand-name) instead of
|
|
2045
|
+
* the account chip leaving the screen. 0.6.0 pinned it (`flex: 0 0 auto`) and a 30-character brand at 461px pushed the
|
|
2046
|
+
* chip 44px past the right edge (review #3690). The menu button and the mark keep their 44px. */
|
|
2047
|
+
.gemboss-topbar-end { flex: 0 0 auto; }
|
|
2048
|
+
.gemboss-topbar-start { flex: 0 1 auto; }
|
|
2049
|
+
.gemboss-topbar-start > .gemboss-mobile-menu-btn { flex: 0 0 auto; }
|
|
2050
|
+
.gemboss-topbar-start > .gb-brand { min-width: 44px; }
|
|
2043
2051
|
}
|
|
2044
2052
|
|
|
2045
2053
|
.gnav-heading {
|
|
@@ -3384,7 +3392,9 @@ button.ui-card__media, a.ui-card__media { cursor: pointer; }
|
|
|
3384
3392
|
/* Delta: `<span class="ui-delta ui-delta--good"><span aria-hidden="true">↑</span> 12%</span>`. Tốt / xấu là của BỀ MẶT
|
|
3385
3393
|
quyết (lượt đọc tăng là tốt, tỉ lệ thoát tăng là xấu), mũi tên là hướng. Không tông = trung tính (không đổi, hoặc
|
|
3386
3394
|
"chưa có kỳ trước"). Luôn kèm chữ cho trình đọc màn hình nếu mũi tên là thứ duy nhất nói hướng. */
|
|
3387
|
-
|
|
3395
|
+
/* Wraps (0.6.2): a delta that carries its comparison ("▼ 50% vs previous 30 days (20m)") ran 73px out of a 145px metric at
|
|
3396
|
+
390 on gemcare. Short ones ("↑ 18%") still sit on one line; long ones break between words, never inside a number. */
|
|
3397
|
+
.ui-delta { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px; font-size: var(--gemboss-fs-caption); font-weight: 600; color: var(--ui-text-muted); font-variant-numeric: tabular-nums; }
|
|
3388
3398
|
.ui-delta--good { color: var(--ui-success-fg); }
|
|
3389
3399
|
.ui-delta--bad { color: var(--ui-danger-fg); }
|
|
3390
3400
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gemboss/ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "GemBoss design system for every surface in the fleet: the admin shell (topbar + rail + drawer) as React components, and the admin stylesheet exported as one CSS file.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
package/src/app-shell.css
CHANGED
|
@@ -31,14 +31,22 @@
|
|
|
31
31
|
.gemboss-topbar-center { display: flex; justify-content: center; min-width: 0; }
|
|
32
32
|
.gemboss-topbar-end { display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 0; }
|
|
33
33
|
@media (max-width: 760px) {
|
|
34
|
-
/* The topbar is one flex row here: the middle slot takes what is left.
|
|
35
|
-
|
|
34
|
+
/* The topbar is one flex row here: the middle slot takes what is left. Basis 0, not auto: with `auto` the search's own
|
|
35
|
+
* width (up to 520px) was its claim, so the other slots had to give way to it (0.6.0 pinned them instead, see below). With
|
|
36
|
+
* 0 it only takes what the others leave, down to a 96px floor: an input with its icon still reads as search. */
|
|
37
|
+
.gemboss-topbar-center { flex: 1 1 0; min-width: 96px; justify-content: flex-start; }
|
|
38
|
+
.gemboss-topbar-center:empty { min-width: 0; }
|
|
36
39
|
/* No actions: the empty slot would still take one flex `gap` (8px) off the search at 320px. */
|
|
37
40
|
.gemboss-topbar-end:empty { display: none; }
|
|
38
|
-
/*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
41
|
+
/* The actions never give: with `min-width: 0` the slot shrank and its buttons (justify flex-end) spilled LEFT over the
|
|
42
|
+
* search (assistant + account, 15px over partner-radar's search at 320 and 360, 0.6.0).
|
|
43
|
+
* The start slot gives LAST, after the search reaches its floor: the brand name ellipsizes (.gb-brand-name) instead of
|
|
44
|
+
* the account chip leaving the screen. 0.6.0 pinned it (`flex: 0 0 auto`) and a 30-character brand at 461px pushed the
|
|
45
|
+
* chip 44px past the right edge (review #3690). The menu button and the mark keep their 44px. */
|
|
46
|
+
.gemboss-topbar-end { flex: 0 0 auto; }
|
|
47
|
+
.gemboss-topbar-start { flex: 0 1 auto; }
|
|
48
|
+
.gemboss-topbar-start > .gemboss-mobile-menu-btn { flex: 0 0 auto; }
|
|
49
|
+
.gemboss-topbar-start > .gb-brand { min-width: 44px; }
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
.gnav-heading {
|
package/src/assistant/dock.ts
CHANGED
|
@@ -131,6 +131,28 @@ export function clampDockHeight(height: number, viewport: number): number {
|
|
|
131
131
|
return Math.min(Math.max(Math.round(height), DOCK_MIN_HEIGHT), max);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* How far below the topbar a popup that has just OPENED starts (03/10/2026).
|
|
136
|
+
*
|
|
137
|
+
* The 12px ceiling above is where a popup the seller DRAGS can reach. It is not where one should open.
|
|
138
|
+
* Chris, 03/10: "default height cao hơn sát vào topbar". Measured on his browser (window 620px tall):
|
|
139
|
+
* gemwatcher had a dragged 599 saved, every reopen clamped it to 552, and the popup opened 12px under
|
|
140
|
+
* the topbar; a flat 480 default also leaves only 84px on a 620 window and ~0 on a 560 one.
|
|
141
|
+
*/
|
|
142
|
+
export const DOCK_OPEN_GAP = 120;
|
|
143
|
+
|
|
144
|
+
/** The tallest a popup OPENS at in this window: a quarter-ish band of page stays visible above it. */
|
|
145
|
+
export function dockOpenCeiling(viewport: number): number {
|
|
146
|
+
return Math.max(DOCK_MIN_HEIGHT, Math.round(viewport) - DOCK_TOPBAR_HEIGHT - DOCK_OPEN_GAP);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** The height a popup opens at: what the seller asked for (or the default), never closer to the topbar
|
|
150
|
+
* than DOCK_OPEN_GAP. Dragging in-session can still go up to the 12px ceiling of `clampDockHeight`. */
|
|
151
|
+
export function openingDockHeight(requested: number | null, viewport: number): number {
|
|
152
|
+
const want = requested !== null && Number.isFinite(requested) && requested > 0 ? requested : DOCK_DEFAULT_HEIGHT;
|
|
153
|
+
return clampDockHeight(Math.min(want, dockOpenCeiling(viewport)), viewport);
|
|
154
|
+
}
|
|
155
|
+
|
|
134
156
|
export const initialAssistantDockState: AssistantDockState = {
|
|
135
157
|
presentation: "hidden",
|
|
136
158
|
mounted: false,
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
initialAssistantDockState,
|
|
19
19
|
DOCK_DEFAULT_HEIGHT,
|
|
20
20
|
DOCK_DEFAULT_OFFSET_RIGHT,
|
|
21
|
+
openingDockHeight,
|
|
21
22
|
SIDE_DEFAULT_WIDTH,
|
|
22
23
|
type AssistantDockState,
|
|
23
24
|
} from "./dock";
|
|
@@ -115,8 +116,10 @@ export function AssistantProvider({ options, children }: { options?: AssistantOp
|
|
|
115
116
|
// Restore the seller's popup size + pin after mount (localStorage is unavailable during SSR).
|
|
116
117
|
useEffect(() => {
|
|
117
118
|
try {
|
|
118
|
-
const
|
|
119
|
-
|
|
119
|
+
const stored = window.localStorage.getItem(storageKey(opts.current.storagePrefix, "dockHeight"));
|
|
120
|
+
// Opens no closer to the topbar than DOCK_OPEN_GAP, even when a past drag saved the ceiling
|
|
121
|
+
// (dock.ts, 03/10/2026). The stored number is left as it was: a drag rewrites it.
|
|
122
|
+
const height = openingDockHeight(stored === null || stored === "" ? null : Number(stored), window.innerHeight);
|
|
120
123
|
requestedHeight.current = height;
|
|
121
124
|
dispatch({ type: "resize", height, viewport: window.innerHeight });
|
|
122
125
|
// `Number(null)` is 0, not NaN — so reading a key that was never written used to slide the
|
package/src/kit-plain.css
CHANGED
|
@@ -127,7 +127,9 @@ button.ui-card__media, a.ui-card__media { cursor: pointer; }
|
|
|
127
127
|
/* Delta: `<span class="ui-delta ui-delta--good"><span aria-hidden="true">↑</span> 12%</span>`. Tốt / xấu là của BỀ MẶT
|
|
128
128
|
quyết (lượt đọc tăng là tốt, tỉ lệ thoát tăng là xấu), mũi tên là hướng. Không tông = trung tính (không đổi, hoặc
|
|
129
129
|
"chưa có kỳ trước"). Luôn kèm chữ cho trình đọc màn hình nếu mũi tên là thứ duy nhất nói hướng. */
|
|
130
|
-
|
|
130
|
+
/* Wraps (0.6.2): a delta that carries its comparison ("▼ 50% vs previous 30 days (20m)") ran 73px out of a 145px metric at
|
|
131
|
+
390 on gemcare. Short ones ("↑ 18%") still sit on one line; long ones break between words, never inside a number. */
|
|
132
|
+
.ui-delta { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px; font-size: var(--gemboss-fs-caption); font-weight: 600; color: var(--ui-text-muted); font-variant-numeric: tabular-nums; }
|
|
131
133
|
.ui-delta--good { color: var(--ui-success-fg); }
|
|
132
134
|
.ui-delta--bad { color: var(--ui-danger-fg); }
|
|
133
135
|
|
package/src/kit-plain.js
CHANGED
|
@@ -149,7 +149,13 @@
|
|
|
149
149
|
if (fresh) vp.dataset.readyAt = String(Date.now() + 50);
|
|
150
150
|
var wait = Math.max(0, Number(vp.dataset.readyAt || 0) - Date.now());
|
|
151
151
|
var put = function () { vp.append(t); };
|
|
152
|
-
|
|
152
|
+
// ONE timer drains the waiting toasts in the order they were sent. A setTimeout per toast did not: the second one
|
|
153
|
+
// computed a slightly shorter wait and could land first (CI, 03/10/2026: "down" before "<b>hi</b>"). Anything sent
|
|
154
|
+
// after the region is ready still goes straight in, behind the queue.
|
|
155
|
+
if (wait || vp._gbQueue) {
|
|
156
|
+
(vp._gbQueue = vp._gbQueue || []).push(put);
|
|
157
|
+
if (!vp._gbFlush) vp._gbFlush = setTimeout(function () { var q = vp._gbQueue; vp._gbQueue = null; vp._gbFlush = null; q.forEach(function (f) { f(); }); }, wait);
|
|
158
|
+
} else put();
|
|
153
159
|
if (!sticky) setTimeout(function () { t.remove(); }, wait + (opts.duration || (opts.error ? 6000 : 3500)));
|
|
154
160
|
return t;
|
|
155
161
|
}
|
package/src/ui.css
CHANGED
|
@@ -249,7 +249,7 @@ a.ui-metric:focus-visible { outline: 2px solid var(--ui-focus); outline-offset:
|
|
|
249
249
|
/* ── Thông báo: `<div class="ui-notice ui-notice--warning">…</div>`. Lỗi tải, cảnh báo cấu hình, việc cần người
|
|
250
250
|
làm. Mỗi tông mang màu chữ riêng (nền tông luôn sáng, kể cả trong admin tối). Không có tông = ghi chú trung tính.
|
|
251
251
|
role="status"/"alert" CHỈ khi thông báo xuất hiện sau khi trang đã tải (vùng live); có sẵn lúc tải thì không role. */
|
|
252
|
-
.ui-notice { padding: 12px 16px; border-radius: var(--ui-radius-md); border: 1px solid var(--ui-border); background: var(--ui-surface-2); color: var(--ui-text); font-size: var(--ui-fs-body); }
|
|
252
|
+
.ui-notice { padding: 12px 16px; border-radius: var(--ui-radius-md); border: 1px solid var(--ui-border); background: var(--ui-surface-2); color: var(--ui-text); font-size: var(--ui-fs-body); overflow-wrap: anywhere; } /* a URL or key in a notice wraps instead of being cut by its card (gemwatcher Pulse, 0.6.2) */
|
|
253
253
|
.ui-notice--warning { background: var(--gemboss-warning-soft); border-color: var(--gemboss-warning-border); color: var(--gemboss-warning); }
|
|
254
254
|
.ui-notice--danger { background: var(--gemboss-danger-soft); border-color: var(--gemboss-danger-border); color: var(--gemboss-danger-strong); }
|
|
255
255
|
.ui-notice--success { background: var(--gemboss-success-soft); border-color: var(--gemboss-success-border); color: var(--gemboss-success-strong); }
|