File size: 3,556 Bytes
6b3405c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { usePubSub } from "create-pubsub/react";
import {
  searchResultsPubSub,
  searchStatePubSub,
  settingsPubSub,
} from "../../../modules/pubSub";
import { match, Pattern } from "ts-pattern";
import {
  Divider,
  Skeleton,
  Alert,
  Stack,
  Group,
  Space,
  AspectRatio,
  em,
} from "@mantine/core";
import { IconInfoCircle } from "@tabler/icons-react";
import { lazy, Suspense, useMemo } from "react";
import { Settings } from "../../../modules/settings";
import { SearchResults } from "../../../modules/search";
import { useMediaQuery } from "@mantine/hooks";

const ImageResultsList = lazy(() => import("./Graphical/ImageResultsList"));
const SearchResultsList = lazy(() => import("./Textual/SearchResultsList"));

export default function SearchResultsSection() {
  const [searchResults] = usePubSub(searchResultsPubSub);
  const [searchState] = usePubSub(searchStatePubSub);
  const [settings] = usePubSub(settingsPubSub);

  return useMemo(
    () =>
      match(searchState)
        .with("running", () => <RunningSearchContent />)
        .with("failed", () => <FailedSearchContent />)
        .with("completed", () => (
          <CompletedSearchContent
            searchResults={searchResults}
            settings={settings}
          />
        ))
        .otherwise(() => null),
    [searchState, searchResults, settings],
  );
}

function RunningSearchContent() {
  const hasSmallScreen = useMediaQuery(`(max-width: ${em(530)})`);

  const numberOfSquareSkeletons = hasSmallScreen ? 4 : 6;

  return (
    <>
      <Divider
        mb="sm"
        variant="dashed"
        labelPosition="center"
        label="Searching the web..."
      />
      <Stack>
        <Group>
          {[...Array(numberOfSquareSkeletons)].map((_, index) => (
            <AspectRatio key={index} ratio={1} flex={1}>
              <Skeleton />
            </AspectRatio>
          ))}
        </Group>
        <Stack>
          <Skeleton height={8} radius="xl" />
          <Skeleton height={8} width="87%" radius="xl" />
          <Skeleton height={8} radius="xl" />
          <Skeleton height={8} width="70%" radius="xl" />
          <Skeleton height={8} radius="xl" />
          <Skeleton height={8} width="52%" radius="xl" />
          <Skeleton height={8} radius="xl" />
          <Skeleton height={8} width="63%" radius="xl" />
        </Stack>
      </Stack>
    </>
  );
}

function FailedSearchContent() {
  return (
    <>
      <Divider
        mb="sm"
        variant="dashed"
        labelPosition="center"
        label="Search Results"
      />
      <Alert
        variant="light"
        color="yellow"
        title="No results found"
        icon={<IconInfoCircle />}
      >
        It looks like your current search did not return any results. Try
        refining your search by adding more keywords or rephrasing your query.
      </Alert>
    </>
  );
}

function CompletedSearchContent({
  searchResults,
  settings,
}: {
  searchResults: SearchResults;
  settings: Settings;
}) {
  return (
    <>
      <Divider variant="dashed" labelPosition="center" label="Search Results" />
      {match([settings.enableImageSearch, searchResults.imageResults.length])
        .with([true, Pattern.number.positive()], () => (
          <Suspense>
            <ImageResultsList imageResults={searchResults.imageResults} />
            <Space h={8} />
          </Suspense>
        ))
        .otherwise(() => null)}
      <Suspense>
        <SearchResultsList searchResults={searchResults.textResults} />
      </Suspense>
    </>
  );
}