From 1b4e893bfa9e8fe802e5bc905f304bf633db41f5 Mon Sep 17 00:00:00 2001 From: Rainnny7 Date: Thu, 29 Aug 2024 17:05:41 -0400 Subject: [PATCH] Improve mobile responsiveness --- .prettierrc | 4 + README.md | 4 +- bun.lockb | Bin 163513 -> 173913 bytes package.json | 1 + src/app/(pages)/layout.tsx | 36 +-- src/app/(pages)/page.tsx | 24 +- src/app/globals.css | 119 ++++---- src/components/landing/greeting.tsx | 100 +++---- .../landing/nav-content/homelab.tsx | 54 ++-- .../landing/nav-content/my-work.tsx | 201 +++++++------- src/components/landing/nav-content/skills.tsx | 254 +++++++++--------- src/components/landing/navbar.tsx | 177 ++++++------ src/components/landing/navigation.tsx | 114 ++++---- src/components/landing/theme-switcher.tsx | 52 ++-- src/components/theme-provider.tsx | 2 +- src/components/ui/button.tsx | 95 +++---- src/components/ui/flip-words.tsx | 184 +++++++------ src/components/ui/magic-card.tsx | 90 +++---- src/components/ui/navigation-menu.tsx | 164 +++++------ src/components/ui/simple-tooltip.tsx | 44 +-- src/components/ui/tooltip.tsx | 42 +-- src/lib/utils.ts | 6 +- tailwind.config.ts | 151 ++++++----- 23 files changed, 980 insertions(+), 938 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..2ef2d71 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "trailingComma": "es5", + "tabWidth": 4 +} \ No newline at end of file diff --git a/README.md b/README.md index 81d71e2..5477ed8 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,6 @@ My personal portfolio website hosted [here](https://rainnny.club) ## TODO -- [ ] Mobile Responsiveness +- [x] Mobile Responsiveness - [ ] Discord Integration (Status, Activity, etc) -- [ ] Add Configuration +- [ ] Add Configuration \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index e8be417d312640350f8370a6ef278da806d2e250..37b44464f8be1044216c1a99ae52ea7af89d66b3 100644 GIT binary patch delta 33023 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 wN>!V@zFuWxNstVB(R diff --git a/package.json b/package.json index 24195fe..68feea8 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "next-themes": "^0.3.0", "react": "^18", "react-dom": "^18", + "sharp": "^0.33.5", "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7" }, diff --git a/src/app/(pages)/layout.tsx b/src/app/(pages)/layout.tsx index f9255c4..f542699 100644 --- a/src/app/(pages)/layout.tsx +++ b/src/app/(pages)/layout.tsx @@ -11,33 +11,33 @@ const inter = Inter({ subsets: ["latin"] }); * The metadata for this app. */ export const metadata: Metadata = { - title: "RainnnyCLUB", - description: - "My name is Braydon and I am a self-taught software engineer living in Canada.", + title: "RainnnyCLUB", + description: + "My name is Braydon and I am a self-taught software engineer living in Canada.", }; export const viewport: Viewport = { - themeColor: "#5555FF", + themeColor: "#5555FF", }; /** * The primary layout for this app. */ const RootLayout = ({ - children, + children, }: Readonly<{ - children: React.ReactNode; + children: React.ReactNode; }>): ReactElement => ( - - - - {children} - - - + + + + {children} + + + ); export default RootLayout; diff --git a/src/app/(pages)/page.tsx b/src/app/(pages)/page.tsx index b327b78..0134554 100644 --- a/src/app/(pages)/page.tsx +++ b/src/app/(pages)/page.tsx @@ -3,17 +3,17 @@ import Navbar from "@/components/landing/navbar"; import { ReactElement } from "react"; const LandingPage = (): ReactElement => ( -
- -
- -
-
+
+ +
+ +
+
); export default LandingPage; diff --git a/src/app/globals.css b/src/app/globals.css index a36413a..ebac54f 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,69 +3,70 @@ @tailwind utilities; @layer base { - :root { - --background: 0 0% 100%; - --foreground: 240 10% 3.9%; - --card: 0 0% 100%; - --card-foreground: 240 10% 3.9%; - --popover: 0 0% 100%; - --popover-foreground: 240 10% 3.9%; - --primary: 240 5.9% 10%; - --primary-foreground: 0 0% 98%; - --secondary: 240 4.8% 95.9%; - --secondary-foreground: 240 5.9% 10%; - --muted: 240 4.8% 95.9%; - --muted-foreground: 240 3.8% 46.1%; - --accent: 240 4.8% 95.9%; - --accent-foreground: 240 5.9% 10%; - --destructive: 0 72.22% 50.59%; - --destructive-foreground: 0 0% 98%; - --border: 240 5.9% 90%; - --input: 240 5.9% 90%; - --ring: 240 5% 64.9%; - --radius: 0.5rem; + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 72.22% 50.59%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 5% 64.9%; + --radius: 0.5rem; - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - } + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } - .dark { - --background: 0 0% 0%; - --foreground: 0 0% 98%; - --card: 240 10% 3.9%; - --card-foreground: 0 0% 98%; - --popover: 240 10% 3.9%; - --popover-foreground: 0 0% 98%; - --primary: 0 0% 98%; - --primary-foreground: 240 5.9% 10%; - --secondary: 240 3.7% 15.9%; - --secondary-foreground: 0 0% 98%; - --muted: 240 3.7% 15.9%; - --muted-foreground: 240 5% 64.9%; - --accent: 240 3.7% 15.9%; - --accent-foreground: 0 0% 98%; - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 85.7% 97.3%; - --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; - --ring: 240 4.9% 83.9%; + .dark { + --background: 0 0% 0%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 85.7% 97.3%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - } + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } } @layer base { - * { - @apply border-border; - } - body { - @apply bg-background text-foreground; - } + * { + @apply border-border; + } + + body { + @apply bg-background text-foreground; + } } diff --git a/src/components/landing/greeting.tsx b/src/components/landing/greeting.tsx index 4ec0381..9ed7e94 100644 --- a/src/components/landing/greeting.tsx +++ b/src/components/landing/greeting.tsx @@ -9,59 +9,59 @@ import { FlipWords } from "@/components/ui/flip-words"; import Navigation from "./navigation"; const Greeting = (): ReactElement => { - const now: Moment = moment(Date.now()); - return ( -
- - My Selfie (: - + const now: Moment = moment(Date.now()); + return ( +
+ + My Selfie (: + - -

- Hello, I'm - - Braydon - - - Waving Hand - -

-
+ +

+ Hello, I'm + + Braydon + + + Waving Hand + +

+
- - + - + ]} + /> + - - - -
- ); + + + +
+ ); }; export default Greeting; diff --git a/src/components/landing/nav-content/homelab.tsx b/src/components/landing/nav-content/homelab.tsx index 5256989..9a3eb80 100644 --- a/src/components/landing/nav-content/homelab.tsx +++ b/src/components/landing/nav-content/homelab.tsx @@ -1,32 +1,32 @@ import { ReactElement } from "react"; const HomelabContent = (): ReactElement => ( -
    -
  • - Server Rack: 22U, 32" Depth -
  • -
  • - Router: UDM Pro -
  • -
  • - UPS: 1350VA -
  • -
  • -
  • - Proxmox Node-01: -
  • - - Motherboard: Prime B550-PLUS -
  • -
  • - - CPU: Ryzen 5 5600G -
  • -
  • - - RAM: 38GB of DDR4 @ 3200Mhz -
  • -
  • - - Storage: 8TB (x2 4TB, x1 4TB Parity) Unraid Array -
  • - -
+
    +
  • + Server Rack: 22U, 32" Depth +
  • +
  • + Router: UDM Pro +
  • +
  • + UPS: 1350VA +
  • +
  • +
  • + Proxmox Node-01: +
  • + - Motherboard: Prime B550-PLUS +
  • +
  • + - CPU: Ryzen 5 5600G +
  • +
  • + - RAM: 38GB of DDR4 @ 3200Mhz +
  • +
  • + - Storage: 8TB (x2 4TB, x1 4TB Parity) Unraid Array +
  • + +
); export default HomelabContent; diff --git a/src/components/landing/nav-content/my-work.tsx b/src/components/landing/nav-content/my-work.tsx index f12b9b5..b333550 100644 --- a/src/components/landing/nav-content/my-work.tsx +++ b/src/components/landing/nav-content/my-work.tsx @@ -1,7 +1,6 @@ "use client"; import { MagicCard } from "@/components/ui/magic-card"; -import { cn } from "@/lib/utils"; import moment, { Moment } from "moment"; import { useTheme } from "next-themes"; import { UseThemeProps } from "next-themes/dist/types"; @@ -9,102 +8,122 @@ import Link from "next/link"; import { ReactElement } from "react"; type Project = { - name: string; - link?: string | undefined; - previewContent: ReactElement; - startDate: Moment; - endDate?: Moment | undefined; + name: string; + link?: string | undefined; + previewContent: ReactElement; + startDate: Moment; + endDate?: Moment | undefined; }; const projects: Project[] = [ - { - name: "This Website!", - link: "https://github.com/Rainnny7/rainnny.club", - previewContent:
This website!
, - startDate: moment([2024, 7, 29]), - }, - { - name: "WildNetwork", - link: "https://discord.gg/WildPrison", - previewContent: ( -

- WildNetwork is a Minecraft server that contains multiple gamemodes, one - of which is Prison, which is the most popular. I first joined the server - as a Developer where I would work behind the scenes to create new - features, now I'm currently working as a System Administrator. -

- ), - startDate: moment([2020, 7, 1]), - }, - { - name: "Lucity", - link: "https://youtube.com/@iamLucid", - previewContent: ( -

- Lucity was a minigame network for the game Minecraft, and was owned by - the YouTuber iamLucid. When I worked at Lucity, I was the development - lead, I focused mainly on infrastructure, databases, and monitoring - systems. A few things that I have made - a dynamically managed server - system, proxy rotation via the TCPShield API, and an API that can - interact with the entire network from a normal Java app. -

- ), - startDate: moment([2020, 7, 1]), - endDate: moment([2022, 10, 30]), - }, - { - name: "Rainplex", - previewContent: ( -

- Rainplex was a remake of the once popular Minecraft server, Mineplex. - Rainplex initially came to light using the plugin, Skript where it just - contained a Hub. After some time, the entirety of the network was - re-coded in the Java programming from the ground up. Rainplex went - through numerous re-codes over the time it was active, however I have - since abandoned development due to lack of free time. -

- ), - startDate: moment([2018, 8, 1]), - endDate: moment([2021, 6, 11]), - }, - { - name: "Arcane Client", - link: "https://github.com/ArcaneClientNET", - previewContent: ( -

- Arcane is the all-in-one Minecraft mod pack. This client was built to be - similar to LunarClient for portfolio and experience sake. I have since - abandoned development due to lack of free time. -

- ), - startDate: moment([2021, 6, 1]), - endDate: moment([2021, 10, 1]), - }, + { + name: "This Website!", + link: "https://github.com/Rainnny7/rainnny.club", + previewContent:
This website!
, + startDate: moment([2024, 7, 29]), + }, + { + name: "WildNetwork", + link: "https://discord.gg/WildPrison", + previewContent: ( +

+ WildNetwork is a Minecraft server that contains multiple + gamemodes, one of which is Prison, which is the most popular. I + first joined the server as a Developer where I would work behind + the scenes to create new features, now I'm currently + working as a System Administrator. +

+ ), + startDate: moment([2020, 7, 1]), + }, + { + name: "Bonfire", + link: "https://bonfire.wtf", + previewContent: ( +

+ Bonfire is a platform similar to Discord that a friend and I are + working on together in our free time. Bonfire is perfect for + connecting with friends or building a global community. + Personalize your space to chat, and hang out. +

+ ), + startDate: moment([2024, 3, 30]), + }, + { + name: "Lucity", + link: "https://youtube.com/@iamLucid", + previewContent: ( +

+ Lucity was a minigame network for the game Minecraft, and was + owned by the YouTuber iamLucid. When I worked at Lucity, I was + the development lead, I focused mainly on infrastructure, + databases, and monitoring systems. A few things that I have made + - a dynamically managed server system, proxy rotation via the + TCPShield API, and an API that can interact with the entire + network from a normal Java app. +

+ ), + startDate: moment([2020, 7, 1]), + endDate: moment([2022, 10, 30]), + }, + { + name: "Rainplex", + previewContent: ( +

+ Rainplex was a remake of the once popular Minecraft server, + Mineplex. Rainplex initially came to light using the plugin, + Skript where it just contained a Hub. After some time, the + entirety of the network was re-coded in the Java programming + from the ground up. Rainplex went through numerous re-codes over + the time it was active, however I have since abandoned + development due to lack of free time. +

+ ), + startDate: moment([2018, 8, 1]), + endDate: moment([2021, 6, 11]), + }, + { + name: "Arcane Client", + link: "https://github.com/ArcaneClientNET", + previewContent: ( +

+ Arcane is the all-in-one Minecraft mod pack. This client was + built to be similar to LunarClient for portfolio and experience + sake. I have since abandoned development due to lack of free + time. +

+ ), + startDate: moment([2021, 6, 1]), + endDate: moment([2021, 10, 1]), + }, ]; const MyWork = (): ReactElement => { - const { theme }: UseThemeProps = useTheme(); - return ( -
- {projects.map((project, index) => ( - - -

- {project.name} -

+ const { theme }: UseThemeProps = useTheme(); + return ( +
+ {projects.map((project, index) => ( + + +

+ {project.name} +

- {/* Years Active */} -

- {project.startDate.format("MMM YYYY")} - {project.endDate && ` - ${project.endDate.format("MMM YYYY")}`} -

-
- - ))} -
- ); + {/* Years Active */} +

+ {project.startDate.format("MMM YYYY")} + {project.endDate && + ` - ${project.endDate.format("MMM YYYY")}`} +

+
+ + ))} +
+ ); }; export default MyWork; diff --git a/src/components/landing/nav-content/skills.tsx b/src/components/landing/nav-content/skills.tsx index 0aff409..99b9f86 100644 --- a/src/components/landing/nav-content/skills.tsx +++ b/src/components/landing/nav-content/skills.tsx @@ -1,145 +1,145 @@ import Image from "next/image"; import Link from "next/link"; import { ReactElement } from "react"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; import SimpleTooltip from "@/components/ui/simple-tooltip"; type Skill = { - name: string; - icon: string; - link: string; + name: string; + icon: string; + link: string; }; const skillset: Skill[] = [ - // Languages - { - name: "Java", - icon: "https://img.icons8.com/color/2x/java-coffee-cup-logo.png", - link: "https://www.java.com", - }, - { - name: "JavaScript", - icon: "https://img.icons8.com/fluent/2x/javascript.png", - link: "https://developer.mozilla.org/en-US/docs/Web/JavaScript", - }, - { - name: "CSS", - icon: "https://img.icons8.com/fluent/2x/css3.png", - link: "https://www.w3schools.com/css", - }, + // Languages + { + name: "Java", + icon: "https://img.icons8.com/color/2x/java-coffee-cup-logo.png", + link: "https://www.java.com", + }, + { + name: "JavaScript", + icon: "https://img.icons8.com/fluent/2x/javascript.png", + link: "https://developer.mozilla.org/en-US/docs/Web/JavaScript", + }, + { + name: "CSS", + icon: "https://img.icons8.com/fluent/2x/css3.png", + link: "https://www.w3schools.com/css", + }, - // Operating Systems - { - name: "Linux", - icon: "https://img.icons8.com/color/2x/linux.png", - link: "https://www.linux.org", - }, - { - name: "Bash", - icon: "https://img.icons8.com/color/2x/bash.png", - link: "https://www.gnu.org/software/bash", - }, + // Operating Systems + { + name: "Linux", + icon: "https://img.icons8.com/color/2x/linux.png", + link: "https://www.linux.org", + }, + { + name: "Bash", + icon: "https://img.icons8.com/color/2x/bash.png", + link: "https://www.gnu.org/software/bash", + }, - // Databases - { - name: "MariaDB", - icon: "https://img.icons8.com/fluent/2x/maria-db.png", - link: "https://mariadb.org", - }, - { - name: "MongoDB", - icon: "https://img.icons8.com/color/2x/mongodb.png", - link: "https://www.mongodb.com", - }, - { - name: "Redis", - icon: "https://img.icons8.com/color/2x/redis.png", - link: "https://redis.io", - }, + // Databases + { + name: "MariaDB", + icon: "https://img.icons8.com/fluent/2x/maria-db.png", + link: "https://mariadb.org", + }, + { + name: "MongoDB", + icon: "https://img.icons8.com/color/2x/mongodb.png", + link: "https://www.mongodb.com", + }, + { + name: "Redis", + icon: "https://img.icons8.com/color/2x/redis.png", + link: "https://redis.io", + }, - // Software - { - name: "Git", - icon: "https://img.icons8.com/color/2x/git.png", - link: "https://git-scm.com", - }, - { - name: "Docker", - icon: "https://img.icons8.com/fluent/2x/docker.png", - link: "https://www.docker.com", - }, - { - name: "Jenkins", - icon: "https://img.icons8.com/color/2x/jenkins.png", - link: "https://www.jenkins.io", - }, - { - name: "Figma", - icon: "https://img.icons8.com/fluent/2x/figma.png", - link: "https://www.figma.com", - }, - { - name: "Postman", - icon: "https://img.icons8.com/dusk/2x/postman-api.png", - link: "https://www.postman.com", - }, + // Software + { + name: "Git", + icon: "https://img.icons8.com/color/2x/git.png", + link: "https://git-scm.com", + }, + { + name: "Docker", + icon: "https://img.icons8.com/fluent/2x/docker.png", + link: "https://www.docker.com", + }, + { + name: "Jenkins", + icon: "https://img.icons8.com/color/2x/jenkins.png", + link: "https://www.jenkins.io", + }, + { + name: "Figma", + icon: "https://img.icons8.com/fluent/2x/figma.png", + link: "https://www.figma.com", + }, + { + name: "Postman", + icon: "https://img.icons8.com/dusk/2x/postman-api.png", + link: "https://www.postman.com", + }, - // Frameworks & Libraries - { - name: "Maven", - icon: "/maven.png", - link: "https://maven.apache.org", - }, - { - name: "NPM", - icon: "https://img.icons8.com/color/2x/npm.png", - link: "https://www.npmjs.com", - }, - { - name: "React", - icon: "https://img.icons8.com/dusk/2x/react.png", - link: "https://reactjs.org/", - }, - { - name: "NextJS", - icon: "https://img.icons8.com/color/2x/nextjs.png", - link: "https://nextjs.org/", - }, - { - name: "TailwindCSS", - icon: "https://img.icons8.com/color/2x/tailwindcss.png", - link: "https://tailwindcss.com", - }, - { - name: "Redux", - icon: "https://img.icons8.com/color/2x/redux.png", - link: "https://redux.js.org", - }, - { - name: "Nginx", - icon: "https://img.icons8.com/color/2x/nginx.png", - link: "https://www.nginx.com", - }, + // Frameworks & Libraries + { + name: "Maven", + icon: "/maven.png", + link: "https://maven.apache.org", + }, + { + name: "NPM", + icon: "https://img.icons8.com/color/2x/npm.png", + link: "https://www.npmjs.com", + }, + { + name: "React", + icon: "https://img.icons8.com/dusk/2x/react.png", + link: "https://reactjs.org/", + }, + { + name: "NextJS", + icon: "https://img.icons8.com/color/2x/nextjs.png", + link: "https://nextjs.org/", + }, + { + name: "TailwindCSS", + icon: "https://img.icons8.com/color/2x/tailwindcss.png", + link: "https://tailwindcss.com", + }, + { + name: "Redux", + icon: "https://img.icons8.com/color/2x/redux.png", + link: "https://redux.js.org", + }, + { + name: "Nginx", + icon: "https://img.icons8.com/color/2x/nginx.png", + link: "https://www.nginx.com", + }, ]; const Skills = (): ReactElement => ( -
- {skillset.map((skill, index) => ( - - - {`${skill.name} - - - ))} -
+
+ {skillset.map((skill, index) => ( + + + {`${skill.name} + + + ))} +
); export default Skills; diff --git a/src/components/landing/navbar.tsx b/src/components/landing/navbar.tsx index fa020b8..2abb658 100644 --- a/src/components/landing/navbar.tsx +++ b/src/components/landing/navbar.tsx @@ -2,114 +2,115 @@ import Image from "next/image"; import Link from "next/link"; import { ReactElement } from "react"; import { - NavigationMenu, - NavigationMenuContent, - NavigationMenuIndicator, - NavigationMenuItem, - NavigationMenuLink, - NavigationMenuList, - NavigationMenuTrigger, - NavigationMenuViewport, + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, + navigationMenuTriggerStyle, } from "@/components/ui/navigation-menu"; -import { navigationMenuTriggerStyle } from "@/components/ui/navigation-menu"; import { HeartIcon } from "@heroicons/react/24/solid"; import { cn } from "@/lib/utils"; import ThemeSwitcher from "./theme-switcher"; import { Button } from "@/components/ui/button"; -import { BookOpenIcon } from "@heroicons/react/24/outline"; -import { SignalIcon } from "@heroicons/react/24/outline"; +import { + BookOpenIcon, + CodeBracketIcon, + SignalIcon, +} from "@heroicons/react/24/outline"; import BlurFade from "@/components/ui/blur-fade"; -import { CodeBracketIcon } from "@heroicons/react/24/outline"; const Navbar = (): ReactElement => ( - - - + + + ); const Branding = (): ReactElement => ( - - My Selfie (: -

RainnnyCLUB

- + + My Selfie (: +

RainnnyCLUB

+ ); const Links = (): ReactElement => ( - - - {/* Useful Links */} - - Useful Links - - - - - - + + + {/* Useful Links */} + + Useful Links + + + + + + - {/* Donate */} - - - - Buy me a Coffee - - - - - - {/* Theme Switcher */} - - - - - + {/* Donate */} + + + + Buy me a Coffee + Donate + + + + + + ); const UsefulLinksContent = (): ReactElement => ( -
- {/* Git */} - - - +
+ {/* Git */} + + + - {/* Wiki */} - - - + {/* Wiki */} + + + - {/* Status Page */} - - - -
+ {/* Status Page */} + + + +
); export default Navbar; diff --git a/src/components/landing/navigation.tsx b/src/components/landing/navigation.tsx index c45c006..9d6f339 100644 --- a/src/components/landing/navigation.tsx +++ b/src/components/landing/navigation.tsx @@ -2,9 +2,11 @@ import { ReactElement, useState } from "react"; import { Button } from "@/components/ui/button"; -import { BriefcaseIcon } from "@heroicons/react/24/outline"; -import { WrenchIcon } from "@heroicons/react/24/outline"; -import { ServerStackIcon } from "@heroicons/react/24/outline"; +import { + BriefcaseIcon, + ServerStackIcon, + WrenchIcon, +} from "@heroicons/react/24/outline"; import { cn } from "@/lib/utils"; import BlurFade from "@/components/ui/blur-fade"; import HomelabContent from "./nav-content/homelab"; @@ -12,64 +14,66 @@ import Skills from "./nav-content/skills"; import MyWork from "./nav-content/my-work"; type Item = { - name: string; - icon: ReactElement; - content: ReactElement; + name: string; + icon: ReactElement; + content: ReactElement; }; const items: Item[] = [ - { - name: "My Work", - icon: , - content: , - }, - { - name: "Skills", - icon: , - content: , - }, - { - name: "Homelab", - icon: , - content: , - }, + { + name: "My Work", + icon: , + content: , + }, + { + name: "Skills", + icon: , + content: , + }, + { + name: "Homelab", + icon: , + content: , + }, ]; const Navigation = (): ReactElement => { - const [selected, setSelected] = useState(undefined); - return ( -
- {/* Selection Buttons */} -
- {items.map((item, index) => { - const active: boolean = selected === item; - return ( - - - - ); - })} -
+ const [selected, setSelected] = useState(undefined); + return ( +
+ {/* Selection Buttons */} +
+ {items.map((item, index) => { + const active: boolean = selected === item; + return ( + + + + ); + })} +
- {/* Selected Content */} - {selected && ( - -
{selected.content}
-
- )} -
- ); + {/* Selected Content */} + {selected && ( + +
{selected.content}
+
+ )} +
+ ); }; export default Navigation; diff --git a/src/components/landing/theme-switcher.tsx b/src/components/landing/theme-switcher.tsx index 73b626d..cfed50e 100644 --- a/src/components/landing/theme-switcher.tsx +++ b/src/components/landing/theme-switcher.tsx @@ -8,31 +8,31 @@ import { motion } from "framer-motion"; import { UseThemeProps } from "next-themes/dist/types"; const ThemeSwitcher = (): ReactElement => { - const { theme, setTheme }: UseThemeProps = useTheme(); - const isLight = theme === "light"; - return ( - - ); + const { theme, setTheme }: UseThemeProps = useTheme(); + const isLight = theme === "light"; + return ( + + ); }; export default ThemeSwitcher; diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx index c527cde..6b5fce1 100644 --- a/src/components/theme-provider.tsx +++ b/src/components/theme-provider.tsx @@ -5,5 +5,5 @@ import { ThemeProvider as NextThemesProvider } from "next-themes"; import { type ThemeProviderProps } from "next-themes/dist/types"; export function ThemeProvider({ children, ...props }: ThemeProviderProps) { - return {children}; + return {children}; } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 0ba4277..cd7d5b9 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -1,56 +1,57 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const buttonVariants = cva( - "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; } const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/src/components/ui/flip-words.tsx b/src/components/ui/flip-words.tsx index ec3fe0a..c974ebd 100644 --- a/src/components/ui/flip-words.tsx +++ b/src/components/ui/flip-words.tsx @@ -1,99 +1,107 @@ "use client"; -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { AnimatePresence, motion, LayoutGroup } from "framer-motion"; +import React, { useCallback, useEffect, useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; import { cn } from "@/lib/utils"; export const FlipWords = ({ - words, - duration = 3000, - className, + words, + duration = 3000, + className, }: { - words: string[]; - duration?: number; - className?: string; + words: string[]; + duration?: number; + className?: string; }) => { - const [currentWord, setCurrentWord] = useState(words[0]); - const [isAnimating, setIsAnimating] = useState(false); + const [currentWord, setCurrentWord] = useState(words[0]); + const [isAnimating, setIsAnimating] = useState(false); - // thanks for the fix Julian - https://github.com/Julian-AT - const startAnimation = useCallback(() => { - const word = words[words.indexOf(currentWord) + 1] || words[0]; - setCurrentWord(word); - setIsAnimating(true); - }, [currentWord, words]); + // thanks for the fix Julian - https://github.com/Julian-AT + const startAnimation = useCallback(() => { + const word = words[words.indexOf(currentWord) + 1] || words[0]; + setCurrentWord(word); + setIsAnimating(true); + }, [currentWord, words]); - useEffect(() => { - if (!isAnimating) - setTimeout(() => { - startAnimation(); - }, duration); - }, [isAnimating, duration, startAnimation]); + useEffect(() => { + if (!isAnimating) + setTimeout(() => { + startAnimation(); + }, duration); + }, [isAnimating, duration, startAnimation]); - return ( - { - setIsAnimating(false); - }} - > - - {/* edit suggested by Sajal: https://x.com/DewanganSajal */} - {currentWord.split(" ").map((word, wordIndex) => ( - - {word.split("").map((letter, letterIndex) => ( - - {letter} - - ))} -   - - ))} - - - ); + return ( + { + setIsAnimating(false); + }} + > + + {/* edit suggested by Sajal: https://x.com/DewanganSajal */} + {currentWord.split(" ").map((word, wordIndex) => ( + + {word.split("").map((letter, letterIndex) => ( + + {letter} + + ))} +   + + ))} + + + ); }; diff --git a/src/components/ui/magic-card.tsx b/src/components/ui/magic-card.tsx index 4177af6..1651c77 100644 --- a/src/components/ui/magic-card.tsx +++ b/src/components/ui/magic-card.tsx @@ -6,59 +6,59 @@ import { motion, useMotionTemplate, useMotionValue } from "framer-motion"; import { cn } from "@/lib/utils"; export interface MagicCardProps extends React.HTMLAttributes { - gradientSize?: number; - gradientColor?: string; - gradientOpacity?: number; + gradientSize?: number; + gradientColor?: string; + gradientOpacity?: number; } export function MagicCard({ - children, - className, - gradientSize = 200, - gradientColor = "#262626", - gradientOpacity = 0.8, + children, + className, + gradientSize = 200, + gradientColor = "#262626", + gradientOpacity = 0.8, }: MagicCardProps) { - const mouseX = useMotionValue(-gradientSize); - const mouseY = useMotionValue(-gradientSize); + const mouseX = useMotionValue(-gradientSize); + const mouseY = useMotionValue(-gradientSize); - const handleMouseMove = useCallback( - (e: React.MouseEvent) => { - const { left, top } = e.currentTarget.getBoundingClientRect(); - mouseX.set(e.clientX - left); - mouseY.set(e.clientY - top); - }, - [mouseX, mouseY], - ); + const handleMouseMove = useCallback( + (e: React.MouseEvent) => { + const { left, top } = e.currentTarget.getBoundingClientRect(); + mouseX.set(e.clientX - left); + mouseY.set(e.clientY - top); + }, + [mouseX, mouseY] + ); - const handleMouseLeave = useCallback(() => { - mouseX.set(-gradientSize); - mouseY.set(-gradientSize); - }, [mouseX, mouseY, gradientSize]); + const handleMouseLeave = useCallback(() => { + mouseX.set(-gradientSize); + mouseY.set(-gradientSize); + }, [mouseX, mouseY, gradientSize]); - useEffect(() => { - mouseX.set(-gradientSize); - mouseY.set(-gradientSize); - }, [mouseX, mouseY, gradientSize]); + useEffect(() => { + mouseX.set(-gradientSize); + mouseY.set(-gradientSize); + }, [mouseX, mouseY, gradientSize]); - return ( -
-
{children}
- +
{children}
+ -
- ); + opacity: gradientOpacity, + }} + /> + + ); } diff --git a/src/components/ui/navigation-menu.tsx b/src/components/ui/navigation-menu.tsx index ede85e0..7b792b6 100644 --- a/src/components/ui/navigation-menu.tsx +++ b/src/components/ui/navigation-menu.tsx @@ -6,123 +6,123 @@ import { ChevronDown } from "lucide-react"; import { cn } from "@/lib/utils"; const NavigationMenu = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - {children} - - + + {children} + + )); NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName; const NavigationMenuList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - + )); NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName; const NavigationMenuItem = NavigationMenuPrimitive.Item; const navigationMenuTriggerStyle = cva( - "group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium cursor-default transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50", + "group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium cursor-default transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50" ); const NavigationMenuTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - {children}{" "} - + + {children}{" "} + )); NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName; const NavigationMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - + )); NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName; const NavigationMenuLink = NavigationMenuPrimitive.Link; const NavigationMenuViewport = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( -
- -
+
+ +
)); NavigationMenuViewport.displayName = - NavigationMenuPrimitive.Viewport.displayName; + NavigationMenuPrimitive.Viewport.displayName; const NavigationMenuIndicator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -
- + +
+ )); NavigationMenuIndicator.displayName = - NavigationMenuPrimitive.Indicator.displayName; + NavigationMenuPrimitive.Indicator.displayName; export { - navigationMenuTriggerStyle, - NavigationMenu, - NavigationMenuList, - NavigationMenuItem, - NavigationMenuContent, - NavigationMenuTrigger, - NavigationMenuLink, - NavigationMenuIndicator, - NavigationMenuViewport, + navigationMenuTriggerStyle, + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, }; diff --git a/src/components/ui/simple-tooltip.tsx b/src/components/ui/simple-tooltip.tsx index ce2be2e..5e0b07b 100644 --- a/src/components/ui/simple-tooltip.tsx +++ b/src/components/ui/simple-tooltip.tsx @@ -1,8 +1,8 @@ import { ReactElement, ReactNode } from "react"; import { - Tooltip, - TooltipContent, - TooltipTrigger, + Tooltip, + TooltipContent, + TooltipTrigger, } from "@/components/ui/tooltip"; import { SIDE_OPTIONS } from "@radix-ui/react-popper"; @@ -10,20 +10,20 @@ import { SIDE_OPTIONS } from "@radix-ui/react-popper"; * The props for a simple tooltip. */ type SimpleTooltipProps = { - /** - * The content to display in the tooltip. - */ - content: string | ReactElement; + /** + * The content to display in the tooltip. + */ + content: string | ReactElement; - /** - * The side to display the tooltip on. - */ - side?: (typeof SIDE_OPTIONS)[number]; + /** + * The side to display the tooltip on. + */ + side?: (typeof SIDE_OPTIONS)[number]; - /** - * The children to render in this tooltip. - */ - children: ReactNode; + /** + * The children to render in this tooltip. + */ + children: ReactNode; }; /** @@ -33,13 +33,13 @@ type SimpleTooltipProps = { * @return the tooltip jsx */ const SimpleTooltip = ({ - content, - side, - children, + content, + side, + children, }: SimpleTooltipProps): ReactElement => ( - - {children} - {content} - + + {children} + {content} + ); export default SimpleTooltip; diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx index 30fc44d..0990b90 100644 --- a/src/components/ui/tooltip.tsx +++ b/src/components/ui/tooltip.tsx @@ -1,30 +1,30 @@ -"use client" +"use client"; -import * as React from "react" -import * as TooltipPrimitive from "@radix-ui/react-tooltip" +import * as React from "react"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; -const TooltipProvider = TooltipPrimitive.Provider +const TooltipProvider = TooltipPrimitive.Provider; -const Tooltip = TooltipPrimitive.Root +const Tooltip = TooltipPrimitive.Root; -const TooltipTrigger = TooltipPrimitive.Trigger +const TooltipTrigger = TooltipPrimitive.Trigger; const TooltipContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - -)) -TooltipContent.displayName = TooltipPrimitive.Content.displayName + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index d084cca..e644794 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,6 +1,6 @@ -import { type ClassValue, clsx } from "clsx" -import { twMerge } from "tailwind-merge" +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); } diff --git a/tailwind.config.ts b/tailwind.config.ts index 84287e8..e7d28ca 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,80 +1,83 @@ -import type { Config } from "tailwindcss" +import type {Config} from "tailwindcss" + +const defaultTheme = require('tailwindcss/defaultTheme') const config = { - darkMode: ["class"], - content: [ - './pages/**/*.{ts,tsx}', - './components/**/*.{ts,tsx}', - './app/**/*.{ts,tsx}', - './src/**/*.{ts,tsx}', - ], - prefix: "", - theme: { - container: { - center: true, - padding: "2rem", - screens: { - "2xl": "1400px", - }, + darkMode: ["class"], + content: [ + "./src/**/*.{ts,tsx}", + ], + prefix: "", + theme: { + screens: { + 'xs': '475px', + ...defaultTheme.screens, + }, + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: {height: "0"}, + to: {height: "var(--radix-accordion-content-height)"}, + }, + "accordion-up": { + from: {height: "var(--radix-accordion-content-height)"}, + to: {height: "0"}, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, }, - extend: { - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", - }, - keyframes: { - "accordion-down": { - from: { height: "0" }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: "0" }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, - }, - }, - plugins: [require("tailwindcss-animate")], + plugins: [require("tailwindcss-animate")], } satisfies Config export default config \ No newline at end of file