diff --git a/public/css/index.css b/public/css/index.css index 59e3a37..7a1a288 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1,7 +1,38 @@ +:root { + --background: #0e0e10; + --card-bg: #1e1f22; + --card-hover-bg: #2a2a2d; + --border-color: #2e2e30; + + --text-color: #ffffff; + --text-subtle: #bbb; + --text-secondary: #b5bac1; + --text-muted: #888; + --link-color: #00b0f4; + + --status-online: #23a55a; + --status-idle: #f0b232; + --status-dnd: #e03e3e; + --status-offline: #747f8d; + --status-streaming: #b700ff; + + --progress-bg: #f23f43; + --progress-fill: #5865f2; + + --button-bg: #5865f2; + --button-hover-bg: #4752c4; + --button-disabled-bg: #2d2e31; + + --blockquote-color: #aaa; + --code-bg: #2e2e30; + + --readme-bg: #1a1a1d; +} + body { font-family: system-ui, sans-serif; - background-color: #0e0e10; - color: #ffffff; + background-color: var(--background); + color: var(--text-color); margin: 0; padding: 2rem; display: flex; @@ -52,26 +83,30 @@ body { width: 24px; height: 24px; border-radius: 50%; - border: 4px solid #0e0e10; + border: 4px solid var(--background); display: flex; align-items: center; justify-content: center; } .status-indicator.online { - background-color: #23a55a; + background-color: var(--status-online); } .status-indicator.idle { - background-color: #f0b232; + background-color: var(--status-idle); } .status-indicator.dnd { - background-color: #f23f43; + background-color: var(--status-dnd); } .status-indicator.offline { - background-color: #747f8d; + background-color: var(--status-offline); +} + +.status-indicator.streaming { + background-color: var(--status-streaming); } .platform-icon.mobile-only { @@ -91,12 +126,12 @@ body { h1 { font-size: 2.5rem; margin: 0; - color: #00b0f4; + color: var(--link-color); } .custom-status { font-size: 1.2rem; - color: #bbb; + color: var(--text-subtle); margin-top: 0.25rem; word-break: break-word; overflow-wrap: anywhere; @@ -141,14 +176,14 @@ ul { display: flex; flex-direction: row; gap: 1rem; - background-color: #1e1f22; + background-color: var(--card-bg); padding: 0.75rem 1rem; border-radius: 10px; - box-shadow: 0 1px 0 0 #2e2e30; + border: 1px solid var(--border-color); } .activity:hover { - background: #2a2a2d; + background: var(--card-hover-bg); } .activity-wrapper { @@ -163,7 +198,28 @@ ul { gap: 1rem; } -.activity-art { +.activity-image-wrapper { + position: relative; + width: 80px; + height: 80px; +} + +.activity-image-small { + width: 25px; + height: 25px; + border-radius: 50%; + object-fit: cover; + flex-shrink: 0; + border-color: var(--card-bg); + border-width: 2px; + border-style: solid; + + position: absolute; + bottom: -6px; + right: -10px; +} + +.activity-image { width: 80px; height: 80px; border-radius: 6px; @@ -201,17 +257,17 @@ ul { .activity-name { font-weight: 600; font-size: 1rem; - color: #fff; + color: var(--text-color); } .activity-detail { font-size: 0.875rem; - color: #b5bac1; + color: var(--text-secondary); } .activity-timestamp { font-size: 0.75rem; - color: #b5bac1; + color: var(--text-secondary); text-align: right; margin-left: auto; white-space: nowrap; @@ -219,14 +275,14 @@ ul { .progress-bar { height: 4px; - background-color: #2e2e30; + background-color: var(--border-color); border-radius: 2px; - margin-top: 0.5rem; + margin-top: 1rem; overflow: hidden; } .progress-fill { - background-color: #5865f2; + background-color: var(--progress-fill); transition: width 0.4s ease; height: 100%; } @@ -234,14 +290,13 @@ ul { .progress-bar, .progress-time-labels { width: 100%; - margin-top: 0.5rem; } .progress-time-labels { display: flex; justify-content: space-between; font-size: 0.75rem; - color: #888; + color: var(--text-muted); margin-top: 0.25rem; } @@ -255,7 +310,7 @@ ul { font-size: 0.75rem; text-transform: uppercase; font-weight: 600; - color: #aaa; + color: var(--blockquote-color); margin-bottom: 0.50rem; display: block; } @@ -266,7 +321,7 @@ ul { .progress-time-labels.paused .progress-current::after { content: " ⏸"; - color: #f0b232; + color: var(--status-idle); } .activity-buttons { @@ -277,7 +332,7 @@ ul { } .activity-button { - background-color: #5865f2; + background-color: var(--progress-fill); color: white; border: none; border-radius: 3px; @@ -290,12 +345,12 @@ ul { } .activity-button:hover { - background-color: #4752c4; + background-color: var(--button-hover-bg); text-decoration: none; } .activity-button:disabled { - background-color: #2d2e31; + background-color: var(--button-disabled-bg); cursor: not-allowed; opacity: 0.8; } @@ -324,6 +379,13 @@ ul { width: 100%; } + .activity-image-wrapper { + max-width: 100%; + max-height: 100%; + width: 100%; + height: 100%; + } + .avatar-wrapper { width: 96px; height: 96px; @@ -381,18 +443,28 @@ ul { border-radius: 0; } - .activity-art { + .activity-image { width: 100%; - max-width: 300px; + max-width: 100%; height: auto; border-radius: 8px; } + .activity-image-small { + width: 40px; + height: 40px; + } + .activity-content { width: 100%; align-items: center; } + .activity-wrapper-inner { + flex-direction: column; + align-items: center; + } + .activity-header { flex-direction: column; align-items: center; @@ -429,12 +501,12 @@ ul { /* readme :p */ .readme { - max-width: 600px; + max-width: 700px; width: 100%; - background: #1a1a1d; + background: var(--readme-bg); padding: 1.5rem; border-radius: 8px; - box-shadow: 0 0 0 1px #2e2e30; + border: 1px solid var(--border-color); margin-top: 2rem; @@ -445,13 +517,13 @@ ul { .readme h2 { margin-top: 0; - color: #00b0f4; + color: var(--link-color); } .markdown-body { font-size: 1rem; line-height: 1.6; - color: #ddd; + color: var(--text-color); } .markdown-body h1, @@ -460,7 +532,7 @@ ul { .markdown-body h4, .markdown-body h5, .markdown-body h6 { - color: #ffffff; + color: var(--text-color); margin-top: 1.25rem; margin-bottom: 0.5rem; } @@ -470,7 +542,7 @@ ul { } .markdown-body a { - color: #00b0f4; + color: var(--link-color); text-decoration: none; } @@ -479,7 +551,7 @@ ul { } .markdown-body code { - background: #2e2e30; + background: var(--border-color); padding: 0.2em 0.4em; border-radius: 4px; font-family: monospace; @@ -487,7 +559,7 @@ ul { } .markdown-body pre { - background: #2e2e30; + background: var(--border-color); padding: 1rem; border-radius: 6px; overflow-x: auto; @@ -502,9 +574,9 @@ ul { } .markdown-body blockquote { - border-left: 4px solid #00b0f4; + border-left: 4px solid var(--link-color); padding-left: 1rem; - color: #aaa; + color: var(--blockquote-color); margin: 1rem 0; } diff --git a/public/js/index.js b/public/js/index.js index 913773e..e6a9afe 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -130,6 +130,25 @@ if (userId && instanceUri) { }); } +function resolveActivityImage(img, applicationId) { + if (!img) return null; + + if (img.startsWith("mp:external/")) { + return `https://media.discordapp.net/external/${img.slice("mp:external/".length)}`; + } + + if (img.includes("/https/")) { + const clean = img.split("/https/")[1]; + return clean ? `https://${clean}` : null; + } + + if (img.startsWith("spotify:")) { + return `https://i.scdn.co/image/${img.split(":")[1]}`; + } + + return `https://cdn.discordapp.com/app-assets/${applicationId}/${img}.png`; +} + function buildActivityHTML(activity) { const start = activity.timestamps?.start; const end = activity.timestamps?.end; @@ -141,18 +160,18 @@ function buildActivityHTML(activity) { ? Math.min(100, Math.floor((elapsed / total) * 100)) : null; - const img = activity.assets?.large_image; let art = null; + let smallArt = null; - if (img?.startsWith("mp:external/")) { - art = `https://media.discordapp.net/external/${img.slice("mp:external/".length)}`; - } else if (img?.includes("/https/")) { - const clean = img.split("/https/")[1]; - if (clean) art = `https://${clean}`; - } else if (img?.startsWith("spotify:")) { - art = `https://i.scdn.co/image/${img.split(":")[1]}`; - } else if (img) { - art = `https://cdn.discordapp.com/app-assets/${activity.application_id}/${img}.png`; + if (activity.assets) { + art = resolveActivityImage( + activity.assets.large_image, + activity.application_id, + ); + smallArt = resolveActivityImage( + activity.assets.small_image, + activity.application_id, + ); } const activityTypeMap = { @@ -220,6 +239,13 @@ function buildActivityHTML(activity) { const secondaryLine = isMusic ? activity.state : activity.details; const tertiaryLine = isMusic ? activity.assets?.large_text : activity.state; + const activityArt = art + ? `
+ Art + ${smallArt ? `Small Art` : ""} +
` + : ""; + return `
  • @@ -228,7 +254,7 @@ function buildActivityHTML(activity) { ${activityTimestamp}
    - ${art ? `Art` : ""} + ${activityArt}
    @@ -264,8 +290,16 @@ function updatePresence(data) { desktop: data.active_on_discord_desktop, }; + let status = "offline"; + console.log(data.activities.some((activity) => activity.type === 1)); + if (data.activities.some((activity) => activity.type === 1)) { + status = "streaming"; + } else { + status = data.discord_status; + } + if (statusIndicator) { - statusIndicator.className = `status-indicator ${data.discord_status}`; + statusIndicator.className = `status-indicator ${status}`; } if (platform.mobile && !mobileIcon) { @@ -276,7 +310,7 @@ function updatePresence(data) { `; } else if (!platform.mobile && mobileIcon) { mobileIcon.remove(); - avatarWrapper.innerHTML += `
    `; + avatarWrapper.innerHTML += `
    `; } const custom = data.activities?.find((a) => a.type === 4); diff --git a/src/routes/[id].ts b/src/routes/[id].ts index b970485..bdfc975 100644 --- a/src/routes/[id].ts +++ b/src/routes/[id].ts @@ -31,10 +31,18 @@ async function handler(request: ExtendedRequest): Promise { const presence: LanyardData = data.data; const readme: string | Promise | null = await handleReadMe(presence); + let status: string; + if (presence.activities.some((activity) => activity.type === 1)) { + status = "streaming"; + } else { + status = presence.discord_status; + } + const ejsTemplateData: EjsTemplateData = { - title: `${presence.discord_user.username || "Unknown"}`, - username: presence.discord_user.username, - status: presence.discord_status, + title: presence.discord_user.global_name || presence.discord_user.username, + username: + presence.discord_user.global_name || presence.discord_user.username, + status: status, activities: presence.activities, user: presence.discord_user, platform: { diff --git a/src/routes/index.ts b/src/routes/index.ts index faa9e61..829d105 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -30,11 +30,18 @@ async function handler(): Promise { const presence: LanyardData = data.data; const readme: string | Promise | null = await handleReadMe(presence); + let status: string; + if (presence.activities.some((activity) => activity.type === 1)) { + status = "streaming"; + } else { + status = presence.discord_status; + } + const ejsTemplateData: EjsTemplateData = { title: presence.discord_user.global_name || presence.discord_user.username, username: presence.discord_user.global_name || presence.discord_user.username, - status: presence.discord_status, + status: status, activities: presence.activities, user: presence.discord_user, platform: { diff --git a/src/views/index.ejs b/src/views/index.ejs index 4b1e1bb..0611579 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -76,20 +76,32 @@ const total = (start && end) ? end - start : null; const progress = (total && elapsed > 0) ? Math.min(100, Math.floor((elapsed / total) * 100)) : null; - const img = activity.assets?.large_image; let art = null; + let smallArt = null; - if (img?.startsWith("mp:external/")) { - art = `https://media.discordapp.net/external/${img.slice("mp:external/".length)}`; - } else if (img?.includes("/https/")) { - const clean = img.split("/https/")[1]; - if (clean) art = `https://${clean}`; - } else if (img?.startsWith("spotify:")) { - art = `https://i.scdn.co/image/${img.split(":")[1]}`; - } else if (img) { - art = `https://cdn.discordapp.com/app-assets/${activity.application_id}/${img}.png`; + function resolveActivityImage(img, applicationId) { + if (!img) return null; + + if (img.startsWith("mp:external/")) { + return `https://media.discordapp.net/external/${img.slice("mp:external/".length)}`; + } + + if (img.includes("/https/")) { + const clean = img.split("/https/")[1]; + return clean ? `https://${clean}` : null; + } + + if (img.startsWith("spotify:")) { + return `https://i.scdn.co/image/${img.split(":")[1]}`; + } + + return `https://cdn.discordapp.com/app-assets/${applicationId}/${img}.png`; } + if (activity.assets) { + art = resolveActivityImage(activity.assets.large_image, activity.application_id); + smallArt = resolveActivityImage(activity.assets.small_image, activity.application_id); + } const activityTypeMap = { 0: "Playing", @@ -124,7 +136,12 @@
    <% if (art) { %> - Art +
    + Art> + <% if (smallArt) { %> + Small Art> + <% } %> +
    <% } %>