diff --git a/package.json b/package.json index 8240d4f..c272712 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "typescript": "^5.8.2" }, "dependencies": { - "ejs": "^3.1.10" + "ejs": "^3.1.10", + "marked": "^15.0.7" } } diff --git a/public/css/index.css b/public/css/index.css index d6b1db9..9271040 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -230,7 +230,8 @@ ul { } body { - padding: 1rem; + padding: 0; + margin: 0; align-items: stretch; } @@ -301,6 +302,7 @@ ul { align-items: center; text-align: center; padding: 1rem; + border-radius:0; } .activity-art { @@ -329,7 +331,104 @@ ul { .activity-detail { text-align: center; } + + .progress-time-labels { + justify-content: space-between; + font-size: 0.7rem; + margin-top: 0.25rem; + width: 100%; + } } +/* readme :p */ +.readme { + max-width: 600px; + width: 100%; + background: #1a1a1d; + padding: 1.5rem; + border-radius: 8px; + box-shadow: 0 0 0 1px #2e2e30; + box-sizing: border-box; + overflow: hidden; + overflow-y: auto; +} +.readme h2 { + margin-top: 0; + color: #00b0f4; +} + +.markdown-body { + font-size: 1rem; + line-height: 1.6; + color: #ddd; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + color: #ffffff; + margin-top: 1.25rem; + margin-bottom: 0.5rem; +} + +.markdown-body p { + margin: 0.5rem 0; +} + +.markdown-body a { + color: #00b0f4; + text-decoration: none; +} + +.markdown-body a:hover { + text-decoration: underline; +} + +.markdown-body code { + background: #2e2e30; + padding: 0.2em 0.4em; + border-radius: 4px; + font-family: monospace; + color: #f8f8f2; +} + +.markdown-body pre { + background: #2e2e30; + padding: 1rem; + border-radius: 6px; + overflow-x: auto; + font-family: monospace; + color: #f8f8f2; +} + +.markdown-body ul, +.markdown-body ol { + padding-left: 1.5rem; + margin: 0.5rem 0; +} + +.markdown-body blockquote { + border-left: 4px solid #00b0f4; + padding-left: 1rem; + color: #aaa; + margin: 1rem 0; +} + +@media (max-width: 600px) { + .readme { + width: 100%; + padding: 1rem; + + margin-top: 1rem; + border-radius: 0; + } + + .markdown-body { + font-size: 0.95rem; + } +} diff --git a/src/helpers/lanyard.ts b/src/helpers/lanyard.ts index 6592d7b..cac8c75 100644 --- a/src/helpers/lanyard.ts +++ b/src/helpers/lanyard.ts @@ -1,5 +1,6 @@ import { lanyardConfig } from "@config/environment"; import { fetch } from "bun"; +import { marked } from "marked"; export async function getLanyardData(id?: string): Promise { let instance: string = lanyardConfig.instance; @@ -44,3 +45,49 @@ export async function getLanyardData(id?: string): Promise { return data; } + +export async function handleReadMe(data: LanyardData): Promise { + const userReadMe: string | null = data.kv?.readme; + console.log("userReadMe", userReadMe); + + if ( + !userReadMe || + !userReadMe.toLowerCase().endsWith("readme.md") || + !userReadMe.startsWith("http") + ) { + return null; + } + + try { + const res: Response = await fetch(userReadMe, { + headers: { + Accept: "text/markdown", + }, + }); + + const contentType: string = res.headers.get("content-type") || ""; + if ( + !res.ok || + !( + contentType.includes("text/markdown") || + contentType.includes("text/plain") + ) + ) + return null; + + if (res.headers.has("content-length")) { + const size: number = parseInt( + res.headers.get("content-length") || "0", + 10, + ); + if (size > 1024 * 100) return null; + } + + const text: string = await res.text(); + if (!text || text.length < 10) return null; + + return marked.parse(text); + } catch { + return null; + } +} diff --git a/src/routes/[id].ts b/src/routes/[id].ts index e43c73d..30412e9 100644 --- a/src/routes/[id].ts +++ b/src/routes/[id].ts @@ -1,6 +1,6 @@ import { lanyardConfig } from "@config/environment"; import { renderEjsTemplate } from "@helpers/ejs"; -import { getLanyardData } from "@helpers/lanyard"; +import { getLanyardData, handleReadMe } from "@helpers/lanyard"; const routeDef: RouteDef = { method: "GET", @@ -14,7 +14,7 @@ async function handler(request: ExtendedRequest): Promise { if (!data.success) { return await renderEjsTemplate("error", { - message: "User not found or Lanyard data unavailable.", + message: data.error.message, }); } @@ -29,20 +29,22 @@ async function handler(request: ExtendedRequest): Promise { } const presence: LanyardData = data.data; + const readme: string | Promise | null = + await handleReadMe(presence); + const ejsTemplateData: EjsTemplateData = { title: "User Page", username: presence.discord_user.username, status: presence.discord_status, activities: presence.activities, user: presence.discord_user, - platform: { desktop: presence.active_on_discord_desktop, mobile: presence.active_on_discord_mobile, web: presence.active_on_discord_web, }, - - instance: instance, + instance, + readme, }; return await renderEjsTemplate("index", ejsTemplateData); diff --git a/src/routes/index.ts b/src/routes/index.ts index d9da07b..6603493 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,6 +1,6 @@ import { lanyardConfig } from "@config/environment"; import { renderEjsTemplate } from "@helpers/ejs"; -import { getLanyardData } from "@helpers/lanyard"; +import { getLanyardData, handleReadMe } from "@helpers/lanyard"; const routeDef: RouteDef = { method: "GET", @@ -12,8 +12,8 @@ async function handler(): Promise { const data: LanyardResponse = await getLanyardData(); if (!data.success) { - return Response.json(data.error, { - status: 500, + return await renderEjsTemplate("error", { + message: data.error.message, }); } @@ -28,20 +28,22 @@ async function handler(): Promise { } const presence: LanyardData = data.data; + const readme: string | Promise | null = + await handleReadMe(presence); + const ejsTemplateData: EjsTemplateData = { title: "User Page", username: presence.discord_user.username, status: presence.discord_status, activities: presence.activities, user: presence.discord_user, - platform: { desktop: presence.active_on_discord_desktop, mobile: presence.active_on_discord_mobile, web: presence.active_on_discord_web, }, - - instance: instance, + instance, + readme, }; return await renderEjsTemplate("index", ejsTemplateData); diff --git a/src/views/index.ejs b/src/views/index.ejs index e95c0ff..a77b12a 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -3,6 +3,11 @@ + + + + + <%= title %> @@ -99,7 +104,7 @@ <% if (progress !== null) { %>
-
+
>
<% if (start && end) { %> @@ -114,5 +119,11 @@ <% }) %> <% } %> + <% if (readme) { %> +

Readme

+
+
<%- readme %>
+
+ <% } %>