-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(editor-ui): onboarding welcome modal and hook #4363
Open
hejtful
wants to merge
6
commits into
staging
Choose a base branch
from
feat/onboarding-welcome-modal
base: staging
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
bf659a9
feat(editor-ui): onboarding welcome modal and hook
hejtful 811e6e3
refactor(editor-ui): simplify welcome modal
hejtful 68bf9a4
feat(editor-ui): add welcome modal video and text content
hejtful b5cf14b
fix(editor-ui): welcome modal align padding
hejtful bea854d
fix(editor-ui): welcome modal text changes
hejtful 41a5acc
fix(editor-ui): welcome modal localStorage key naming convention
hejtful File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
packages/editor/src/editor-ui/welcome-modal/use-welcome-modal.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { fold } from 'fp-ts/lib/Either' | ||
import { pipe } from 'fp-ts/lib/function' | ||
import * as t from 'io-ts' | ||
import { useEffect, useState } from 'react' | ||
|
||
const localStorageKey = 'serlo-editor::hasUserSeenWelcomeModal' | ||
|
||
export const useWelcomeModal = () => { | ||
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 | ||
) | ||
) | ||
} |
20 changes: 20 additions & 0 deletions
20
packages/editor/src/editor-ui/welcome-modal/welcome-modal-button.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<button | ||
className={cn( | ||
'h-4 w-4 rounded-full transition-all', | ||
isActive ? 'w-8 bg-brand-600' : 'border-2 border-brand-600' | ||
)} | ||
onClick={onClick} | ||
/> | ||
) | ||
} |
106 changes: 106 additions & 0 deletions
106
packages/editor/src/editor-ui/welcome-modal/welcome-modal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
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' | ||
|
||
import { FaIcon } from '../fa-icon' | ||
import { useWelcomeModal } from './use-welcome-modal' | ||
import { WelcomeModalButton } from './welcome-modal-button' | ||
|
||
export function WelcomeModal() { | ||
const { isOpen, onClose } = useWelcomeModal() | ||
const [currentStep, setCurrentStep] = useState(1) | ||
|
||
function handleNextButtonClick() { | ||
setCurrentStep((previousValue) => { | ||
if (previousValue < steps.length) return previousValue + 1 | ||
return onClose() ?? 1 | ||
}) | ||
} | ||
|
||
return ( | ||
<EditorModal | ||
// width should match slideWidth const | ||
className="top-1/2 flex w-[600px] max-w-[95%] flex-col gap-16 px-0 pt-20" | ||
extraTitleClassName="sr-only" | ||
title="Herzlich Willkommen beim Serlo Editor" | ||
isOpen={isOpen} | ||
setIsOpen={(isOpen) => !isOpen && onClose()} | ||
> | ||
<div className="flex h-[400px] overflow-hidden"> | ||
<div | ||
className="flex items-center transition-transform" | ||
style={{ | ||
transform: `translateX(${translateXValuesMap[currentStep]})`, | ||
}} | ||
> | ||
<div {...slideProps}> | ||
<h1 className="serlo-h1"> | ||
Herzlich Willkommen! <br /> | ||
<span className="text-brand-600">beim Serlo Editor</span> | ||
</h1> | ||
<p className="serlo-p"> | ||
Der Serlo Editor hilft Dir,{' '} | ||
<b>Texte, Bilder und interaktive Aufgaben</b> direkt zu bearbeiten | ||
und sofort sehen, wie sie später aussehen. | ||
</p> | ||
<p className="serlo-p"> | ||
So kannst Du Lernmaterialien <b>einfach</b> erstellen,{' '} | ||
<b>ohne technische Vorkenntnisse</b> zu benötigen. | ||
</p> | ||
</div> | ||
|
||
<div {...slideProps}> | ||
<div className="px-4"> | ||
<video controls> | ||
<source | ||
src="https://storage.googleapis.com/assets.serlo.org/wikimedia/Der_Menstruationszyklus.webm" | ||
type="video/webm" | ||
/> | ||
</video> | ||
</div> | ||
<p className="serlo-p mb-0 mt-4"> | ||
Weitere <b>Erklärungen und Videos</b> findest du jeweils in der | ||
Toolbar der einzelnen Plugins. Einfach auf das{' '} | ||
<FaIcon icon={faCircleQuestion} /> | ||
 -Symbol klicken. | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div className="flex items-center justify-between px-8"> | ||
<div className="flex items-center gap-1"> | ||
{steps.map((step) => ( | ||
<WelcomeModalButton | ||
key={step} | ||
isActive={step === currentStep} | ||
onClick={() => setCurrentStep(step)} | ||
/> | ||
))} | ||
</div> | ||
<button | ||
className="serlo-button-learner-primary" | ||
onClick={handleNextButtonClick} | ||
> | ||
{currentStep === steps.length ? "Los geht's!" : 'Weiter'}{' '} | ||
<FaIcon icon={faArrowCircleRight} /> | ||
</button> | ||
</div> | ||
</EditorModal> | ||
) | ||
} | ||
|
||
const steps = [1, 2] | ||
|
||
const slideWidth = 600 | ||
|
||
const slideProps = { | ||
style: { width: slideWidth }, | ||
className: 'px-4', | ||
} | ||
|
||
const translateXValuesMap: Record<number, string> = { | ||
hejtful marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1: '0', | ||
2: `-${slideWidth}px`, | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't reuse the preferences:
Could we simplify this by just checking if the key exists?
That way we wouldn't need any type checks and parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but I like the idea of decoding any value coming from
localStorage
, think it's a good practice.Also, if we later want to expand on this in any way, for example using logged-in user ID to check if a specific user has seen the modal, in case of shared school devices, we can easily expand the codec.
Don't get me wrong, if you implemented it by just checking if the key exists, I wouldn't mind it. But since we already have this code, I wouldn't remove it.