feat(ui): give the app one visual identity as Movie Loop
Gold is the primary in both themes, Bricolage Grotesque carries the wordmark, titles and the score, and Movie A / Movie B wear the blue and magenta of three-strip Technicolor on their posters instead of colouring whole rows. The loop closes on screen - connectors light, a gold line draws back to Movie A, the row glows, then the result arrives - in place of confetti, on every play mode, scaled to the chain's length. Every page shares one header and hairline lists; copy is sentence case with one verb per flow, and the Home hero shows a real finished loop. Also clamps link counts at zero: an opponent who had not moved yet showed "-1 links".
This commit is contained in:
1 parent
da32e49b0b
commit
8d0b7f39ee
122 files changed
+3129
-2089
No files matched your search
@@ -1,7 +1,14 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router';
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// The completion modal waits for the loop-closing animation; there is none
|
||||
// to wait for in jsdom, and these tests are about the content, not the delay.
|
||||
vi.mock('@/lib/motion', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('@/lib/motion')>()),
|
||||
prefersReducedMotion: () => true,
|
||||
}));
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useVersusStore } from '@/stores/versus-store';
|
||||
import VersusCompletionModal from './VersusCompletionModal';
|
||||
@@ -57,9 +64,9 @@ describe('VersusCompletionModal', () => {
|
||||
useVersusStore.setState({ myScore: score(1500), lobbyState: 'playing' });
|
||||
renderModal();
|
||||
|
||||
expect(screen.getByRole('dialog', { name: 'You finished!' })).toBeInTheDocument();
|
||||
expect(screen.getByText('1500')).toBeInTheDocument();
|
||||
expect(screen.getByText('Waiting for opponent to finish...')).toBeInTheDocument();
|
||||
expect(screen.getByRole('dialog', { name: 'You finished' })).toBeInTheDocument();
|
||||
expect(screen.getByText('1,500')).toBeInTheDocument();
|
||||
expect(screen.getByText('Waiting for opponent to finish…')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('defaults myTotal to 0 when the score object has no totalScore field', () => {
|
||||
@@ -85,7 +92,7 @@ describe('VersusCompletionModal', () => {
|
||||
useVersusStore.setState({ myScore: score(1500), lobbyState: 'finished', matchResult: null });
|
||||
renderModal();
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Match Complete!')).toBeNull();
|
||||
expect(screen.queryByText('Match complete')).toBeNull();
|
||||
});
|
||||
|
||||
it('declares a tie when the match has no winner', () => {
|
||||
@@ -103,8 +110,8 @@ describe('VersusCompletionModal', () => {
|
||||
});
|
||||
renderModal();
|
||||
|
||||
expect(screen.getByRole('heading', { name: /Match Complete!/ })).toBeInTheDocument();
|
||||
expect(screen.getByText("It's a tie!")).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: /Match complete/ })).toBeInTheDocument();
|
||||
expect(screen.getByText('A tie')).toBeInTheDocument();
|
||||
expect(screen.getByText('Me')).toBeInTheDocument();
|
||||
expect(screen.getByText('Rival')).toBeInTheDocument();
|
||||
});
|
||||
@@ -124,7 +131,7 @@ describe('VersusCompletionModal', () => {
|
||||
});
|
||||
renderModal();
|
||||
|
||||
expect(screen.getByText('You win!')).toBeInTheDocument();
|
||||
expect(screen.getByText('You won')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('declares a loss when the winner is the other player', () => {
|
||||
@@ -142,7 +149,7 @@ describe('VersusCompletionModal', () => {
|
||||
});
|
||||
renderModal();
|
||||
|
||||
expect(screen.getByText('You lose!')).toBeInTheDocument();
|
||||
expect(screen.getByText('You lost')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('defaults a missing player score to 0', () => {
|
||||
|
||||
Reference in new issue
Block a user