feat: 教程卡片价值区用法示例——MemphisCard 增 zoneText(静置态相框过程文字),components 页第 4 卡演示荧光标记;E2E 加用法断言

This commit is contained in:
cqh963852 committed 2026-10-06 15:39:20 +08:00
1 parent cd49408083
commit 1dfbb0940d
4 files changed
+39 -3

No files matched your search

+15
View File
@@ -68,6 +68,21 @@ test.describe('CourseCard 规格契约', () => {
recipes.forEach((r) => expect(r.split('rgb(17, 17, 17)').length - 1).toBe(1)) // 每卡只出一份阴影
})
test('价值区标记用法卡:相框静置态过程文字带荧光 Mark', async ({ page }) => {
const m = await page.evaluate(() => {
const card = document.querySelector('a[href="#ch4"]')
const mark = card?.querySelector('mark')
if (!card || !mark) return null
const cs = getComputedStyle(mark)
return { bg: cs.backgroundColor, rot: cs.rotate, inZone: !!card.querySelector('.aspect-video mark'), txt: mark.textContent }
})
expect(m).not.toBeNull()
expect(m!.inZone).toBeTruthy() // 标记骑在相框内的过程文字上
expect(m!.bg).toBe('rgb(255, 217, 61)') // 荧光笔 mustard
expect(m!.rot).toContain('deg')
expect(m!.txt).toContain('咬合')
})
test('16:9 相框:比例、3px 黑边、内阴影、章节撞色', async ({ page }) => {
const zone = page.locator('a[href="#ch1"] .aspect-video').first()
const s = await zone.evaluate((el) => {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 155 KiB

+16 -2
View File
@@ -2,7 +2,7 @@
* 卡头三件套=靶子:▲目标 + ○预期结果(16:9 相框) + ●积木点列
* 交互:hover/聚焦拿起(浮起+投影加深)并播放 GIF;desc ⇄ GIF 每 8000ms 翻转;
* hover/Tab 锁定;触屏与 prefers-reduced-motion 不翻转。 */
import { useEffect, useRef, useState } from 'react'
import { useEffect, useRef, useState, type ReactNode } from 'react'
import type { Chapter } from '../lib/types'
import { Ring, Tri } from './shapes'
@@ -33,7 +33,18 @@ export function EntryBadge({ n }: { n: 1 | 2 | 3 }) {
)
}
export function MemphisCard({ chapter, entry, compact = false }: { chapter: Chapter; entry?: 1 | 2 | 3; compact?: boolean }) {
export function MemphisCard({
chapter,
entry,
compact = false,
zoneText,
}: {
chapter: Chapter
entry?: 1 | 2 | 3
compact?: boolean
/** 静置态相框文字(可含 <Mark> 荧光标记):教程卡片的价值区用法示例 */
zoneText?: ReactNode
}) {
const [gifOn, setGifOn] = useState(false)
const [locked, setLocked] = useState(false)
const boxRef = useRef<HTMLAnchorElement>(null)
@@ -100,6 +111,9 @@ export function MemphisCard({ chapter, entry, compact = false }: { chapter: Chap
<span className="px-3 text-center text-[11px] leading-snug text-ink/80 mix-blend-multiply">
{chapter.target.goal}
</span>
) : zoneText ? (
/* 静置态(用法示例):过程文字骑在相框里,价值区短语带荧光标记 */
<span className="px-3 text-center text-[11.5px] font-semibold leading-snug text-ink">{zoneText}</span>
) : (
/* 静置态:章节 emoji 是相框的视觉主体(对齐设计稿解剖卡) */
<span style={{ fontSize: compact ? '28px' : '40px' }}>{chapter.emoji}</span>
+8 -1
View File
@@ -3,6 +3,7 @@ import { ASSIGNMENT, CHAPTERS } from '../../lib/chapters'
import { MemphisCard } from '../../components/MemphisCard'
import { AssignBlock, Ticket } from '../../components/Ticket'
import { EntryGuide } from '../../components/EntryGuide'
import { Mark } from '../../components/shapes'
export function App() {
return (
@@ -11,11 +12,17 @@ export function App() {
title="组件 · 入口载体与状态"
desc="CourseCard(入口)· 票券(状态)· 指派块+脱靶标记(任务与警示)· 入口画像。线条的形式规格见 02 符号形状,与卡片的实际组合见 04 样例。"
>
<Section label="CourseCard" note="卡头三件套=靶子;hover 拿起播放 GIF,8000ms 翻转">
<Section label="CourseCard" note="卡头三件套=靶子;hover 拿起播放 GIF,8000ms 翻转;末张=价值区标记用法">
<div className="flex flex-wrap items-start gap-8">
<div className="w-[280px]"><MemphisCard chapter={CHAPTERS[1]} entry={1} /></div>
<div className="w-[280px]"><MemphisCard chapter={CHAPTERS[2]} entry={2} /></div>
<div className="w-[160px]"><MemphisCard chapter={CHAPTERS[5]} compact /></div>
<div className="w-[280px]">
<MemphisCard
chapter={CHAPTERS[4]}
zoneText={<>这一步过程就地写清:<Mark>环境与依赖如何咬合</Mark></>}
/>
</div>
</div>
</Section>
<Section label="票券 & 指派学习块" note="票=完成状态;块=位置/预期/场景+脱靶标记">