- {filteredProblems.map((problem) => (
-
- ))}
+
+
+
+ {currentView === 'grid' ? (
+
+ {problems.map((problem) => (
+
+ ))}
+
+ ) : (
+
+ )}
);
};
-export default ProblemGrid;
+export default ProblemGrid;
\ No newline at end of file
diff --git a/src/client/src/components/problems/ProblemList.js b/src/client/src/components/problems/ProblemList.js
new file mode 100644
index 0000000..a08eeee
--- /dev/null
+++ b/src/client/src/components/problems/ProblemList.js
@@ -0,0 +1,53 @@
+import React from "react";
+import { Link } from "react-router-dom";
+import {
+ getDifficultyText,
+ getDifficultyClass,
+} from "../../constants/difficulty";
+import "../../styles/components/ProblemList.css";
+
+const ProblemList = ({ problems }) => {
+ if (problems.length === 0) {
+ return (
+
+
No problems found matching your criteria.
+
+ );
+ }
+
+ return (
+
+
+ ID
+ Problem Name
+ Difficulty
+ Acceptance
+
+
+ {problems.map((problem, index) => (
+
+ ))}
+
+
+ );
+};
+
+const ProblemListItem = ({ problem, index }) => {
+ const difficultyText = getDifficultyText(problem.difficulty);
+ const difficultyClass = getDifficultyClass(problem.difficulty);
+
+ return (
+
+
{problem.id}
+
+ {problem.title}
+
+
+ {difficultyText}
+
+
{problem.acceptance}%
+
+ );
+};
+
+export default ProblemList;
\ No newline at end of file
diff --git a/src/client/src/services/api.js b/src/client/src/services/api.js
index b57069a..762d1c6 100644
--- a/src/client/src/services/api.js
+++ b/src/client/src/services/api.js
@@ -10,13 +10,13 @@ export const fetchProblems = async (page = 1, limit = 50, filters = {}) => {
// Add filter parameters if they exist
if (filters.company) {
- params.append('companies', filters.company);
+ params.append('company', filters.company);
}
if (filters.difficulty) {
- params.append('difficulties', filters.difficulty);
+ params.append('difficulty', filters.difficulty);
}
if (filters.timePeriod) {
- params.append('tags', filters.timePeriod);
+ params.append('tag', filters.timePeriod);
}
const response = await fetch(`${API_BASE_URL}/problems?${params}`);
diff --git a/src/client/src/styles/components/ProblemCard.css b/src/client/src/styles/components/ProblemCard.css
index 97027f8..1b18551 100644
--- a/src/client/src/styles/components/ProblemCard.css
+++ b/src/client/src/styles/components/ProblemCard.css
@@ -2,7 +2,7 @@
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
- padding: 1.75rem;
+ padding: 1.25rem; /* Reduced from 1.75rem */
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid rgba(255, 255, 255, 0.8);
position: relative;
@@ -22,8 +22,8 @@
}
.problem-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+ transform: translateY(-2px); /* Reduced from -4px */
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); /* Reduced shadow */
}
.problem-card:hover::before {
@@ -34,16 +34,16 @@
display: flex;
justify-content: space-between;
align-items: flex-start;
- margin-bottom: 1.25rem;
+ margin-bottom: 1rem; /* Reduced from 1.25rem */
gap: 1rem;
}
.problem-header h3 {
margin: 0;
- font-size: 1.25rem;
+ font-size: 1.1rem; /* Slightly smaller */
flex: 1;
font-weight: 600;
- line-height: 1.4;
+ line-height: 1.3; /* Tighter line height */
}
.problem-header a {
@@ -79,9 +79,9 @@
}
.difficulty {
- padding: 0.4rem 1rem;
+ padding: 0.3rem 0.8rem; /* Slightly smaller */
border-radius: 20px;
- font-size: 0.8rem;
+ font-size: 0.75rem; /* Smaller font */
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
@@ -110,9 +110,9 @@
.problem-stats {
display: flex;
- gap: 1.5rem;
- margin-bottom: 1.25rem;
- font-size: 0.9rem;
+ gap: 1rem; /* Reduced from 1.5rem */
+ margin-bottom: 1rem; /* Reduced from 1.25rem */
+ font-size: 0.85rem; /* Slightly smaller */
}
.problem-stats span {
@@ -148,16 +148,16 @@
.problem-companies {
border-top: 1px solid #e2e8f0;
- padding-top: 1.25rem;
- margin-top: 1rem;
+ padding-top: 1rem; /* Reduced from 1.25rem */
+ margin-top: 0.75rem; /* Reduced from 1rem */
}
.problem-companies small {
display: block;
- margin-bottom: 0.75rem;
+ margin-bottom: 0.5rem; /* Reduced from 0.75rem */
color: #718096;
font-weight: 600;
- font-size: 0.8rem;
+ font-size: 0.75rem; /* Smaller */
text-transform: uppercase;
letter-spacing: 0.5px;
}
@@ -165,17 +165,17 @@
.company-tags {
display: flex;
flex-wrap: wrap;
- gap: 0.6rem;
+ gap: 0.5rem; /* Reduced from 0.6rem */
}
.company-tag {
background: linear-gradient(135deg, #ffffff, #f7fafc);
- padding: 0.5rem 1rem;
+ padding: 0.4rem 0.8rem; /* Reduced padding */
border-radius: 10px;
- font-size: 0.8rem;
+ font-size: 0.75rem; /* Smaller */
display: flex;
align-items: center;
- gap: 0.4rem;
+ gap: 0.3rem; /* Reduced gap */
border: 1px solid #e2e8f0;
transition: all 0.2s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
@@ -185,7 +185,7 @@
.company-tag:hover {
transform: translateY(-1px);
- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); /* Reduced shadow */
border-color: #ffa116;
background: linear-gradient(135deg, #fffaf0, #fffbeb);
}
@@ -196,7 +196,7 @@
}
.recent-indicator {
- font-size: 0.7rem;
+ font-size: 0.65rem; /* Smaller */
animation: pulse 2s infinite;
}
@@ -214,18 +214,18 @@
/* Responsive Design */
@media (max-width: 768px) {
.problem-card {
- padding: 1.25rem;
- margin: 0.5rem;
+ padding: 1rem; /* Reduced from 1.25rem */
+ margin: 0.25rem; /* Reduced from 0.5rem */
}
.problem-header {
flex-direction: column;
align-items: flex-start;
- gap: 0.75rem;
+ gap: 0.5rem; /* Reduced from 0.75rem */
}
.problem-header h3 {
- font-size: 1.1rem;
+ font-size: 1rem; /* Smaller on mobile */
padding-right: 0;
}
@@ -235,7 +235,7 @@
.problem-stats {
flex-direction: column;
- gap: 0.5rem;
+ gap: 0.25rem; /* Reduced from 0.5rem */
}
.problem-stats span::before {
@@ -243,12 +243,12 @@
}
.company-tags {
- gap: 0.4rem;
+ gap: 0.3rem; /* Reduced from 0.4rem */
}
.company-tag {
- padding: 0.4rem 0.8rem;
- font-size: 0.75rem;
+ padding: 0.3rem 0.6rem; /* Smaller on mobile */
+ font-size: 0.7rem; /* Smaller on mobile */
}
}
@@ -256,7 +256,7 @@
@keyframes cardEntrance {
from {
opacity: 0;
- transform: translateY(20px);
+ transform: translateY(10px); /* Reduced from 20px */
}
to {
opacity: 1;
diff --git a/src/client/src/styles/components/ProblemGrid.css b/src/client/src/styles/components/ProblemGrid.css
index ec54e5d..7eeadfb 100644
--- a/src/client/src/styles/components/ProblemGrid.css
+++ b/src/client/src/styles/components/ProblemGrid.css
@@ -1,21 +1,34 @@
+.problem-container {
+ margin-bottom: 1rem;
+ padding-bottom: 0;
+}
+
.problem-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 1.5rem;
- padding: 1rem 0;
+ gap: 1rem;
+ padding: 0.5rem 0;
}
.no-problems {
text-align: center;
- padding: 2rem;
+ padding: 1.5rem;
background: white;
border-radius: 8px;
color: #666;
+ margin: 1rem 0;
+}
+
+/* Ensure list view takes only needed space */
+.problem-list-container {
+ margin-bottom: 0;
+ padding-bottom: 0;
}
/* Responsive adjustments */
@media (max-width: 640px) {
.problem-grid {
grid-template-columns: 1fr;
+ gap: 0.75rem;
}
}
\ No newline at end of file
diff --git a/src/client/src/styles/components/ProblemList.css b/src/client/src/styles/components/ProblemList.css
new file mode 100644
index 0000000..59e4c2c
--- /dev/null
+++ b/src/client/src/styles/components/ProblemList.css
@@ -0,0 +1,165 @@
+/* styles/components/ProblemList.css */
+.problem-list {
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+ margin: 0.5rem 0;
+}
+
+.list-header {
+ display: grid;
+ grid-template-columns: 80px 1fr 120px 100px;
+ gap: 1rem;
+ padding: 0.75rem 1.5rem;
+ background: #f8fafc;
+ border-bottom: 2px solid #e2e8f0;
+ font-weight: 600;
+ color: #4a5568;
+ font-size: 0.9rem;
+ align-items: center;
+}
+
+/* Left align all headers explicitly */
+.header-id,
+.header-title,
+.header-difficulty,
+.header-acceptance {
+ text-align: left;
+ justify-self: start;
+}
+
+.list-content {
+ min-height: auto;
+}
+
+.problem-list-item {
+ display: grid;
+ grid-template-columns: 80px 1fr 120px 100px;
+ gap: 1rem;
+ padding: 0.75rem 1.5rem;
+ border-bottom: 1px solid #f1f5f9;
+ transition: background-color 0.2s ease;
+ align-items: center;
+ min-height: 60px;
+}
+
+/* Alternate background colors for rows */
+.problem-list-item:nth-child(even) {
+ background-color: #fafbfc;
+}
+
+.problem-list-item:nth-child(odd) {
+ background-color: #ffffff;
+}
+
+.problem-list-item:hover {
+ background: #f0f7ff !important; /* Override alternate colors on hover */
+ border-left: 3px solid #0066cc;
+ margin-left: -3px;
+}
+
+.problem-list-item:last-child {
+ border-bottom: none;
+}
+
+/* Left align all content cells */
+.problem-id {
+ color: #666;
+ font-weight: 500;
+ font-size: 0.9rem;
+ text-align: left;
+ justify-self: start;
+}
+
+.problem-title {
+ font-weight: 500;
+ text-align: left;
+ justify-self: start;
+}
+
+.problem-title a {
+ color: #2d3748;
+ text-decoration: none;
+ transition: color 0.2s ease;
+ display: block;
+ width: 100%;
+}
+
+.problem-title a:hover {
+ color: #0066cc;
+}
+
+.problem-difficulty {
+ padding: 0.25rem 0.75rem;
+ border-radius: 12px;
+ font-size: 0.8rem;
+ font-weight: 500;
+ text-align: center;
+ text-transform: uppercase;
+ justify-self: start; /* Changed to left align */
+ width: fit-content;
+}
+
+.problem-acceptance {
+ color: #666;
+ font-size: 0.9rem;
+ text-align: left; /* Changed to left align */
+ justify-self: start;
+}
+
+.problem-difficulty.easy {
+ background: #e7f6e7;
+ color: #2cbb5d;
+ border: 1px solid #c8e6c9;
+}
+
+.problem-difficulty.medium {
+ background: #fff7e6;
+ color: #ffa116;
+ border: 1px solid #ffe0b2;
+}
+
+.problem-difficulty.hard {
+ background: #ffe6e6;
+ color: #ff375f;
+ border: 1px solid #ffcdd2;
+}
+
+/* Ensure no extra space when empty */
+.problem-list:empty {
+ display: none;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .list-header {
+ grid-template-columns: 60px 1fr 100px;
+ padding: 0.75rem 1rem;
+ }
+
+ .problem-list-item {
+ grid-template-columns: 60px 1fr 100px;
+ padding: 0.75rem 1rem;
+ }
+
+ .header-acceptance,
+ .problem-acceptance {
+ display: none;
+ }
+
+ .problem-difficulty {
+ font-size: 0.75rem;
+ padding: 0.2rem 0.5rem;
+ }
+}
+
+/* Enhanced hover effects */
+.problem-list-item {
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.problem-list-item:hover {
+ transform: translateX(4px);
+ box-shadow: 2px 0 8px rgba(0, 102, 204, 0.1);
+}
\ No newline at end of file
diff --git a/src/client/src/styles/layout/Body.css b/src/client/src/styles/layout/Body.css
index c98c329..a1c8ffa 100644
--- a/src/client/src/styles/layout/Body.css
+++ b/src/client/src/styles/layout/Body.css
@@ -1,20 +1,25 @@
+/* styles/layout/Body.css */
.body {
flex: 1;
- padding: 2rem 0;
+ padding: 0.5rem 0;
background-color: #f5f5f5;
+ min-height: auto;
}
.body-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
+ min-height: auto;
+ /* Ensure no extra padding at bottom */
+ padding-bottom: 0;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
- min-height: 400px;
+ min-height: 200px;
}
.loading-spinner {
@@ -26,7 +31,7 @@
display: flex;
justify-content: center;
align-items: center;
- min-height: 400px;
+ min-height: 200px;
}
.error-message {
@@ -48,7 +53,7 @@
background-color: #c82333;
}
-/* Add to styles/layout/Body.css */
-.body-content {
- min-height: 60vh;
-}
+/* Remove any bottom margin from the last element in body */
+.body-content > *:last-child {
+ margin-bottom: 0;
+}
\ No newline at end of file
diff --git a/src/client/src/styles/layout/Footer.css b/src/client/src/styles/layout/Footer.css
deleted file mode 100644
index 9e9425a..0000000
--- a/src/client/src/styles/layout/Footer.css
+++ /dev/null
@@ -1,64 +0,0 @@
-.footer {
- background: #1a1a1a;
- color: white;
- padding: 1.5rem 0;
- margin-top: auto;
- border-top: 1px solid #2d2d2d;
-}
-
-.footer-content {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0 2rem;
- text-align: center;
-}
-
-.footer p {
- margin: 0;
- font-size: 0.95rem;
- color: #a0a0a0;
- font-weight: 400;
- letter-spacing: 0.5px;
- transition: color 0.2s ease;
-}
-
-.footer p:hover {
- color: #d0d0d0;
-}
-
-/* Optional: Add a subtle top border accent */
-.footer {
- position: relative;
-}
-
-.footer::before {
- content: '';
- position: absolute;
- top: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 100px;
- height: 2px;
- background: linear-gradient(90deg, transparent, #ffa116, transparent);
-}
-
-/* Responsive Design */
-@media (max-width: 768px) {
- .footer {
- padding: 1.25rem 0;
- }
-
- .footer-content {
- padding: 0 1rem;
- }
-
- .footer p {
- font-size: 0.9rem;
- }
-}
-
-@media (max-width: 480px) {
- .footer p {
- font-size: 0.85rem;
- }
-}
\ No newline at end of file
diff --git a/src/client/src/styles/layout/ViewToggle.css b/src/client/src/styles/layout/ViewToggle.css
new file mode 100644
index 0000000..262796a
--- /dev/null
+++ b/src/client/src/styles/layout/ViewToggle.css
@@ -0,0 +1,28 @@
+.view-toggle {
+ display: flex;
+ gap: 0.5rem;
+ margin-bottom: 1.5rem;
+ justify-content: flex-end;
+}
+
+.toggle-btn {
+ padding: 0.5rem 1rem;
+ border: 1px solid #e2e8f0;
+ background: white;
+ color: #4a5568;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ font-size: 0.9rem;
+}
+
+.toggle-btn:hover {
+ background: #f7fafc;
+ border-color: #cbd5e0;
+}
+
+.toggle-btn.active {
+ background: #0066cc;
+ color: white;
+ border-color: #0066cc;
+}
\ No newline at end of file