Squashed commit of the following: commit bd9fd5cd3cf3f1301df18074c997ec537a81b4f5 Author: Elliu <elliu@hashi.re> Date: Sat Nov 15 15:32:18 2025 +0900 Revert "fix matrix / db resource cleanup on space unlink" This reverts commit ccc10564f1e33ab277bc15f360b8c65f2d0ea867. commit eec559293861305394770343d501389905fe1650 Author: Cadence Ember <cadence@disroot.org> Date: Sat Nov 8 13:01:59 2025 +1300 Dependency inject snow for testing commit b45eeb150e0702c201b8f710a3bdaa8e9f7d90be Author: Elliu <elliu@hashi.re> Date: Wed Nov 5 00:20:20 2025 +0900 manually revert 3597a3b: "Factorize some of the space link/unlink sanity checks" commit 0f2e575df21bf940e4780c30d2701da989f62471 Author: Elliu <elliu@hashi.re> Date: Wed Nov 5 00:04:38 2025 +0900 on unbriding room, also demote powel level of bridge user in matrix room commit ccc10564f1e33ab277bc15f360b8c65f2d0ea867 Author: Elliu <elliu@hashi.re> Date: Wed Nov 5 00:04:13 2025 +0900 fix matrix / db resource cleanup on space unlink commit f4c1ea7c7f7d5a265b84ce464cd8e9e26d934a32 Author: Elliu <elliu@hashi.re> Date: Tue Nov 4 23:54:41 2025 +0900 /unlink-space: properly leave guild and clean DB commit 5f0ec3b2c861cc8b9edc51389d6176c7a22a1135 Author: Cadence Ember <cadence@disroot.org> Date: Sun Nov 2 22:31:14 2025 +1300 Improve HTML to a state I'm happy with commit 16309f26b3dd72927e05454cee8c63504b447b7f Author: Elliu <elliu@hashi.re> Date: Sat Nov 1 22:24:51 2025 +0900 add tests from /unlink-space endpoint commit 5aff6f9048330a86eda3b2d1862f42df8d2bad84 Author: Elliu <elliu@hashi.re> Date: Sat Sep 6 20:05:18 2025 +0900 Add /api/unlink-space implementation commit dfc61594f68db4b52b3553ac7d3561ae9ce13b49 Author: Elliu <elliu@hashi.re> Date: Sat Sep 6 19:59:44 2025 +0900 Extract /api/unlink code to its own function commit 3597a3b5ce9dde3a9ddfe0853253bfda91a38335 Author: Elliu <elliu@hashi.re> Date: Sat Sep 6 19:28:42 2025 +0900 Factorize some of the space link/unlink sanity checks commit 05d788e26394106d9be24cef8b38f6c6f1e4c984 Author: Elliu <elliu@hashi.re> Date: Sat Sep 6 18:23:01 2025 +0900 Add button to unlink a space Co-authored-by: Cadence Ember <cadence@disroot.org>
156 lines
7.6 KiB
Plaintext
156 lines
7.6 KiB
Plaintext
mixin guild(guild)
|
|
span.s-avatar.s-avatar__32.s-user-card--avatar
|
|
if guild.icon
|
|
img.s-avatar--image(src=`https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=32` alt="")
|
|
else
|
|
.s-avatar--letter.bg-silver-400.bar-md(aria-hidden="true")= guild.name[0]
|
|
.s-user-card--info.ai-start
|
|
strong= guild.name
|
|
ul.s-user-card--awards
|
|
li #{discord.guildChannelMap.get(guild.id).filter(c => [0, 5, 15, 16].includes(discord.channels.get(c).type)).length} channels
|
|
|
|
mixin define-theme(name, h, s, l)
|
|
style.
|
|
:root {
|
|
--#{name}-h: #{h};
|
|
--#{name}-s: #{s};
|
|
--#{name}-l: #{l};
|
|
--#{name}: var(--#{name}-400);
|
|
--#{name}-100: hsl(var(--#{name}-h), calc(var(--#{name}-s) + 0 * 1%), clamp(70%, calc(var(--#{name}-l) + 50 * 1%), 95%));
|
|
--#{name}-200: hsl(var(--#{name}-h), calc(var(--#{name}-s) + 0 * 1%), clamp(55%, calc(var(--#{name}-l) + 35 * 1%), 90%));
|
|
--#{name}-300: hsl(var(--#{name}-h), calc(var(--#{name}-s) + 0 * 1%), clamp(35%, calc(var(--#{name}-l) + 15 * 1%), 75%));
|
|
--#{name}-400: hsl(var(--#{name}-h), calc(var(--#{name}-s) + 0 * 1%), clamp(20%, calc(var(--#{name}-l) + 0 * 1%), 60%));
|
|
--#{name}-500: hsl(var(--#{name}-h), calc(var(--#{name}-s) + 0 * 1%), clamp(15%, calc(var(--#{name}-l) + -14 * 1%), 45%));
|
|
--#{name}-600: hsl(var(--#{name}-h), calc(var(--#{name}-s) + 0 * 1%), clamp(5%, calc(var(--#{name}-l) + -26 * 1%), 30%));
|
|
}
|
|
|
|
mixin define-themed-button(name, theme)
|
|
style.
|
|
.s-btn.s-btn__#{name} {
|
|
--_bu-bg-active: var(--#{theme}-300);
|
|
--_bu-bg-hover: var(--#{theme}-200);
|
|
--_bu-bg-selected: var(--#{theme}-300);
|
|
--_bu-fc: var(--#{theme}-500);
|
|
--_bu-fc-active: var(--_bu-fc);
|
|
--_bu-fc-hover: var(--#{theme}-500);
|
|
--_bu-fc-selected: var(--#{theme}-600);
|
|
--_bu-filled-bc: transparent;
|
|
--_bu-filled-bc-selected: var(--_bu-filled-bc);
|
|
--_bu-filled-bg: var(--#{theme}-400);
|
|
--_bu-filled-bg-active: var(--#{theme}-500);
|
|
--_bu-filled-bg-hover: var(--#{theme}-500);
|
|
--_bu-filled-bg-selected: var(--#{theme}-600);
|
|
--_bu-filled-fc: var(--white);
|
|
--_bu-filled-fc-active: var(--_bu-filled-fc);
|
|
--_bu-filled-fc-hover: var(--_bu-filled-fc);
|
|
--_bu-filled-fc-selected: var(--_bu-filled-fc);
|
|
--_bu-outlined-bc: var(--#{theme}-400);
|
|
--_bu-outlined-bc-selected: var(--#{theme}-500);
|
|
--_bu-outlined-bg-selected: var(--_bu-bg-selected);
|
|
--_bu-outlined-fc-selected: var(--_bu-fc-selected);
|
|
--_bu-number-fc: var(--white);
|
|
--_bu-number-fc-filled: var(--#{theme});
|
|
}
|
|
|
|
doctype html
|
|
html(lang="en")
|
|
head
|
|
title Out Of Your Element
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
link(rel="stylesheet" type="text/css" href=rel("/static/stacks.min.css"))
|
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 80%22><text y=%22.83em%22 font-size=%2283%22>💬</text></svg>">
|
|
meta(name="htmx-config" content='{"requestClass":"is-loading"}')
|
|
style.
|
|
.s-prose a {
|
|
text-decoration: underline;
|
|
}
|
|
.themed {
|
|
--theme-base-primary-color-h: 266;
|
|
--theme-base-primary-color-s: 53%;
|
|
--theme-base-primary-color-l: 63%;
|
|
--theme-dark-primary-color-h: 266;
|
|
--theme-dark-primary-color-s: 53%;
|
|
--theme-dark-primary-color-l: 63%;
|
|
}
|
|
.s-toggle-switch.s-toggle-switch__multiple.s-toggle-switch__incremental input[type="radio"]:checked ~ label:not(.s-toggle-switch--label-off) {
|
|
--_ts-multiple-bg: var(--green-400);
|
|
--_ts-multiple-fc: var(--white);
|
|
}
|
|
.s-btn__dropdown:has(+ :popover-open) {
|
|
background-color: var(--theme-topbar-item-background-hover, var(--black-200)) !important;
|
|
}
|
|
+define-themed-button("matrix", "black")
|
|
body.themed.theme-system
|
|
header.s-topbar
|
|
a.s-topbar--skip-link(href="#content") Skip to main content
|
|
.s-topbar--container.wmx9
|
|
a.s-topbar--logo(href=rel("/"))
|
|
img.s-avatar.s-avatar__32(src=rel("/icon.png") alt="")
|
|
nav.s-topbar--navigation
|
|
ul.s-topbar--content
|
|
li.ps-relative.g8
|
|
if !session.data.mxid
|
|
a.s-btn.s-btn__icon.s-btn__matrix.s-btn__outlined.as-center(href=rel("/log-in-with-matrix"))
|
|
!= icons.Icons.IconSpeechBubble
|
|
= ` Log in`
|
|
span(class="sm:d-none")= ` with Matrix`
|
|
if !session.data.userID
|
|
a.s-btn.s-btn__icon.s-btn__featured.s-btn__outlined.as-center(href=rel("/oauth"))
|
|
!= icons.Icons.IconDiscord
|
|
= ` Log in`
|
|
span(class="sm:d-none")= ` with Discord`
|
|
if guild_id && managed.has(guild_id) && discord.guilds.has(guild_id)
|
|
button.s-topbar--item.s-btn.s-btn__muted.s-btn__dropdown.pr32.bar0.s-user-card(popovertarget="guilds")
|
|
+guild(discord.guilds.get(guild_id))
|
|
else if managed.size
|
|
button.s-topbar--item.s-btn.s-btn__muted.s-btn__dropdown.pr24.s-user-card.bar0.fc-black(popovertarget="guilds")
|
|
| Your servers
|
|
else if session.data.mxid || session.data.userID
|
|
.d-flex.ai-center
|
|
.s-badge.s-badge__bot.py6.px16.bar-md
|
|
| No servers available
|
|
#guilds(popover data-popper-placement="bottom" style="display: revert; width: revert;").s-popover.overflow-visible
|
|
.s-popover--arrow.s-popover--arrow__tc
|
|
.s-popover--content.overflow-y-auto.overflow-x-hidden
|
|
ul.s-menu(role="menu")
|
|
each guild in [...managed].map(id => discord.guilds.get(id)).filter(g => g).sort((a, b) => a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1)
|
|
li(role="menuitem")
|
|
a.s-topbar--item.s-user-card.d-flex.p4(href=rel(`/guild?guild_id=${guild.id}`))
|
|
+guild(guild)
|
|
//- Body
|
|
.mx-auto.w100.wmx9.py24.px8.fs-body1#content
|
|
block body
|
|
//- Guild list popover
|
|
script.
|
|
document.querySelectorAll("[popovertarget]").forEach(e => {
|
|
e.addEventListener("click", () => {
|
|
const rect = e.getBoundingClientRect()
|
|
const t = `:popover-open { position: absolute; top: ${Math.floor(rect.bottom)}px; left: ${Math.floor(rect.left + rect.width / 2)}px; width: ${Math.floor(rect.width)}px; transform: translateX(-50%); box-sizing: content-box; margin: 0 }`
|
|
document.styleSheets[0].insertRule(t, document.styleSheets[0].cssRules.length)
|
|
})
|
|
})
|
|
//- Prevent default
|
|
script.
|
|
document.querySelectorAll("[cx-prevent-default]").forEach(e => {
|
|
e.addEventListener("click", event => {
|
|
event.preventDefault()
|
|
})
|
|
})
|
|
script(src=rel("/static/htmx.js"))
|
|
//- Error dialog
|
|
aside.s-modal#server-error(aria-hidden="true")
|
|
.s-modal--dialog
|
|
h1.s-modal--header Server error
|
|
pre.overflow-auto#server-error-content
|
|
button.s-modal--close.s-btn.s-btn__muted(aria-label="Close" type="button" onclick="hideError()")!= icons.Icons.IconClearSm
|
|
.s-modal--footer
|
|
button.s-btn.s-btn__outlined.s-btn__muted(type="button" onclick="hideError()") OK
|
|
script.
|
|
function hideError() {
|
|
document.getElementById("server-error").setAttribute("aria-hidden", "true")
|
|
}
|
|
document.body.addEventListener("htmx:responseError", event => {
|
|
document.getElementById("server-error").setAttribute("aria-hidden", "false")
|
|
document.getElementById("server-error-content").textContent = event.detail.xhr.responseText
|
|
})
|