diff --git a/client/src/components/Tours/ski/skiMarks.test.tsx b/client/src/components/Tours/ski/skiMarks.test.tsx index 2dec2b266..02e9bb768 100644 --- a/client/src/components/Tours/ski/skiMarks.test.tsx +++ b/client/src/components/Tours/ski/skiMarks.test.tsx @@ -2,9 +2,17 @@ import { render, screen } from '@testing-library/react'; import { describe, expect, it } from 'vitest'; import { TourDayRowAvatar } from '../TourDayRowFacts'; import { TourGradeTile } from '../tourParts'; -import { SkiCornerMark, SkiHeadPill, skiClassificationText, skiDisciplineOf, skiTechniqueOf } from './skiMarks'; +import { WINTER_ACTIVITY_ICON } from '../winter/winterMarks'; +import { + SKI_DISCIPLINE_ICON, + SkiCornerMark, + SkiHeadPill, + skiClassificationText, + skiDisciplineOf, + skiTechniqueOf, +} from './skiMarks'; -// FE-TOUR-SKI-MARK-001 to FE-TOUR-SKI-MARK-005 +// FE-TOUR-SKI-MARK-001 to FE-TOUR-SKI-MARK-006 const t = (key: string) => key; const skiTrack = { @@ -39,6 +47,8 @@ describe('ski marks (SKI-02)', () => { const mark = screen.getByRole('img', { name: 'tours.ski.discipline.snowboard' }); expect(mark).toHaveAttribute('data-testid', 'tour-ski-mark'); expect(mark).toHaveStyle({ width: '20px', height: '20px' }); + expect(mark.querySelector('svg.lucide-snowboard')).not.toBeNull(); + expect(mark.querySelector('svg.lucide-snowflake')).toBeNull(); }); it('FE-TOUR-SKI-MARK-003: the head pill names the discipline with a cross-country technique inside it', () => { @@ -68,4 +78,9 @@ describe('ski marks (SKI-02)', () => { rerender(); expect(screen.getByTestId('tour-ski-mark')).toHaveStyle({ width: '22px' }); }); + + it('FE-TOUR-SKI-MARK-006: no discipline shares its corner glyph with another, nor with a winter label', () => { + const icons = [...Object.values(SKI_DISCIPLINE_ICON), ...Object.values(WINTER_ACTIVITY_ICON)]; + expect(new Set(icons).size).toBe(icons.length); + }); }); diff --git a/client/src/components/Tours/ski/skiMarks.tsx b/client/src/components/Tours/ski/skiMarks.tsx index 5e3a38ddd..fcec7511c 100644 --- a/client/src/components/Tours/ski/skiMarks.tsx +++ b/client/src/components/Tours/ski/skiMarks.tsx @@ -1,18 +1,32 @@ import type { SkiDiscipline, SkiTechnique, TourListItem } from '@trek/shared'; -import { CableCar, Snowflake, Spline, TrendingUp, type LucideIcon } from 'lucide-react'; +import { CableCar, createLucideIcon, Spline, TrendingUp, type LucideIcon } from 'lucide-react'; import { useTranslation } from '../../../i18n'; import { fs } from '../../shared/DialogShell'; import { Tooltip } from '../../shared/Tooltip'; import { TourCornerMark } from '../TourCornerMark'; /** - * SKI-02: the icon each discipline goes by: a lift for alpine skiing, a - * snowflake for the board, a winding trail for cross-country and the climb on - * skins for ski touring. + * SKI-02: a snowboard seen from above, laid across the square with its two + * bindings. Lucide has no board, and the snowflake is the winter hike's mark + * (HIK-01): both sit in the same corner badge, so the board needs a glyph of + * its own to be told apart there. + */ +const BOARD = 'rotate(-45 12 12)'; +const Snowboard = createLucideIcon('snowboard', [ + ['rect', { x: '1.5', y: '8.5', width: '21', height: '7', rx: '3.5', transform: BOARD, key: 'board' }], + ['path', { d: 'M8.5 10v4', transform: BOARD, key: 'binding-front' }], + ['path', { d: 'M15.5 10v4', transform: BOARD, key: 'binding-back' }], +]); + +/** + * SKI-02: the icon each discipline goes by: a lift for alpine skiing, a board + * for snowboarding, a winding trail for cross-country and the climb on skins + * for ski touring. None of them is the winter hike's snowflake, which takes + * the same corner of a tile. */ export const SKI_DISCIPLINE_ICON: Record = { alpine: CableCar, - snowboard: Snowflake, + snowboard: Snowboard, cross_country: Spline, touring: TrendingUp, };