import { houseOff } from "@lucide/lab";
import { Check, Copy, Home, Icon, Loader2 } from "lucide-react";
import { Skeleton } from "@/client/components/ui/skeleton";
import { isActionEnabled, isActionVisible } from "@/client/lib/affordance/action-state";
import type { SitePageStatus } from "@/shared/types";
import { useShareDialogShell, useSitePublish } from "./context";
export function PublishTabContent() {
const { publishAffordance } = useShareDialogShell();
const {
site,
pageStatus,
loading,
saving,
slugSavePending,
siteTogglePending,
setHomePending,
publishPending,
unpublishPending,
featureDisabled,
error,
slugDraft,
setSlugDraft,
saveSiteSlug,
toggleSitePublished,
publishPage,
unpublishPage,
isHome,
toggleHomePage,
copyPublicUrl,
copied,
} = useSitePublish();
if (loading) {
return (
);
}
if (featureDisabled) {
return Sites are not enabled on this instance.
;
}
const siteRow = site?.site ?? null;
const baseDomain = site?.base_domain ?? null;
const sitePublished = !!siteRow?.published_at;
const showManageSite = isActionVisible(publishAffordance.manageSite);
const canManage = isActionEnabled(publishAffordance.manageSite);
const siteReady = !!siteRow && sitePublished;
return (
{error &&
{error}
}
{pageStatus ? (
void publishPage()}
onUnpublish={() => void unpublishPage()}
onToggleHome={() => void toggleHomePage()}
/>
) : null}
{showManageSite && baseDomain ? (
void saveSiteSlug(slugDraft.trim())}
onToggleSite={() => void toggleSitePublished()}
/>
) : null}
);
}
interface PagePublicationSectionProps {
status: SitePageStatus;
siteReady: boolean;
showManageSite: boolean;
canManage: boolean;
saving: boolean;
publishPending: boolean;
unpublishPending: boolean;
setHomePending: boolean;
isHome: boolean;
copied: boolean;
onCopy: () => void;
onPublish: () => void;
onUnpublish: () => void;
onToggleHome: () => void;
}
function PagePublicationSection({
status,
siteReady,
showManageSite,
canManage,
saving,
publishPending,
unpublishPending,
setHomePending,
isHome,
copied,
onCopy,
onPublish,
onUnpublish,
onToggleHome,
}: PagePublicationSectionProps) {
if (status.canvas) {
return Canvas pages cannot be published.
;
}
return (
{status.public_url ? : null}
{showManageSite ? (
) : (
Only admins can publish pages.
)}
);
}
function StatusRow({ status }: { status: SitePageStatus }) {
if (status.is_explicit_root) {
return (
Live on the web
);
}
if (status.inherited_from) {
return (
Live via {status.inherited_from.title || "ancestor"}
);
}
return (
Page is private
);
}
function PublicUrlPill({ url, copied, onCopy }: { url: string; copied: boolean; onCopy: () => void }) {
return (
{url}
);
}
interface PageActionsProps {
status: SitePageStatus;
siteReady: boolean;
canManage: boolean;
saving: boolean;
publishPending: boolean;
unpublishPending: boolean;
setHomePending: boolean;
isHome: boolean;
onPublish: () => void;
onUnpublish: () => void;
onToggleHome: () => void;
}
function PageActions({
status,
siteReady,
canManage,
saving,
publishPending,
unpublishPending,
setHomePending,
isHome,
onPublish,
onUnpublish,
onToggleHome,
}: PageActionsProps) {
// Inherited-from-ancestor: explain the relationship and offer a way to
// promote the page to its own root.
if (!status.is_explicit_root && status.inherited_from) {
return (
This page is live because{" "}
{status.inherited_from.title || "an ancestor"} is published.
);
}
// Explicit root: stop-publishing primary + set-as-home secondary
if (status.is_explicit_root) {
return (
);
}
// Not published: primary "Publish this page" CTA, or note when no site exists yet
if (!siteReady) {
return Set up your site URL below to publish this page.
;
}
return (
);
}
interface SiteSettingsSectionProps {
baseDomain: string;
slugDraft: string;
setSlugDraft: (next: string) => void;
siteRow: { published_at: string | null } | null;
sitePublished: boolean;
saving: boolean;
slugSavePending: boolean;
siteTogglePending: boolean;
canManage: boolean;
dividerAbove: boolean;
onSaveSlug: () => void;
onToggleSite: () => void;
}
function SiteSettingsSection({
baseDomain,
slugDraft,
setSlugDraft,
siteRow,
sitePublished,
saving,
slugSavePending,
siteTogglePending,
canManage,
dividerAbove,
onSaveSlug,
onToggleSite,
}: SiteSettingsSectionProps) {
return (
Site settings
setSlugDraft(e.target.value)}
placeholder="your-slug"
disabled={!canManage || saving}
className="min-w-0 flex-1 rounded-md border border-zinc-700 bg-zinc-900 py-1 pl-2 text-sm text-zinc-300 outline-none focus:border-accent-500/50 focus:ring-1 focus:ring-accent-500/30 disabled:opacity-60"
aria-label="Site slug"
/>
.{baseDomain}
{siteRow ? (
) : null}
);
}