1
1
import { useCallback , useContext } from 'react'
2
2
import { useTheme } from 'next-themes'
3
3
import Link from 'next/link'
4
- import { ResumeIcon } from '@radix-ui/react-icons'
5
- import {
6
- LucideChevronLeft ,
7
- LucideChevronRight ,
8
- LucideFiles ,
9
- LucidePause ,
10
- LucidePlay ,
11
- } from 'lucide-react'
4
+ import { ReplPayload } from '@jsrepl/shared-types'
5
+ import { LucideFiles , LucidePlay , LucideRewind , LucideRotateCw } from 'lucide-react'
12
6
import { LucideEye , LucideMoon , LucidePalette , LucideShare2 , LucideSun } from 'lucide-react'
13
- import IconPause from '~icons/mdi/pause.jsx'
14
7
import IconGithub from '~icons/simple-icons/github.jsx'
15
8
import Logo from '@/components/logo'
16
9
import ShareRepl from '@/components/share-repl'
@@ -25,72 +18,35 @@ import {
25
18
DropdownMenuTrigger ,
26
19
} from '@/components/ui/dropdown-menu'
27
20
import { Tooltip , TooltipContent , TooltipTrigger } from '@/components/ui/tooltip'
28
- import { ReplHistoryModeContext } from '@/context/repl-history-mode-context'
29
21
import { ReplPayloadsContext } from '@/context/repl-payloads-context'
30
- import { ReplStateContext } from '@/context/repl-state -context'
22
+ import { ReplRewindModeContext } from '@/context/repl-rewind-mode -context'
31
23
import { UserStateContext } from '@/context/user-state-context'
24
+ import { useReplPreviewShown } from '@/hooks/useReplPreviewShown'
32
25
import { Themes } from '@/lib/themes'
33
26
import { cn } from '@/lib/utils'
34
27
35
28
export default function ActivityBar ( ) {
36
29
const { resolvedTheme : themeId , setTheme } = useTheme ( )
37
- const { replState, setReplState } = useContext ( ReplStateContext ) !
38
30
const { userState, setUserState } = useContext ( UserStateContext ) !
39
- const { historyMode , setHistoryMode } = useContext ( ReplHistoryModeContext ) !
31
+ const { rewindMode , setRewindMode } = useContext ( ReplRewindModeContext ) !
40
32
const { payloads } = useContext ( ReplPayloadsContext ) !
41
-
42
- const startRepl = useCallback ( ( ) => {
43
- window . dispatchEvent ( new Event ( 'jsrepl-start-repl' ) )
44
- } , [ ] )
45
-
46
- const toggleHistoryMode = useCallback ( ( ) => {
47
- const lastPayload = payloads [ payloads . length - 1 ]
48
- if ( ! lastPayload ) {
49
- return
50
- }
51
-
52
- setHistoryMode ( ( prev ) => ( { ...prev , currentPayloadId : lastPayload . id } ) )
53
- } , [ payloads , setHistoryMode ] )
54
-
55
- const historyModeGoPrev = useCallback ( ( ) => {
56
- if ( ! historyMode ) {
57
- return
58
- }
59
-
60
- const currentIndex = payloads . findIndex (
61
- ( payload ) => payload . id === historyMode . currentPayloadId
62
- )
63
- if ( currentIndex === - 1 ) {
64
- return
65
- }
66
-
67
- const prevPayload = payloads [ currentIndex - 1 ]
68
- if ( ! prevPayload ) {
69
- return
70
- }
71
-
72
- setHistoryMode ( ( prev ) => ( { ...prev , currentPayloadId : prevPayload . id } ) )
73
- } , [ payloads , setHistoryMode , historyMode ] )
74
-
75
- const historyModeGoNext = useCallback ( ( ) => {
76
- if ( ! historyMode ) {
77
- return
78
- }
79
-
80
- const currentIndex = payloads . findIndex (
81
- ( payload ) => payload . id === historyMode . currentPayloadId
82
- )
83
- if ( currentIndex === - 1 ) {
84
- return
85
- }
86
-
87
- const nextPayload = payloads [ currentIndex + 1 ]
88
- if ( ! nextPayload ) {
89
- return
90
- }
91
-
92
- setHistoryMode ( ( prev ) => ( { ...prev , currentPayloadId : nextPayload . id } ) )
93
- } , [ payloads , setHistoryMode , historyMode ] )
33
+ const { previewEnabled, previewShown, setPreviewShown } = useReplPreviewShown ( )
34
+
35
+ const restartRepl = useCallback ( ( ) => {
36
+ setRewindMode ( ( prev ) => ( { ...prev , active : false , currentPayloadId : null } ) )
37
+ window . dispatchEvent ( new Event ( 'jsrepl-restart-repl' ) )
38
+ } , [ setRewindMode ] )
39
+
40
+ const toggleRewindMode = useCallback ( ( ) => {
41
+ setRewindMode ( ( prev ) => {
42
+ if ( prev . active ) {
43
+ return { ...prev , active : false , currentPayloadId : null }
44
+ } else {
45
+ const lastPayload : ReplPayload | undefined = payloads [ payloads . length - 1 ]
46
+ return { ...prev , active : true , currentPayloadId : lastPayload ? lastPayload . id : null }
47
+ }
48
+ } )
49
+ } , [ payloads , setRewindMode ] )
94
50
95
51
return (
96
52
< div className = "bg-activityBar flex flex-col gap-2 px-1 pb-2 pt-1 [grid-area:activity-bar]" >
@@ -135,9 +91,10 @@ export default function ActivityBar() {
135
91
variant = "ghost"
136
92
className = { cn (
137
93
'text-activityBar-foreground' ,
138
- replState . showPreview && 'bg-accent border-activityBar-foreground/30 border'
94
+ previewShown && 'bg-accent border-activityBar-foreground/30 border'
139
95
) }
140
- onClick = { ( ) => setReplState ( ( prev ) => ( { ...prev , showPreview : ! prev . showPreview } ) ) }
96
+ disabled = { ! previewEnabled }
97
+ onClick = { ( ) => setPreviewShown ( ( prev ) => ! prev ) }
141
98
>
142
99
< LucideEye size = { 20 } />
143
100
</ Button >
@@ -155,21 +112,22 @@ export default function ActivityBar() {
155
112
size = "icon"
156
113
variant = "ghost"
157
114
className = "text-activityBar-foreground"
158
- onClick = { startRepl }
115
+ onClick = { restartRepl }
159
116
>
160
117
< div className = "relative" >
161
- < LucidePlay size = { 20 } />
162
- { ! userState . autostartOnCodeChange && (
163
- < IconPause width = { 10 } height = { 10 } className = "absolute -bottom-1 -right-0.5" />
118
+ { userState . autostartOnCodeChange ? (
119
+ < LucideRotateCw size = { 18 } />
120
+ ) : (
121
+ < LucidePlay size = { 19 } />
164
122
) }
165
123
</ div >
166
124
</ Button >
167
125
</ TooltipTrigger >
168
126
< TooltipContent side = "right" sideOffset = { 8 } align = "start" >
169
- Start / Restart REPL
127
+ { userState . autostartOnCodeChange ? ' Restart REPL' : 'Start REPL' }
170
128
< div className = "bg-secondary text-secondary-foreground border-primary -mx-2 -mb-1 mt-1 rounded-b border px-2 py-2" >
171
129
< label className = "flex items-center gap-1" >
172
- < span > Autostart on code change</ span >
130
+ < span > Restart on code change</ span >
173
131
< input
174
132
type = "checkbox"
175
133
defaultChecked = { userState . autostartOnCodeChange }
@@ -182,32 +140,24 @@ export default function ActivityBar() {
182
140
</ TooltipContent >
183
141
</ Tooltip >
184
142
185
- < Button
186
- size = "icon"
187
- variant = "ghost"
188
- className = "text-activityBar-foreground"
189
- onClick = { toggleHistoryMode }
190
- >
191
- { historyMode ? < ResumeIcon width = { 18 } height = { 18 } /> : < LucidePause size = { 18 } /> }
192
- </ Button >
193
-
194
- < Button
195
- size = "icon"
196
- variant = "ghost"
197
- className = "text-activityBar-foreground"
198
- onClick = { historyModeGoPrev }
199
- >
200
- < LucideChevronLeft size = { 18 } />
201
- </ Button >
202
-
203
- < Button
204
- size = "icon"
205
- variant = "ghost"
206
- className = "text-activityBar-foreground"
207
- onClick = { historyModeGoNext }
208
- >
209
- < LucideChevronRight size = { 18 } />
210
- </ Button >
143
+ < Tooltip >
144
+ < TooltipTrigger asChild >
145
+ < Button
146
+ size = "icon"
147
+ variant = "ghost"
148
+ className = { cn (
149
+ 'text-activityBar-foreground' ,
150
+ rewindMode . active && 'bg-accent border-activityBar-foreground/30 border'
151
+ ) }
152
+ onClick = { toggleRewindMode }
153
+ >
154
+ < LucideRewind size = { 18 } />
155
+ </ Button >
156
+ </ TooltipTrigger >
157
+ < TooltipContent side = "right" sideOffset = { 8 } >
158
+ Rewind mode
159
+ </ TooltipContent >
160
+ </ Tooltip >
211
161
212
162
< div className = "flex-1" />
213
163
@@ -259,7 +209,7 @@ export default function ActivityBar() {
259
209
260
210
< DropdownMenuContent className = "w-96" side = "left" align = "end" >
261
211
< DropdownMenuLabel className = "text-foreground/80 text-sm font-normal" >
262
- < ShareRepl setReplState = { setReplState } />
212
+ < ShareRepl />
263
213
</ DropdownMenuLabel >
264
214
</ DropdownMenuContent >
265
215
</ DropdownMenu >
0 commit comments