From bf659a993a5bf7f85d77be4133d829fa985d7046 Mon Sep 17 00:00:00 2001 From: Vitomir Budimir Date: Wed, 18 Dec 2024 17:11:56 +0100 Subject: [PATCH 1/6] feat(editor-ui): onboarding welcome modal and hook --- packages/editor/src/core/editor.tsx | 4 + .../welcome-modal/use-welcome-modal.ts | 36 ++++++ .../welcome-modal/welcome-modal-button.tsx | 20 ++++ .../editor-ui/welcome-modal/welcome-modal.tsx | 105 ++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 packages/editor/src/editor-ui/welcome-modal/use-welcome-modal.ts create mode 100644 packages/editor/src/editor-ui/welcome-modal/welcome-modal-button.tsx create mode 100644 packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx diff --git a/packages/editor/src/core/editor.tsx b/packages/editor/src/core/editor.tsx index 01c4711e35..66c54fbf39 100644 --- a/packages/editor/src/core/editor.tsx +++ b/packages/editor/src/core/editor.tsx @@ -4,6 +4,8 @@ import { debouncedStoreToLocalStorage, getStateFromLocalStorage, } from '@editor/editor-ui/save/local-storage-notice' +import { useWelcomeModal } from '@editor/editor-ui/welcome-modal/use-welcome-modal' +import { WelcomeModal } from '@editor/editor-ui/welcome-modal/welcome-modal' import { getEditorVersion } from '@editor/package/editor-version' import { cn } from '@editor/utils/cn' import { useState, useMemo } from 'react' @@ -23,6 +25,7 @@ import { useIsSerlo } from './hooks/use-is-serlo' export function Editor(props: EditorProps) { const isSerlo = useIsSerlo() const [useStored, setUseStored] = useState(false) + const welcomeModalProps = useWelcomeModal() const storedState = getStateFromLocalStorage() const initialState = @@ -52,6 +55,7 @@ export function Editor(props: EditorProps) { {/* For non serlo environments, we need to render the toaster (already gets rendered in the web project) */} {!isSerlo ? : null} +
{ + const [isOpen, setIsOpen] = useState(false) + + useEffect(() => { + const localStorageValue = localStorage.getItem(localStorageKey) + if (localStorageValue === null) return setIsOpen(true) + const hasSeenModal = decodeWelcomeModalData(localStorageValue) + if (!hasSeenModal) setIsOpen(true) + }, []) + + const handleClose = () => { + setIsOpen(false) + localStorage.setItem(localStorageKey, 'true') + } + + return { isOpen, onClose: handleClose } +} + +const WelcomeModalDataCodec = t.boolean + +function decodeWelcomeModalData(input: string) { + return pipe( + WelcomeModalDataCodec.decode(JSON.parse(input)), + fold( + () => false, + (decoded) => decoded + ) + ) +} diff --git a/packages/editor/src/editor-ui/welcome-modal/welcome-modal-button.tsx b/packages/editor/src/editor-ui/welcome-modal/welcome-modal-button.tsx new file mode 100644 index 0000000000..a409d4e329 --- /dev/null +++ b/packages/editor/src/editor-ui/welcome-modal/welcome-modal-button.tsx @@ -0,0 +1,20 @@ +import { cn } from '@editor/utils/cn' + +interface WelcomeModalButtonProps { + isActive: boolean + onClick: () => void +} + +export function WelcomeModalButton(props: WelcomeModalButtonProps) { + const { isActive, onClick } = props + + return ( + +
+ + ) +} + +const steps = [1, 2, 3] + +const slideWidth = 700 + +const slideProps = { + style: { width: slideWidth }, + className: 'px-4', +} + +const translateXValuesMap: Record = { + 1: '0', + 2: `-${slideWidth}px`, + 3: `-${slideWidth * 2}px`, +} From 811e6e32df8be4a0af1672e714cba458499c1da5 Mon Sep 17 00:00:00 2001 From: Vitomir Budimir Date: Wed, 18 Dec 2024 17:17:06 +0100 Subject: [PATCH 2/6] refactor(editor-ui): simplify welcome modal --- packages/editor/src/core/editor.tsx | 4 +--- .../editor/src/editor-ui/welcome-modal/welcome-modal.tsx | 9 +++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/editor/src/core/editor.tsx b/packages/editor/src/core/editor.tsx index 66c54fbf39..6ce042dca3 100644 --- a/packages/editor/src/core/editor.tsx +++ b/packages/editor/src/core/editor.tsx @@ -4,7 +4,6 @@ import { debouncedStoreToLocalStorage, getStateFromLocalStorage, } from '@editor/editor-ui/save/local-storage-notice' -import { useWelcomeModal } from '@editor/editor-ui/welcome-modal/use-welcome-modal' import { WelcomeModal } from '@editor/editor-ui/welcome-modal/welcome-modal' import { getEditorVersion } from '@editor/package/editor-version' import { cn } from '@editor/utils/cn' @@ -25,7 +24,6 @@ import { useIsSerlo } from './hooks/use-is-serlo' export function Editor(props: EditorProps) { const isSerlo = useIsSerlo() const [useStored, setUseStored] = useState(false) - const welcomeModalProps = useWelcomeModal() const storedState = getStateFromLocalStorage() const initialState = @@ -55,7 +53,7 @@ export function Editor(props: EditorProps) { {/* For non serlo environments, we need to render the toaster (already gets rendered in the web project) */} {!isSerlo ? : null} - +
void -} - -export function WelcomeModal({ isOpen, onClose }: WelcomeModalProps) { +export function WelcomeModal() { + const { isOpen, onClose } = useWelcomeModal() const [currentStep, setCurrentStep] = useState(1) function handleNextButtonClick() { From 68bf9a4117721cda3996663d8874ddd9a42e303e Mon Sep 17 00:00:00 2001 From: Vitomir Budimir Date: Thu, 19 Dec 2024 10:31:34 +0100 Subject: [PATCH 3/6] feat(editor-ui): add welcome modal video and text content --- .../editor-ui/welcome-modal/welcome-modal.tsx | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx b/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx index 99834103e7..c2736d4e6a 100644 --- a/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx +++ b/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx @@ -1,4 +1,5 @@ import { EditorModal } from '@editor/editor-ui/editor-modal' +import { faCircleQuestion } from '@fortawesome/free-regular-svg-icons' import { faArrowCircleRight } from '@fortawesome/free-solid-svg-icons' import { useState } from 'react' @@ -17,27 +18,16 @@ export function WelcomeModal() { }) } - // TODO: Placeholder strings until final strings are provided - const welcomeModalStrings = { - title: 'Welcome', - firstStepText: - "What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.", - thirdStepText: - "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).", - nextButton: 'Next', - nextButtonLastStep: "Let's go!", - } - return ( !isOpen && onClose()} > -
+

- {welcomeModalStrings.title}{' '} - Serlo Editor + Herzlich Willkommen!
+ beim Serlo Editor

-

{welcomeModalStrings.firstStepText}

-
- -
-

Video

+

+ Der Serlo Editor hilft Dir,{' '} + Texte, Bilder und interaktive Aufgaben + direkt zu bearbeiten und sofort sehen, wie sie später aussehen. +

+

+ So kannst Du Lernmaterialien einfach erstellen,{' '} + ohne technische Vorkenntnisse zu benötigen. +

-

{welcomeModalStrings.thirdStepText}

+
+ +
+

+ Weitere Erklärungen und Videos findest du jeweils in der + Toolbar der einzelnen Plugins. Einfach auf das{' '} + klicken. +

@@ -76,9 +82,7 @@ export function WelcomeModal() { className="serlo-button-learner-primary" onClick={handleNextButtonClick} > - {currentStep === 3 - ? welcomeModalStrings.nextButtonLastStep - : welcomeModalStrings.nextButton}{' '} + {currentStep === steps.length ? "Los geht's!" : 'Weiter'}{' '}
@@ -86,9 +90,9 @@ export function WelcomeModal() { ) } -const steps = [1, 2, 3] +const steps = [1, 2] -const slideWidth = 700 +const slideWidth = 600 const slideProps = { style: { width: slideWidth }, @@ -98,5 +102,4 @@ const slideProps = { const translateXValuesMap: Record = { 1: '0', 2: `-${slideWidth}px`, - 3: `-${slideWidth * 2}px`, } From b5cf14b2dcce31df48ca7debedaa409a5a67c1ad Mon Sep 17 00:00:00 2001 From: Vitomir Budimir Date: Thu, 19 Dec 2024 10:34:19 +0100 Subject: [PATCH 4/6] fix(editor-ui): welcome modal align padding --- packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx b/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx index c2736d4e6a..d6d2a015ac 100644 --- a/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx +++ b/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx @@ -68,7 +68,7 @@ export function WelcomeModal() {
-
+
{steps.map((step) => ( Date: Thu, 19 Dec 2024 12:18:15 +0100 Subject: [PATCH 5/6] fix(editor-ui): welcome modal text changes --- .../editor/src/editor-ui/welcome-modal/welcome-modal.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx b/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx index d6d2a015ac..27479fc903 100644 --- a/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx +++ b/packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx @@ -41,8 +41,8 @@ export function WelcomeModal() {

Der Serlo Editor hilft Dir,{' '} - Texte, Bilder und interaktive Aufgaben - direkt zu bearbeiten und sofort sehen, wie sie später aussehen. + Texte, Bilder und interaktive Aufgaben direkt zu bearbeiten + und sofort sehen, wie sie später aussehen.

So kannst Du Lernmaterialien einfach erstellen,{' '} @@ -62,7 +62,8 @@ export function WelcomeModal() {

Weitere Erklärungen und Videos findest du jeweils in der Toolbar der einzelnen Plugins. Einfach auf das{' '} - klicken. + +  -Symbol klicken.

From 41a5acc7b6fad58914dd0c848850e0e324405c33 Mon Sep 17 00:00:00 2001 From: Vitomir Budimir Date: Thu, 19 Dec 2024 12:32:48 +0100 Subject: [PATCH 6/6] fix(editor-ui): welcome modal localStorage key naming convention --- .../editor/src/editor-ui/welcome-modal/use-welcome-modal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/editor-ui/welcome-modal/use-welcome-modal.ts b/packages/editor/src/editor-ui/welcome-modal/use-welcome-modal.ts index 5fbb1da8ff..b7ce5445c6 100644 --- a/packages/editor/src/editor-ui/welcome-modal/use-welcome-modal.ts +++ b/packages/editor/src/editor-ui/welcome-modal/use-welcome-modal.ts @@ -3,7 +3,7 @@ import { pipe } from 'fp-ts/lib/function' import * as t from 'io-ts' import { useEffect, useState } from 'react' -const localStorageKey = 'hasUserSeenWelcomeModal' +const localStorageKey = 'serlo-editor::hasUserSeenWelcomeModal' export const useWelcomeModal = () => { const [isOpen, setIsOpen] = useState(false)