refactor(creater): wrap Panel with PanelLayout and ScrollArea

This commit is contained in:
cfngc4594 2025-06-20 23:36:44 +08:00
parent ecaba8f48b
commit 7cda49116e
7 changed files with 480 additions and 434 deletions

View File

@ -1,14 +1,16 @@
"use client"; "use client";
import React, { useEffect, useState } from "react";
import { getProblemData } from "@/app/actions/getProblem";
import { updateProblemTemplate } from "@/components/creater/problem-maintain";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { CoreEditor } from "@/components/core-editor";
import { Language } from "@/generated/client";
import { toast } from "sonner"; import { toast } from "sonner";
import { Label } from "@/components/ui/label";
import { Language } from "@/generated/client";
import { Button } from "@/components/ui/button";
import React, { useEffect, useState } from "react";
import { CoreEditor } from "@/components/core-editor";
import { ScrollArea } from "@/components/ui/scroll-area";
import { getProblemData } from "@/app/actions/getProblem";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { PanelLayout } from "@/features/problems/layouts/panel-layout";
import { updateProblemTemplate } from "@/components/creater/problem-maintain";
interface Template { interface Template {
language: string; language: string;
@ -67,9 +69,14 @@ export default function EditCodePanel({ problemId }: EditCodePanelProps) {
}; };
return ( return (
<Card className="w-full"> <PanelLayout>
<CardHeader> <ScrollArea className="h-full">
<CardTitle></CardTitle> <Card className="w-full rounded-none border-none bg-background">
<CardHeader className="px-6 py-4">
<div className="flex items-center justify-between">
<span></span>
<Button onClick={handleSave}></Button>
</div>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="space-y-6"> <div className="space-y-6">
@ -102,10 +109,10 @@ export default function EditCodePanel({ problemId }: EditCodePanelProps) {
/> />
</div> </div>
</div> </div>
<Button onClick={handleSave}></Button>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
</ScrollArea>
</PanelLayout>
); );
} }

View File

@ -1,22 +1,24 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import { toast } from "sonner";
import { Locale } from "@/generated/client";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { CoreEditor } from "@/components/core-editor";
import MdxPreview from "@/components/mdx-preview";
import { getProblemData } from "@/app/actions/getProblem";
import { getProblemLocales } from "@/app/actions/getProblemLocales";
import { Accordion } from "@/components/ui/accordion";
import { VideoEmbed } from "@/components/content/video-embed";
import { toast } from "sonner";
import { import {
updateProblemDescription, updateProblemDescription,
updateProblemTitle, updateProblemTitle,
} from "@/components/creater/problem-maintain"; } from "@/components/creater/problem-maintain";
import { Locale } from "@/generated/client"; import { Button } from "@/components/ui/button";
import MdxPreview from "@/components/mdx-preview";
import React, { useEffect, useState } from "react";
import { Accordion } from "@/components/ui/accordion";
import { CoreEditor } from "@/components/core-editor";
import { ScrollArea } from "@/components/ui/scroll-area";
import { getProblemData } from "@/app/actions/getProblem";
import { VideoEmbed } from "@/components/content/video-embed";
import { getProblemLocales } from "@/app/actions/getProblemLocales";
import { PanelLayout } from "@/features/problems/layouts/panel-layout";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export default function EditDescriptionPanel({ export default function EditDescriptionPanel({
problemId, problemId,
@ -102,7 +104,9 @@ export default function EditDescriptionPanel({
}; };
return ( return (
<Card className="w-full"> <PanelLayout>
<ScrollArea className="h-full">
<Card className="w-full rounded-none border-none bg-background">
<CardHeader> <CardHeader>
<CardTitle></CardTitle> <CardTitle></CardTitle>
</CardHeader> </CardHeader>
@ -145,7 +149,8 @@ export default function EditDescriptionPanel({
</div> </div>
{/* 编辑/预览切换 */} {/* 编辑/预览切换 */}
<div className="flex space-x-2"> <div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<Button <Button
type="button" type="button"
variant={viewMode === "edit" ? "default" : "outline"} variant={viewMode === "edit" ? "default" : "outline"}
@ -170,6 +175,10 @@ export default function EditDescriptionPanel({
</Button> </Button>
</div> </div>
<div className="flex items-center">
<Button onClick={handleSave}></Button>
</div>
</div>
{/* 编辑/预览区域 */} {/* 编辑/预览区域 */}
<div <div
@ -200,9 +209,9 @@ export default function EditDescriptionPanel({
</div> </div>
)} )}
</div> </div>
<Button onClick={handleSave}></Button>
</CardContent> </CardContent>
</Card> </Card>
</ScrollArea>
</PanelLayout>
); );
} }

View File

@ -1,14 +1,16 @@
"use client"; "use client";
import React, { useState, useEffect } from "react"; import { toast } from "sonner";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { getProblemData } from "@/app/actions/getProblem";
import { toast } from "sonner";
import { updateProblemDetail } from "@/components/creater/problem-maintain";
import { Difficulty } from "@/generated/client"; import { Difficulty } from "@/generated/client";
import React, { useState, useEffect } from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
import { getProblemData } from "@/app/actions/getProblem";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { PanelLayout } from "@/features/problems/layouts/panel-layout";
import { updateProblemDetail } from "@/components/creater/problem-maintain";
export default function EditDetailPanel({ problemId }: { problemId: string }) { export default function EditDetailPanel({ problemId }: { problemId: string }) {
const [problemDetails, setProblemDetails] = useState({ const [problemDetails, setProblemDetails] = useState({
@ -77,9 +79,16 @@ export default function EditDetailPanel({ problemId }: { problemId: string }) {
}; };
return ( return (
<Card className="w-full"> <PanelLayout>
<CardHeader> <ScrollArea className="h-full">
<CardTitle></CardTitle> <Card className="w-full rounded-none border-none bg-background">
<CardHeader className="px-6 py-4">
<div className="flex items-center justify-between">
<span></span>
<Button type="button" onClick={handleSave}>
</Button>
</div>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="space-y-6"> <div className="space-y-6">
@ -132,6 +141,7 @@ export default function EditDetailPanel({ problemId }: { problemId: string }) {
</div> </div>
</div> </div>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<input <input
id="is-published" id="is-published"
@ -149,12 +159,11 @@ export default function EditDetailPanel({ problemId }: { problemId: string }) {
</Label> </Label>
</div> </div>
</div>
<Button type="button" onClick={handleSave}>
</Button>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
</ScrollArea>
</PanelLayout>
); );
} }

View File

@ -1,19 +1,21 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import { toast } from "sonner";
import { Locale } from "@/generated/client";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { CoreEditor } from "@/components/core-editor";
import MdxPreview from "@/components/mdx-preview"; import MdxPreview from "@/components/mdx-preview";
import { getProblemData } from "@/app/actions/getProblem"; import React, { useEffect, useState } from "react";
import { getProblemLocales } from "@/app/actions/getProblemLocales";
import { Accordion } from "@/components/ui/accordion"; import { Accordion } from "@/components/ui/accordion";
import { CoreEditor } from "@/components/core-editor";
import { ScrollArea } from "@/components/ui/scroll-area";
import { getProblemData } from "@/app/actions/getProblem";
import { VideoEmbed } from "@/components/content/video-embed"; import { VideoEmbed } from "@/components/content/video-embed";
import { toast } from "sonner"; import { getProblemLocales } from "@/app/actions/getProblemLocales";
import { PanelLayout } from "@/features/problems/layouts/panel-layout";
import { updateProblemSolution } from "@/components/creater/problem-maintain"; import { updateProblemSolution } from "@/components/creater/problem-maintain";
import { Locale } from "@/generated/client"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export default function EditSolutionPanel({ export default function EditSolutionPanel({
problemId, problemId,
@ -93,7 +95,9 @@ export default function EditSolutionPanel({
}; };
return ( return (
<Card className="w-full"> <PanelLayout>
<ScrollArea className="h-full">
<Card className="w-full rounded-none border-none bg-background">
<CardHeader> <CardHeader>
<CardTitle></CardTitle> <CardTitle></CardTitle>
</CardHeader> </CardHeader>
@ -200,5 +204,7 @@ export default function EditSolutionPanel({
</Button> </Button>
</CardContent> </CardContent>
</Card> </Card>
</ScrollArea>
</PanelLayout>
); );
} }

View File

@ -1,18 +1,20 @@
"use client"; "use client";
import React, { useState, useEffect } from "react"; import { toast } from "sonner";
import { generateAITestcase } from "@/app/actions/ai-testcase"; import { Input } from "@/components/ui/input";
import { getProblemData } from "@/app/actions/getProblem"; import { Label } from "@/components/ui/label";
import { import {
addProblemTestcase, addProblemTestcase,
updateProblemTestcase, updateProblemTestcase,
deleteProblemTestcase, deleteProblemTestcase,
} from "@/components/creater/problem-maintain"; } from "@/components/creater/problem-maintain";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import React, { useState, useEffect } from "react";
import { toast } from "sonner"; import { ScrollArea } from "@/components/ui/scroll-area";
import { getProblemData } from "@/app/actions/getProblem";
import { generateAITestcase } from "@/app/actions/ai-testcase";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { PanelLayout } from "@/features/problems/layouts/panel-layout";
interface Testcase { interface Testcase {
id: string; id: string;
@ -182,18 +184,22 @@ export default function EditTestcasePanel({
}; };
return ( return (
<Card className="w-full"> <PanelLayout>
<CardHeader> <ScrollArea className="h-full">
<CardTitle></CardTitle> <Card className="w-full rounded-none border-none bg-background">
<CardHeader className="px-6 py-4">
<div className="flex items-center justify-between">
<span></span>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Button onClick={handleAddTestcase}></Button>
<Button onClick={handleAITestcase} disabled={isGenerating}> <Button onClick={handleAITestcase} disabled={isGenerating}>
{isGenerating ? "生成中..." : "使用AI生成测试用例"} {isGenerating ? "生成中..." : "AI生成"}
</Button> </Button>
<Button onClick={handleAddTestcase}></Button>
<Button variant="secondary" onClick={handleSaveAll}> <Button variant="secondary" onClick={handleSaveAll}>
</Button> </Button>
</div> </div>
</div>
</CardHeader> </CardHeader>
<CardContent className="space-y-6"> <CardContent className="space-y-6">
{testcases.map((tc, idx) => ( {testcases.map((tc, idx) => (
@ -220,7 +226,9 @@ export default function EditTestcasePanel({
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<Label></Label> <Label></Label>
<Button onClick={() => handleAddInput(idx)}></Button> <Button onClick={() => handleAddInput(idx)}>
</Button>
</div> </div>
{tc.inputs.map((inp, iIdx) => ( {tc.inputs.map((inp, iIdx) => (
<div key={iIdx} className="grid grid-cols-2 gap-4"> <div key={iIdx} className="grid grid-cols-2 gap-4">
@ -239,7 +247,12 @@ export default function EditTestcasePanel({
<Input <Input
value={inp.value} value={inp.value}
onChange={(e) => onChange={(e) =>
handleInputChange(idx, iIdx, "value", e.target.value) handleInputChange(
idx,
iIdx,
"value",
e.target.value
)
} }
placeholder="参数值" placeholder="参数值"
/> />
@ -259,5 +272,7 @@ export default function EditTestcasePanel({
))} ))}
</CardContent> </CardContent>
</Card> </Card>
</ScrollArea>
</PanelLayout>
); );
} }

View File

@ -11,9 +11,9 @@ interface ProblemEditViewProps {
export const ProblemEditView = ({ problemId }: ProblemEditViewProps) => { export const ProblemEditView = ({ problemId }: ProblemEditViewProps) => {
const components: Record<string, React.ReactNode> = { const components: Record<string, React.ReactNode> = {
detail: <EditDetailPanel problemId={problemId} />,
description: <EditDescriptionPanel problemId={problemId} />, description: <EditDescriptionPanel problemId={problemId} />,
solution: <EditSolutionPanel problemId={problemId} />, solution: <EditSolutionPanel problemId={problemId} />,
detail: <EditDetailPanel problemId={problemId} />,
code: <EditCodePanel problemId={problemId} />, code: <EditCodePanel problemId={problemId} />,
testcase: <EditTestcasePanel problemId={problemId} />, testcase: <EditTestcasePanel problemId={problemId} />,
}; };

View File

@ -144,6 +144,13 @@ const initialProblemEditFlexLayoutJsonModel: IJsonModel = {
id: "1", id: "1",
weight: 50, weight: 50,
children: [ children: [
{
type: "tab",
id: "detail",
name: "Details",
component: "detail",
enableClose: false,
},
{ {
type: "tab", type: "tab",
id: "description", id: "description",
@ -158,13 +165,6 @@ const initialProblemEditFlexLayoutJsonModel: IJsonModel = {
component: "solution", component: "solution",
enableClose: false, enableClose: false,
}, },
{
type: "tab",
id: "detail",
name: "Details",
component: "detail",
enableClose: false,
},
], ],
}, },
{ {