Prune stale docs and update .hermes content
Delete a large set of outdated documentation (many files under docs/ and .hermes/plans/, including audits, design, prd, technical, planning, assets, and todos). Update and consolidate .hermes content: refresh shared-memory pages (decision-log, development-workflow, document-map, pitfalls, project-overview, team-conventions) and several skills/references under .hermes/skills. Also modify AGENTS.md, README.md, UI_CODING_STANDARD.md, docs/README.md and .encoding-check-ignore. Purpose: clean up stale planning/audit material and keep current hermes documentation and related top-level docs in sync.
This commit is contained in:
@@ -929,7 +929,7 @@ test('拼图运行态主体使用主题语义类承接明暗主题', () => {
|
||||
expect(container.querySelector('.puzzle-runtime-pill')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('合并块按实际拼块外轮廓描边', () => {
|
||||
test('合并块不叠加可见轮廓和单块阴影', () => {
|
||||
const mergedRun: PuzzleRunSnapshot = {
|
||||
...clearedRun,
|
||||
currentLevel: {
|
||||
@@ -976,22 +976,16 @@ test('合并块按实际拼块外轮廓描边', () => {
|
||||
expect(container.querySelector('.ring-2.ring-emerald-100\\/58')).toBeNull();
|
||||
expect(
|
||||
container.querySelector('[data-merged-group-outline="true"]'),
|
||||
).toBeTruthy();
|
||||
).toBeNull();
|
||||
const outlineStroke = container.querySelector(
|
||||
'[data-merged-group-outline-stroke="true"]',
|
||||
);
|
||||
expect(outlineStroke).toBeTruthy();
|
||||
expect(outlineStroke?.getAttribute('d')).toContain('Q 2 1 1.84 1');
|
||||
expect(outlineStroke?.getAttribute('d')).toContain('Q 1 1 1 1.16');
|
||||
expect(
|
||||
container
|
||||
.querySelector('[data-merged-group-outline="true"]')
|
||||
?.getAttribute('fill'),
|
||||
).toBe('transparent');
|
||||
expect(outlineStroke).toBeNull();
|
||||
expect((outlinedPieces[0] as HTMLElement).style.clipPath).toBe('');
|
||||
for (const outlinedPiece of outlinedPieces) {
|
||||
const outlinedPieceElement = outlinedPiece as HTMLElement;
|
||||
expect(outlinedPieceElement.className).not.toContain('bg-emerald-300/10');
|
||||
expect(outlinedPieceElement.className).not.toContain('shadow-[');
|
||||
expect(
|
||||
outlinedPieceElement.querySelector('.absolute.inset-0.bg-black\\/8'),
|
||||
).toBeNull();
|
||||
@@ -999,7 +993,7 @@ test('合并块按实际拼块外轮廓描边', () => {
|
||||
const clippedLayer = container.querySelector(
|
||||
'[style*="clip-path"]',
|
||||
) as HTMLElement | null;
|
||||
expect(clippedLayer?.style.clipPath).toContain('url(#');
|
||||
expect(clippedLayer).toBeNull();
|
||||
});
|
||||
|
||||
test('合并块轮廓路径为内凹角生成圆角曲线', () => {
|
||||
@@ -1026,7 +1020,7 @@ test('合并块轮廓路径为内凹角生成圆角曲线', () => {
|
||||
expect(outlinePath).toContain('Q 1 1 1 1.16');
|
||||
});
|
||||
|
||||
test('基础单块使用圆角裁剪图片', () => {
|
||||
test('基础单块不叠加边框圆角或图片蒙版', () => {
|
||||
const playingRun: PuzzleRunSnapshot = {
|
||||
...clearedRun,
|
||||
currentLevel: {
|
||||
@@ -1055,7 +1049,9 @@ test('基础单块使用圆角裁剪图片', () => {
|
||||
'[data-piece-id="piece-0"]',
|
||||
) as HTMLElement | null;
|
||||
expect(basePiece?.className).toContain('overflow-hidden');
|
||||
expect(basePiece?.className).toContain('rounded-[0.85rem]');
|
||||
expect(basePiece?.className).toContain('border-0');
|
||||
expect(basePiece?.className).not.toContain('rounded-[0.85rem]');
|
||||
expect(basePiece?.className).not.toContain('border-2');
|
||||
expect(basePiece?.querySelector('.puzzle-runtime-piece-overlay')).toBeNull();
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
Sparkles,
|
||||
Trophy,
|
||||
} from 'lucide-react';
|
||||
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import type {
|
||||
DragPuzzlePieceRequest,
|
||||
@@ -23,7 +23,6 @@ import type {
|
||||
SwapPuzzlePiecesRequest,
|
||||
} from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
|
||||
import { useResolvedAssetReadUrl } from '../../hooks/useResolvedAssetReadUrl';
|
||||
import { resolvePuzzleUiBackgroundSource } from '../../services/puzzle-runtime/puzzleUiBackgroundSource';
|
||||
import {
|
||||
createRuntimeDragInputController,
|
||||
createRuntimeInputPointFromClient,
|
||||
@@ -32,6 +31,7 @@ import {
|
||||
type RuntimeDragInputSession,
|
||||
type RuntimeInputPoint,
|
||||
} from '../../services/input-devices';
|
||||
import { resolvePuzzleUiBackgroundSource } from '../../services/puzzle-runtime/puzzleUiBackgroundSource';
|
||||
import {
|
||||
DEFAULT_RUNTIME_LEVEL_AUDIO_CONFIG,
|
||||
playRuntimeClickSound,
|
||||
@@ -44,12 +44,9 @@ import { useAuthUi } from '../auth/AuthUiContext';
|
||||
import { PixelIcon } from '../PixelIcon';
|
||||
import { ResolvedAssetImage } from '../ResolvedAssetImage';
|
||||
import {
|
||||
buildMergedGroupClipPath,
|
||||
buildMergedGroupOutlinePath,
|
||||
resolveDraggedMergedGroupLayer,
|
||||
resolveDraggedPieceCellLayer,
|
||||
resolveDraggedPieceLayer,
|
||||
sanitizeSvgId,
|
||||
} from './puzzleRuntimeShape';
|
||||
|
||||
type PuzzleRuntimeShellProps = {
|
||||
@@ -344,7 +341,6 @@ export function PuzzleRuntimeShell({
|
||||
onUseProp,
|
||||
onTimeExpired,
|
||||
}: PuzzleRuntimeShellProps) {
|
||||
const mergedGroupSvgIdPrefix = sanitizeSvgId(useId());
|
||||
const authUi = useAuthUi();
|
||||
const [selectedPieceId, setSelectedPieceId] = useState<string | null>(null);
|
||||
const selectedPieceIdRef = useRef<string | null>(null);
|
||||
@@ -1376,7 +1372,7 @@ export function PuzzleRuntimeShell({
|
||||
pieceElementRefMap.current.delete(piece.pieceId);
|
||||
}}
|
||||
data-piece-id={piece?.pieceId ?? undefined}
|
||||
className={`puzzle-runtime-piece relative flex h-full items-center justify-center overflow-hidden rounded-[0.85rem] border-2 text-sm font-black transition ${
|
||||
className={`puzzle-runtime-piece relative flex h-full items-center justify-center overflow-hidden border-0 text-sm font-black transition ${
|
||||
occupied
|
||||
? isSelected
|
||||
? 'puzzle-runtime-piece--selected'
|
||||
@@ -1386,8 +1382,8 @@ export function PuzzleRuntimeShell({
|
||||
: 'puzzle-runtime-piece--empty'
|
||||
} ${
|
||||
isMerged
|
||||
? 'transition-colors'
|
||||
: 'transition-[background-color,border-color,box-shadow,opacity]'
|
||||
? 'transition-opacity'
|
||||
: 'transition-[opacity,transform]'
|
||||
}`}
|
||||
style={{
|
||||
zIndex: resolveDraggedPieceLayer(
|
||||
@@ -1451,9 +1447,6 @@ export function PuzzleRuntimeShell({
|
||||
);
|
||||
})}
|
||||
{mergedGroups.map((group) => {
|
||||
const outlinePath = buildMergedGroupOutlinePath(group);
|
||||
const clipPath = buildMergedGroupClipPath(group);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={group.groupId}
|
||||
@@ -1487,57 +1480,9 @@ export function PuzzleRuntimeShell({
|
||||
height: `${(group.rowSpan / board.rows) * 100}%`,
|
||||
}}
|
||||
>
|
||||
{outlinePath ? (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute inset-0 z-20 h-full w-full overflow-visible"
|
||||
preserveAspectRatio="none"
|
||||
viewBox={`0 0 ${group.colSpan} ${group.rowSpan}`}
|
||||
>
|
||||
<defs>
|
||||
<clipPath
|
||||
clipPathUnits="objectBoundingBox"
|
||||
id={`${mergedGroupSvgIdPrefix}-${sanitizeSvgId(
|
||||
group.groupId,
|
||||
)}`}
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d={clipPath}
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<path
|
||||
d={outlinePath}
|
||||
data-merged-group-outline="true"
|
||||
fill="transparent"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
<path
|
||||
d={outlinePath}
|
||||
data-merged-group-outline-stroke="true"
|
||||
fill="none"
|
||||
stroke="rgba(255, 255, 255, 0.22)"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
/>
|
||||
</svg>
|
||||
) : null}
|
||||
<div
|
||||
className="pointer-events-none relative z-10 grid h-full w-full touch-none overflow-hidden active:scale-[0.992]"
|
||||
style={{
|
||||
WebkitClipPath: outlinePath
|
||||
? `url(#${mergedGroupSvgIdPrefix}-${sanitizeSvgId(
|
||||
group.groupId,
|
||||
)})`
|
||||
: undefined,
|
||||
clipPath: outlinePath
|
||||
? `url(#${mergedGroupSvgIdPrefix}-${sanitizeSvgId(
|
||||
group.groupId,
|
||||
)})`
|
||||
: undefined,
|
||||
gridTemplateColumns: `repeat(${group.colSpan}, minmax(0, 1fr))`,
|
||||
gridTemplateRows: `repeat(${group.rowSpan}, minmax(0, 1fr))`,
|
||||
}}
|
||||
@@ -1545,7 +1490,7 @@ export function PuzzleRuntimeShell({
|
||||
{group.pieces.map((piece) => (
|
||||
<div
|
||||
key={piece.pieceId}
|
||||
className="pointer-events-auto relative touch-none overflow-hidden shadow-[0_12px_30px_rgba(15,23,42,0.16)]"
|
||||
className="pointer-events-auto relative touch-none overflow-hidden"
|
||||
data-merged-piece-outline="true"
|
||||
style={{
|
||||
gridColumn: piece.localCol + 1,
|
||||
|
||||
Reference in New Issue
Block a user