mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-15 08:21:16 +03:00
mobile tweaks
stack buttons, add more space on profiles pane, and move the overridden badge beneath the description
This commit is contained in:
parent
705becba8c
commit
e7ef6139ec
@ -936,7 +936,7 @@ export function ConfigSection({
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex w-full items-center gap-2 md:w-auto">
|
||||
<div className="flex w-full flex-col gap-2 sm:flex-row sm:items-center md:w-auto">
|
||||
{((effectiveLevel === "camera" && isOverridden) ||
|
||||
effectiveLevel === "global") &&
|
||||
!hasChanges &&
|
||||
|
||||
@ -385,7 +385,7 @@ export default function ProfilesView({
|
||||
|
||||
{/* Active Profile + Add Profile bar */}
|
||||
{(hasProfiles || profilesUIEnabled) && (
|
||||
<div className="my-4 flex items-center justify-between rounded-lg border border-border/70 bg-card/30 p-4">
|
||||
<div className="my-4 flex flex-col gap-3 rounded-lg border border-border/70 bg-card/30 p-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
{hasProfiles && (
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm font-semibold text-primary-variant">
|
||||
@ -470,12 +470,12 @@ export default function ProfilesView({
|
||||
)}
|
||||
>
|
||||
<CollapsibleTrigger asChild>
|
||||
<div className="flex cursor-pointer items-center justify-between px-4 py-3 hover:bg-secondary/30">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex cursor-pointer flex-wrap items-center gap-y-2 px-4 py-3 hover:bg-secondary/30">
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
{isExpanded ? (
|
||||
<LuChevronDown className="size-4 text-muted-foreground" />
|
||||
<LuChevronDown className="size-4 shrink-0 text-muted-foreground" />
|
||||
) : (
|
||||
<LuChevronRight className="size-4 text-muted-foreground" />
|
||||
<LuChevronRight className="size-4 shrink-0 text-muted-foreground" />
|
||||
)}
|
||||
<span
|
||||
className={cn(
|
||||
@ -483,13 +483,13 @@ export default function ProfilesView({
|
||||
color.dot,
|
||||
)}
|
||||
/>
|
||||
<span className="font-medium">
|
||||
<span className="truncate font-medium">
|
||||
{profileFriendlyNames?.get(profile) ?? profile}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-6 text-muted-foreground hover:text-primary"
|
||||
className="size-6 shrink-0 text-muted-foreground hover:text-primary"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setRenameProfile(profile);
|
||||
@ -500,6 +500,8 @@ export default function ProfilesView({
|
||||
>
|
||||
<Pencil className="size-3" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="ml-auto flex items-center gap-3">
|
||||
{isActive && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
@ -508,8 +510,6 @@ export default function ProfilesView({
|
||||
{t("profiles.active", { ns: "views/settings" })}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{cameras.length > 0
|
||||
? t("profiles.cameraCount", {
|
||||
@ -523,7 +523,7 @@ export default function ProfilesView({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-7 text-muted-foreground hover:text-destructive"
|
||||
className="size-7 shrink-0 text-muted-foreground hover:text-destructive"
|
||||
disabled={deleting && deleteProfile === profile}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@ -131,34 +131,35 @@ export function SingleSectionPage({
|
||||
|
||||
return (
|
||||
<div className="flex size-full flex-col lg:pr-2">
|
||||
<div className="mb-5 flex items-center justify-between gap-4">
|
||||
<div className="flex flex-col">
|
||||
<Heading as="h4">
|
||||
{t(`${sectionKey}.label`, { ns: sectionNamespace })}
|
||||
</Heading>
|
||||
{i18n.exists(`${sectionKey}.description`, {
|
||||
ns: sectionNamespace,
|
||||
}) && (
|
||||
<div className="my-1 text-sm text-muted-foreground">
|
||||
{t(`${sectionKey}.description`, { ns: sectionNamespace })}
|
||||
</div>
|
||||
)}
|
||||
{sectionDocsUrl && (
|
||||
<div className="flex items-center text-sm text-primary-variant">
|
||||
<Link
|
||||
to={sectionDocsUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
{t("readTheDocumentation", { ns: "common" })}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-2 md:flex-row md:items-center">
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<div className="mb-5 flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex flex-col">
|
||||
<Heading as="h4">
|
||||
{t(`${sectionKey}.label`, { ns: sectionNamespace })}
|
||||
</Heading>
|
||||
{i18n.exists(`${sectionKey}.description`, {
|
||||
ns: sectionNamespace,
|
||||
}) && (
|
||||
<div className="my-1 text-sm text-muted-foreground">
|
||||
{t(`${sectionKey}.description`, { ns: sectionNamespace })}
|
||||
</div>
|
||||
)}
|
||||
{sectionDocsUrl && (
|
||||
<div className="flex items-center text-sm text-primary-variant">
|
||||
<Link
|
||||
to={sectionDocsUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
{t("readTheDocumentation", { ns: "common" })}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* Desktop: badge inline next to title */}
|
||||
<div className="hidden shrink-0 sm:flex sm:flex-wrap sm:items-center sm:gap-2">
|
||||
{level === "camera" &&
|
||||
showOverrideIndicator &&
|
||||
sectionStatus.isOverridden && (
|
||||
@ -211,6 +212,40 @@ export function SingleSectionPage({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* Mobile: badge below title/description */}
|
||||
<div className="flex flex-wrap items-center gap-2 sm:hidden">
|
||||
{level === "camera" &&
|
||||
showOverrideIndicator &&
|
||||
sectionStatus.isOverridden && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn(
|
||||
"cursor-default border-2 text-center text-xs text-primary-variant",
|
||||
sectionStatus.overrideSource === "profile" && profileColor
|
||||
? profileColor.border
|
||||
: "border-selected",
|
||||
)}
|
||||
>
|
||||
{sectionStatus.overrideSource === "profile"
|
||||
? t("button.overriddenBaseConfig", {
|
||||
ns: "views/settings",
|
||||
defaultValue: "Overridden (Base Config)",
|
||||
})
|
||||
: t("button.overriddenGlobal", {
|
||||
ns: "views/settings",
|
||||
defaultValue: "Overridden (Global)",
|
||||
})}
|
||||
</Badge>
|
||||
)}
|
||||
{sectionStatus.hasChanges && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="cursor-default bg-danger text-xs text-white hover:bg-danger"
|
||||
>
|
||||
{t("modified", { ns: "common", defaultValue: "Modified" })}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<ConfigSectionTemplate
|
||||
sectionKey={sectionKey}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user