Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions .changeset/better-cameras-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@emdash-cms/admin": patch
---

Replaces 20 raw `<input type="checkbox">` elements across the admin UI with Kumo's `Switch` and `Checkbox` components. Single-boolean toggles (SEO, Enable comments, Required, etc.) become `Switch`; multi-select / list-context checkboxes (collection multi-select, term tree nodes) become `Checkbox`. Drops manual styling and label markup that duplicated what the Kumo components provide built-in.
129 changes: 54 additions & 75 deletions packages/admin/src/components/ContentTypeEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Badge, Button, Input, InputArea, Label, Select } from "@cloudflare/kumo";
import { Badge, Button, Checkbox, Input, InputArea, Label, Select, Switch } from "@cloudflare/kumo";
import {
DndContext,
closestCenter,
Expand Down Expand Up @@ -441,50 +441,43 @@ export function ContentTypeEditor({
<div className="space-y-3">
<Label>Features</Label>
{SUPPORT_OPTIONS.map((option) => (
<label
<div
key={option.value}
className={cn(
"flex items-start space-x-3 p-2 rounded-md cursor-pointer hover:bg-kumo-tint/50",
isFromCode && "opacity-60 cursor-not-allowed",
"p-2 rounded-md hover:bg-kumo-tint/50",
isFromCode && "opacity-60",
)}
>
<input
type="checkbox"
<Checkbox
checked={supports.includes(option.value)}
onChange={() => handleSupportToggle(option.value)}
className="mt-1 rounded border-kumo-line"
onCheckedChange={() => handleSupportToggle(option.value)}
disabled={isFromCode}
label={
<div>
<span className="text-sm font-medium">{t(option.label)}</span>
<p className="text-xs text-kumo-subtle">{t(option.description)}</p>
</div>
}
/>
<div>
<span className="text-sm font-medium">{t(option.label)}</span>
<p className="text-xs text-kumo-subtle">{t(option.description)}</p>
</div>
</label>
</div>
))}
</div>

{/* SEO toggle */}
<div className="pt-2 border-t">
<label
className={cn(
"flex items-start space-x-3 p-2 rounded-md cursor-pointer hover:bg-kumo-tint/50",
isFromCode && "opacity-60 cursor-not-allowed",
)}
>
<input
type="checkbox"
checked={hasSeo}
onChange={() => setHasSeo(!hasSeo)}
className="mt-1 rounded border-kumo-line"
disabled={isFromCode}
/>
<div>
<span className="text-sm font-medium">{t`SEO`}</span>
<p className="text-xs text-kumo-subtle">
{t`Add SEO metadata fields (title, description, image) and include in sitemap`}
</p>
</div>
</label>
<Switch
checked={hasSeo}
onCheckedChange={(checked) => setHasSeo(checked)}
disabled={isFromCode}
label={
<div>
<span className="text-sm font-medium">{t`SEO`}</span>
<p className="text-xs text-kumo-subtle">
{t`Add SEO metadata fields (title, description, image) and include in sitemap`}
</p>
</div>
}
/>
</div>
</div>

Expand All @@ -493,26 +486,19 @@ export function ContentTypeEditor({
<div className="rounded-lg border p-4 space-y-4">
<h2 className="font-semibold">{t`Comments`}</h2>

<label
className={cn(
"flex items-start space-x-3 p-2 rounded-md cursor-pointer hover:bg-kumo-tint/50",
isFromCode && "opacity-60 cursor-not-allowed",
)}
>
<input
type="checkbox"
checked={commentsEnabled}
onChange={() => setCommentsEnabled(!commentsEnabled)}
className="mt-1 rounded border-kumo-line"
disabled={isFromCode}
/>
<div>
<span className="text-sm font-medium">{t`Enable comments`}</span>
<p className="text-xs text-kumo-subtle">
{t`Allow visitors to leave comments on this collection's content`}
</p>
</div>
</label>
<Switch
checked={commentsEnabled}
onCheckedChange={(checked) => setCommentsEnabled(checked)}
disabled={isFromCode}
label={
<div>
<span className="text-sm font-medium">{t`Enable comments`}</span>
<p className="text-xs text-kumo-subtle">
{t`Allow visitors to leave comments on this collection's content`}
</p>
</div>
}
/>

{commentsEnabled && (
<>
Expand Down Expand Up @@ -545,28 +531,21 @@ export function ContentTypeEditor({
{t`Set to 0 to never close comments automatically.`}
</p>

<label
className={cn(
"flex items-start space-x-3 p-2 rounded-md cursor-pointer hover:bg-kumo-tint/50",
isFromCode && "opacity-60 cursor-not-allowed",
)}
>
<input
type="checkbox"
checked={commentsAutoApproveUsers}
onChange={() => setCommentsAutoApproveUsers(!commentsAutoApproveUsers)}
className="mt-1 rounded border-kumo-line"
disabled={isFromCode}
/>
<div>
<span className="text-sm font-medium">
{t`Auto-approve authenticated users`}
</span>
<p className="text-xs text-kumo-subtle">
{t`Comments from logged-in CMS users are approved automatically`}
</p>
</div>
</label>
<Switch
checked={commentsAutoApproveUsers}
onCheckedChange={(checked) => setCommentsAutoApproveUsers(checked)}
disabled={isFromCode}
label={
<div>
<span className="text-sm font-medium">
{t`Auto-approve authenticated users`}
</span>
<p className="text-xs text-kumo-subtle">
{t`Comments from logged-in CMS users are approved automatically`}
</p>
</div>
}
/>
</>
)}
</div>
Expand Down
65 changes: 25 additions & 40 deletions packages/admin/src/components/FieldEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Dialog, Input, InputArea, Select } from "@cloudflare/kumo";
import { Button, Dialog, Input, InputArea, Select, Switch } from "@cloudflare/kumo";
import { useLingui } from "@lingui/react/macro";
import {
TextT,
Expand Down Expand Up @@ -431,38 +431,26 @@ export function FieldEditor({ open, onOpenChange, field, onSave, isSaving }: Fie

{/* Toggles */}
<div className="flex items-center space-x-6">
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={required}
onChange={(e) => setField("required", e.target.checked)}
className="rounded border-kumo-line"
/>
<span className="text-sm">{t`Required`}</span>
</label>
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={unique}
onChange={(e) => setField("unique", e.target.checked)}
className="rounded border-kumo-line"
/>
<span className="text-sm">{t`Unique`}</span>
</label>
<Switch
checked={required}
onCheckedChange={(checked) => setField("required", checked)}
label={<span className="text-sm">{t`Required`}</span>}
/>
<Switch
checked={unique}
onCheckedChange={(checked) => setField("unique", checked)}
label={<span className="text-sm">{t`Unique`}</span>}
/>
{(selectedType === "string" ||
selectedType === "text" ||
selectedType === "portableText" ||
selectedType === "slug" ||
selectedType === "url") && (
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={searchable}
onChange={(e) => setField("searchable", e.target.checked)}
className="rounded border-kumo-line"
/>
<span className="text-sm">{t`Searchable`}</span>
</label>
<Switch
checked={searchable}
onCheckedChange={(checked) => setField("searchable", checked)}
label={<span className="text-sm">{t`Searchable`}</span>}
/>
)}
</div>

Expand Down Expand Up @@ -600,18 +588,15 @@ export function FieldEditor({ open, onOpenChange, field, onSave, isSaving }: Fie
/>
</div>
</div>
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={sf.required}
onChange={(e) => {
const updated = [...formState.subFields];
updated[i] = { ...sf, required: e.target.checked };
setFormState((prev) => ({ ...prev, subFields: updated }));
}}
/>
{t`Required`}
</label>
<Switch
label={t`Required`}
checked={sf.required ?? false}
onCheckedChange={(checked) => {
const updated = [...formState.subFields];
updated[i] = { ...sf, required: checked };
setFormState((prev) => ({ ...prev, subFields: updated }));
}}
/>
</div>
<Button
variant="ghost"
Expand Down
16 changes: 6 additions & 10 deletions packages/admin/src/components/PluginManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* update/uninstall for marketplace-installed plugins.
*/

import { Badge, Button, Switch, Toast } from "@cloudflare/kumo";
import { Badge, Button, Checkbox, Switch, Toast } from "@cloudflare/kumo";
import { useLingui } from "@lingui/react/macro";
import {
PuzzlePiece,
Expand Down Expand Up @@ -569,15 +569,11 @@ export function UninstallConfirmDialog({
<p className="text-sm text-kumo-subtle">
{t`This will remove the plugin and its bundle from your site.`}
</p>
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={deleteData}
onChange={(e) => setDeleteData(e.target.checked)}
className="rounded border"
/>
{t`Also delete plugin storage data`}
</label>
<Checkbox
checked={deleteData}
onCheckedChange={(checked) => setDeleteData(checked)}
label={t`Also delete plugin storage data`}
/>
<DialogError message={error} />
</div>
<div className="flex justify-end gap-3 border-t px-6 py-4">
Expand Down
16 changes: 6 additions & 10 deletions packages/admin/src/components/PortableTextEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* - Floating menu on empty lines
*/

import { Button, Dialog, Input, Select } from "@cloudflare/kumo";
import { Button, Dialog, Input, Select, Switch } from "@cloudflare/kumo";
import {
DndContext,
KeyboardSensor,
Expand Down Expand Up @@ -1361,15 +1361,11 @@ function BlockKitField({
}
case "toggle": {
return (
<div className="flex items-center gap-2">
<input
type="checkbox"
checked={!!value}
onChange={(e) => onChange(field.action_id, e.target.checked)}
className="h-4 w-4"
/>
<label className="text-sm font-medium">{field.label}</label>
</div>
<Switch
checked={!!value}
onCheckedChange={(checked) => onChange(field.action_id, checked)}
label={<span className="text-sm font-medium">{field.label}</span>}
/>
);
}
case "repeater": {
Expand Down
15 changes: 6 additions & 9 deletions packages/admin/src/components/RepeaterField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Items can be added, removed, and reordered via drag-and-drop.
*/

import { Button, Input, InputArea, Select } from "@cloudflare/kumo";
import { Button, Input, InputArea, Select, Switch } from "@cloudflare/kumo";
import { DndContext, closestCenter } from "@dnd-kit/core";
import type { DragEndEvent } from "@dnd-kit/core";
import {
Expand Down Expand Up @@ -335,14 +335,11 @@ function SubFieldInput({ subField, value, onChange }: SubFieldInputProps) {
);
case "boolean":
return (
<label className="flex items-center gap-2">
<input
type="checkbox"
checked={Boolean(value)}
onChange={(e) => onChange(e.target.checked)}
/>
<span className="text-sm">{subField.label}</span>
</label>
<Switch
checked={Boolean(value)}
onCheckedChange={(checked) => onChange(checked)}
label={<span className="text-sm">{subField.label}</span>}
/>
);
case "datetime":
return (
Expand Down
15 changes: 5 additions & 10 deletions packages/admin/src/components/TaxonomyManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -657,18 +657,13 @@ function CreateTaxonomyDialog({
</p>
<div className="border rounded-md p-2 space-y-1">
{collectionEntries.map(({ slug, label: collLabel }) => (
<label
key={slug}
className="flex items-center gap-2 py-1 px-2 cursor-pointer hover:bg-kumo-tint/50 rounded"
>
<input
type="checkbox"
<div key={slug} className="py-1 px-2 hover:bg-kumo-tint/50 rounded">
<Checkbox
checked={selectedCollections.includes(slug)}
onChange={() => toggleCollection(slug)}
className="rounded"
onCheckedChange={() => toggleCollection(slug)}
label={<span className="text-sm">{collLabel}</span>}
/>
<span className="text-sm">{collLabel}</span>
</label>
</div>
))}
</div>
</div>
Expand Down
Loading
Loading