Skip to content

Commit 655748a

Browse files
authored
Merge pull request velopert#114 from velopert/fix/mobile-like
Fix/mobile like
2 parents 33a743f + 18b537e commit 655748a

File tree

14 files changed

+215
-66
lines changed

14 files changed

+215
-66
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React from 'react';
2+
import styled, { css } from 'styled-components';
3+
import palette from '../../lib/styles/palette';
4+
import { LikeIcon } from '../../static/svg';
5+
6+
export type MobileLikeButtonProps = {
7+
likes: number;
8+
onToggle: () => void;
9+
liked: boolean;
10+
};
11+
12+
function MobileLikeButton({ likes, onToggle, liked }: MobileLikeButtonProps) {
13+
return (
14+
<Button onClick={onToggle} data-testid="like-btn" liked={liked}>
15+
<LikeIcon />
16+
<span>{likes}</span>
17+
</Button>
18+
);
19+
}
20+
21+
const Button = styled.button<{ liked: boolean }>`
22+
background: white;
23+
border: 1px solid ${palette.gray5};
24+
padding-left: 0.75rem;
25+
padding-right: 0.75rem;
26+
display: flex;
27+
align-items: center;
28+
height: 1.5rem;
29+
border-radius: 0.75rem;
30+
outline: none;
31+
svg {
32+
width: 0.75rem;
33+
height: 0.75rem;
34+
margin-right: 0.75rem;
35+
color: ${palette.gray5};
36+
}
37+
span {
38+
font-size: 0.75rem;
39+
font-weight: bold;
40+
color: ${palette.gray5};
41+
}
42+
${props =>
43+
props.liked &&
44+
css`
45+
border-color: ${palette.teal5};
46+
background: ${palette.teal5};
47+
svg,
48+
span {
49+
color: white;
50+
}
51+
`}
52+
`;
53+
54+
export default MobileLikeButton;

src/components/post/PostHead.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ const SubInfo = styled.div`
7878
`;
7979

8080
const EditRemoveGroup = styled.div`
81+
display: flex;
82+
justify-content: flex-end;
83+
margin-bottom: -1.25rem;
84+
${media.medium} {
85+
margin-top: -0.5rem;
86+
margin-bottom: 1.5rem;
87+
}
8188
button {
8289
padding: 0;
8390
outline: none;
@@ -112,6 +119,14 @@ const Thumbnail = styled.img`
112119
}
113120
`;
114121

122+
const MobileOnly = styled.div`
123+
align-items: center;
124+
display: none;
125+
${media.medium} {
126+
display: flex;
127+
}
128+
`;
129+
115130
export interface PostHeadProps {
116131
title: string;
117132
tags: string[];
@@ -132,6 +147,7 @@ export interface PostHeadProps {
132147
shareButtons: React.ReactNode;
133148
toc: React.ReactNode;
134149
isPrivate?: boolean;
150+
mobileLikeButton: React.ReactNode;
135151
}
136152

137153
const PostHead: React.FC<PostHeadProps> = ({
@@ -149,6 +165,7 @@ const PostHead: React.FC<PostHeadProps> = ({
149165
shareButtons,
150166
toc,
151167
isPrivate,
168+
mobileLikeButton,
152169
}) => {
153170
const [askRemove, toggleAskRemove] = useToggle(false);
154171

@@ -160,6 +177,12 @@ const PostHead: React.FC<PostHeadProps> = ({
160177
<PostHeadBlock>
161178
<div className="head-wrapper">
162179
<h1>{title}</h1>
180+
{ownPost && (
181+
<EditRemoveGroup>
182+
<button onClick={onEdit}>수정</button>
183+
<button onClick={toggleAskRemove}>삭제</button>
184+
</EditRemoveGroup>
185+
)}
163186
<SubInfo>
164187
<div className="information">
165188
<span className="username">
@@ -174,12 +197,7 @@ const PostHead: React.FC<PostHeadProps> = ({
174197
</>
175198
)}
176199
</div>
177-
{ownPost && (
178-
<EditRemoveGroup>
179-
<button onClick={onEdit}>수정</button>
180-
<button onClick={toggleAskRemove}>삭제</button>
181-
</EditRemoveGroup>
182-
)}
200+
<MobileOnly>{mobileLikeButton}</MobileOnly>
183201
</SubInfo>
184202
<TagList tags={tags} link />
185203
{shareButtons}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as React from 'react';
2+
import { render, fireEvent } from '@testing-library/react';
3+
import MobileLikeButton, { MobileLikeButtonProps } from '../MobileLikeButton';
4+
import palette from '../../../lib/styles/palette';
5+
6+
describe('MobileLikeButton', () => {
7+
const setup = (props: Partial<MobileLikeButtonProps> = {}) => {
8+
const initialProps: MobileLikeButtonProps = {
9+
likes: 0,
10+
onToggle: () => {},
11+
liked: false,
12+
};
13+
const utils = render(<MobileLikeButton {...initialProps} {...props} />);
14+
return {
15+
...utils,
16+
};
17+
};
18+
it('renders properly', () => {
19+
setup();
20+
});
21+
22+
it('shows likes value', () => {
23+
const utils = setup({ likes: 7 });
24+
utils.getByText('7');
25+
});
26+
27+
it('calls onToggle', () => {
28+
const onToggle = jest.fn();
29+
const utils = setup({ onToggle });
30+
const button = utils.getByTestId('like-btn');
31+
fireEvent.click(button);
32+
expect(onToggle).toBeCalled();
33+
});
34+
35+
it('shows inactive button', () => {
36+
const utils = setup({ liked: false });
37+
const button = utils.getByTestId('like-btn');
38+
expect(button).toHaveStyle('background: white');
39+
});
40+
41+
it('shows active button', () => {
42+
const utils = setup({ liked: true });
43+
const button = utils.getByTestId('like-btn');
44+
expect(button).toHaveStyle(`background: ${palette.teal5}`);
45+
});
46+
});

src/components/register/__tests__/__snapshots__/RegisterForm.test.tsx.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@ exports[`RegisterForm matches snapshot 1`] = `
9090
class="buttons"
9191
>
9292
<button
93-
class="sc-bwzfXH glbJxy"
93+
class="sc-bwzfXH eZmwIP"
9494
color="lightGray"
9595
>
9696
취소
9797
</button>
9898
<button
99-
class="sc-bwzfXH hKmRNK"
99+
class="sc-bwzfXH iVHqRZ"
100100
color="teal"
101101
type="submit"
102102
>

src/components/setting/__tests__/SettingUserProfile.test.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { render, fireEvent } from '@testing-library/react';
33
import SettingUserProfile, {
44
SettingUserProfileProps,
55
} from '../SettingUserProfile';
6+
import optimizeImage from '../../../lib/optimizeImage';
67

78
describe('SettingUserProfile', () => {
89
const setup = (props: Partial<SettingUserProfileProps> = {}) => {
@@ -13,6 +14,7 @@ describe('SettingUserProfile', () => {
1314
'https://images.velog.io/images/velopert/profile/ca385170-77e7-11e9-ba3a-fb3a8e4f1096/1536400727.98.png',
1415
displayName: 'Minjun Kim',
1516
shortBio: 'Hello World',
17+
onUpdate: () => Promise.resolve(),
1618
};
1719
const utils = render(<SettingUserProfile {...initialProps} {...props} />);
1820
return {
@@ -23,7 +25,10 @@ describe('SettingUserProfile', () => {
2325
const utils = setup();
2426
const img = utils.getByAltText('profile') as HTMLImageElement;
2527
expect(img.src).toBe(
26-
'https://images.velog.io/images/velopert/profile/ca385170-77e7-11e9-ba3a-fb3a8e4f1096/1536400727.98.png',
28+
optimizeImage(
29+
'https://images.velog.io/images/velopert/profile/ca385170-77e7-11e9-ba3a-fb3a8e4f1096/1536400727.98.png',
30+
400,
31+
),
2732
);
2833
utils.getByText('Minjun Kim');
2934
utils.getByText('Hello World');

src/components/write/__tests__/__snapshots__/MarkdownEditor.test.tsx.snap

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,30 @@
33
exports[`MarkdownEditor matches snapshot 1`] = `
44
<div>
55
<div
6-
class="sc-jTzLTM ekUQPf"
6+
class="sc-jTzLTM bLrIva"
77
data-testid="codemirror"
88
>
99
<div
1010
class="wrapper"
1111
>
1212
<div
13-
class="sc-jzJRlG cocNVz"
13+
style="max-height: 254px; opacity: 1;"
1414
>
15-
<textarea
16-
class="sc-bwzfXH fHpybz"
17-
placeholder="제목을 입력하세요"
18-
style="height: 0px;"
19-
/>
2015
<div
21-
class="sc-fjdhpX gWglfo"
22-
/>
16+
class="sc-jzJRlG bDuWxS"
17+
>
18+
<textarea
19+
class="sc-bwzfXH fHpybz"
20+
placeholder="제목을 입력하세요"
21+
style="height: 0px;"
22+
/>
23+
<div
24+
class="sc-fjdhpX gWglfo"
25+
/>
26+
</div>
2327
</div>
2428
<div
25-
class="sc-htpNat iBxfzA"
29+
class="sc-htpNat dNruCf"
2630
id="toolbar"
2731
>
2832
<button
@@ -204,7 +208,7 @@ exports[`MarkdownEditor matches snapshot 1`] = `
204208
</button>
205209
</div>
206210
<div
207-
class="sc-jzJRlG cocNVz"
211+
class="sc-cSHVUG jOkdze"
208212
>
209213
<textarea
210214
style="display: none;"
@@ -314,7 +318,7 @@ exports[`MarkdownEditor matches snapshot 1`] = `
314318
</div>
315319
</div>
316320
<div
317-
class="sc-cSHVUG fnIIPU"
321+
class="sc-kAzzGY wRxqq"
318322
style="width: 50%;"
319323
/>
320324
</div>

src/components/write/__tests__/__snapshots__/MarkdownPreview.test.tsx.snap

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
exports[`MarkdownPreview matches snapshot 1`] = `
44
<div>
55
<div
6-
class="sc-htpNat bbPbZG"
6+
class="sc-htpNat ixBInR"
7+
id="preview"
78
>
89
<h1
910
class="sc-bxivhb cFXJHm"
1011
/>
1112
<div
12-
class="sc-bdVaJa jVeXZc"
13+
class="sc-bdVaJa epxEIa"
1314
>
1415
<div
15-
class="sc-bwzfXH fQauxf atom-one-light"
16+
class="sc-bwzfXH kcygLR atom-one-light"
1617
>
1718
1819

src/components/write/__tests__/__snapshots__/PublishPrivacySetting.test.tsx.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ exports[`PublishPrivacySetting matches snapshot 1`] = `
1212
class="contents"
1313
>
1414
<button
15-
class="sc-htpNat gZmwlD"
15+
class="sc-htpNat iyyGXk"
1616
>
1717
<svg>
1818
icon-globe.svg
1919
</svg>
2020
전체 공개
2121
</button>
2222
<button
23-
class="sc-htpNat bnnkny"
23+
class="sc-htpNat eajANS"
2424
>
2525
<svg>
2626
icon-lock.svg

src/components/write/__tests__/__snapshots__/Toolbar.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
exports[`Toolbar matches snapshot 1`] = `
44
<div>
55
<div
6-
class="sc-bdVaJa ekYSZp"
6+
class="sc-bdVaJa gYMKah"
77
id="toolbar"
88
>
99
<button

src/containers/auth/__tests__/__snapshots__/AuthModalContainer.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
exports[`AuthForm renders correctly 1`] = `
44
<div>
55
<div
6-
class="sc-bdVaJa ryoqV"
6+
class="sc-bdVaJa hcvBqP"
77
>
88
<div
99
class="wrapper"

src/containers/post/PostViewer.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import useNotFound from '../../lib/hooks/useNotFound';
3434
import { Helmet } from 'react-helmet-async';
3535
import { RootState } from '../../modules';
3636
import { toast } from 'react-toastify';
37+
import MobileLikeButton from '../../components/post/MobileLikeButton';
3738

3839
const UserProfileWrapper = styled(VelogResponsive)`
3940
margin-top: 16rem;
@@ -348,6 +349,13 @@ const PostViewer: React.FC<PostViewerProps> = ({
348349
}
349350
toc={<PostToc />}
350351
isPrivate={post.is_private}
352+
mobileLikeButton={
353+
<MobileLikeButton
354+
likes={post.likes}
355+
liked={post.liked}
356+
onToggle={onLikeToggle}
357+
/>
358+
}
351359
/>
352360
<PostContent isMarkdown={post.is_markdown} body={post.body} />
353361
<UserProfileWrapper>

src/containers/post/__tests__/PostCommentsWriteContainer.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import PostCommentsWriteContainer, {
44
PostCommentsWriteContainerProps,
55
} from '../PostCommentsWriteContainer';
66
import renderWithApollo from '../../../lib/renderWithApollo';
7+
import renderWithProviders from '../../../lib/renderWithProviders';
78

89
describe('PostCommentsWriteContainer', () => {
910
const setup = (props: Partial<PostCommentsWriteContainerProps> = {}) => {
1011
const initialProps: PostCommentsWriteContainerProps = {
1112
postId: 'd91aa54b-0e2c-4a18-9104-ec32ea7218a3',
1213
};
13-
const utils = renderWithApollo(
14+
const utils = renderWithProviders(
1415
<PostCommentsWriteContainer {...initialProps} {...props} />,
15-
[],
1616
);
1717

1818
const textarea = utils.getByPlaceholderText(

0 commit comments

Comments
 (0)