From 8436e3a74c3a31e71e73fa17bd77c9d68bef7c50 Mon Sep 17 00:00:00 2001 From: Namig Date: Mon, 6 Apr 2026 12:49:40 +0400 Subject: [PATCH 1/7] chore: remove hexToRgb utility function as it is no longer needed --- src/lib/utils/hexToRgb.ts | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/lib/utils/hexToRgb.ts diff --git a/src/lib/utils/hexToRgb.ts b/src/lib/utils/hexToRgb.ts deleted file mode 100644 index dba1997..0000000 --- a/src/lib/utils/hexToRgb.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const hexToRgb = (hex: string) => { - const r = parseInt(hex.slice(1, 3), 16); - const g = parseInt(hex.slice(3, 5), 16); - const b = parseInt(hex.slice(5, 7), 16); - return `${r}, ${g}, ${b}`; -}; From 60bd5b76c7f09fa7df09bbe3ac798ddc2379a3c5 Mon Sep 17 00:00:00 2001 From: Namig Date: Thu, 9 Apr 2026 10:41:25 +0400 Subject: [PATCH 2/7] Remove 'task' translations and usage --- messages/az.json | 3 +-- messages/en.json | 3 +-- .../[locale]/roadmap/[category]/[planetId]/page.tsx | 1 - src/components/shared/planet-details/ContentList.tsx | 5 ++--- src/components/shared/planet-details/PlanetDetails.tsx | 4 +--- .../shared/planet-details/contents/Content.tsx | 5 ++--- .../planet-details/contents/ImplementationTaskBlock.tsx | 9 ++------- 7 files changed, 9 insertions(+), 21 deletions(-) diff --git a/messages/az.json b/messages/az.json index 98e73f0..e23db51 100644 --- a/messages/az.json +++ b/messages/az.json @@ -34,7 +34,6 @@ "resources": "Resurslar", "questions": "Suallar", "previous": "Əvvəlki", - "next": "Növbəti", - "task": "Tapşırıq" + "next": "Növbəti" } } \ No newline at end of file diff --git a/messages/en.json b/messages/en.json index fb23515..92404c9 100644 --- a/messages/en.json +++ b/messages/en.json @@ -34,7 +34,6 @@ "resources": "Resources", "questions": "Questions", "previous": "Previous", - "next": "Next", - "task": "Task" + "next": "Next" } } \ No newline at end of file diff --git a/src/app/(public)/[locale]/roadmap/[category]/[planetId]/page.tsx b/src/app/(public)/[locale]/roadmap/[category]/[planetId]/page.tsx index 4b9a764..660c59d 100644 --- a/src/app/(public)/[locale]/roadmap/[category]/[planetId]/page.tsx +++ b/src/app/(public)/[locale]/roadmap/[category]/[planetId]/page.tsx @@ -52,7 +52,6 @@ export default async function PlanetPage({ params }: Props) { questions: t('questions'), previous: t('previous'), next: t('next'), - task: t('task'), }; const planet = await getPlanet( diff --git a/src/components/shared/planet-details/ContentList.tsx b/src/components/shared/planet-details/ContentList.tsx index fe3e36d..6b45174 100644 --- a/src/components/shared/planet-details/ContentList.tsx +++ b/src/components/shared/planet-details/ContentList.tsx @@ -4,14 +4,13 @@ import Content from './contents/Content'; interface Props { contents: PlanetContent[]; - labels: Record; } -const ContentList = ({ contents, labels }: Props) => { +const ContentList = ({ contents }: Props) => { return (
{contents.map((content) => ( - + ))}
); diff --git a/src/components/shared/planet-details/PlanetDetails.tsx b/src/components/shared/planet-details/PlanetDetails.tsx index 9bae536..6d28e75 100644 --- a/src/components/shared/planet-details/PlanetDetails.tsx +++ b/src/components/shared/planet-details/PlanetDetails.tsx @@ -30,9 +30,7 @@ const PlanetDetails = ({ planet, labels }: Props) => { {resources && resources.length > 0 && ( )} - {contents && contents.length > 0 && ( - - )} + {contents && contents.length > 0 && } {questions && questions.length > 0 && ( )} diff --git a/src/components/shared/planet-details/contents/Content.tsx b/src/components/shared/planet-details/contents/Content.tsx index 3deb574..983eb2f 100644 --- a/src/components/shared/planet-details/contents/Content.tsx +++ b/src/components/shared/planet-details/contents/Content.tsx @@ -8,16 +8,15 @@ import ImageBlock from './ImageBlock'; interface Props { content: PlanetContent; - labels: Record; } -const Content = ({ content, labels }: Props) => { +const Content = ({ content }: Props) => { switch (content.type) { case 'text': return ; case 'implementation-task': - return ; + return ; case 'html-element': return ; diff --git a/src/components/shared/planet-details/contents/ImplementationTaskBlock.tsx b/src/components/shared/planet-details/contents/ImplementationTaskBlock.tsx index 1a964d5..27e0d97 100644 --- a/src/components/shared/planet-details/contents/ImplementationTaskBlock.tsx +++ b/src/components/shared/planet-details/contents/ImplementationTaskBlock.tsx @@ -4,18 +4,13 @@ import CustomMarkdown from './CustomMarkdown'; interface Props { content: ImplementationTaskContent; - labels: Record; } -const ImplementationTaskBlock = ({ content, labels }: Props) => { +const ImplementationTaskBlock = ({ content }: Props) => { const { title, task } = content; return (
- {title && ( -

- {labels.task}: {title} -

- )} + {title &&

{title}

}
); From 100d5cc95075cd665189da2be8be3b259929ea1d Mon Sep 17 00:00:00 2001 From: Namig Date: Wed, 15 Apr 2026 10:01:06 +0400 Subject: [PATCH 3/7] Update CustomMarkdown to handle inline elements inside lists --- .../planet-details/contents/CustomMarkdown.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/components/shared/planet-details/contents/CustomMarkdown.tsx b/src/components/shared/planet-details/contents/CustomMarkdown.tsx index 4c1026a..a1234f8 100644 --- a/src/components/shared/planet-details/contents/CustomMarkdown.tsx +++ b/src/components/shared/planet-details/contents/CustomMarkdown.tsx @@ -2,15 +2,15 @@ import Markdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { cn } from '@/lib/utils/cn'; - interface Props { text: string; className?: string; + inline?: boolean; } - -const CustomMarkdown = ({ text, className }: Props) => { +const CustomMarkdown = ({ text, className, inline }: Props) => { + const Wrapper = inline ? 'span' : 'div'; return ( -
{ className, )} > - {text} -
+ children } : undefined} + > + {text} + + ); }; - export default CustomMarkdown; From f9f60790054baa9694425c74085fcd0089c571c8 Mon Sep 17 00:00:00 2001 From: Namig Date: Wed, 15 Apr 2026 10:01:16 +0400 Subject: [PATCH 4/7] Add usePreventScroll hook --- src/lib/hooks/ui/usePreventScroll.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/lib/hooks/ui/usePreventScroll.ts diff --git a/src/lib/hooks/ui/usePreventScroll.ts b/src/lib/hooks/ui/usePreventScroll.ts new file mode 100644 index 0000000..8a42274 --- /dev/null +++ b/src/lib/hooks/ui/usePreventScroll.ts @@ -0,0 +1,23 @@ +import { useEffect } from 'react'; + +export function usePreventScroll(isActive: boolean = true) { + useEffect(() => { + if (!isActive) return; + + const originalOverflow = document.body.style.overflow; + const scrollY = window.scrollY; + + document.body.style.overflow = 'hidden'; + document.body.style.position = 'fixed'; + document.body.style.top = `-${scrollY}px`; + document.body.style.width = '100%'; + + return () => { + document.body.style.overflow = originalOverflow; + document.body.style.position = ''; + document.body.style.top = ''; + document.body.style.width = ''; + window.scrollTo(0, scrollY); + }; + }, [isActive]); +} From e2076472cf74eb9b069d6c90b8d550b7c5ea3a1e Mon Sep 17 00:00:00 2001 From: Namig Date: Wed, 15 Apr 2026 10:01:48 +0400 Subject: [PATCH 5/7] Temporarily disable zod validation for full Json import --- src/lib/hooks/admin/usePlanetJsonIO.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lib/hooks/admin/usePlanetJsonIO.ts b/src/lib/hooks/admin/usePlanetJsonIO.ts index f717925..70ada00 100644 --- a/src/lib/hooks/admin/usePlanetJsonIO.ts +++ b/src/lib/hooks/admin/usePlanetJsonIO.ts @@ -68,21 +68,21 @@ export const usePlanetJsonIO = ({ const parsed = JSON.parse(reader.result); if (jsonTypeRef.current === 'full') { - const result = preSubmitCreatePlanetDataSchema.safeParse(parsed); - - if (!result.success) { - toast.error( - "JSON content doesn't satisfy full planet data structure", - ); - console.error( - 'JSON validation error for full planet data:', - result.error.flatten().fieldErrors, - ); - return; - } + // const result = preSubmitCreatePlanetDataSchema.safeParse(parsed); + + // if (!result.success) { + // toast.error( + // "JSON content doesn't satisfy full planet data structure", + // ); + // console.error( + // 'JSON validation error for full planet data:', + // result.error.flatten().fieldErrors, + // ); + // return; + // } setPlanetData(() => { - return result.data; + return parsed; }); } else if (jsonTypeRef.current === 'locale') { const result = preSubmitLocalizedPlanetDataSchema.safeParse(parsed); From ec2784d4379453f1e88aab2e61cbda9e5d8b82e3 Mon Sep 17 00:00:00 2001 From: Namig Date: Wed, 15 Apr 2026 10:02:06 +0400 Subject: [PATCH 6/7] Update and handle UI issues --- .../planet/add/components/AddPlanetClient.tsx | 5 ++++- .../components/UpdatePlanetClient.tsx | 5 ++++- .../shared/planet-details/CodeEditor.tsx | 2 +- .../shared/planet-details/CodePreview.tsx | 2 +- .../shared/planet-details/Questions.tsx | 4 +++- .../shared/planet-details/ResearchTopics.tsx | 6 +++++- .../contents/HtmlElementBlock.tsx | 17 +++-------------- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/app/(protected)/admin/planet/add/components/AddPlanetClient.tsx b/src/app/(protected)/admin/planet/add/components/AddPlanetClient.tsx index 4703190..e765a17 100644 --- a/src/app/(protected)/admin/planet/add/components/AddPlanetClient.tsx +++ b/src/app/(protected)/admin/planet/add/components/AddPlanetClient.tsx @@ -12,6 +12,7 @@ import PlanetDetails from '@/components/shared/planet-details/PlanetDetails'; import { useOrphanedImageCleanup } from '@/lib/hooks/admin/useOrphanedImageCleanup'; import ExitPreviewButton from '@/components/admin/ui/ExitPreviewButton'; import { PLANET_CATEGORY } from '@/lib/constants/planet'; +import { usePreventScroll } from '@/lib/hooks/ui/usePreventScroll'; interface Props { category: PlanetCategory; } @@ -50,6 +51,8 @@ const AddPlanetClient = ({ category }: Props) => { useOrphanedImageCleanup(planetData, setPendingContentImages); + usePreventScroll(previewActive); + const labels = { researchTopics: 'Research Topics', resources: 'Resources', @@ -62,7 +65,7 @@ const AddPlanetClient = ({ category }: Props) => { return ( <> {previewActive && ( -
+
setPreviewActive(false)} /> { // Remove orphaned content images: keep only images referenced by any content in any locale useOrphanedImageCleanup(planetData, setPendingContentImages); + usePreventScroll(previewActive); + const labels = { researchTopics: 'Research Topics', resources: 'Resources', @@ -62,7 +65,7 @@ const UpdatePlanetClient = ({ planetId, step, initialData }: Props) => { return ( <> {previewActive && ( -
+
setPreviewActive(false)} /> { // eslint-disable-next-line @typescript-eslint/no-explicit-any const editorRef = useRef(null); diff --git a/src/components/shared/planet-details/CodePreview.tsx b/src/components/shared/planet-details/CodePreview.tsx index f05cf85..139efd7 100644 --- a/src/components/shared/planet-details/CodePreview.tsx +++ b/src/components/shared/planet-details/CodePreview.tsx @@ -19,7 +19,7 @@ const CodePreview = ({ height, paddingTop = 20, paddingBottom = 20, - fontSize = 18, + fontSize = 16, color, }: Props) => { return ( diff --git a/src/components/shared/planet-details/Questions.tsx b/src/components/shared/planet-details/Questions.tsx index 6f5ec4b..1b8da02 100644 --- a/src/components/shared/planet-details/Questions.tsx +++ b/src/components/shared/planet-details/Questions.tsx @@ -1,5 +1,7 @@ import type { Question } from '@/types/planet'; +import CustomMarkdown from './contents/CustomMarkdown'; + interface Props { questions: Question[]; labels: Record; @@ -15,7 +17,7 @@ const Questions = ({ questions, labels }: Props) => { {idx + 1}. - {qn.question} + ))} diff --git a/src/components/shared/planet-details/ResearchTopics.tsx b/src/components/shared/planet-details/ResearchTopics.tsx index cbc76de..c49ec64 100644 --- a/src/components/shared/planet-details/ResearchTopics.tsx +++ b/src/components/shared/planet-details/ResearchTopics.tsx @@ -1,5 +1,7 @@ import type { ResearchTopic } from '@/types/planet'; +import CustomMarkdown from './contents/CustomMarkdown'; + interface Props { researchTopics: ResearchTopic[]; labels: Record; @@ -11,7 +13,9 @@ const ResearchTopics = ({ researchTopics, labels }: Props) => {

{labels.researchTopics}

    {researchTopics.map((topic) => ( -
  • {topic.topic}
  • +
  • + +
  • ))}
diff --git a/src/components/shared/planet-details/contents/HtmlElementBlock.tsx b/src/components/shared/planet-details/contents/HtmlElementBlock.tsx index 68a435d..56c9dae 100644 --- a/src/components/shared/planet-details/contents/HtmlElementBlock.tsx +++ b/src/components/shared/planet-details/contents/HtmlElementBlock.tsx @@ -4,28 +4,24 @@ import { useEffect, useState, useRef } from 'react'; import type { HtmlElementContent } from '@/types/planet'; import CustomMarkdown from './CustomMarkdown'; - interface Props { content: HtmlElementContent; } - const HtmlElementBlock = ({ content }: Props) => { const { title, description, element } = content; const { html, css, js } = element; const [iframeHeight, setIframeHeight] = useState(300); const iframeRef = useRef(null); - useEffect(() => { const handleMessage = (e: MessageEvent) => { + if (e.source !== iframeRef.current?.contentWindow) return; if (e.data.type === 'resize') { setIframeHeight(e.data.height); } }; - window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, []); - const iframeContent = ` @@ -41,19 +37,15 @@ const HtmlElementBlock = ({ content }: Props) => { ${html}