feat(plugin-sdk): add TypeScript SDK for Infinite Canvas plugins with automatic JSX and build support
This commit is contained in:
@@ -33,7 +33,7 @@ const modelGroups: ModelGroup[] = [
|
||||
const webdavDomainKeys: AppSyncDomainKey[] = ["canvas", "assets", "image-workbench", "video-workbench"];
|
||||
const webdavDomainLabels: Record<AppSyncDomainKey, string> = {
|
||||
canvas: "画布",
|
||||
assets: "我的素材",
|
||||
assets: "我的资产",
|
||||
"image-workbench": "生图工作台",
|
||||
"video-workbench": "视频创作台",
|
||||
};
|
||||
@@ -141,7 +141,7 @@ export function AppConfigPanel({ showDoneButton = false, initialTab = "channels"
|
||||
try {
|
||||
const result = await syncAppDataToWebdav(webdav, updateWebdavProgress);
|
||||
updateWebdavConfig("lastSyncedAt", result.syncedAt);
|
||||
message.success(`同步完成:${result.projects} 个画布,${result.assets} 个素材,${result.imageLogs + result.videoLogs} 条记录,本次上传 ${result.uploadedFiles} 个文件 ${formatBytes(result.uploadedBytes)}`);
|
||||
message.success(`同步完成:${result.projects} 个画布,${result.assets} 个资产,${result.imageLogs + result.videoLogs} 条记录,本次上传 ${result.uploadedFiles} 个文件 ${formatBytes(result.uploadedBytes)}`);
|
||||
} catch (error) {
|
||||
setWebdavSyncStatus(error instanceof Error ? error.message : "WebDAV 同步失败");
|
||||
message.error(error instanceof Error ? error.message : "WebDAV 同步失败");
|
||||
@@ -252,7 +252,7 @@ export function AppConfigPanel({ showDoneButton = false, initialTab = "channels"
|
||||
<Cloud className="size-4" />
|
||||
WebDAV 同步
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-stone-500">同步画布、我的素材、生成记录和本地媒体文件,不包含 AI API Key;浏览器会直接连接 WebDAV 服务。</div>
|
||||
<div className="mt-1 text-xs text-stone-500">同步画布、我的资产、生成记录和本地媒体文件,不包含 AI API Key;浏览器会直接连接 WebDAV 服务。</div>
|
||||
</div>
|
||||
<div className="text-xs text-stone-500">{webdav.lastSyncedAt ? `上次同步 ${formatWebdavTime(webdav.lastSyncedAt)}` : "尚未同步"}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CSSProperties } from "react";
|
||||
import { BookOpen, Keyboard, Settings2 } from "lucide-react";
|
||||
import { BookOpen, Keyboard, Puzzle, Settings2 } from "lucide-react";
|
||||
|
||||
import { AnimatedThemeToggler } from "@/components/ui/animated-theme-toggler";
|
||||
import { GitHubLink } from "@/components/layout/github-link";
|
||||
@@ -14,9 +14,10 @@ type UserStatusActionsProps = {
|
||||
showConfig?: boolean;
|
||||
variant?: "default" | "canvas";
|
||||
onOpenShortcuts?: () => void;
|
||||
onOpenPlugins?: () => void;
|
||||
};
|
||||
|
||||
export function UserStatusActions({ showConfig = true, variant = "default", onOpenShortcuts }: UserStatusActionsProps) {
|
||||
export function UserStatusActions({ showConfig = true, variant = "default", onOpenShortcuts, onOpenPlugins }: UserStatusActionsProps) {
|
||||
const theme = useThemeStore((state) => state.theme);
|
||||
const setTheme = useThemeStore((state) => state.setTheme);
|
||||
const openConfigDialog = useConfigStore((state) => state.openConfigDialog);
|
||||
@@ -29,6 +30,11 @@ export function UserStatusActions({ showConfig = true, variant = "default", onOp
|
||||
|
||||
return (
|
||||
<div className="inline-flex shrink-0 items-center gap-1">
|
||||
{onOpenPlugins ? (
|
||||
<button type="button" className={naturalIconClass} style={iconStyle} onClick={onOpenPlugins} aria-label="节点插件" title="节点插件">
|
||||
<Puzzle className="size-4" />
|
||||
</button>
|
||||
) : null}
|
||||
<a href={DOCS_URL} target="_blank" rel="noopener noreferrer" className={naturalIconClass} style={iconStyle} aria-label="文档" title="文档">
|
||||
<BookOpen className="size-4" />
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user