Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 93 additions & 36 deletions apps/builder/app/builder/features/publish/publish.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
css,
textVariants,
SmallIconButton,
Collapsible,
} from "@webstudio-is/design-system";
import { validateProjectDomain, type Project } from "@webstudio-is/project";
import {
Expand Down Expand Up @@ -82,6 +83,8 @@ import {
UpgradeIcon,
HelpIcon,
InfoCircleIcon,
ChevronDownIcon,
ChevronRightIcon,
} from "@webstudio-is/icons";
import { AddDomain } from "./add-domain";
import { humanizeString } from "~/shared/string-utils";
Expand Down Expand Up @@ -549,6 +552,36 @@ export const usePublishTarget = (projectId: string) => {
return { renderMode, setRenderMode, host, setHost };
};

const advancedPublishOpenStorageKey = "publish:advancedOpen";

/**
* Open/closed state of the "Advanced settings" disclosure holding the
* renderMode / host selectors. Persisted globally — it's a UI preference, not a
* per-project setting. Forced open on mount when a non-default target is
* selected so the user can see (and change) what they'll publish with.
*/
const useAdvancedPublishOpen = (hasNonDefaultTarget: boolean) => {
const [isOpen, setIsOpen] = useState(() => {
if (hasNonDefaultTarget) {
return true;
}
try {
return localStorage.getItem(advancedPublishOpenStorageKey) === "true";
} catch {
return false;
}
});
const handleOpenChange = (open: boolean) => {
try {
localStorage.setItem(advancedPublishOpenStorageKey, String(open));
} catch {
// localStorage unavailable — keep the in-memory state only
}
setIsOpen(open);
};
return [isOpen, handleOpenChange] as const;
};

const Publish = ({
project,
timesLeft,
Expand Down Expand Up @@ -585,6 +618,9 @@ const Publish = ({
useState(false);
const countdown = usePublishCountdown(isPublishing);
const publisherHost = useStore($publisherHost);
const [advancedOpen, setAdvancedOpen] = useAdvancedPublishOpen(
renderMode !== "ssr" || host !== "local"
);
const { load: loadCapabilities, data: capabilities } =
trpcClient.domain.publisherCapabilities.useQuery();

Expand Down Expand Up @@ -811,42 +847,63 @@ const Publish = ({
)}

{publisherHost && (
<>
<Select
fullWidth
value={renderMode}
options={["ssr", "ssg"] as const}
getLabel={(value: RenderMode) =>
value === "ssr" ? "Dynamic (SSR)" : "Static (SSG)"
}
getDescription={(value: RenderMode) =>
value === "ssr"
? "Dynamic data, rendered per request"
: "Prerendered static files, no dynamic data"
}
onChange={onRenderModeChange}
/>
<Select
fullWidth
value={host}
options={publishHosts}
getLabel={(value: PublishHost) => publishHostLabels[value]}
getDescription={(value: PublishHost) =>
publishHostDescriptions[value]
}
getItemProps={(value: PublishHost) => {
const reason = publishHostUnavailableReason(
capabilities,
renderMode,
value
);
return reason === undefined
? {}
: { disabled: true, title: reason };
}}
onChange={onHostChange}
/>
</>
<Collapsible.Root
asChild
open={advancedOpen}
onOpenChange={setAdvancedOpen}
>
<Flex direction="column" gap="2">
<Collapsible.Trigger asChild>
<Button
color="ghost"
css={{ width: "100%", justifyContent: "start" }}
prefix={
advancedOpen ? <ChevronDownIcon /> : <ChevronRightIcon />
}
>
Advanced settings
</Button>
</Collapsible.Trigger>
<Collapsible.Content asChild>
<Flex direction="column" gap="2">
<Select
fullWidth
value={renderMode}
options={["ssr", "ssg"] as const}
getLabel={(value: RenderMode) =>
value === "ssr" ? "Dynamic (SSR)" : "Static (SSG)"
}
getDescription={(value: RenderMode) =>
value === "ssr"
? "Dynamic data, rendered per request"
: "Prerendered static files, no dynamic data"
}
onChange={onRenderModeChange}
/>
<Select
fullWidth
value={host}
options={publishHosts}
getLabel={(value: PublishHost) => publishHostLabels[value]}
getDescription={(value: PublishHost) =>
publishHostDescriptions[value]
}
getItemProps={(value: PublishHost) => {
const reason = publishHostUnavailableReason(
capabilities,
renderMode,
value
);
return reason === undefined
? {}
: { disabled: true, title: reason };
}}
onChange={onHostChange}
/>
</Flex>
</Collapsible.Content>
</Flex>
</Collapsible.Root>
)}

<Tooltip
Expand Down
Loading