Better Github Sponsors && HotKey && Scroll Hash

This commit is contained in:
암냥 2025-03-02 01:13:52 +09:00
commit c4ed0b3e94
No known key found for this signature in database
GPG key ID: C96C0327210DD61A
3 changed files with 170 additions and 131 deletions

View file

@ -1,6 +1,5 @@
import { useState, useEffect } from "react";
import { Send, AlignJustify, BadgeCheck, House, CircleHelp, ChartGantt, PhoneCall } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
@ -8,27 +7,25 @@ import {
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
} from "@/components/ui/dropdown-menu";
export default function BottomBar() {
const [email, setEmail] = useState<string>('me@imnya.ng');
const [hash, setHash] = useState<string>(window.location.hash);
const [accessKeyCombo, setAccessKeyCombo] = useState<string>("Alt");
useEffect(() => {
const emaillist = ['me', 'mail', 'not', 'cat', 'neko', 'meow', 'heart']
const domainlist = ['imnya.ng', 'al-1s.kr']
const emaillist = ['me', 'mail', 'not', 'cat', 'neko', 'meow', 'heart'];
const domainlist = ['imnya.ng', 'al-1s.kr'];
// furry is 0.001%
const randomEmail = () => {
const random = Math.floor(Math.random() * 1000);
if (random === 0) {
setEmail(`furry@${domainlist[Math.floor(Math.random() * domainlist.length)]}`);
}
else {
} else {
setEmail(`${emaillist[Math.floor(Math.random() * emaillist.length)]}@${domainlist[Math.floor(Math.random() * domainlist.length)]}`);
}
}
};
randomEmail();
const handleHashChange = () => {
@ -42,6 +39,25 @@ export default function BottomBar() {
};
}, []);
useEffect(() => {
const ua = navigator.userAgent;
let keyCombo = "Alt";
if (/Mac/i.test(ua)) {
keyCombo = "Control + Option";
} else if (/Linux/i.test(ua)) {
keyCombo = "Alt";
if (/Firefox/i.test(ua)) {
keyCombo = "Alt + Shift";
}
} else if (/Windows/i.test(ua)) {
if (/Firefox/i.test(ua)) {
keyCombo = "Alt + Shift";
}
}
setAccessKeyCombo(keyCombo);
}, []);
return (
<div className="w-full flex justify-center fixed bottom-0 z-50">
@ -49,11 +65,14 @@ export default function BottomBar() {
<div className="flex items-center justify-between w-full h-full py-4 px-8">
<a href={`mailto:${email}`} className="flex flex-row gap-4"><Send width={16} /> {email}</a>
<div>
<button onClick={() => window.location.hash = "#top"} accessKey="1" className="w-[0px] h-[0px] text-[0px] text-background"></button>
<button onClick={() => window.location.hash = "#about"} accessKey="2" className="w-[0px] h-[0px] text-[0px] text-background"></button>
<button onClick={() => window.location.hash = "#project"} accessKey="3" className="w-[0px] h-[0px] text-[0px] text-background"></button>
<button onClick={() => window.location.hash = "#timeline"} accessKey="4" className="w-[0px] h-[0px] text-[0px] text-background"></button>
<button onClick={() => window.location.hash = "#contact"} accessKey="5" className="w-[0px] h-[0px] text-[0px] text-background"></button>
{["top", "about", "project", "timeline", "contact"].map((section, index) => (
<button
key={section}
onClick={() => window.location.hash = `#${section}`}
accessKey={(index + 1).toString()}
className="w-[0px] h-[0px] text-[0px] text-background"
></button>
))}
</div>
<div className="flex flex-row items-center justify-center">
<DropdownMenu>
@ -61,76 +80,25 @@ export default function BottomBar() {
<button><AlignJustify /></button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem asChild>
<a href="#top" className="flex flex-row items-center justify-between">
<div className="flex flex-row gap-2 items-center justify-between h-4">
{hash === "#top" ? (
<BadgeCheck width={16} height={16} />
) : (
<House width={16} height={16} />
)}
Home
</div>
<p className="text-muted-foreground">Alt + 1</p>
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="#about" className="flex flex-row items-center justify-between">
<div className="flex flex-row gap-2 items-center justify-between h-4">
{hash === "#about" ? (
<BadgeCheck width={16} height={16} />
) : (
<CircleHelp width={16} height={16} />
)}
About
</div>
<p className="text-muted-foreground">Alt + 2</p>
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="#project" className="flex flex-row items-center justify-between">
<div className="flex flex-row gap-2 items-center justify-between h-4">
{hash === "#project" ? (
<BadgeCheck width={16} height={16} />
) : (
<ChartGantt width={16} height={16} />
)}
Project
</div>
<p className="text-muted-foreground">Alt + 3</p>
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="#timeline" className="flex flex-row items-center justify-between">
<div className="flex flex-row gap-2 items-center justify-between h-4">
{hash === "#timeline" ? (
<BadgeCheck width={16} height={16} />
) : (
<ChartGantt width={16} height={16} />
)}
Timeline
</div>
<p className="text-muted-foreground">Alt + 4</p>
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="#contact" className="flex flex-row items-center justify-between">
<div className="flex flex-row gap-2 items-center justify-between h-4">
{hash === "#contact" ? (
<BadgeCheck width={16} height={16} />
) : (
<PhoneCall width={16} height={16} />
)}
Contact
</div>
<p className="text-muted-foreground">Alt + 5</p>
</a>
</DropdownMenuItem>
{["top", "about", "project", "timeline", "contact"].map((section, index) => {
const icons = [House, CircleHelp, ChartGantt, ChartGantt, PhoneCall];
const Icon = icons[index];
return (
<DropdownMenuItem asChild key={section}>
<a href={`#${section}`} className="flex flex-row items-center justify-between">
<div className="flex flex-row gap-2 items-center justify-between h-4">
{hash === `#${section}` ? (
<BadgeCheck width={16} height={16} />
) : (
<Icon width={16} height={16} />
)}
{section.charAt(0).toUpperCase() + section.slice(1)}
</div>
<p className="text-muted-foreground">{accessKeyCombo} + {index + 1}</p>
</a>
</DropdownMenuItem>
);
})}
<DropdownMenuSeparator />
<DropdownMenuLabel>© 2021-2025 imnyang</DropdownMenuLabel>
</DropdownMenuContent>
@ -139,5 +107,5 @@ export default function BottomBar() {
</div>
</header>
</div>
)
}
);
}

View file

@ -1,45 +1,91 @@
import { Github, Instagram, Rss } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "../ui/button";
export default function Contact() {
return (
<div className="w-full h-screen flex items-center justify-center">
<div className="w-full md:w-[50%] p-4 flex items-center justify-center flex-col gap-4">
<div className="flex items-center justify-center gap-4 flex-row">
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<a href="https://github.com/imnyang" target="_blank" rel="noreferrer" className="flex flex-row gap-4"><Github /></a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">Github</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<a href="https://x.com/imnya_ng" target="_blank" rel="noreferrer" className="flex flex-row gap-4 text-3xl">𝕏</a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">𝕏</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<a href="https://instagram.com/loopback.ip" target="_blank" rel="noreferrer" className="flex flex-row gap-4"><Instagram /></a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">Instagram</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<a href="https://blog.imnya.ng" target="_blank" rel="noreferrer" className="flex flex-row gap-4"><Rss /></a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">Blog</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<iframe src="https://github.com/sponsors/imnyang/card" title="Sponsor imnyang" height="117" width="600" className="rounded-2xl" />
</div>
return (
<div className="w-full h-screen flex items-center justify-center">
<div className="w-full md:w-[50%] p-4 flex items-center justify-center flex-col gap-4">
<div className="flex items-center justify-center gap-4 flex-row">
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<a
href="https://github.com/imnyang"
target="_blank"
rel="noreferrer"
className="flex flex-row gap-4"
>
<Github />
</a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">
Github
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<a
href="https://x.com/imnya_ng"
target="_blank"
rel="noreferrer"
className="flex flex-row gap-4 text-3xl"
>
𝕏
</a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">𝕏</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<a
href="https://instagram.com/loopback.ip"
target="_blank"
rel="noreferrer"
className="flex flex-row gap-4"
>
<Instagram />
</a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">
Instagram
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<a
href="https://blog.imnya.ng"
target="_blank"
rel="noreferrer"
className="flex flex-row gap-4"
>
<Rss />
</a>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">
Blog
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
<div className="flex flex-row gap-3 items-center justify-center">
<p>Github</p>
<Button
variant="secondary"
size="sm"
>
<a href="https://github.com/sponsors/imnyang" target="_blank" rel="noreferrer" className="flex items-center justify-center gap-2">
<span>💕</span>
<span>Sponsor</span>
</a>
</Button>
</div>
</div>
</div>
);
}