From d5ed46f9555fd8b775075cb2f33bc936c95c760e Mon Sep 17 00:00:00 2001 From: dem4ron Date: Wed, 22 Jan 2025 13:16:52 +0100 Subject: [PATCH 01/10] Add context, use editorView, fix scrolling to line on drawing page --- .../bootcamp/DrawingPage/DrawingPage.tsx | 64 ++++++++++--------- .../SolveExercisePage/Scrubber/useScrubber.ts | 2 +- .../SolveExercisePageContextWrapper.tsx | 7 +- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx index 0a865f86b5..22786a52c6 100644 --- a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx +++ b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx @@ -11,6 +11,7 @@ import { useLocalStorage } from '@uidotdev/usehooks' import Scrubber from '../SolveExercisePage/Scrubber/Scrubber' import { debounce } from 'lodash' import { useSetupDrawingPage } from './useSetupDrawingPage' +import SolveExercisePageContextWrapper from '../SolveExercisePage/SolveExercisePageContextWrapper' export default function DrawingPage({ drawing, @@ -27,9 +28,8 @@ export default function DrawingPage({ } = useResizablePanels({ initialSize: 800, direction: 'horizontal', - localStorageId: 'drawing-page-lhs', + localStorageId: 'solve-exercise-page-lhs', }) - const { handleRunCode, handleEditorDidMount, @@ -62,35 +62,41 @@ export default function DrawingPage({ }, [setEditorLocalStorageValue]) return ( -
-
-
-
- - - - -
- - {/* RHS */} -
-
+ +
+
+
+
+ + + + +
+ + {/* RHS */} +
+
+
-
+
) } diff --git a/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/useScrubber.ts b/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/useScrubber.ts index 82173f1a49..60eae31eba 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/useScrubber.ts +++ b/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/useScrubber.ts @@ -140,7 +140,7 @@ export function useScrubber({ scrollToLine(editorView, highlightedLine) } }, - [setValue, setInformationWidgetData] + [setValue, setInformationWidgetData, editorView] ) const handleMouseDown = useCallback( diff --git a/app/javascript/components/bootcamp/SolveExercisePage/SolveExercisePageContextWrapper.tsx b/app/javascript/components/bootcamp/SolveExercisePage/SolveExercisePageContextWrapper.tsx index f68223857f..d6aa4661cb 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/SolveExercisePageContextWrapper.tsx +++ b/app/javascript/components/bootcamp/SolveExercisePage/SolveExercisePageContextWrapper.tsx @@ -3,10 +3,9 @@ import React from 'react' import { createContext } from 'react' -type SolveExercisePageContextValues = Pick< - SolveExercisePageProps, - 'links' | 'solution' | 'exercise' | 'code' -> & { resetEditorToStub: () => void; editorView: EditorView | null } +type SolveExercisePageContextValues = Partial< + Pick +> & { resetEditorToStub?: () => void; editorView: EditorView | null } export const SolveExercisePageContext = createContext({ From 0e69a36b09127c7b06afc69b78395957c60f4823 Mon Sep 17 00:00:00 2001 From: dem4ron Date: Wed, 22 Jan 2025 16:46:54 +0100 Subject: [PATCH 02/10] Add better autorun value holding storage + store entry --- .../bootcamp/DrawingPage/DrawingPage.tsx | 33 +++++++++++++++- .../DrawingPage/useSetupDrawingPage.ts | 11 ++++-- .../SolveExercisePage/Scrubber/Scrubber.tsx | 2 +- .../SolveExercisePage/store/editorStore.ts | 39 +++++++++++++++---- 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx index 22786a52c6..d802c42aca 100644 --- a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx +++ b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { Header, StudentCodeGetter } from './Header/Header' import { Resizer, @@ -12,6 +12,8 @@ import Scrubber from '../SolveExercisePage/Scrubber/Scrubber' import { debounce } from 'lodash' import { useSetupDrawingPage } from './useSetupDrawingPage' import SolveExercisePageContextWrapper from '../SolveExercisePage/SolveExercisePageContextWrapper' +import useEditorStore from '../SolveExercisePage/store/editorStore' +import { assembleClassNames } from '@/utils/assemble-classnames' export default function DrawingPage({ drawing, @@ -61,6 +63,14 @@ export default function DrawingPage({ }, 5000) }, [setEditorLocalStorageValue]) + const { shouldAutoRunCode, toggleShouldAutoRunCode } = useEditorStore() + const handleToggleAutoRun = useCallback(() => { + if (!shouldAutoRunCode) { + handleRunCode() + } + toggleShouldAutoRunCode() + }, [shouldAutoRunCode]) + return ( - + +
+
+ + +
+ +
diff --git a/app/javascript/components/bootcamp/DrawingPage/useSetupDrawingPage.ts b/app/javascript/components/bootcamp/DrawingPage/useSetupDrawingPage.ts index 1ffe2d3e93..8196b25535 100644 --- a/app/javascript/components/bootcamp/DrawingPage/useSetupDrawingPage.ts +++ b/app/javascript/components/bootcamp/DrawingPage/useSetupDrawingPage.ts @@ -6,10 +6,16 @@ export function useSetupDrawingPage({ setEditorLocalStorageValue, code, }) { - const { setDefaultCode, setShouldAutoRunCode } = useEditorStore() + const { setDefaultCode, setActiveEditor, setShouldAutoRunCode } = + useEditorStore() // Setup hook useEffect(() => { + setActiveEditor('drawing') + const storedShouldAutoRunCode = localStorage.getItem( + 'drawing-should-autorun-code' + ) + setShouldAutoRunCode(storedShouldAutoRunCode === 'true') if ( editorLocalStorageValue.storedAt && code.storedAt && @@ -22,6 +28,5 @@ export function useSetupDrawingPage({ // otherwise we are using the code from the storage setDefaultCode(editorLocalStorageValue.code) } - setShouldAutoRunCode(true) - }, [code, setDefaultCode, setEditorLocalStorageValue]) + }, []) } diff --git a/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/Scrubber.tsx b/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/Scrubber.tsx index c637d1edea..82fa865d21 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/Scrubber.tsx +++ b/app/javascript/components/bootcamp/SolveExercisePage/Scrubber/Scrubber.tsx @@ -45,7 +45,7 @@ function Scrubber({ rangeRef.current?.focus() }} tabIndex={-1} - className="relative group" + className="relative group grow" > {animationTimeline && ( void defaultCode: string setDefaultCode: (defaultCode: string) => void shouldAutoRunCode: boolean @@ -32,18 +34,40 @@ type EditorStore = { setReadonlyRanges: (ranges: Array<{ from: number; to: number }>) => void } -const useEditorStore = createStoreWithMiddlewares( - (set) => ({ +const useEditorStore = createStoreWithMiddlewares((set) => { + return { + activeEditor: null, + setActiveEditor: (activeEditor: 'solve-exercise' | 'drawing') => { + set({ activeEditor }, false, 'editor/setActiveEditor') + }, defaultCode: '', setDefaultCode: (defaultCode: string) => { set({ defaultCode }, false, 'editor/setDefaultCode') }, shouldAutoRunCode: false, - setShouldAutoRunCode: (shouldAutoRunCode) => - set({ shouldAutoRunCode }, false, 'editor/setShouldAutoRunCode'), + setShouldAutoRunCode: (shouldAutoRunCode: boolean) => { + set( + (state) => { + localStorage.setItem( + `${state.activeEditor}-should-autorun-code`, + shouldAutoRunCode.toString() + ) + return { shouldAutoRunCode } + }, + false, + 'editor/setShouldAutoRunCode' + ) + }, toggleShouldAutoRunCode: () => { set( - (state) => ({ shouldAutoRunCode: !state.shouldAutoRunCode }), + (state) => { + const newState = !state.shouldAutoRunCode + localStorage.setItem( + `${state.activeEditor}-should-autorun-code`, + newState.toString() + ) + return { shouldAutoRunCode: newState } + }, false, 'editor/toggleShouldAutoRunCode' ) @@ -111,8 +135,7 @@ const useEditorStore = createStoreWithMiddlewares( setReadonlyRanges: (readonlyRanges) => { set({ readonlyRanges }, false, 'exercise/setReadonlyRanges') }, - }), - 'EditorStore' -) + } +}, 'EditorStore') export default useEditorStore From 04b512768d3909aab569a8d15d3a46d985f07cf1 Mon Sep 17 00:00:00 2001 From: dem4ron Date: Wed, 22 Jan 2025 17:00:01 +0100 Subject: [PATCH 03/10] Adjust handler --- .../bootcamp/DrawingPage/DrawingPage.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx index d802c42aca..4e7fc23a96 100644 --- a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx +++ b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx @@ -64,12 +64,15 @@ export default function DrawingPage({ }, [setEditorLocalStorageValue]) const { shouldAutoRunCode, toggleShouldAutoRunCode } = useEditorStore() - const handleToggleAutoRun = useCallback(() => { - if (!shouldAutoRunCode) { - handleRunCode() - } - toggleShouldAutoRunCode() - }, [shouldAutoRunCode]) + const handleToggleAutoRun = useCallback( + (shouldAutoRunCode: boolean) => { + if (!shouldAutoRunCode) { + handleRunCode() + } + toggleShouldAutoRunCode() + }, + [shouldAutoRunCode] + ) return ( handleToggleAutoRun(shouldAutoRunCode)} > AUTO From c7c12eea8e7daf8006460b89991c71a9eeac4943 Mon Sep 17 00:00:00 2001 From: dem4ron Date: Wed, 22 Jan 2025 17:09:31 +0100 Subject: [PATCH 04/10] Debounce on edit --- .../bootcamp/SolveExercisePage/CodeMirror/CodeMirror.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/CodeMirror.tsx b/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/CodeMirror.tsx index 1aa91e2e22..eb0bd7ebe4 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/CodeMirror.tsx +++ b/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/CodeMirror.tsx @@ -119,6 +119,12 @@ export const CodeMirror = forwardRef(function _CodeMirror( }, 500) }, [setEditorLocalStorageValue, readOnlyRangesStateField]) + const autoRunOnDebounce = useMemo(() => { + return debounce(() => { + handleRunCode() + }, 500) + }, []) + let value = defaultCode const getEditorView = (): EditorView | null => { @@ -207,7 +213,7 @@ export const CodeMirror = forwardRef(function _CodeMirror( () => { const { shouldAutoRunCode } = useEditorStore.getState() if (shouldAutoRunCode) { - handleRunCode() + autoRunOnDebounce() } }, () => { From 45f780078c47de1a2bb7b2976fdac62000bea079 Mon Sep 17 00:00:00 2001 From: dem4ron Date: Wed, 22 Jan 2025 17:30:01 +0100 Subject: [PATCH 05/10] Remove styling from ref element --- .../extensions/end-line-information/information-widget.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/extensions/end-line-information/information-widget.ts b/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/extensions/end-line-information/information-widget.ts index 73f830a418..c536b91845 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/extensions/end-line-information/information-widget.ts +++ b/app/javascript/components/bootcamp/SolveExercisePage/CodeMirror/extensions/end-line-information/information-widget.ts @@ -40,12 +40,6 @@ export class InformationWidget extends WidgetType { private createRefElement() { const refElement = document.createElement('span') - refElement.classList.add('font-bold', 'text-black') - // refElement.style.float = 'right' - refElement.style.position = 'absolute' - refElement.style.right = '0' - refElement.innerText = ' ' - return refElement } From 0e397654e79999f431f09f9dc1759bd607071b6e Mon Sep 17 00:00:00 2001 From: Jeremy Walker Date: Thu, 23 Jan 2025 15:36:21 +0000 Subject: [PATCH 06/10] Style autorun --- .../components/solve-exercise-page.css | 57 +++++++++++++++++++ app/images/bootcamp/autorun.svg | 1 + .../bootcamp/DrawingPage/DrawingPage.tsx | 25 ++++++-- app/views/bootcamp/projects/show.html.haml | 6 +- 4 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 app/images/bootcamp/autorun.svg diff --git a/app/css/bootcamp/components/solve-exercise-page.css b/app/css/bootcamp/components/solve-exercise-page.css index 32fbf2f469..04fb497b14 100644 --- a/app/css/bootcamp/components/solve-exercise-page.css +++ b/app/css/bootcamp/components/solve-exercise-page.css @@ -72,6 +72,63 @@ .btn-primary { @apply bg-bootcamp-purple; } + .autorun-button { + @apply btn-primary btn-s; + @apply flex items-stretch; + @apply p-0; + + box-shadow: 0px 3px 6px rgba(var(--shadowColorMain), 0.4); + + .primary-segment, + .autorun-segment { + transition: background 0.1s ease-in; + } + &:not(:disabled):not(.--disabled):hover { + @apply bg-purple !important; + } + + .primary-segment { + @apply flex items-center; + @apply font-semibold; + @apply px-16; + @apply border-r-1 border-borderColor3; + + &.disabled { + @apply bg-purpleDarkened; + opacity: 0.5; + cursor: not-allowed; + } + + &:not(.disabled) { + &:hover { + @apply !bg-purpleDarkened; + } + } + } + .autorun-segment { + @apply grid place-items-center px-12; + @apply rounded-r-3; + & .c-icon { + height: 18px; + width: 18px; + } + + &:hover { + @apply bg-purpleDarkened; + } + &.on { + @apply bg-purpleDarkened; + & .c-icon { + @apply filter-lightGold; + } + } + &.off { + & .c-icon { + @apply filter-white; + } + } + } + } } body.namespace-bootcamp.controller-exercises.action-edit { diff --git a/app/images/bootcamp/autorun.svg b/app/images/bootcamp/autorun.svg new file mode 100644 index 0000000000..cc7b39722c --- /dev/null +++ b/app/images/bootcamp/autorun.svg @@ -0,0 +1 @@ +Ai Redo Spark Streamline Icon: https://streamlinehq.com \ No newline at end of file diff --git a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx index 4e7fc23a96..76b08914e4 100644 --- a/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx +++ b/app/javascript/components/bootcamp/DrawingPage/DrawingPage.tsx @@ -14,6 +14,7 @@ import { useSetupDrawingPage } from './useSetupDrawingPage' import SolveExercisePageContextWrapper from '../SolveExercisePage/SolveExercisePageContextWrapper' import useEditorStore from '../SolveExercisePage/store/editorStore' import { assembleClassNames } from '@/utils/assemble-classnames' +import { Icon } from '@/components/common' export default function DrawingPage({ drawing, @@ -101,17 +102,29 @@ export default function DrawingPage({ />
-
+
-
Date: Thu, 23 Jan 2025 15:52:14 +0000 Subject: [PATCH 07/10] Tweak styling --- app/images/bootcamp/edit.svg | 1 + .../bootcamp/DrawingPage/Header/Header.tsx | 36 +++++++++++-------- 2 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 app/images/bootcamp/edit.svg diff --git a/app/images/bootcamp/edit.svg b/app/images/bootcamp/edit.svg new file mode 100644 index 0000000000..d13605284c --- /dev/null +++ b/app/images/bootcamp/edit.svg @@ -0,0 +1 @@ +Pencil 2 Streamline Icon: https://streamlinehq.com \ No newline at end of file diff --git a/app/javascript/components/bootcamp/DrawingPage/Header/Header.tsx b/app/javascript/components/bootcamp/DrawingPage/Header/Header.tsx index 61eb6f31a9..7e0f1c9817 100644 --- a/app/javascript/components/bootcamp/DrawingPage/Header/Header.tsx +++ b/app/javascript/components/bootcamp/DrawingPage/Header/Header.tsx @@ -78,6 +78,7 @@ function _Header({ handleBackgroundChange(selectedBackground) }} value={drawing.backgroundSlug} + className="bg-backgroundColorD rounded-5 py-4 px-8 font-medium" > {backgrounds.map((background) => (