mirror of
https://github.com/cfngc4594/monaco-editor-lsp-next.git
synced 2025-05-18 15:26:36 +00:00
refactor(problems): migrate description and solution to feature-based structure
- Remove old parallel route implementations (@Description and @Solutions) - Add new feature-based components for problem description and solution - Create content and panel components for both features - Implement skeleton loading states - Use cached data fetching - Update MDX rendering and scroll area implementations
This commit is contained in:
parent
f464fb7636
commit
5f3eb72d00
@ -1,16 +0,0 @@
|
||||
import { Suspense } from "react";
|
||||
import { Loading } from "@/components/loading";
|
||||
|
||||
interface DescriptionLayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function DescriptionLayout({ children }: DescriptionLayoutProps) {
|
||||
return (
|
||||
<div className="h-full flex flex-col border border-t-0 border-muted rounded-b-3xl bg-background">
|
||||
<Suspense fallback={<Loading />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { notFound } from "next/navigation";
|
||||
import MdxPreview from "@/components/mdx-preview";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import ProblemDescriptionFooter from "@/components/features/playground/problem/description/footer";
|
||||
|
||||
interface DescriptionPageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function DescriptionPage({ params }: DescriptionPageProps) {
|
||||
const { id } = await params;
|
||||
|
||||
if (!id) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
const problem = await prisma.problem.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
title: true,
|
||||
description: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!problem) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative flex-1">
|
||||
<div className="absolute h-full w-full">
|
||||
<ScrollArea className="h-full [&>[data-radix-scroll-area-viewport]>div:min-w-0 [&>[data-radix-scroll-area-viewport]>div]:!block bg-background">
|
||||
<MdxPreview source={problem.description} className="p-4 md:p-6" />
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
<ProblemDescriptionFooter title={problem.title} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Suspense } from "react";
|
||||
import { Loading } from "@/components/loading";
|
||||
|
||||
interface SolutionsLayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default async function SolutionsLayout({ children }: SolutionsLayoutProps) {
|
||||
return (
|
||||
<div className="flex flex-col h-full border border-t-0 border-muted rounded-b-3xl bg-background">
|
||||
<Suspense fallback={<Loading />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { notFound } from "next/navigation";
|
||||
import MdxPreview from "@/components/mdx-preview";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
import ProblemSolutionFooter from "@/components/features/playground/problem/solution/footer";
|
||||
|
||||
interface SolutionsPageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function SolutionsPage({ params }: SolutionsPageProps) {
|
||||
const { id } = await params;
|
||||
|
||||
if (!id) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
const problem = await prisma.problem.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
title: true,
|
||||
solution: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!problem) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative flex-1">
|
||||
<div className="absolute h-full w-full">
|
||||
<ScrollArea className="h-full [&>[data-radix-scroll-area-viewport]>div:min-w-0 [&>[data-radix-scroll-area-viewport]>div]:!block bg-background">
|
||||
<MdxPreview source={problem.solution} className="p-4 md:p-6" />
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
<ProblemSolutionFooter title={problem.title} />
|
||||
</>
|
||||
);
|
||||
}
|
56
src/features/problems/description/components/content.tsx
Normal file
56
src/features/problems/description/components/content.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { getCachedProblem } from "@/lib/prisma";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { MdxRenderer } from "@/components/content/mdx-renderer";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
|
||||
interface DescriptionContentProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const DescriptionContent = async ({ id }: DescriptionContentProps) => {
|
||||
const problem = await getCachedProblem(id);
|
||||
|
||||
return (
|
||||
<ScrollArea className="h-full">
|
||||
<MdxRenderer
|
||||
source={problem?.description ?? "description not found"}
|
||||
className="p-4 md:p-6"
|
||||
/>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
);
|
||||
};
|
||||
|
||||
const DescriptionContentSkeleton = () => {
|
||||
return (
|
||||
<div className="h-full flex flex-col p-4 md:p-6">
|
||||
{/* Title skeleton */}
|
||||
<Skeleton className="h-8 w-3/4 mb-6" />
|
||||
|
||||
{/* Content skeletons */}
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-5/6 mb-4" />
|
||||
<Skeleton className="h-4 w-2/3 mb-4" />
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-4/5 mb-4" />
|
||||
|
||||
{/* Example section heading */}
|
||||
<Skeleton className="h-6 w-1/4 mb-4 mt-8" />
|
||||
|
||||
{/* Example content */}
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-5/6 mb-4" />
|
||||
|
||||
{/* Code block skeleton */}
|
||||
<div className="mb-6">
|
||||
<Skeleton className="h-40 w-full rounded-md" />
|
||||
</div>
|
||||
|
||||
{/* More content */}
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-3/4 mb-4" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { DescriptionContent, DescriptionContentSkeleton };
|
25
src/features/problems/description/components/panel.tsx
Normal file
25
src/features/problems/description/components/panel.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Suspense } from "react";
|
||||
import {
|
||||
DescriptionContent,
|
||||
DescriptionContentSkeleton,
|
||||
} from "@/features/problems/description/components/content";
|
||||
|
||||
interface DescriptionPanelProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const DescriptionPanel = ({ id }: DescriptionPanelProps) => {
|
||||
return (
|
||||
<div className="h-full flex flex-col border border-t-0 border-muted rounded-b-3xl bg-background overflow-hidden">
|
||||
<div className="relative flex-1">
|
||||
<div className="absolute h-full w-full">
|
||||
<Suspense fallback={<DescriptionContentSkeleton />}>
|
||||
<DescriptionContent id={id} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { DescriptionPanel };
|
56
src/features/problems/solution/components/content.tsx
Normal file
56
src/features/problems/solution/components/content.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { getCachedProblem } from "@/lib/prisma";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { MdxRenderer } from "@/components/content/mdx-renderer";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
|
||||
interface SolutionContentProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const SolutionContent = async ({ id }: SolutionContentProps) => {
|
||||
const problem = await getCachedProblem(id);
|
||||
|
||||
return (
|
||||
<ScrollArea className="h-full">
|
||||
<MdxRenderer
|
||||
source={problem?.solution ?? "solution not found"}
|
||||
className="p-4 md:p-6"
|
||||
/>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
);
|
||||
};
|
||||
|
||||
const SolutionContentSkeleton = () => {
|
||||
return (
|
||||
<div className="h-full flex flex-col p-4 md:p-6">
|
||||
{/* Title skeleton */}
|
||||
<Skeleton className="h-8 w-3/4 mb-6" />
|
||||
|
||||
{/* Content skeletons */}
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-5/6 mb-4" />
|
||||
<Skeleton className="h-4 w-2/3 mb-4" />
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-4/5 mb-4" />
|
||||
|
||||
{/* Example section heading */}
|
||||
<Skeleton className="h-6 w-1/4 mb-4 mt-8" />
|
||||
|
||||
{/* Example content */}
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-5/6 mb-4" />
|
||||
|
||||
{/* Code block skeleton */}
|
||||
<div className="mb-6">
|
||||
<Skeleton className="h-40 w-full rounded-md" />
|
||||
</div>
|
||||
|
||||
{/* More content */}
|
||||
<Skeleton className="h-4 w-full mb-4" />
|
||||
<Skeleton className="h-4 w-3/4 mb-4" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { SolutionContent, SolutionContentSkeleton };
|
25
src/features/problems/solution/components/panel.tsx
Normal file
25
src/features/problems/solution/components/panel.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Suspense } from "react";
|
||||
import {
|
||||
SolutionContent,
|
||||
SolutionContentSkeleton,
|
||||
} from "@/features/problems/solution/components/content";
|
||||
|
||||
interface SolutionPanelProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const SolutionPanel = ({ id }: SolutionPanelProps) => {
|
||||
return (
|
||||
<div className="h-full flex flex-col border border-t-0 border-muted rounded-b-3xl bg-background overflow-hidden">
|
||||
<div className="relative flex-1">
|
||||
<div className="absolute h-full w-full">
|
||||
<Suspense fallback={<SolutionContentSkeleton />}>
|
||||
<SolutionContent id={id} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { SolutionPanel };
|
Loading…
Reference in New Issue
Block a user