Rework Friends: Add in some extra components for friends
This commit is contained in:
parent
414eddea42
commit
ec5c39f855
Binary file not shown.
|
After Width: | Height: | Size: 527 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 231 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 401 KiB |
62
css/main.css
62
css/main.css
|
|
@ -2039,6 +2039,34 @@ body:has(.friends-wrap) .hub {
|
||||||
padding-top: 0.1rem;
|
padding-top: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-name-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.15rem 0.3rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
/* name claims the full first line (so a clan tag never truncates it); the
|
||||||
|
tag chip wraps onto its own line just beneath when there isn't room */
|
||||||
|
.fc-name-row .fc-name { flex: 1 1 100%; min-width: 0; }
|
||||||
|
|
||||||
|
/* Discord server (clan) tag chip */
|
||||||
|
.fc-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.15rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0.05rem 0.3rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: var(--surface-2);
|
||||||
|
font-size: 0.56rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.fc-tag[hidden] { display: none; }
|
||||||
|
.fc-tag-badge { width: 12px; height: 12px; display: block; }
|
||||||
|
|
||||||
.fc-name {
|
.fc-name {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
@ -2076,6 +2104,35 @@ a.fc-name:hover { color: rgb(var(--accent-rgb)); }
|
||||||
.fc-badge { width: 16px; height: 16px; display: block; }
|
.fc-badge { width: 16px; height: 16px; display: block; }
|
||||||
.fc-badge-link { display: inline-flex; line-height: 0; }
|
.fc-badge-link { display: inline-flex; line-height: 0; }
|
||||||
|
|
||||||
|
/* ---- Alts (active + dead) ---- */
|
||||||
|
.fc-name.active-alt::before { content: "🎭 "; }
|
||||||
|
.fc-name.dead-alt::before { content: "💀 "; }
|
||||||
|
|
||||||
|
/* dead alts: banned accounts — greyed out, name struck through, no status */
|
||||||
|
.friend-card.tier-dead-alt .fc-pfp {
|
||||||
|
filter: grayscale(1) brightness(0.6);
|
||||||
|
}
|
||||||
|
.friend-card.tier-dead-alt .fc-name {
|
||||||
|
color: var(--overlay-1);
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
.friend-card.tier-dead-alt .fc-status { display: none; }
|
||||||
|
|
||||||
|
/* the "struck off" diagonal slash across the avatar */
|
||||||
|
.friend-card.tier-dead-alt .fc-avatar::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
width: 132%;
|
||||||
|
height: 4px;
|
||||||
|
background: var(--red);
|
||||||
|
border-radius: 2px;
|
||||||
|
transform: translate(-50%, -50%) rotate(-45deg);
|
||||||
|
box-shadow: 0 0 0 2px var(--surface-0);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* =====================================================================
|
/* =====================================================================
|
||||||
* MUSIC PAGE (/music) — merged in from music.css.
|
* MUSIC PAGE (/music) — merged in from music.css.
|
||||||
* Hero classes are .mnp-* to avoid colliding with the .np-* now-playing
|
* Hero classes are .mnp-* to avoid colliding with the .np-* now-playing
|
||||||
|
|
@ -3365,7 +3422,10 @@ body:has(.presence-stage) {
|
||||||
.presence-stage .presence-card.has-banner-color .pc-av-img {
|
.presence-stage .presence-card.has-banner-color .pc-av-img {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
border: 5px solid var(--surface-0);
|
/* solid dark plate + ring so the banner sits clearly BEHIND the avatar
|
||||||
|
(the PFP itself is partly transparent) */
|
||||||
|
background: var(--crust);
|
||||||
|
border: 6px solid var(--crust);
|
||||||
}
|
}
|
||||||
.presence-stage .pc-av-deco,
|
.presence-stage .pc-av-deco,
|
||||||
.presence-stage .presence-card.has-banner .pc-av-deco,
|
.presence-stage .presence-card.has-banner .pc-av-deco,
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,6 @@
|
||||||
(function friends() {
|
(function friends() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// FRIENDS CONFIG ✏️ EDIT ME
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// Each friend is one card. Fields:
|
|
||||||
// name (required) display name
|
|
||||||
// img (required) static fallback image (used until/unless Lanyard
|
|
||||||
// gives a live avatar, and forever if they're not
|
|
||||||
// in the Lanyard server or the API is down)
|
|
||||||
// discordId (optional) Discord user ID. If set AND they're in the
|
|
||||||
// Lanyard server (https://discord.gg/lanyard),
|
|
||||||
// the card goes live: real avatar, status dot
|
|
||||||
// (green/idle/dnd/offline), badges + Nitro banner.
|
|
||||||
// Leave null for friends who aren't in the server —
|
|
||||||
// they get a blue "not connected" dot + static img.
|
|
||||||
// link (optional) where the card links to (their site, etc.)
|
|
||||||
//
|
|
||||||
// To make Camilla (etc.) live, paste her Discord ID into discordId.
|
|
||||||
// IMPORTANT: keep IDs as STRINGS in quotes ("123..."), not bare numbers —
|
|
||||||
// Discord IDs are too big for a JS number and get rounded (wrong user!).
|
|
||||||
// =====================================================================
|
|
||||||
var FRIENDS = [
|
var FRIENDS = [
|
||||||
{
|
{
|
||||||
title: "Fiancée",
|
title: "Fiancée",
|
||||||
|
|
@ -53,6 +33,16 @@
|
||||||
members: [
|
members: [
|
||||||
{ name: "Aureal", img: "/assets/friends/aureal.gif", tier: "known", discordId: "1498977251134279900", link: "https://aureal.dev/" }
|
{ name: "Aureal", img: "/assets/friends/aureal.gif", tier: "known", discordId: "1498977251134279900", link: "https://aureal.dev/" }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Alts",
|
||||||
|
subtitle: "My other accounts, dead or alive",
|
||||||
|
members: [
|
||||||
|
{ name: "Uzi", img: "/assets/alts/uzi.png", tier: "active-alt", discordId: "526626867973849123", link: null },
|
||||||
|
{ name: "Clove <3", img: "/assets/alts/clove.png", tier: "dead-alt", discordId: "1125844710511104030", link: null},
|
||||||
|
{ name: "Clove ⛤", img: "/assets/alts/butterfly.png", tier: "dead-alt", discordId: "514994021970739201", link: null },
|
||||||
|
{ name: "Mrow", img: "/assets/alts/mrow.png", tier: "dead-alt", discordId: "219480349053288450", link: null }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -89,8 +79,12 @@
|
||||||
}
|
}
|
||||||
function bannerUrl(id, hash) {
|
function bannerUrl(id, hash) {
|
||||||
if (!id || !hash) return null;
|
if (!id || !hash) return null;
|
||||||
var ext = String(hash).startsWith("a_") ? "gif" : "png";
|
// Animated banners (a_) must be requested WITHOUT the .gif extension:
|
||||||
return proxyImg("https://cdn.discordapp.com/banners/" + id + "/" + hash + "." + ext + "?size=480", { w: 480 });
|
// Discord's CDN throws HTTP 415 for some a_*.gif banners, but the
|
||||||
|
// extension-less URL works (wsrv then re-serves it as cookieless webp).
|
||||||
|
var animated = String(hash).startsWith("a_");
|
||||||
|
var url = "https://cdn.discordapp.com/banners/" + id + "/" + hash + (animated ? "" : ".png") + "?size=480";
|
||||||
|
return proxyImg(url, { w: 480 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// dstn.to badge list → small icon row (same source the presence card uses)
|
// dstn.to badge list → small icon row (same source the presence card uses)
|
||||||
|
|
@ -107,6 +101,23 @@
|
||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Discord server (clan) tag — the little guild badge + tag next to a name
|
||||||
|
function guildTagBadgeUrl(pg) {
|
||||||
|
if (!pg || !pg.badge || !pg.identity_guild_id) return null;
|
||||||
|
return proxyImg("https://cdn.discordapp.com/guild-tag-badges/" + pg.identity_guild_id + "/" + pg.badge + ".png?size=24");
|
||||||
|
}
|
||||||
|
function renderClanTag(refs, pg) {
|
||||||
|
if (!refs.tag) return;
|
||||||
|
if (pg && pg.tag && pg.identity_enabled) {
|
||||||
|
var b = guildTagBadgeUrl(pg);
|
||||||
|
refs.tag.innerHTML = (b ? '<img class="fc-tag-badge" src="' + b + '" alt="" onerror="this.remove()">' : "") +
|
||||||
|
'<span class="fc-tag-text">' + esc(pg.tag) + "</span>";
|
||||||
|
refs.tag.hidden = false;
|
||||||
|
} else {
|
||||||
|
refs.tag.hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---- build one card -------------------------------------------------
|
// ---- build one card -------------------------------------------------
|
||||||
function buildCard(m) {
|
function buildCard(m) {
|
||||||
var card = document.createElement("article");
|
var card = document.createElement("article");
|
||||||
|
|
@ -124,7 +135,10 @@
|
||||||
'<span class="fc-status" title="not connected to Lanyard"></span>' +
|
'<span class="fc-status" title="not connected to Lanyard"></span>' +
|
||||||
'</span>' +
|
'</span>' +
|
||||||
'<span class="fc-id">' +
|
'<span class="fc-id">' +
|
||||||
|
'<span class="fc-name-row">' +
|
||||||
'<' + nameTag + ' class="fc-name' + (m.tier ? " " + m.tier : "") + '"' + nameAttrs + '>' + esc(m.name) + '</' + nameTag + '>' +
|
'<' + nameTag + ' class="fc-name' + (m.tier ? " " + m.tier : "") + '"' + nameAttrs + '>' + esc(m.name) + '</' + nameTag + '>' +
|
||||||
|
'<span class="fc-tag" hidden></span>' +
|
||||||
|
'</span>' +
|
||||||
'<span class="fc-user"></span>' +
|
'<span class="fc-user"></span>' +
|
||||||
'<span class="fc-badges"></span>' +
|
'<span class="fc-badges"></span>' +
|
||||||
'</span>' +
|
'</span>' +
|
||||||
|
|
@ -135,6 +149,7 @@
|
||||||
pfp: card.querySelector(".fc-pfp"),
|
pfp: card.querySelector(".fc-pfp"),
|
||||||
statusDot: card.querySelector(".fc-status"),
|
statusDot: card.querySelector(".fc-status"),
|
||||||
user: card.querySelector(".fc-user"),
|
user: card.querySelector(".fc-user"),
|
||||||
|
tag: card.querySelector(".fc-tag"),
|
||||||
badges: card.querySelector(".fc-badges"),
|
badges: card.querySelector(".fc-badges"),
|
||||||
banner: card.querySelector(".fc-banner")
|
banner: card.querySelector(".fc-banner")
|
||||||
};
|
};
|
||||||
|
|
@ -163,6 +178,7 @@
|
||||||
refs.statusDot.title = STATUS_TITLE[status] || "Offline";
|
refs.statusDot.title = STATUS_TITLE[status] || "Offline";
|
||||||
if (u.avatar) refs.pfp.src = avatarUrl(u);
|
if (u.avatar) refs.pfp.src = avatarUrl(u);
|
||||||
if (u.username) refs.user.textContent = "@" + u.username;
|
if (u.username) refs.user.textContent = "@" + u.username;
|
||||||
|
renderClanTag(refs, u.primary_guild);
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
|
|
@ -228,7 +244,8 @@
|
||||||
group.members.forEach(function (m) {
|
group.members.forEach(function (m) {
|
||||||
var refs = buildCard(m);
|
var refs = buildCard(m);
|
||||||
grid.appendChild(refs.el);
|
grid.appendChild(refs.el);
|
||||||
if (m.discordId) {
|
// dead alts are banned/retired — never pull live data for them
|
||||||
|
if (m.discordId && m.tier !== "dead-alt") {
|
||||||
liveMembers.push({ m: m, refs: refs });
|
liveMembers.push({ m: m, refs: refs });
|
||||||
refreshMember(m, refs);
|
refreshMember(m, refs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,8 +237,12 @@
|
||||||
// ---- banner / bio / connected accounts (extras for the /discord page) ---
|
// ---- banner / bio / connected accounts (extras for the /discord page) ---
|
||||||
function bannerUrl(id, hash) {
|
function bannerUrl(id, hash) {
|
||||||
if (!id || !hash) return null;
|
if (!id || !hash) return null;
|
||||||
const ext = String(hash).startsWith("a_") ? "gif" : "png";
|
// Animated banners (a_) must be requested WITHOUT the .gif extension:
|
||||||
return proxyImg("https://cdn.discordapp.com/banners/" + id + "/" + hash + "." + ext + "?size=600", { w: 600 });
|
// Discord's CDN throws HTTP 415 for some a_*.gif banners, but the
|
||||||
|
// extension-less URL works (wsrv then re-serves it as cookieless webp).
|
||||||
|
const animated = String(hash).startsWith("a_");
|
||||||
|
const url = "https://cdn.discordapp.com/banners/" + id + "/" + hash + (animated ? "" : ".png") + "?size=600";
|
||||||
|
return proxyImg(url, { w: 600 });
|
||||||
}
|
}
|
||||||
function applyBanner(url, fallbackColor) {
|
function applyBanner(url, fallbackColor) {
|
||||||
if (!bannerEl) return;
|
if (!bannerEl) return;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue