From 5d7220f5a8d9e7b576dce0cf3ddbcbf1157a4641 Mon Sep 17 00:00:00 2001 From: seth Date: Mon, 19 May 2025 01:13:14 -0400 Subject: [PATCH] feat: enhance Lanyard component with tooltip support and improve styling --- src/front/components/Lanyard/index.module.css | 110 ++++++++++++++++++ src/front/components/Lanyard/index.tsx | 92 ++++++++++----- src/front/components/pages/About/index.tsx | 53 +++++---- src/front/utilities/clicker/index.ts | 4 +- src/front/utilities/colors.module.css | 40 ------- types/lanyard.d.ts | 24 +++- 6 files changed, 229 insertions(+), 94 deletions(-) create mode 100644 src/front/components/Lanyard/index.module.css diff --git a/src/front/components/Lanyard/index.module.css b/src/front/components/Lanyard/index.module.css new file mode 100644 index 0000000..18afb93 --- /dev/null +++ b/src/front/components/Lanyard/index.module.css @@ -0,0 +1,110 @@ +.card { + width: 100%; +} + +.activityCard { + background-color: transparent; + border-radius: 8px; + padding: 16px; + width: 100% !important; + /* Set a max width */ +} + +.status { + font-size: 14px; + margin-bottom: 8px; +} + +.content { + display: flex; + flex-wrap: wrap; + /* Allow wrapping for smaller screens */ +} + +.bigImage { + position: relative; + width: 120px; + /* Set fixed width for the big image */ + height: 120px; + /* Set fixed height for the big image */ + flex-shrink: 0; + /* Prevent shrinking */ +} + +.bigImage img { + width: 100%; + height: 100%; + border-radius: 8px; + object-fit: cover; + /* Ensures the image covers the area without distortion */ +} + +.smallImage { + position: absolute; + bottom: -8px; + right: -8px; + width: 40px; + /* Set fixed width for the small image */ + height: 40px; + /* Set fixed height for the small image */ + overflow: hidden; + border-radius: 50%; +} + +.smallImage img { + width: 100%; + height: 100%; + object-fit: cover; + /* Ensures the image covers the area without distortion */ +} + +.textInfo { + margin-left: 16px; + display: flex; + flex-direction: column; + justify-content: center; + flex-grow: 1; + /* Allow text info to grow */ +} + +.appName { + font-size: 16px; + font-weight: bold; +} + +.state, +.details { + font-size: 14px; + color: #b9bbbe; +} + +/* Media Queries for Responsiveness */ +@media (max-width: 480px) { + .bigImage { + width: 80px; + /* Adjust size for smaller screens */ + height: 80px; + } + + .smallImage { + width: 30px; + /* Adjust size for smaller screens */ + height: 30px; + } + + .textInfo { + margin-left: 8px; + /* Reduce margin for smaller screens */ + } + + .appName { + font-size: 14px; + /* Adjust font size */ + } + + .state, + .details { + font-size: 12px; + /* Adjust font size */ + } +} \ No newline at end of file diff --git a/src/front/components/Lanyard/index.tsx b/src/front/components/Lanyard/index.tsx index bfa13c1..23ca176 100644 --- a/src/front/components/Lanyard/index.tsx +++ b/src/front/components/Lanyard/index.tsx @@ -1,8 +1,11 @@ -import { highlightElement } from "@speed-highlight/core"; import { createRef } from "tsx-dom"; import colors from "../../utilities/colors.module.css"; import socket from "../../utilities/socket"; +import "mdui/components/tooltip.js"; + +import style from "./index.module.css"; // entirely gpt generated :sob: + const activityTypes: Record = { 0: "Playing", 1: "Streaming", @@ -12,6 +15,22 @@ const activityTypes: Record = { 5: "Competing in", }; +const getImageUrl = (activity: LanyardActivity, size: "large" | "small") => { + if (!activity.assets) return null; + + const image = activity.assets[`${size}_image`]; + + if (!image) return null; + + if (image.startsWith("mp:external")) { + return `https://wsrv.nl/?w=${size === "large" ? 120 : 40}&url=https://${image.split("/").slice(3).join("/")}`; + } + + if (image.startsWith("mp:")) { + return `https://cdn.discordapp.com/app-assets/${activity.application_id}/${image.slice(3)}.webp`; + } +}; + export default () => { const container = createRef(); @@ -32,33 +51,52 @@ export default () => { } if (container.current) { - container.current.textContent = JSON.stringify( - { - activities: [ - ...new Set( - lanyard.activities.map((act) => { - const type = activityTypes[act.type]; - const parts = [ - `${type}${act.name === "Custom Status" ? "" : ` ${act.name}`}`, - ]; - if (act.details && act.details !== act.name) - parts.push(act.details); - if (act.state && act.state !== act.name) parts.push(act.state); - return parts; - }), - ), - ], - }, - null, - 2, - ); - highlightElement(container.current); + container.current.innerHTML = ""; + for (const activity of lanyard.activities) { + if (activity.type === 4) { + continue; + } + const largeImage = getImageUrl(activity, "large"); + const smallImage = getImageUrl(activity, "small"); + + container.current.innerHTML += ( +
+ {/* @ts-expect-error; variant is not in the types for some reason? */} + + {" "} +
+
{activityTypes[activity.type]}
+
+ {largeImage && ( +
+ {/* @ts-expect-error; placement is not in the types for some reason? */} + + Large Activity + + {smallImage && ( +
+ {/* @ts-expect-error; placement is not in the types for some reason? */} + + Small Activity + +
+ )} +
+ )} +
+
{activity.name}
+
{activity.state}
+
{activity.details}
+
+
+
+
+
+
+ ).outerHTML; + } } }); - return ( - - {"{}"} - - ); + return
; }; diff --git a/src/front/components/pages/About/index.tsx b/src/front/components/pages/About/index.tsx index 8fea3c0..cdc3795 100644 --- a/src/front/components/pages/About/index.tsx +++ b/src/front/components/pages/About/index.tsx @@ -1,26 +1,41 @@ import "mdui/components/card"; import "mdui/components/avatar"; - import "mdui/components/segmented-button-group"; import "mdui/components/segmented-button"; +import "mdui/components/tooltip.js"; -import colors from "../../../utilities/colors.module.css"; +import type { Tooltip } from "mdui/components/tooltip.js"; +import { createRef } from "tsx-dom"; +import socket from "../../../utilities/socket"; import Hyperate from "../../Hyperate"; import Lanyard from "../../Lanyard"; import styles from "./index.module.css"; export default () => { + const tooltip = createRef(); + + socket.addEventListener("lanyard", (event: Event) => { + const lanyard = (event as CustomEvent).detail; + + const customStatus = lanyard.activities.find((act) => act.type === 4); + + if (tooltip.current) { + if (customStatus?.state) { + tooltip.current.setAttribute("content", customStatus.state); + } else { + tooltip.current.removeAttribute("content"); + } + } + }); return (
- - + + + +

Seth, the dedicated backend developer, with many{" "} passions. @@ -34,16 +49,6 @@ export default () => {

-
- - - - -
{ > + +
+ +
+ +
); }; diff --git a/src/front/utilities/clicker/index.ts b/src/front/utilities/clicker/index.ts index 90ef4bd..8b10c6a 100644 --- a/src/front/utilities/clicker/index.ts +++ b/src/front/utilities/clicker/index.ts @@ -2,7 +2,7 @@ const effectTick = new Audio("https://no.ipv4.army/u/Effect_Tick.ogg"); effectTick.volume = 0.1; -const whitelistedTags = ["button", "icon", "item"]; +const whitelistedTags = ["button", "icon", "item", "tooltip", "avatar"]; document.onclick = (event: MouseEvent) => { const target = event.target as HTMLElement; @@ -12,8 +12,6 @@ document.onclick = (event: MouseEvent) => { const tagName = target.tagName.toLowerCase(); const isWhitelisted = whitelistedTags.some((tag) => tagName.includes(tag)); - console.log(tagName, isWhitelisted); - if (!isWhitelisted) return; "vibrate" in navigator && navigator.vibrate(1); diff --git a/src/front/utilities/colors.module.css b/src/front/utilities/colors.module.css index 3a4dc1f..a03b962 100644 --- a/src/front/utilities/colors.module.css +++ b/src/front/utilities/colors.module.css @@ -197,43 +197,3 @@ --mdui-color-surface-container-highest: 56, 51, 54; --mdui-color-surface-tint-color: 255, 171, 243; } - -.pfp { - --mdui-color-primary: 255, 183, 123; - --mdui-color-on-primary: 77, 39, 0; - --mdui-color-primary-container: 109, 58, 0; - --mdui-color-on-primary-container: 255, 220, 194; - --mdui-color-secondary: 227, 192, 166; - --mdui-color-on-secondary: 65, 44, 25; - --mdui-color-secondary-container: 90, 66, 46; - --mdui-color-on-secondary-container: 255, 220, 194; - --mdui-color-tertiary: 196, 203, 151; - --mdui-color-on-tertiary: 46, 51, 13; - --mdui-color-tertiary-container: 68, 74, 34; - --mdui-color-on-tertiary-container: 224, 231, 177; - --mdui-color-error: 255, 180, 171; - --mdui-color-on-error: 105, 0, 5; - --mdui-color-error-container: 147, 0, 10; - --mdui-color-on-error-container: 255, 180, 171; - --mdui-color-background: 32, 27, 23; - --mdui-color-on-background: 236, 224, 218; - --mdui-color-surface: 32, 27, 23; - --mdui-color-on-surface: 236, 224, 218; - --mdui-color-surface-variant: 81, 68, 59; - --mdui-color-on-surface-variant: 214, 195, 182; - --mdui-color-outline: 158, 142, 130; - --mdui-color-outline-variant: 81, 68, 59; - --mdui-color-shadow: 0, 0, 0; - --mdui-color-scrim: 0, 0, 0; - --mdui-color-inverse-surface: 236, 224, 218; - --mdui-color-inverse-on-surface: 53, 47, 43; - --mdui-color-inverse-primary: 143, 78, 0; - --mdui-color-surface-dim: 23, 18, 15; - --mdui-color-surface-bright: 62, 56, 51; - --mdui-color-surface-container-lowest: 18, 13, 10; - --mdui-color-surface-container-low: 32, 27, 23; - --mdui-color-surface-container: 36, 31, 27; - --mdui-color-surface-container-high: 47, 41, 37; - --mdui-color-surface-container-highest: 58, 52, 47; - --mdui-color-surface-tint-color: 255, 183, 123; -} diff --git a/types/lanyard.d.ts b/types/lanyard.d.ts index d0f92b0..565a4de 100644 --- a/types/lanyard.d.ts +++ b/types/lanyard.d.ts @@ -1,9 +1,27 @@ type LanyardActivity = { - type: number; + id: string; name: string; - details?: string; + type: number; state?: string; - [key: string]: unknown; + session_id: string; + details?: string; + application_id: string; + + timestamps?: { + start?: number; + end?: number; + }; + + assets?: { + large_image?: string; + large_text?: string; + small_image?: string; + small_text?: string; + }; + + created_at?: number; + + buttons?: string[]; }; type LanyardData = {