Skip to content

Commit f505197

Browse files
committed
feat(): Search article feature
1 parent 2d83e31 commit f505197

23 files changed

Lines changed: 359 additions & 103 deletions

File tree

src/components/ArticleCard/ArticleCard.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,12 @@ const ArticleCard = ({
3232

3333
return (
3434
<Box
35-
zIndex={1}
3635
_hover={{
3736
transform: 'scale(1.02)',
3837
cursor: 'pointer',
3938
}}
4039
transition={'all 0.4s ease'}
41-
bg={'rgba(0, 0, 0, 0.4)'}
42-
backdropFilter={'blur(10px)'}
40+
bg={'rgba(0, 0, 0, 0.2)'}
4341
padding={4}
4442
borderRadius={10}
4543
border={'1px solid gray'}

src/components/Chip/Chip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ const Chip = ({ type, size = 'md' }: ChipProps) => {
102102
borderRadius="lg"
103103
border={`1px solid`}
104104
color="white"
105-
zIndex={10}
105+
zIndex={0}
106106
>
107107
<Text fontSize="sm">{ChipMap[type].title}</Text>
108108
{ChipMap[type].Icon({})}

src/components/CoverText/Cover.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export const Cover = ({ children }: { children?: React.ReactNode }) => {
125125
},
126126
}}
127127
className={
128-
'dark:text-white inline-block text-neutral-900 relative z-20 group-hover/cover:text-white transition duration-200'
128+
'dark:text-white inline-block text-neutral-900 relative z-1 group-hover/cover:text-white transition duration-200'
129129
}
130130
>
131131
{children}

src/components/CoverText/CoverText.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const CoverText = ({
1313
}) => {
1414
return (
1515
<Box position={'absolute'} left={32} top={'200px'}>
16-
<Heading className="text-2xl md:text-4xl lg:text-6xl font-semibold max-w-7xl mx-auto mt-6 relative z-20 py-6 bg-clip-text text-transparent bg-gradient-to-b from-neutral-800 via-neutral-700 to-neutral-700 dark:from-neutral-800 dark:via-white dark:to-white">
16+
<Heading className="text-2xl md:text-4xl lg:text-6xl font-semibold max-w-7xl mx-auto mt-6 relative z-1 py-6 bg-clip-text text-transparent bg-gradient-to-b from-neutral-800 via-neutral-700 to-neutral-700 dark:from-neutral-800 dark:via-white dark:to-white">
1717
<Text className="text-xl md:text-3xl lg:text-4xl pb-6">{text}</Text>
1818
<Cover>{highlightedText}</Cover>
1919
</Heading>

src/components/animateModal/AnimatedModal.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,16 @@ export const ModalBody = ({
9494
opacity: 0,
9595
backdropFilter: 'blur(0px)',
9696
}}
97-
className="fixed [perspective:800px] [transform-style:preserve-3d] inset-0 h-full w-full flex items-center justify-center z-10"
97+
className={
98+
'fixed [perspective:800px] [transform-style:preserve-3d] inset-0 h-full w-full flex items-center justify-center z-100 ' +
99+
className
100+
}
98101
>
99102
<Overlay />
100103
<motion.div
101104
ref={modalRef}
102105
className={
103-
'min-h-[50%] max-h-[90%] base:max-w-[60%] md:max-w-[47%] lg:max-w-[35%] bg-white dark:bg-neutral-950 border border-transparent dark:border-neutral-800 md:rounded-2xl relative z-10 flex flex-col flex-1 overflow-hidden'
106+
'min-h-[50%] max-h-[90%] max-w-[60%] bg-white dark:bg-neutral-950 border border-transparent dark:border-neutral-800 md:rounded-2xl relative z-10 flex flex-col flex-1 overflow-hidden'
104107
}
105108
initial={{
106109
opacity: 0,
@@ -138,8 +141,11 @@ export const ModalContent = ({ children }: { children: ReactNode }) => {
138141
return (
139142
<div
140143
className={
141-
'flex flex-col flex-1 p-2 md:p-4 justify-center z-1000 w-[50%]'
144+
'flex flex-col flex-1 p-2 md:p-4 justify-start z-100 w-[100%] '
142145
}
146+
style={{
147+
alignItems: 'center',
148+
}}
143149
>
144150
{children}
145151
</div>
@@ -168,7 +174,7 @@ const Overlay = ({ className }: { className?: string }) => {
168174
opacity: 0,
169175
backdropFilter: 'blur(0px)',
170176
}}
171-
className={`fixed inset-0 h-full w-full bg-black bg-opacity-50 z-10 ${className}`}
177+
className={`fixed inset-0 h-full w-full bg-black bg-opacity-50 z-100 ${className}`}
172178
></motion.div>
173179
);
174180
};

src/components/animateModal/Modal.tsx

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,28 @@
1-
import ReactPlayer from 'react-player';
21
import {
32
Modal,
43
ModalBody,
54
ModalContent,
65
ModalFooter,
76
ModalTrigger,
87
} from './AnimatedModal';
9-
import { Box, Button, Heading } from '@chakra-ui/react';
8+
import { Box, Heading } from '@chakra-ui/react';
109

1110
const AnimatedModal = ({
12-
triggerText,
1311
title,
14-
videoUrl,
15-
websiteUrl,
12+
triggerComponent,
13+
children,
14+
footer,
1615
}: {
17-
triggerText: string;
1816
title: string;
19-
videoUrl: string;
20-
websiteUrl: string;
17+
triggerComponent: React.ReactNode;
18+
children: React.ReactNode;
19+
footer: React.ReactNode;
2120
}) => {
2221
return (
23-
<Box height={10} className="flex items-center justify-center">
22+
<Box className="flex items-center justify-center">
2423
<Modal>
2524
<ModalTrigger className="bg-white flex justify-center group/modal-btn">
26-
<Button
27-
variant="outline"
28-
colorScheme="white"
29-
boxShadow={'0 0 10px 2px #ffffff5a'}
30-
style={{
31-
padding: '0.5rem 1rem',
32-
borderRadius: '0.5rem',
33-
}}
34-
>
35-
{triggerText}
36-
</Button>
25+
{triggerComponent}
3726
</ModalTrigger>
3827
<ModalBody>
3928
<ModalContent>
@@ -44,29 +33,9 @@ const AnimatedModal = ({
4433
>
4534
{title}
4635
</Heading>
47-
<ReactPlayer
48-
controls
49-
progressInterval={1000}
50-
previewTabIndex={0}
51-
url={videoUrl}
52-
style={{
53-
justifyContent: 'center',
54-
flex: 1,
55-
borderRadius: '0.5rem',
56-
}}
57-
/>
36+
{children}
5837
</ModalContent>
59-
<ModalFooter>
60-
<Button
61-
as="a"
62-
href={websiteUrl}
63-
target="_blank"
64-
rel="noopener noreferrer"
65-
className="px-2 py-1 bg-gray-200 text-black dark:bg-black dark:border-black dark:text-white border border-gray-300 rounded-md text-sm w-28"
66-
>
67-
Visit website
68-
</Button>
69-
</ModalFooter>
38+
<ModalFooter>{footer}</ModalFooter>
7039
</ModalBody>
7140
</Modal>
7241
</Box>

src/screens/articles/ArticlesScreen.tsx

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Button, HStack, Text, VStack, Wrap } from '@chakra-ui/react';
1+
import { HStack, Text, VStack, Wrap } from '@chakra-ui/react';
22
import { ArticleCard, LoadingSpinner } from '@components';
33
import { useGetArticlesData } from '@services';
44
import { useLocation, useNavigate } from 'react-router-dom';
@@ -7,6 +7,7 @@ import { useMemo, useState } from 'react';
77
import { groupBy, sortBy } from 'lodash';
88
import { BASE_NAV_ROUTE } from '@router';
99
import SortBy, { SortByType } from './components/SortBy';
10+
import SearchFeature from './components/SearchFeature';
1011

1112
const CategoryButton = ({
1213
category,
@@ -21,14 +22,13 @@ const CategoryButton = ({
2122
}) => {
2223
const navigate = useNavigate();
2324
return (
24-
<Button
25+
<Text
2526
w={'100%'}
2627
color={'white'}
27-
py={3}
28+
py={1}
2829
px={5}
2930
bg={isSelected ? 'gray.800' : ''}
3031
fontSize={20}
31-
variant={'ghost'}
3232
border={'1px solid gray'}
3333
_hover={{ bg: 'gray.600', cursor: 'pointer', color: 'violet' }}
3434
onClick={() => {
@@ -39,7 +39,7 @@ const CategoryButton = ({
3939
}}
4040
>
4141
{category}
42-
</Button>
42+
</Text>
4343
);
4444
};
4545

@@ -92,12 +92,12 @@ const ArticlesScreen = () => {
9292
w={'100%'}
9393
textAlign={'center'}
9494
top={2}
95-
zIndex={2}
9695
padding={2}
9796
textShadow={'2px 2px 4px #000000'}
9897
borderBottom={'1px solid gray'}
9998
bg={'rgba(0, 0, 0, 0.5)'}
10099
backdropFilter={'blur(10px)'}
100+
zIndex={10}
101101
>
102102
Articles
103103
</Text>
@@ -119,30 +119,32 @@ const ArticlesScreen = () => {
119119
<HStack>
120120
<StreakStalker dates={date} />
121121
<SortBy sortBy={sortByName} setSortBy={setSortBy} />
122+
<SearchFeature data={articles} />
122123
</HStack>
123-
<CategoryButton
124-
category={'All'}
125-
setCategory={setCategory}
126-
secondPath={secondPath}
127-
isSelected={'All' === category}
128-
/>
129-
{Object.keys(filteredArticles).map(
130-
(group_name: any, index: number) => (
131-
<CategoryButton
132-
key={index}
133-
category={group_name}
134-
setCategory={setCategory}
135-
secondPath={secondPath}
136-
isSelected={group_name === category}
137-
/>
138-
),
139-
)}
124+
<VStack>
125+
<CategoryButton
126+
category={'All'}
127+
setCategory={setCategory}
128+
secondPath={secondPath}
129+
isSelected={'All' === category}
130+
/>
131+
{Object.keys(filteredArticles).map(
132+
(group_name: any, index: number) => (
133+
<CategoryButton
134+
key={index}
135+
category={group_name}
136+
setCategory={setCategory}
137+
secondPath={secondPath}
138+
isSelected={group_name === category}
139+
/>
140+
),
141+
)}
142+
</VStack>
140143
</VStack>
141144
<VStack
142145
w={'80%'}
143146
id="projects"
144147
rowGap={20}
145-
bg={'black'}
146148
paddingTop={20}
147149
justifyContent={'flex-start'}
148150
>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { ArrowIcon, SearchIcon } from '@assets';
2+
import {
3+
Box,
4+
CloseButton,
5+
HStack,
6+
IconButton,
7+
Input,
8+
Text,
9+
VStack,
10+
} from '@chakra-ui/react';
11+
import { AnimatedModal } from '@components';
12+
import { BASE_NAV_ROUTE } from '@router';
13+
import {
14+
resetSearchTextSelector,
15+
selectSearchText,
16+
setSearchTextSelector,
17+
} from '@selectors';
18+
import { appStore } from '@store';
19+
import { isEmpty, isEqual, isNil } from 'lodash';
20+
import { memo } from 'react';
21+
22+
const SearchFeature = ({ data }: { data: any }) => {
23+
const searchText = appStore(selectSearchText);
24+
const setSearchText = appStore(setSearchTextSelector);
25+
const resetSearchText = appStore(resetSearchTextSelector);
26+
27+
const filteredArticle = data.filter((article: any) =>
28+
!isNil(searchText) && !isEmpty(searchText)
29+
? ((article.title + article.description) as string).includes(searchText)
30+
: false,
31+
);
32+
33+
return (
34+
<AnimatedModal
35+
triggerComponent={
36+
<Box
37+
border={'1px solid gray'}
38+
padding="2.5"
39+
color={'white'}
40+
borderRadius="100px"
41+
bg={'rgba(255, 255, 255, 0.1)'}
42+
backdropFilter={'blur(20px)'}
43+
transition={'all 0.3s'}
44+
_hover={{
45+
transform: 'scale(1.1)',
46+
cursor: 'pointer',
47+
}}
48+
p={2}
49+
>
50+
<SearchIcon />
51+
</Box>
52+
}
53+
title="Search"
54+
footer={
55+
<Box color={'gray'}>Search for articles by title or description</Box>
56+
}
57+
>
58+
<HStack
59+
color={'white'}
60+
w={'90%'}
61+
justifyContent="center"
62+
alignItems="center"
63+
>
64+
<Input
65+
value={searchText}
66+
onChange={(e) => setSearchText(e.target.value)}
67+
/>
68+
<CloseButton onClick={resetSearchText} bg={'red'} />
69+
</HStack>
70+
<VStack overflow={'auto'} maxHeight={'40vh'} w={'100%'} mt={10}>
71+
{filteredArticle.map((article: any) => (
72+
<HStack
73+
w={'70%'}
74+
key={article.title}
75+
padding={1}
76+
border={'1px solid gray'}
77+
m={1}
78+
px={10}
79+
color={'white'}
80+
justifyContent={'space-between'}
81+
>
82+
<Text
83+
fontSize="lg"
84+
fontWeight="bold"
85+
color="brand.900"
86+
marginBottom={2}
87+
>
88+
{article.title}
89+
</Text>
90+
<IconButton
91+
ml={4}
92+
variant={'outline'}
93+
colorScheme="white"
94+
size={'sm'}
95+
aria-label="Search database"
96+
icon={<ArrowIcon />}
97+
_hover={{
98+
transform: 'scale(1.1)',
99+
}}
100+
as={'a'}
101+
href={BASE_NAV_ROUTE + 'articles/' + article.article_key}
102+
target={'_blank'}
103+
rel={'noopener noreferrer'}
104+
/>
105+
</HStack>
106+
))}
107+
</VStack>
108+
</AnimatedModal>
109+
);
110+
};
111+
112+
export default memo(SearchFeature, isEqual);

0 commit comments

Comments
 (0)