Skip to content

Commit 2f5fabb

Browse files
committed
Change to home page, added detailed explanation for each solution akin to Google docs. Added support for multiple solutions.
1 parent 4f2f510 commit 2f5fabb

23 files changed

+4112
-717
lines changed

next.config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const nextConfig = {
33
experimental: {
44
appDir: true,
55
},
6-
}
6+
productionBrowserSourceMaps: true,
7+
};
78

8-
module.exports = nextConfig
9+
module.exports = nextConfig;

package-lock.json

Lines changed: 3444 additions & 533 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
"postbuild": "next-sitemap"
1111
},
1212
"dependencies": {
13+
"@emotion/react": "^11.10.5",
14+
"@emotion/styled": "^11.10.5",
1315
"@material-tailwind/react": "^1.2.5",
16+
"@mui/material": "^5.11.5",
1417
"@next/font": "13.1.2",
1518
"@supabase/supabase-js": "^2.4.0",
1619
"@uiw/codemirror-extensions-langs": "^4.19.6",
1720
"@uiw/codemirror-theme-github": "^4.19.6",
1821
"@uiw/codemirror-theme-material": "^4.19.6",
1922
"@uiw/react-codemirror": "^4.19.6",
23+
"antd": "^5.1.5",
2024
"encoding": "^0.1.13",
2125
"eslint": "8.31.0",
2226
"eslint-config-next": "13.1.2",
@@ -27,6 +31,10 @@
2731
"react-dom": "18.2.0",
2832
"react-html-parser": "^2.0.2",
2933
"react-icons": "^4.7.1",
34+
"react-markdown": "^8.0.5",
35+
"react-paginate": "^8.1.4",
36+
"remark-breaks": "^3.0.2",
37+
"remark-gfm": "^3.0.1",
3038
"tailwind-scrollbar": "^2.1.0"
3139
},
3240
"devDependencies": {

src/app/QuestionsList.jsx

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import Paginate from "@/components/Paginate2";
5+
import { SiPython } from "react-icons/si";
6+
import { BsLockFill } from "react-icons/bs";
7+
import Link from "next/link";
8+
9+
export default function QuestionsList({ questions }) {
10+
const [currentPage, setCurrentPage] = useState(1);
11+
const [questionsPerPage, setQuestionsPerPage] = useState(10);
12+
const startIndex = (currentPage - 1) * questionsPerPage;
13+
const endIndex = startIndex + questionsPerPage;
14+
const currentQuestions = questions.slice(startIndex, endIndex);
15+
16+
const handlePageChange = (page) => {
17+
setCurrentPage(page);
18+
};
19+
const handlePageSizeChange = (size) => {
20+
const changePageTo = Math.ceil((startIndex + 1) / size);
21+
setCurrentPage(changePageTo);
22+
setQuestionsPerPage(size);
23+
};
24+
25+
return (
26+
<div className="bg-inherit text-primary-800 dark:text-primary-100 min-w-full flex justify-center ">
27+
<div className="mx-auto max-w-screen">
28+
<div className="flex justify-center my-4">
29+
<Paginate
30+
totalItems={questions.length}
31+
currentPage={currentPage}
32+
itemsPerPage={questionsPerPage}
33+
handlePageChange={handlePageChange}
34+
handleItemsPerPageChange={handlePageSizeChange}
35+
itemLabels={"questions"}
36+
/>
37+
</div>
38+
39+
{/* Questions Table */}
40+
<table className="min-w-full">
41+
<thead className="border-b-2">
42+
<tr>
43+
<th className="p-3 text-sm font-semibold tracking-wide text-left">
44+
Number
45+
</th>
46+
<th className="p-3 text-sm font-semibold tracking-wide text-left">
47+
Name
48+
</th>
49+
<th className="p-3 text-sm font-semibold tracking-wide text-left">
50+
Difficulty
51+
</th>
52+
<th className="p-3 text-sm font-semibold tracking-wide text-left hidden sm:block">
53+
Topics
54+
</th>
55+
</tr>
56+
</thead>
57+
<tbody>
58+
{currentQuestions.map((question, index) => (
59+
<tr
60+
key={index}
61+
className="border-b-[1px] border-gray-500 border-opacity-60"
62+
>
63+
<td className="px-3 py-2 text-center">{question.QID}</td>
64+
<td className="px-3 py-2 text-sm font-semibold">
65+
<div className="flex items-center gap-2 hover:scale-105">
66+
<Link href={`/questions/${question.QID}`}>
67+
{question.title}
68+
</Link>{" "}
69+
{question.solutionAvailable && (
70+
<SiPython className="text-sm text-blue-900" />
71+
)}
72+
{question.paidOnly && (
73+
<BsLockFill className="text-sm text-yellow-800" />
74+
)}
75+
</div>
76+
</td>
77+
<td
78+
className={`px-3 py-2 text-sm ${
79+
question.difficulty === "Easy"
80+
? "text-difficulty-Easy"
81+
: question.difficulty === "Medium"
82+
? "text-difficulty-Medium"
83+
: "text-difficulty-Hard"
84+
}`}
85+
>
86+
{question.difficulty}
87+
</td>
88+
<td className="px-3 py-2 text-left font-thin hidden sm:block">
89+
{question.topicTags.join(", ")}
90+
</td>
91+
</tr>
92+
))}
93+
</tbody>
94+
</table>
95+
<div className="flex justify-center my-4">
96+
<Paginate
97+
totalItems={questions.length}
98+
currentPage={currentPage}
99+
itemsPerPage={questionsPerPage}
100+
handlePageChange={handlePageChange}
101+
handleItemsPerPageChange={handlePageSizeChange}
102+
itemLabels={"questions"}
103+
/>
104+
</div>
105+
</div>
106+
</div>
107+
);
108+
}

src/app/head.jsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
1+
import Script from "next/script";
2+
import * as gtag from "../lib/gtag";
3+
14
export default function Head() {
25
return (
36
<>
47
<title>ScuffedCode</title>
58
<meta content="width=device-width, initial-scale=1" name="viewport" />
6-
<meta name="description" content="Generated by create next app" />
9+
<meta name="description" content="My Leetcode journey" />
10+
<meta name="theme-color" content="#317EFB" />
711
<link rel="icon" href="/favicon.ico" />
8-
{/* <script
9-
async
10-
src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${process.env.NEXT_PUBLIC_GOOGLE_ADSENSE}`}
11-
crossOrigin="anonymous"
12-
></script> */}
12+
<link rel="apple-touch-icon" href="/favicon.ico" />
13+
<Script
14+
strategy="lazyOnload"
15+
src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}
16+
/>
17+
<Script
18+
id="gtag-init"
19+
strategy="lazyOnload"
20+
dangerouslySetInnerHTML={{
21+
__html: `
22+
window.dataLayer = window.dataLayer || [];
23+
function gtag(){dataLayer.push(arguments);}
24+
gtag('js', new Date());
25+
gtag('config', '${gtag.GA_TRACKING_ID}', {
26+
page_path: window.location.pathname,
27+
});
28+
`,
29+
}}
30+
/>
1331
</>
1432
);
1533
}

src/app/layout.jsx

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,14 @@
11
import "./globals.css";
22
import { Providers } from "@/components/Providers";
3-
import Script from "next/script";
4-
import * as gtag from "../lib/gtag";
5-
import Head from "./head";
63
import NavigationBar from "@/components/NavigationBar";
74

85
export default function RootLayout({ children }) {
96
return (
107
<html lang="en">
11-
<Script
12-
strategy="lazyOnload"
13-
src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}
14-
/>
15-
<Script
16-
id="gtag-init"
17-
strategy="lazyOnload"
18-
dangerouslySetInnerHTML={{
19-
__html: `
20-
window.dataLayer = window.dataLayer || [];
21-
function gtag(){dataLayer.push(arguments);}
22-
gtag('js', new Date());
23-
gtag('config', '${gtag.GA_TRACKING_ID}', {
24-
page_path: window.location.pathname,
25-
});
26-
`,
27-
}}
28-
/>
29-
{/* <Head /> */}
308
<body>
319
<Providers>
3210
<main className="dark:bg-primary-800 min-h-screen px-10 flex-col">
33-
<section title="Navigation Bar" className="mx-auto">
11+
<section title="Navigation Bar" className="flex flex-grow">
3412
<NavigationBar />
3513
</section>
3614
<section className="flex flex-grow">{children}</section>

src/app/page.jsx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
"use client";
2-
3-
import { BsSearch } from "react-icons/bs";
42
import { useEffect, useState } from "react";
5-
import QuestionsList from "@/components/QuestionsList";
63
import { getQuestionsList } from "@/utils/controllers";
7-
import { Input } from "@material-tailwind/react";
4+
import QuestionsList from "./QuestionsList";
5+
import { LoadingOutlined } from "@ant-design/icons";
6+
import { Spin } from "antd";
7+
import { BsSearch } from "react-icons/bs";
8+
9+
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
810

911
export default function Home() {
1012
const [searchTerm, setSearchTerm] = useState("");
1113
const [isLoading, setLoading] = useState(false);
14+
const [firstLoad, setFirstLoad] = useState(true);
1215
const [data, setData] = useState([]);
1316
useEffect(() => {
1417
setLoading(true);
@@ -19,32 +22,38 @@ export default function Home() {
1922
getData(searchTerm).then((data) => {
2023
setData(data);
2124
setLoading(false);
25+
setFirstLoad(false);
2226
});
2327
}, [searchTerm]);
2428

25-
return (
26-
<div className="min-w-full mx-auto">
27-
<div className="max-w-6xl mx-auto">
28-
<div>
29-
<h3 className="text-center text-2xl mb-3">Questions</h3>
30-
</div>
31-
<div className="flex items-center gap-2">
32-
<Input
33-
label="Search..."
34-
icon={<BsSearch />}
35-
onChange={(event) => setSearchTerm(event.target.value)}
36-
/>
37-
</div>
38-
{isLoading ? (
39-
<p className="text-center p-10">Loading...</p>
40-
) : !data ? (
41-
<p className="text-center p-10">
42-
No questions matching the current search...
43-
</p>
44-
) : (
45-
<QuestionsList questions={data} />
46-
)}
29+
return firstLoad ? (
30+
<div className="mx-auto max-w-[1080px] align-center text-center pt-10">
31+
<Spin indicator={antIcon} />
32+
</div>
33+
) : (
34+
<div className="mx-auto max-w-[1080px]">
35+
<div className="flex gap-4 items-center text-center justify-center w-full">
36+
<BsSearch className="flex-shrink" />
37+
<input
38+
label="Search Term"
39+
aria-label="Search for questions"
40+
aria-labelledby="Search for questions"
41+
value={searchTerm}
42+
onChange={(event) => setSearchTerm(event.target.value)}
43+
className="flex-grow bg-primary-300 dark:bg-primary-900 items-center p-1 rounded-lg"
44+
/>
4745
</div>
46+
{isLoading ? (
47+
<div className="align-center text-center pt-10">
48+
<Spin indicator={antIcon} />
49+
</div>
50+
) : !data ? (
51+
<p className="text-center p-10">
52+
No questions matching the current search...
53+
</p>
54+
) : (
55+
<QuestionsList questions={data} />
56+
)}
4857
</div>
4958
);
5059
}

src/app/page_old.jsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"use client";
2+
3+
import { BsSearch } from "react-icons/bs";
4+
import { useEffect, useState } from "react";
5+
import QuestionsList from "@/components/QuestionsList";
6+
import { getQuestionsList } from "@/utils/controllers";
7+
import { LoadingOutlined } from "@ant-design/icons";
8+
import { Spin } from "antd";
9+
import TextField from "@mui/material/TextField";
10+
import InputAdornment from "@mui/material/InputAdornment";
11+
12+
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
13+
14+
export default function Home() {
15+
const [searchTerm, setSearchTerm] = useState("");
16+
const [isLoading, setLoading] = useState(false);
17+
const [data, setData] = useState([]);
18+
useEffect(() => {
19+
setLoading(true);
20+
async function getData(term) {
21+
const { data } = await getQuestionsList(term);
22+
return data;
23+
}
24+
getData(searchTerm).then((data) => {
25+
setData(data);
26+
setLoading(false);
27+
});
28+
}, [searchTerm]);
29+
30+
return (
31+
<div className="min-w-full mx-auto">
32+
<div className="max-w-6xl mx-auto">
33+
<div className="text-center text-2xl mb-3">Questions</div>
34+
<div className="flex width-full items-baseline gap-4 text-primary-800 dark:text-primary-100">
35+
<TextField
36+
id="input-with-sx"
37+
label="Search..."
38+
variant="filled"
39+
className="flex-grow text-white [&>div>input]:text-primary-800 dark:[&>div>input]:text-primary-100 [&>label]:text-primary-800 dark:[&>label]:text-primary-100"
40+
onChange={(event) => setSearchTerm(event.target.value)}
41+
aria-describedby="Search..."
42+
inputProps={{
43+
"aria-label": "Search",
44+
}}
45+
InputProps={{
46+
startAdornment: (
47+
<InputAdornment position="start">
48+
<BsSearch className="text-primary-800 dark:text-primary-100" />
49+
</InputAdornment>
50+
),
51+
}}
52+
/>
53+
</div>
54+
{isLoading ? (
55+
<div className="align-center text-center pt-10">
56+
<Spin indicator={antIcon} />
57+
</div>
58+
) : !data ? (
59+
<p className="text-center p-10">
60+
No questions matching the current search...
61+
</p>
62+
) : (
63+
<QuestionsList questions={data} />
64+
)}
65+
</div>
66+
</div>
67+
);
68+
}

src/app/questions/[qid]/head.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ export default function Head({ params }) {
22
return (
33
<>
44
<title>{`ScuffedCode | Question ${params.qid}`}</title>
5+
<meta
6+
name="description"
7+
content={`Page containing the solution to Leetcode questions ${params.qid}`}
8+
/>
59
<meta content="width=device-width, initial-scale=1" name="viewport" />
6-
<meta name="description" content="Generated by create next app" />
7-
<link rel="icon" href="/favicon.ico" />
810
</>
911
);
1012
}

0 commit comments

Comments
 (0)