Skip to content

Commit b2392a4

Browse files
Merge pull request #97 from Evolutionary-Algorithms-On-Click/evoc-v2-phase1
Evoc v2 phase1
2 parents 0969521 + fd4926e commit b2392a4

6 files changed

Lines changed: 149 additions & 23 deletions

File tree

app/components/ClientLayout.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
"use client";
22

3+
import { usePathname } from "next/navigation";
34
import Header from "./Header";
45

6+
const notebookPathRegex = /^\/create\/custom-ea\/[^/]+\/notebook\/[^/]+$/;
7+
58
export default function ClientLayout({ children }) {
9+
const pathname = usePathname();
10+
const isNotebookPage = notebookPathRegex.test(pathname);
11+
612
return (
713
<>
8-
<Header />
14+
{!isNotebookPage && <Header />}
915
{children}
1016
</>
1117
);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"use client";
2+
3+
import { usePathname, useRouter } from "next/navigation";
4+
import { useEffect, useState } from "react";
5+
import VideoAcademy from "../_components/VideoAcademy.js";
6+
import HelpDocsButton from "../_components/HelpDocsButton.js";
7+
8+
const notebookPathRegex = /^\/create\/custom-ea\/[^/]+\/notebook\/[^/]+$/;
9+
10+
export default function GlobalLayoutComponents() {
11+
const pathname = usePathname();
12+
const router = useRouter();
13+
const isNotebookPage = notebookPathRegex.test(pathname);
14+
15+
const [isLoggedIn, setIsLoggedIn] = useState(false);
16+
useEffect(() => {
17+
if (localStorage.getItem("id")) {
18+
setIsLoggedIn(true);
19+
}
20+
}, []);
21+
22+
const handleLogout = () => {
23+
localStorage.removeItem("id");
24+
localStorage.removeItem("email");
25+
localStorage.removeItem("jwt_token");
26+
// TODO: Check for cookies and clear them if necessary
27+
setIsLoggedIn(false);
28+
router.push("/");
29+
};
30+
31+
if (isNotebookPage) {
32+
return null;
33+
}
34+
35+
return (
36+
<>
37+
{isLoggedIn && (
38+
<div className="fixed bottom-4 left-4 z-[100] pointer-events-auto">
39+
<button
40+
onClick={handleLogout}
41+
className="bg-white/70 backdrop-blur-sm rounded-full p-3 shadow-lg hover:bg-white transition-all duration-200 text-red-500 hover:text-red-700"
42+
title="Logout"
43+
>
44+
<svg
45+
xmlns="http://www.w3.org/2000/svg"
46+
fill="none"
47+
viewBox="0 0 24 24"
48+
strokeWidth={1.5}
49+
stroke="currentColor"
50+
className="w-6 h-6"
51+
>
52+
<path
53+
strokeLinecap="round"
54+
strokeLinejoin="round"
55+
d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75"
56+
/>
57+
</svg>
58+
</button>
59+
</div>
60+
)}
61+
<VideoAcademy />
62+
<HelpDocsButton />
63+
</>
64+
);
65+
}

app/components/Header.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,18 @@
33
import Link from "next/link";
44
import Image from "next/image";
55
import { usePathname } from "next/navigation";
6-
import { useEffect, useState } from "react";
76

87
export default function Header() {
98
const pathname = usePathname();
109
const isHome = pathname === "/";
1110

12-
const [isLoggedIn, setIsLoggedIn] = useState(false);
13-
useEffect(() => {
14-
if (localStorage.getItem("id")) {
15-
setIsLoggedIn(true);
16-
}
17-
}, []);
18-
1911
return (
2012
<header className="fixed top-0 left-0 right-0 z-[100] flex justify-between items-center px-6 py-4 pointer-events-none">
2113
<div
2214
className={`transition-all duration-300 pointer-events-auto ${isHome ? "opacity-0 -translate-x-4" : "opacity-100 translate-x-0"}`}
2315
>
2416
<Link
25-
href={isLoggedIn ? "/create" : "/"}
17+
href={"/create"}
2618
className="flex items-center gap-2 group"
2719
>
2820
<div className="bg-foreground text-background p-1.5 rounded-lg rotate-[-4deg] group-hover:rotate-0 transition-transform duration-200">

app/create/custom-ea/[problemID]/notebook/[notebookID]/_components/NotebookLayout.js

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,58 @@
11
"use client";
22

33
import React from "react";
4+
import { useRouter } from "next/navigation";
5+
import Image from "next/image";
46

57
export default function NotebookLayout({ children }) {
8+
const router = useRouter();
9+
610
return (
711
<div className="w-full bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen font-[family-name:var(--font-geist-mono)]">
812
<div className="w-full py-4 px-4 border-b border-slate-200 bg-white/40 backdrop-blur-sm">
9-
<div className="max-w-full mx-auto flex items-start justify-between gap-4 relative">
10-
<div>
11-
<h1 className="text-xl font-bold text-slate-800">
12-
Notebook
13-
</h1>
14-
<p className="text-xs text-slate-500 mt-0.5">
15-
Interactive Python notebook
16-
</p>
13+
<div className="max-w-full mx-auto flex items-center justify-between gap-4 relative">
14+
<div className="flex items-center gap-4">
15+
<button
16+
onClick={() => router.back()}
17+
className="flex items-center gap-2 group text-sm font-medium text-slate-600 hover:text-slate-800 transition-colors duration-200"
18+
>
19+
<svg
20+
xmlns="http://www.w3.org/2000/svg"
21+
fill="none"
22+
viewBox="0 0 24 24"
23+
strokeWidth={1.5}
24+
stroke="currentColor"
25+
className="w-5 h-5"
26+
>
27+
<path
28+
strokeLinecap="round"
29+
strokeLinejoin="round"
30+
d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h17.25"
31+
/>
32+
</svg>
33+
Back
34+
</button>
35+
<div className="flex items-center gap-2">
36+
<div className="bg-foreground text-background p-1.5 rounded-lg rotate-[-4deg] group-hover:rotate-0 transition-transform duration-200">
37+
<Image
38+
src="/EvOCicon.png"
39+
alt="EvOC Icon"
40+
width={24}
41+
height={24}
42+
className="invert dark:invert-0"
43+
/>
44+
</div>
45+
<div>
46+
<h1 className="text-xl font-bold text-slate-800">
47+
Notebook
48+
</h1>
49+
<p className="text-xs text-slate-500 mt-0.5">
50+
Interactive Python notebook
51+
</p>
52+
</div>
53+
</div>
1754
</div>
18-
<div className="absolute right-0 top-0 p-1 px-2 bg-yellow-50 border border-yellow-200 text-yellow-800 text-xs rounded-md whitespace-nowrap">
55+
<div className="p-1 px-2 bg-yellow-50 border border-yellow-200 text-yellow-800 text-xs rounded-md whitespace-nowrap">
1956
Tip: Top Markdown cell sets title.
2057
</div>
2158
</div>

app/create/page.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,34 @@ export default function ChooseGpOrNotGp() {
121121
</div>
122122
</Link>
123123
</div>
124+
125+
<div className="text-center mt-12 mb-8">
126+
<h2 className="text-3xl font-bold text-gray-800 mb-4">
127+
Build Your Own
128+
</h2>
129+
<p className="text-md text-gray-600">
130+
Dive into advanced customization with a blank notebook.
131+
</p>
132+
</div>
133+
<div className="w-full max-w-2xl mx-auto">
134+
<Link
135+
href="/create/custom-ea"
136+
className="block w-full rounded-xl shadow-lg hover:shadow-xl transition-shadow duration-300"
137+
>
138+
<div className="bg-gradient-to-br from-teal-500 to-teal-700 text-white p-8 flex flex-col items-center justify-center rounded-xl overflow-hidden transform hover:-translate-y-1 transition-transform duration-300">
139+
<div className="text-6xl mb-4">🎨</div>
140+
<div className="font-bold text-2xl text-center">
141+
Custom Notebook Development
142+
</div>
143+
<div className="text-lg text-center mt-2 opacity-90">
144+
Start with a blank slate for advanced problem-solving
145+
</div>
146+
<div className="mt-4 px-6 py-3 bg-white text-teal-700 rounded-full font-semibold text-lg shadow-md hover:bg-gray-100 transition-colors duration-300">
147+
Create Custom Notebook →
148+
</div>
149+
</div>
150+
</Link>
151+
</div>
124152
</div>
125153
<footer className="flex justify-center space-x-4 p-4">
126154
<Link

app/layout.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import localFont from "next/font/local";
22
import "./globals.css";
33
import "./print.css";
44
import { PublicEnvScript } from "next-runtime-env";
5-
import VideoAcademy from "./_components/VideoAcademy";
5+
import GlobalLayoutComponents from "./components/GlobalLayoutComponents";
66
import ClientLayout from "./components/ClientLayout";
7-
import HelpDocsButton from "./_components/HelpDocsButton";
87

98
const geistSans = localFont({
109
src: "./fonts/GeistVF.woff",
@@ -56,9 +55,8 @@ export default function RootLayout({ children }) {
5655
<body
5756
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
5857
>
59-
<VideoAcademy />
58+
<GlobalLayoutComponents />
6059
{children}
61-
<HelpDocsButton />
6260
<ClientLayout />
6361
</body>
6462
</html>

0 commit comments

Comments
 (0)