Skip to content

Commit

Permalink
add search settings for columns and default view selection
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkeye217 committed Oct 16, 2024
1 parent b943a6f commit 754d897
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 69 deletions.
4 changes: 2 additions & 2 deletions web/src/components/overlay/dialog/SearchFilterDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FaArrowRight, FaCog } from "react-icons/fa";
import { FaArrowRight, FaFilter } from "react-icons/fa";

import { useEffect, useMemo, useState } from "react";
import { PlatformAwareSheet } from "./PlatformAwareDialog";
Expand Down Expand Up @@ -66,7 +66,7 @@ export default function SearchFilterDialog({
size="sm"
variant={moreFiltersSelected ? "select" : "default"}
>
<FaCog
<FaFilter
className={cn(
moreFiltersSelected ? "text-white" : "text-secondary-foreground",
)}
Expand Down
97 changes: 97 additions & 0 deletions web/src/components/settings/SearchSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Button } from "../ui/button";
import { useState } from "react";
import { isDesktop } from "react-device-detect";
import { cn } from "@/lib/utils";
import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog";
import { FaCog } from "react-icons/fa";
import { Slider } from "../ui/slider";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
} from "@/components/ui/select";

type SearchSettingsProps = {
className?: string;
columns: number;
defaultView: string;
setColumns: (columns: number) => void;
setDefaultView: (view: string) => void;
};
export default function SearchSettings({
className,
columns,
setColumns,
defaultView,
setDefaultView,
}: SearchSettingsProps) {
const [open, setOpen] = useState(false);

const trigger = (
<Button className="flex items-center gap-2" size="sm">
<FaCog className="text-secondary-foreground" />
Settings
</Button>
);
const content = (
<div className={cn(className, "space-y-3")}>
<div className="flex w-full flex-col space-y-4">
<div className="text-md leading-none">Grid Columns</div>
<div className="flex items-center space-x-4">
<Slider
value={[columns]}
onValueChange={([value]) => setColumns(value)}
max={6}
min={2}
step={1}
className="flex-grow"
/>
<span className="w-9 text-center text-sm font-medium">{columns}</span>
</div>
</div>

<div className="space-y-4">
<div className="text-md">Default View</div>
<Select
value={defaultView}
onValueChange={(value) => setDefaultView(value)}
>
<SelectTrigger className="w-full">
{defaultView == "summary" ? "Summary" : "Unfiltered Grid"}
</SelectTrigger>
<SelectContent>
<SelectGroup>
{["summary", "grid"].map((value) => (
<SelectItem
key={value}
className="cursor-pointer"
value={value}
>
{value == "summary" ? "Summary" : "Unfiltered Grid"}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
);

return (
<PlatformAwareDialog
trigger={trigger}
content={content}
contentClassName={
isDesktop
? "scrollbar-container h-auto max-h-[80dvh] overflow-y-auto"
: "max-h-[75dvh] overflow-hidden p-4"
}
open={open}
onOpenChange={(open) => {
setOpen(open);
}}
/>
);
}
25 changes: 23 additions & 2 deletions web/src/pages/Explore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ActivityIndicator from "@/components/indicators/activity-indicator";
import AnimatedCircularProgressBar from "@/components/ui/circular-progress-bar";
import { useApiFilterArgs } from "@/hooks/use-api-filter";
import { useTimezone } from "@/hooks/use-date-utils";
import { usePersistence } from "@/hooks/use-persistence";
import { FrigateConfig } from "@/types/frigateConfig";
import { SearchFilter, SearchQuery, SearchResult } from "@/types/search";
import { ModelState } from "@/types/ws";
Expand All @@ -28,6 +29,18 @@ export default function Explore() {
revalidateOnFocus: false,
});

// grid

const [columnCount, setColumnCount] = usePersistence("exploreGridColumns", 4);
const gridColumns = useMemo(() => columnCount ?? 4, [columnCount]);

// default layout

const [defaultView, setDefaultView] = usePersistence(
"exploreDefaultView",
"summary",
);

const timezone = useTimezone(config);

const [search, setSearch] = useState("");
Expand Down Expand Up @@ -65,7 +78,11 @@ export default function Explore() {
const searchQuery: SearchQuery = useMemo(() => {
// no search parameters
if (searchSearchParams && Object.keys(searchSearchParams).length === 0) {
return null;
if (defaultView == "grid") {
return ["events", {}];
} else {
return null;
}
}

// parameters, but no search term and not similarity
Expand Down Expand Up @@ -117,7 +134,7 @@ export default function Explore() {
include_thumbnails: 0,
},
];
}, [searchTerm, searchSearchParams, similaritySearch, timezone]);
}, [searchTerm, searchSearchParams, similaritySearch, timezone, defaultView]);

// paging

Expand Down Expand Up @@ -385,6 +402,8 @@ export default function Explore() {
searchResults={searchResults}
isLoading={(isLoadingInitialData || isLoadingMore) ?? true}
hasMore={!isReachingEnd}
columns={gridColumns}
defaultView={defaultView}
setSearch={setSearch}
setSimilaritySearch={(search) => {
setSearchFilter({
Expand All @@ -395,6 +414,8 @@ export default function Explore() {
}}
setSearchFilter={setSearchFilter}
onUpdateFilter={setSearchFilter}
setColumns={setColumnCount}
setDefaultView={setDefaultView}
loadMore={loadMore}
refresh={mutate}
/>
Expand Down
90 changes: 25 additions & 65 deletions web/src/views/search/SearchView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@ import SearchDetailDialog, {
SearchTab,
} from "@/components/overlay/detail/SearchDetailDialog";
import { Toaster } from "@/components/ui/sonner";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { FrigateConfig } from "@/types/frigateConfig";
import { SearchFilter, SearchResult, SearchSource } from "@/types/search";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { isDesktop, isMobileOnly } from "react-device-detect";
import { LuColumns, LuSearchX } from "react-icons/lu";
import { isMobileOnly } from "react-device-detect";
import { LuSearchX } from "react-icons/lu";
import useSWR from "swr";
import ExploreView from "../explore/ExploreView";
import useKeyboardListener, {
Expand All @@ -26,14 +21,8 @@ import InputWithTags from "@/components/input/InputWithTags";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { isEqual } from "lodash";
import { formatDateToLocaleString } from "@/utils/dateUtil";
import { Slider } from "@/components/ui/slider";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { usePersistence } from "@/hooks/use-persistence";
import SearchThumbnailFooter from "@/components/card/SearchThumbnailFooter";
import SearchSettings from "@/components/settings/SearchSettings";

type SearchViewProps = {
search: string;
Expand All @@ -42,12 +31,16 @@ type SearchViewProps = {
searchResults?: SearchResult[];
isLoading: boolean;
hasMore: boolean;
columns: number;
defaultView?: string;
setSearch: (search: string) => void;
setSimilaritySearch: (search: SearchResult) => void;
setSearchFilter: (filter: SearchFilter) => void;
onUpdateFilter: (filter: SearchFilter) => void;
loadMore: () => void;
refresh: () => void;
setColumns: (columns: number) => void;
setDefaultView: (name: string) => void;
};
export default function SearchView({
search,
Expand All @@ -56,12 +49,16 @@ export default function SearchView({
searchResults,
isLoading,
hasMore,
columns,
defaultView = "summary",
setSearch,
setSimilaritySearch,
setSearchFilter,
onUpdateFilter,
loadMore,
refresh,
setColumns,
setDefaultView,
}: SearchViewProps) {
const contentRef = useRef<HTMLDivElement | null>(null);
const { data: config } = useSWR<FrigateConfig>("config", {
Expand All @@ -70,18 +67,15 @@ export default function SearchView({

// grid

const [columnCount, setColumnCount] = usePersistence("exploreGridColumns", 4);
const effectiveColumnCount = useMemo(() => columnCount ?? 4, [columnCount]);

const gridClassName = cn(
"grid w-full gap-2 px-1 gap-2 lg:gap-4 md:mx-2",
isMobileOnly && "grid-cols-2",
{
"sm:grid-cols-2": effectiveColumnCount <= 2,
"sm:grid-cols-3": effectiveColumnCount === 3,
"sm:grid-cols-4": effectiveColumnCount === 4,
"sm:grid-cols-5": effectiveColumnCount === 5,
"sm:grid-cols-6": effectiveColumnCount === 6,
"sm:grid-cols-2": columns <= 2,
"sm:grid-cols-3": columns === 3,
"sm:grid-cols-4": columns === 4,
"sm:grid-cols-5": columns === 5,
"sm:grid-cols-6": columns === 6,
},
);

Expand Down Expand Up @@ -342,14 +336,20 @@ export default function SearchView({

{hasExistingSearch && (
<ScrollArea className="w-full whitespace-nowrap lg:ml-[35%]">
<div className="flex flex-row">
<div className="flex flex-row gap-2">
<SearchFilterGroup
className={cn(
"w-full justify-between md:justify-start lg:justify-end",
)}
filter={searchFilter}
onUpdateFilter={onUpdateFilter}
/>
<SearchSettings
columns={columns}
setColumns={setColumns}
defaultView={defaultView}
setDefaultView={setDefaultView}
/>
<ScrollBar orientation="horizontal" className="h-0" />
</div>
</ScrollArea>
Expand Down Expand Up @@ -425,53 +425,13 @@ export default function SearchView({
<div className="flex h-12 w-full justify-center">
{hasMore && isLoading && <ActivityIndicator />}
</div>

{isDesktop && columnCount && (
<div
className={cn(
"fixed bottom-12 right-3 z-50 flex flex-row gap-2 lg:bottom-9",
)}
>
<Popover>
<Tooltip>
<TooltipTrigger asChild>
<PopoverTrigger asChild>
<div className="cursor-pointer rounded-lg bg-secondary text-secondary-foreground opacity-75 transition-all duration-300 hover:bg-muted hover:opacity-100">
<LuColumns className="size-5 md:m-[6px]" />
</div>
</PopoverTrigger>
</TooltipTrigger>
<TooltipContent>Adjust Grid Columns</TooltipContent>
</Tooltip>
<PopoverContent className="mr-2 w-80">
<div className="space-y-4">
<div className="font-medium leading-none">
Grid Columns
</div>
<div className="flex items-center space-x-4">
<Slider
value={[effectiveColumnCount]}
onValueChange={([value]) => setColumnCount(value)}
max={6}
min={2}
step={1}
className="flex-grow"
/>
<span className="w-9 text-center text-sm font-medium">
{effectiveColumnCount}
</span>
</div>
</div>
</PopoverContent>
</Popover>
</div>
)}
</>
)}
</div>
{searchFilter &&
Object.keys(searchFilter).length === 0 &&
!searchTerm && (
!searchTerm &&
defaultView == "summary" && (
<div className="scrollbar-container flex size-full flex-col overflow-y-auto">
<ExploreView
searchDetail={searchDetail}
Expand Down

0 comments on commit 754d897

Please sign in to comment.