feat(home): replace homepage redirect with actual content

This commit is contained in:
cfngc4594 2025-04-17 16:45:49 +08:00
parent 93da6eb2cb
commit 5e7ef4a99d
12 changed files with 463 additions and 2 deletions

View File

@ -172,5 +172,32 @@
"WorkspaceEditorFooter": {
"Row": "Row",
"Column": "Column"
},
"HomePage": {
"MainView": {
"title": "Judge4c",
"description": "All in one place to support coding learning and teaching:",
"features": {
"feature1": "Integrated Language Services with Code Completion & Diagnostics",
"feature2": "Multi-language Support + Real-time Execution Feedback for Faster Learning",
"feature3": "World's First Open-Source Next.js + Monaco LSP Implementation"
},
"quickStart": "Quickstart",
"contactUs": "Contact Us"
},
"FAQs": {
"title": "Frequently Asked Questions",
"description": "Can't find your answer? Contact us!",
"questions": {
"question1": "Which code editor is used?",
"answer1": "Built with Microsoft's Monaco Editor",
"question2": "What programming languages are supported?",
"answer2": "Full support for C/C++ (with LSP integration), syntax highlighting for other languages",
"question3": "How do theme and language settings work?",
"answer3": "Themes auto-switch (system-aware) or can be manually set; language defaults to browser preference with manual override",
"question4": "What styling solutions are used for the editor and docs?",
"answer4": "Editor uses @shikijs/monaco themes, documentation rendered with github-markdown-css"
}
}
}
}

View File

@ -172,5 +172,32 @@
"WorkspaceEditorFooter": {
"Row": "行",
"Column": "列"
},
"HomePage": {
"MainView": {
"title": "Judge4c",
"description": "一站式助力编程学习与教学:",
"features": {
"feature1": "语言服务集成,内置代码补全与诊断",
"feature2": "多语言支持 + 实时运行反馈,学习更高效",
"feature3": "全球首个 Next.js + Monaco LSP 开源解决方案"
},
"quickStart": "即刻启程",
"contactUs": "联系我们"
},
"FAQs": {
"title": "常见问题",
"description": "未找到答案?欢迎联系我们!",
"questions": {
"question1": "使用什么代码编辑器?",
"answer1": "基于 @monaco-editor/react 开发",
"question2": "支持哪些编程语言?",
"answer2": "支持 C/C++ (集成LSP),其他语言支持语法高亮",
"question3": "如何设置主题和语言?",
"answer3": "主题支持自动切换(跟随系统)或手动设置;语言默认跟随浏览器,可手动修改",
"question4": "编辑器主题和文档样式方案?",
"answer4": "编辑器采用 @shikijs/monaco, 文档采用 github-markdown-css 样式"
}
}
}
}

BIN
public/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

View File

@ -1,5 +1,15 @@
import { redirect } from "next/navigation";
import FAQs from "@/components/faqs";
import { Header } from "@/components/header";
import { Footer } from "@/components/footer";
import { MainView } from "@/components/main-view";
export default function HomePage() {
redirect("/problemset");
return (
<>
<Header />
<MainView />
<FAQs />
<Footer />
</>
)
}

View File

@ -0,0 +1,13 @@
import { cn } from "@/lib/utils";
export function Container({
className,
...props
}: React.ComponentPropsWithoutRef<"div">) {
return (
<div
className={cn("mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", className)}
{...props}
/>
);
}

56
src/components/faqs.tsx Normal file
View File

@ -0,0 +1,56 @@
import { useTranslations } from "next-intl";
export default function FAQs() {
const t = useTranslations("HomePage.FAQs");
const faqs = [
{
id: 1,
question: t("questions.question1"),
answer: t("questions.answer1"),
},
{
id: 2,
question: t("questions.question2"),
answer: t("questions.answer2"),
},
{
id: 3,
question: t("questions.question3"),
answer: t("questions.answer3"),
},
{
id: 4,
question: t("questions.question4"),
answer: t("questions.answer4"),
}
];
return (
<div className="border-t">
<div className="mx-auto max-w-7xl px-6 py-8 sm:py-12 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-2xl font-bold leading-10 tracking-tight">
{t("title")}
</h2>
<p className="mt-6 text-base leading-7 text-foreground/50">
{t("description")}
</p>
</div>
<div className="mt-12">
<dl className="space-y-16 sm:grid sm:grid-cols-2 sm:gap-x-6 sm:gap-y-16 sm:space-y-0 lg:gap-x-10">
{faqs.map((faq) => (
<div key={faq.id}>
<dt className="text-base font-semibold leading-7 text-foreground">
{faq.question}
</dt>
<dd className="mt-2 text-base leading-7 text-foreground/75">
{faq.answer}
</dd>
</div>
))}
</dl>
</div>
</div>
</div>
);
}

47
src/components/footer.tsx Normal file
View File

@ -0,0 +1,47 @@
import { SVGProps } from "react";
import { siteConfig } from "@/config/site";
import { Container } from "@/components/container";
const navigation = {
social: [
{
name: "GitHub",
href: siteConfig.url.repo.github,
icon: (props: SVGProps<SVGSVGElement>) => (
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
<path
fillRule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clipRule="evenodd"
/>
</svg>
),
},
],
};
export function Footer() {
return (
<footer>
<Container>
<div className="flex items-center border-t pb-8 pt-8 justify-between">
<p className="text-sm">
&copy; Copyright {new Date().getFullYear()}. All rights reserved.
</p>
<div className="flex space-x-6">
{navigation.social.map((item) => (
<a
key={item.name}
href={item.href}
className="hover:text-foreground/50"
>
<span className="sr-only">{item.name}</span>
<item.icon aria-hidden="true" className="h-6 w-6" />
</a>
))}
</div>
</div>
</Container>
</footer>
);
}

25
src/components/header.tsx Normal file
View File

@ -0,0 +1,25 @@
import Link from "next/link";
import { Logo } from "@/components/logo";
import { Container } from "@/components/container";
import { ThemeToggle } from "@/components/theme-toggle";
import { LanguageSettings } from "@/components/language-settings";
export async function Header() {
return (
<header>
<nav>
<Container className="relative z-50 flex justify-between py-8">
<div className="relative z-10 flex items-center gap-16">
<Link href="/" aria-label="Home">
<Logo className="h-10 w-auto flex items-center" />
</Link>
</div>
<div className="flex items-center gap-6">
<LanguageSettings />
<ThemeToggle />
</div>
</Container>
</nav>
</header>
);
}

94
src/components/logo.tsx Normal file
View File

@ -0,0 +1,94 @@
export function Logomark(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 384 384" aria-hidden="true" {...props}>
<path
className="fill-background"
d="M.06 192C.06 129.06.07 66.11 0 3.17 0 .78.23 0 2.97 0 129 .1 255.03.1 381.06 0c2.81 0 2.93.89 2.93 3.2-.06 87.42-.05 174.85-.05 262.27-1.87-.03-1.61-1.66-1.89-2.72-2.56-9.67-7.95-16.88-17.62-20.35-3.03-1.09-3.65-3.6-3.85-6.27-.98-13.28-4.67-25.77-10.82-37.53-16.12-30.84-41.51-49.18-75.56-55.74-1.22-.24-2.46-.54-3.7-.59-3.29-.15-4.72-1.95-5.55-5.01-3.15-11.58-10.24-19.94-21.49-24.29-8.49-3.28-14.21-9.04-17.48-17.41-3.17-8.12-8.76-14.14-16.14-18.62-5.02-3.05-5.06-3.27-2.51-8.48 7.16-14.65 7.27-29.56 1.64-44.69-1.35-3.62-3.73-6.05-7.4-7.41-20.05-7.42-38.54-4.89-55.25 8.66-5.79 4.7-5.56 4.65-11.45-.05-17.4-13.9-36.42-16.37-56.93-7.72-2.47 1.04-4.07 2.77-5.07 5.2-6.28 15.23-6.38 30.35.75 45.36.48 1.02.99 2.02 1.46 3.04 1 2.21.46 3.85-1.7 4.99-9.39 4.95-15.56 12.6-19.44 22.41-2.65 6.72-7.79 11.21-14.5 13.84-10.28 4.03-17.75 10.92-22.05 21.18-2.82 6.73-2.57 13.74-1.71 20.67.78 6.3-.23 12.23-3.72 17.18-4.58 6.5-8.49 13.2-10.85 20.79-.32.32-.67.36-1.05.11Z"
/>
<path
className="fill-background"
d="M383.94 275.97c0 35.11-.03 70.22.06 105.33 0 2.24-.45 2.69-2.69 2.68-126.21-.07-252.42-.07-378.63.02-2.75 0-2.66-1.06-2.66-3.08.05-58.97.04-117.95.04-176.92 1.96.13 1.77 1.87 2.1 3.04 1.37 4.88 3.54 9.28 6.67 13.3 5.44 6.97 7.85 14.61 6.69 23.74-2.36 18.54 5.94 32.33 23.19 39.67 7.76 3.3 13.21 8.55 16.41 16.47 6.87 16.97 22.02 25.44 40.15 22.98 7.87-1.07 15.16.43 21.52 5.51 6.18 4.95 13.02 8.25 21.11 8.72 6.36.36 12.41-.49 18.16-3.34 4.88-2.42 4.84-2.33 8.46 1.68 4.28 4.74 9.5 8.05 15.72 9.69 2.18.57 4.38 1.07 6.61 1.35 7.91.99 13.9 4.9 18.61 11.32 6.83 9.31 16.25 13.75 27.79 13.52 4.14-.08 8.19-.94 11.99-2.7 7.59-3.52 15.15-3.44 22.88-.36 15.81 6.29 30.17 2.48 40.83-10.85 4.99-6.24 11.09-9.97 19.14-11.24 17.78-2.79 27.83-13.47 30.1-31.33.89-7.04 4.45-12.44 9.87-16.61 6.78-5.22 11.52-11.68 13.87-19.93.3-1.06.2-2.66 2.02-2.67Z"
/>
<path
className="fill-[#010101]"
d="M383.94 275.97c-.83 2.43-1.55 4.9-2.5 7.28-2.42 6.05-6.22 11.11-11.51 14.91-6.46 4.65-9.96 10.73-10.96 18.7-2.15 17.17-13.95 28.63-31.55 30.89-7.25.93-12.86 4.22-17.27 9.97-10.99 14.33-26.21 18.51-42.86 11.65-7.11-2.93-13.93-2.9-20.97.21-15.39 6.79-31.71 2.56-41.71-10.88-4.75-6.38-10.65-10.16-18.65-11.03-9.72-1.06-17.82-5.42-23.81-13.27-1.1-1.44-1.85-1.4-3.32-.63-14.78 7.73-28.85 6.37-41.95-3.8-6.75-5.24-14.14-7.02-22.47-5.66-16.4 2.67-33.19-6.43-39.43-21.96-3.58-8.91-9.29-14.83-18.25-18.45-16.48-6.65-24.89-22.89-22.11-41.44.91-6.06.1-11.94-3.41-16.82-4.82-6.71-9.01-13.6-11.14-21.63v-8.25c.9-1.17-.08-2.66.67-3.85.76-6.1 3.2-11.55 7.03-16.26 5.67-6.97 7.87-14.56 6.71-23.64-2.38-18.74 6.31-33.1 23.85-40.38 7.7-3.2 12.95-8.5 15.95-16.32 3.55-9.22 9.82-16.16 18.91-20.24 2.42-1.09 1.95-2.03.99-3.84-8.65-16.23-9.26-32.81-2.04-49.72 1.03-2.41 2.64-3.98 5.1-5.1 20.65-9.46 43.82-5.78 60.78 9.99 2 1.86 2.99 2.09 5.15.07 16.67-15.64 40.28-19.52 60.44-10.29 2.66 1.22 4.48 2.9 5.62 5.61 7.02 16.67 6.43 33.05-1.97 49.05-1.27 2.43-1.3 3.22 1.4 4.5 8.31 3.94 14.51 10.26 17.78 18.89 3.37 8.89 9.33 14.58 18.12 18.12 11.51 4.64 18.66 13.48 21.62 25.51.57 2.33 1.44 3.09 3.81 3.4 47.67 6.27 84.43 42.52 91.07 90.31.84 6.07 2.14 9.65 8.27 12.22 8.22 3.46 12.02 11.19 13.88 19.74.15.68-.16 1.54.73 1.95v10.5Z"
/>
<path
className="fill-[#7fdeb4]"
d="M143.03 57.76c-10.68-.95-19.46 3.13-27.48 9.35-6.46 5.01-13.74 5.46-21.64 4.95-5.94-.38-8.74-3.27-10.97-8.09-5.22-11.32-5.9-22.79-1.89-34.57.63-1.84 1.53-3.14 3.52-3.96 24.45-9.96 53.45 5.76 58.45 32.32Z"
/>
<path
className="fill-[#36d299]"
d="M161.25 27.31c2.81 6.57 6.67 12.69 8.3 19.77 1.77 7.69 3.39 15.38 2.23 23.34-6.18-1.98-10.25-7.45-16.2-9.85-.54-.22-.81-1.5-.92-2.32-.86-6.37-2.85-12.38-5.98-17.97-.97-1.73-.78-2.83.58-4.17 3.57-3.53 7.37-6.7 11.98-8.79Z"
/>
<path
className="fill-[#60d8a6]"
d="M161.25 27.31c11.43-5.8 23.14-6.24 35.16-1.95 1.98.71 3.08 1.88 3.71 3.78 4.66 14 3.27 27.26-4.71 39.77-1.08 1.7-2.32 2.5-4.49 2.61-5.59.29-11.15 1.59-16.71-.15-.83-.26-1.61-.63-2.42-.96-1.11-2.96-.7-6.1-.91-9.13-.68-10.13-3.46-19.55-8.16-28.49-.88-1.67-2.46-3.26-1.46-5.48Z"
/>
<path
className="fill-[#fe879d]"
d="M95.27 83.43c-8.59 14.57-14.79 30.1-18.91 46.5-4.29 17.06-5.47 34.47-4.14 51.83 2.48 32.47 13.57 62 33.23 88.09 12.39 16.44 27.57 29.94 44.88 41.03.96.62 2.04 2.05 3.56.84 1.38 3 .96 6.36 1.88 9.47.5 1.69-1.13 2.07-2.13 2.61-9.68 5.25-19.43 5.19-28.14-1.53-10.1-7.79-20.86-10.96-33.55-9.03-11.57 1.76-22.43-4.68-26.72-15.57-4.64-11.76-12.56-19.65-24.37-24.23-10.57-4.1-16.67-14.61-15.36-26.13.96-8.49.87-16.66-2.93-24.5-1.42-2.94-3.22-5.61-5.22-8.18-8.11-10.43-8.15-22.62.02-33.06 6.97-8.91 9.88-18.76 8.33-30.08-1.97-14.39 4.02-24.32 17.55-29.82 9.88-4.02 17.22-10.82 20.8-20.81 4.35-12.13 16.77-20.86 31.24-17.43Z"
/>
<path
className="fill-[#fe9caf]"
d="M95.27 83.43c11.52.99 21.33-2.59 30.52-9.68 8.55-6.59 18.26-6.61 27.76-1.28 2.06 1.15 4.01 2.54 5.88 3.99 8.53 6.57 18.04 8.43 28.59 6.69 12.63-2.08 23.72 4.22 28.42 16.17 4.32 10.97 11.72 18.64 22.72 22.87 7.27 2.79 12.26 7.87 15.21 15.07.98 2.4.66 3.13-2.11 3.26-12.94.58-25.41 3.38-37.3 8.61-4.7 2.07-5.35 3.12-4.84 8.32-2.15 2.86-5.15 4.39-8.48 5.39-3.96-3.18-5.57-3.26-9.52-.11-23.63 18.86-37.14 43.27-39.94 73.44-.28 3.03-1.09 4.64-4.24 5.81-14.27 5.3-21.6 23.3-16.29 39.24 2.36 7.09 6.63 12.78 12.68 17.18 4.64 3.37 8.45 7.4 9.57 13.32-1.37 1.34-1.55 1.43-3.67.19-4.43-2.58-8.62-5.55-12.66-8.68-35.5-27.52-57.55-63.3-64.62-107.72-5.96-37.41.19-73.06 18.08-106.56 1.09-2.04 1.92-4.4 4.25-5.54Z"
/>
<path
className="fill-[#dfdfdf]"
d="M216.73 160.61c-4.68 2.62-6.66 7.56-9.43 11.65-5.06 7.49-9.16 15.58-12.25 24.13-.2.55-.69 1.1 0 1.64-.04 1.69-1.58 1.7-2.58 2.25-2.19 1.2-4.33 2.43-6.03 4.3-4.96 5.43-5.02 11.86-.23 17.42.93 1.08 2.39 1.91 2.1 3.7-.99.13-1.58.65-1.55 1.7.13 4.18-1.27 8.27-.77 12.47-6.85.04-13.71.03-20.56.17-1.96.04-2.43-.45-2.23-2.5 2.57-26.81 14.35-48.64 35.29-65.5 3.16-2.55 5.06-5.12 3.12-9.2 2.52-2.28 5.6-3.68 8.48-5.39 1.62 2.29 3.77 3.46 6.62 3.16Z"
/>
<path
className="fill-[#e7e7e7]"
d="M306.62 245.87c-3.67-.19-7.39.62-11.01-.54-1.41-4.41-2.69-5.32-7.67-5.32-32.61 0-65.21 0-97.82 0-1.37 0-2.74-.08-4.11-.13-1.83-5.09-1.36-9.95 1.4-14.6 1.74-.42 3.12.59 4.61 1.18 7.22 2.83 14.31 3.04 21.28-.83 7.76-4.3 9.9-12.11 5.33-19.65-.64-1.06-1.44-2.05-1.59-3.35 1.42-3.86 2.22-7.81 1.6-11.94-.37-2.44-1.2-4.62-4.05-5.07-2.74-.43-4.49.84-5.41 3.39-.71 2.06-.31 4.18-.41 6.27-.12 2.44-1.18 3.8-3.74 3.3-3.11-.61-6.15.52-9.23.25-2.78-.79-1.58-2.68-1.01-4.19 3.22-8.54 7.53-16.53 12.57-24.12 1.58-2.38 3.23-4.73 4.86-7.08 1.14-1.63 2.56-2.62 4.53-2.83 56.65-25.39 119.47 6.19 132.33 66.56.7 3.28.79 6.7 1.48 9.99.51 2.45-.27 2.91-2.57 2.89-11.24-.11-22.48-.06-33.72-.04-4.98 0-6.29 1.04-7.62 5.86Z"
/>
<path
className="fill-[#010101]"
d="M217.38 202.52c-5.83 2.35-9.06.22-9.1-5.99-.02-2.7 0-5.41 0-8.11 1.12-3.12 3.28-4.7 6.62-4.07 3.45.65 4.64 3.22 4.51 6.36-.17 4 1.19 8.32-2.03 11.81Z"
/>
<path
className="fill-[#010101]"
d="M305.48 188.41c.02 2.71.06 5.42.04 8.13-.05 6.19-3.37 8.33-9.16 5.96-3.42-4.75-2.11-10.02-1.34-15.08.33-2.19 2.63-3.22 4.96-3.21 2.85.02 4.59 1.6 5.51 4.21Z"
/>
<path
className="fill-[#010101]"
d="M257.29 208.55c-6.26-.04-11.39-2.21-15.5-6.63-2.43-2.61-2.48-5.74-.31-8.01 2.25-2.34 5.17-2.38 8.02-.09 5.96 4.78 8.79 4.78 14.75 0 2.87-2.29 5.75-2.26 8.01.09 2.16 2.24 2.11 5.45-.28 8.03-4.01 4.31-9.03 6.46-14.7 6.61Z"
/>
<path
className="fill-[#fe9caf]"
d="M188.32 225.7c-2.01-2.5-4.68-4.46-5.79-7.68-2.25-6.52.22-12.82 6.95-17.1 1.76-1.12 3.71-1.94 5.58-2.9 3.66-.04 7.25-1.52 10.99-.3 1.69.55 1.57-.95 1.68-2.06.25-2.41-.63-4.91.56-7.25 1.98 1.76 1.17 4.12 1.21 6.22.13 6.81.29 7.05 6.84 7.54.37.03.71.17 1.04.34 8.07 9.32 4.73 17.62-.7 22.05-5.63 4.59-12.25 5.83-19.34 4.58-3.22-.57-6.2-1.81-9.02-3.45Z"
/>
<path
className="fill-[#fe9caf]"
d="M305.48 188.41c1.11 2.12.45 4.39.49 6.59.04 2.11.16 3 2.9 2.56 5.98-.97 11.73.54 16.63 4.06 9.39 6.75 8.44 19.03-1.74 24.93-8.21 4.76-19.69 3.82-27-2.21-5.83-4.81-6.81-13.05-2.27-19.05.67-.89 1.25-1.85 1.87-2.79 7.69-1.21 7.66-1.21 7.84-9.39.04-1.63-.5-3.51 1.28-4.7Z"
/>
<path
className="fill-[#fe879d]"
d="M197.24 301.44c4.15 11.87 11.14 22.12 18.85 31.84 7.27 9.16 15.81 17.13 25.03 24.34.56.44 1.33.59 2 .88-10.51 5.62-22.32 3.25-29.33-6.3-6.74-9.18-15.39-14.48-26.83-15.77-11.4-1.28-19.17-8.97-20.59-20.44-1.44-11.67-6.88-20.5-16.26-27.42-9.31-6.87-11.67-19.34-5.99-29.16 2.89-5 7.14-8.11 13.02-8.11 44.35-.03 88.7.02 133.05.05-1.31 1.09-2.88.59-4.32.59-31.81.03-63.63.08-95.44-.06-3.66-.02-4.78 1.04-4.48 4.61.76 8.91 2.12 17.7 4.49 26.33.39 1.44 1.01 2.82.82 4.37-2.15.44-2.96-1.47-4.21-2.51-2.11-1.76-4.14-2.18-6.28-.17-1.99 1.87-2.17 4.34-.25 6.64 3.23 3.89 7.05 6.93 12.11 8.19 1.63.4 3.51.45 4.61 2.09Z"
/>
<path
className="fill-[#fe9caf]"
d="M290.19 251.35c3.37-.6 5.2-2.59 5.42-6.02 3.71-.66 7.41-1.05 11.01.53.92 4.11 3.57 5.48 7.66 5.44 12.85-.15 25.71-.05 38.56-.05 15.04 0 23.41 11.8 18.66 26.33-1.56 4.77-4.31 8.71-8.38 11.64-9.15 6.58-14.1 15.41-15.35 26.64-1.27 11.35-9.63 19.37-21.29 20.69-10.67 1.21-19 6.11-25.48 14.6-7.57 9.93-17.82 12.8-29.16 7.94-9.59-4.11-19.08-4.07-28.74-.59-1.38.7-2.36-.1-3.36-.88-10.91-8.46-20.53-18.2-28.69-29.33-4.58-6.25-8.6-12.87-11.99-19.83-1.08-2.22-3.02-4.42-1.79-7.29 2.31-1.04 4.85-.91 7.27-1.46 5.58-1.28 9.99-4.28 13.43-8.78 1.68-2.19 1.79-4.45-.22-6.37-2.03-1.94-4.37-1.7-6.35.16-2.74 2.58-5.52 5-9.29 5.98-4.86 1.25-9.79-.55-11.86-4.42-2.8-8.6-4.17-17.48-5.23-26.42-.13-1.12-.19-2.24-.17-3.37.07-4.44.49-4.86 4.92-4.86 32.11 0 64.23 0 96.34-.01 1.36 0 2.75.24 4.09-.25Z"
/>
<path
className="fill-[#010101]"
d="M197.24 301.44c-6.68-1.13-12.59-3.7-17.02-9.07-2.76-3.34-2.84-6.59-.16-8.87 2.66-2.26 5.52-1.82 8.45 1.28.84.89 1.49 2 2.75 2.41 5.78 4.24 12.54 3.8 17.52-1.17.7-.7 1.26-1.55 2-2.21 2.34-2.11 4.88-2.35 7.43-.42 2.45 1.84 2.94 4.98 1.01 7.64-4.67 6.43-11.14 9.69-19 10.29-.99.08-1.98.09-2.97.13Z"
/>
<path
className="fill-[#010101]"
d="M314.57 301.38c-7.79-.32-14.39-3.28-19.37-9.51-2.45-3.05-2.36-6.11.12-8.31 2.53-2.24 5.86-2.15 8.19.91 5.58 7.34 16.52 7.44 22.21-.1 2.2-2.91 5.38-3 7.9-.95 2.58 2.1 2.81 5.31.46 8.29-4.94 6.25-11.52 9.29-19.51 9.66Z"
/>
<path
className="fill-[#010101]"
d="M256.94 323.12c-7.82-.3-14.41-3.28-19.42-9.48-2.44-3.03-2.36-6.13.1-8.32 2.53-2.25 5.84-2.17 8.19.89 5.66 7.39 16.54 7.41 22.21-.09 2.2-2.91 5.39-3.01 7.91-.97 2.6 2.11 2.84 5.28.48 8.28-4.93 6.26-11.51 9.3-19.47 9.69Z"
/>
</svg>
);
}
export function Logo(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 384 384" aria-hidden="true" {...props}>
<Logomark width="384" height="384" />
</svg>
);
}

View File

@ -0,0 +1,62 @@
import Link from "next/link";
import Image from "next/image";
import { siteConfig } from "@/config/site";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import { Container } from "@/components/container";
import { TypingEffect } from "@/components/typing-effect";
export function MainView() {
const t = useTranslations("HomePage.MainView");
return (
<div className="overflow-hidden py-10 sm:py-16 lg:pb-16 xl:pb-18">
<Container>
<div className="lg:grid lg:grid-cols-12 lg:gap-x-8 lg:gap-y-20">
<div className="relative z-10 mx-auto max-w-2xl lg:col-span-7 lg:max-w-none lg:pt-6 xl:col-span-6">
<h1 className="text-4xl font-medium tracking-tight">
{t("title")}
</h1>
<p className="mt-6 text-lg text-foreground/75">
{t("description")}
</p>
<div className="mt-6 text-lg text-foreground/50">
<TypingEffect />
</div>
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
<Button
size="sm"
className="rounded-2xl bg-muted text-muted-foreground shadow hover:bg-muted/50"
asChild
>
<Link href="/problemset" prefetch>
{t("quickStart")}
</Link>
</Button>
<Button
size="sm"
className="rounded-2xl bg-accent text-accent-foreground shadow hover:bg-accent/50"
>
<Link href={siteConfig.url.repo.github}>
{t("contactUs")}
</Link>
</Button>
</div>
</div>
<div className="relative mt-10 sm:mt-20 lg:col-span-5 lg:row-span-2 lg:mt-0 xl:col-span-6">
<div>
<Image
src="/background.png"
alt=""
width={2275}
height={1280}
className="rounded-2xl"
priority
/>
</div>
</div>
</div>
</Container>
</div>
);
}

View File

@ -0,0 +1,48 @@
"use client";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
function SunIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" {...props}>
<path d="M12.5 10a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0Z" />
<path
strokeLinecap="round"
d="M10 5.5v-1M13.182 6.818l.707-.707M14.5 10h1M13.182 13.182l.707.707M10 15.5v-1M6.11 13.889l.708-.707M4.5 10h1M6.11 6.111l.708.707"
/>
</svg>
);
}
function MoonIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" {...props}>
<path d="M15.224 11.724a5.5 5.5 0 0 1-6.949-6.949 5.5 5.5 0 1 0 6.949 6.949Z" />
</svg>
);
}
export function ThemeToggle() {
const { resolvedTheme, setTheme } = useTheme();
const otherTheme = resolvedTheme === "dark" ? "light" : "dark";
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<Button
size="icon"
variant="outline"
className="flex h-6 w-6 items-center justify-center rounded-md transition"
aria-label={mounted ? `Switch to ${otherTheme} theme` : "Toggle theme"}
onClick={() => setTheme(otherTheme)}
>
<SunIcon className="h-5 w-5 stroke-foreground dark:hidden" />
<MoonIcon className="hidden h-5 w-5 stroke-foreground dark:block" />
</Button>
);
}

View File

@ -0,0 +1,52 @@
"use client";
import { motion } from "framer-motion";
import { useTranslations } from "next-intl";
import { useEffect, useState, useMemo } from "react";
export function TypingEffect() {
const t = useTranslations("HomePage.MainView.features");
const texts = useMemo(
() => [t("feature1"), t("feature2"), t("feature3")],
[t]
);
const [index, setIndex] = useState(0);
const [displayText, setDisplayText] = useState("");
const [isDeleting, setIsDeleting] = useState(false);
useEffect(() => {
const handleTyping = () => {
const currentText = texts[index];
if (isDeleting) {
setDisplayText(currentText.substring(0, displayText.length - 1));
} else {
setDisplayText(currentText.substring(0, displayText.length + 1));
}
if (!isDeleting && displayText === currentText) {
setTimeout(() => setIsDeleting(true), 1000);
} else if (isDeleting && displayText === "") {
setIsDeleting(false);
setIndex((prevIndex) => (prevIndex + 1) % texts.length);
}
};
const typingSpeed = isDeleting ? 50 : 100;
const timer = setTimeout(handleTyping, typingSpeed);
return () => clearTimeout(timer);
}, [displayText, isDeleting, index, texts]);
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="inline-block"
>
{displayText}
<span className="blinking-cursor">|</span>
</motion.div>
);
}