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:
2026-06-15 21:38:28 +08:00
commit f21fa5b5e8
239 changed files with 29010 additions and 0 deletions
+169
View File
@@ -0,0 +1,169 @@
/*
* 本地优先字体层 —— 用 local() 覆盖 CDN 的纯 url() @font-face。
*
* 问题:三个字体 CDN 的 @font-face 都只有 src: url(...)、无 local()。浏览器解析到
* 这些 family 名(如 "Orbit Gothic CJK SC")时会被该 @font-face 捕获、直接走网络
* url,即便本机已安装同名字体也不会用 → 首屏闪烁、无谓流量。
*
* 修法:在 CDN <link>(见 index.html)之后,对项目实际用到的 family × 字重重新声明
* @font-facesrc 把 local() 放最前、CDN url() 兜底。同 family 同 weight/style 的
* @font-face 以「后定义者胜」,cdrop 打包 CSS 在 index.html 静态 <link> 之后加载,故
* 本层覆盖 CDN:本机命中即零网络瞬时渲染,未装则回退网络(swap)。
*
* 覆盖范围:仅项目用到的字重(400/500/600/700)× 实际激活的 region
* - Orbit Gothic CJK SC / TCSans 正文 Mono 的 CJK 落字)
* - Maple MonoMono 拉丁 / 符号)
* Serif 的 "Noto Serif CJK SC" 是本地专属名(gfonts 只定义 "Noto Serif SC"、不含该
* 名),字体栈里已排最前 → 本就本地优先,无需在此覆盖。日韩(JP/KR)region 暂未激活,
* 启用时按同样 4 字重补充即可。
*
* local() 同时给 family 名与 PostScript 名两种写法以提高命中率;font-display: swap
* 与 CDN 保持一致。
*/
/* ===== Orbit Gothic CJK SC(默认 / 简体 Sans + Mono CJK===== */
@font-face
{
font-family: "Orbit Gothic CJK SC";
font-style: normal;
font-weight: 400;
font-display: swap;
src:
local("Orbit Gothic CJK SC"),
local("OrbitGothicCJKsc-Regular"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKsc/OrbitGothicCJKsc-Regular.woff2") format("woff2");
}
@font-face
{
font-family: "Orbit Gothic CJK SC";
font-style: normal;
font-weight: 500;
font-display: swap;
src:
local("Orbit Gothic CJK SC"),
local("OrbitGothicCJKsc-Medium"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKsc/OrbitGothicCJKsc-Medium.woff2") format("woff2");
}
@font-face
{
font-family: "Orbit Gothic CJK SC";
font-style: normal;
font-weight: 600;
font-display: swap;
src:
local("Orbit Gothic CJK SC"),
local("OrbitGothicCJKsc-SemiBold"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKsc/OrbitGothicCJKsc-SemiBold.woff2") format("woff2");
}
@font-face
{
font-family: "Orbit Gothic CJK SC";
font-style: normal;
font-weight: 700;
font-display: swap;
src:
local("Orbit Gothic CJK SC"),
local("OrbitGothicCJKsc-Bold"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKsc/OrbitGothicCJKsc-Bold.woff2") format("woff2");
}
/* ===== Orbit Gothic CJK TC(繁体 Sans + Mono CJK===== */
@font-face
{
font-family: "Orbit Gothic CJK TC";
font-style: normal;
font-weight: 400;
font-display: swap;
src:
local("Orbit Gothic CJK TC"),
local("OrbitGothicCJKtc-Regular"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKtc/OrbitGothicCJKtc-Regular.woff2") format("woff2");
}
@font-face
{
font-family: "Orbit Gothic CJK TC";
font-style: normal;
font-weight: 500;
font-display: swap;
src:
local("Orbit Gothic CJK TC"),
local("OrbitGothicCJKtc-Medium"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKtc/OrbitGothicCJKtc-Medium.woff2") format("woff2");
}
@font-face
{
font-family: "Orbit Gothic CJK TC";
font-style: normal;
font-weight: 600;
font-display: swap;
src:
local("Orbit Gothic CJK TC"),
local("OrbitGothicCJKtc-SemiBold"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKtc/OrbitGothicCJKtc-SemiBold.woff2") format("woff2");
}
@font-face
{
font-family: "Orbit Gothic CJK TC";
font-style: normal;
font-weight: 700;
font-display: swap;
src:
local("Orbit Gothic CJK TC"),
local("OrbitGothicCJKtc-Bold"),
url("https://orbit-gothic.cdn.commilitia.net/WOFF2/CJKtc/OrbitGothicCJKtc-Bold.woff2") format("woff2");
}
/* ===== Maple MonoMono 拉丁 / 符号)===== */
@font-face
{
font-family: "Maple Mono";
font-style: normal;
font-weight: 400;
font-display: swap;
src:
local("Maple Mono"),
local("MapleMono-Regular"),
url("https://maple-mono.cdn.commilitia.net/MapleMono-Regular.ttf.woff2") format("woff2");
}
@font-face
{
font-family: "Maple Mono";
font-style: normal;
font-weight: 500;
font-display: swap;
src:
local("Maple Mono"),
local("MapleMono-Medium"),
url("https://maple-mono.cdn.commilitia.net/MapleMono-Medium.ttf.woff2") format("woff2");
}
@font-face
{
font-family: "Maple Mono";
font-style: normal;
font-weight: 600;
font-display: swap;
src:
local("Maple Mono"),
local("MapleMono-SemiBold"),
url("https://maple-mono.cdn.commilitia.net/MapleMono-SemiBold.ttf.woff2") format("woff2");
}
@font-face
{
font-family: "Maple Mono";
font-style: normal;
font-weight: 700;
font-display: swap;
src:
local("Maple Mono"),
local("MapleMono-Bold"),
url("https://maple-mono.cdn.commilitia.net/MapleMono-Bold.ttf.woff2") format("woff2");
}