import { useId, useState } from "react"; import { Check, Rocket } from "lucide-react"; import { cn } from "../../core/cn"; import type { DeploymentInfo } from "../../document-model"; import { WorkbenchDialog } from "../dialog"; import type { DeployStatus } from "../workbenchTypes"; import { deployButtonText, deploymentStatusKind, deploymentStatusSummary, deploymentStatusText, } from "./deploymentStatusModel"; import { DEPLOY_STATUS_TOOLBAR_CLASS, TOOLBAR_ACTION_CLASS, TOOLBAR_DEPLOY_STATUS_DOT_CLASS } from "../toolbarClasses"; import { Button } from "@/openpress/ui/button"; const DEPLOY_DIALOG_CLASS = "openpress-deploy-dialog !w-[min(420px,calc(100vw-56px))] gap-3 !p-4"; const DEPLOY_DIALOG_FOOTER_CLASS = [ "[&_button]:!h-[30px] [&_button]:!gap-[7px] [&_button]:!px-2.5 [&_button]:!font-[560]", "[&_svg]:h-[13px] [&_svg]:w-[13px]", ].join(" "); const DEPLOY_SOURCE_CLASS = [ "openpress-deploy-dialog__source inline-flex min-h-[19px] max-w-full items-center overflow-hidden text-ellipsis whitespace-nowrap", "rounded-full border border-[color-mix(in_srgb,var(--op-workspace-success)_18%,transparent)] bg-[color-mix(in_srgb,var(--op-workspace-success)_7%,transparent)] px-[7px]", "text-[10px] font-semibold leading-none text-[var(--op-workspace-success)]", ].join(" "); const DEPLOY_DETAILS_CLASS = [ "grid gap-2 border-y border-[var(--op-workspace-border-muted)] py-3", ].join(" "); const DEPLOY_ROW_CLASS = "grid min-w-0 grid-cols-[78px_minmax(0,1fr)] items-center gap-3"; const DEPLOY_TERM_CLASS = "m-0 min-w-0 text-[11px] leading-[1.35] text-[var(--op-workspace-text-muted)]"; const DEPLOY_VALUE_CLASS = "m-0 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-left text-[11px] leading-[1.35] text-[var(--op-workspace-text-soft)]"; const DEPLOY_LINK_CLASS = "text-[var(--op-workspace-text-soft)] no-underline hover:text-[var(--op-workspace-accent)] hover:underline hover:underline-offset-[3px]"; const DEPLOY_STATUS_CLASS = "openpress-deploy-dialog__status inline-flex items-center justify-start gap-1.5 text-[var(--op-workspace-text-muted)]"; const DEPLOY_STATUS_DOT_CLASS = "h-1.5 w-1.5 shrink-0 rounded-full bg-current"; const DEPLOY_STATUS_KIND_CLASS: Record = { online: "text-[var(--op-workspace-success)]", dirty: "text-[var(--op-workspace-accent)]", deploying: "text-[var(--op-workspace-accent)]", failed: "text-[var(--op-workspace-danger)]", }; const DEPLOY_MESSAGE_CLASS = "openpress-deploy-dialog__message m-0 border-l-2 border-[var(--op-workspace-danger)] py-1.5 pl-2.5 pr-0 text-xs leading-[1.45] text-[var(--op-workspace-danger)]"; export function DeploymentControl({ info, status, onDeploy, }: { info: DeploymentInfo; status: DeployStatus; onDeploy: () => void | Promise; }) { const [dialogOpen, setDialogOpen] = useState(false); const kind = deploymentStatusKind(info, status); const buttonText = deployButtonText(info, status); const description = deploymentStatusText(info, status); const busy = status === "deploying"; return ( <> {busy ? ( ) : null} ); } export interface DeploymentDialogProps { open: boolean; onOpenChange: (open: boolean) => void; info: DeploymentInfo; status: DeployStatus; onDeploy: () => void | Promise; } export function DeploymentDialog({ open, onOpenChange, info, status, onDeploy, }: DeploymentDialogProps) { const titleId = useId(); if (!open) return null; const kind = deploymentStatusKind(info, status); const summary = deploymentStatusSummary(info, status); const sourceLabel = deploymentSourceLabel(info); const busy = status === "deploying"; const confirmDisabled = busy || status === "unavailable" || info.configured === false; const confirmDeploy = () => { if (confirmDisabled) return; onOpenChange(false); void onDeploy(); }; return ( {sourceLabel}} className={DEPLOY_DIALOG_CLASS} backdropClassName="openpress-deploy-dialog-backdrop" footerClassName={DEPLOY_DIALOG_FOOTER_CLASS} closeLabel="關閉部署資訊" onClose={() => onOpenChange(false)} footer={( <> )} >
{info.configured === false ? (

{info.setupMessage ?? "部署設定尚未完成。"}

) : null} ); } function DeployStatusRow({ label, value, kind }: { label: string; value: string; kind: string }) { return (
{label}
); } function DeployLinkRow({ label, url }: { label: string; url?: string }) { return (
{label}
{url ? ( {formatDeployUrl(url)} ) : ( "尚未產生" )}
); } function deploymentSourceLabel(info: DeploymentInfo) { const adapter = info.adapter?.trim().toLowerCase(); if (adapter === "cloudflare-pages" || adapter === "cloudflare") return "Cloudflare Pages"; if (adapter === "github-pages" || adapter === "github") return "GitHub Pages"; if (adapter === "zeabur" || adapter === "zebur") return "Zeabur"; return info.projectName?.trim() || info.source?.trim() || info.adapter?.trim() || "本機工作區"; } function formatDeployUrl(value: string) { try { const url = new URL(value); const pathname = url.pathname === "/" ? "" : url.pathname.replace(/\/$/, ""); return shortenDeployUrl(`${url.host}${pathname}`); } catch { return shortenDeployUrl(value); } } function shortenDeployUrl(value: string) { if (value.length <= 48) return value; return `${value.slice(0, 30)}...${value.slice(-14)}`; }