- apps/api: FastAPI backend with Dockerfile - apps/web: Next.js frontend with Dockerfile - apps/sensor: Signal collection agent - packages: shared packages Co-Authored-By: Claude <noreply@anthropic.com>
119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* BorderBeam - Magic UI 流光邊框特效
|
|
* ===================================
|
|
* 用於 CRITICAL 風險等級的審核卡片
|
|
*
|
|
* Features:
|
|
* - 沿邊框流動的光束動畫
|
|
* - 可配置顏色、速度、寬度
|
|
* - 支援暫停/啟動
|
|
*/
|
|
|
|
import { cn } from '@/lib/utils'
|
|
import { type CSSProperties, type HTMLAttributes } from 'react'
|
|
|
|
// =============================================================================
|
|
// Types
|
|
// =============================================================================
|
|
|
|
export interface BorderBeamProps extends HTMLAttributes<HTMLDivElement> {
|
|
/** 動畫持續時間 (秒) */
|
|
duration?: number
|
|
/** 邊框寬度 (px) */
|
|
borderWidth?: number
|
|
/** 光束顏色 - 起始色 */
|
|
colorFrom?: string
|
|
/** 光束顏色 - 結束色 */
|
|
colorTo?: string
|
|
/** 動畫延遲 (秒) */
|
|
delay?: number
|
|
/** 光束尺寸 (px) */
|
|
size?: number
|
|
/** 是否暫停動畫 */
|
|
paused?: boolean
|
|
}
|
|
|
|
// =============================================================================
|
|
// Component
|
|
// =============================================================================
|
|
|
|
export function BorderBeam({
|
|
className,
|
|
duration = 6,
|
|
borderWidth = 2,
|
|
colorFrom = '#FF3300',
|
|
colorTo = '#FF6B35',
|
|
delay = 0,
|
|
size = 200,
|
|
paused = false,
|
|
...props
|
|
}: BorderBeamProps) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'pointer-events-none absolute inset-0 rounded-xl overflow-hidden',
|
|
'[mask-composite:intersect] [mask:linear-gradient(#fff_0_0)_content-box,linear-gradient(#fff_0_0)]',
|
|
className
|
|
)}
|
|
style={
|
|
{
|
|
'--duration': `${duration}s`,
|
|
'--delay': `${delay}s`,
|
|
'--color-from': colorFrom,
|
|
'--color-to': colorTo,
|
|
'--size': `${size}px`,
|
|
padding: `${borderWidth}px`,
|
|
} as CSSProperties
|
|
}
|
|
{...props}
|
|
>
|
|
<div
|
|
className={cn(
|
|
'absolute inset-0',
|
|
'bg-[conic-gradient(from_calc(var(--start,_0)*1turn),transparent_0%,var(--color-from)_10%,var(--color-to)_20%,transparent_30%)]',
|
|
'[animation:border-beam_var(--duration)_linear_infinite]',
|
|
paused && '[animation-play-state:paused]'
|
|
)}
|
|
style={{
|
|
width: `calc(100% + var(--size))`,
|
|
height: `calc(100% + var(--size))`,
|
|
top: '50%',
|
|
left: '50%',
|
|
transform: 'translate(-50%, -50%)',
|
|
animationDelay: `var(--delay)`,
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* CriticalGlow - CRITICAL 風險等級的脈動光暈
|
|
*/
|
|
export function CriticalGlow({
|
|
className,
|
|
intensity = 'medium',
|
|
...props
|
|
}: HTMLAttributes<HTMLDivElement> & { intensity?: 'low' | 'medium' | 'high' }) {
|
|
const intensityStyles = {
|
|
low: 'opacity-20',
|
|
medium: 'opacity-40',
|
|
high: 'opacity-60',
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'absolute inset-0 rounded-xl pointer-events-none',
|
|
'bg-gradient-to-br from-status-critical/20 via-transparent to-status-critical/10',
|
|
intensityStyles[intensity],
|
|
'animate-pulse',
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|