haixunMaster/components/settings/extension-sync-card.tsx

62 lines
3.5 KiB
TypeScript
Raw Permalink Normal View History

2026-06-21 12:50:31 +00:00
"use client";
import { useEffect, useState } from "react";
import { CheckCircle2, Loader2, Puzzle, RefreshCw } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
type SyncResult = { success?: boolean; valid?: boolean; message?: string; username?: string };
export function ExtensionSyncCard() {
const [ready, setReady] = useState(false);
const [syncing, setSyncing] = useState(false);
const [result, setResult] = useState<SyncResult | null>(null);
useEffect(() => {
const onMessage = (event: MessageEvent) => {
if (event.source !== window) return;
if (event.data?.type === "HAIXUN_EXTENSION_READY") setReady(true);
if (event.data?.type === "HAIXUN_THREADS_SYNC_RESULT") {
setSyncing(false);
setResult(event.data);
}
};
window.addEventListener("message", onMessage);
window.postMessage({ type: "HAIXUN_PING_EXTENSION" }, "*");
return () => window.removeEventListener("message", onMessage);
}, []);
function sync() {
setSyncing(true);
setResult(null);
window.postMessage({ type: "HAIXUN_REQUEST_THREADS_SYNC", serverUrl: window.location.origin }, "*");
window.setTimeout(() => setSyncing(false), 15000);
}
return (
<Card id="extension" className="overflow-hidden border-primary/20">
<CardHeader>
<div className="flex items-start justify-between gap-4">
<div>
<CardTitle className="flex items-center gap-2 text-base"><Puzzle className="h-4 w-4 text-primary" />Threads Extension</CardTitle>
<CardDescription> Threads 使 Chrome Extension API</CardDescription>
</div>
<span className={`rounded-full px-2.5 py-1 text-xs font-medium ${ready ? "bg-success-bg text-success" : "bg-muted text-muted-foreground"}`}>
{ready ? "已偵測" : "未偵測"}
</span>
</div>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid gap-3 text-sm sm:grid-cols-3">
<p className="rounded-xl bg-muted/70 p-3"><b className="block text-foreground">1. Threads</b><span className="text-muted-foreground"> Chrome </span></p>
<p className="rounded-xl bg-muted/70 p-3"><b className="block text-foreground">2. Session</b><span className="text-muted-foreground"></span></p>
<p className="rounded-xl bg-muted/70 p-3"><b className="block text-foreground">3. </b><span className="text-muted-foreground"> TA </span></p>
</div>
{result && <p className={`rounded-xl border p-3 text-sm ${result.success ? "border-success-border bg-success-bg text-success" : "border-danger-border bg-danger-bg text-destructive"}`}>{result.success && <CheckCircle2 className="mr-2 inline h-4 w-4" />}{result.username ? `@${result.username} · ` : ""}{result.message ?? (result.success ? "同步成功" : "同步失敗")}</p>}
<Button onClick={sync} disabled={!ready || syncing}>{syncing ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}{syncing ? "同步中…" : "同步 Threads Session"}</Button>
{!ready && <p className="text-xs text-muted-foreground"> <code className="rounded bg-muted px-1">extension/haixun-threads-sync</code></p>}
</CardContent>
</Card>
);
}