Skip to content

Commit 0fd2438

Browse files
committed
Added interactable terminal and fixed "/" href on the logo
1 parent 858c27c commit 0fd2438

File tree

4 files changed

+112
-12
lines changed

4 files changed

+112
-12
lines changed

frontend/package-lock.json

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/components/Navbar.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Image from 'next/image';
22
import Link from 'next/link';
33
import { useEffect, useState } from 'react';
44
import Hamburger from './Hamburger';
5+
import Terminal from './Terminal';
56

67
const Navbar = () => {
78
const [path, setPath] = useState<string[]>([]);
@@ -13,22 +14,25 @@ const Navbar = () => {
1314

1415
return (
1516
<nav className="flex justify-between items-center relative z-10">
16-
<Link href="/">
17-
<Image
18-
src="/assets/csesoc_logo.svg"
19-
alt="CSESoc Logo"
20-
width={200}
21-
height={200}
22-
draggable={false}
23-
/>
17+
<div>
18+
<Link href="/">
19+
<Image
20+
src="/assets/csesoc_logo.svg"
21+
alt="CSESoc Logo"
22+
width={200}
23+
height={200}
24+
draggable={false}
25+
/>
26+
</Link>
2427
<p className="font-mono mt-3 font-bold">
2528
<span className="text-green-500">csesoc@unsw</span>
2629
<span>:</span>
2730
<span className="text-blue-500">~{path.map(segment => '/' + segment.toLowerCase())}</span>
2831
<span>$ </span>
29-
<span id="cursor" className="text-gray-400 inline-block animate-blink">_</span>
32+
{/* The interactive terminal that allows changing pages using 'cd' */}
33+
<Terminal/>
3034
</p>
31-
</Link>
35+
</div>
3236
<div>
3337
<div className="md:flex xl:gap-18 lg:gap-10 md:gap-5 text-right font-bold hidden">
3438
<Link href="/about">

frontend/src/components/Terminal.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { useRouter } from "next/router";
2+
import { useRef, useState } from "react";
3+
4+
const Terminal = () => {
5+
// Store the value of the input
6+
const [value, setValue] = useState("");
7+
8+
// Automatically select the end of the input as the custom
9+
// cursor only works at the end of the input.
10+
const inputRef: any = useRef(null);
11+
const setInputEnd = () => {
12+
if (inputRef.current) {
13+
const len = inputRef.current.value.length;
14+
inputRef.current.setSelectionRange(len, len);
15+
}
16+
}
17+
18+
// Keep track of if the input is focused
19+
const [inputFocused, setInputFocused] = useState(false);
20+
21+
// Using the router to change pages seamlessly
22+
const router = useRouter();
23+
const goToPage = (target: string) => {
24+
router.push(target);
25+
};
26+
27+
// Checking for "Enter" and if so, changing to
28+
// the inputted page
29+
const handleKey = (key: string) => {
30+
if (key !== "Enter") return;
31+
32+
if (value.toLowerCase() === "~"
33+
|| value.toLowerCase() === "cd"
34+
|| value.toLowerCase() === "cd ~"
35+
) {
36+
goToPage("/");
37+
} else if (value.toLowerCase() === "cd about"
38+
|| value.toLowerCase() === "cd about us"
39+
) {
40+
goToPage("/about");
41+
} else if (value.toLowerCase() === "cd events"
42+
|| value.toLowerCase() === "cd event"
43+
) {
44+
goToPage("/events");
45+
} else if (value.toLowerCase() === "cd resources"
46+
|| value.toLowerCase() === "cd resource"
47+
) {
48+
goToPage("/resources");
49+
} else if (value.toLowerCase() === "cd sponsors"
50+
|| value.toLowerCase() === "cd sponsor"
51+
) {
52+
goToPage("/sponsors");
53+
} else if (value.toLowerCase() === "cd contact"
54+
|| value.toLowerCase() === "cd contacts"
55+
|| value.toLowerCase() === "cd contact us"
56+
) {
57+
goToPage("/contact-us");
58+
}
59+
60+
clearInput()
61+
};
62+
63+
const clearInput = () => {
64+
setValue("");
65+
};
66+
67+
return (
68+
// Using relative + absolute to overlap the `input` and `span`
69+
<span className="relative">
70+
{/* The input */}
71+
<input type="text" id="input" value={value} ref={inputRef} maxLength={40}
72+
className="absolute text-blue-500 p-0 m-0 bg-transparent outline-none caret-transparent w-[50vw] z-10"
73+
onKeyDown={(e) => {
74+
handleKey(e.key)
75+
setInputEnd()
76+
}}
77+
onChange={(e) => setValue(e.target.value)}
78+
onFocus={() => setInputFocused(true)}
79+
onBlur={() => {
80+
clearInput()
81+
setInputFocused(false)
82+
}}
83+
></input>
84+
{/* The custom cursor */}
85+
<span className="absolute w-[60vw] p-0 m-0 z-0">
86+
{/* The invisable span that is the same length as the input */}
87+
<span
88+
className="invisible whitespace-pre pointer-events-none text-base"
89+
>{value}</span>
90+
{/* The custom cursor */}
91+
<span id="cursor" className={`text-${inputFocused ? "white" : "gray-500"} pointer-events-none inline-block animate-blink p-0 m-0`}>_</span>
92+
</span>
93+
</span>
94+
)
95+
}
96+
97+
export default Terminal

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)