feat: enhance Lanyard component with tooltip support and improve styling
Some checks failed
Code quality checks / biome (push) Has been cancelled
Some checks failed
Code quality checks / biome (push) Has been cancelled
This commit is contained in:
parent
cc451a8fef
commit
5d7220f5a8
6 changed files with 229 additions and 94 deletions
110
src/front/components/Lanyard/index.module.css
Normal file
110
src/front/components/Lanyard/index.module.css
Normal file
|
@ -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 */
|
||||
}
|
||||
}
|
|
@ -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<number, string> = {
|
||||
0: "Playing",
|
||||
1: "Streaming",
|
||||
|
@ -12,6 +15,22 @@ const activityTypes: Record<number, string> = {
|
|||
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<HTMLDivElement>();
|
||||
|
||||
|
@ -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 += (
|
||||
<div>
|
||||
{/* @ts-expect-error; variant is not in the types for some reason? */}
|
||||
<mdui-card variant="filled" class={style.card}>
|
||||
{" "}
|
||||
<div class={style.activityCard}>
|
||||
<div class={style.status}>{activityTypes[activity.type]}</div>
|
||||
<div class={style.content}>
|
||||
{largeImage && (
|
||||
<div class={style.bigImage}>
|
||||
{/* @ts-expect-error; placement is not in the types for some reason? */}
|
||||
<mdui-tooltip content={activity.assets?.large_text} placement="top-right">
|
||||
<img src={largeImage} alt="Large Activity" />
|
||||
</mdui-tooltip>
|
||||
{smallImage && (
|
||||
<div class={style.smallImage}>
|
||||
{/* @ts-expect-error; placement is not in the types for some reason? */}
|
||||
<mdui-tooltip content={activity.assets?.small_text} placement="top-right">
|
||||
<img src={smallImage} alt="Small Activity" />
|
||||
</mdui-tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div class={style.textInfo}>
|
||||
<div class={style.appName}>{activity.name}</div>
|
||||
<div class={style.state}>{activity.state}</div>
|
||||
<div class={style.details}>{activity.details}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mdui-card>
|
||||
<br />
|
||||
</div>
|
||||
).outerHTML;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<code class="shj-lang-json" ref={container}>
|
||||
{"{}"}
|
||||
</code>
|
||||
);
|
||||
return <div ref={container} />;
|
||||
};
|
||||
|
|
|
@ -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<Tooltip>();
|
||||
|
||||
socket.addEventListener("lanyard", (event: Event) => {
|
||||
const lanyard = (event as CustomEvent<LanyardData>).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 (
|
||||
<div class={styles.container}>
|
||||
<mdui-card
|
||||
// @ts-expect-error; variant is not in the types for some reason?
|
||||
variant="filled"
|
||||
class={`${styles.card} ${styles.center}`}
|
||||
>
|
||||
<mdui-avatar
|
||||
src="/public/Abyssinian/default.png"
|
||||
class={`${styles.avatar} ${colors.pfp}`}
|
||||
/>
|
||||
<mdui-card class={`${styles.card} ${styles.center}`}>
|
||||
<mdui-tooltip ref={tooltip}>
|
||||
<mdui-avatar
|
||||
src="/public/Abyssinian/default.png"
|
||||
class={styles.avatar}
|
||||
/>
|
||||
</mdui-tooltip>
|
||||
<p>
|
||||
Seth, the <strong>dedicated</strong> backend developer, with many{" "}
|
||||
<strong>passions</strong>.
|
||||
|
@ -34,16 +49,6 @@ export default () => {
|
|||
</p>
|
||||
</mdui-card>
|
||||
|
||||
<br class={styles.lanyard} />
|
||||
|
||||
<mdui-card
|
||||
// @ts-expect-error; variant is not in the types for some reason?
|
||||
variant="filled"
|
||||
class={`${styles.card} ${styles.lanyard}`}
|
||||
>
|
||||
<Lanyard />
|
||||
</mdui-card>
|
||||
|
||||
<br class={styles.hyperate} />
|
||||
|
||||
<mdui-card
|
||||
|
@ -53,6 +58,12 @@ export default () => {
|
|||
>
|
||||
<Hyperate />
|
||||
</mdui-card>
|
||||
|
||||
<br class={styles.lanyard} />
|
||||
|
||||
<div class={`${styles.card} ${styles.lanyard}`}>
|
||||
<Lanyard />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
24
types/lanyard.d.ts
vendored
24
types/lanyard.d.ts
vendored
|
@ -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 = {
|
||||
|
|
Loading…
Add table
Reference in a new issue