403 lines
9.3 KiB
HTML
403 lines
9.3 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Archive Status Preview</title>
|
|
<style>
|
|
:root {
|
|
color-scheme: dark;
|
|
--page: #1e1f22;
|
|
--channel: #313338;
|
|
--message: #2b2d31;
|
|
--text: #dbdee1;
|
|
--muted: #949ba4;
|
|
--link: #00a8fc;
|
|
--border: #3f4147;
|
|
--green: #10b981;
|
|
--orange: #f59e0b;
|
|
--red: #ef4444;
|
|
--gray: #6b7280;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--page);
|
|
color: var(--text);
|
|
font: 14px/1.45 system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
|
|
}
|
|
|
|
main {
|
|
width: min(980px, calc(100vw - 32px));
|
|
margin: 0 auto;
|
|
padding: 32px 0;
|
|
}
|
|
|
|
h1 {
|
|
margin: 0 0 16px;
|
|
font-size: 20px;
|
|
font-weight: 650;
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
.channel {
|
|
background: var(--channel);
|
|
border: 1px solid #26272b;
|
|
border-radius: 8px;
|
|
min-height: 560px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.channel-header {
|
|
height: 48px;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 16px;
|
|
border-bottom: 1px solid #26272b;
|
|
color: #f2f3f5;
|
|
font-weight: 650;
|
|
}
|
|
|
|
.message {
|
|
display: grid;
|
|
grid-template-columns: 40px 1fr;
|
|
gap: 12px;
|
|
padding: 20px 18px;
|
|
}
|
|
|
|
.avatar {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
background: #5865f2;
|
|
display: grid;
|
|
place-items: center;
|
|
color: #fff;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.message-meta {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 8px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.author {
|
|
color: #f2f3f5;
|
|
font-weight: 650;
|
|
}
|
|
|
|
.bot-tag {
|
|
padding: 1px 4px;
|
|
border-radius: 3px;
|
|
background: #5865f2;
|
|
color: #fff;
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.time {
|
|
color: var(--muted);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.embeds {
|
|
display: grid;
|
|
gap: 8px;
|
|
max-width: 560px;
|
|
}
|
|
|
|
.embed {
|
|
position: relative;
|
|
background: var(--message);
|
|
border: 1px solid var(--border);
|
|
border-radius: 4px;
|
|
padding: 10px 12px 10px 16px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.embed::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0 auto 0 0;
|
|
width: 4px;
|
|
background: var(--embed-color, var(--gray));
|
|
}
|
|
|
|
.embed-title {
|
|
margin: 0 0 6px;
|
|
color: #f2f3f5;
|
|
font-size: 14px;
|
|
font-weight: 650;
|
|
}
|
|
|
|
.embed-description {
|
|
margin: 0;
|
|
white-space: pre-line;
|
|
color: var(--text);
|
|
}
|
|
|
|
.embed-description a {
|
|
color: var(--link);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.embed-description a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.embed-footer {
|
|
margin-top: 8px;
|
|
color: var(--muted);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.embed-fields {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
|
|
gap: 12px;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.embed-field {
|
|
grid-column: span 2;
|
|
}
|
|
|
|
.embed-field.inline {
|
|
grid-column: span 1;
|
|
}
|
|
|
|
.embed-field-name {
|
|
color: #f2f3f5;
|
|
font-weight: 650;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.embed-field-value {
|
|
color: var(--text);
|
|
white-space: pre-line;
|
|
}
|
|
|
|
.embed-field-value a {
|
|
color: var(--link);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.embed-field-value a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.controls {
|
|
display: grid;
|
|
gap: 8px;
|
|
margin-top: 18px;
|
|
max-width: 560px;
|
|
}
|
|
|
|
label {
|
|
color: var(--muted);
|
|
font-weight: 600;
|
|
}
|
|
|
|
textarea {
|
|
width: 100%;
|
|
min-height: 220px;
|
|
resize: vertical;
|
|
border: 1px solid #3f4147;
|
|
border-radius: 6px;
|
|
background: #232428;
|
|
color: var(--text);
|
|
padding: 10px;
|
|
font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
}
|
|
|
|
button {
|
|
justify-self: start;
|
|
border: 1px solid #4e5058;
|
|
border-radius: 6px;
|
|
background: #404249;
|
|
color: #fff;
|
|
padding: 8px 12px;
|
|
font-weight: 650;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button:hover {
|
|
background: #4e5058;
|
|
}
|
|
|
|
.error {
|
|
color: #fca5a5;
|
|
min-height: 20px;
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
main {
|
|
width: 100%;
|
|
padding: 0;
|
|
}
|
|
|
|
h1 {
|
|
padding: 16px;
|
|
margin: 0;
|
|
}
|
|
|
|
.channel {
|
|
border-left: 0;
|
|
border-right: 0;
|
|
border-radius: 0;
|
|
}
|
|
|
|
.embeds,
|
|
.controls {
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>Archive Status Preview</h1>
|
|
|
|
<section class="channel" aria-label="Discord status channel preview">
|
|
<div class="channel-header"># status</div>
|
|
<article class="message">
|
|
<div class="avatar">A</div>
|
|
<div>
|
|
<div class="message-meta">
|
|
<span class="author">Archive Status</span>
|
|
<span class="bot-tag">BOT</span>
|
|
<span class="time">Today at 9:03 PM</span>
|
|
</div>
|
|
<div id="embeds" class="embeds"></div>
|
|
<div class="controls">
|
|
<label for="payload">Preview payload</label>
|
|
<textarea id="payload" spellcheck="false"></textarea>
|
|
<button type="button" id="render">Render payload</button>
|
|
<div id="error" class="error" role="status"></div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
</main>
|
|
|
|
<script>
|
|
const samplePayload = {
|
|
content: "",
|
|
embeds: [
|
|
{
|
|
title: "The Mithral Archive",
|
|
description: "🟡 Degraded · 5/6 online · 1 service needs attention",
|
|
color: 16096779,
|
|
fields: [
|
|
{
|
|
name: "Service",
|
|
value: "**Portal**\n**Jellyfin**\n**Navidrome**\n**Voting Hub**\n**Forgejo**\n**Support**",
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Status",
|
|
value: "🟢 Online\n🟢 Online\n🟢 Online\n🟢 Online\n🟢 Online\n🔴 Issue",
|
|
inline: true
|
|
}
|
|
],
|
|
footer: { text: "Refreshes every 60s • Last checked 2026-05-14 01:56:29 UTC" }
|
|
}
|
|
]
|
|
};
|
|
|
|
const embedsEl = document.querySelector("#embeds");
|
|
const payloadEl = document.querySelector("#payload");
|
|
const errorEl = document.querySelector("#error");
|
|
|
|
function colorToHex(value) {
|
|
const number = Number(value);
|
|
if (!Number.isFinite(number)) return "#6b7280";
|
|
return `#${number.toString(16).padStart(6, "0").slice(-6)}`;
|
|
}
|
|
|
|
function renderMarkdownLinks(text) {
|
|
const escaped = text
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">");
|
|
|
|
return escaped
|
|
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
|
.replace(/\[([^\]]+)]\((https?:\/\/[^)\s]+)\)/g, '<a href="$2">$1</a>');
|
|
}
|
|
|
|
function render(payload) {
|
|
embedsEl.innerHTML = "";
|
|
const embeds = Array.isArray(payload.embeds) ? payload.embeds : [];
|
|
|
|
embeds.forEach((embed) => {
|
|
const article = document.createElement("section");
|
|
article.className = "embed";
|
|
article.style.setProperty("--embed-color", colorToHex(embed.color));
|
|
|
|
const title = document.createElement("h2");
|
|
title.className = "embed-title";
|
|
title.textContent = embed.title || "Untitled";
|
|
article.append(title);
|
|
|
|
if (embed.description) {
|
|
const description = document.createElement("p");
|
|
description.className = "embed-description";
|
|
description.innerHTML = renderMarkdownLinks(String(embed.description));
|
|
article.append(description);
|
|
}
|
|
|
|
if (Array.isArray(embed.fields) && embed.fields.length) {
|
|
const fields = document.createElement("div");
|
|
fields.className = "embed-fields";
|
|
embed.fields.forEach((field) => {
|
|
const item = document.createElement("div");
|
|
item.className = "embed-field";
|
|
if (field.inline) {
|
|
item.classList.add("inline");
|
|
}
|
|
const name = document.createElement("div");
|
|
name.className = "embed-field-name";
|
|
name.textContent = field.name || "\u200b";
|
|
const value = document.createElement("div");
|
|
value.className = "embed-field-value";
|
|
value.innerHTML = renderMarkdownLinks(String(field.value || "\u200b"));
|
|
item.append(name, value);
|
|
fields.append(item);
|
|
});
|
|
article.append(fields);
|
|
}
|
|
|
|
if (embed.footer?.text) {
|
|
const footer = document.createElement("div");
|
|
footer.className = "embed-footer";
|
|
footer.textContent = embed.footer.text;
|
|
article.append(footer);
|
|
}
|
|
|
|
embedsEl.append(article);
|
|
});
|
|
}
|
|
|
|
document.querySelector("#render").addEventListener("click", () => {
|
|
try {
|
|
const payload = JSON.parse(payloadEl.value);
|
|
errorEl.textContent = "";
|
|
render(payload);
|
|
} catch (error) {
|
|
errorEl.textContent = error.message;
|
|
}
|
|
});
|
|
|
|
payloadEl.value = JSON.stringify(samplePayload, null, 2);
|
|
render(samplePayload);
|
|
</script>
|
|
</body>
|
|
</html>
|