|  | 
|  | 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 = useRef<HTMLInputElement>(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 | +      || value.toLowerCase() === "cd .." | 
|  | 36 | +    ) { | 
|  | 37 | +      goToPage("/"); | 
|  | 38 | +    } else if (value.toLowerCase() === "cd about" | 
|  | 39 | +      || value.toLowerCase() === "cd about us" | 
|  | 40 | +      || value.toLowerCase() === "cd about_us" | 
|  | 41 | +    ) { | 
|  | 42 | +      goToPage("/about"); | 
|  | 43 | +    } else if (value.toLowerCase() === "cd events" | 
|  | 44 | +      || value.toLowerCase() === "cd event" | 
|  | 45 | +    ) { | 
|  | 46 | +      goToPage("/events"); | 
|  | 47 | +    } else if (value.toLowerCase() === "cd resources" | 
|  | 48 | +      || value.toLowerCase() === "cd resource" | 
|  | 49 | +    ) { | 
|  | 50 | +      goToPage("/resources"); | 
|  | 51 | +    } else if (value.toLowerCase() === "cd sponsors" | 
|  | 52 | +      || value.toLowerCase() === "cd sponsor" | 
|  | 53 | +    ) { | 
|  | 54 | +      goToPage("/sponsors"); | 
|  | 55 | +    } else if (value.toLowerCase() === "cd contact" | 
|  | 56 | +      || value.toLowerCase() === "cd contacts" | 
|  | 57 | +      || value.toLowerCase() === "cd contact us" | 
|  | 58 | +      || value.toLowerCase() === "cd contact_us" | 
|  | 59 | +    ) { | 
|  | 60 | +      goToPage("/contact-us"); | 
|  | 61 | +    } | 
|  | 62 | + | 
|  | 63 | +    clearInput() | 
|  | 64 | +  }; | 
|  | 65 | + | 
|  | 66 | +  const clearInput = () => { | 
|  | 67 | +    setValue(""); | 
|  | 68 | +  }; | 
|  | 69 | + | 
|  | 70 | +  return ( | 
|  | 71 | +    // Using relative + absolute to overlap the `input` and `span` | 
|  | 72 | +    <span className="relative"> | 
|  | 73 | +      {/* The input */} | 
|  | 74 | +      <input type="text" id="input" value={value} ref={inputRef} maxLength={40} | 
|  | 75 | +        className="absolute text-blue-500 p-0 m-0 bg-transparent outline-none caret-transparent w-[50vw] z-10" | 
|  | 76 | +        onKeyDown={(e) => { | 
|  | 77 | +          handleKey(e.key) | 
|  | 78 | +          setInputEnd() | 
|  | 79 | +        }} | 
|  | 80 | +        onChange={(e) => setValue(e.target.value)} | 
|  | 81 | +        onFocus={() => setInputFocused(true)} | 
|  | 82 | +        onBlur={() => { | 
|  | 83 | +          clearInput() | 
|  | 84 | +          setInputFocused(false) | 
|  | 85 | +        }} | 
|  | 86 | +      ></input> | 
|  | 87 | +      {/* The custom cursor */} | 
|  | 88 | +      <span className="absolute w-[60vw] p-0 m-0 z-0"> | 
|  | 89 | +        {/* The invisable span that is the same length as the input */} | 
|  | 90 | +        <span | 
|  | 91 | +          className="invisible whitespace-pre pointer-events-none text-base" | 
|  | 92 | +        >{value}</span> | 
|  | 93 | +        {/* The custom cursor */} | 
|  | 94 | +        <span id="cursor" className={`text-${inputFocused ? "white" : "gray-500"} pointer-events-none inline-block animate-blink p-0 m-0`}>_</span> | 
|  | 95 | +      </span> | 
|  | 96 | +    </span> | 
|  | 97 | +  ) | 
|  | 98 | +} | 
|  | 99 | + | 
|  | 100 | +export default Terminal | 
0 commit comments