UI tweaks (#23346)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled

* remove redundant per-view toasters in settings

* add variants to standardize dialog footer button layouts

* remove text-md

this class name compiles to nothing in tailwind. we used to add it to prevent iOS from zooming when focusing on an input, but that is now solved via the viewport meta in index.html

* make wizard footers consistent with dialog footers

* consistent destructive button style

remove text-white from individual buttons and add it to the variant
This commit is contained in:
Josh Hawkins
2026-05-29 16:00:30 -06:00
committed by GitHub
parent 4b6fa49449
commit 6fdd65ddb5
88 changed files with 440 additions and 593 deletions
+24 -30
View File
@@ -213,36 +213,30 @@ export default function CreateRoleDialog({
<FormMessage />
</div>
<DialogFooter className="flex gap-2 pt-2 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
className="flex flex-1"
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter className="pt-2">
<Button
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</DialogFooter>
</form>
</Form>
@@ -433,36 +433,30 @@ export default function CreateTriggerDialog({
)}
/>
<DialogFooter className="flex gap-2 pt-2 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
className="flex flex-1"
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter className="pt-2">
<Button
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</DialogFooter>
</form>
</Form>
+24 -30
View File
@@ -411,36 +411,30 @@ export default function CreateUserDialog({
)}
/>
<DialogFooter className="flex gap-2 pt-2 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
className="flex flex-1"
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter className="pt-2">
<Button
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</DialogFooter>
</form>
</Form>
@@ -144,7 +144,7 @@ export function CustomTimeSelector({
/>
<SelectSeparator className="bg-secondary" />
<input
className="text-md mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
className="mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
id="startTime"
type="time"
value={startClock}
@@ -210,7 +210,7 @@ export function CustomTimeSelector({
/>
<SelectSeparator className="bg-secondary" />
<input
className="text-md mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
className="mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
id="endTime"
type="time"
value={endClock}
@@ -113,19 +113,14 @@ export function DebugReplayContent({
{isDesktop && <SelectSeparator className="my-4 bg-secondary" />}
<DialogFooter
className={isDesktop ? "" : "mt-3 flex flex-col-reverse gap-2"}
>
<DialogFooter className="mt-3 sm:mt-0">
<Button
className={isDesktop ? "" : "w-full"}
aria-label={t("button.cancel", { ns: "common" })}
variant="outline"
onClick={onCancel}
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
className={isDesktop ? "" : "w-full"}
variant="select"
disabled={isStarting}
onClick={() => {
+25 -32
View File
@@ -70,38 +70,31 @@ export default function DeleteRoleDialog({
</div>
</div>
<DialogFooter className="flex gap-2 pt-2 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
variant="outline"
disabled={isLoading}
onClick={onCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
className="flex flex-1"
aria-label={t("button.delete", { ns: "common" })}
variant="destructive"
disabled={isLoading}
onClick={handleDelete}
type="button"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("roles.dialog.deleteRole.deleting")}</span>
</div>
) : (
t("button.delete", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={onCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
aria-label={t("button.delete", { ns: "common" })}
variant="destructive"
disabled={isLoading}
onClick={handleDelete}
type="button"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("roles.dialog.deleteRole.deleting")}</span>
</div>
) : (
t("button.delete", { ns: "common" })
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -43,36 +43,30 @@ export default function DeleteTriggerDialog({
</Trans>
</DialogDescription>
</DialogHeader>
<DialogFooter className="flex gap-3 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
disabled={isLoading}
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
aria-label={t("button.delete", { ns: "common" })}
className="flex flex-1 text-white"
onClick={onDelete}
disabled={isLoading}
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.delete", { ns: "common" })}</span>
</div>
) : (
t("button.delete", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
disabled={isLoading}
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
aria-label={t("button.delete", { ns: "common" })}
onClick={onDelete}
disabled={isLoading}
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.delete", { ns: "common" })}</span>
</div>
) : (
t("button.delete", { ns: "common" })
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
+15 -21
View File
@@ -46,27 +46,21 @@ export default function DeleteUserDialog({
</p>
</div>
<DialogFooter className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
aria-label={t("button.delete", { ns: "common" })}
className="flex flex-1 text-white"
onClick={onDelete}
>
{t("button.delete", { ns: "common" })}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
aria-label={t("button.delete", { ns: "common" })}
onClick={onDelete}
>
{t("button.delete", { ns: "common" })}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -105,13 +105,15 @@ export default function EditRoleCamerasDialog({
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-5 pt-4"
className="space-y-5 pt-2"
>
<div className="space-y-2">
<FormLabel>{t("roles.dialog.form.cameras.title")}</FormLabel>
<FormDescription className="text-xs text-muted-foreground">
{t("roles.dialog.form.cameras.desc")}
</FormDescription>
<div className="space-y-3">
<div>
<FormLabel>{t("roles.dialog.form.cameras.title")}</FormLabel>
<FormDescription className="text-xs text-muted-foreground">
{t("roles.dialog.form.cameras.desc")}
</FormDescription>
</div>
<div className="scrollbar-container max-h-[40dvh] space-y-2 overflow-y-auto">
{cameras.map((camera) => (
<FormField
@@ -159,36 +161,30 @@ export default function EditRoleCamerasDialog({
<FormMessage />
</div>
<DialogFooter className="flex gap-2 pt-2 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
className="flex flex-1"
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
disabled={isLoading}
onClick={handleCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading || !form.formState.isValid}
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</DialogFooter>
</form>
</Form>
+1 -14
View File
@@ -794,7 +794,6 @@ export function ExportContent({
)}
<Input
className="text-md"
type="search"
placeholder={t("export.name.placeholder")}
value={name}
@@ -835,13 +834,11 @@ export function ExportContent({
{selectedCaseId === "new" && (
<div className="space-y-2 pt-1">
<Input
className="text-md"
placeholder={t("export.case.newCaseNamePlaceholder")}
value={singleNewCaseName}
onChange={(e) => setSingleNewCaseName(e.target.value)}
/>
<Textarea
className="text-md"
placeholder={t("export.case.newCaseDescriptionPlaceholder")}
value={singleNewCaseDescription}
onChange={(e) =>
@@ -988,7 +985,6 @@ export function ExportContent({
{t("export.multiCamera.nameLabel")}
</Label>
<Input
className="text-md"
type="search"
placeholder={t("export.multiCamera.namePlaceholder")}
value={name}
@@ -1028,13 +1024,11 @@ export function ExportContent({
{batchCaseSelection === "new" && (
<div className="space-y-2 pt-1">
<Input
className="text-md"
placeholder={t("export.case.newCaseNamePlaceholder")}
value={newCaseName}
onChange={(event) => setNewCaseName(event.target.value)}
/>
<Textarea
className="text-md"
placeholder={t("export.case.newCaseDescriptionPlaceholder")}
value={newCaseDescription}
onChange={(event) =>
@@ -1049,20 +1043,15 @@ export function ExportContent({
</Tabs>
{isDesktop && <SelectSeparator className="my-4 bg-secondary" />}
<DialogFooter
className={isDesktop ? "" : "mt-3 flex flex-col-reverse gap-2"}
>
<DialogFooter className="mt-3 sm:mt-0">
<Button
className={isDesktop ? "" : "w-full"}
aria-label={t("button.cancel", { ns: "common" })}
variant="outline"
onClick={onCancel}
>
{t("button.cancel", { ns: "common" })}
</Button>
{activeTab === "export" ? (
<Button
className={isDesktop ? "" : "w-full"}
aria-label={t("export.selectOrExport")}
variant="select"
disabled={isStartingExport}
@@ -1086,12 +1075,10 @@ export function ExportContent({
</Button>
) : (
<Button
className={isDesktop ? "" : "w-full"}
aria-label={t("export.multiCamera.exportButton", {
count: selectedCameraCount,
})}
variant="select"
size="sm"
disabled={!canStartBatchExport}
onClick={() => void startBatchExport()}
>
+1 -1
View File
@@ -85,7 +85,7 @@ export default function ImagePicker({
<Input
type="text"
placeholder={t("imagePicker.search.placeholder")}
className="text-md mb-3 md:text-sm"
className="mb-3 md:text-sm"
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
@@ -290,7 +290,6 @@ export default function MultiExportDialog({
const newCaseInputs = (
<div className="space-y-2 pt-1">
<Input
className="text-md"
placeholder={t("export.case.newCaseNamePlaceholder")}
value={newCaseName}
onChange={(event) => setNewCaseName(event.target.value)}
@@ -298,7 +297,6 @@ export default function MultiExportDialog({
autoFocus={isDesktop}
/>
<Textarea
className="text-md"
placeholder={t("export.case.newCaseDescriptionPlaceholder")}
value={newCaseDescription}
onChange={(event) => setNewCaseDescription(event.target.value)}
@@ -344,11 +342,7 @@ export default function MultiExportDialog({
const footer = (
<>
<Button
variant="outline"
onClick={() => handleOpenChange(false)}
disabled={isExporting}
>
<Button onClick={() => handleOpenChange(false)} disabled={isExporting}>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
@@ -380,7 +374,7 @@ export default function MultiExportDialog({
</DialogDescription>
</DialogHeader>
{body}
<DialogFooter className="gap-2">{footer}</DialogFooter>
<DialogFooter>{footer}</DialogFooter>
</DialogContent>
</Dialog>
);
@@ -399,7 +393,7 @@ export default function MultiExportDialog({
</DrawerDescription>
</DrawerHeader>
{body}
<div className="mt-4 flex flex-col-reverse gap-2">{footer}</div>
<DialogFooter className="mt-4">{footer}</DialogFooter>
</DrawerContent>
</Drawer>
);
+17 -24
View File
@@ -117,30 +117,23 @@ export default function RoleChangeDialog({
</Select>
</div>
<DialogFooter className="flex gap-3 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
variant="outline"
onClick={onCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
className="flex flex-1"
onClick={() => onSave(selectedRole)}
type="button"
disabled={selectedRole === currentRole}
>
{t("button.save", { ns: "common" })}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
onClick={() => onSave(selectedRole)}
type="button"
disabled={selectedRole === currentRole}
>
{t("button.save", { ns: "common" })}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -450,36 +450,30 @@ export default function SetPasswordDialog({
</div>
)}
<DialogFooter className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
disabled={isLoading}
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
className="flex flex-1"
type="submit"
disabled={isLoading || !form.formState.isValid}
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
onClick={onCancel}
type="button"
disabled={isLoading}
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
type="submit"
disabled={isLoading || !form.formState.isValid}
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator className="size-4" />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
</DialogFooter>
</form>
</Form>
@@ -196,21 +196,16 @@ export function ShareTimestampContent({
{isDesktop && <Separator className="my-4 bg-secondary" />}
<DialogFooter
className={cn("mt-4", !isDesktop && "flex flex-col-reverse gap-2")}
>
<DialogFooter className="mt-3 sm:mt-0">
{onCancel && (
<Button
className={cn(!isDesktop && "w-full")}
aria-label={t("button.cancel", { ns: "common" })}
variant="outline"
onClick={onCancel}
>
{t("button.cancel", { ns: "common" })}
</Button>
)}
<Button
className={cn(!isDesktop && "w-full")}
variant="select"
onClick={() => onShareTimestamp(Math.floor(selectedTimestamp))}
>
@@ -338,7 +333,7 @@ function CustomTimestampSelector({
/>
<div className="my-3 h-px w-full bg-secondary" />
<input
className="text-md mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
className="mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
id="shareTimestamp"
type="time"
value={clock}
@@ -145,7 +145,7 @@ export function AnnotationSettingsPane({
return (
<div className="p-4">
<div className="text-md mb-2">
<div className="mb-2">
{t("trackingDetails.annotationSettings.title")}
</div>
@@ -131,7 +131,7 @@ export default function CreateFaceWizardDialog({
forbiddenPattern={/#/}
forbiddenErrorMessage={t("description.nameCannotContainHash")}
>
<div className="flex justify-end py-2">
<div className="flex flex-col-reverse gap-2 py-2 sm:flex-row sm:justify-end">
<Button variant="select" type="submit">
{t("button.next", { ns: "common" })}
</Button>
@@ -144,7 +144,7 @@ export default function CreateFaceWizardDialog({
{t("steps.description.uploadFace", { name })}
</div>
<ImageEntry onSave={onUploadImage}>
<div className="flex justify-end py-2">
<div className="flex flex-col-reverse gap-2 py-2 sm:flex-row sm:justify-end">
<Button variant="select" type="submit">
{t("button.next", { ns: "common" })}
</Button>
@@ -173,7 +173,7 @@ export default function CreateFaceWizardDialog({
<LuExternalLink className="ml-2 inline-flex size-3" />
</Link>
</div>
<div className="flex justify-end">
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<Button
variant="select"
onClick={() => {
@@ -1569,7 +1569,7 @@ function ObjectDetailsTab({
{t("button.yes", { ns: "common" })}
</Button>
<Button
className="flex-1 text-white"
className="flex-1"
aria-label={t("button.no", { ns: "common" })}
variant="destructive"
onClick={() => {
@@ -1706,7 +1706,7 @@ function ObjectDetailsTab({
) : (
<div className="flex flex-col gap-2">
<Textarea
className="text-md h-32 md:text-sm"
className="h-32 md:text-sm"
placeholder={t("details.description.placeholder")}
value={desc}
onChange={(e) => setDesc(e.target.value)}
@@ -821,7 +821,7 @@ export function TrackingDetails({
</div>
<div className="flex items-center gap-2">
<span className="capitalize">{label}</span>
<div className="md:text-md flex items-center text-xs text-secondary-foreground">
<div className="flex items-center text-xs text-secondary-foreground">
{formattedStart ?? ""}
{event.end_time != null ? (
<> - {formattedEnd}</>
@@ -1072,7 +1072,7 @@ function LifecycleIconRow({
<div className="ml-2 flex w-full min-w-0 flex-1">
<div className="flex flex-col">
<div className="text-md flex items-start break-words text-left">
<div className="flex items-start break-words text-left">
{getLifecycleItemDescription(item)}
</div>
{/* Only show Score/Ratio/Area for object events, not for audio (heard) or manual API (external) events */}
@@ -121,28 +121,22 @@ export default function DeleteCameraDialog({
))}
</SelectContent>
</Select>
<DialogFooter className="flex gap-3 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.cancel", { ns: "common" })}
onClick={handleClose}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
aria-label={t("button.delete", { ns: "common" })}
className="flex flex-1 text-white"
onClick={handleDelete}
disabled={!selectedCamera}
>
{t("button.delete", { ns: "common" })}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.cancel", { ns: "common" })}
onClick={handleClose}
type="button"
>
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
aria-label={t("button.delete", { ns: "common" })}
onClick={handleDelete}
disabled={!selectedCamera}
>
{t("button.delete", { ns: "common" })}
</Button>
</DialogFooter>
</>
) : (
@@ -173,39 +167,31 @@ export default function DeleteCameraDialog({
{t("cameraManagement.deleteCameraDialog.deleteExports")}
</Label>
</div>
<DialogFooter className="flex gap-3 sm:justify-end">
<div className="flex flex-1 flex-col justify-end">
<div className="flex flex-row gap-2 pt-5">
<Button
className="flex flex-1"
aria-label={t("button.back", { ns: "common" })}
onClick={handleBack}
type="button"
disabled={isDeleting}
>
{t("button.back", { ns: "common" })}
</Button>
<Button
variant="destructive"
className="flex flex-1 text-white"
onClick={handleConfirmDelete}
disabled={isDeleting}
>
{isDeleting ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>
{t(
"cameraManagement.deleteCameraDialog.confirmButton",
)}
</span>
</div>
) : (
t("cameraManagement.deleteCameraDialog.confirmButton")
)}
</Button>
</div>
</div>
<DialogFooter>
<Button
aria-label={t("button.back", { ns: "common" })}
onClick={handleBack}
type="button"
disabled={isDeleting}
>
{t("button.back", { ns: "common" })}
</Button>
<Button
variant="destructive"
onClick={handleConfirmDelete}
disabled={isDeleting}
>
{isDeleting ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>
{t("cameraManagement.deleteCameraDialog.confirmButton")}
</span>
</div>
) : (
t("cameraManagement.deleteCameraDialog.confirmButton")
)}
</Button>
</DialogFooter>
</>
)}
@@ -173,7 +173,7 @@ export function FrigatePlusDialog({
{t("button.yes", { ns: "common" })}
</Button>
<Button
className="flex-1 text-white"
className="flex-1"
aria-label={t("button.no", { ns: "common" })}
variant="destructive"
onClick={() => {
@@ -7,9 +7,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import { useState } from "react";
import { isMobile } from "react-device-detect";
import { useTranslation } from "react-i18next";
import FilterSwitch from "@/components/filter/FilterSwitch";
@@ -77,7 +75,7 @@ export default function MultiSelectDialog({
/>
))}
</div>
<DialogFooter className={cn("pt-4", isMobile && "gap-2")}>
<DialogFooter className="pt-4">
<Button type="button" onClick={() => setOpen(false)}>
{t("button.cancel")}
</Button>
@@ -144,18 +144,13 @@ export default function OptionAndInputDialog({
<label className="text-sm font-medium text-secondary-foreground">
{nameLabel}
</label>
<Input
className="text-md"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<Input value={name} onChange={(e) => setName(e.target.value)} />
</div>
<div className="space-y-1">
<label className="text-sm font-medium text-secondary-foreground">
{descriptionLabel}
</label>
<Textarea
className="text-md"
value={descriptionValue}
onChange={(e) => setDescriptionValue(e.target.value)}
rows={2}
@@ -164,10 +159,9 @@ export default function OptionAndInputDialog({
</div>
)}
<DialogFooter className={cn("pt-2", isMobile && "gap-2")}>
<DialogFooter>
<Button
type="button"
variant="outline"
disabled={isLoading}
onClick={() => {
setOpen(false);
@@ -349,7 +349,7 @@ function TimeRangeFilterContent({
</PopoverTrigger>
<PopoverContent className="flex flex-row items-center justify-center">
<input
className="text-md mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
className="mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
id="startTime"
type="time"
value={selectedAfterHour}
@@ -389,7 +389,7 @@ function TimeRangeFilterContent({
</PopoverTrigger>
<PopoverContent className="flex flex-col items-center">
<input
className="text-md mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
className="mx-4 w-full border border-input bg-background p-1 text-secondary-foreground hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
id="startTime"
type="time"
value={
@@ -9,8 +9,6 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import { isMobile } from "react-device-detect";
import { useTranslation } from "react-i18next";
type TextEntryDialogProps = {
@@ -63,7 +61,7 @@ export default function TextEntryDialog({
forbiddenPattern={forbiddenPattern}
forbiddenErrorMessage={forbiddenErrorMessage}
>
<DialogFooter className={cn("pt-4", isMobile && "gap-2")}>
<DialogFooter>
<Button
type="button"
disabled={isSaving}