mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 00:26:37 +08:00
refactor(repo): consolidate openflare-server to root and move subprojects to internal/apps
- Merge all files inside openflare-server to the repository root directory. - Relocate agent, relay, and flared subprojects from internal/ to internal/apps/. - Combine docker-compose files and update build context paths to root. - Update GitHub workflows and Dockerfiles to refer to new directories and package names. - Rewrite Go package imports across all files. - Resolve database renew test race condition and clean up docs.
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import * as React from "react"
|
||||
import {motion} from "motion/react"
|
||||
import {cn} from "@/lib/utils"
|
||||
import {FileTextIcon} from "lucide-react"
|
||||
|
||||
/**
|
||||
* 加载页面组件
|
||||
*
|
||||
* 用于统一显示加载状态
|
||||
* @example
|
||||
* ```tsx
|
||||
* <LoadingPage text="系统" badgeText="系统" />
|
||||
* ```
|
||||
* @param {string} text - 显示的文本内容,默认为"系统"
|
||||
* @param {string} badgeText - 显示的徽章文本,默认为"系统"
|
||||
* @returns {React.ReactNode} 加载页面组件
|
||||
*/
|
||||
|
||||
export function AppleSpinner({ className = "size-8 text-muted-foreground" }: { className?: string }) {
|
||||
const spokes = Array.from({ length: 12 })
|
||||
return (
|
||||
<div className={cn("relative flex items-center justify-center", className)}>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
@keyframes apple-spinner-fade {
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.15; }
|
||||
}
|
||||
.apple-spinner-spoke {
|
||||
animation: apple-spinner-fade 1.2s linear infinite;
|
||||
}
|
||||
`}} />
|
||||
<div className="relative size-full">
|
||||
{spokes.map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="apple-spinner-spoke absolute top-0 left-[46%] w-[8%] h-[28%] bg-current rounded-full"
|
||||
style={{
|
||||
transform: `rotate(${i * 30}deg)`,
|
||||
transformOrigin: "50% 178.5%",
|
||||
animationDelay: `${(i - 12) * 0.1}s`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载页面组件
|
||||
*
|
||||
* 用于统一显示加载状态
|
||||
*/
|
||||
export function LoadingPage(props: { text?: string; badgeText?: string }) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const _ = props
|
||||
return (
|
||||
<div className="absolute inset-0 z-50 overflow-hidden font-sans bg-background/80 backdrop-blur-md text-foreground flex items-center justify-center">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.96 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.25, ease: "easeOut" }}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
<AppleSpinner className="size-9 text-muted-foreground/80" />
|
||||
</motion.div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface LoadingStateProps extends React.ComponentProps<"div"> {
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: React.ComponentType<{ className?: string }>
|
||||
iconSize?: "sm" | "md" | "lg"
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载状态展示组件
|
||||
* 用于统一显示加载中的状态
|
||||
*/
|
||||
export function LoadingState({
|
||||
title = "加载中",
|
||||
description = "正在获取活动数据...",
|
||||
icon: Icon = FileTextIcon,
|
||||
className,
|
||||
iconSize = "md",
|
||||
}: LoadingStateProps) {
|
||||
const iconSizes = { sm: "size-8", md: "size-10", lg: "size-14" }
|
||||
const iconInnerSizes = { sm: "size-4", md: "size-5", lg: "size-7" }
|
||||
|
||||
return (
|
||||
<div className={cn("flex flex-col items-center justify-center py-12 text-center", className)}>
|
||||
<div className={cn(
|
||||
"rounded-full bg-muted flex items-center justify-center mb-2 animate-pulse",
|
||||
iconSizes[iconSize]
|
||||
)}>
|
||||
<Icon className={cn("text-muted-foreground", iconInnerSizes[iconSize])} />
|
||||
</div>
|
||||
|
||||
{title && (
|
||||
<h3 className="text-sm font-medium mb-1 animate-pulse">
|
||||
{title}
|
||||
</h3>
|
||||
)}
|
||||
|
||||
{description && (
|
||||
<p className="text-xs text-muted-foreground max-w-md animate-pulse">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 带边框的加载状态组件
|
||||
*/
|
||||
export function LoadingStateWithBorder(props: LoadingStateProps) {
|
||||
return (
|
||||
<div className="border border-dashed rounded-lg">
|
||||
<LoadingState {...props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user