cdrop — 跨 OS 剪贴板与文件传输服务
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)。 本次为公开发布初始提交:完整开发历史(含部署细节)留存于私有归档,公开仓库自此干净起步。
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user