Skip to content

Commit 1a671c1

Browse files
fix: content admin submit-for-review button and status chip UI (#3820)
* fix: enable submit for review button regardless of unsaved changes Co-Authored-By: john@hyprnote.com <john@hyprnote.com> * refactor: move published/draft status chip next to slug, remove toolbar button Co-Authored-By: john@hyprnote.com <john@hyprnote.com> * chore: remove unused publish handlers and tidy handleSave spacing Co-Authored-By: john@hyprnote.com <john@hyprnote.com> * chore(fmt): dprint format admin collections index.tsx Co-Authored-By: john@hyprnote.com <john@hyprnote.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: john@hyprnote.com <john@hyprnote.com>
1 parent b7959eb commit 1a671c1

File tree

1 file changed

+17
-114
lines changed
  • apps/web/src/routes/admin/collections

1 file changed

+17
-114
lines changed

apps/web/src/routes/admin/collections/index.tsx

Lines changed: 17 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { createFileRoute, redirect } from "@tanstack/react-router";
44
import { allArticles } from "content-collections";
55
import {
66
AlertTriangleIcon,
7-
CheckIcon,
87
ChevronDownIcon,
98
ChevronRightIcon,
109
ClipboardIcon,
@@ -1242,41 +1241,6 @@ function ContentPanel({
12421241
},
12431242
});
12441243

1245-
const { mutate: publishContent, isPending: isPublishing } = useMutation({
1246-
mutationFn: async (params: {
1247-
path: string;
1248-
content: string;
1249-
metadata: ArticleMetadata;
1250-
branch?: string;
1251-
action?: "publish" | "unpublish";
1252-
}) => {
1253-
if (!params.branch) {
1254-
throw new Error("Cannot publish: no branch specified");
1255-
}
1256-
const response = await fetch("/api/admin/content/publish", {
1257-
method: "POST",
1258-
headers: { "Content-Type": "application/json" },
1259-
body: JSON.stringify({
1260-
path: params.path,
1261-
content: params.content,
1262-
branch: params.branch,
1263-
metadata: params.metadata,
1264-
action: params.action || "publish",
1265-
}),
1266-
});
1267-
if (!response.ok) {
1268-
const error = await response.json();
1269-
throw new Error(error.error || "Failed to publish");
1270-
}
1271-
return response.json();
1272-
},
1273-
onSuccess: (data) => {
1274-
if (data.prUrl) {
1275-
window.open(data.prUrl, "_blank");
1276-
}
1277-
},
1278-
});
1279-
12801244
const handleSave = useCallback(
12811245
(options?: { isAutoSave?: boolean }) => {
12821246
if (currentTab?.type === "file" && editorData) {
@@ -1292,30 +1256,6 @@ function ContentPanel({
12921256
[currentTab, editorData, saveContent],
12931257
);
12941258

1295-
const handlePublish = useCallback(() => {
1296-
if (currentTab?.type === "file" && editorData) {
1297-
publishContent({
1298-
path: currentTab.path,
1299-
content: editorData.content,
1300-
metadata: editorData.metadata,
1301-
branch: currentTab.branch,
1302-
action: "publish",
1303-
});
1304-
}
1305-
}, [currentTab, editorData, publishContent]);
1306-
1307-
const handleUnpublish = useCallback(() => {
1308-
if (currentTab?.type === "file" && editorData) {
1309-
publishContent({
1310-
path: currentTab.path,
1311-
content: editorData.content,
1312-
metadata: editorData.metadata,
1313-
branch: currentTab.branch,
1314-
action: "unpublish",
1315-
});
1316-
}
1317-
}, [currentTab, editorData, publishContent]);
1318-
13191259
const currentFileContent = useMemo(
13201260
() =>
13211261
currentTab?.type === "file" ? getFileContent(currentTab.path) : undefined,
@@ -1441,9 +1381,6 @@ function ContentPanel({
14411381
onTogglePreview={() => setIsPreviewMode(!isPreviewMode)}
14421382
onSave={handleSave}
14431383
isSaving={isSaving}
1444-
onPublish={handlePublish}
1445-
onUnpublish={handleUnpublish}
1446-
isPublishing={isPublishing}
14471384
isPublished={currentFileContent?.published}
14481385
onSubmitForReview={handleSubmitForReview}
14491386
isSubmittingForReview={isSubmittingForReview}
@@ -1497,9 +1434,6 @@ function EditorHeader({
14971434
onTogglePreview,
14981435
onSave,
14991436
isSaving,
1500-
onPublish: _onPublish,
1501-
onUnpublish,
1502-
isPublishing,
15031437
isPublished,
15041438
onSubmitForReview,
15051439
isSubmittingForReview,
@@ -1520,9 +1454,6 @@ function EditorHeader({
15201454
onTogglePreview: () => void;
15211455
onSave: () => void;
15221456
isSaving: boolean;
1523-
onPublish: () => void;
1524-
onUnpublish: () => void;
1525-
isPublishing: boolean;
15261457
isPublished?: boolean;
15271458
onSubmitForReview?: () => void;
15281459
isSubmittingForReview?: boolean;
@@ -1531,7 +1462,6 @@ function EditorHeader({
15311462
hasUnsavedChanges?: boolean;
15321463
autoSaveCountdown?: number | null;
15331464
}) {
1534-
const [isHoveringPublish, setIsHoveringPublish] = useState(false);
15351465
const [isEditingSlug, setIsEditingSlug] = useState(false);
15361466
const [slugValue, setSlugValue] = useState("");
15371467
const slugInputRef = useRef<HTMLInputElement>(null);
@@ -1598,11 +1528,22 @@ function EditorHeader({
15981528
className="text-neutral-700 font-medium bg-transparent outline-none"
15991529
/>
16001530
) : (
1601-
<span
1602-
onClick={handleSlugClick}
1603-
className="text-neutral-700 font-medium hover:text-neutral-900 cursor-text"
1604-
>
1605-
{crumb.replace(/\.mdx$/, "")}
1531+
<span className="flex items-center gap-2">
1532+
<span
1533+
onClick={handleSlugClick}
1534+
className="text-neutral-700 font-medium hover:text-neutral-900 cursor-text"
1535+
>
1536+
{crumb.replace(/\.mdx$/, "")}
1537+
</span>
1538+
{isPublished ? (
1539+
<span className="px-1.5 py-0.5 text-[10px] font-medium font-mono rounded bg-green-100 text-green-700">
1540+
Published
1541+
</span>
1542+
) : (
1543+
<span className="px-1.5 py-0.5 text-[10px] font-medium font-mono rounded bg-neutral-100 text-neutral-500">
1544+
Draft
1545+
</span>
1546+
)}
16061547
</span>
16071548
)
16081549
) : (
@@ -1671,7 +1612,7 @@ function EditorHeader({
16711612
{onSubmitForReview && (
16721613
<button
16731614
onClick={onSubmitForReview}
1674-
disabled={isSubmittingForReview || !hasUnsavedChanges}
1615+
disabled={isSubmittingForReview}
16751616
className={cn([
16761617
"cursor-pointer px-2 py-1.5 text-xs font-medium font-mono rounded-xs transition-colors flex items-center gap-1.5",
16771618
"text-white bg-blue-600 hover:bg-blue-700",
@@ -1687,44 +1628,6 @@ function EditorHeader({
16871628
Submit for Review
16881629
</button>
16891630
)}
1690-
{isPublished ? (
1691-
<button
1692-
type="button"
1693-
onClick={onUnpublish}
1694-
disabled={isPublishing}
1695-
onMouseEnter={() => setIsHoveringPublish(true)}
1696-
onMouseLeave={() => setIsHoveringPublish(false)}
1697-
className={cn([
1698-
"cursor-pointer px-2 py-1.5 text-xs font-medium font-mono rounded-xs flex items-center gap-1.5",
1699-
isHoveringPublish
1700-
? "text-white bg-red-600 hover:bg-red-700"
1701-
: "text-white bg-green-600",
1702-
"disabled:cursor-not-allowed",
1703-
])}
1704-
>
1705-
{isPublishing ? (
1706-
<>
1707-
<Spinner size={14} color="white" />
1708-
Unpublishing
1709-
</>
1710-
) : isHoveringPublish ? (
1711-
<>
1712-
<XIcon className="size-4" />
1713-
Unpublish
1714-
</>
1715-
) : (
1716-
<>
1717-
<CheckIcon className="size-4" />
1718-
Published
1719-
</>
1720-
)}
1721-
</button>
1722-
) : (
1723-
<span className="px-2 py-1.5 text-xs font-medium font-mono rounded-xs bg-neutral-100 text-neutral-400 flex items-center gap-1.5">
1724-
<XIcon className="size-4" />
1725-
Not Published
1726-
</span>
1727-
)}
17281631
</div>
17291632
)}
17301633
</div>

0 commit comments

Comments
 (0)