diff options
| author | Maze <167211895+mazeincoding@users.noreply.github.com> | 2026-01-31 00:20:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-31 00:20:04 +0100 |
| commit | 7bf0984698e43b9aa2dd879f65951318ed410390 (patch) | |
| tree | ccf2cd590a47d550152afc07129cb55c71a9ec35 /apps/web/src/components/editor/onboarding.tsx | |
| parent | 0173db99448d1c4c6415dcf15272e17551b48b04 (diff) | |
| download | opencut-7bf0984698e43b9aa2dd879f65951318ed410390.tar.gz | |
codebase overhaul (#697)
Diffstat (limited to 'apps/web/src/components/editor/onboarding.tsx')
| -rw-r--r-- | apps/web/src/components/editor/onboarding.tsx | 227 |
1 files changed, 113 insertions, 114 deletions
diff --git a/apps/web/src/components/editor/onboarding.tsx b/apps/web/src/components/editor/onboarding.tsx index 8ee60690..c60c2de5 100644 --- a/apps/web/src/components/editor/onboarding.tsx +++ b/apps/web/src/components/editor/onboarding.tsx @@ -1,138 +1,137 @@ "use client"; -import { Dialog, DialogContent, DialogTitle } from "../ui/dialog"; -import { Button } from "../ui/button"; import { ArrowRightIcon } from "lucide-react"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import ReactMarkdown from "react-markdown"; +import { SOCIAL_LINKS } from "@/constants/site-constants"; +import { useLocalStorage } from "@/hooks/storage/use-local-storage"; +import { Button } from "../ui/button"; +import { Dialog, DialogBody, DialogContent, DialogTitle } from "../ui/dialog"; export function Onboarding() { - const [step, setStep] = useState(0); - const [isOpen, setIsOpen] = useState(false); + const [step, setStep] = useState(0); + const [hasSeenOnboarding, setHasSeenOnboarding] = useLocalStorage({ + key: "hasSeenOnboarding", + defaultValue: false, + }); - useEffect(() => { - const hasSeenOnboarding = localStorage.getItem("hasSeenOnboarding"); - if (!hasSeenOnboarding) { - setIsOpen(true); - } - }, []); + const isOpen = !hasSeenOnboarding; - const handleNext = () => { - setStep(step + 1); - }; + const handleNext = () => { + setStep(step + 1); + }; - const handleClose = () => { - setIsOpen(false); - localStorage.setItem("hasSeenOnboarding", "true"); - }; + const handleClose = () => { + setHasSeenOnboarding({ value: true }); + }; - const getStepTitle = () => { - switch (step) { - case 0: - return "Welcome to OpenCut Beta! 🎉"; - case 1: - return "⚠️ This is a super early beta!"; - case 2: - return "🦋 Have fun testing!"; - default: - return "OpenCut Onboarding"; - } - }; + const getStepTitle = () => { + switch (step) { + case 0: + return "Welcome to OpenCut Beta! 🎉"; + case 1: + return "⚠️ This is a super early beta!"; + case 2: + return "🦋 Have fun testing!"; + default: + return "OpenCut Onboarding"; + } + }; - const renderStepContent = () => { - switch (step) { - case 0: - return ( - <div className="space-y-5"> - <div className="space-y-3"> - <Title title="Welcome to OpenCut Beta! 🎉" /> - <Description description="You're among the first to try OpenCut - the fully open source CapCut alternative." /> - </div> - <NextButton onClick={handleNext}>Next</NextButton> - </div> - ); - case 1: - return ( - <div className="space-y-5"> - <div className="space-y-3"> - <Title title={getStepTitle()} /> - <Description description="OpenCut started just one month ago. There's still a ton of things to do to make this editor amazing." /> - <Description description="A lot of features are still missing, like the export functionality. We're working hard to build them out!" /> - <Description description="If you're curious, check out our roadmap [here](https://opencut.app/roadmap)" /> - </div> - <NextButton onClick={handleNext}>Next</NextButton> - </div> - ); - case 2: - return ( - <div className="space-y-5"> - <div className="space-y-3"> - <Title title={getStepTitle()} /> - <Description description="Join our [Discord](https://discord.gg/zmR9N35cjK), chat with cool people and share feedback to help make OpenCut the best editor ever." /> - </div> - <NextButton onClick={handleClose}>Finish</NextButton> - </div> - ); - default: - return null; - } - }; + const renderStepContent = () => { + switch (step) { + case 0: + return ( + <div className="space-y-5"> + <div className="space-y-3"> + <Title title="Welcome to OpenCut Beta! 🎉" /> + <Description description="You're among the first to try OpenCut - the fully open source CapCut alternative." /> + </div> + <NextButton onClick={handleNext}>Next</NextButton> + </div> + ); + case 1: + return ( + <div className="space-y-5"> + <div className="space-y-3"> + <Title title={getStepTitle()} /> + <Description description="OpenCut started just one month ago. There's still a ton of things to do to make this editor amazing." /> + <Description description="A lot of features are still missing, like the export functionality. We're working hard to build them out!" /> + <Description description="If you're curious, check out our roadmap [here](https://opencut.app/roadmap)" /> + </div> + <NextButton onClick={handleNext}>Next</NextButton> + </div> + ); + case 2: + return ( + <div className="space-y-5"> + <div className="space-y-3"> + <Title title={getStepTitle()} /> + <Description + description={`Join our [Discord](${SOCIAL_LINKS.discord}), chat with cool people and share feedback to help make OpenCut the best editor ever.`} + /> + </div> + <NextButton onClick={handleClose}>Finish</NextButton> + </div> + ); + default: + return null; + } + }; - return ( - <Dialog open={isOpen} onOpenChange={handleClose}> - <DialogContent className="sm:max-w-[425px] !outline-none pt-2"> - <DialogTitle> - <span className="sr-only">{getStepTitle()}</span> - </DialogTitle> - {renderStepContent()} - </DialogContent> - </Dialog> - ); + return ( + <Dialog open={isOpen} onOpenChange={handleClose}> + <DialogContent className="sm:max-w-[425px]"> + <DialogTitle> + <span className="sr-only">{getStepTitle()}</span> + </DialogTitle> + <DialogBody> + {renderStepContent()} + </DialogBody> + </DialogContent> + </Dialog> + ); } function Title({ title }: { title: string }) { - return <h2 className="text-lg md:text-xl font-bold">{title}</h2>; -} - -function Subtitle({ subtitle }: { subtitle: string }) { - return <h3 className="text-lg font-medium">{subtitle}</h3>; + return <h2 className="text-lg font-bold md:text-xl">{title}</h2>; } function Description({ description }: { description: string }) { - return ( - <div className="text-muted-foreground"> - <ReactMarkdown - components={{ - p: ({ children }) => <p className="mb-0">{children}</p>, - a: ({ href, children }) => ( - <a - href={href} - target="_blank" - rel="noopener noreferrer" - className="text-foreground hover:text-foreground/80 underline" - > - {children} - </a> - ), - }} - > - {description} - </ReactMarkdown> - </div> - ); + return ( + <div className="text-muted-foreground"> + <ReactMarkdown + components={{ + p: ({ children }) => <p className="mb-0">{children}</p>, + a: ({ href, children }) => ( + <a + href={href} + target="_blank" + rel="noopener noreferrer" + className="text-foreground hover:text-foreground/80 underline" + > + {children} + </a> + ), + }} + > + {description} + </ReactMarkdown> + </div> + ); } function NextButton({ - children, - onClick, + children, + onClick, }: { - children: React.ReactNode; - onClick: () => void; + children: React.ReactNode; + onClick: () => void; }) { - return ( - <Button onClick={onClick} variant="default" className="w-full"> - {children} - <ArrowRightIcon className="w-4 h-4" /> - </Button> - ); + return ( + <Button onClick={onClick} variant="default" className="w-full"> + {children} + <ArrowRightIcon className="size-4" /> + </Button> + ); } |
