statuses
This commit is contained in:
parent
a801609eb9
commit
808207bbeb
46
css/main.css
46
css/main.css
|
|
@ -2093,6 +2093,25 @@ a.fc-name:hover { color: rgb(var(--accent-rgb)); }
|
||||||
}
|
}
|
||||||
.fc-user:empty { display: none; }
|
.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 {
|
.fc-badges {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -2923,6 +2942,33 @@ html[data-theme] body.api-body {
|
||||||
}
|
}
|
||||||
.pc-user:empty { display: none; }
|
.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 ---- */
|
/* ---- expandable sections ---- */
|
||||||
.pc-sections {
|
.pc-sections {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- ============ GIRLS-NETWORK ============ -->
|
<!-- ============ GIRLS-NETWORK ============ -->
|
||||||
<section class="section">
|
<section class="section" id="girls-network">
|
||||||
<h2 class="section-title">Girls-Network</h2>
|
<h2 class="section-title">Girls-Network</h2>
|
||||||
<div class="bot-grid">
|
<div class="bot-grid">
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- ============ MY BOTS (doughmination) ============ -->
|
<!-- ============ MY BOTS (doughmination) ============ -->
|
||||||
<section class="section">
|
<section class="section" id="my-bots">
|
||||||
<h2 class="section-title">My Bots</h2>
|
<h2 class="section-title">My Bots</h2>
|
||||||
<div class="bot-grid">
|
<div class="bot-grid">
|
||||||
|
|
||||||
|
|
@ -160,7 +160,7 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- ============ TOOLS ============ -->
|
<!-- ============ TOOLS ============ -->
|
||||||
<section class="section">
|
<section class="section" id="tools">
|
||||||
<h2 class="section-title">Tools</h2>
|
<h2 class="section-title">Tools</h2>
|
||||||
<div class="bot-grid">
|
<div class="bot-grid">
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -291,4 +291,29 @@
|
||||||
} else {
|
} else {
|
||||||
init();
|
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);
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,30 @@
|
||||||
return proxyImg(url, { w: 480 });
|
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)
|
// dstn.to badge list → small icon row (same source the presence card uses)
|
||||||
function renderDstnBadges(badges) {
|
function renderDstnBadges(badges) {
|
||||||
if (!Array.isArray(badges)) return "";
|
if (!Array.isArray(badges)) return "";
|
||||||
|
|
@ -150,6 +174,7 @@
|
||||||
'<span class="fc-tag" hidden></span>' +
|
'<span class="fc-tag" hidden></span>' +
|
||||||
'</span>' +
|
'</span>' +
|
||||||
'<span class="fc-user"></span>' +
|
'<span class="fc-user"></span>' +
|
||||||
|
'<span class="fc-custom" hidden></span>' +
|
||||||
'<span class="fc-badges"></span>' +
|
'<span class="fc-badges"></span>' +
|
||||||
'</span>' +
|
'</span>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
@ -159,6 +184,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"),
|
||||||
|
custom: card.querySelector(".fc-custom"),
|
||||||
tag: card.querySelector(".fc-tag"),
|
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")
|
||||||
|
|
@ -188,6 +214,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;
|
||||||
|
renderCustomStatus(refs, d.activities);
|
||||||
renderClanTag(refs, u.primary_guild);
|
renderClanTag(refs, u.primary_guild);
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
'</span>' +
|
'</span>' +
|
||||||
'<span class="pc-sub-row">' +
|
'<span class="pc-sub-row">' +
|
||||||
'<span class="pc-user"></span>' +
|
'<span class="pc-user"></span>' +
|
||||||
|
'<span class="pc-status-text"></span>' +
|
||||||
'<span class="pc-pronouns" hidden></span>' +
|
'<span class="pc-pronouns" hidden></span>' +
|
||||||
'<span class="pc-platforms" aria-hidden="true"></span>' +
|
'<span class="pc-platforms" aria-hidden="true"></span>' +
|
||||||
'</span>' +
|
'</span>' +
|
||||||
|
|
@ -71,6 +72,8 @@
|
||||||
const tagEl = card.querySelector(".pc-tag");
|
const tagEl = card.querySelector(".pc-tag");
|
||||||
const userEl = card.querySelector(".pc-user");
|
const userEl = card.querySelector(".pc-user");
|
||||||
const platformsEl = card.querySelector(".pc-platforms");
|
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 metaEl = card.querySelector(".pc-meta");
|
||||||
const badgesEl = card.querySelector(".pc-badges");
|
const badgesEl = card.querySelector(".pc-badges");
|
||||||
const sections = card.querySelector(".pc-sections");
|
const sections = card.querySelector(".pc-sections");
|
||||||
|
|
@ -505,6 +508,7 @@
|
||||||
const u = d.discord_user || {};
|
const u = d.discord_user || {};
|
||||||
const status = d.discord_status || "offline";
|
const status = d.discord_status || "offline";
|
||||||
card.dataset.status = status;
|
card.dataset.status = status;
|
||||||
|
if (statusTextEl) statusTextEl.textContent = STATUS_TITLE[status] || "Offline";
|
||||||
|
|
||||||
avImg.src = avatarUrl(u);
|
avImg.src = avatarUrl(u);
|
||||||
const deco = u.avatar_decoration_data;
|
const deco = u.avatar_decoration_data;
|
||||||
|
|
|
||||||
|
|
@ -62,14 +62,14 @@
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- lyrics -->
|
<!-- lyrics -->
|
||||||
<div class="sec-row">
|
<div class="sec-row" id="lyrics-section">
|
||||||
<h2 class="sec-title">Lyrics</h2>
|
<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>
|
<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>
|
||||||
<div class="lyrics is-empty" id="lyrics"><p class="ly-note">Waiting for a track…</p></div>
|
<div class="lyrics is-empty" id="lyrics"><p class="ly-note">Waiting for a track…</p></div>
|
||||||
|
|
||||||
<!-- recently played -->
|
<!-- 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>
|
<ul class="recent" id="recent"></ul>
|
||||||
|
|
||||||
<!-- top artists (hidden until Last.fm data arrives) -->
|
<!-- top artists (hidden until Last.fm data arrives) -->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue