Skip to content

Commit 1f59c7e

Browse files
Merge pull request #13 from CSSLab/v1-dev
Add tour tutorials to each page
2 parents a4a5fcc + 0e8ed38 commit 1f59c7e

28 files changed

Lines changed: 1136 additions & 95 deletions

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@types/chroma-js": "^2.1.3",
4242
"@types/node": "17.0.8",
4343
"@types/react": "19.0.8",
44+
"@types/react-dom": "^19.1.6",
4445
"@typescript-eslint/eslint-plugin": "^5.9.1",
4546
"autoprefixer": "^10.4.20",
4647
"babel-loader": "^8.2.3",

src/components/Analysis/AnalysisGameList.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,10 @@ export const AnalysisGameList: React.FC<AnalysisGameListProps> = ({
357357
}
358358

359359
return analysisTournamentList ? (
360-
<div className="flex h-full flex-col items-start justify-start overflow-hidden bg-background-1 md:rounded">
360+
<div
361+
id="analysis-game-list"
362+
className="flex h-full flex-col items-start justify-start overflow-hidden bg-background-1 md:rounded"
363+
>
361364
<div className="flex h-full w-full flex-col">
362365
<div className="grid select-none grid-cols-5 border-b-2 border-white border-opacity-10">
363366
<Header

src/components/Analysis/BlunderMeter.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
6262
}: Props) => {
6363
return (
6464
<div
65+
id="analysis-blunder-meter"
6566
className={`flex h-64 max-h-full w-full flex-col gap-2 overflow-hidden rounded ${showContainer ? 'bg-background-1/60 p-3 md:w-auto md:min-w-[40%] md:max-w-[40%]' : ''} md:h-full`}
6667
>
6768
<p className="text-sm text-primary xl:text-base">Blunder Meter</p>
@@ -116,6 +117,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
116117
}: Props) => {
117118
return (
118119
<div
120+
id="analysis-blunder-meter"
119121
className={`flex w-full flex-col gap-2 overflow-hidden rounded ${showContainer ? 'bg-background-1/60 p-3' : ''}`}
120122
>
121123
<p className="text-sm text-primary xl:text-base">Blunder Meter</p>

src/components/Analysis/Highlight.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ export const Highlight: React.FC<Props> = ({
126126
}, [boardDescription])
127127

128128
return (
129-
<div className="flex h-full w-full flex-col border-white/40 bg-background-1">
129+
<div
130+
id="analysis-highlight"
131+
className="flex h-full w-full flex-col border-white/40 bg-background-1"
132+
>
130133
<div className="grid grid-cols-2 border-b border-white/20">
131134
<div className="flex flex-col items-center justify-start gap-0.5 border-r border-white/20 bg-human-3/5 xl:gap-1">
132135
<div className="relative flex w-full flex-col border-b border-white/5">

src/components/Analysis/MoveMap.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export const MoveMap: React.FC<Props> = ({
170170

171171
return (
172172
<div
173+
id="analysis-move-map"
173174
className="flex h-64 max-h-full w-full flex-col overflow-hidden bg-background-1/60 md:h-full md:rounded"
174175
onMouseLeave={onContainerMouseLeave}
175176
>

src/components/Analysis/MovesByRating.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ export const MovesByRating: React.FC<Props> = ({
3737
const domain = [0, domainMax]
3838

3939
return (
40-
<div className="flex h-64 w-full flex-col md:h-full">
40+
<div
41+
id="analysis-moves-by-rating"
42+
className="flex h-64 w-full flex-col md:h-full"
43+
>
4144
<h2 className="p-3 text-sm text-primary xl:text-base">Moves by Rating</h2>
4245
<ResponsiveContainer width="100%" height="100%">
4346
<AreaChart

src/components/Board/GameplayInterface.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,10 @@ export const GameplayInterface: React.FC<React.PropsWithChildren<Props>> = (
182182
<StatsDisplay stats={stats} hideSession={true} />
183183
</div>
184184
</div>
185-
<div className="relative flex aspect-square w-full max-w-[75vh]">
185+
<div
186+
id="play-page"
187+
className="relative flex aspect-square w-full max-w-[75vh]"
188+
>
186189
<GameBoard
187190
game={game}
188191
availableMoves={availableMovesMapped}

src/components/Misc/GameInfo.tsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useContext } from 'react'
22

3-
import { ModalContext } from 'src/contexts'
3+
import { ModalContext, useTour } from 'src/contexts'
44
import { InstructionsType } from 'src/components'
5+
import { tourConfigs } from 'src/config/tours'
56

67
interface Props {
78
icon: string
@@ -27,6 +28,7 @@ export const GameInfo: React.FC<Props> = ({
2728
onGameListClick,
2829
}: Props) => {
2930
const { setInstructionsModalProps } = useContext(ModalContext)
31+
const { startTour, hasCompletedTour } = useTour()
3032

3133
return (
3234
<div className="flex w-full flex-col items-start justify-start gap-1 overflow-hidden bg-background-1 p-3 md:rounded">
@@ -69,9 +71,30 @@ export const GameInfo: React.FC<Props> = ({
6971
</button>
7072
)}
7173
<button
72-
className="material-symbols-outlined duration-200 hover:text-human-3"
73-
onClick={() => {
74-
setInstructionsModalProps({ instructionsType: type })
74+
type="button"
75+
className="material-symbols-outlined duration-200 hover:text-human-3 focus:outline-none"
76+
onClick={(e) => {
77+
e.preventDefault()
78+
e.stopPropagation()
79+
// Map page types to tour configs
80+
const tourTypeMap: { [key: string]: keyof typeof tourConfigs } = {
81+
againstMaia: 'play',
82+
handAndBrain: 'handBrain',
83+
analysis: 'analysis',
84+
train: 'train',
85+
turing: 'turing',
86+
}
87+
88+
const tourType = tourTypeMap[type]
89+
90+
// Check if page type has a tour configuration
91+
if (tourType && tourConfigs[tourType]) {
92+
const tourConfig = tourConfigs[tourType]
93+
// Force restart the tour even if completed
94+
startTour(tourConfig.id, tourConfig.steps, true)
95+
} else {
96+
setInstructionsModalProps({ instructionsType: type })
97+
}
7598
}}
7699
>
77100
help

src/components/Openings/OpeningSelectionModal.tsx

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
DrillConfiguration,
1010
} from 'src/types'
1111
import { ModalContainer } from '../Misc/ModalContainer'
12+
import { useTour } from 'src/contexts'
13+
import { tourConfigs } from 'src/config/tours'
1214

1315
const MAIA_VERSIONS = [
1416
{ id: 'maia_kdd_1100', name: 'Maia 1100' },
@@ -103,6 +105,7 @@ const BrowsePanel: React.FC<{
103105
setSearchTerm,
104106
}) => (
105107
<div
108+
id="opening-drill-browse"
106109
className={`flex w-full flex-col overflow-y-scroll ${activeTab !== 'browse' ? 'hidden md:flex' : 'flex'} md:border-r md:border-white/10`}
107110
>
108111
<div className="hidden h-20 flex-col justify-center gap-1 border-b border-white/10 p-4 md:flex">
@@ -288,6 +291,7 @@ const PreviewPanel: React.FC<{
288291
isDuplicateSelection,
289292
}) => (
290293
<div
294+
id="opening-drill-preview"
291295
className={`flex w-full flex-col overflow-hidden ${activeTab !== 'preview' ? 'hidden md:flex' : 'flex'}`}
292296
>
293297
<div className="hidden h-20 flex-col justify-center gap-1 border-b border-white/10 p-4 md:flex">
@@ -441,6 +445,7 @@ const SelectedPanel: React.FC<{
441445
handleStartDrilling,
442446
}) => (
443447
<div
448+
id="opening-drill-selected"
444449
className={`flex w-full flex-col overflow-hidden ${activeTab !== 'selected' ? 'hidden md:flex' : 'flex'} md:border-l md:border-white/10`}
445450
>
446451
<div className="hidden h-20 flex-col justify-center gap-1 border-b border-white/10 p-4 md:flex">
@@ -570,6 +575,7 @@ export const OpeningSelectionModal: React.FC<Props> = ({
570575
onComplete,
571576
onClose,
572577
}) => {
578+
const { startTour } = useTour()
573579
const [selections, setSelections] =
574580
useState<OpeningSelection[]>(initialSelections)
575581
const [previewOpening, setPreviewOpening] = useState<Opening>(openings[0])
@@ -583,6 +589,31 @@ export const OpeningSelectionModal: React.FC<Props> = ({
583589
const [drillCount, setDrillCount] = useState(5)
584590
const [searchTerm, setSearchTerm] = useState('')
585591
const [activeTab, setActiveTab] = useState<MobileTab>('browse')
592+
const [initialTourCheck, setInitialTourCheck] = useState(false)
593+
594+
// Check if user has completed the tour on initial load
595+
useEffect(() => {
596+
if (!initialTourCheck) {
597+
setInitialTourCheck(true)
598+
if (typeof window !== 'undefined') {
599+
const completedTours = JSON.parse(
600+
localStorage.getItem('maia-completed-tours') || '[]',
601+
)
602+
603+
if (!completedTours.includes('openingDrill')) {
604+
startTour(
605+
tourConfigs.openingDrill.id,
606+
tourConfigs.openingDrill.steps,
607+
false,
608+
)
609+
}
610+
}
611+
}
612+
}, [initialTourCheck, startTour])
613+
614+
const handleStartTour = () => {
615+
startTour(tourConfigs.openingDrill.id, tourConfigs.openingDrill.steps, true)
616+
}
586617

587618
const previewFen = useMemo(() => {
588619
return previewVariation ? previewVariation.fen : previewOpening.fen
@@ -717,14 +748,32 @@ export const OpeningSelectionModal: React.FC<Props> = ({
717748
</button>
718749

719750
{/* Header Section */}
720-
<div className="flex w-full flex-col gap-1 border-b border-white/10 p-4">
721-
<h1 className="text-xl font-bold text-primary md:text-2xl">
722-
Opening Drills
723-
</h1>
724-
<p className="text-xs text-secondary md:text-sm">
725-
Practice openings against Maia. Select openings to drill, choose
726-
your color and opponent strength.
727-
</p>
751+
<div
752+
id="opening-drill-modal"
753+
className="flex w-full flex-col gap-1 border-b border-white/10 p-4"
754+
>
755+
<div className="flex items-center justify-between">
756+
<div className="flex flex-col gap-1">
757+
<div className="flex flex-row items-center gap-3">
758+
<h1 className="text-xl font-bold text-primary md:text-2xl">
759+
Opening Drills
760+
</h1>
761+
<button
762+
type="button"
763+
className="material-symbols-outlined text-lg text-secondary duration-200 hover:text-human-3 focus:outline-none"
764+
onClick={handleStartTour}
765+
title="Start tour"
766+
>
767+
help
768+
</button>
769+
</div>
770+
771+
<p className="text-xs text-secondary md:text-sm">
772+
Practice openings against Maia. Select openings to drill, choose
773+
your color and opponent strength.
774+
</p>
775+
</div>
776+
</div>
728777
</div>
729778

730779
{/* Mobile Tab Navigation */}

0 commit comments

Comments
 (0)