diff --git a/src/app/me/components/ActivityTimeline.tsx b/src/app/me/components/ActivityTimeline.tsx deleted file mode 100644 index 42b301f..0000000 --- a/src/app/me/components/ActivityTimeline.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { memo } from "react" -import { formatDistanceToNow } from "date-fns" -import { - History, - LogIn, - LogOut, - UserPlus, - ShieldCheck, - Key, - FolderPlus, - GitCommit, - GitPullRequest, - AlertCircle, - Settings, - Image as ImageIcon, -} from "lucide-react" -import type { UserActivityItem } from "@/client/model" -import { - Empty, - EmptyDescription, - EmptyHeader, - EmptyMedia, - EmptyTitle, -} from "@/components/ui/empty" -import { Separator } from "@/components/ui/separator" -import { Skeleton } from "@/components/ui/skeleton" -import type { ComponentType, SVGProps } from "react" - -interface ActivityTimelineProps { - items: UserActivityItem[] - isLoading?: boolean -} - -const ICON_MAP: Record>> = { - login: LogIn, - logout: LogOut, - register: UserPlus, - password_change: ShieldCheck, - ssh_key_add: Key, - project_create: FolderPlus, - commit: GitCommit, - pull_request_create: GitPullRequest, - issue_create: AlertCircle, - profile_update: Settings, - avatar_upload: ImageIcon, -} - -export const ActivityTimeline = memo(function ActivityTimeline({ - items, - isLoading, -}: ActivityTimelineProps) { - if (isLoading) { - return ( -
- {[...Array(6)].map((_, i) => ( -
- -
- - -
-
- ))} -
- ) - } - - if (items.length === 0) { - return ( - - - - - - No recent activity - 暂无最近动态 - - - ) - } - - return ( -
- {items.map((item, index) => { - const Icon = ICON_MAP[item.action] || History - return ( -
-
-
-
-
-

- - {item.title} - - {item.resource_name && ( - <> - {" "} - in{" "} - - {item.resource_name} - - - )} -

- -
-
- {index < items.length - 1 && } -
- ) - })} -
- ) -}) diff --git a/src/app/me/components/ContributionHeatmap.tsx b/src/app/me/components/ContributionHeatmap.tsx deleted file mode 100644 index 7ee625f..0000000 --- a/src/app/me/components/ContributionHeatmap.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { useMemo } from "react"; -import { format, parseISO, eachDayOfInterval, isSameDay } from "date-fns"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; -import type { ContributionHeatmapResponse } from "@/client/model"; -import { t } from "@/i18n/T"; - -interface ContributionHeatmapProps { - data: ContributionHeatmapResponse; -} - -export function ContributionHeatmap({ data }: ContributionHeatmapProps) { - const { heatmap, total_contributions, start_date, end_date } = data; - - const days = useMemo(() => { - const start = parseISO(start_date); - const end = parseISO(end_date); - return eachDayOfInterval({ start, end }); - }, [start_date, end_date]); - - const getColor = (count: number) => { - if (count === 0) return { bg: "var(--heatmap-0)", darkBg: "var(--heatmap-0)" }; - if (count < 3) return { bg: "var(--heatmap-1)", darkBg: "var(--heatmap-1)" }; - if (count < 6) return { bg: "var(--heatmap-2)", darkBg: "var(--heatmap-2)" }; - if (count < 10) return { bg: "var(--heatmap-3)", darkBg: "var(--heatmap-3)" }; - return { bg: "var(--heatmap-4)", darkBg: "var(--heatmap-4)" }; - }; - - // Group days by weeks (Sunday to Saturday) - const weeks = useMemo(() => { - const result: Date[][] = []; - let currentWeek: Date[] = []; - - // Pad the first week if it doesn't start on Sunday - const firstDay = days[0]; - const firstDayOfWeek = firstDay.getDay(); // 0 is Sunday - for (let i = 0; i < firstDayOfWeek; i++) { - // currentWeek.push(subDays(firstDay, firstDayOfWeek - i)); // Using null for padding - } - - days.forEach((day) => { - if (day.getDay() === 0 && currentWeek.length > 0) { - result.push(currentWeek); - currentWeek = []; - } - currentWeek.push(day); - }); - - if (currentWeek.length > 0) { - result.push(currentWeek); - } - - return result; - }, [days]); - - return ( -
-
-

- {t("me.profile.contributions_in_year", { count: total_contributions })} -

-
- -
-
-
-
- Mon - Tue - Wed - Thu - Fri - Sat - Sun -
-
- {weeks.map((week, weekIdx) => ( -
- {/* Month labels would go here */} - {Array.from({ length: 7 }).map((_, dayIdx) => { - const day = week.find(d => d.getDay() === (dayIdx + 1) % 7); - if (!day) return
; - - const entry = heatmap.find(h => isSameDay(parseISO(h.date), day)); - const count = entry?.count ?? 0; - - return ( - - - -
- - -

- {t("me.profile.contributions_on_date", { count, date: format(day, "MMM d, yyyy") })} -

-
- - - ); - })} -
- ))} -
-
- -
- {t("me.profile.less")} -
-
-
-
-
- {t("me.profile.more")} -
-
-
-
- ); -} \ No newline at end of file diff --git a/src/app/me/components/CreateProjectModal.tsx b/src/app/me/components/CreateProjectModal.tsx deleted file mode 100644 index ef7f5ce..0000000 --- a/src/app/me/components/CreateProjectModal.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import { useState } from "react"; -import { useNavigate } from "react-router-dom"; -import { useCreateProjectMutation } from "@/hooks/useProjectsQuery"; -import { - X, - AtSign, - Type, - AlignLeft, - Globe, - Loader2, - Rocket, - ShieldCheck, - AlertCircle -} from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { t } from "@/i18n/T"; - -interface CreateProjectModalProps { - onClose: () => void; -} - -export function CreateProjectModal({ onClose }: CreateProjectModalProps) { - const navigate = useNavigate(); - const createMutation = useCreateProjectMutation(); - - const [form, setForm] = useState({ - name: "", - display_name: "", - description: "", - is_public: true - }); - const [error, setError] = useState(null); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!form.name.trim() || !form.display_name.trim()) return; - - try { - setError(null); - const res = await createMutation.mutateAsync({ - name: form.name.trim(), - display_name: form.display_name.trim(), - description: form.description.trim() || null, - is_public: form.is_public - }); - - onClose(); - if (res?.project) { - navigate(`/${res.project.name}/repos`); - } - } catch (err: unknown) { - const apiError = err as { response?: { data?: { message?: string } } }; - setError(apiError.response?.data?.message || t("me.create_project.create_failed")); - } - }; - - return ( -
-
e.stopPropagation()} - > - {/* Header */} -
-
-
- -
-
-

{t("me.create_project.title")}

-

{t("me.create_project.subtitle")}

-
-
- -
- -
-
- {/* Project Slug */} -
-
- - {t("me.create_project.slug_required")} -
- setForm({...form, name: e.target.value.toLowerCase().replace(/\s+/g, '-')})} - className="h-11 text-[15px] font-mono" - style={{ backgroundColor: "var(--surface-elevated)", border: "none", colorScheme: "dark" }} - /> -

- {t("me.create_project.slug_hint")} -

-
- - {/* Display Name */} -
-
- - {t("me.create_project.display_name_required")} -
- setForm({...form, display_name: e.target.value})} - className="h-11 text-[15px]" - style={{ backgroundColor: "var(--surface-elevated)", border: "none", colorScheme: "dark" }} - /> -
- - {/* Description */} -
- -