Compare commits

...

13 Commits

7 changed files with 111 additions and 43 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

+48 -12
View File
@@ -98,18 +98,22 @@ interface DiscordActivity {
}; };
} }
function resolveDiscordAsset(image: string | undefined): string { function resolveDiscordAsset(applicationId: string | undefined, image: string | undefined): string {
if (!image) return ""; if (!image) return "";
if (image.startsWith("mp:external/")) { if (image.startsWith("mp:external/")) {
const httpsIndex = image.indexOf("/https/"); const httpsIndex = image.indexOf("/https/");
if (httpsIndex !== -1) { if (httpsIndex !== -1) {
const after = image.slice(httpsIndex + "/https/".length); return `https://${image.slice(httpsIndex + "/https/".length)}`;
return `https://${after}`;
} }
} }
if (/^\d+$/.test(image) || image.startsWith("spotify:")) return ""; if (image.startsWith("spotify:"))
return "";
if (applicationId && image)
return `https://cdn.discordapp.com/app-assets/${applicationId}/${image}.png`;
return image; return image;
} }
@@ -130,13 +134,14 @@ export function DiscordStatus({ userId }: DiscordStatusParams) {
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
useEffect(() => { useEffect(() => {
let interval: NodeJS.Timeout | null = null;
async function fetchRichPresence() { async function fetchRichPresence() {
try { try {
const response = await fetch(`https://api.lanyard.rest/v1/users/${userId}`); const response = await fetch(`https://api.lanyard.rest/v1/users/${userId}`);
const json: LanyardResponse = await response.json(); const json: LanyardResponse = await response.json();
if (json.success) { if (json.success)
setPresence(json.data); setPresence(json.data);
}
} catch (error) { } catch (error) {
console.error("Failed to fetch Lanyard presence:", error); console.error("Failed to fetch Lanyard presence:", error);
} finally { } finally {
@@ -144,9 +149,39 @@ export function DiscordStatus({ userId }: DiscordStatusParams) {
} }
} }
fetchRichPresence(); const startPolling = () => {
const interval = setInterval(fetchRichPresence, 30000); if (!interval) {
return () => clearInterval(interval); fetchRichPresence();
interval = setInterval(fetchRichPresence, 30000);
}
};
const stopPolling = () => {
if (interval) {
clearInterval(interval);
interval = null;
}
};
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible')
startPolling();
else
stopPolling();
};
if (document.visibilityState === 'visible')
startPolling();
else
setLoading(false);
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
stopPolling();
};
}, [userId]); }, [userId]);
if (loading) if (loading)
@@ -177,9 +212,10 @@ export function DiscordStatus({ userId }: DiscordStatusParams) {
if (gameActivity.details) if (gameActivity.details)
activityText += `${gameActivity.details}`; activityText += `${gameActivity.details}`;
activityImage = gameActivity.assets if (gameActivity.assets) {
? resolveDiscordAsset(gameActivity.assets.small_image || gameActivity.assets.large_image) const targetImage = gameActivity.assets.small_image || gameActivity.assets.large_image;
: ""; activityImage = resolveDiscordAsset(gameActivity.application_id, targetImage);
}
} }
else if (isListeningToSpotify && presence.spotify) { else if (isListeningToSpotify && presence.spotify) {
primaryActivity = { name: "Spotify" } as DiscordActivity; primaryActivity = { name: "Spotify" } as DiscordActivity;
+1 -1
View File
@@ -9,7 +9,7 @@ export const metadata: Metadata = {
// description: '', // description: '',
images: [ images: [
{ {
url: 'https://neru.rip/ok.jpg', url: 'https://neru.rip/img/ok.jpg',
width: 734, width: 734,
height: 1104, height: 1104,
}, },
+37 -18
View File
@@ -22,7 +22,7 @@
} }
* { * {
cursor: url('https://cdn.cursors-4u.net/previews/my-custom-cursor-8-957a5617-32.webp') 32 32, auto; cursor: url('/cur/kuromi.webp') 32 32, auto;
} }
body { body {
@@ -64,7 +64,7 @@ body {
padding: 35px 25px 25px 25px; padding: 35px 25px 25px 25px;
position: relative; position: relative;
max-width: 400px; max-width: 400px;
width: 100%; width: calc(100% - 30px);
border: 1px solid var(--pink-accent); border: 1px solid var(--pink-accent);
outline: 4px solid #fff; outline: 4px solid #fff;
@@ -115,7 +115,7 @@ body {
} }
/* /*
text stuffs text stuff
*/ */
h1 { h1 {
font-size: 1.8rem; font-size: 1.8rem;
@@ -156,6 +156,23 @@ h1 {
border-bottom: 1px dashed var(--pink-accent); border-bottom: 1px dashed var(--pink-accent);
} }
.social-links button {
background: none;
border: none;
font-family: inherit;
font-size: 0.8rem;
color: var(--text-main);
padding: 2px 6px;
margin: 0 6px;
border-bottom: 1px dashed transparent;
transition: all 0.3s ease;
}
.social-links button:hover {
color: var(--pink-accent);
border-bottom: 1px dashed var(--pink-accent);
}
.title { .title {
font-size: 0.95rem; font-size: 0.95rem;
font-style: italic; font-style: italic;
@@ -172,22 +189,17 @@ h1 {
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
margin: 5px 0; margin: 5px 0;
flex-wrap: wrap;
} }
.directory a { .directory a {
text-decoration: none; text-decoration: none;
background: #fff; background: #fff;
padding: 3px 8px;
font-size: 0.73rem; font-size: 0.73rem;
color: var(--text-main); color: var(--text-main);
border: 1px solid #fff;
padding: 3px 10px; padding: 3px 10px;
border: 1px solid var(--accent); border: 1px solid var(--accent);
box-shadow: 2px 2px 0px var(--pink-accent); box-shadow: 2px 2px 0px var(--pink-accent);
transition: 0.2s ease; transition: 0.2s ease;
} }
@@ -196,16 +208,19 @@ h1 {
} }
.directory a::after { .directory a::after {
content:" " content: " "
} }
.directory a:hover { .directory a:hover {
cursor: url('https://cdn.cursors-4u.net/previews/my-custom-cursor-8-1-e2eeed6e-preview-32.webp') 0 0, auto !important; cursor: url('/cur/kuromi-hearts.webp') 0 0, auto !important;
color: var(--text-header); color: var(--text-header);
box-shadow: 1px 1px 0px var(--pink-accent); box-shadow: 1px 1px 0px var(--pink-accent);
background: var(--pink-accent); background: var(--pink-accent);
} }
/*
marquee stuff at the bottom
*/
.marquee { .marquee {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
@@ -222,19 +237,23 @@ h1 {
background: linear-gradient(to right, transparent, rgba(255, 214, 245, 0.3), transparent); background: linear-gradient(to right, transparent, rgba(255, 214, 245, 0.3), transparent);
} }
.marquee span { .marquee-track {
display: inline-block; display: flex;
padding-left: 100%; width: max-content;
animation: marquee 25s linear infinite; animation: marquee-loop 10s linear infinite;
} }
@keyframes marquee { .marquee-track span {
padding-right: 2rem;
}
@keyframes marquee-loop {
0% { 0% {
transform: translate(0, 0); transform: translate3d(0, 0, 0);
} }
100% { 100% {
transform: translate(-100%, 0); transform: translate3d(-50%, 0, 0);
} }
} }
+25 -12
View File
@@ -1,6 +1,6 @@
'use client'; 'use client';
import { useState } from 'react'; import { useEffect, useState } from 'react';
import './page.css'; import './page.css';
import { DiscordStatus } from './components/discordstatus'; import { DiscordStatus } from './components/discordstatus';
@@ -14,6 +14,17 @@ function Content() {
const toggleModal = () => setIsOpen(!isOpen); const toggleModal = () => setIsOpen(!isOpen);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape' && isOpen)
setIsOpen(false);
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [isOpen]);
const marqueeText = "✧ ꒰ა˵• ﻌ •˵ა꒱ ✧ ฅ^•ﻌ•^ฅ ✧ ᶻ 𝗓 𐰁 /ᐠ. 。 .ᐟ\\ ✧ ฅ/ᐠ. ̫ .ᐟ\\ฅ ✧ ꒰ა≽^•⩊•^≼໒꒱ ✧ ₍˄·͈༝·͈˄₎ ✧ /ᐠ. ⩊ .ᐟ\\ノ ✧ 𓏲ּ ֶָ ࣪ /ᐠ .ᆺ. ᐟ\\ノ ✧";
return ( return (
<> <>
<div className="main-frame"> <div className="main-frame">
@@ -23,9 +34,9 @@ function Content() {
</header> </header>
<nav className="social-links"> <nav className="social-links">
<a href={TWITTER_LINK}>twitter</a> <a href={TWITTER_LINK} target="_blank" rel="noopener noreferrer">twitter</a>
<a onClick={toggleModal}>discord</a> <button onClick={toggleModal}>discord</button>
<a href={STEAM_LINK} style={{ cursor: 'pointer' }}>steam</a> <a href={STEAM_LINK} target="_blank" rel="noopener noreferrer">steam</a>
</nav> </nav>
<section className="content-box"> <section className="content-box">
@@ -36,18 +47,18 @@ function Content() {
<section className="content-box"> <section className="content-box">
<h2 className="title"> projects im currently working on </h2> <h2 className="title"> projects im currently working on </h2>
<ul className="directory"> <ul className="directory">
<li><a href="https://git.neru.rip/neru/seallib">seallib</a></li> <li><a href="https://git.neru.rip/neru/seallib" target="_blank" rel="noopener noreferrer">seallib</a></li>
<li><a href="https://git.neru.rip/neru/tinymitm">tinymitm</a></li> <li><a href="https://git.neru.rip/neru/tinymitm" target="_blank" rel="noopener noreferrer">tinymitm</a></li>
<li><a href="https://git.neru.rip/neru/luma">luma</a></li> <li><a href="https://git.neru.rip/neru/luma" target="_blank" rel="noopener noreferrer">luma</a></li>
</ul> </ul>
</section> </section>
<section className="content-box"> <section className="content-box">
<h2 className="title"> sites </h2> <h2 className="title"> sites </h2>
<ul className="directory"> <ul className="directory">
<li><a href="https://git.neru.rip">gitea</a></li> <li><a href="https://git.neru.rip" target="_blank" rel="noopener noreferrer">gitea</a></li>
<li><a href="https://zl.neru.rip">zipline</a></li> <li><a href="https://zl.neru.rip" target="_blank" rel="noopener noreferrer">zipline</a></li>
<li><a href="https://files.neru.rip">files</a></li> <li><a href="https://files.neru.rip" target="_blank" rel="noopener noreferrer">files</a></li>
</ul> </ul>
</section> </section>
@@ -61,9 +72,11 @@ function Content() {
<footer> <footer>
<div className="marquee"> <div className="marquee">
<span> ˵ ˵ ^^ 𝗓 𐰁 /. .\ /. ̫ .\ ^^ ˄·͈·͈˄ /. .\ 𓏲ּ ֶָ / .. \ </span> <div className="marquee-track">
<span>{marqueeText}</span>
<span>{marqueeText}</span>
</div>
</div> </div>
{/* <p style={{ fontSize: '0.65rem', opacity: 0.5 }}>✼  ҉  ✼  ҉  ✼  ҉  ✼</p> */}
</footer> </footer>
{isOpen && ( {isOpen && (