diff --git a/app/components/Community.tsx b/app/components/Community.tsx new file mode 100644 index 0000000..d5593b0 --- /dev/null +++ b/app/components/Community.tsx @@ -0,0 +1,139 @@ +import { Button } from "./ui/button"; +import { Card, CardContent } from "./ui/card"; +import { Badge } from "./ui/badge"; +import { + ExternalLink, + MessageCircle, + Github, + BookOpen, + GraduationCap, +} from "lucide-react"; + +export function Community() { + return ( +
+
+
+

+ 成为{" "} + + 社区 + {" "} + 的一员 +

+

+ 与来自世界各地的开发者一起学习、成长、创造。每个人的贡献都让社区变得更好。 +

+
+ + {/* Main CTA Card */} +
+ + +
+
+ +
+

+ 内卷知识库 +

+

+ 探索我们精心整理的技术文档、教程和工具。从基础到进阶,应有尽有。 +

+ +
+
+
+
+ + {/* Action Cards */} +
+ + +
+
+ +
+

GitHub 仓库

+

+ 查看源代码,提交 Issue,参与项目讨论。 +

+ +
+
+
+ + + +
+
+ +
+

Discord 社区

+

+ 实时交流,分享经验,结识志同道合的朋友。 +

+ +
+
+
+ + + +
+
+ +
+

文献资料

+

+ 访问我们在 Zotero 的文献库,获取精选学术资源。 +

+ +
+
+
+
+
+
+ ); +} diff --git a/app/components/ExternalFrame.tsx b/app/components/ExternalFrame.tsx new file mode 100644 index 0000000..48d2ff6 --- /dev/null +++ b/app/components/ExternalFrame.tsx @@ -0,0 +1,45 @@ +import * as React from "react"; + +type Props = { + src: string; + title?: string; + height?: number | string; // e.g. 480 or "70vh" + className?: string; + allowFullScreen?: boolean; + sandbox?: string; // override if needed + referrerPolicy?: React.IframeHTMLAttributes["referrerPolicy"]; +}; + +export function ExternalFrame({ + src, + title = "Embedded Content", + height = "70vh", + className, + allowFullScreen = true, + sandbox, + referrerPolicy = "no-referrer", +}: Props) { + // Keep the API conservative by default; caller can override sandbox if needed. + const sandboxAttrs = + sandbox ?? "allow-scripts allow-popups allow-forms allow-presentation"; + + return ( +
+