This commit is contained in:
Clove 2026-06-16 22:52:45 +01:00
parent a801609eb9
commit 808207bbeb
6 changed files with 107 additions and 5 deletions

View File

@ -2093,6 +2093,25 @@ a.fc-name:hover { color: rgb(var(--accent-rgb)); }
}
.fc-user:empty { display: none; }
/* custom status (Discord activity type 4) */
.fc-custom {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.72rem;
color: var(--subtext-1);
margin-top: 0.1rem;
min-width: 0;
}
.fc-custom[hidden] { display: none; }
.fc-custom-emoji { width: 14px; height: 14px; display: block; flex: none; }
.fc-custom-emoji-uni { font-size: 0.8rem; line-height: 1; flex: none; }
.fc-custom-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.fc-badges {
display: inline-flex;
align-items: center;
@ -2923,6 +2942,33 @@ html[data-theme] body.api-body {
}
.pc-user:empty { display: none; }
/* status word (Online / Idle / Do Not Disturb / Offline) */
.pc-status-text {
font-size: 0.7rem;
font-weight: 600;
white-space: nowrap;
color: var(--overlay-1);
}
.pc-status-text:empty { display: none; }
.pc-status-text::before {
content: "";
display: inline-block;
width: 7px;
height: 7px;
border-radius: 50%;
margin-right: 0.3rem;
vertical-align: baseline;
background: var(--overlay-0);
}
.presence-card[data-status="online"] .pc-status-text { color: var(--green); }
.presence-card[data-status="online"] .pc-status-text::before { background: var(--green); }
.presence-card[data-status="idle"] .pc-status-text { color: var(--yellow); }
.presence-card[data-status="idle"] .pc-status-text::before { background: var(--yellow); }
.presence-card[data-status="dnd"] .pc-status-text { color: var(--red); }
.presence-card[data-status="dnd"] .pc-status-text::before { background: var(--red); }
.presence-card[data-status="offline"] .pc-status-text { color: var(--overlay-1); }
.presence-card[data-status="offline"] .pc-status-text::before { background: var(--overlay-0); }
/* ---- expandable sections ---- */
.pc-sections {
display: flex;

View File

@ -64,7 +64,7 @@
</header>
<!-- ============ GIRLS-NETWORK ============ -->
<section class="section">
<section class="section" id="girls-network">
<h2 class="section-title">Girls-Network</h2>
<div class="bot-grid">
@ -96,7 +96,7 @@
</section>
<!-- ============ MY BOTS (doughmination) ============ -->
<section class="section">
<section class="section" id="my-bots">
<h2 class="section-title">My Bots</h2>
<div class="bot-grid">
@ -160,7 +160,7 @@
</section>
<!-- ============ TOOLS ============ -->
<section class="section">
<section class="section" id="tools">
<h2 class="section-title">Tools</h2>
<div class="bot-grid">

View File

@ -291,4 +291,29 @@
} else {
init();
}
// ---- anchor links: open the targeted <details> and scroll to it --------
// Sections are collapsible (and some are populated/un-hidden async), so a
// plain #hash won't reliably reveal them. Open + scroll on load and on
// hashchange, retrying briefly while late content settles in.
function openFromHash() {
var id = (location.hash || "").slice(1);
if (!id) return;
var attempts = 0;
(function tryOpen() {
var target = document.getElementById(id);
if (target && !target.hidden) {
if (target.tagName === "DETAILS") target.open = true;
target.scrollIntoView();
return;
}
if (attempts++ < 10) setTimeout(tryOpen, 200);
})();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", openFromHash);
} else {
openFromHash();
}
window.addEventListener("hashchange", openFromHash);
})();

View File

@ -97,6 +97,30 @@
return proxyImg(url, { w: 480 });
}
// custom-status emoji → CDN url (custom emoji) or null (unicode emoji)
function customEmojiUrl(e) {
if (!e || !e.id) return null;
return proxyImg("https://cdn.discordapp.com/emojis/" + e.id + (e.animated ? ".gif" : ".png") + "?size=32");
}
// Render the Discord custom status (activity type 4): emoji + text.
function renderCustomStatus(refs, activities) {
if (!refs.custom) return;
var c = (activities || []).find(function (a) { return a && a.type === 4; });
var text = c && c.state ? String(c.state) : "";
var emoji = c && c.emoji;
if (!text && !(emoji && (emoji.id || emoji.name))) {
refs.custom.hidden = true;
refs.custom.innerHTML = "";
return;
}
var eu = emoji ? customEmojiUrl(emoji) : null;
var emojiHtml = eu
? '<img class="fc-custom-emoji" src="' + eu + '" alt="" onerror="this.remove()">'
: (emoji && emoji.name ? '<span class="fc-custom-emoji-uni">' + esc(emoji.name) + "</span>" : "");
refs.custom.innerHTML = emojiHtml + (text ? '<span class="fc-custom-text">' + esc(text) + "</span>" : "");
refs.custom.hidden = false;
}
// dstn.to badge list → small icon row (same source the presence card uses)
function renderDstnBadges(badges) {
if (!Array.isArray(badges)) return "";
@ -150,6 +174,7 @@
'<span class="fc-tag" hidden></span>' +
'</span>' +
'<span class="fc-user"></span>' +
'<span class="fc-custom" hidden></span>' +
'<span class="fc-badges"></span>' +
'</span>' +
'</div>';
@ -159,6 +184,7 @@
pfp: card.querySelector(".fc-pfp"),
statusDot: card.querySelector(".fc-status"),
user: card.querySelector(".fc-user"),
custom: card.querySelector(".fc-custom"),
tag: card.querySelector(".fc-tag"),
badges: card.querySelector(".fc-badges"),
banner: card.querySelector(".fc-banner")
@ -188,6 +214,7 @@
refs.statusDot.title = STATUS_TITLE[status] || "Offline";
if (u.avatar) refs.pfp.src = avatarUrl(u);
if (u.username) refs.user.textContent = "@" + u.username;
renderCustomStatus(refs, d.activities);
renderClanTag(refs, u.primary_guild);
return true;
})

View File

@ -51,6 +51,7 @@
'</span>' +
'<span class="pc-sub-row">' +
'<span class="pc-user"></span>' +
'<span class="pc-status-text"></span>' +
'<span class="pc-pronouns" hidden></span>' +
'<span class="pc-platforms" aria-hidden="true"></span>' +
'</span>' +
@ -71,6 +72,8 @@
const tagEl = card.querySelector(".pc-tag");
const userEl = card.querySelector(".pc-user");
const platformsEl = card.querySelector(".pc-platforms");
const statusTextEl = card.querySelector(".pc-status-text");
const STATUS_TITLE = { online: "Online", idle: "Idle", dnd: "Do Not Disturb", offline: "Offline" };
const metaEl = card.querySelector(".pc-meta");
const badgesEl = card.querySelector(".pc-badges");
const sections = card.querySelector(".pc-sections");
@ -505,6 +508,7 @@
const u = d.discord_user || {};
const status = d.discord_status || "offline";
card.dataset.status = status;
if (statusTextEl) statusTextEl.textContent = STATUS_TITLE[status] || "Offline";
avImg.src = avatarUrl(u);
const deco = u.avatar_decoration_data;

View File

@ -62,14 +62,14 @@
</a>
<!-- lyrics -->
<div class="sec-row">
<div class="sec-row" id="lyrics-section">
<h2 class="sec-title">Lyrics</h2>
<button class="ly-lock is-locked" id="ly-lock" type="button" aria-pressed="true" hidden><span class="ly-bars" aria-hidden="true"><i></i><i></i><i></i><i></i></span><span class="ly-lock-label">Synced</span></button>
</div>
<div class="lyrics is-empty" id="lyrics"><p class="ly-note">Waiting for a track…</p></div>
<!-- recently played -->
<h2 class="sec-title">Recently played</h2>
<h2 class="sec-title" id="recently-played">Recently played</h2>
<ul class="recent" id="recent"></ul>
<!-- top artists (hidden until Last.fm data arrives) -->