Skip to content

Commit 2d80839

Browse files
committed
Apply MongoDB branding and modern UI improvements to mFlix application
- Implement comprehensive MongoDB brand color system with CSS custom properties - Add ExpandableTable component with modern pill-shaped Show More/Show Less button - Update all component styling to use MongoDB brand colors (Forest, Evergreen, Mint, Slate) - Replace gradient styling with solid MongoDB brand colors throughout - Change background from Mint to White for cleaner appearance - Update comment boxes with MongoDB branding (Mint background, Forest border) - Redesign pagination to text-link style with animated underlines - Update search modal buttons (Clear, Close, Search Movies) from blue to Forest green - Enhance hover effects, transitions, and accessibility across all components - Improve responsive design and focus states for better UX
1 parent edd67db commit 2d80839

16 files changed

Lines changed: 1078 additions & 615 deletions

File tree

mflix/client/app/aggregations/aggregations.module.css

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,54 @@
1-
/* Aggregations styles */
1+
/* Aggregations styles - MongoDB Branded */
22
.container {
33
max-width: 1200px;
44
margin: 0 auto;
5-
padding: 2rem;
5+
padding: 2.5rem;
66
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
77
}
88

99
.title {
10-
font-size: 2.5rem;
10+
font-size: 2.75rem;
1111
font-weight: 700;
12-
color: #1a1a1a;
13-
margin-bottom: 0.5rem;
12+
color: var(--mongodb-slate);
13+
margin-bottom: 0.75rem;
1414
text-align: center;
1515
}
1616

17+
.title::after {
18+
content: '';
19+
display: block;
20+
width: 100px;
21+
height: 4px;
22+
background: var(--mongodb-spring);
23+
margin: 1rem auto 0;
24+
border-radius: 2px;
25+
}
26+
1727
.subtitle {
18-
font-size: 1.1rem;
19-
color: #666;
28+
font-size: 1.15rem;
29+
color: var(--color-text-secondary);
2030
text-align: center;
2131
margin-bottom: 3rem;
32+
font-weight: 500;
2233
}
2334

2435
.section {
2536
margin-bottom: 3rem;
26-
background: #fff;
27-
border-radius: 8px;
28-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
37+
background: var(--mongodb-white);
38+
border-radius: var(--radius-xl);
39+
box-shadow: var(--shadow-lg);
2940
overflow: hidden;
41+
border: 2px solid var(--mongodb-mint);
3042
}
3143

3244
.sectionTitle {
3345
font-size: 1.5rem;
34-
font-weight: 600;
35-
color: #2c3e50;
46+
font-weight: 700;
47+
color: var(--mongodb-white);
3648
margin: 0;
3749
padding: 1.5rem 2rem;
38-
background: #f8f9fa;
39-
border-bottom: 1px solid #e9ecef;
50+
background: var(--mongodb-forest);
51+
border-bottom: 3px solid var(--mongodb-spring);
4052
}
4153

4254
.tableContainer {
@@ -47,31 +59,34 @@
4759
.table {
4860
width: 100%;
4961
border-collapse: collapse;
50-
font-size: 0.9rem;
62+
font-size: 0.95rem;
5163
}
5264

5365
.table th {
54-
background: #34495e;
55-
color: white;
66+
background: var(--mongodb-slate);
67+
color: var(--mongodb-white);
5668
font-weight: 600;
57-
padding: 1rem;
69+
padding: 1.125rem 1.25rem;
5870
text-align: left;
5971
white-space: nowrap;
72+
font-size: 0.9rem;
73+
text-transform: uppercase;
74+
letter-spacing: 0.05em;
6075
}
6176

6277
.table td {
63-
padding: 1rem;
64-
border-bottom: 1px solid #e9ecef;
78+
padding: 1.125rem 1.25rem;
79+
border-bottom: 1px solid var(--color-border);
6580
vertical-align: top;
6681
}
6782

6883
.table tr:hover {
69-
background: #f8f9fa;
84+
background: var(--mongodb-mint);
7085
}
7186

7287
.movieTitle {
7388
font-weight: 600;
74-
color: #2c3e50;
89+
color: var(--mongodb-slate);
7590
max-width: 200px;
7691
word-wrap: break-word;
7792
}
@@ -96,9 +111,9 @@
96111
.comment {
97112
margin-bottom: 0.75rem;
98113
padding: 0.5rem;
99-
background: #f8f9fa;
100-
border-radius: 4px;
101-
border-left: 3px solid #3498db;
114+
background: var(--mongodb-mint);
115+
border-radius: var(--radius-md);
116+
border-left: 3px solid var(--mongodb-forest);
102117
}
103118

104119
.comment:last-child {
@@ -107,14 +122,14 @@
107122

108123
.commentText {
109124
font-size: 0.85rem;
110-
color: #2c3e50;
125+
color: var(--mongodb-slate);
111126
margin-bottom: 0.25rem;
112127
line-height: 1.4;
113128
}
114129

115130
.commentMeta {
116131
font-size: 0.75rem;
117-
color: #7f8c8d;
132+
color: var(--color-text-muted);
118133
font-style: italic;
119134
}
120135

mflix/client/app/aggregations/page.tsx

Lines changed: 98 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { fetchMoviesWithComments, fetchMoviesByYear, fetchDirectorStats } from '@/lib/api';
33
import { MovieWithComments, YearlyStats, DirectorStats } from '@/types/aggregations';
44
import styles from './aggregations.module.css';
5+
import ExpandableTable from '@/components/ExpandableTable/ExpandableTable';
56

67
export default async function AggregationsPage() {
78
const MOVIES_WITH_COMMENTS_LIMIT = 5;
@@ -38,43 +39,48 @@ export default async function AggregationsPage() {
3839
<section className={styles.section}>
3940
<h2 className={styles.sectionTitle}>Movies with Recent Comments</h2>
4041
{commentsData.success && commentsData.data ? (
41-
<div className={styles.tableContainer}>
42-
<table className={styles.table}>
43-
<thead>
44-
<tr>
45-
<th>Movie Title</th>
46-
<th>Year</th>
47-
<th>Rating</th>
48-
<th>Total Comments</th>
49-
<th>Recent Comments</th>
50-
</tr>
51-
</thead>
52-
<tbody>
53-
{(commentsData.data as MovieWithComments[]).map((movie) => (
54-
<tr key={movie._id}>
55-
<td className={styles.movieTitle}>{movie.title}</td>
56-
<td>{movie.year}</td>
57-
<td>{movie.imdbRating ? movie.imdbRating.toFixed(1) : 'N/A'}</td>
58-
<td>{movie.totalComments}</td>
59-
<td>
60-
<div className={styles.commentsContainer}>
61-
{movie.recentComments?.slice(0, 2).map((comment, index) => (
62-
<div key={`${movie._id}-${comment.date}-${index}`} className={styles.comment}>
63-
<div className={styles.commentText}>
64-
&ldquo;{(comment.text || 'No text').slice(0, 80)}{comment.text?.length > 80 ? '...' : ''}&rdquo;
65-
</div>
66-
<div className={styles.commentMeta}>
67-
by {comment.userName} on {new Date(comment.date).toLocaleDateString()}
68-
</div>
69-
</div>
70-
)) || <div>No recent comments</div>}
71-
</div>
72-
</td>
42+
<ExpandableTable
43+
initialRowCount={5}
44+
totalRowCount={(commentsData.data as MovieWithComments[]).length}
45+
>
46+
<div className={styles.tableContainer}>
47+
<table className={styles.table}>
48+
<thead>
49+
<tr>
50+
<th>Movie Title</th>
51+
<th>Year</th>
52+
<th>Rating</th>
53+
<th>Total Comments</th>
54+
<th>Recent Comments</th>
7355
</tr>
74-
))}
75-
</tbody>
76-
</table>
77-
</div>
56+
</thead>
57+
<tbody>
58+
{(commentsData.data as MovieWithComments[]).map((movie) => (
59+
<tr key={movie._id}>
60+
<td className={styles.movieTitle}>{movie.title}</td>
61+
<td>{movie.year}</td>
62+
<td>{movie.imdbRating ? movie.imdbRating.toFixed(1) : 'N/A'}</td>
63+
<td>{movie.totalComments}</td>
64+
<td>
65+
<div className={styles.commentsContainer}>
66+
{movie.recentComments?.slice(0, 2).map((comment, index) => (
67+
<div key={`${movie._id}-${comment.date}-${index}`} className={styles.comment}>
68+
<div className={styles.commentText}>
69+
&ldquo;{(comment.text || 'No text').slice(0, 80)}{comment.text?.length > 80 ? '...' : ''}&rdquo;
70+
</div>
71+
<div className={styles.commentMeta}>
72+
by {comment.userName} on {new Date(comment.date).toLocaleDateString()}
73+
</div>
74+
</div>
75+
)) || <div>No recent comments</div>}
76+
</div>
77+
</td>
78+
</tr>
79+
))}
80+
</tbody>
81+
</table>
82+
</div>
83+
</ExpandableTable>
7884
) : (
7985
<div className={styles.error}>
8086
Failed to load movies with comments: {commentsData.error || 'Unknown error'}
@@ -86,32 +92,37 @@ export default async function AggregationsPage() {
8692
<section className={styles.section}>
8793
<h2 className={styles.sectionTitle}>Movies by Year Statistics</h2>
8894
{yearData.success && yearData.data ? (
89-
<div className={styles.tableContainer}>
90-
<table className={styles.table}>
91-
<thead>
92-
<tr>
93-
<th>Year</th>
94-
<th>Movie Count</th>
95-
<th>Average Rating</th>
96-
<th>Highest Rating</th>
97-
<th>Lowest Rating</th>
98-
<th>Total Votes</th>
99-
</tr>
100-
</thead>
101-
<tbody>
102-
{(yearData.data as YearlyStats[]).slice(0, 20).map((yearStats) => (
103-
<tr key={yearStats.year}>
104-
<td className={styles.year}>{yearStats.year}</td>
105-
<td>{yearStats.movieCount}</td>
106-
<td>{yearStats.averageRating ? yearStats.averageRating.toFixed(2) : 'N/A'}</td>
107-
<td>{yearStats.highestRating ? yearStats.highestRating.toFixed(1) : 'N/A'}</td>
108-
<td>{yearStats.lowestRating ? yearStats.lowestRating.toFixed(1) : 'N/A'}</td>
109-
<td>{yearStats.totalVotes?.toLocaleString() || 'N/A'}</td>
95+
<ExpandableTable
96+
initialRowCount={10}
97+
totalRowCount={(yearData.data as YearlyStats[]).length}
98+
>
99+
<div className={styles.tableContainer}>
100+
<table className={styles.table}>
101+
<thead>
102+
<tr>
103+
<th>Year</th>
104+
<th>Movie Count</th>
105+
<th>Average Rating</th>
106+
<th>Highest Rating</th>
107+
<th>Lowest Rating</th>
108+
<th>Total Votes</th>
110109
</tr>
111-
))}
112-
</tbody>
113-
</table>
114-
</div>
110+
</thead>
111+
<tbody>
112+
{(yearData.data as YearlyStats[]).map((yearStats) => (
113+
<tr key={yearStats.year}>
114+
<td className={styles.year}>{yearStats.year}</td>
115+
<td>{yearStats.movieCount}</td>
116+
<td>{yearStats.averageRating ? yearStats.averageRating.toFixed(2) : 'N/A'}</td>
117+
<td>{yearStats.highestRating ? yearStats.highestRating.toFixed(1) : 'N/A'}</td>
118+
<td>{yearStats.lowestRating ? yearStats.lowestRating.toFixed(1) : 'N/A'}</td>
119+
<td>{yearStats.totalVotes?.toLocaleString() || 'N/A'}</td>
120+
</tr>
121+
))}
122+
</tbody>
123+
</table>
124+
</div>
125+
</ExpandableTable>
115126
) : (
116127
<div className={styles.error}>
117128
Failed to load yearly statistics: {yearData.error || 'Unknown error'}
@@ -123,28 +134,33 @@ export default async function AggregationsPage() {
123134
<section className={styles.section}>
124135
<h2 className={styles.sectionTitle}>Directors with Most Movies</h2>
125136
{directorsData.success && directorsData.data ? (
126-
<div className={styles.tableContainer}>
127-
<table className={styles.table}>
128-
<thead>
129-
<tr>
130-
<th>Rank</th>
131-
<th>Director</th>
132-
<th>Movie Count</th>
133-
<th>Average Rating</th>
134-
</tr>
135-
</thead>
136-
<tbody>
137-
{(directorsData.data as DirectorStats[]).map((director, index) => (
138-
<tr key={director.director}>
139-
<td className={styles.rank}>#{index + 1}</td>
140-
<td className={styles.directorName}>{director.director}</td>
141-
<td>{director.movieCount}</td>
142-
<td>{director.averageRating ? director.averageRating.toFixed(2) : 'N/A'}</td>
137+
<ExpandableTable
138+
initialRowCount={10}
139+
totalRowCount={(directorsData.data as DirectorStats[]).length}
140+
>
141+
<div className={styles.tableContainer}>
142+
<table className={styles.table}>
143+
<thead>
144+
<tr>
145+
<th>Rank</th>
146+
<th>Director</th>
147+
<th>Movie Count</th>
148+
<th>Average Rating</th>
143149
</tr>
144-
))}
145-
</tbody>
146-
</table>
147-
</div>
150+
</thead>
151+
<tbody>
152+
{(directorsData.data as DirectorStats[]).map((director, index) => (
153+
<tr key={director.director}>
154+
<td className={styles.rank}>#{index + 1}</td>
155+
<td className={styles.directorName}>{director.director}</td>
156+
<td>{director.movieCount}</td>
157+
<td>{director.averageRating ? director.averageRating.toFixed(2) : 'N/A'}</td>
158+
</tr>
159+
))}
160+
</tbody>
161+
</table>
162+
</div>
163+
</ExpandableTable>
148164
) : (
149165
<div className={styles.error}>
150166
Failed to load director statistics: {directorsData.error || 'Unknown error'}

0 commit comments

Comments
 (0)