Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/search fe #882

Draft
wants to merge 53 commits into
base: isom-1653-global-search-backend
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4496d29
refactor: add header area to grid
seaerchin Nov 13, 2024
ee218fa
refactor: make base header for search
seaerchin Nov 13, 2024
4448c54
fix: align searchbar to middle
seaerchin Nov 13, 2024
50878eb
fix: add modal
seaerchin Nov 13, 2024
71b4900
feat: add remaining frontend components
seaerchin Nov 13, 2024
c8e80a0
chore: align modal vertically to searchbar
seaerchin Nov 13, 2024
02e1211
refactor: use grid for header
seaerchin Nov 13, 2024
06ddfde
chore: use ogp search bar
seaerchin Nov 15, 2024
d59164a
chore: add query
seaerchin Nov 15, 2024
2da8e5c
feat: add conditional wording
seaerchin Nov 15, 2024
537b70d
chore: fix search value
seaerchin Nov 15, 2024
43e9973
chore: add story
seaerchin Nov 15, 2024
9b0771d
fix: add search
seaerchin Nov 15, 2024
a8f54c8
feat: show results
seaerchin Nov 15, 2024
a64375a
chore: add interaction states
seaerchin Nov 15, 2024
11a4784
fix: update link references
seaerchin Nov 15, 2024
f47d4ea
fix: textstyle
seaerchin Nov 15, 2024
baec04a
chore: fix styling
seaerchin Nov 15, 2024
a7ec742
fix linting issue
adriangohjw Nov 16, 2024
918d7a1
fix lint
adriangohjw Nov 16, 2024
d9e6562
add test cases for getSiteName() endpoint
adriangohjw Nov 17, 2024
b318191
split stories into 2 file
adriangohjw Nov 17, 2024
8ef9a52
update copywriting
adriangohjw Nov 17, 2024
2d21096
split into multiple files for improved readability
adriangohjw Nov 17, 2024
341a387
add highlighted title text + add unique key
adriangohjw Nov 17, 2024
b59b15a
do not pass in search limit
adriangohjw Nov 17, 2024
4b0d967
refactor type out + improve readability
adriangohjw Nov 17, 2024
b457fe8
add copywriting
adriangohjw Nov 17, 2024
a9c2691
add display for no search result
adriangohjw Nov 17, 2024
f9be6ec
do not render empty Text div if no text (use gap instead)
adriangohjw Nov 17, 2024
ffe4542
fix - wrong import
adriangohjw Nov 17, 2024
5f35885
make overflow scrollable content
adriangohjw Nov 17, 2024
7b7d65c
fix height
adriangohjw Nov 17, 2024
abae43b
align "no search results" to center
adriangohjw Nov 17, 2024
e38f67c
fix logic for determining states
adriangohjw Nov 17, 2024
8a935b9
fix gaps
adriangohjw Nov 17, 2024
507c527
refactor conditional rendering of different states
adriangohjw Nov 17, 2024
ee88941
add loading state
adriangohjw Nov 17, 2024
adfbd38
fit footer padding
adriangohjw Nov 17, 2024
a765df7
fix - SearchResultsState headerText copywriting
adriangohjw Nov 17, 2024
0314ebf
refactor to use common SearchResults
adriangohjw Nov 17, 2024
69e7e5c
fix type
adriangohjw Nov 17, 2024
ba24523
add "last edited" to search result
adriangohjw Nov 17, 2024
d8acbeb
add search shortcut hint display
adriangohjw Nov 17, 2024
9cc0a88
trigger searchbar on hitting K with ctrl/cmd key
adriangohjw Nov 17, 2024
ef91b51
fix - import filename error
adriangohjw Nov 17, 2024
16964a0
Merge branch 'isom-1653-global-search-backend' into feat/search-fe
adriangohjw Nov 17, 2024
c433c36
add leading slash
adriangohjw Nov 17, 2024
30f285d
reduce rowgap for searchresult
adriangohjw Nov 17, 2024
01318d9
add border radius to searchresult
adriangohjw Nov 17, 2024
a743591
conditional singular
adriangohjw Nov 17, 2024
8752a03
Merge branch 'isom-1653-global-search-backend' into feat/search-fe
adriangohjw Nov 17, 2024
c57e561
fix broken stories
adriangohjw Nov 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"@trpc/next": "10.45.0",
"@trpc/react-query": "10.45.0",
"@trpc/server": "10.45.0",
"@uidotdev/usehooks": "^2.4.1",
"ajv": "^8.16.0",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.1.3",
Expand Down
27 changes: 27 additions & 0 deletions apps/studio/public/assets/seaarch-no-results.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,32 @@ export interface CmsSidebarContainerProps {
children: ReactNode
sidebar: ReactElement
sidenav: ReactElement
header: ReactElement
}

export function CmsSidebarContainer({
export function CmsContainer({
children,
sidebar,
sidenav,
header,
}: CmsSidebarContainerProps) {
return (
<Grid
templateAreas={`'sidebar sidenav main'`}
templateColumns="auto 18.75rem 1fr"
templateAreas={`'header header header'
'sidebar sidenav main'`}
gridTemplateColumns="auto 18.75rem 1fr"
gridTemplateRows="3.75rem 1fr"
width="100%"
>
<GridItem area="header" as="header" w="full" p={0}>
{header}
</GridItem>
<GridItem area="sidebar" as="aside" w="full" p={0}>
<Box
pos="sticky"
top={0}
borderRight="1px solid"
borderTop="1px solid"
borderColor="base.divider.medium"
py={{ base: 0, md: "0.75rem" }}
px={{ base: 0, md: "0.5rem" }}
Expand Down Expand Up @@ -51,6 +59,7 @@ export function CmsSidebarContainer({
pos="sticky"
top={0}
borderRight="1px solid"
borderTop="1px solid"
borderColor="base.divider.medium"
overflow="auto"
css={{
Expand All @@ -67,7 +76,14 @@ export function CmsSidebarContainer({
</Box>
</GridItem>
<GridItem as="main" area="main" overflow="hidden">
{children}
<Box
height={0}
minH="100%"
borderTop="1px solid"
borderColor="base.divider.medium"
>
{children}
</Box>
</GridItem>
</Grid>
)
Expand Down
19 changes: 0 additions & 19 deletions apps/studio/src/components/CmsSidebar/CmsSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import Image from "next/image"
import NextLink from "next/link"
import { VStack } from "@chakra-ui/react"
import { IconButton } from "@opengovsg/design-system-react"

import type { CmsSidebarItem } from "./CmsSidebarItems"
import { DASHBOARD } from "~/lib/routes"
import CmsSidebarItems from "./CmsSidebarItems"

export interface CmsSidebarProps {
Expand All @@ -19,21 +15,6 @@ export function CmsSidebar({
return (
<VStack spacing="0.75rem" as="nav" justify="space-between" height="100%">
<VStack spacing="0.75rem">
<IconButton
as={NextLink}
href={DASHBOARD}
variant="clear"
aria-label="Back to dashboard"
icon={
<Image
src="/assets/isomer-logo-color.svg"
height={24}
width={22}
alt="Back to dashboard"
priority
/>
}
/>
<CmsSidebarItems navItems={topNavItems} />
</VStack>
<CmsSidebarItems navItems={bottomNavItems} />
Expand Down
2 changes: 1 addition & 1 deletion apps/studio/src/components/CmsSidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from "./CmsSidebarContainer"
export * from "./CmsContainer"
export * from "./CmsSidebar"
export * from "./CmsSidebarOnlyContainer"
125 changes: 125 additions & 0 deletions apps/studio/src/components/Searchbar/NoSearchResultSvgr.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import type { SVGProps } from "react"
import { chakra } from "@chakra-ui/react"

export const NoSearchResultSvgr = chakra((props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={146}
height={122}
fill="none"
{...props}
>
<g clipPath="url(#clip0_10663_11875)">
<path
fill="#BABECB"
stroke="#000"
strokeMiterlimit={10}
strokeWidth={0.439}
d="M50.817 98.069 30.258 48.777c-.938-2.247.238-4.073 2.627-4.073h4.137c1.689 0 2.839-.924 2.945-2.366l.136-1.813c.11-1.442 1.26-2.366 2.953-2.366h19.655c1.532 0 3.264.76 4.553 2.003l1.596 1.535c1.286 1.24 3.017 2.003 4.549 2.003H98.44c2.389 0 5.067 1.822 5.979 4.074l20.381 50.3H50.817v-.005Z"
/>
<path
fill="#E0E0E0"
stroke="#000"
strokeDasharray="1.55 1.55"
strokeLinecap="round"
strokeMiterlimit={10}
strokeWidth={0.439}
d="m47.418 81.327-7.752-29.792c-.51-1.961.78-3.93 2.58-3.93h60.777c1.201 0 2.258.906 2.589 2.218l11.287 44.842c.496 1.97-.297 3.15-2.096 3.13l-61.151.016c-1.184-.017-2.224-.907-2.555-2.201l-3.674-14.283h-.005Z"
/>
<path
fill="#fff"
stroke="#000"
strokeDasharray="2.81 2.81"
strokeLinecap="round"
strokeMiterlimit={10}
strokeWidth={0.439}
d="M51.42 95.923 48.113 40.19c-.12-1.979 1.212-3.657 2.895-3.657h61.06c1.118 0 2.025.907 2.025 2.025v57.364H51.42Z"
/>
<path
fill="#fff"
stroke="#000"
strokeDasharray="2.81 2.81"
strokeLinecap="round"
strokeMiterlimit={10}
strokeWidth={0.439}
d="m50.915 97.794 7.494-48.363c.343-1.578 1.773-2.703 3.424-2.703h63.701c2.517 0 4.21 2.513 3.217 4.765l-13.757 44.26-64.079 2.037v.004Z"
/>
<path
fill="#BABECB"
stroke="#000"
strokeMiterlimit={10}
strokeWidth={0.439}
d="m124.937 97.922-73.67-.02 15.385-45.334c.618-1.818 2.26-3.023 4.1-3.023h65.803c1.96 0 3.364 2.012 2.73 3.977l-14.348 44.4Z"
/>
<path
fill="#000"
stroke="#000"
strokeWidth={0.169}
d="m82.689 76.916-20.672 9.45L77.542 73.71l10.209-2.7 23.034 26.831-28.096-20.925Z"
/>
<mask
id="mask0_10663_11875"
width={75}
height={74}
x={19}
y={10}
maskUnits="userSpaceOnUse"
style={{
maskType: "alpha",
}}
>
<circle cx={56.391} cy={46.974} r={36.808} fill="#D9D9D9" />
</mask>
<g
stroke="#000"
strokeMiterlimit={10}
strokeWidth={0.439}
mask="url(#mask0_10663_11875)"
>
<path
fill="#BABECB"
d="M23.533 47.192c-.704-1.689-.602-3.183.084-4.248.685-1.063 1.983-1.744 3.773-1.744h6.395c1.344 0 2.492-.368 3.33-1.04.84-.676 1.354-1.647 1.44-2.82l.21-2.802c.08-1.056.54-1.913 1.283-2.51.746-.597 1.793-.943 3.063-.943h30.378c2.301 0 4.924 1.144 6.885 3.034l2.466 2.372c2.02 1.949 4.748 3.158 7.182 3.158h38.688c1.793 0 3.708.684 5.352 1.804 1.644 1.12 2.999 2.662 3.685 4.354l.203-.082-.203.082 31.377 77.439H55.254l-31.72-76.054Z"
/>
<path
fill="#F8F9F9"
strokeDasharray="2.81 2.81"
strokeLinecap="round"
d="M49.853 97.585 37.871 51.539c-.787-3.03 1.207-6.074 3.988-6.074h93.935c1.856 0 3.489 1.401 4 3.428l17.445 69.307c.768 3.043-.459 4.868-3.24 4.836l-94.511.026c-1.83-.026-3.437-1.402-3.949-3.402L49.86 97.585h-.007Z"
/>
<path
fill="#fff"
strokeDasharray="2.81 2.81"
strokeLinecap="round"
d="m56.038 120.143-5.111-86.137c-.184-3.058 1.872-5.651 4.474-5.651h95.476c1.118 0 2.025.906 2.025 2.024v89.764H56.038Z"
/>
<path
fill="#fff"
strokeDasharray="2.81 2.81"
strokeLinecap="round"
d="m55.257 123.036 11.582-74.749c.531-2.438 2.741-4.178 5.292-4.178h98.454c3.889 0 6.506 3.885 4.971 7.365l-21.262 68.407-99.037 3.148v.007Z"
/>
<path
fill="#BABECB"
d="m55.106 123.427 23.88-70.01c.996-2.92 3.652-4.87 6.643-4.87h101.496c3.273 0 5.575 3.331 4.532 6.544l-22.206 68.375-114.345-.033v-.006Z"
/>
</g>
<path
fill="#465173"
stroke="#000"
strokeWidth={0.375}
d="m82.782 63.822.075.053.655.462A7883.987 7883.987 0 0 1 93.8 71.614c6.132 4.344 13.354 9.474 17.719 12.623 2.211 1.595 5.264 3.874 8.297 6.137 2.572 1.92 5.129 3.827 7.145 5.298 4.982 3.635 6.359 4.586 6.997 5.023.157.108.269.184.379.261.331.233.651.482 2.172 1.665 1.834 1.426 4.407 3.489 6.055 5.871.823 1.19 1.408 2.448 1.56 3.737.151 1.284-.124 2.611-1.042 3.948-.922 1.343-1.985 2.09-3.089 2.44-1.107.351-2.272.308-3.403.047-2.268-.525-4.359-1.92-5.487-2.7-.66-.456-.741-.535-1.306-1.086l-.227-.221c-.786-.762-2.333-2.237-6.134-5.614-7.075-6.285-18.196-15.866-27.547-23.874a6044.133 6044.133 0 0 0-15.603-13.317l-.986-.839-.237-.2 2.204-4.839 1.515-2.153Z"
/>
<path
fill="#465173"
stroke="#000"
strokeWidth={0.375}
d="m21.022 16.2.005-.005.005-.005A42.057 42.057 0 0 1 41.688 4.232C64.357-1.284 87.217 12.619 92.735 35.3c5.518 22.68-8.388 45.528-31.068 51.047-11.333 2.757-23.13.03-32.581-5.912-9.452-5.943-16.537-15.09-18.464-25.147-1.424-7.429-.966-15.266.922-22.218 1.888-6.953 5.203-13.003 9.478-16.87ZM59.97 79.374c18.828-4.58 30.37-23.562 25.793-42.378-4.581-18.828-23.551-30.373-42.379-25.792-18.827 4.58-30.373 23.55-25.792 42.378 4.581 18.828 23.55 30.373 42.379 25.792Z"
/>
</g>
<defs>
<clipPath id="clip0_10663_11875">
<path fill="#fff" d="M0 .5h146v121H0z" />
</clipPath>
</defs>
</svg>
))
129 changes: 129 additions & 0 deletions apps/studio/src/components/Searchbar/SearchModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { useState } from "react"
import {
Modal,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
} from "@chakra-ui/react"
import { Searchbar as OgpSearchBar } from "@opengovsg/design-system-react"
import { useDebounce } from "@uidotdev/usehooks"

import type { SearchResultResource } from "~/server/modules/resource/resource.types"
import { useBanner } from "~/hooks/useBanner"
import { trpc } from "~/utils/trpc"
import { isMac } from "./isMac"
import {
InitialState,
LoadingState,
NoResultsState,
SearchResultsState,
} from "./SearchModalBodyContentStates"

interface SearchModalProps {
isOpen: boolean
onClose: () => void
siteId: string
}
export const SearchModal = ({ siteId, isOpen, onClose }: SearchModalProps) => {
const banner = useBanner()
const mt = banner ? "3rem" : "0.5rem"
const [searchValue, setSearchValue] = useState("")
const debouncedSearchTerm = useDebounce(searchValue, 300)
const { data, isLoading } = trpc.resource.search.useInfiniteQuery({
siteId,
query: debouncedSearchTerm,
})
const resources: SearchResultResource[] =
data?.pages.flatMap((page) => page.resources) ?? []

const renderModalBody = (): React.ReactNode => {
if (!!debouncedSearchTerm) {
if (isLoading) {
return <LoadingState />
}
if (resources.length === 0) {
return <NoResultsState />
}
return (
<SearchResultsState
siteId={siteId}
items={resources}
totalResultsCount={
data?.pages.reduce(
(acc, page) => acc + (page.totalCount ?? 0),
0,
) ?? 0
}
searchTerm={debouncedSearchTerm}
/>
)
}
return (
<InitialState
siteId={siteId}
items={data?.pages[0]?.suggestions.recentlyEdited ?? []}
/>
)
}

return (
<Modal isOpen={isOpen} onClose={onClose} motionPreset="none">
<ModalOverlay bg="none" backdropFilter="brightness(80%)" />
<ModalContent
rounded="base"
w="42.5rem"
p={0}
mt={`calc(${mt} + 1px)`}
// NOTE: This is required to align the inner Searchbar
// with the outer search bar
ml="3px"
boxShadow="md"
h="30.625rem"
>
<ModalHeader p={0}>
<OgpSearchBar
defaultIsExpanded
onChange={({ target }) => setSearchValue(target.value)}
w="42.5rem"
// border={0}
placeholder={`Search pages, collections, or folders by name. e.g. "Speech by Minister"`}
/>
</ModalHeader>
{renderModalBody()}
<ModalFooter
bg="base.canvas.alt"
border="1px solid"
borderColor="base.divider.medium"
px="1.25rem"
display="flex"
flexDir="row"
pt="0.75rem"
pb="1rem"
justifyContent="space-between"
borderBottomRadius="base"
>
<Text textStyle="caption-2" textColor="base.content.medium">
{resources.length === 0
? "Tip: Type in the full title to get the most accurate search results."
: "Scroll to see more results. Too many results? Try typing something longer."}
</Text>
<Text
textStyle="caption-1"
textColor="base.content.medium"
bg="white"
py="0.125rem"
px="0.375rem"
borderRadius="base"
border="1px solid"
borderColor="base.divider.medium"
boxShadow="sm"
>
{isMac ? "⌘ + K" : "Ctrl + K"}
</Text>
</ModalFooter>
</ModalContent>
</Modal>
)
}
Loading
Loading