mirror of
https://github.com/massbug/judge4c.git
synced 2025-05-18 15:26:33 +00:00
chore(app): remove playground folder
This commit is contained in:
parent
13217399d0
commit
672b627ed1
@ -1,18 +0,0 @@
|
|||||||
// import ProblemDescriptionFooter from "@/features/playground/problem/description/footer";
|
|
||||||
|
|
||||||
interface ProblemDescriptionLayoutProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemDescriptionLayout({
|
|
||||||
children,
|
|
||||||
}: ProblemDescriptionLayoutProps) {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
<div className="flex-1">
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
{/* <ProblemDescriptionFooter /> */}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import MdxPreview from "@/components/mdx-preview";
|
|
||||||
import { DEFAULT_PROBLEM_DESCRIPTION } from "@/config/problem/description";
|
|
||||||
|
|
||||||
export default function ProblemDescriptionPage() {
|
|
||||||
return <MdxPreview source={DEFAULT_PROBLEM_DESCRIPTION} />;
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
import { cn } from "@/lib/utils";
|
|
||||||
|
|
||||||
interface ProblemSolutionFooterProps {
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemSolutionFooter({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: ProblemSolutionFooterProps) {
|
|
||||||
return (
|
|
||||||
<footer
|
|
||||||
{...props}
|
|
||||||
className={cn("h-9 flex flex-none items-center bg-muted px-3 py-2", className)}
|
|
||||||
>
|
|
||||||
<div className="w-full flex items-center justify-center">
|
|
||||||
<span className="truncate">
|
|
||||||
Solution of Two Sum
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import ProblemSolutionFooter from "./components/footer";
|
|
||||||
|
|
||||||
interface ProblemSolutionLayoutProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemSolutionLayout({
|
|
||||||
children,
|
|
||||||
}: ProblemSolutionLayoutProps) {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
<div className="flex-1">
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
<ProblemSolutionFooter />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import MdxPreview from "@/components/mdx-preview";
|
|
||||||
import { DEFAULT_PROBLEM_SOLUTION } from "@/config/problem/solution";
|
|
||||||
|
|
||||||
export default function ProblemSolutionPage() {
|
|
||||||
return <MdxPreview source={DEFAULT_PROBLEM_SOLUTION} />;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
import { cn } from "@/lib/utils";
|
|
||||||
|
|
||||||
interface ProblemSubmissionFooterProps {
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemSubmissionFooter({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: ProblemSubmissionFooterProps) {
|
|
||||||
return (
|
|
||||||
<footer
|
|
||||||
{...props}
|
|
||||||
className={cn(
|
|
||||||
"h-9 flex flex-none items-center bg-muted px-3 py-2",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="w-full flex items-center justify-center">
|
|
||||||
<span className="truncate">Submission of Two Sum</span>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import ProblemSubmissionFooter from "./components/footer";
|
|
||||||
|
|
||||||
interface ProblemSubmissionLayoutProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemSubmissionLayout({
|
|
||||||
children,
|
|
||||||
}: ProblemSubmissionLayoutProps) {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
<div className="flex-1">{children}</div>
|
|
||||||
<ProblemSubmissionFooter />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import MdxPreview from "@/components/mdx-preview";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
export default function ProblemSubmissionPage() {
|
|
||||||
const { result } = useCodeEditorStore();
|
|
||||||
const { exitCode, output, executionTime, memoryUsage } = result || {};
|
|
||||||
|
|
||||||
const template = useMemo(() => {
|
|
||||||
return `
|
|
||||||
${exitCode || ""}
|
|
||||||
\`\`\`bash
|
|
||||||
${output || ""}
|
|
||||||
\`\`\`
|
|
||||||
${executionTime || ""}
|
|
||||||
${memoryUsage || ""}
|
|
||||||
`;
|
|
||||||
}, [exitCode, output, executionTime, memoryUsage]);
|
|
||||||
|
|
||||||
return <MdxPreview source={template} />;
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
|
||||||
import { useTabsStore } from "@/store/useTabsStore";
|
|
||||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
||||||
import { CircleCheckBigIcon, FileTextIcon, FlaskConicalIcon } from "lucide-react";
|
|
||||||
|
|
||||||
interface ProblemLayoutProps {
|
|
||||||
description: React.ReactNode;
|
|
||||||
solution: React.ReactNode;
|
|
||||||
submission: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProblemLayout({
|
|
||||||
description,
|
|
||||||
solution,
|
|
||||||
submission,
|
|
||||||
}: ProblemLayoutProps) {
|
|
||||||
const { hydrated, problemTab, setProblemTab } = useTabsStore();
|
|
||||||
|
|
||||||
if (!hydrated) return (
|
|
||||||
<div className="h-9 w-full flex items-center px-2 py-1 bg-muted gap-1">
|
|
||||||
<Skeleton className="h-full w-[136px] rounded-3xl" />
|
|
||||||
<Skeleton className="h-full w-[111px] rounded-3xl" />
|
|
||||||
<Skeleton className="h-full w-32 rounded-3xl" />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleTabChange = (value: string) => {
|
|
||||||
setProblemTab(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tabs value={problemTab} onValueChange={handleTabChange} className="h-full flex flex-col">
|
|
||||||
<ScrollArea className="h-9 flex-none bg-muted px-1">
|
|
||||||
<TabsList className="gap-1 bg-transparent">
|
|
||||||
<TabsTrigger
|
|
||||||
value="description"
|
|
||||||
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground rounded-full data-[state=active]:shadow-none"
|
|
||||||
>
|
|
||||||
<FileTextIcon
|
|
||||||
className="-ms-0.5 me-1.5 opacity-60"
|
|
||||||
size={16}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
Description
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger
|
|
||||||
value="solution"
|
|
||||||
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground rounded-full data-[state=active]:shadow-none"
|
|
||||||
>
|
|
||||||
<FlaskConicalIcon
|
|
||||||
className="-ms-0.5 me-1.5 opacity-60"
|
|
||||||
size={16}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
Solution
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger
|
|
||||||
value="submission"
|
|
||||||
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground rounded-full data-[state=active]:shadow-none"
|
|
||||||
>
|
|
||||||
<CircleCheckBigIcon
|
|
||||||
className="-ms-0.5 me-1.5 opacity-60"
|
|
||||||
size={16}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
Submission
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
<ScrollBar orientation="horizontal" />
|
|
||||||
</ScrollArea>
|
|
||||||
<TabsContent value="description" className="h-full mt-0">
|
|
||||||
{description}
|
|
||||||
</TabsContent>
|
|
||||||
<TabsContent value="solution" className="h-full mt-0">
|
|
||||||
{solution}
|
|
||||||
</TabsContent>
|
|
||||||
<TabsContent value="submission" className="flex-1 mt-0">
|
|
||||||
{submission}
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Check, Copy } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
export default function CopyButton() {
|
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
const { editor } = useCodeEditorStore();
|
|
||||||
|
|
||||||
const handleCopy = async () => {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(editor?.getValue() || "");
|
|
||||||
setCopied(true);
|
|
||||||
setTimeout(() => setCopied(false), 1500);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to copy text: ", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TooltipProvider delayDuration={0}>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
className="h-6 w-6 border-none px-1.5 py-0.5 disabled:opacity-100 hover:bg-muted"
|
|
||||||
onClick={handleCopy}
|
|
||||||
aria-label={copied ? "Copied" : "Copy to clipboard"}
|
|
||||||
disabled={copied}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"transition-all",
|
|
||||||
copied ? "scale-100 opacity-100" : "scale-0 opacity-0"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Check
|
|
||||||
className="stroke-emerald-500"
|
|
||||||
size={16}
|
|
||||||
strokeWidth={2}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"absolute transition-all",
|
|
||||||
copied ? "scale-0 opacity-0" : "scale-100 opacity-100"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Copy size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent className="px-2 py-1 text-xs">
|
|
||||||
Click to Copy
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
interface WorkspaceEditorFooterProps {
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function WorkspaceEditorFooter({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: WorkspaceEditorFooterProps) {
|
|
||||||
const { editor } = useCodeEditorStore();
|
|
||||||
const [position, setPosition] = useState<{ lineNumber: number; column: number } | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!editor) return;
|
|
||||||
|
|
||||||
const initialPosition = editor.getPosition();
|
|
||||||
if (initialPosition) {
|
|
||||||
setPosition({
|
|
||||||
lineNumber: initialPosition.lineNumber,
|
|
||||||
column: initialPosition.column,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispose = editor.onDidChangeCursorPosition((e) => {
|
|
||||||
setPosition({
|
|
||||||
lineNumber: e.position.lineNumber,
|
|
||||||
column: e.position.column,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => dispose.dispose();
|
|
||||||
}, [editor]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<footer
|
|
||||||
{...props}
|
|
||||||
className={cn("h-9 flex flex-none items-center bg-muted px-3 py-2", className)}
|
|
||||||
>
|
|
||||||
<div className="w-full flex items-center justify-end">
|
|
||||||
<span className="truncate">
|
|
||||||
{position
|
|
||||||
? `Row ${position.lineNumber}, Column ${position.column}`
|
|
||||||
: "Row -, Column -"}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip";
|
|
||||||
import { Paintbrush } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
export default function FormatButton() {
|
|
||||||
const { editor } = useCodeEditorStore();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TooltipProvider delayDuration={0}>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
aria-label="Format Code"
|
|
||||||
onClick={() => {
|
|
||||||
editor?.trigger("format", "editor.action.formatDocument", null);
|
|
||||||
}}
|
|
||||||
className="h-6 w-6 px-1.5 py-0.5 border-none hover:bg-muted"
|
|
||||||
>
|
|
||||||
<Paintbrush size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent className="px-2 py-1 text-xs">
|
|
||||||
Format Code
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
import { cn } from "@/lib/utils";
|
|
||||||
import CopyButton from "./copy-button";
|
|
||||||
import RedoButton from "./redo-button";
|
|
||||||
import UndoButton from "./undo-button";
|
|
||||||
import ResetButton from "./reset-button";
|
|
||||||
import FormatButton from "./format-button";
|
|
||||||
import LanguageSelector from "./language-selector";
|
|
||||||
|
|
||||||
interface WorkspaceEditorHeaderProps {
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function WorkspaceEditorHeader({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: WorkspaceEditorHeaderProps) {
|
|
||||||
return (
|
|
||||||
<header
|
|
||||||
{...props}
|
|
||||||
className={cn("h-8 flex flex-none items-center px-2 border-b", className)}
|
|
||||||
>
|
|
||||||
<div className="w-full flex items-center justify-between">
|
|
||||||
<div className="flex items-center gap-x-2">
|
|
||||||
<LanguageSelector />
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-x-2">
|
|
||||||
<ResetButton />
|
|
||||||
<UndoButton />
|
|
||||||
<RedoButton />
|
|
||||||
<FormatButton />
|
|
||||||
<CopyButton />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
import { getPath } from "@/lib/utils";
|
|
||||||
import { EditorLanguage } from "@prisma/client";
|
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
|
||||||
import LanguageServerConfig from "@/config/language-server";
|
|
||||||
import { EditorLanguageConfig } from "@/config/editor-language";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
export default function LanguageSelector() {
|
|
||||||
const { hydrated, language, setLanguage, setPath, setLspConfig } = useCodeEditorStore();
|
|
||||||
|
|
||||||
if (!hydrated) {
|
|
||||||
return <Skeleton className="h-6 w-16 rounded-2xl" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleValueChange = (lang: EditorLanguage) => {
|
|
||||||
setLanguage(lang);
|
|
||||||
setPath(getPath(lang));
|
|
||||||
setLspConfig(LanguageServerConfig[lang]);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select value={language} onValueChange={handleValueChange}>
|
|
||||||
<SelectTrigger className="h-6 px-1.5 py-0.5 border-none focus:ring-0 hover:bg-muted [&>span]:flex [&>span]:items-center [&>span]:gap-2 [&>span_svg]:shrink-0 [&>span_svg]:text-muted-foreground/80">
|
|
||||||
<SelectValue placeholder="Select language" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent className="[&_*[role=option]>span>svg]:shrink-0 [&_*[role=option]>span>svg]:text-muted-foreground/80 [&_*[role=option]>span]:end-2 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:flex [&_*[role=option]>span]:items-center [&_*[role=option]>span]:gap-2 [&_*[role=option]]:pe-8 [&_*[role=option]]:ps-2">
|
|
||||||
{Object.values(EditorLanguageConfig).map((langConfig) => (
|
|
||||||
<SelectItem key={langConfig.id} value={langConfig.id}>
|
|
||||||
<langConfig.icon size={16} aria-hidden="true" />
|
|
||||||
<span className="truncate text-sm font-semibold mr-2">
|
|
||||||
{langConfig.label}
|
|
||||||
</span>
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip";
|
|
||||||
import { Redo2 } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
export default function RedoButton() {
|
|
||||||
const { editor } = useCodeEditorStore();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TooltipProvider delayDuration={0}>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
aria-label="Redo Code"
|
|
||||||
onClick={() => {
|
|
||||||
editor?.trigger("redo", "redo", null);
|
|
||||||
}}
|
|
||||||
className="h-6 w-6 px-1.5 py-0.5 border-none hover:bg-muted"
|
|
||||||
>
|
|
||||||
<Redo2 size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent className="px-2 py-1 text-xs">
|
|
||||||
Redo Code
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip";
|
|
||||||
import { RotateCcw } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
import { TEMP_DEFAULT_EDITOR_VALUE } from "@/config/problem/value";
|
|
||||||
|
|
||||||
export default function ResetButton() {
|
|
||||||
const { editor, language } = useCodeEditorStore();
|
|
||||||
return (
|
|
||||||
<TooltipProvider delayDuration={0}>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
aria-label="Reset Code"
|
|
||||||
onClick={() => {
|
|
||||||
if (editor) {
|
|
||||||
const value = TEMP_DEFAULT_EDITOR_VALUE[language];
|
|
||||||
const model = editor.getModel();
|
|
||||||
if (model) {
|
|
||||||
const fullRange = model.getFullModelRange();
|
|
||||||
editor.executeEdits("reset-code", [
|
|
||||||
{
|
|
||||||
range: fullRange,
|
|
||||||
text: value,
|
|
||||||
forceMoveMarkers: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="h-6 w-6 px-1.5 py-0.5 border-none hover:bg-muted"
|
|
||||||
>
|
|
||||||
<RotateCcw size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent className="px-2 py-1 text-xs">
|
|
||||||
Reset Code
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip";
|
|
||||||
import { Undo2 } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useCodeEditorStore } from "@/store/useCodeEditorStore";
|
|
||||||
|
|
||||||
export default function UndoButton() {
|
|
||||||
const { editor } = useCodeEditorStore();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TooltipProvider delayDuration={0}>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
aria-label="Undo Code"
|
|
||||||
onClick={() => {
|
|
||||||
editor?.trigger("undo", "undo", null);
|
|
||||||
}}
|
|
||||||
className="h-6 w-6 px-1.5 py-0.5 border-none hover:bg-muted"
|
|
||||||
>
|
|
||||||
<Undo2 size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent className="px-2 py-1 text-xs">
|
|
||||||
Undo Code
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import WorkspaceEditorHeader from "@/app/(app)/playground/@workspace/@editor/components/header";
|
|
||||||
import WorkspaceEditorFooter from "@/app/(app)/playground/@workspace/@editor/components/footer";
|
|
||||||
|
|
||||||
interface WorkspaceEditorLayoutProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function WorkspaceEditorLayout({
|
|
||||||
children,
|
|
||||||
}: WorkspaceEditorLayoutProps) {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
<WorkspaceEditorHeader />
|
|
||||||
<div className="flex-1">
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
<WorkspaceEditorFooter />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
// import CodeEditor from "@/components/code-editor";
|
|
||||||
|
|
||||||
export default function WorkspaceEditorPage() {
|
|
||||||
// return <CodeEditor />;
|
|
||||||
return null;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { SquarePenIcon } from "lucide-react";
|
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
|
||||||
import { useTabsStore } from "@/store/useTabsStore";
|
|
||||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
||||||
|
|
||||||
interface WorkspaceLayoutProps {
|
|
||||||
editor: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function WorkspaceLayout({ editor }: WorkspaceLayoutProps) {
|
|
||||||
const { hydrated, workspaceTab, setWorkspaceTab } = useTabsStore();
|
|
||||||
|
|
||||||
if (!hydrated) return (
|
|
||||||
<div className="h-9 w-full flex items-center px-2 py-1 bg-muted">
|
|
||||||
<Skeleton className="h-full w-[94px] rounded-3xl" />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleTabChange = (value: string) => {
|
|
||||||
setWorkspaceTab(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tabs value={workspaceTab} onValueChange={handleTabChange} className="h-full flex flex-col">
|
|
||||||
<ScrollArea className="h-9 flex-none bg-muted px-1">
|
|
||||||
<TabsList className="gap-1 bg-transparent">
|
|
||||||
<TabsTrigger
|
|
||||||
value="editor"
|
|
||||||
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground rounded-full data-[state=active]:shadow-none"
|
|
||||||
>
|
|
||||||
<SquarePenIcon
|
|
||||||
className="-ms-0.5 me-1.5 opacity-60"
|
|
||||||
size={16}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
Editor
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
<ScrollBar orientation="horizontal" />
|
|
||||||
</ScrollArea>
|
|
||||||
<TabsContent value="editor" className="flex-1 mt-0">
|
|
||||||
{editor}
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import {
|
|
||||||
ResizableHandle,
|
|
||||||
ResizablePanel,
|
|
||||||
ResizablePanelGroup,
|
|
||||||
} from "@/components/ui/resizable";
|
|
||||||
import { PlaygroundHeader } from "@/features/playground/header";
|
|
||||||
|
|
||||||
interface PlaygroundLayoutProps {
|
|
||||||
problem: React.ReactNode;
|
|
||||||
workspace: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PlaygroundLayout({
|
|
||||||
problem,
|
|
||||||
workspace,
|
|
||||||
}: PlaygroundLayoutProps) {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
<PlaygroundHeader />
|
|
||||||
<ResizablePanelGroup direction="horizontal" className="p-2.5 pt-0">
|
|
||||||
<ResizablePanel
|
|
||||||
defaultSize={50}
|
|
||||||
className="border border-muted rounded-2xl"
|
|
||||||
>
|
|
||||||
{problem}
|
|
||||||
</ResizablePanel>
|
|
||||||
<ResizableHandle
|
|
||||||
withHandle
|
|
||||||
className="w-0.5 bg-transparent hover:bg-blue-500 mx-1"
|
|
||||||
/>
|
|
||||||
<ResizablePanel
|
|
||||||
defaultSize={50}
|
|
||||||
className="border border-muted rounded-2xl"
|
|
||||||
>
|
|
||||||
{workspace}
|
|
||||||
</ResizablePanel>
|
|
||||||
</ResizablePanelGroup>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import { redirect } from "next/navigation";
|
|
||||||
|
|
||||||
export default function PlaygroundPage() {
|
|
||||||
redirect("/problemset");
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user