Explore UI changes (#14393)

* Add time ago to explore summary view on desktop

* add search settings for columns and default view selection

* add descriptions

* clarify wording

* padding tweak

* padding tweaks for mobile

* fix size of activity indicator

* smaller
This commit is contained in:
Josh Hawkins
2024-10-16 11:54:01 -05:00
committed by GitHub
parent 9f866be110
commit e836523bc3
7 changed files with 175 additions and 72 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useMemo } from "react";
import { isIOS, isMobileOnly, isSafari } from "react-device-detect";
import { isDesktop, isIOS, isMobileOnly, isSafari } from "react-device-detect";
import useSWR from "swr";
import { useApiHost } from "@/api";
import { cn } from "@/lib/utils";
@@ -17,6 +17,7 @@ import useImageLoaded from "@/hooks/use-image-loaded";
import ActivityIndicator from "@/components/indicators/activity-indicator";
import { useEventUpdate } from "@/api/ws";
import { isEqual } from "lodash";
import TimeAgo from "@/components/dynamic/TimeAgo";
type ExploreViewProps = {
searchDetail: SearchResult | undefined;
@@ -197,6 +198,7 @@ function ExploreThumbnailImage({
className="absolute inset-0"
imgLoaded={imgLoaded}
/>
<img
ref={imgRef}
className={cn(
@@ -218,6 +220,17 @@ function ExploreThumbnailImage({
onImgLoad();
}}
/>
{isDesktop && (
<div className="absolute bottom-1 right-1 z-10 rounded-lg bg-black/50 px-2 py-1 text-xs text-white">
{event.end_time ? (
<TimeAgo time={event.start_time * 1000} dense />
) : (
<div>
<ActivityIndicator size={10} />
</div>
)}
</div>
)}
</>
);
}

View File

@@ -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, {
@@ -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;
@@ -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,
@@ -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", {
@@ -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,
},
);
@@ -342,7 +336,7 @@ 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",
@@ -350,6 +344,12 @@ export default function SearchView({
filter={searchFilter}
onUpdateFilter={onUpdateFilter}
/>
<SearchSettings
columns={columns}
setColumns={setColumns}
defaultView={defaultView}
setDefaultView={setDefaultView}
/>
<ScrollBar orientation="horizontal" className="h-0" />
</div>
</ScrollArea>
@@ -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}