mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-12-19 19:06:16 +01:00
Theme scrollbars with tailwind-scrollbar (#11723)
This commit is contained in:
parent
9808ff64e7
commit
e6d1ad0ac5
12
web/package-lock.json
generated
12
web/package-lock.json
generated
@ -66,6 +66,7 @@
|
||||
"strftime": "^0.10.2",
|
||||
"swr": "^2.2.5",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vaul": "^0.9.1",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
@ -7389,6 +7390,17 @@
|
||||
"url": "https://github.com/sponsors/dcastil"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-scrollbar": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.1.0.tgz",
|
||||
"integrity": "sha512-pmrtDIZeHyu2idTejfV59SbaJyvp1VRjYxAjZBH0jnyrPRo6HL1kD5Glz8VPagasqr6oAx6M05+Tuw429Z8jxg==",
|
||||
"engines": {
|
||||
"node": ">=12.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": "3.x"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
|
||||
|
@ -72,6 +72,7 @@
|
||||
"strftime": "^0.10.2",
|
||||
"swr": "^2.2.5",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vaul": "^0.9.1",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
|
@ -310,7 +310,7 @@ function NewGroupDialog({
|
||||
<Content
|
||||
className={`min-w-0 ${isMobile ? "max-h-[90%] w-full rounded-t-2xl p-3" : "max-h-dvh w-6/12 overflow-y-hidden"}`}
|
||||
>
|
||||
<div className="my-4 flex flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container my-4 flex flex-col overflow-y-auto">
|
||||
{editState === "none" && (
|
||||
<>
|
||||
<div className="flex flex-row items-center justify-between py-2">
|
||||
@ -400,7 +400,7 @@ export function EditGroupDialog({
|
||||
<DialogContent
|
||||
className={`min-w-0 ${isMobile ? "max-h-[90%] w-full rounded-t-2xl p-3" : "max-h-dvh w-6/12 overflow-y-hidden"}`}
|
||||
>
|
||||
<div className="my-4 flex flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container my-4 flex flex-col overflow-y-auto">
|
||||
<div className="mb-3 flex flex-row items-center justify-between">
|
||||
<DialogTitle>Edit Camera Group</DialogTitle>
|
||||
</div>
|
||||
@ -651,7 +651,7 @@ export function CameraGroupEdit({
|
||||
/>
|
||||
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
<div className="max-h-[25dvh] overflow-y-auto md:max-h-[40dvh]">
|
||||
<div className="scrollbar-container max-h-[25dvh] overflow-y-auto md:max-h-[40dvh]">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cameras"
|
||||
|
@ -58,7 +58,7 @@ export function GeneralFilterContent({
|
||||
}: GeneralFilterContentProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="h-auto overflow-y-auto overflow-x-hidden">
|
||||
<div className="scrollbar-container h-auto overflow-y-auto overflow-x-hidden">
|
||||
<div className="my-2.5 flex items-center justify-between">
|
||||
<Label
|
||||
className="mx-2 cursor-pointer text-primary"
|
||||
|
@ -263,7 +263,7 @@ export function CamerasFilterButton({
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<div className="h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden p-4">
|
||||
<div className="scrollbar-container h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden p-4">
|
||||
<FilterSwitch
|
||||
isChecked={currentCameras == undefined}
|
||||
label="All Cameras"
|
||||
@ -602,7 +602,7 @@ export function GeneralFilterContent({
|
||||
}: GeneralFilterContentProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden">
|
||||
<div className="scrollbar-container h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden">
|
||||
{currentSeverity && setShowAll && (
|
||||
<div className="my-2.5 flex flex-col gap-2.5">
|
||||
<FilterSwitch
|
||||
|
@ -115,7 +115,7 @@ export default function IconPicker({
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
<div className="flex h-full flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container flex h-full flex-col overflow-y-auto">
|
||||
<div className="grid grid-cols-6 gap-2 pr-1">
|
||||
{icons.map(([name, Icon]) => (
|
||||
<div
|
||||
|
@ -62,7 +62,7 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
|
||||
isDesktop ? "mr-5 w-72" : "max-h-[75dvh] overflow-hidden p-2"
|
||||
}
|
||||
>
|
||||
<div className="w-full flex-col overflow-y-auto overflow-x-hidden">
|
||||
<div className="scrollbar-container w-full flex-col overflow-y-auto overflow-x-hidden">
|
||||
<DropdownMenuLabel>
|
||||
Current User: {profile?.username || "anonymous"}
|
||||
</DropdownMenuLabel>
|
||||
|
@ -142,7 +142,7 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
isDesktop ? "mr-5 w-72" : "max-h-[75dvh] overflow-hidden p-2"
|
||||
}
|
||||
>
|
||||
<div className="w-full flex-col overflow-y-auto overflow-x-hidden">
|
||||
<div className="scrollbar-container w-full flex-col overflow-y-auto overflow-x-hidden">
|
||||
<DropdownMenuLabel>System</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup className={isDesktop ? "" : "flex flex-col"}>
|
||||
|
@ -93,7 +93,7 @@ function StatusAlertNav({ className }: StatusAlertNavProps) {
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="flex h-auto w-full flex-col items-center gap-2 overflow-y-auto overflow-x-hidden py-4">
|
||||
<div className="scrollbar-container flex h-auto w-full flex-col items-center gap-2 overflow-y-auto overflow-x-hidden py-4">
|
||||
{Object.entries(messages).map(([key, messageArray]) => (
|
||||
<div key={key} className="flex w-full items-center gap-2">
|
||||
{messageArray.map(({ id, text, color, link }: StatusMessage) => {
|
||||
|
@ -12,7 +12,7 @@ function Sidebar() {
|
||||
const navbarLinks = useNavigation();
|
||||
|
||||
return (
|
||||
<aside className="left-o scrollbar-hidden absolute inset-y-0 z-10 flex w-[52px] flex-col justify-between overflow-y-auto border-r border-secondary-highlight bg-background_alt py-4">
|
||||
<aside className="scrollbar-container scrollbar-hidden absolute inset-y-0 left-0 z-10 flex w-[52px] flex-col justify-between overflow-y-auto border-r border-secondary-highlight bg-background_alt py-4">
|
||||
<span tabIndex={0} className="sr-only" />
|
||||
<div className="flex w-full flex-col items-center gap-0">
|
||||
<Logo className="mb-6 h-8 w-8" />
|
||||
|
@ -28,7 +28,7 @@ export default function MobileCameraDrawer({
|
||||
</Button>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="mx-1 max-h-[75dvh] overflow-hidden rounded-t-2xl px-4">
|
||||
<div className="flex h-auto w-full flex-col items-center gap-2 overflow-y-auto overflow-x-hidden py-4">
|
||||
<div className="scrollbar-container flex h-auto w-full flex-col items-center gap-2 overflow-y-auto overflow-x-hidden py-4">
|
||||
{allCameras.map((cam) => (
|
||||
<div
|
||||
key={cam}
|
||||
|
@ -222,7 +222,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
);
|
||||
} else if (drawerMode == "filter") {
|
||||
content = (
|
||||
<div className="flex h-auto w-full flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container flex h-auto w-full flex-col overflow-y-auto">
|
||||
<div className="relative mb-2 h-8 w-full">
|
||||
<div
|
||||
className="absolute left-0 text-selected"
|
||||
|
@ -33,7 +33,7 @@ export default function VainfoDialog({
|
||||
<DialogTitle>Vainfo Output</DialogTitle>
|
||||
</DialogHeader>
|
||||
{vainfo ? (
|
||||
<div className="mb-2 max-h-96 overflow-y-scroll whitespace-pre-line">
|
||||
<div className="scrollbar-container mb-2 max-h-96 overflow-y-scroll whitespace-pre-line">
|
||||
<div>Return Code: {vainfo.return_code}</div>
|
||||
<br />
|
||||
<div>Process {vainfo.return_code == 0 ? "Output" : "Error"}:</div>
|
||||
|
@ -587,7 +587,7 @@ export function ZoneObjectSelector({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="h-auto overflow-y-auto overflow-x-hidden">
|
||||
<div className="scrollbar-container h-auto overflow-y-auto overflow-x-hidden">
|
||||
<div className="my-2.5 flex items-center justify-between">
|
||||
<Label className="cursor-pointer text-primary" htmlFor="allLabels">
|
||||
All Objects
|
||||
|
@ -24,6 +24,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.scrollbar-container {
|
||||
@apply scrollbar-thumb-rounded-full scrollbar-track-rounded-full scrollbar-thin scrollbar-thumb-border scrollbar-track-background_alt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
|
@ -139,7 +139,7 @@ function Exports() {
|
||||
|
||||
<div className="w-full overflow-hidden">
|
||||
{exports && filteredExports && (
|
||||
<div className="grid size-full gap-2 overflow-y-auto sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
<div className="scrollbar-container grid size-full gap-2 overflow-y-auto sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
{Object.values(exports).map((item) => (
|
||||
<ExportCard
|
||||
key={item.name}
|
||||
|
@ -242,7 +242,7 @@ function CameraSelectButton({
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<div className="mb-5 h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden p-4 md:mb-1">
|
||||
<div className="scrollbar-container mb-5 h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden p-4 md:mb-1">
|
||||
<div className="flex flex-col gap-2.5">
|
||||
{allCameras.map((item) => (
|
||||
<FilterSwitch
|
||||
|
@ -226,7 +226,7 @@ export default function SubmitPlus() {
|
||||
|
||||
return (
|
||||
<div className="flex size-full flex-col">
|
||||
<div className="flex h-16 w-full items-center justify-between overflow-x-auto px-2">
|
||||
<div className="scrollbar-container flex h-16 w-full items-center justify-between overflow-x-auto px-2">
|
||||
<PlusFilterGroup
|
||||
selectedCameras={selectedCameras}
|
||||
selectedLabels={selectedLabels}
|
||||
|
@ -610,7 +610,7 @@ function PtzControlPanel({
|
||||
<BsThreeDotsVertical />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="max-h-[40dvh] overflow-y-auto">
|
||||
<DropdownMenuContent className="scrollbar-container max-h-[40dvh] overflow-y-auto">
|
||||
{ptz?.presets.map((preset) => {
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
|
@ -163,7 +163,7 @@ export default function LiveDashboardView({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="size-full overflow-y-auto px-1 pt-2 md:p-2"
|
||||
className="scrollbar-container size-full overflow-y-auto px-1 pt-2 md:p-2"
|
||||
ref={containerRef}
|
||||
>
|
||||
{isMobile && (
|
||||
|
@ -88,7 +88,7 @@ export default function AuthenticationView() {
|
||||
return (
|
||||
<div className="flex size-full flex-col md:flex-row">
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
|
||||
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
|
||||
<div className="flex flex-row items-center justify-between gap-2">
|
||||
<Heading as="h3" className="my-2">
|
||||
Users
|
||||
|
@ -58,7 +58,7 @@ export default function GeneralSettingsView() {
|
||||
<>
|
||||
<div className="flex size-full flex-col md:flex-row">
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
|
||||
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
|
||||
<Heading as="h3" className="my-2">
|
||||
General Settings
|
||||
</Heading>
|
||||
|
@ -379,7 +379,7 @@ export default function MasksAndZonesView({
|
||||
{cameraConfig && editingPolygons && (
|
||||
<div className="flex size-full flex-col md:flex-row">
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
|
||||
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
|
||||
{editPane == "zone" && (
|
||||
<ZoneEditPane
|
||||
polygons={editingPolygons}
|
||||
|
@ -177,7 +177,7 @@ export default function MotionTunerView({
|
||||
return (
|
||||
<div className="flex size-full flex-col md:flex-row">
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
|
||||
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
|
||||
<Heading as="h3" className="my-2">
|
||||
Motion Detection Tuner
|
||||
</Heading>
|
||||
|
@ -113,7 +113,7 @@ export default function ObjectSettingsView({
|
||||
return (
|
||||
<div className="flex size-full flex-col md:flex-row">
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
|
||||
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
|
||||
<Heading as="h3" className="my-2">
|
||||
Debug
|
||||
</Heading>
|
||||
@ -162,12 +162,10 @@ export default function ObjectSettingsView({
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
key={`${param}-${optionsLoaded}`}
|
||||
key={`${param}-${selectedCamera}`}
|
||||
className="ml-1"
|
||||
id={param}
|
||||
checked={
|
||||
optionsLoaded ? options && options[param] : false
|
||||
}
|
||||
checked={options && options[param]}
|
||||
onCheckedChange={(isChecked) => {
|
||||
handleSetOption(param, isChecked);
|
||||
}}
|
||||
@ -224,7 +222,7 @@ function ObjectList(objects?: ObjectType[]) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container flex w-full flex-col overflow-y-auto">
|
||||
{objects && objects.length > 0 ? (
|
||||
objects.map((obj) => {
|
||||
return (
|
||||
|
@ -204,7 +204,7 @@ export default function CameraMetrics({
|
||||
}, [statsHistory]);
|
||||
|
||||
return (
|
||||
<div className="mt-4 flex size-full flex-col gap-3 overflow-y-auto">
|
||||
<div className="scrollbar-container mt-4 flex size-full flex-col gap-3 overflow-y-auto">
|
||||
<div className="text-sm font-medium text-muted-foreground">Overview</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3">
|
||||
{statsHistory.length != 0 ? (
|
||||
|
@ -344,7 +344,7 @@ export default function GeneralMetrics({
|
||||
<>
|
||||
<VainfoDialog showVainfo={showVainfo} setShowVainfo={setShowVainfo} />
|
||||
|
||||
<div className="mt-4 flex size-full flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container mt-4 flex size-full flex-col overflow-y-auto">
|
||||
<div className="text-sm font-medium text-muted-foreground">
|
||||
Detectors
|
||||
</div>
|
||||
|
@ -42,7 +42,7 @@ export default function StorageMetrics({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-4 flex size-full flex-col overflow-y-auto">
|
||||
<div className="scrollbar-container mt-4 flex size-full flex-col overflow-y-auto">
|
||||
<div className="text-sm font-medium text-muted-foreground">Overview</div>
|
||||
<div className="mt-4 grid grid-cols-1 gap-2 sm:grid-cols-3">
|
||||
<div className="flex-col rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
|
@ -144,5 +144,9 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
plugins: [
|
||||
require("tailwindcss-animate"),
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require("tailwind-scrollbar")({ nocompatible: true }),
|
||||
],
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user