diff --git a/frontend/src/app/components/share/PublishModal.tsx b/frontend/src/app/components/share/PublishModal.tsx
index bd03703d..d887c716 100644
--- a/frontend/src/app/components/share/PublishModal.tsx
+++ b/frontend/src/app/components/share/PublishModal.tsx
@@ -34,6 +34,28 @@ interface Props {
type Phase = 'scanning' | 'review' | 'publishing' | 'done' | 'error';
+// A build can take up to ~3 minutes on a cold node_modules. Stay silent for the
+// fast common case, then fade in an honest hint after 10s so a slow build doesn't
+// read as a hang (matches the SlowHint pattern in ChatInputOverlays).
+const SlowHint: React.FC<{ active: boolean; color: string }> = ({ active, color }) => {
+ const [show, setShow] = useState(false);
+ useEffect(() => {
+ if (!active) {
+ setShow(false);
+ return;
+ }
+ const t = setTimeout(() => setShow(true), 10000);
+ return () => clearTimeout(t);
+ }, [active]);
+ return (
+
+
+ This can take up to a minute. Hang tight.
+
+
+ );
+};
+
const PublishModal: React.FC = ({ outputId, outputName, open, onClose }) => {
const c = useClaudeTokens();
const dispatch = useAppDispatch();
@@ -46,6 +68,7 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
const [liveUrl, setLiveUrl] = useState(null);
const [busy, setBusy] = useState(false);
const [toast, setToast] = useState('');
+ const [confirmUnpublish, setConfirmUnpublish] = useState(false);
const runScan = useCallback(() => {
setPhase('scanning');
@@ -63,6 +86,7 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
useEffect(() => {
if (!open) return;
setShowDetails(false);
+ setConfirmUnpublish(false);
if (publishedUrl) {
setLiveUrl(publishedUrl);
setPhase('done');
@@ -107,6 +131,7 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
setToast('App unpublished');
onClose();
} catch (e: any) {
+ setConfirmUnpublish(false);
setToast(e?.message || "We couldn't unpublish.");
} finally {
setBusy(false);
@@ -134,6 +159,7 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
<>
Checking your app before it goes live...
+
>,
);
}
@@ -142,6 +168,7 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
<>
Building and publishing your app...
+
>,
);
}
@@ -154,6 +181,16 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
);
}
if (phase === 'done') {
+ if (confirmUnpublish) {
+ return center(
+ <>
+ Take this app offline?
+
+ The public link will stop working for anyone you've shared it with.
+
+ >,
+ );
+ }
return (
@@ -220,9 +257,19 @@ const PublishModal: React.FC = ({ outputId, outputName, open, onClose })
);
}
if (phase === 'done') {
+ if (confirmUnpublish) {
+ return (
+ <>
+
+
+ >
+ );
+ }
return (
<>
-
+
>
);