Basic Discord integration
All checks were successful
Deploy Site / docker (ubuntu-latest, 2.44.0) (push) Successful in 1m47s
All checks were successful
Deploy Site / docker (ubuntu-latest, 2.44.0) (push) Successful in 1m47s
This commit is contained in:
parent
adbc648d05
commit
65f8d0c189
@ -1,7 +1,2 @@
|
|||||||
# RainnnyCLUB
|
# RainnnyCLUB
|
||||||
My personal portfolio website hosted [here](https://rainnny.club)
|
My personal portfolio website hosted [here](https://rainnny.club)
|
||||||
|
|
||||||
## TODO
|
|
||||||
- [x] Mobile Responsiveness
|
|
||||||
- [ ] Discord Integration (Status, Activity, etc)
|
|
||||||
- [ ] Add Configuration
|
|
@ -7,6 +7,10 @@ const nextConfig = {
|
|||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "cdn.rainnny.club",
|
hostname: "cdn.rainnny.club",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
hostname: "cdn.discordapp.com",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "bonfire.wtf",
|
hostname: "bonfire.wtf",
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"tailwind-merge": "^2.5.2",
|
"tailwind-merge": "^2.5.2",
|
||||||
"tailwindcss-animate": "^1.0.7"
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"use-lanyard": "^1.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import Greeting from "@/components/landing/greeting";
|
import Greeting from "@/components/landing/greeting";
|
||||||
import Navbar from "@/components/landing/navbar";
|
import Navbar from "@/components/landing/navbar";
|
||||||
import { ReactElement } from "react";
|
import { ReactElement } from "react";
|
||||||
|
import Navigation from "@/components/landing/navigation";
|
||||||
|
import BlurFade from "@/components/ui/blur-fade";
|
||||||
|
import DiscordStatus from "@/components/landing/discord-status";
|
||||||
|
|
||||||
const LandingPage = (): ReactElement => (
|
const LandingPage = (): ReactElement => (
|
||||||
<main className="h-screen flex flex-col">
|
<main className="h-screen flex flex-col">
|
||||||
@ -13,6 +16,10 @@ const LandingPage = (): ReactElement => (
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Greeting />
|
<Greeting />
|
||||||
|
<BlurFade className="my-7" delay={1.25} inView>
|
||||||
|
<Navigation />
|
||||||
|
</BlurFade>
|
||||||
|
<DiscordStatus />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
89
src/components/landing/discord-status.tsx
Normal file
89
src/components/landing/discord-status.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ReactElement } from "react";
|
||||||
|
import { Activity, Data, DiscordUser, useLanyardWS } from "use-lanyard";
|
||||||
|
import BlurFade from "@/components/ui/blur-fade";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { PlayIcon } from "@heroicons/react/24/outline";
|
||||||
|
|
||||||
|
const statusColors = {
|
||||||
|
online: "bg-green-500",
|
||||||
|
idle: "bg-yellow-500",
|
||||||
|
dnd: "bg-red-500",
|
||||||
|
};
|
||||||
|
|
||||||
|
const DiscordStatus = (): ReactElement => {
|
||||||
|
const discordData: Data | undefined = useLanyardWS("504147739131641857");
|
||||||
|
const discordUser: DiscordUser | undefined = discordData?.discord_user;
|
||||||
|
return (
|
||||||
|
<div className="absolute left-4 bottom-4">
|
||||||
|
{discordData && discordUser && (
|
||||||
|
<BlurFade
|
||||||
|
className="flex select-none pointer-events-none"
|
||||||
|
delay={1.65}
|
||||||
|
inView
|
||||||
|
>
|
||||||
|
{/* Avatar & Status */}
|
||||||
|
<div className="relative z-50">
|
||||||
|
<Image
|
||||||
|
className="scale-110 rounded-full border"
|
||||||
|
src={`https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.webp`}
|
||||||
|
alt={`${discordUser.username}'s Discord Avatar`}
|
||||||
|
width={60}
|
||||||
|
height={60}
|
||||||
|
/>
|
||||||
|
{discordData.discord_status !== "offline" && (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute bottom-1.5 right-1 w-2.5 h-2.5 bg-red-500 rounded-full",
|
||||||
|
statusColors[discordData.discord_status]
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Username & Basic Activity */}
|
||||||
|
<div className="-translate-x-7 p-2 pl-10 pr-6 flex flex-col justify-center bg-white/55 dark:bg-zinc-800/45 border rounded-r-3xl">
|
||||||
|
<div className="flex gap-1 items-center">
|
||||||
|
<h1 className="text-lg font-bold">
|
||||||
|
{discordUser.display_name}
|
||||||
|
</h1>
|
||||||
|
<h2 className="opacity-65">
|
||||||
|
{discordUser.username}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{discordData.activities.length > 0 && (
|
||||||
|
<BasicActivityDisplay
|
||||||
|
activity={discordData.activities[0]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</BlurFade>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BasicActivityDisplay = ({
|
||||||
|
activity,
|
||||||
|
}: {
|
||||||
|
activity: Activity;
|
||||||
|
}): ReactElement => {
|
||||||
|
const prefix =
|
||||||
|
activity.type === 0
|
||||||
|
? "Playing"
|
||||||
|
: activity.type === 1
|
||||||
|
? "Streaming"
|
||||||
|
: "Listening to";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-1.5 items-center text-sm">
|
||||||
|
<span className="opacity-80">{prefix}</span> {activity.name}{" "}
|
||||||
|
<PlayIcon className="text-blue-500" width={16} height={16} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DiscordStatus;
|
@ -6,12 +6,12 @@ import moment, { Moment } from "moment";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { ReactElement } from "react";
|
import { ReactElement } from "react";
|
||||||
import { FlipWords } from "@/components/ui/flip-words";
|
import { FlipWords } from "@/components/ui/flip-words";
|
||||||
import Navigation from "./navigation";
|
|
||||||
|
|
||||||
const Greeting = (): ReactElement => {
|
const Greeting = (): ReactElement => {
|
||||||
const now: Moment = moment(Date.now());
|
const now: Moment = moment(Date.now());
|
||||||
return (
|
return (
|
||||||
<section className="flex flex-col gap-5 items-center">
|
<section className="flex flex-col gap-5 items-center">
|
||||||
|
{/* Picture */}
|
||||||
<BlurFade delay={0.3} inView>
|
<BlurFade delay={0.3} inView>
|
||||||
<Image
|
<Image
|
||||||
className="shadow-2xl shadow-blue-500 rounded-full scale-90 sm:scale-100 select-none pointer-events-none transition-all transform-gpu"
|
className="shadow-2xl shadow-blue-500 rounded-full scale-90 sm:scale-100 select-none pointer-events-none transition-all transform-gpu"
|
||||||
@ -22,6 +22,7 @@ const Greeting = (): ReactElement => {
|
|||||||
/>
|
/>
|
||||||
</BlurFade>
|
</BlurFade>
|
||||||
|
|
||||||
|
{/* Intro */}
|
||||||
<BlurFade delay={0.6} inView>
|
<BlurFade delay={0.6} inView>
|
||||||
<h1
|
<h1
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -52,15 +53,11 @@ const Greeting = (): ReactElement => {
|
|||||||
"text-black dark:!text-transparent bg-clip-text bg-gradient-to-br from-zinc-300/85 to-white"
|
"text-black dark:!text-transparent bg-clip-text bg-gradient-to-br from-zinc-300/85 to-white"
|
||||||
)}
|
)}
|
||||||
words={[
|
words={[
|
||||||
`A ${now.diff(moment([2002, 10, 13]), "years")} year old${" "}
|
`A ${now.diff(moment([2002, 10, 13]), "years")} year old
|
||||||
passionate software engineer living in Canada with ${moment([2016, 8, 1]).fromNow(true)} of experience!`,
|
passionate software engineer living in Canada with ${moment([2016, 8, 1]).fromNow(true)} of experience!`,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</BlurFade>
|
</BlurFade>
|
||||||
|
|
||||||
<BlurFade className="mt-3.5" delay={1.25} inView>
|
|
||||||
<Navigation />
|
|
||||||
</BlurFade>
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,12 @@ const Navigation = (): ReactElement => {
|
|||||||
|
|
||||||
{/* Selected Content */}
|
{/* Selected Content */}
|
||||||
{selected && (
|
{selected && (
|
||||||
<BlurFade key={selected.name} delay={0.05} inView>
|
<BlurFade
|
||||||
|
key={selected.name}
|
||||||
|
className="flex justify-center"
|
||||||
|
delay={0.05}
|
||||||
|
inView
|
||||||
|
>
|
||||||
<div className="mt-5">{selected.content}</div>
|
<div className="mt-5">{selected.content}</div>
|
||||||
</BlurFade>
|
</BlurFade>
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user