f21fa5b5e8
Commilitia Drop:自托管的跨设备剪贴板同步与点对点文件传输。 - 后端 Go(chi / SQLite WAL / SSE Hub / WebRTC signaling + 状态机 / Relay ring buffer),编译进单个 distroless 镜像(前端 go:embed)。 - 前端 React + TanStack Router + Zustand,自实现 SSE + WebRTC P2P,NAT 受阻时回退服务端中继;聚珍(Juzhen)CJK 综合排版。 - 桌面端 Wails v2(macOS / Windows),瘦客户端复用 web。 - 鉴权 OIDC PKCE(自建 Casdoor 等),refresh_token 信封加密存系统密钥库;iOS Shortcut 用 HS256 scoped token。 架构文档与变更记录见 docs 分支(PROJECT_BRIEF / FRONTEND_DESIGN / CHANGELOG)。 本次为公开发布初始提交:完整开发历史(含部署细节)留存于私有归档,公开仓库自此干净起步。
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import type { TransferRecord } from "../../store";
|
|
import { TransferRow } from "./TransferRow";
|
|
import { t } from "../../i18n";
|
|
import s from "./ActivityFeed.module.css";
|
|
|
|
export interface ActivityFeedProps
|
|
{
|
|
active: TransferRecord[];
|
|
history: TransferRecord[];
|
|
}
|
|
|
|
// 1Hz now tick:仅在有 active 时启动,避免空转。
|
|
function useNowTick(activeKey: string)
|
|
{
|
|
const [ now, setNow ] = useState(() => Date.now());
|
|
useEffect(() =>
|
|
{
|
|
if (!activeKey) { return; }
|
|
const id = window.setInterval(() => setNow(Date.now()), 1000);
|
|
return () => window.clearInterval(id);
|
|
}, [ activeKey ]);
|
|
return now;
|
|
}
|
|
|
|
export function ActivityFeed(props: ActivityFeedProps)
|
|
{
|
|
const { active, history } = props;
|
|
const activeKey = active.map((t) => t.sessionId).sort().join("|");
|
|
const now = useNowTick(activeKey);
|
|
|
|
if (active.length === 0 && history.length === 0) { return null; }
|
|
|
|
return (
|
|
<section className={s.section}>
|
|
{active.length > 0 && (
|
|
<div>
|
|
<div className={s.subhead}>{t("home.transfer.active")}</div>
|
|
<div className={s.list}>
|
|
{active.map((tr) => (
|
|
<TransferRow key={tr.sessionId} record={tr} active now={now} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
{history.length > 0 && (
|
|
<div>
|
|
<div className={s.subhead}>{t("home.transfer.history")}</div>
|
|
<div className={s.list}>
|
|
{history.map((tr) => (
|
|
<TransferRow key={tr.sessionId} record={tr} active={false} now={now} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</section>
|
|
);
|
|
}
|