Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions messages/az.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"resources": "Resurslar",
"questions": "Suallar",
"previous": "Əvvəlki",
"next": "Növbəti",
"task": "Tapşırıq"
"next": "Növbəti"
}
}
}
5 changes: 2 additions & 3 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"resources": "Resources",
"questions": "Questions",
"previous": "Previous",
"next": "Next",
"task": "Task"
"next": "Next"
}
}
}
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
import './.next/dev/types/routes.d.ts';

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -50,6 +51,8 @@ const AddPlanetClient = ({ category }: Props) => {

useOrphanedImageCleanup(planetData, setPendingContentImages);

usePreventScroll(previewActive);

const labels = {
researchTopics: 'Research Topics',
resources: 'Resources',
Expand All @@ -62,7 +65,7 @@ const AddPlanetClient = ({ category }: Props) => {
return (
<>
{previewActive && (
<div className="absolute top-0 left-0 w-full z-500 min-h-screen">
<div className="fixed top-0 left-0 w-full z-500 h-screen overflow-auto">
<ExitPreviewButton onClick={() => setPreviewActive(false)} />
<PlanetDetails
planet={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useUpdatePlanet } from '@/lib/hooks/admin/useUpdatePlanet';
import PlanetDetails from '@/components/shared/planet-details/PlanetDetails';
import { useOrphanedImageCleanup } from '@/lib/hooks/admin/useOrphanedImageCleanup';
import ExitPreviewButton from '@/components/admin/ui/ExitPreviewButton';
import { usePreventScroll } from '@/lib/hooks/ui/usePreventScroll';

interface Props {
planetId: string;
Expand Down Expand Up @@ -50,6 +51,8 @@ const UpdatePlanetClient = ({ planetId, step, initialData }: Props) => {
// 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',
Expand All @@ -62,7 +65,7 @@ const UpdatePlanetClient = ({ planetId, step, initialData }: Props) => {
return (
<>
{previewActive && (
<div className="absolute top-0 left-0 w-full z-500 min-h-screen">
<div className="fixed top-0 left-0 w-full z-500 h-screen overflow-auto">
<ExitPreviewButton onClick={() => setPreviewActive(false)} />
<PlanetDetails
planet={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion src/components/shared/planet-details/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const CodeEditor = ({
onChange,
paddingTop = 20,
paddingBottom = 20,
fontSize = 18,
fontSize = 16,
}: Props) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const editorRef = useRef<any>(null);
Expand Down
2 changes: 1 addition & 1 deletion src/components/shared/planet-details/CodePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CodePreview = ({
height,
paddingTop = 20,
paddingBottom = 20,
fontSize = 18,
fontSize = 16,
color,
}: Props) => {
return (
Expand Down
5 changes: 2 additions & 3 deletions src/components/shared/planet-details/ContentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import Content from './contents/Content';

interface Props {
contents: PlanetContent[];
labels: Record<string, string>;
}

const ContentList = ({ contents, labels }: Props) => {
const ContentList = ({ contents }: Props) => {
return (
<section className="space-y-8">
{contents.map((content) => (
<Content key={content.id} content={content} labels={labels} />
<Content key={content.id} content={content} />
))}
</section>
);
Expand Down
4 changes: 1 addition & 3 deletions src/components/shared/planet-details/PlanetDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ const PlanetDetails = ({ planet, labels }: Props) => {
{resources && resources.length > 0 && (
<Resources resources={resources} labels={labels} />
)}
{contents && contents.length > 0 && (
<ContentList contents={contents} labels={labels} />
)}
{contents && contents.length > 0 && <ContentList contents={contents} />}
{questions && questions.length > 0 && (
<Questions questions={questions} labels={labels} />
)}
Expand Down
4 changes: 3 additions & 1 deletion src/components/shared/planet-details/Questions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Question } from '@/types/planet';

import CustomMarkdown from './contents/CustomMarkdown';

interface Props {
questions: Question[];
labels: Record<string, string>;
Expand All @@ -15,7 +17,7 @@ const Questions = ({ questions, labels }: Props) => {
<span className="shrink-0 text-slate-400 font-medium">
{idx + 1}.
</span>
<span>{qn.question}</span>
<CustomMarkdown text={qn.question} inline={true} />
</li>
))}
</ol>
Expand Down
6 changes: 5 additions & 1 deletion src/components/shared/planet-details/ResearchTopics.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { ResearchTopic } from '@/types/planet';

import CustomMarkdown from './contents/CustomMarkdown';

interface Props {
researchTopics: ResearchTopic[];
labels: Record<string, string>;
Expand All @@ -11,7 +13,9 @@ const ResearchTopics = ({ researchTopics, labels }: Props) => {
<h2 className="heading-secondary">{labels.researchTopics}</h2>
<ul className="list-indented list-disc">
{researchTopics.map((topic) => (
<li key={topic.id}>{topic.topic}</li>
<li key={topic.id}>
<CustomMarkdown text={topic.topic} inline={true} />
</li>
))}
</ul>
</section>
Expand Down
5 changes: 2 additions & 3 deletions src/components/shared/planet-details/contents/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import ImageBlock from './ImageBlock';

interface Props {
content: PlanetContent;
labels: Record<string, string>;
}

const Content = ({ content, labels }: Props) => {
const Content = ({ content }: Props) => {
switch (content.type) {
case 'text':
return <TextContentBlock content={content} />;

case 'implementation-task':
return <ImplementationTaskBlock content={content} labels={labels} />;
return <ImplementationTaskBlock content={content} />;

case 'html-element':
return <HtmlElementBlock content={content} />;
Expand Down
18 changes: 11 additions & 7 deletions src/components/shared/planet-details/contents/CustomMarkdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div
<Wrapper
className={cn(
`prose max-w-none
text-lg text-white
Expand All @@ -24,9 +24,13 @@ const CustomMarkdown = ({ text, className }: Props) => {
className,
)}
>
<Markdown remarkPlugins={[remarkGfm]}>{text}</Markdown>
</div>
<Markdown
remarkPlugins={[remarkGfm]}
components={inline ? { p: ({ children }) => children } : undefined}
>
{text}
</Markdown>
</Wrapper>
);
};

export default CustomMarkdown;
17 changes: 3 additions & 14 deletions src/components/shared/planet-details/contents/HtmlElementBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLIFrameElement>(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 = `
<!DOCTYPE html>
<html>
Expand All @@ -41,19 +37,15 @@ const HtmlElementBlock = ({ content }: Props) => {
<body>
${html}
<script>
// Send initial height
function sendHeight() {
const height = document.body.scrollHeight;
window.parent.postMessage({ type: 'resize', height }, '*');
}

// Send height after content loads
window.addEventListener('load', sendHeight);

// Send height after a short delay (for dynamic content)
setTimeout(sendHeight, 250);

// watch for content changes
if (window.ResizeObserver) {
const observer = new ResizeObserver(sendHeight);
observer.observe(document.body);
Expand All @@ -64,17 +56,15 @@ const HtmlElementBlock = ({ content }: Props) => {
</body>
</html>
`;

return (
<div>
{title && <h3 className="heading-sub">{title}</h3>}
{description && <CustomMarkdown text={description} />}

<div className="mt-4 border border-gray-300 rounded-lg overflow-hidden bg-white resize">
<div className="mt-4 border border-gray-300 rounded-lg overflow-auto bg-white resize">
<iframe
ref={iframeRef}
className="w-full border-0 bg-white block"
style={{ height: `${iframeHeight}px` }}
style={{ height: `${Math.min(iframeHeight, 600)}px` }}
srcDoc={iframeContent}
sandbox="allow-scripts allow-modals allow-top-navigation-by-user-activation"
title="HTML Preview"
Expand All @@ -83,5 +73,4 @@ const HtmlElementBlock = ({ content }: Props) => {
</div>
);
};

export default HtmlElementBlock;
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@ import CustomMarkdown from './CustomMarkdown';

interface Props {
content: ImplementationTaskContent;
labels: Record<string, string>;
}

const ImplementationTaskBlock = ({ content, labels }: Props) => {
const ImplementationTaskBlock = ({ content }: Props) => {
const { title, task } = content;
return (
<div>
{title && (
<h3 className="heading-sub">
{labels.task}: {title}
</h3>
)}
{title && <h3 className="heading-sub">{title}</h3>}
<CustomMarkdown text={task} />
</div>
);
Expand Down
28 changes: 14 additions & 14 deletions src/lib/hooks/admin/usePlanetJsonIO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Updater } from 'use-immer';

import type { CreatePlanetData, SupportedLanguage } from '@/types/planet';
import {
preSubmitCreatePlanetDataSchema,
// preSubmitCreatePlanetDataSchema,
preSubmitLocalizedPlanetDataSchema,
} from '@/lib/validation/planetDataSchema';

Expand Down Expand Up @@ -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);
Expand Down
23 changes: 23 additions & 0 deletions src/lib/hooks/ui/usePreventScroll.ts
Original file line number Diff line number Diff line change
@@ -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]);
}
6 changes: 0 additions & 6 deletions src/lib/utils/hexToRgb.ts

This file was deleted.

Loading