diff --git a/src/app/admin/catalog/[id]/catalog-items-table/field-helpers.tsx b/src/app/admin/catalog/[id]/catalog-items-table/field-helpers.tsx
index 7f1d41ccc1..008904f0b9 100644
--- a/src/app/admin/catalog/[id]/catalog-items-table/field-helpers.tsx
+++ b/src/app/admin/catalog/[id]/catalog-items-table/field-helpers.tsx
@@ -1,7 +1,7 @@
"use client";
import { Check, ChevronsUpDown, Star } from "lucide-react";
-import { useMemo, useState } from "react";
+import { useId, useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import {
Command,
@@ -37,11 +37,15 @@ export function ToggleField({
onChange: (v: boolean) => void;
disabled?: boolean;
}) {
+ const id = useId();
const isChecked = checked ?? (value === 1 || value === "1");
return (
-
+
-
+
Hide from public
setGeneral({ ...general, hidden_rank: v ? "1" : "0" })
@@ -361,12 +364,15 @@ export function RankEditClient({
-
+
Record to audit log
setGeneral({ ...general, log_commands: v ? "1" : "0" })
diff --git a/src/app/admin/polls/poll-form.tsx b/src/app/admin/polls/poll-form.tsx
index 014e5c4fa6..a91b65ba6b 100644
--- a/src/app/admin/polls/poll-form.tsx
+++ b/src/app/admin/polls/poll-form.tsx
@@ -146,19 +146,23 @@ export function PollForm({ defaultValues }: PollFormProps) {
form.setValue("showResults", v ? 1 : 0)}
/>
-
+
form.setValue("multipleChoice", v ? 1 : 0)
}
/>
-
+
diff --git a/src/components/admin/catalog-manager/catalog-access.module.css b/src/components/admin/catalog-manager/catalog-access.module.css
index 11b4bcb7a4..a585a2eac8 100644
--- a/src/components/admin/catalog-manager/catalog-access.module.css
+++ b/src/components/admin/catalog-manager/catalog-access.module.css
@@ -39,32 +39,6 @@
line-height: 1.5;
color: var(--admin-text-muted);
}
-.toggle[data-slot="switch"] {
- width: 44px;
- height: 24px;
- border: 1px solid var(--admin-text-muted);
- background: var(--admin-border);
- cursor: pointer;
-}
-.toggle[data-checked] {
- background: var(--admin-accent);
- border-color: var(--admin-accent);
-}
-.toggle [data-slot="switch-thumb"] {
- width: 18px;
- height: 18px;
- left: 2px;
- background: var(--admin-text);
- color: var(--admin-canvas);
-}
-.toggle[data-checked] [data-slot="switch-thumb"] {
- left: 22px;
-}
-.toggle:focus-visible {
- outline: 2px solid var(--admin-accent);
- outline-offset: 3px;
-}
-.option[data-disabled] .toggle,
.option[data-disabled] .label {
cursor: not-allowed;
}
diff --git a/src/components/admin/catalog-manager/inline-editor.tsx b/src/components/admin/catalog-manager/inline-editor.tsx
index 564a77ddaf..a8879b0579 100644
--- a/src/components/admin/catalog-manager/inline-editor.tsx
+++ b/src/components/admin/catalog-manager/inline-editor.tsx
@@ -864,7 +864,6 @@ function ToggleRow({
onCheckedChange={onChange}
disabled={disabled}
aria-describedby={`${id}-description`}
- className={styles.toggle}
/>
diff --git a/src/components/ui/switch.module.css b/src/components/ui/switch.module.css
new file mode 100644
index 0000000000..9378228864
--- /dev/null
+++ b/src/components/ui/switch.module.css
@@ -0,0 +1,105 @@
+.root {
+ --switch-off: var(--color-input);
+ --switch-on: var(--color-primary);
+ --switch-border: var(--color-muted-foreground);
+ --switch-thumb: var(--color-foreground);
+ --switch-mark: var(--color-background);
+ position: relative;
+ display: inline-flex;
+ flex-shrink: 0;
+ width: 44px;
+ height: 24px;
+ border: 1px solid var(--switch-border);
+ border-radius: 999px;
+ background: var(--switch-off);
+ cursor: pointer;
+ outline: none;
+ transition:
+ background-color 150ms,
+ border-color 150ms;
+}
+body:has([data-admin]) .root {
+ --switch-off: var(--admin-border);
+ --switch-on: var(--admin-accent);
+ --switch-border: var(--admin-text-muted);
+ --switch-thumb: var(--admin-text);
+ --switch-mark: var(--admin-canvas);
+}
+.root[data-checked] {
+ background: var(--switch-on);
+ border-color: var(--switch-on);
+}
+.root:focus-visible {
+ outline: 2px solid var(--switch-on);
+ outline-offset: 3px;
+}
+.root[data-disabled] {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+.thumb {
+ pointer-events: none;
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 18px;
+ height: 18px;
+ top: 50%;
+ left: 2px;
+ transform: translateY(-50%);
+ border-radius: 999px;
+ background: var(--switch-thumb);
+ color: var(--switch-mark);
+ transition: left 150ms;
+}
+.root[data-checked] .thumb {
+ left: 22px;
+}
+.check {
+ width: 10px;
+ height: 10px;
+ stroke-width: 3;
+ opacity: 0;
+}
+.root[data-checked] .check {
+ opacity: 1;
+}
+.root[data-size="sm"] {
+ width: 32px;
+ height: 20px;
+}
+.root[data-size="sm"] .thumb {
+ width: 14px;
+ height: 14px;
+}
+.root[data-size="sm"][data-checked] .thumb {
+ left: 14px;
+}
+.root[data-size="sm"] .check {
+ width: 8px;
+ height: 8px;
+}
+@media (prefers-reduced-motion: reduce) {
+ .root,
+ .thumb {
+ transition: none;
+ }
+}
+@media (forced-colors: active) {
+ .root {
+ border-color: ButtonText;
+ background: Canvas;
+ }
+ .root[data-checked] {
+ background: Highlight;
+ border-color: Highlight;
+ }
+ .thumb {
+ background: ButtonText;
+ color: Canvas;
+ }
+ .root:focus-visible {
+ outline-color: Highlight;
+ }
+}
diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx
index 3d140508e5..0da12dfd3e 100644
--- a/src/components/ui/switch.tsx
+++ b/src/components/ui/switch.tsx
@@ -4,6 +4,7 @@ import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
import { CheckIcon } from "lucide-react";
import { cn } from "@/lib/utils";
+import styles from "./switch.module.css";
function Switch({
className,
@@ -16,35 +17,11 @@ function Switch({
-
-
+
+
);