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

62 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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>
);
}