Skip to content

Commit 78a076e

Browse files
committed
✨ Add likes functionality
1 parent 7453a09 commit 78a076e

File tree

8 files changed

+253
-76
lines changed

8 files changed

+253
-76
lines changed

src/app/core/mocks/feed.mock.ts

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export const getFeedMock = (): Feed => ({
1414
image: faker.datatype.string(),
1515
website: getWebsitesMock(),
1616
inUser: faker.datatype.boolean(),
17+
liked: faker.datatype.boolean(),
18+
likes: faker.datatype.number(),
1719
});
1820

1921
export const getFeedsMock = (size = 10): Feed[] => {

src/app/core/models/feed.model.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export class Feed {
1010
public link: string,
1111
public image: string,
1212
public website: Website,
13+
public likes: number,
1314
public inUser?: boolean,
15+
public liked?: boolean,
1416
) {}
1517
}

src/app/core/services/user.service.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { environment } from 'environments/environment';
44

55
import { Observable, map } from 'rxjs';
66

7+
import { OptionFeed } from '@customTypes/option.type';
8+
79
import { IResponseUser } from '@interfaces/response.interface';
810
import { IUser } from '@interfaces/user.interface';
911

@@ -31,7 +33,7 @@ export class UserService {
3133
private authService: AuthService,
3234
) { }
3335

34-
modifyPreferences(resourceID: string, filter: 'subscription' | 'read' | 'saved') {
36+
modifyPreferences(resourceID: string, filter: OptionFeed) {
3537
const url = `${base_url}/user/${filter}/${resourceID}`;
3638
return this.http.patch(url, {}, this.headers);
3739
}

src/app/core/types/option.type.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type OptionFeed = 'subscription' | 'read' | 'saved' | 'liked';

src/app/shared/news-container/news-container.component.css

+189-45
Original file line numberDiff line numberDiff line change
@@ -6,103 +6,247 @@
66
.card.card-new {
77
display: flex;
88
align-items: flex-start;
9-
min-height: 13rem;
10-
height: 13rem;
11-
max-height: 13rem;
9+
flex-direction: column;
10+
min-height: 10rem;
1211
transition: 0.5s;
13-
}
14-
15-
.card.card.card-new:hover {
16-
box-shadow: rgb(0 0 0 / 20%) 1px 1px 24px 1px;
17-
}
18-
19-
.card.card-new figure {
20-
height: 100%;
21-
width: 16rem;
22-
}
23-
24-
.card.card-new figure img {
25-
object-fit: cover;
26-
width: 100%;
27-
height: 100%;
28-
border-radius: 0.6rem 0 0 0.6rem;
12+
padding: 1rem;
13+
gap: 1rem;
2914
}
3015

3116
.card.card-new .card-body {
3217
display: flex;
33-
flex-direction: column;
18+
flex-direction: row;
19+
justify-content: space-between;
3420
height: 100%;
3521
width: 100%;
3622
flex-grow: 1;
37-
padding: 1rem;
3823
gap: 10px;
3924
}
4025

41-
.card.card-new .card-body .title-wrapper {
26+
.title-wrapper {
4227
display: flex;
43-
justify-content: space-between;
44-
font-size: 24px;
28+
font-size: 22px;
4529
gap: 5px;
30+
width: 100%;
31+
flex-direction: column;
4632
}
4733

48-
.card.card-new .card-body .title-wrapper .new-title {
34+
.title-wrapper .new-title {
4935
font-weight: 600;
5036
text-overflow: ellipsis;
5137
overflow: hidden;
5238
display: -webkit-box !important;
39+
line-clamp: 3;
5340
-webkit-line-clamp: 3;
5441
-webkit-box-orient: vertical;
5542
white-space: normal;
56-
height: 108px;
57-
max-height: 108px;
43+
height: 100px;
44+
max-height: 100px;
45+
transition: 0.2s ease-in-out;
46+
text-wrap: balance;
5847
}
5948

60-
.card.card-new .card-body .title-wrapper .new-title:hover {
49+
.title-wrapper .new-title:hover {
6150
text-decoration: underline;
51+
transition: 0.2s ease-in-out;
6252
}
6353

64-
.card.card-new .card-body .title-wrapper .new-title:hover,
65-
.card.card-new .card-body .title-wrapper .save {
54+
.title-wrapper .new-title:hover,
55+
.title-wrapper .save {
6656
cursor: pointer;
6757
}
6858

69-
.card.card-new .card-body .title-wrapper .save {
59+
.title-wrapper .save {
7060
color: var(--primary-color);
7161
margin-top: 5px;
7262
z-index: 10;
7363
}
7464

75-
.card.card.card-new .card-body .date {
76-
flex-grow: 1;
65+
.title-wrapper .website-name {
66+
font-size: 15px;
67+
color: var(--secondary-color);
68+
font-weight: 500;
69+
}
70+
71+
.card-body .details {
7772
display: flex;
78-
align-items: flex-end;
79-
justify-content: flex-end;
73+
gap: 10px;
74+
align-items: center;
75+
color: var(--font-color-secondary);
76+
}
77+
78+
.details .date,
79+
.details .read {
8080
font-size: 13px;
81+
}
82+
83+
.details .bull {
84+
font-size: 18px;
85+
}
86+
87+
.details-wrapper .options {
88+
display: flex;
89+
justify-content: center;
90+
align-items: center;
91+
width: fit-content;
92+
gap: 0.6rem;
93+
flex-wrap: wrap;
94+
margin: 0 0 0 auto;
95+
}
96+
97+
.details-wrapper .options .separator {
98+
height: 24px;
99+
width: 0.1rem;
100+
background: #c1c1c1;
101+
}
102+
103+
.details-wrapper .options .option {
81104
color: var(--font-color-secondary);
105+
cursor: pointer;
106+
padding: 3px 10px;
107+
border-radius: 10px;
108+
display: flex;
109+
justify-content: center;
110+
align-items: center;
111+
gap: 6px;
112+
min-height: 29px;
82113
}
83114

84-
.card.card.card-new .card-body .date span {
115+
.details-wrapper .option.default {
116+
cursor: default !important;
117+
}
118+
119+
.options .option:hover:has(.bx-like) {
120+
background: #e66d9b2e;
121+
}
122+
123+
.options .option:hover:has(.bx-bookmark) {
124+
background: #0098fa2e;
125+
}
126+
127+
.option .btn-icon {
128+
color: var(--font-color-secondary);
129+
width: 24px;
130+
height: 24px;
131+
cursor: pointer;
132+
133+
}
134+
135+
.details-wrapper .options .option i {
136+
font-size: 20px;
137+
}
138+
139+
.bx-bookmark {
140+
color: var(--primary-color);
141+
}
142+
143+
.bx-like {
85144
color: var(--secondary-color);
86-
margin-left: 4px;
87-
font-weight: 500;
145+
}
146+
147+
.bx-bookmark {
148+
color: var(--primary-color);
149+
}
150+
151+
.bx {
152+
position: relative;
153+
display: inline-block;
154+
}
155+
156+
.bx-like::before,
157+
.bx-bookmark::before {
158+
position: absolute;
159+
top: 0;
160+
left: 0;
161+
transition: opacity 0.3s ease, transform 0.3s ease;
162+
}
163+
164+
.bx::after {
165+
top: 0;
166+
left: 0;
167+
opacity: 0;
168+
transition: opacity 0.3s ease, transform 0.3s ease;
169+
}
170+
171+
.bx-like::after {
172+
content: "\ed5f";
173+
}
174+
175+
.bx-bookmark::after {
176+
content: "\ec31";
177+
}
178+
179+
.option:hover:has(.bx-like) .bx-like::before,
180+
.option:hover:has(.bx-bookmark) .bx-bookmark::before {
181+
opacity: 0;
182+
}
183+
184+
.option:hover:has(.bx-like) .bx-like::after,
185+
.option:hover:has(.bx-bookmark) .bx-bookmark::after {
186+
opacity: 1;
187+
}
188+
189+
190+
.details-wrapper {
191+
display: flex;
192+
justify-content: space-between;
193+
align-items: center;
194+
flex-direction: row;
195+
height: 100%;
196+
width: 100%;
197+
}
198+
199+
.details {
200+
display: flex;
201+
gap: 10px;
202+
width: fit-content;
203+
align-items: center;
204+
color: var(--font-color-secondary);
205+
}
206+
207+
208+
figure {
209+
height: 10.5rem;
210+
width: 25rem;
211+
}
212+
213+
figure img {
214+
object-fit: cover;
215+
width: 100%;
216+
height: 100%;
217+
border-radius: 0.6rem;
88218
}
89219

90220
@media (max-width: 480px) {
91221
.card.card-new {
222+
padding: 0.6rem;
223+
gap: 0.5rem;
224+
}
225+
226+
.card.card-new .card-body {
227+
flex-direction: column-reverse;
228+
}
229+
230+
.details-wrapper {
231+
width: 100%;
92232
flex-direction: column;
93-
height: auto;
94-
max-height: none;
233+
align-items: flex-start;
234+
justify-content: flex-end;
235+
gap: 1rem;
95236
}
96237

97-
.card.card-new figure {
98-
max-height: 9rem;
238+
.details-wrapper .options {
239+
align-self: center;
240+
margin: 0;
99241
width: 100%;
242+
justify-content: space-evenly;
100243
}
101244

102-
.card.card-new figure img {
103-
border-radius: 0.6rem 0.6rem 0 0;
245+
figure {
246+
width: 100%;
104247
}
105-
.card.card-new .card-body .title-wrapper .new-title {
248+
249+
.title-wrapper .new-title {
106250
height: 90px;
107251
font-size: 20px;
108252
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,36 @@
11
<div class="news" infiniteScroll [infiniteScrollDistance]="1" (scrolled)="onScroll()">
2-
<app-new-card-recent *ngIf="recentFeed" [feed]="recentFeed"></app-new-card-recent>
2+
<!-- <app-new-card-recent *ngIf="recentFeed" [feed]="recentFeed"></app-new-card-recent> -->
33
<div class="card card-new" *ngFor="let feed of feeds; let i = index">
4-
<figure *ngIf="feed.image">
5-
<img [src]="feed.image" alt="news-image" loading="lazy">
6-
</figure>
74
<div class="card-body">
85
<div class="title-wrapper">
6+
<span class="website-name">{{ feed.website.name }}</span>
97
<a (click)="moreDetails(feed._id)" class="new-title"> {{feed.title }}</a>
10-
<a class="save" (click)="saveFeed(feed._id)">
11-
<i class="bx bx-bookmark-plus" [class.bxs-bookmark-minus]="feed.inUser" #iconi
12-
(mouseover)="changeStyle(iconi, true)" (mouseout)="changeStyle(iconi, false)"></i>
13-
</a>
148
</div>
15-
<p class="date">
16-
{{ feed.pubDate | date: 'dd/MM/yyyy, h:mm a' }} &bull; by
17-
<span>{{ feed.website.name }}</span>
18-
</p>
9+
<figure *ngIf="feed.image">
10+
<img [src]="feed.image" alt="news-image" loading="lazy">
11+
</figure>
12+
</div>
13+
<div class="details-wrapper">
14+
<div class="details">
15+
<p class="date"> {{ feed.pubDate | date: 'dd-MM-yyyy' }} </p>
16+
<p class="bull">&bull;</p>
17+
<p class="read"> {{ 10 }} min </p>
18+
</div>
19+
<div class="options">
20+
<div class="option default">
21+
<i class="bx bx-show"></i>
22+
<span> {{ 10 }} </span>
23+
</div>
24+
<div class="separator"></div>
25+
<div class="option" (click)="modifyPreference(feed._id, 'liked')">
26+
<i class="bx bx-like" [class.bxs-like]="feed.liked"></i>
27+
<span *ngIf="feed.likes || feed.likes > 0"> {{ feed.likes }} </span>
28+
</div>
29+
<div class="separator"></div>
30+
<div class="option" (click)="modifyPreference(feed._id, 'saved')">
31+
<i class="bx bx-bookmark" [class.bxs-bookmark]="feed.inUser"></i>
32+
</div>
33+
</div>
1934
</div>
2035
</div>
21-
</div>
36+
</div>

0 commit comments

Comments
 (0)