From 93fc8e107b0e489f137e5092756f2279e8608ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=BCl=C3=B6p=20Kov=C3=A1cs?= <43729152+fulopkovacs@users.noreply.github.com> Date: Sun, 4 Jan 2026 15:59:15 +0100 Subject: [PATCH 1/4] Rename a query param --- src/components/tutorial/TutorialWindow.tsx | 24 ++++++++++++++-------- src/components/tutorial/index.tsx | 4 ++-- src/routes/_tutorial.tsx | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/tutorial/TutorialWindow.tsx b/src/components/tutorial/TutorialWindow.tsx index e243e83..bbcebb6 100644 --- a/src/components/tutorial/TutorialWindow.tsx +++ b/src/components/tutorial/TutorialWindow.tsx @@ -9,7 +9,7 @@ import { useRef, useState, } from "react"; -import { steps } from "@/data/tutorial"; +import { steps as articles } from "@/data/tutorial"; import { useScrollShadow } from "@/hooks/use-scroll-shadow"; import { cn } from "@/lib/utils"; import { @@ -379,7 +379,7 @@ function FloatingWindow({ isResizing ? "contain-strict" : "contain-none", )} > - {steps.map((step) => ( + {articles.map((step) => ( { - if (activeStepFromSearch && typeof activeStepFromSearch === "string") { - const stepInSearch = decodeURIComponent(activeStepFromSearch); - if (steps.find((step) => step.title === stepInSearch)) { - setActiveStep(stepInSearch); + if ( + activeArticleFromSearch && + typeof activeArticleFromSearch === "string" + ) { + const articleInSearch = decodeURIComponent( + activeArticleFromSearch.toLowerCase(), + ); + + if (articles.find((a) => a.title === articleInSearch)) { + setActiveStep(articleInSearch); } } - }, [activeStepFromSearch]); + }, [activeArticleFromSearch]); const router = useRouter(); diff --git a/src/components/tutorial/index.tsx b/src/components/tutorial/index.tsx index af08fe6..2016499 100644 --- a/src/components/tutorial/index.tsx +++ b/src/components/tutorial/index.tsx @@ -99,7 +99,7 @@ export function LinkToArticle({ articleTitle: string; }) { const encodedTitle = useMemo( - () => encodeURIComponent(articleTitle), + () => encodeURIComponent(articleTitle.toLowerCase()), [articleTitle], ); @@ -107,7 +107,7 @@ export function LinkToArticle({ diff --git a/src/routes/_tutorial.tsx b/src/routes/_tutorial.tsx index 54e27e6..855718f 100644 --- a/src/routes/_tutorial.tsx +++ b/src/routes/_tutorial.tsx @@ -10,7 +10,7 @@ export const Route = createFileRoute("/_tutorial")({ validateSearch: z .object({ temp_db_missing: z.string().optional(), - step: z.string().optional(), + article: z.string().optional(), }) .extend(highlightParamSchema.shape), loader: async () => { From 898deb30d4e67caaa6b98c131ebd95930886baa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=BCl=C3=B6p=20Kov=C3=A1cs?= <43729152+fulopkovacs@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:05:55 +0100 Subject: [PATCH 2/4] Add a button to copy the currently viewed article's link --- src/components/tutorial/TutorialWindow.tsx | 57 +++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/components/tutorial/TutorialWindow.tsx b/src/components/tutorial/TutorialWindow.tsx index bbcebb6..68d19cd 100644 --- a/src/components/tutorial/TutorialWindow.tsx +++ b/src/components/tutorial/TutorialWindow.tsx @@ -1,6 +1,6 @@ import { Tabs, TabsContent } from "@radix-ui/react-tabs"; import { useNavigate, useRouter, useSearch } from "@tanstack/react-router"; -import { DatabaseZapIcon, XIcon } from "lucide-react"; +import { CheckIcon, DatabaseZapIcon, LinkIcon, XIcon } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; import { useCallback, @@ -22,6 +22,60 @@ import { ScrollArea } from "../ui/scroll-area"; import { ScrollShadow } from "../ui/scroll-shadow"; import { TutorialTableOfContents } from "./TutorialTableOfContents"; +function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { + const [copied, setCopied] = useState(false); + + const copyLink = useCallback(() => { + if (!activeStep) return; + + const url = new URL(window.location.href); + url.searchParams.set( + "article", + encodeURIComponent(activeStep.toLowerCase()), + ); + + navigator.clipboard.writeText(url.toString()).then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }); + }, [activeStep]); + + return ( + + ); +} + function FloatingWindowHeader({ toggleWindow }: { toggleWindow: () => void }) { return (
@@ -365,6 +419,7 @@ function FloatingWindow({ isResizing && "pointer-events-none", )} > + Date: Sun, 4 Jan 2026 16:34:24 +0100 Subject: [PATCH 3/4] Show an error message if the url cannot be copied --- src/components/tutorial/TutorialWindow.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/tutorial/TutorialWindow.tsx b/src/components/tutorial/TutorialWindow.tsx index 68d19cd..083fb8a 100644 --- a/src/components/tutorial/TutorialWindow.tsx +++ b/src/components/tutorial/TutorialWindow.tsx @@ -21,6 +21,7 @@ import { Button } from "../ui/button"; import { ScrollArea } from "../ui/scroll-area"; import { ScrollShadow } from "../ui/scroll-shadow"; import { TutorialTableOfContents } from "./TutorialTableOfContents"; +import { toast } from "sonner"; function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { const [copied, setCopied] = useState(false); @@ -34,10 +35,15 @@ function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { encodeURIComponent(activeStep.toLowerCase()), ); - navigator.clipboard.writeText(url.toString()).then(() => { - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }); + navigator.clipboard + .writeText(url.toString()) + .then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }) + .catch((_) => { + toast.error("Couldn't copy the url"); + }); }, [activeStep]); return ( From 6b33aefb4ecccf1133fc5b33f52f487c42b00a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=BCl=C3=B6p=20Kov=C3=A1cs?= <43729152+fulopkovacs@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:41:40 +0100 Subject: [PATCH 4/4] Fix a formatting issue --- src/components/tutorial/TutorialWindow.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/tutorial/TutorialWindow.tsx b/src/components/tutorial/TutorialWindow.tsx index 083fb8a..c595ee4 100644 --- a/src/components/tutorial/TutorialWindow.tsx +++ b/src/components/tutorial/TutorialWindow.tsx @@ -9,6 +9,7 @@ import { useRef, useState, } from "react"; +import { toast } from "sonner"; import { steps as articles } from "@/data/tutorial"; import { useScrollShadow } from "@/hooks/use-scroll-shadow"; import { cn } from "@/lib/utils"; @@ -21,7 +22,6 @@ import { Button } from "../ui/button"; import { ScrollArea } from "../ui/scroll-area"; import { ScrollShadow } from "../ui/scroll-shadow"; import { TutorialTableOfContents } from "./TutorialTableOfContents"; -import { toast } from "sonner"; function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { const [copied, setCopied] = useState(false);