diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 789f0f2..af3ff22 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -12,6 +12,7 @@
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "gsap": "^3.13.0",
"lucide-react": "^0.511.0",
"matter-js": "^0.20.0",
"next": "15.3.3",
diff --git a/frontend/package.json b/frontend/package.json
index f03717a..47ef107 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -13,6 +13,7 @@
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "gsap": "^3.13.0",
"lucide-react": "^0.511.0",
"matter-js": "^0.20.0",
"next": "15.3.3",
diff --git a/frontend/src/app/blog/[slug]/page.tsx b/frontend/src/app/blog/[slug]/page.tsx
new file mode 100644
index 0000000..fdae6ae
--- /dev/null
+++ b/frontend/src/app/blog/[slug]/page.tsx
@@ -0,0 +1,24 @@
+import { GetStaticPaths, GetStaticProps } from "next";
+import { getMarkdownContent } from "@/lib/markdown";
+
+export default async function BlogPost() {
+ const content = await getMarkdownContent(`docker_primer.md`);
+
+ return (
+
+
+
+ );
+}
+
+// export const getStaticPaths: GetStaticPaths = async () => {
+// // Here you would fetch the list of markdown files to create paths
+// const paths = [{ params: { slug: "example" } }]; // Example path
+// return { paths, fallback: false };
+// };
+//
+// export const getStaticProps: GetStaticProps = async ({ params }) => {
+// console.log(params?.slug);
+// const content = await getMarkdownContent(`docker_primer.md`);
+// return { props: { content } };
+// };
diff --git a/frontend/src/app/blog/content/docker_primer.md b/frontend/src/app/blog/content/docker_primer.md
new file mode 100644
index 0000000..d3910ba
--- /dev/null
+++ b/frontend/src/app/blog/content/docker_primer.md
@@ -0,0 +1,178 @@
+---
+title: Docker Primer
+date: 2018-02-13T13:56:12-05:00
+tags: ["docker", "containers"]
+type: Docker
+summary: Docker basics to get you started
+---
+
+When we think of virtualization today, we may think of Virtual Box, which abstracts away the system processes, and lets you run a completely system from another. Think of Docker as Virtual Box, but extremely lightweight (in terms of resource consumption). Obviously I'm over simplifying the explanation a little, and a whole of things are getting lost in simplification. But for now, this will do.
+
+## Installation
+
+- Install docker
+
+```shell
+apt remove docker docker-engine docker.io
+apt update && apt -y upgrade
+apt install -y linux-image-extra-$(uname -r) linux-image-extra-virtual #FOR UBUNTU 18: apt install -y linux-image-$(uname -r) linux-image-extra-virtual
+apt update && apt -y upgrade
+apt install -y apt-transport-https ca-certificates curl software-properties-common
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
+add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #FOR UBUNTU 18: instead of stable use edge (just for now, since they haven't released the stable version on 18.04 yet)
+apt update && apt -y upgrade
+apt install -y docker-ce
+```
+
+- Install docker-compose
+
+```shell
+curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose #use the latest docker-compose version, by looking at releases on github pages [https://github.com/docker/compose/releases]https://gist.githubusercontent.com/mamigot/1abdefc684f97d3476f177d85248ff36/raw/5f57b4918b237f8e0127b45984fa51a483218349/docker-compose.yml
+chmod +x /usr/local/bin/docker-compose
+```
+
+## Post Installation stuff
+
+Allow docker usage without sudo access
+
+The docker daemon binds to a Unix socket instead of a TCP port. By
+default that Unix socket is owned by the user root and other users can
+only access it using sudo. The docker daemon always runs as the root
+user. To prevent using sudo when you use the docker command, create a
+Unix group called docker and add users to it. When the docker daemon
+starts, it makes the ownership of the Unix socket read/writable by the
+docker group
+
+```shell
+sudo groupadd docker
+sudo usermod -aG docker $USER
+newgrp docker
+```
+
+## Terminology
+
+- Images
+
+Images are read only We upload images to hub. Think of them as classes in an object oriented programming language terminology.
+
+- Containers
+
+Containers boot up from images. Think of them as instances of a class.
+
+- Tags
+
+You can think of this as versions
+
+- Container ID or Image ID
+
+Unique ID assigned to every container or image respectively
+
+## Usage
+
+- A `Dockerfile` can be used to build docker images
+
+- To list all images available on your system
+
+```shell
+docker images
+```
+
+- To list all containers
+
+```shell
+docker ps -a
+```
+
+- To pull images from the docker hub, for example for pulling the
+ ubuntu image
+
+```shell
+docker pull ubuntu
+```
+
+By default the `latest` `tag` is pulled. Consider `tag` to be sort of like the version of the image you want.
+
+- To pull a specific tag, lets say the `tag` is `12.04`
+
+```shell
+docker pull ubuntu:12.04
+```
+
+- To delete an image
+
+```shell
+docker rmi ubuntu:latest
+```
+
+or
+
+```shell
+docker rmi IMAGE_ID
+```
+
+- To create a `container` from an `image` and run it
+
+```shell
+docker run -it ID /bin/bash
+```
+
+- `i` stands for interactive
+- `t` stands for pseudo tty. It is for specifying the path to the shell to be run.
+- `ID` can be an `IMAGE-ID` or a `CONTAINER-ID` obtained by listing all images, or containers respectively.
+
+Note: Every time you use `docker run` using the IMAGE-ID, a new
+container is created based on the `image`
+
+Extra bits: If the argument `--rm` is if passed, causes the container to automatically get deleted after exiting the shell.
+
+- To exit a container
+
+```shell
+exit
+```
+
+- To start a container
+
+```shell
+docker start CONTAINER_ID
+```
+
+- To stop a container
+
+```shell
+docker stop CONTAINER_ID
+```
+
+- To delete a container
+
+```shell
+docker rm CONTAINER_ID
+```
+
+- To build your own docker image using a `Dockerfile`. Create a `Dockerfile` and put it in a folder, and execute the following command
+
+```shell
+docker build -t username/image_name:image_tag .
+```
+
+`username` - as on hub.docker.com
+`image_name` - the name of the image you want to build
+`image_tag` - the tag you want to assign to the image
+
+- To delete dangling images (unused images present on your system)
+
+```shell
+docker rmi $(docker images -f dangling=true -q)
+```
+
+- Save an existing docker container as an image
+
+```shell
+docker commit CONTAINER_ID IMAGE_NAME:IMAGE_TAG
+```
+
+- Saving an image as a tar file
+
+```shell
+docker save IMAGE_ID -o file_name.tar
+```
diff --git a/frontend/src/app/blog/page.tsx b/frontend/src/app/blog/page.tsx
index f71b5fa..0985da0 100644
--- a/frontend/src/app/blog/page.tsx
+++ b/frontend/src/app/blog/page.tsx
@@ -1,7 +1,8 @@
export default function Blog() {
return (
- This is blog list page
+ This is blogs index page
);
}
+
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index 5301dfc..a3942eb 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -4,6 +4,7 @@ import { Geist, Geist_Mono, Space_Grotesk, Space_Mono } from "next/font/google";
import "./globals.css";
import { NavigationMenu } from "@/components/Navbar";
+import GSAPCursor from "@/components/CustomCircleCursor";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -49,6 +50,7 @@ export default function RootLayout({
disableTransitionOnChange
>
+
{children}
diff --git a/frontend/src/components/CustomCircleCursor.tsx b/frontend/src/components/CustomCircleCursor.tsx
new file mode 100644
index 0000000..92ea1eb
--- /dev/null
+++ b/frontend/src/components/CustomCircleCursor.tsx
@@ -0,0 +1,45 @@
+"use client";
+import { useRef, useEffect, FC } from "react";
+import gsap from "gsap";
+
+const GSAPCursor: FC = () => {
+ const cursorRef = useRef
(null);
+
+ // For touch devices, return null
+ if (typeof window !== "undefined" && "ontouchstart" in window) return null;
+
+ useEffect(() => {
+ // Initialize GSAP animation
+ let xTo = gsap.quickTo(cursorRef.current, "x", {
+ duration: 2,
+ ease: "power2.out",
+ });
+ let yTo = gsap.quickTo(cursorRef.current, "y", {
+ duration: 2,
+ ease: "power2.out",
+ });
+
+ const onMouseMove = (e: MouseEvent) => {
+ xTo(e.clientX);
+ yTo(e.clientY);
+ };
+
+ window.addEventListener("mousemove", onMouseMove);
+
+ return () => {
+ window.removeEventListener("mousemove", onMouseMove);
+ };
+ }, []);
+
+ return (
+
+ );
+};
+
+export default GSAPCursor;
diff --git a/frontend/src/components/NameComponent.tsx b/frontend/src/components/NameComponent.tsx
index 37d266d..faf7848 100644
--- a/frontend/src/components/NameComponent.tsx
+++ b/frontend/src/components/NameComponent.tsx
@@ -4,7 +4,7 @@ export function NameComponent() {
return (
);
}
diff --git a/frontend/src/components/TextScramble.tsx b/frontend/src/components/TextScramble.tsx
index 410e2a3..5c4f100 100644
--- a/frontend/src/components/TextScramble.tsx
+++ b/frontend/src/components/TextScramble.tsx
@@ -1,6 +1,7 @@
"use client";
import { useState, useEffect, useCallback } from "react";
+import { useIsMobile } from "@/hooks/useIsMobile"; // Adjust the path as necessary
interface TextScrambleProps {
firstName: string;
@@ -22,7 +23,7 @@ const TextScramble: React.FC = ({
const chars = "!<>-_\\/[]{}—=+*^?#________";
const scramble = useCallback(
- (fromText: string, toText: string, setFunctiono) => {
+ (fromText: string, toText: string, setFunction: Function) => {
let counter = 0;
const length = Math.max(fromText.length, toText.length);
const queue = [];
@@ -56,7 +57,7 @@ const TextScramble: React.FC = ({
if (counter >= end) complete++;
}
- setFunctiono(output);
+ setFunction(output);
if (complete < length) {
requestAnimationFrame(update);
counter++;
@@ -78,6 +79,26 @@ const TextScramble: React.FC = ({
}
}, [isHovering, scramble, firstName, lastName]);
+ const autoScramble = () => {
+ console.log(displayFirstName, firstName);
+ if (displayFirstName == firstName) {
+ scramble(firstName, onlineHandleFirstName, setfirstNameText);
+ scramble(lastName, onlineHandleLastName, setLastNameText);
+ } else {
+ scramble(displayFirstName, firstName, setfirstNameText);
+ scramble(displayLastNameText, lastName, setLastNameText);
+ }
+ };
+
+ const isMobile = useIsMobile();
+
+ useEffect(() => {
+ if (isMobile) {
+ const intervalID = setInterval(autoScramble, 2000);
+ return () => clearInterval(intervalID);
+ }
+ }, [isMobile, displayFirstName, displayLastNameText]);
+
return (
{
+ const [isMobile, setIsMobile] = useState(false);
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth < 640); // Tailwind's mobile breakpoint
+ };
+
+ handleResize(); // Check on mount
+ window.addEventListener("resize", handleResize);
+
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ return isMobile;
+};
diff --git a/frontend/src/lib/markdown.ts b/frontend/src/lib/markdown.ts
new file mode 100644
index 0000000..d4ea7ea
--- /dev/null
+++ b/frontend/src/lib/markdown.ts
@@ -0,0 +1,16 @@
+// utils/markdown.ts
+import fs from "fs";
+import path from "path";
+import { remark } from "remark";
+import html from "remark-html";
+
+const markdownDirectory = path.join(process.cwd(), "src/app/blog/content");
+console.log(markdownDirectory)
+
+export async function getMarkdownContent(fileName: string) {
+ const filePath = path.join(markdownDirectory, fileName);
+ const fileContents = fs.readFileSync(filePath, "utf8");
+
+ const processedContent = await remark().use(html).process(fileContents);
+ return processedContent.toString();
+}