style(web): 工作台入口 - 侧栏容量加硬盘图标,积分入口改为礼盒标
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
521629c2a8
commit
1077a9106d
10 files changed
+254
-50
No files matched your search
@@ -26,7 +26,7 @@ description: 当前项目已实现的核心工作台能力与使用入口
|
||||
|
||||
## 工作区账号容量
|
||||
|
||||
登录后,首页侧栏左下角用户头像上方显示账号文件容量进度:已用容量、剩余容量和总容量,细进度条表示已用比例。用量达到 70% 变为警告色,达到 90% 或已满变为危险色。点击进入素材库;资产页页头仍展示同一用量。收起侧栏时保留细进度条,悬停可看到已用、剩余与总容量。统计包含素材文件和 Agent 会话附件。
|
||||
登录后,首页侧栏左下角用户头像上方显示账号文件容量进度:左侧硬盘图标,右侧已用容量与总容量,进度条旁显示剩余容量。用量达到 70% 变为警告色,达到 90% 或已满变为危险色。点击进入素材库;资产页页头仍展示同一用量。收起侧栏时保留图标和细进度条,悬停可看到已用、剩余与总容量。统计包含素材文件和 Agent 会话附件。
|
||||
|
||||
### 相关实现
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ description: 当前项目已实现功能的手工验证清单与未确认边界
|
||||
|
||||
登录后首页侧栏左下角用户头像上方展示账号文件容量。待登录工作台后:
|
||||
|
||||
- [ ] 展开侧栏时能看到已用容量、剩余容量、总容量和进度条;数字为真实配额,不是占位。
|
||||
- [ ] 收起侧栏后头像上方仍有细进度条,悬停能看到剩余/总容量。
|
||||
- [ ] 展开侧栏时能看到硬盘图标、已用容量、剩余容量、总容量和进度条;数字为真实配额,不是占位。
|
||||
- [ ] 收起侧栏后头像上方仍有硬盘图标和细进度条,悬停能看到剩余/总容量。
|
||||
- [ ] 用量到 70% 变警告色,到 90% 或已满变危险色;点进度条进入资产页,两边数字一致。
|
||||
- [ ] 未登录不显示该进度;接口失败时可重试。
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useId } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function WorkspaceCreditGiftMark({ className }: { className?: string }) {
|
||||
const uid = useId().replace(/:/g, "");
|
||||
const box = `${uid}-box`;
|
||||
const lid = `${uid}-lid`;
|
||||
const ribbon = `${uid}-ribbon`;
|
||||
|
||||
return (
|
||||
<span className={cn("app-workspace-credit-gift", className)} aria-hidden="true">
|
||||
<svg viewBox="0 0 32 32" fill="none">
|
||||
<defs>
|
||||
<linearGradient id={box} x1="8" y1="14" x2="24" y2="28" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#FFB34A" />
|
||||
<stop offset="1" stopColor="#F26B12" />
|
||||
</linearGradient>
|
||||
<linearGradient id={lid} x1="6" y1="10" x2="26" y2="16" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#FFC66A" />
|
||||
<stop offset="1" stopColor="#FF8A28" />
|
||||
</linearGradient>
|
||||
<linearGradient id={ribbon} x1="16" y1="6" x2="16" y2="28" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#5FE8D8" />
|
||||
<stop offset="1" stopColor="#12B8A8" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<ellipse cx="16" cy="28.5" rx="9.2" ry="1.6" fill="#7A3A00" opacity=".22" />
|
||||
<rect x="6.5" y="14" width="19" height="13.2" rx="2.4" fill={`url(#${box})`} />
|
||||
<path d="M23.4 16.4v8.4c0 1.3-1 2.4-2.3 2.4h.1V14c1.3.2 2.2 1.2 2.2 2.4Z" fill="#7A3A00" opacity=".16" />
|
||||
<rect x="14.4" y="14" width="3.2" height="13.2" fill={`url(#${ribbon})`} />
|
||||
<rect x="6.5" y="19.3" width="19" height="2.8" fill={`url(#${ribbon})`} />
|
||||
<rect x="5.4" y="10.3" width="21.2" height="5.5" rx="2.1" fill={`url(#${lid})`} />
|
||||
<rect x="5.4" y="10.3" width="21.2" height="2.1" rx="2.1" fill="#fff" opacity=".24" />
|
||||
<rect x="14.4" y="10.3" width="3.2" height="5.5" fill={`url(#${ribbon})`} />
|
||||
<path d="M15.8 11.1C10.4 5.6 7.2 11.8 12.8 13.7c1.6.5 2.4 0 3-1.2Z" fill="#4FE3D4" />
|
||||
<path d="M16.2 11.1C21.6 5.6 24.8 11.8 19.2 13.7c-1.6.5-2.4 0-3-1.2Z" fill="#14C4B4" />
|
||||
<rect x="14.7" y="9.3" width="2.6" height="2.6" rx=".8" fill="#0E9E92" />
|
||||
<path d="M14.9 12.1 11.6 16.4l3.8-3.1Z" fill="#3FDDD0" />
|
||||
<path d="M17.1 12.1 20.4 16.4l-3.8-3.1Z" fill="#12B6A6" />
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { HardDrive } from "lucide-react";
|
||||
import { Link } from "react-router";
|
||||
|
||||
import { useAccountFileStorageUsage } from "@/hooks/use-account-file-storage-usage";
|
||||
@@ -5,6 +6,14 @@ import { accountStorageMeter } from "@/lib/account-storage-usage";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { preloadWorkspaceRoute } from "@/lib/workspace-route-modules";
|
||||
|
||||
function StorageGlyph() {
|
||||
return (
|
||||
<span className="app-workspace-sidebar-storage-icon" aria-hidden="true">
|
||||
<HardDrive strokeWidth={1.75} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export function WorkspaceSidebarStorageMeter({ collapsed }: { collapsed: boolean }) {
|
||||
const query = useAccountFileStorageUsage();
|
||||
const meter = accountStorageMeter(query.data);
|
||||
@@ -13,13 +22,30 @@ export function WorkspaceSidebarStorageMeter({ collapsed }: { collapsed: boolean
|
||||
const totalText = query.data ? `共 ${meter.totalLabel}` : "";
|
||||
const summary = query.data ? `${usedText},${remainingText},${totalText}` : usedText;
|
||||
|
||||
const track = (
|
||||
<span
|
||||
className="app-workspace-sidebar-storage-track"
|
||||
role="progressbar"
|
||||
aria-label="账号文件容量使用进度"
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={query.data?.totalBytes ?? 0}
|
||||
aria-valuenow={query.data ? Math.min(query.data.usedBytes, query.data.totalBytes) : 0}
|
||||
aria-valuetext={summary}
|
||||
>
|
||||
<span style={{ width: `${meter.percent}%` }} />
|
||||
</span>
|
||||
);
|
||||
|
||||
if (query.isError && !query.data) {
|
||||
return (
|
||||
<div className={cn("app-workspace-sidebar-storage is-error", collapsed && "is-collapsed")}>
|
||||
{collapsed ? (
|
||||
<button type="button" title="容量统计暂时不可用,点击重试" aria-label="重试加载账号容量" onClick={() => void query.refetch()} />
|
||||
<button type="button" title="容量统计暂时不可用,点击重试" aria-label="重试加载账号容量" onClick={() => void query.refetch()}>
|
||||
<StorageGlyph />
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<StorageGlyph />
|
||||
<span>容量暂不可用</span>
|
||||
<button type="button" onClick={() => void query.refetch()}>
|
||||
重试
|
||||
@@ -47,26 +73,23 @@ export function WorkspaceSidebarStorageMeter({ collapsed }: { collapsed: boolean
|
||||
onFocus={() => preloadWorkspaceRoute("/assets")}
|
||||
onPointerEnter={() => preloadWorkspaceRoute("/assets")}
|
||||
>
|
||||
{collapsed ? null : (
|
||||
<span className="app-workspace-sidebar-storage-copy">
|
||||
<span className="app-workspace-sidebar-storage-meta">
|
||||
<span className="app-workspace-sidebar-storage-used">{usedText}</span>
|
||||
{totalText ? <span className="app-workspace-sidebar-storage-total">{totalText}</span> : null}
|
||||
<StorageGlyph />
|
||||
{collapsed ? (
|
||||
track
|
||||
) : (
|
||||
<span className="app-workspace-sidebar-storage-body">
|
||||
<span className="app-workspace-sidebar-storage-copy">
|
||||
<span className="app-workspace-sidebar-storage-meta">
|
||||
<span className="app-workspace-sidebar-storage-used">{usedText}</span>
|
||||
{totalText ? <span className="app-workspace-sidebar-storage-total">{totalText}</span> : null}
|
||||
</span>
|
||||
</span>
|
||||
<span className="app-workspace-sidebar-storage-foot">
|
||||
{track}
|
||||
{remainingText ? <span className="app-workspace-sidebar-storage-remain">{remainingText}</span> : null}
|
||||
</span>
|
||||
{remainingText ? <span className="app-workspace-sidebar-storage-remain">{remainingText}</span> : null}
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className="app-workspace-sidebar-storage-track"
|
||||
role="progressbar"
|
||||
aria-label="账号文件容量使用进度"
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={query.data?.totalBytes ?? 0}
|
||||
aria-valuenow={query.data ? Math.min(query.data.usedBytes, query.data.totalBytes) : 0}
|
||||
aria-valuetext={summary}
|
||||
>
|
||||
<span style={{ width: `${meter.percent}%` }} />
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Coins, PanelLeftClose, PanelLeftOpen } from "lucide-react";
|
||||
import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
|
||||
import { Link, useLocation } from "react-router";
|
||||
|
||||
import { SystemAnnouncementCenter } from "@/components/layout/system-announcement-center";
|
||||
import { WorkspaceAccountMenu } from "@/components/layout/workspace-account-menu";
|
||||
import { WorkspaceCreditGiftMark } from "@/components/layout/workspace-credit-gift-mark";
|
||||
import { WorkspaceTopBarExtensionSlot } from "@/components/layout/workspace-top-bar-extension";
|
||||
import { AnimatedThemeToggler } from "@/components/ui/animated-theme-toggler";
|
||||
import { useThemeStore } from "@/stores/use-theme-store";
|
||||
@@ -48,7 +49,7 @@ export function WorkspaceTopBar({ sidebarOpen, onToggleSidebar }: { sidebarOpen:
|
||||
<WorkspaceTopBarExtensionSlot />
|
||||
<div className="app-workspace-topbar-actions">
|
||||
{creditsEnabled ? <button type="button" className="app-workspace-topbar-credit-pill" aria-label={`打开积分中心,可用 ${balance} 积分`} onClick={() => openWorkspaceWallet()}>
|
||||
<Coins aria-hidden="true" />
|
||||
<WorkspaceCreditGiftMark />
|
||||
<span>积分</span>
|
||||
<strong>{balance}</strong>
|
||||
</button> : null}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from "react";
|
||||
import { Link } from "react-router";
|
||||
import { Clapperboard, CloudDownload, CloudUpload, Coins, CopyPlus, Focus, FolderKanban, Gauge, Home, LayoutGrid, LoaderCircle, Menu, Pencil, Plus, Redo2, Save, Search, Share2, Trash2, Undo2, Upload } from "lucide-react";
|
||||
import { Clapperboard, CloudDownload, CloudUpload, CopyPlus, Focus, FolderKanban, Gauge, Home, LayoutGrid, LoaderCircle, Menu, Pencil, Plus, Redo2, Save, Search, Share2, Trash2, Undo2, Upload } from "lucide-react";
|
||||
import { Button, Dropdown, Tooltip } from "antd";
|
||||
|
||||
import { WorkspaceCreditGiftMark } from "@/components/layout/workspace-credit-gift-mark";
|
||||
import { useWalletBalance } from "@/hooks/use-wallet-balance";
|
||||
import { openWorkspaceWallet } from "@/lib/workspace-wallet";
|
||||
import { canvasDockStyle } from "@/lib/canvas/canvas-aceternity-style";
|
||||
@@ -241,7 +242,7 @@ export function CanvasTopBar({
|
||||
aria-label="打开积分中心"
|
||||
onClick={() => openWorkspaceWallet()}
|
||||
>
|
||||
{refreshing && availableMicrocredits === null ? <LoaderCircle className="size-3.5 animate-spin opacity-60" style={{ color: theme.accent.primary }} /> : <Coins className="size-3.5" style={{ color: theme.accent.primary }} />}
|
||||
{refreshing && availableMicrocredits === null ? <LoaderCircle className="size-3.5 animate-spin opacity-60" style={{ color: theme.accent.primary }} /> : <WorkspaceCreditGiftMark className="is-compact" />}
|
||||
<span>{availableMicrocredits === null ? "--" : (availableMicrocredits / 1_000_000).toLocaleString("zh-CN", { maximumFractionDigits: 3 })}</span>
|
||||
</button>
|
||||
</CanvasTopBarTooltip>
|
||||
|
||||
+135
-24
@@ -1863,6 +1863,10 @@
|
||||
background: var(--dock-command-hover) !important;
|
||||
}
|
||||
|
||||
.canvas-topbar-action:hover:not(:disabled) .app-workspace-credit-gift {
|
||||
transform: translateY(-1px) rotate(-8deg);
|
||||
}
|
||||
|
||||
.canvas-topbar-project-cluster {
|
||||
width: max-content;
|
||||
max-width: min(360px, calc(50vw - 88px));
|
||||
@@ -16099,11 +16103,12 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
height: 36px;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
padding: 0 12px;
|
||||
gap: 8px;
|
||||
padding: 0 12px 0 8px;
|
||||
border: 1px solid rgba(0, 0, 0, .075);
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
@@ -16113,15 +16118,46 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill:hover {
|
||||
border-color: rgba(91, 78, 224, .26);
|
||||
background: #fbfaff;
|
||||
border-color: color-mix(in srgb, #ff8a28 34%, transparent);
|
||||
background: #fffaf4;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
color: #6a58e8;
|
||||
.app-user-workspace .app-workspace-credit-gift {
|
||||
display: grid;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex: none;
|
||||
place-items: center;
|
||||
filter: drop-shadow(0 1px 1px rgba(92, 42, 0, .22));
|
||||
transform-origin: 50% 70%;
|
||||
transition: transform .18s ease;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-credit-gift svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
overflow: visible;
|
||||
color: unset;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-credit-gift.is-compact,
|
||||
.app-user-workspace .app-workspace-credit-gift.is-compact svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill:hover .app-workspace-credit-gift {
|
||||
transform: translateY(-1px) rotate(-8deg);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill,
|
||||
.app-user-workspace .app-workspace-credit-gift,
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill:hover .app-workspace-credit-gift {
|
||||
transform: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill strong {
|
||||
@@ -16268,9 +16304,9 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
.app-user-workspace .app-workspace-sidebar-storage {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 8px 8px 6px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
border-radius: 12px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
@@ -16282,11 +16318,40 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
background: var(--user-surface-hover, rgba(72, 72, 73, .055));
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage:hover .app-workspace-sidebar-storage-icon,
|
||||
.app-user-workspace .app-workspace-sidebar-storage:focus-visible .app-workspace-sidebar-storage-icon {
|
||||
color: var(--user-ink, var(--foreground));
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage:focus-visible {
|
||||
outline: 2px solid var(--control-focus-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-icon {
|
||||
display: grid;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex: none;
|
||||
place-items: center;
|
||||
border-radius: 9px;
|
||||
background: color-mix(in srgb, var(--user-ink, var(--foreground)) 8%, transparent);
|
||||
color: color-mix(in srgb, var(--user-ink, var(--foreground)) 78%, transparent);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-body {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-copy {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
@@ -16294,6 +16359,13 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-foot {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-meta {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
@@ -16326,12 +16398,14 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-remain {
|
||||
min-width: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage-track {
|
||||
display: block;
|
||||
height: 5px;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
height: 4px;
|
||||
overflow: hidden;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--user-ink, var(--foreground)) 10%, transparent);
|
||||
@@ -16353,18 +16427,28 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
background: color-mix(in srgb, var(--user-ink, var(--foreground)) 8%, transparent);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-warn .app-workspace-sidebar-storage-used {
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-warn .app-workspace-sidebar-storage-used,
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-warn .app-workspace-sidebar-storage-icon {
|
||||
color: var(--status-warning);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-warn .app-workspace-sidebar-storage-icon {
|
||||
background: color-mix(in srgb, var(--status-warning) 14%, transparent);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-warn .app-workspace-sidebar-storage-track > span {
|
||||
background: var(--status-warning);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-critical .app-workspace-sidebar-storage-used {
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-critical .app-workspace-sidebar-storage-used,
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-critical .app-workspace-sidebar-storage-icon {
|
||||
color: var(--status-error);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-critical .app-workspace-sidebar-storage-icon {
|
||||
background: color-mix(in srgb, var(--status-error) 14%, transparent);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-critical .app-workspace-sidebar-storage-track > span {
|
||||
background: var(--progress-bar-fill-error);
|
||||
}
|
||||
@@ -16379,6 +16463,11 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
font-size: var(--fs-tiny);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-error .app-workspace-sidebar-storage-icon {
|
||||
color: color-mix(in srgb, var(--status-error) 72%, transparent);
|
||||
background: color-mix(in srgb, var(--status-error) 12%, transparent);
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-error button {
|
||||
color: var(--user-ink, var(--foreground));
|
||||
text-decoration: underline;
|
||||
@@ -16391,26 +16480,43 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-collapsed {
|
||||
width: 36px;
|
||||
padding: 8px 0 6px;
|
||||
width: 40px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 0;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-collapsed .app-workspace-sidebar-storage-track {
|
||||
flex: none;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-collapsed.is-error {
|
||||
width: 36px;
|
||||
width: 40px;
|
||||
min-height: 0;
|
||||
padding: 2px 0 4px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-collapsed.is-error button {
|
||||
display: block;
|
||||
width: 36px;
|
||||
height: 5px;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--status-error) 48%, transparent);
|
||||
display: grid;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
place-items: center;
|
||||
border-radius: 9px;
|
||||
background: color-mix(in srgb, var(--status-error) 14%, transparent);
|
||||
color: var(--status-error);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-storage.is-collapsed.is-error .app-workspace-sidebar-storage-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.app-user-workspace .app-workspace-sidebar-profile-row {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
@@ -18604,6 +18710,11 @@ html:not(.dark) .creation-home .creation-user-message-copy-wrap { box-shadow: 0
|
||||
}
|
||||
.app-user-workspace .app-workspace-topbar-breadcrumb { color: var(--user-ink-muted) !important; }
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill { border-color: var(--user-border) !important; background: var(--user-surface) !important; color: var(--user-ink-muted) !important; }
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill:hover,
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill:focus-visible {
|
||||
border-color: color-mix(in srgb, #ff8a28 36%, var(--user-border)) !important;
|
||||
background: color-mix(in srgb, #ff8a28 10%, var(--user-surface)) !important;
|
||||
}
|
||||
.app-user-workspace .app-workspace-topbar-credit-pill strong { color: var(--user-ink) !important; }
|
||||
|
||||
/* One scroll owner on the creation route. */
|
||||
|
||||
@@ -469,7 +469,7 @@
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-nav-link .app-workspace-nav-main > svg { width: 18px !important; height: 18px !important; flex: 0 0 18px; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-account { width: 100%; align-items: center; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-checkin { width: 48px; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-storage { width: 36px; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-storage { width: 40px; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-profile-row { width: 100%; justify-content: center; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-profile { width: 48px; min-width: 48px; flex: 0 0 48px; margin-inline: auto; }
|
||||
.app-user-workspace .app-workspace-sidebar-nav.is-collapsed .app-workspace-sidebar-notification-spacer { display: none; }
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("workspace credit gift mark", () => {
|
||||
test("top-bar credit entries use a product gift instead of a lucide coin", () => {
|
||||
const topBar = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-top-bar.tsx"), "utf8");
|
||||
const canvas = readFileSync(resolve(import.meta.dir, "../src/pages/canvas/canvas-project-top-bar.tsx"), "utf8");
|
||||
const mark = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-credit-gift-mark.tsx"), "utf8");
|
||||
const css = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
|
||||
|
||||
expect(topBar).toContain("<WorkspaceCreditGiftMark />");
|
||||
expect(topBar).not.toContain("Coins");
|
||||
expect(canvas).toContain("<WorkspaceCreditGiftMark className=\"is-compact\" />");
|
||||
expect(canvas).not.toContain("Coins");
|
||||
expect(mark).toContain("#FFB34A");
|
||||
expect(mark).toContain("#12B8A8");
|
||||
expect(css).toContain(".app-workspace-credit-gift");
|
||||
expect(css).toContain("rotate(-8deg)");
|
||||
});
|
||||
});
|
||||
@@ -55,10 +55,13 @@ describe("workspace sidebar storage meter", () => {
|
||||
|
||||
expect(sidebar).toContain("<WorkspaceSidebarStorageMeter collapsed={collapsed} />");
|
||||
expect(sidebar.indexOf("WorkspaceSidebarStorageMeter")).toBeLessThan(sidebar.indexOf("app-workspace-sidebar-profile-row"));
|
||||
expect(meter).toContain("HardDrive");
|
||||
expect(meter).toContain("app-workspace-sidebar-storage-icon");
|
||||
expect(meter).toContain("已用 ${meter.usedLabel}");
|
||||
expect(meter).toContain("剩余 ${meter.remainingLabel}");
|
||||
expect(meter).toContain("共 ${meter.totalLabel}");
|
||||
expect(meter).toContain('to="/assets"');
|
||||
expect(css).toContain(".app-workspace-sidebar-storage-icon");
|
||||
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