mirror of
https://github.com/ArcaneChat/server.git
synced 2026-07-03 14:05:37 +02:00
299 lines
7.4 KiB
HTML
299 lines
7.4 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
|
<link rel="icon" type="image/png" href="/img/favicon-96x96.png" sizes="96x96" />
|
|
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg" />
|
|
<link rel="shortcut icon" href="/img/favicon.ico" />
|
|
|
|
<title>ArcaneChat Channels</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
padding: 40px 20px;
|
|
}
|
|
|
|
.container {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.header {
|
|
text-align: center;
|
|
color: white;
|
|
margin-bottom: 50px;
|
|
}
|
|
|
|
.header h1 {
|
|
font-size: 2.5em;
|
|
margin-bottom: 10px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.header p {
|
|
font-size: 1.1em;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.channels-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 25px;
|
|
}
|
|
|
|
.channel-card {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
transition: all 0.3s ease;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.channel-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.channel-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.channel-avatar {
|
|
width: 60px;
|
|
height: 60px;
|
|
min-width: 60px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
background: #f0f0f0;
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.channel-name {
|
|
font-size: 1.3em;
|
|
font-weight: 600;
|
|
color: #333;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.channel-content {
|
|
flex: 1;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.channel-description {
|
|
display: inline;
|
|
font-size: 0.95em;
|
|
color: #666;
|
|
line-height: 1.5;
|
|
margin-right: 6px;
|
|
}
|
|
|
|
.show-more-btn {
|
|
background: none;
|
|
border: none;
|
|
color: #667eea;
|
|
font-size: 0.9em;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
padding: 4px 0;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.show-more-btn:hover {
|
|
color: #764ba2;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.button-group {
|
|
display: flex;
|
|
gap: 1rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.join-button {
|
|
display: inline-block;
|
|
flex: 1;
|
|
padding: 0.8rem 1rem;
|
|
transition: all 0.3s ease;
|
|
border-radius: 8px;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
text-align: center;
|
|
}
|
|
|
|
.join-button:hover {
|
|
transform: scale(1.05);
|
|
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
|
}
|
|
|
|
.join-button:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
.share-button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0.8rem 1rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
background-color: rgb(229, 231, 235);
|
|
text-decoration: none;
|
|
color: rgb(55, 65, 81);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.share-button:hover {
|
|
transform: scale(1.05);
|
|
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.2);
|
|
}
|
|
|
|
.share-button:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
.channels-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.header h1 {
|
|
font-size: 2em;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>Channel Directory</h1>
|
|
<p>Discover ArcaneChat channels</p>
|
|
</div>
|
|
|
|
<div class="channels-grid" id="channelsContainer"></div>
|
|
</div>
|
|
|
|
<script>
|
|
const assets = "/assets/channels";
|
|
|
|
function toOpenpgp4fpr(url) {
|
|
return url
|
|
.replace(/https:\/\/i\.delta\.chat\/#/, "openpgp4fpr:")
|
|
.replace(/&/, "#");
|
|
}
|
|
|
|
async function renderChannels() {
|
|
function h(tag, attributes, ...children) {
|
|
const element = document.createElement(tag);
|
|
if (attributes) {
|
|
Object.entries(attributes).forEach((entry) => {
|
|
element.setAttribute(entry[0], entry[1]);
|
|
});
|
|
}
|
|
element.append(...children);
|
|
return element;
|
|
}
|
|
|
|
const data = (
|
|
await (await fetch(`${assets}/channels-others.json`)).json()
|
|
).concat(await (await fetch(`${assets}/channels.json`)).json());
|
|
|
|
const container = document.getElementById("channelsContainer");
|
|
const MAX_LENGTH = 160;
|
|
|
|
data.forEach((channel) => {
|
|
const description = channel.settings.description || "";
|
|
const isLong = description.length > MAX_LENGTH;
|
|
|
|
const descEl = h("p", { class: "channel-description" });
|
|
const channelContent = [descEl];
|
|
|
|
if (isLong) {
|
|
descEl.textContent =
|
|
description.substring(0, MAX_LENGTH).trimEnd() + "...";
|
|
|
|
const showMoreBtn = h(
|
|
"button",
|
|
{ class: "show-more-btn" },
|
|
"Show more",
|
|
);
|
|
channelContent.push(showMoreBtn);
|
|
|
|
let expanded = false;
|
|
showMoreBtn.addEventListener("click", () => {
|
|
expanded = !expanded;
|
|
if (expanded) {
|
|
descEl.textContent = description;
|
|
showMoreBtn.textContent = "Show Less";
|
|
} else {
|
|
descEl.textContent =
|
|
description.substring(0, MAX_LENGTH).trimEnd() + "... ";
|
|
showMoreBtn.textContent = "Show more";
|
|
}
|
|
});
|
|
} else {
|
|
descEl.textContent = description;
|
|
}
|
|
|
|
container.appendChild(
|
|
h(
|
|
"div",
|
|
{ class: "channel-card" },
|
|
h(
|
|
"div",
|
|
{ class: "channel-header" },
|
|
h("img", {
|
|
src: `${assets}/images/${channel.image}`,
|
|
class: "channel-avatar",
|
|
}),
|
|
h("h2", { class: "channel-name" }, channel.settings.name),
|
|
),
|
|
h("div", { class: "channel-content" }, ...channelContent),
|
|
h(
|
|
"div",
|
|
{ class: "button-group" },
|
|
h(
|
|
"a",
|
|
{ href: toOpenpgp4fpr(channel.invite), class: "join-button" },
|
|
"Join Channel",
|
|
),
|
|
h(
|
|
"a",
|
|
{
|
|
href: channel.invite,
|
|
class: "share-button",
|
|
target: "_blank",
|
|
},
|
|
"Share",
|
|
),
|
|
),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", renderChannels);
|
|
</script>
|
|
</body>
|
|
</html>
|