Merge remote-tracking branch 'origin/master' into codex/wechat-mini-program-virtual-payment
# Conflicts: # .hermes/shared-memory/decision-log.md
This commit is contained in:
@@ -142,17 +142,22 @@ describe('CustomWorldGenerationView', () => {
|
||||
screen
|
||||
.getByRole('progressbar', { name: progressTitle })
|
||||
.className,
|
||||
).toContain('w-[min(35rem,94vw)]');
|
||||
).toContain('w-[400px]');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: progressTitle })
|
||||
.className,
|
||||
).toContain('sm:w-[52rem]');
|
||||
).toContain('h-[400px]');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: progressTitle })
|
||||
.getAttribute('data-ring-start-degrees'),
|
||||
).toBe('155');
|
||||
).toBe('135');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: progressTitle })
|
||||
.getAttribute('data-ring-fill-start-degrees'),
|
||||
).toBe('135');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: progressTitle })
|
||||
@@ -193,12 +198,12 @@ describe('CustomWorldGenerationView', () => {
|
||||
screen
|
||||
.getByTestId('generation-hero-progress-ring-track')
|
||||
.getAttribute('transform'),
|
||||
).toBe('rotate(155 200 200)');
|
||||
).toBe('rotate(135 200 200)');
|
||||
expect(
|
||||
screen
|
||||
.getByTestId('generation-hero-progress-ring-fill')
|
||||
.getAttribute('transform'),
|
||||
).toBe('rotate(155 200 200)');
|
||||
).toBe('rotate(135 200 200)');
|
||||
expect(
|
||||
screen
|
||||
.getByTestId('generation-hero-progress-ring-fill')
|
||||
|
||||
@@ -4,8 +4,16 @@ import { useEffect, useId, useRef } from 'react';
|
||||
|
||||
import generationHeroVideo from '../../media/create_bg_video.mp4';
|
||||
|
||||
const GENERATION_PROGRESS_RING_START_DEGREES = 155;
|
||||
const GENERATION_PROGRESS_RING_SWEEP_DEGREES = 270;
|
||||
const GENERATION_PROGRESS_RING_GAP_DEGREES = 90;
|
||||
const GENERATION_PROGRESS_RING_BOTTOM_DEGREES = 90;
|
||||
// 中文注释:SVG 圆从 3 点钟方向起笔;起点放在 135deg,可让 90deg 开口居中落在正下方。
|
||||
const GENERATION_PROGRESS_RING_START_DEGREES =
|
||||
GENERATION_PROGRESS_RING_BOTTOM_DEGREES +
|
||||
GENERATION_PROGRESS_RING_GAP_DEGREES / 2;
|
||||
const GENERATION_PROGRESS_RING_FILL_START_DEGREES =
|
||||
GENERATION_PROGRESS_RING_START_DEGREES;
|
||||
const GENERATION_PROGRESS_RING_SWEEP_DEGREES =
|
||||
360 - GENERATION_PROGRESS_RING_GAP_DEGREES;
|
||||
const GENERATION_PROGRESS_RING_VIEWBOX = 400;
|
||||
const GENERATION_PROGRESS_RING_CENTER = GENERATION_PROGRESS_RING_VIEWBOX / 2;
|
||||
const GENERATION_PROGRESS_RING_RADIUS = 166;
|
||||
@@ -118,7 +126,9 @@ export function GenerationProgressHero({
|
||||
const safeProgress = clampGenerationProgress(progressValue);
|
||||
const ringGradientId = useId().replace(/:/g, '');
|
||||
const ringMetrics = buildGenerationRingMetrics(safeProgress);
|
||||
const ringDegrees = Math.round((safeProgress / 100) * 270);
|
||||
const ringDegrees = Math.round(
|
||||
(safeProgress / 100) * GENERATION_PROGRESS_RING_SWEEP_DEGREES,
|
||||
);
|
||||
const ringTrackDasharray = `${ringMetrics.sweepLength.toFixed(2)} ${ringMetrics.circumference.toFixed(2)}`;
|
||||
const ringFillDasharray = `${ringMetrics.progressLength.toFixed(2)} ${ringMetrics.circumference.toFixed(2)}`;
|
||||
|
||||
@@ -160,16 +170,19 @@ export function GenerationProgressHero({
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="relative mx-auto aspect-square w-[min(35rem,94vw)] overflow-visible rounded-full sm:w-[52rem]"
|
||||
className="relative mx-auto h-[400px] w-[400px] shrink-0 overflow-visible rounded-full"
|
||||
role="progressbar"
|
||||
aria-label={title}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={safeProgress}
|
||||
data-ring-start-degrees={GENERATION_PROGRESS_RING_START_DEGREES}
|
||||
data-ring-fill-start-degrees={
|
||||
GENERATION_PROGRESS_RING_FILL_START_DEGREES
|
||||
}
|
||||
data-ring-sweep-degrees={GENERATION_PROGRESS_RING_SWEEP_DEGREES}
|
||||
data-ring-fill-degrees={ringDegrees}
|
||||
data-ring-gap-degrees={90}
|
||||
data-ring-gap-degrees={GENERATION_PROGRESS_RING_GAP_DEGREES}
|
||||
>
|
||||
<svg
|
||||
data-testid="generation-hero-progress-ring"
|
||||
@@ -214,7 +227,7 @@ export function GenerationProgressHero({
|
||||
strokeLinecap="round"
|
||||
strokeWidth={GENERATION_PROGRESS_RING_STROKE_WIDTH}
|
||||
strokeDasharray={ringFillDasharray}
|
||||
transform={`rotate(${GENERATION_PROGRESS_RING_START_DEGREES} ${GENERATION_PROGRESS_RING_CENTER} ${GENERATION_PROGRESS_RING_CENTER})`}
|
||||
transform={`rotate(${GENERATION_PROGRESS_RING_FILL_START_DEGREES} ${GENERATION_PROGRESS_RING_CENTER} ${GENERATION_PROGRESS_RING_CENTER})`}
|
||||
vectorEffect="non-scaling-stroke"
|
||||
shapeRendering="geometricPrecision"
|
||||
/>
|
||||
|
||||
@@ -130,12 +130,12 @@ describe('BarkBattleGeneratingView', () => {
|
||||
screen
|
||||
.getByRole('progressbar', { name: '汪汪声浪素材生成进度' })
|
||||
.className,
|
||||
).toContain('w-[min(35rem,94vw)]');
|
||||
).toContain('w-[400px]');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: '汪汪声浪素材生成进度' })
|
||||
.className,
|
||||
).toContain('sm:w-[52rem]');
|
||||
).toContain('h-[400px]');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: '汪汪声浪素材生成进度' })
|
||||
@@ -145,7 +145,12 @@ describe('BarkBattleGeneratingView', () => {
|
||||
screen
|
||||
.getByRole('progressbar', { name: '汪汪声浪素材生成进度' })
|
||||
.getAttribute('data-ring-start-degrees'),
|
||||
).toBe('155');
|
||||
).toBe('135');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: '汪汪声浪素材生成进度' })
|
||||
.getAttribute('data-ring-fill-start-degrees'),
|
||||
).toBe('135');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('progressbar', { name: '汪汪声浪素材生成进度' })
|
||||
@@ -186,12 +191,12 @@ describe('BarkBattleGeneratingView', () => {
|
||||
screen
|
||||
.getByTestId('generation-hero-progress-ring-track')
|
||||
.getAttribute('transform'),
|
||||
).toBe('rotate(155 200 200)');
|
||||
).toBe('rotate(135 200 200)');
|
||||
expect(
|
||||
screen
|
||||
.getByTestId('generation-hero-progress-ring-fill')
|
||||
.getAttribute('transform'),
|
||||
).toBe('rotate(155 200 200)');
|
||||
).toBe('rotate(135 200 200)');
|
||||
expect(
|
||||
screen
|
||||
.getByTestId('generation-hero-progress-ring-fill')
|
||||
|
||||
@@ -560,7 +560,7 @@ test('creation hub shows RPG public work code from published library entry', ()
|
||||
expect(screen.queryByText('CW-00000001')).toBeNull();
|
||||
});
|
||||
|
||||
test('creation hub hides persisted draft delete action behind swipe underlay', () => {
|
||||
test('creation hub exposes persisted draft delete action directly on the card', () => {
|
||||
const { container } = render(
|
||||
<CustomWorldCreationHub
|
||||
items={[{ ...baseDraftItem, profileId: 'profile-1' }]}
|
||||
@@ -579,7 +579,7 @@ test('creation hub hides persisted draft delete action behind swipe underlay', (
|
||||
expect(
|
||||
container.querySelector('.creation-work-card__swipe-underlay'),
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByRole('button', { name: '删除' })).toBeNull();
|
||||
expect(screen.getByRole('button', { name: '删除' })).toBeTruthy();
|
||||
});
|
||||
|
||||
test('creation hub reveals persisted draft delete action from left swipe', () => {
|
||||
@@ -607,7 +607,9 @@ test('creation hub reveals persisted draft delete action from left swipe', () =>
|
||||
});
|
||||
fireEvent.touchEnd(card);
|
||||
|
||||
expect(screen.getByRole('button', { name: '删除' })).toBeTruthy();
|
||||
expect(
|
||||
container.querySelector('.creation-work-card__swipe-button--danger'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
container.querySelector('.creation-work-card-shell--actions-visible'),
|
||||
).toBeTruthy();
|
||||
@@ -615,7 +617,7 @@ test('creation hub reveals persisted draft delete action from left swipe', () =>
|
||||
|
||||
test('creation hub reveals persisted draft delete action from keyboard', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
const { container } = render(
|
||||
<CustomWorldCreationHub
|
||||
items={[{ ...baseDraftItem, profileId: 'profile-1' }]}
|
||||
loading={false}
|
||||
@@ -633,7 +635,9 @@ test('creation hub reveals persisted draft delete action from keyboard', async (
|
||||
screen.getByRole('button', { name: /继续完善《潮雾列岛》/u }).focus();
|
||||
await user.keyboard('{ArrowLeft}');
|
||||
|
||||
expect(screen.getByRole('button', { name: '删除' })).toBeTruthy();
|
||||
expect(
|
||||
container.querySelector('.creation-work-card__swipe-button--danger'),
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByRole('button', { name: '分享' })).toBeNull();
|
||||
});
|
||||
|
||||
@@ -642,7 +646,7 @@ test('creation hub shows delete action for baby object match drafts', async () =
|
||||
const onDeleteBabyObjectMatch = vi.fn();
|
||||
const onOpenBabyObjectMatchDetail = vi.fn();
|
||||
|
||||
render(
|
||||
const { container } = render(
|
||||
<CustomWorldCreationHub
|
||||
items={[]}
|
||||
babyObjectMatchItems={[babyObjectMatchDraftItem]}
|
||||
@@ -662,7 +666,11 @@ test('creation hub shows delete action for baby object match drafts', async () =
|
||||
screen.getByRole('button', { name: /继续创作《宝贝识物删除测试》/u }).focus();
|
||||
await user.keyboard('{ArrowLeft}');
|
||||
|
||||
await user.click(screen.getByRole('button', { name: '删除' }));
|
||||
await user.click(
|
||||
container.querySelector(
|
||||
'.creation-work-card__swipe-button--danger',
|
||||
) as HTMLButtonElement,
|
||||
);
|
||||
|
||||
expect(onDeleteBabyObjectMatch).toHaveBeenCalledWith(
|
||||
babyObjectMatchDraftItem,
|
||||
@@ -711,7 +719,7 @@ test('creation hub works-only tab filters bark battle draft and published works'
|
||||
expect(onOpenBarkBattleDetail).toHaveBeenCalledWith(barkBattlePublishedItem);
|
||||
});
|
||||
|
||||
test('creation hub published work delete action is revealed without opening card', async () => {
|
||||
test('creation hub published work delete action is directly visible', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onDeletePuzzle = vi.fn();
|
||||
const onOpenPuzzleDetail = vi.fn();
|
||||
@@ -751,12 +759,6 @@ test('creation hub published work delete action is revealed without opening card
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.queryByRole('button', { name: '删除' })).toBeNull();
|
||||
expect(screen.getByRole('button', { name: '分享' })).toBeTruthy();
|
||||
|
||||
screen.getByRole('button', { name: /查看详情《待删拼图》/u }).focus();
|
||||
await user.keyboard('{ArrowLeft}');
|
||||
|
||||
expect(screen.getByRole('button', { name: '删除' })).toBeTruthy();
|
||||
expect(screen.getByRole('button', { name: '分享' })).toBeTruthy();
|
||||
|
||||
@@ -768,6 +770,115 @@ test('creation hub published work delete action is revealed without opening card
|
||||
expect(onOpenPuzzleDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('creation hub exposes work delete action directly on card', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onDeletePuzzle = vi.fn();
|
||||
const onOpenPuzzleDetail = vi.fn();
|
||||
|
||||
render(
|
||||
<CustomWorldCreationHub
|
||||
items={[]}
|
||||
puzzleItems={[
|
||||
{
|
||||
workId: 'puzzle:direct-delete',
|
||||
profileId: 'puzzle-profile-direct-delete',
|
||||
ownerUserId: 'user-1',
|
||||
authorDisplayName: '拼图作者',
|
||||
levelName: '直接删除拼图',
|
||||
summary: '作品卡片直接开放删除入口。',
|
||||
themeTags: ['灯塔'],
|
||||
coverImageSrc: null,
|
||||
publicationStatus: 'draft',
|
||||
updatedAt: new Date('2026-05-02T12:00:00.000Z').toISOString(),
|
||||
publishedAt: null,
|
||||
playCount: 0,
|
||||
remixCount: 0,
|
||||
likeCount: 0,
|
||||
publishReady: true,
|
||||
},
|
||||
]}
|
||||
loading={false}
|
||||
error={null}
|
||||
onRetry={() => {}}
|
||||
onCreateType={noopCreateType}
|
||||
onOpenDraft={() => {}}
|
||||
onEnterPublished={() => {}}
|
||||
onOpenPuzzleDetail={onOpenPuzzleDetail}
|
||||
onDeletePuzzle={onDeletePuzzle}
|
||||
entryConfig={testEntryConfig}
|
||||
creationTypes={testCreationTypes}
|
||||
/>,
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: '删除' }));
|
||||
|
||||
expect(onDeletePuzzle).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ profileId: 'puzzle-profile-direct-delete' }),
|
||||
);
|
||||
expect(onOpenPuzzleDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('creation hub keeps swipe delete action available', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onDeletePuzzle = vi.fn();
|
||||
const onOpenPuzzleDetail = vi.fn();
|
||||
|
||||
const { container } = render(
|
||||
<CustomWorldCreationHub
|
||||
items={[]}
|
||||
puzzleItems={[
|
||||
{
|
||||
workId: 'puzzle:swipe-delete',
|
||||
profileId: 'puzzle-profile-swipe-delete',
|
||||
ownerUserId: 'user-1',
|
||||
authorDisplayName: '拼图作者',
|
||||
levelName: '左滑删除拼图',
|
||||
summary: '左滑仍然保留辅助删除入口。',
|
||||
themeTags: ['灯塔'],
|
||||
coverImageSrc: null,
|
||||
publicationStatus: 'published',
|
||||
updatedAt: new Date('2026-05-02T12:00:00.000Z').toISOString(),
|
||||
publishedAt: new Date('2026-05-02T12:10:00.000Z').toISOString(),
|
||||
playCount: 8,
|
||||
remixCount: 2,
|
||||
likeCount: 1,
|
||||
publishReady: true,
|
||||
},
|
||||
]}
|
||||
loading={false}
|
||||
error={null}
|
||||
onRetry={() => {}}
|
||||
onCreateType={noopCreateType}
|
||||
onOpenDraft={() => {}}
|
||||
onEnterPublished={() => {}}
|
||||
onOpenPuzzleDetail={onOpenPuzzleDetail}
|
||||
onDeletePuzzle={onDeletePuzzle}
|
||||
entryConfig={testEntryConfig}
|
||||
creationTypes={testCreationTypes}
|
||||
/>,
|
||||
);
|
||||
|
||||
const card = screen.getByRole('button', { name: /查看详情《左滑删除拼图》/u });
|
||||
fireEvent.touchStart(card, {
|
||||
touches: [{ clientX: 180, clientY: 20 }],
|
||||
});
|
||||
fireEvent.touchMove(card, {
|
||||
touches: [{ clientX: 80, clientY: 22 }],
|
||||
});
|
||||
fireEvent.touchEnd(card);
|
||||
|
||||
const swipeDeleteButton = container.querySelector(
|
||||
'.creation-work-card__swipe-button--danger',
|
||||
) as HTMLButtonElement | null;
|
||||
expect(swipeDeleteButton).toBeTruthy();
|
||||
await user.click(swipeDeleteButton!);
|
||||
|
||||
expect(onDeletePuzzle).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ profileId: 'puzzle-profile-swipe-delete' }),
|
||||
);
|
||||
expect(onOpenPuzzleDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('creation hub opens persisted rpg drafts by card click', async () => {
|
||||
const user = userEvent.setup();
|
||||
const openedItems: CustomWorldWorkSummary[] = [];
|
||||
@@ -942,7 +1053,7 @@ test('creation hub left swipe draft reveals delete without opening card', () =>
|
||||
const onDeletePublished = vi.fn();
|
||||
const onOpenDraft = vi.fn();
|
||||
|
||||
render(
|
||||
const { container } = render(
|
||||
<CustomWorldCreationHub
|
||||
items={[{ ...baseDraftItem, profileId: 'profile-1' }]}
|
||||
loading={false}
|
||||
@@ -966,6 +1077,8 @@ test('creation hub left swipe draft reveals delete without opening card', () =>
|
||||
});
|
||||
fireEvent.touchEnd(card);
|
||||
|
||||
expect(screen.getByRole('button', { name: '删除' })).toBeTruthy();
|
||||
expect(
|
||||
container.querySelector('.creation-work-card__swipe-button--danger'),
|
||||
).toBeTruthy();
|
||||
expect(onOpenDraft).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -676,43 +676,75 @@ export function CustomWorldWorkCard({
|
||||
{displayTitle}
|
||||
</span>
|
||||
</div>
|
||||
{canUseShareAction ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
suppressOpenRef.current = false;
|
||||
closeSwipeActions();
|
||||
copyShareText();
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onPointerDown={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onTouchStart={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
title={
|
||||
shareState === 'copied'
|
||||
? '已复制'
|
||||
: shareState === 'failed'
|
||||
? '复制失败'
|
||||
: '分享作品'
|
||||
}
|
||||
aria-label={
|
||||
shareState === 'copied'
|
||||
? '分享内容已复制'
|
||||
: shareState === 'failed'
|
||||
? '分享内容复制失败'
|
||||
: '分享'
|
||||
}
|
||||
className="creation-work-card__share-button"
|
||||
>
|
||||
<Share2 aria-hidden="true" className="h-4 w-4" />
|
||||
</button>
|
||||
) : null}
|
||||
<div className="creation-work-card__quick-actions">
|
||||
{canUseShareAction ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
suppressOpenRef.current = false;
|
||||
closeSwipeActions();
|
||||
copyShareText();
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onPointerDown={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onTouchStart={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
title={
|
||||
shareState === 'copied'
|
||||
? '已复制'
|
||||
: shareState === 'failed'
|
||||
? '复制失败'
|
||||
: '分享作品'
|
||||
}
|
||||
aria-label={
|
||||
shareState === 'copied'
|
||||
? '分享内容已复制'
|
||||
: shareState === 'failed'
|
||||
? '分享内容复制失败'
|
||||
: '分享'
|
||||
}
|
||||
className="creation-work-card__quick-action-button"
|
||||
>
|
||||
<Share2 aria-hidden="true" className="h-4 w-4" />
|
||||
</button>
|
||||
) : null}
|
||||
{onDelete ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
suppressOpenRef.current = false;
|
||||
closeSwipeActions();
|
||||
onDelete();
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onPointerDown={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onTouchStart={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
disabled={deleteBusy}
|
||||
title={deleteBusy ? '删除中' : '删除作品'}
|
||||
aria-label={deleteBusy ? '删除中' : '删除'}
|
||||
className="creation-work-card__quick-action-button creation-work-card__quick-action-button--danger"
|
||||
>
|
||||
{deleteBusy ? (
|
||||
<span className="text-xs leading-none">...</span>
|
||||
) : (
|
||||
<Trash2 aria-hidden="true" className="h-4 w-4" />
|
||||
)}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="creation-work-card__meta platform-category-game-item__meta">
|
||||
|
||||
@@ -2044,7 +2044,14 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.creation-work-card__share-button {
|
||||
.creation-work-card__quick-actions {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
.creation-work-card__quick-action-button {
|
||||
display: inline-flex;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
@@ -2061,17 +2068,32 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock {
|
||||
transform 160ms ease;
|
||||
}
|
||||
|
||||
.creation-work-card__share-button:hover {
|
||||
.creation-work-card__quick-action-button:hover {
|
||||
transform: translateY(-1px);
|
||||
background: color-mix(in srgb, var(--platform-cool-bg) 24%, transparent);
|
||||
color: var(--platform-cool-text);
|
||||
}
|
||||
|
||||
.creation-work-card__share-button:focus-visible {
|
||||
.creation-work-card__quick-action-button:focus-visible {
|
||||
outline: 2px solid var(--platform-cool-border);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.creation-work-card__quick-action-button--danger {
|
||||
color: color-mix(in srgb, #c7653d 78%, var(--platform-text-soft));
|
||||
}
|
||||
|
||||
.creation-work-card__quick-action-button--danger:hover {
|
||||
background: color-mix(in srgb, #c7653d 18%, transparent);
|
||||
color: #a9472c;
|
||||
}
|
||||
|
||||
.creation-work-card__quick-action-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.62;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.creation-work-card__meta {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
|
||||
Reference in New Issue
Block a user