fix: 优化docker 镜像
This commit is contained in:
@@ -1,10 +1,19 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { StatCard } from './StatCard'
|
||||
import { useSituationStore } from '@/store/situationStore'
|
||||
import { useReplaySituation } from '@/hooks/useReplaySituation'
|
||||
import { usePlaybackStore } from '@/store/playbackStore'
|
||||
import { Wifi, WifiOff, Clock, Database } from 'lucide-react'
|
||||
import { Wifi, WifiOff, Clock, Share2, Heart, Eye } from 'lucide-react'
|
||||
|
||||
const STORAGE_LIKES = 'us-iran-dashboard-likes'
|
||||
|
||||
function getStoredLikes(): number {
|
||||
try {
|
||||
return parseInt(localStorage.getItem(STORAGE_LIKES) ?? '0', 10)
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
export function HeaderPanel() {
|
||||
const situation = useReplaySituation()
|
||||
@@ -12,12 +21,64 @@ export function HeaderPanel() {
|
||||
const isReplayMode = usePlaybackStore((s) => s.isReplayMode)
|
||||
const { usForces, iranForces } = situation
|
||||
const [now, setNow] = useState(() => new Date())
|
||||
const [likes, setLikes] = useState(getStoredLikes)
|
||||
const [liked, setLiked] = useState(false)
|
||||
const [viewers, setViewers] = useState(0)
|
||||
const [cumulative, setCumulative] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => setNow(new Date()), 1000)
|
||||
return () => clearInterval(timer)
|
||||
}, [])
|
||||
|
||||
const fetchStats = async () => {
|
||||
try {
|
||||
const res = await fetch('/api/visit', { method: 'POST' })
|
||||
const data = await res.json()
|
||||
if (data.viewers != null) setViewers(data.viewers)
|
||||
if (data.cumulative != null) setCumulative(data.cumulative)
|
||||
} catch {
|
||||
setViewers((v) => (v > 0 ? v : 0))
|
||||
setCumulative((c) => (c > 0 ? c : 0))
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchStats()
|
||||
const t = setInterval(fetchStats, 30000)
|
||||
return () => clearInterval(t)
|
||||
}, [])
|
||||
|
||||
const handleShare = async () => {
|
||||
const url = window.location.href
|
||||
const title = '美伊军事态势显示'
|
||||
if (typeof navigator.share === 'function') {
|
||||
try {
|
||||
await navigator.share({ title, url })
|
||||
} catch (e) {
|
||||
if ((e as Error).name !== 'AbortError') {
|
||||
await copyToClipboard(url)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await copyToClipboard(url)
|
||||
}
|
||||
}
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
return navigator.clipboard?.writeText(text) ?? Promise.resolve()
|
||||
}
|
||||
|
||||
const handleLike = () => {
|
||||
if (liked) return
|
||||
setLiked(true)
|
||||
const next = likes + 1
|
||||
setLikes(next)
|
||||
try {
|
||||
localStorage.setItem(STORAGE_LIKES, String(next))
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const formatDateTime = (d: Date) =>
|
||||
d.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
@@ -59,14 +120,33 @@ export function HeaderPanel() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-3">
|
||||
<Link
|
||||
to="/db"
|
||||
<div className="flex shrink-0 items-center gap-4">
|
||||
<div className="flex items-center gap-2 text-military-text-secondary">
|
||||
<Eye className="h-3.5 w-3.5" />
|
||||
<span className="text-[10px]">在看 <b className="text-military-accent tabular-nums">{viewers}</b></span>
|
||||
<span className="text-[10px] opacity-70">|</span>
|
||||
<span className="text-[10px]">累积 <b className="tabular-nums">{cumulative}</b></span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleShare}
|
||||
className="flex items-center gap-1 rounded border border-military-border px-2 py-1 text-[10px] text-military-text-secondary hover:bg-military-border/30 hover:text-cyan-400"
|
||||
>
|
||||
<Database className="h-3 w-3" />
|
||||
数据库
|
||||
</Link>
|
||||
<Share2 className="h-3 w-3" />
|
||||
分享
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleLike}
|
||||
className={`flex items-center gap-1 rounded border px-2 py-1 text-[10px] transition-colors ${
|
||||
liked
|
||||
? 'border-red-500/50 bg-red-500/20 text-red-400'
|
||||
: 'border-military-border text-military-text-secondary hover:bg-military-border/30 hover:text-red-400'
|
||||
}`}
|
||||
>
|
||||
<Heart className={`h-3 w-3 ${liked ? 'fill-current' : ''}`} />
|
||||
点赞 {likes > 0 && <span className="tabular-nums">{likes}</span>}
|
||||
</button>
|
||||
{isConnected ? (
|
||||
<>
|
||||
<Wifi className="h-3.5 w-3.5 text-green-500" />
|
||||
|
||||
Reference in New Issue
Block a user