Skip to content

Commit c23d39c

Browse files
authored
merge: 상세보기 페이지 추가 (#16)
merge: 상세보기 페이지 추가 (#16)
2 parents c8c4084 + 32d63df commit c23d39c

File tree

21 files changed

+386
-82
lines changed

21 files changed

+386
-82
lines changed

.yarn/install-state.gz

557 Bytes
Binary file not shown.

packages/design-system/src/Font.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const FONT_TYPE_PREFIX = {
2323
};
2424

2525
export type Color = keyof typeof COLOR_PREFIX;
26-
type FontType = keyof typeof FONT_TYPE_PREFIX;
26+
export type FontType = keyof typeof FONT_TYPE_PREFIX;
2727

2828
interface FontProps {
2929
children: ReactNode;

packages/react-native/.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ module.exports = {
2121
'import/no-extraneous-dependencies': 'off',
2222
'react/require-default-props': 'off',
2323
'no-console': 'error',
24+
'import/prefer-default-export': 'off',
25+
'@typescript-eslint/no-unused-vars': 'warn',
26+
'react/no-array-index-key': 'off',
2427
},
2528
ignorePatterns: [
2629
'index.js',

packages/react-native/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"react-native-pager-view": "^6.3.3",
3737
"react-native-permissions": "^4.1.5",
3838
"react-native-reanimated": "^3.14.0",
39+
"react-native-reanimated-carousel": "^3.5.1",
3940
"react-native-safe-area-context": "^4.10.8",
4041
"react-native-screens": "^3.32.0",
4142
"react-native-svg": "^15.4.0",
Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
1-
import { Path, Svg, SvgProps } from 'react-native-svg';
1+
import { G, Mask, Path, Svg, SvgProps } from 'react-native-svg';
22

33
export default function HeartIcon({ width, height, color }: SvgProps) {
44
return (
55
<Svg
6-
width={width || 20}
7-
height={height || 19}
8-
viewBox="0 0 20 19"
6+
width={width || 14}
7+
height={height || 13}
8+
viewBox="0 0 14 13"
99
fill="none"
1010
>
11-
<Path
12-
d="M10 18.9999L8.55 17.6999C6.86667 16.1832 5.475 14.8749 4.375 13.7749C3.275 12.6749 2.4 11.6874 1.75 10.8124C1.1 9.9374 0.645833 9.13324 0.3875 8.3999C0.129167 7.66657 0 6.91657 0 6.1499C0 4.58324 0.525 3.2749 1.575 2.2249C2.625 1.1749 3.93333 0.649902 5.5 0.649902C6.36667 0.649902 7.19167 0.833236 7.975 1.1999C8.75833 1.56657 9.43333 2.08324 10 2.7499C10.5667 2.08324 11.2417 1.56657 12.025 1.1999C12.8083 0.833236 13.6333 0.649902 14.5 0.649902C16.0667 0.649902 17.375 1.1749 18.425 2.2249C19.475 3.2749 20 4.58324 20 6.1499C20 6.91657 19.8708 7.66657 19.6125 8.3999C19.3542 9.13324 18.9 9.9374 18.25 10.8124C17.6 11.6874 16.725 12.6749 15.625 13.7749C14.525 14.8749 13.1333 16.1832 11.45 17.6999L10 18.9999ZM10 16.2999C11.6 14.8666 12.9167 13.6374 13.95 12.6124C14.9833 11.5874 15.8 10.6957 16.4 9.9374C17 9.17907 17.4167 8.50407 17.65 7.9124C17.8833 7.32074 18 6.73324 18 6.1499C18 5.1499 17.6667 4.31657 17 3.6499C16.3333 2.98324 15.5 2.6499 14.5 2.6499C13.7167 2.6499 12.9917 2.87074 12.325 3.3124C11.6583 3.75407 11.2 4.31657 10.95 4.9999H9.05C8.8 4.31657 8.34167 3.75407 7.675 3.3124C7.00833 2.87074 6.28333 2.6499 5.5 2.6499C4.5 2.6499 3.66667 2.98324 3 3.6499C2.33333 4.31657 2 5.1499 2 6.1499C2 6.73324 2.11667 7.32074 2.35 7.9124C2.58333 8.50407 3 9.17907 3.6 9.9374C4.2 10.6957 5.01667 11.5874 6.05 12.6124C7.08333 13.6374 8.4 14.8666 10 16.2999Z"
13-
fill={color || '#E8EAED'}
14-
/>
11+
<Mask
12+
id="mask0_470_923"
13+
maskUnits="userSpaceOnUse"
14+
x="0"
15+
y="0"
16+
width="14"
17+
height="13"
18+
>
19+
<Path
20+
d="M4.40755 1.46802C2.63568 1.46802 1.19922 2.90448 1.19922 4.67635C1.19922 7.88468 4.99089 10.8014 7.03255 11.4798C9.07422 10.8014 12.8659 7.88468 12.8659 4.67635C12.8659 2.90448 11.4294 1.46802 9.65755 1.46802C8.57255 1.46802 7.61297 2.00673 7.03255 2.83127C6.73666 2.40992 6.34362 2.06605 5.8867 1.82876C5.42978 1.59146 4.92242 1.46773 4.40755 1.46802Z"
21+
fill="#555555"
22+
stroke="white"
23+
stroke-width="1.16667"
24+
stroke-linecap="round"
25+
stroke-linejoin="round"
26+
/>
27+
</Mask>
28+
<G mask="url(#mask0_470_923)">
29+
<Path
30+
d="M0.0322266 -0.865234H14.0322V13.1348H0.0322266V-0.865234Z"
31+
fill={color || '#FF1919'}
32+
/>
33+
</G>
1534
</Svg>
1635
);
1736
}

packages/react-native/src/components/CardSlider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default function CardSlider({ title, data }: CardSliderProps) {
2626
horizontal
2727
showsHorizontalScrollIndicator={false}
2828
ItemSeparatorComponent={CardSeperation}
29-
renderItem={({ item }) => <Card data={item} />}
29+
renderItem={({ item }) => <Card.Small data={item} />}
3030
/>
3131
</View>
3232
);
Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,102 @@
1-
import { FlatList, ImageBackground, Text, View } from 'react-native';
1+
import {
2+
Alert,
3+
FlatList,
4+
ImageBackground,
5+
TouchableOpacity,
6+
View,
7+
} from 'react-native';
28
import HeartIcon from '@assets/HeartIcon';
9+
import { Font } from 'design-system';
310
import { SpotData } from '@/types/spot';
411
import Tag from './Tag';
512

613
function TagSeperation() {
714
return <View style={{ width: 5 }} />;
815
}
916

10-
export default function Card({ data }: { data: SpotData }) {
11-
const { location, locationName, tags, backgroundImage } = data;
17+
function Default({ data }: { data: SpotData }) {
18+
const { location, name, tags, backgroundImage, likeCount, spotId, isLiked } =
19+
data;
1220

1321
return (
1422
<ImageBackground
1523
source={{ uri: backgroundImage }}
16-
className="w-[180px] h-[240px] rounded-lg overflow-hidden"
24+
className="w-[262px] h-[350px] rounded-2xl overflow-hidden"
1725
>
18-
<View
19-
className="flex-1 justify-end"
20-
style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}
26+
<TouchableOpacity
27+
className="flex-1 justify-end bg-black/40"
28+
// FIXME: 실제 상세보기로 변경
29+
onPress={() => Alert.alert('상세정보보기', `${spotId}`)}
30+
activeOpacity={1}
2131
>
32+
<View className="flex-row justify-between items-center">
33+
<FlatList
34+
data={tags}
35+
keyExtractor={(_, index) => index.toString()}
36+
horizontal
37+
showsHorizontalScrollIndicator={false}
38+
ItemSeparatorComponent={TagSeperation}
39+
renderItem={({ item }) => <Tag tag={item} />}
40+
className="flex flex-row p-3"
41+
/>
42+
<TouchableOpacity
43+
className="flex-row items-center p-3"
44+
// FIXME: 실제 좋아요 기능 추가
45+
onPress={() => Alert.alert('좋아요', `${spotId}`)}
46+
>
47+
<HeartIcon
48+
width={15}
49+
height={15}
50+
color={isLiked ? 'red' : 'white'}
51+
/>
52+
<View className="ml-1">
53+
<Font type="body3" color="white">
54+
{likeCount}
55+
</Font>
56+
</View>
57+
</TouchableOpacity>
58+
</View>
59+
<View className="bg-SPOT-black p-3">
60+
<Font.Bold type="body1" color="white">
61+
{name}
62+
</Font.Bold>
63+
<View className="mt-1">
64+
<Font type="body3" color="white">
65+
{location}
66+
</Font>
67+
</View>
68+
</View>
69+
</TouchableOpacity>
70+
</ImageBackground>
71+
);
72+
}
73+
74+
function Small({ data }: { data: SpotData }) {
75+
const { location, name, tags, backgroundImage, isLiked } = data;
76+
77+
return (
78+
<ImageBackground
79+
source={{ uri: backgroundImage }}
80+
className="w-[180px] h-[240px] rounded-lg overflow-hidden"
81+
>
82+
<View className="flex-1 justify-end bg-black/40">
2283
<View className="p-2.5 gap-2">
2384
<View>
24-
<View className="flex flex-row gap-2 justify-start items-center">
25-
{/* FIXME: 디자인 시스템 적용 */}
26-
<Text className="text-white font-Pretendard-Bold text-[16px] leading-[20px]">
27-
{locationName}
28-
</Text>
29-
<View>
30-
<HeartIcon width={12} height={12} />
85+
<View className="flex flex-row justify-start items-center">
86+
<Font.Bold type="body1" color="white">
87+
{name}
88+
</Font.Bold>
89+
<View className="ml-2">
90+
<HeartIcon
91+
width={12}
92+
height={12}
93+
color={isLiked ? 'red' : 'white'}
94+
/>
3195
</View>
3296
</View>
33-
{/* FIXME: 디자인 시스템 적용 */}
34-
<Text className="text-white font-Pretendard-Medium text-[12px] leading-[16px]">
97+
<Font type="body3" color="white">
3598
{location}
36-
</Text>
99+
</Font>
37100
</View>
38101
<View>
39102
<FlatList
@@ -51,3 +114,7 @@ export default function Card({ data }: { data: SpotData }) {
51114
</ImageBackground>
52115
);
53116
}
117+
118+
const Card = Object.assign(Default, { Small });
119+
120+
export default Card;

packages/react-native/src/components/common/SearchBar.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import { useState } from 'react';
2-
import { Alert, TextInput, TouchableOpacity, View } from 'react-native';
2+
import { TextInput, TouchableOpacity, View } from 'react-native';
33
import Search from '@assets/Search';
44

55
interface SearchBarProps {
66
placeholder: string;
7+
handleSearch: (title: string) => void;
78
}
89

9-
export default function SearchBar({ placeholder }: SearchBarProps) {
10+
export default function SearchBar({
11+
placeholder,
12+
handleSearch,
13+
}: SearchBarProps) {
1014
const [searchKeyword, setSearchKeyword] = useState('');
1115

1216
const search = () => {
1317
if (!searchKeyword) return;
1418

15-
Alert.alert(searchKeyword);
19+
handleSearch(searchKeyword);
1620
};
1721

1822
return (
@@ -22,12 +26,11 @@ export default function SearchBar({ placeholder }: SearchBarProps) {
2226
onChangeText={(newKeyword) => setSearchKeyword(newKeyword)}
2327
placeholder={placeholder}
2428
placeholderTextColor="#0F0F0F"
25-
className="w-full rounded-md p-4 opacity-60 bg-white border text-SPOT-black text-body1 font-Pretendard-Medium"
29+
className="w-full rounded-md p-4 opacity-60 bg-white border text-SPOT-black text-body1 leading-5 font-Pretendard-Medium"
2630
onSubmitEditing={search}
2731
/>
2832
<TouchableOpacity
29-
className="absolute right-2.5 w-10 h-10 items-center justify-center rounded-full"
30-
style={{ backgroundColor: 'rgba(15,15,15,0.15)' }}
33+
className="absolute right-2.5 w-10 h-10 items-center justify-center rounded-full bg-SPOT-black/[0.15]"
3134
onPress={search}
3235
disabled={!searchKeyword}
3336
>
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import { Text, View } from 'react-native';
1+
import { Font } from 'design-system';
2+
import { View } from 'react-native';
23

34
interface TagProps {
45
tag: string;
56
}
67

78
export default function Tag({ tag }: TagProps) {
89
return (
9-
<View
10-
className="rounded-[32px] py-1 px-2"
11-
style={{ backgroundColor: 'rgba(15,15,15,0.7)' }}
12-
>
13-
{/* FIXME: 디자인 시스템 적용 */}
14-
<Text className="text-white font-Pretendard-Light text-[12px] leading-[16px]">
10+
<View className="rounded-[32px] py-1 px-2 bg-SPOT-black/50">
11+
<Font type="body3" color="white">
1512
#{tag}
16-
</Text>
13+
</Font>
1714
</View>
1815
);
1916
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Color, Font, FontType } from 'design-system';
2+
import { View } from 'react-native';
3+
4+
interface WordBreakProps {
5+
content: string;
6+
width: number;
7+
type: FontType;
8+
color: Color;
9+
}
10+
11+
/**
12+
* @description content의 단어 단위로 줄바꿈 적용
13+
*/
14+
export default function WordBreak({
15+
content,
16+
width,
17+
type,
18+
color,
19+
}: WordBreakProps) {
20+
return (
21+
<View
22+
style={{
23+
width,
24+
flexWrap: 'wrap',
25+
display: 'flex',
26+
flexDirection: 'row',
27+
alignItems: 'center',
28+
justifyContent: 'center',
29+
}}
30+
>
31+
{content.split(' ').map((word, index) => (
32+
<Font key={`${word}-${index}`} type={type} color={color}>
33+
{word}{' '}
34+
</Font>
35+
))}
36+
</View>
37+
);
38+
}

0 commit comments

Comments
 (0)