feat(web): 工作区侧栏 - 账号容量进度与签到加油站
头像上方展示已用/剩余/总容量,积分开启且未领取时固定显示品牌加油站卡片,当天领取后消失。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
43
web/test/workspace-sidebar-checkin.test.ts
Normal file
43
web/test/workspace-sidebar-checkin.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import { sidebarCheckinTitle, shouldShowSidebarCheckin } from "../src/lib/sidebar-checkin";
|
||||
|
||||
describe("sidebar checkin offer", () => {
|
||||
test("shows only when credits and a checkin bonus are enabled and today is unclaimed", () => {
|
||||
expect(shouldShowSidebarCheckin({ creditsEnabled: true, checkinBonusMicrocredits: 100_000_000, checkedInToday: false })).toBe(true);
|
||||
expect(shouldShowSidebarCheckin({ creditsEnabled: false, checkinBonusMicrocredits: 100_000_000, checkedInToday: false })).toBe(false);
|
||||
expect(shouldShowSidebarCheckin({ creditsEnabled: true, checkinBonusMicrocredits: 0, checkedInToday: false })).toBe(false);
|
||||
expect(shouldShowSidebarCheckin({ creditsEnabled: true, checkinBonusMicrocredits: 100_000_000, checkedInToday: true })).toBe(false);
|
||||
});
|
||||
|
||||
test("uses the configured brand name instead of Buddy", () => {
|
||||
expect(sidebarCheckinTitle("影策")).toBe("影策加油站");
|
||||
expect(sidebarCheckinTitle(" 本地工作室 ")).toBe("本地工作室加油站");
|
||||
expect(sidebarCheckinTitle("")).toBe("影策加油站");
|
||||
});
|
||||
});
|
||||
|
||||
describe("workspace sidebar checkin card", () => {
|
||||
test("sits above account storage and uses the claim card colors without a light-blue stage", () => {
|
||||
const sidebar = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-sidebar-nav.tsx"), "utf8");
|
||||
const card = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-sidebar-checkin.tsx"), "utf8");
|
||||
const css = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
|
||||
const checkinIndex = sidebar.indexOf("<WorkspaceSidebarCheckin collapsed={collapsed} />");
|
||||
const storageIndex = sidebar.indexOf("<WorkspaceSidebarStorageMeter collapsed={collapsed} />");
|
||||
const start = css.indexOf(".app-user-workspace .app-workspace-sidebar-checkin {");
|
||||
const end = css.indexOf(".app-user-workspace .app-workspace-sidebar-storage {", start);
|
||||
const block = css.slice(start, end);
|
||||
|
||||
expect(checkinIndex).toBeGreaterThan(-1);
|
||||
expect(storageIndex).toBeGreaterThan(checkinIndex);
|
||||
expect(card).toContain("立即领取");
|
||||
expect(card).toContain("今日可领");
|
||||
expect(card).toContain("checkinCredits()");
|
||||
expect(block).toContain("background: #fff;");
|
||||
expect(block).toContain("background: #171717;");
|
||||
expect(block).toContain("color: #12c8a0;");
|
||||
expect(block).not.toMatch(/#(?:dbeafe|e8f1ff|eef4ff|e6f0ff|d6e8ff)/i);
|
||||
});
|
||||
});
|
||||
66
web/test/workspace-sidebar-storage.test.ts
Normal file
66
web/test/workspace-sidebar-storage.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import { accountStorageMeter } from "../src/lib/account-storage-usage";
|
||||
|
||||
const GB = 1024 ** 3;
|
||||
|
||||
describe("account storage meter", () => {
|
||||
test("exposes remaining capacity and total capacity", () => {
|
||||
const meter = accountStorageMeter({ usedBytes: 2 * GB, totalBytes: 10 * GB });
|
||||
|
||||
expect(meter.usedLabel).toBe("2.0 GB");
|
||||
expect(meter.remainingLabel).toBe("8.0 GB");
|
||||
expect(meter.totalLabel).toBe("10 GB");
|
||||
expect(meter.percent).toBe(20);
|
||||
expect(meter.tone).toBe("ok");
|
||||
expect(meter.full).toBe(false);
|
||||
});
|
||||
|
||||
test("warns when usage reaches seventy percent", () => {
|
||||
const meter = accountStorageMeter({ usedBytes: 7 * GB, totalBytes: 10 * GB });
|
||||
|
||||
expect(meter.percent).toBe(70);
|
||||
expect(meter.tone).toBe("warn");
|
||||
expect(meter.remainingLabel).toBe("3.0 GB");
|
||||
});
|
||||
|
||||
test("marks full accounts as critical with zero remaining", () => {
|
||||
const meter = accountStorageMeter({ usedBytes: 10 * GB, totalBytes: 10 * GB });
|
||||
|
||||
expect(meter.full).toBe(true);
|
||||
expect(meter.tone).toBe("critical");
|
||||
expect(meter.remainingBytes).toBe(0);
|
||||
expect(meter.remainingLabel).toBe("0 B");
|
||||
expect(meter.percent).toBe(100);
|
||||
});
|
||||
|
||||
test("treats missing usage as empty instead of overflowing", () => {
|
||||
const meter = accountStorageMeter();
|
||||
|
||||
expect(meter.percent).toBe(0);
|
||||
expect(meter.remainingLabel).toBe("0 B");
|
||||
expect(meter.totalLabel).toBe("0 B");
|
||||
expect(meter.tone).toBe("ok");
|
||||
expect(meter.full).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("workspace sidebar storage meter", () => {
|
||||
test("sits above the signed-in profile and shows used, remaining and total", () => {
|
||||
const sidebar = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-sidebar-nav.tsx"), "utf8");
|
||||
const meter = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-sidebar-storage-meter.tsx"), "utf8");
|
||||
const css = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
|
||||
|
||||
expect(sidebar).toContain("<WorkspaceSidebarStorageMeter collapsed={collapsed} />");
|
||||
expect(sidebar.indexOf("WorkspaceSidebarStorageMeter")).toBeLessThan(sidebar.indexOf("app-workspace-sidebar-profile-row"));
|
||||
expect(meter).toContain("已用 ${meter.usedLabel}");
|
||||
expect(meter).toContain("剩余 ${meter.remainingLabel}");
|
||||
expect(meter).toContain("共 ${meter.totalLabel}");
|
||||
expect(meter).toContain('to="/assets"');
|
||||
expect(css).toMatch(/\.app-workspace-sidebar-storage-used\s*\{[^}]*font-variant-numeric:\s*tabular-nums/s);
|
||||
expect(css).toContain(".app-workspace-sidebar-storage.is-warn");
|
||||
expect(css).toContain(".app-workspace-sidebar-storage.is-critical");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user