From 62481a9e8973c7f35a1a5c5013b10e8d475f69eb Mon Sep 17 00:00:00 2001 From: Snowsune Date: Mon, 27 Jul 2026 16:56:38 -0400 Subject: [PATCH] Add matrix widget and remove discord bits! --- snowsune/context_processors.py | 19 +------ snowsune/settings.py | 5 +- snowsune/templates/home.html | 6 +-- snowsune/urls.py | 4 +- snowsune/views/redirects.py | 27 ++-------- static/css/base.css | 98 ++++++++++++++++++++++------------ static/js/matrix-widget.js | 43 +++++++++++++++ templates/base.html | 20 ++++--- 8 files changed, 133 insertions(+), 89 deletions(-) create mode 100644 static/js/matrix-widget.js diff --git a/snowsune/context_processors.py b/snowsune/context_processors.py index 5a7b896..c4c4d97 100644 --- a/snowsune/context_processors.py +++ b/snowsune/context_processors.py @@ -1,10 +1,7 @@ import os from django.conf import settings -from django.utils.safestring import mark_safe - from datetime import datetime, date -from django.utils import timezone as django_timezone from .models import SiteSetting @@ -28,20 +25,8 @@ def debug_mode(request): } -# Expiry links -def expiry_links(request): - return { - "discord": mark_safe( - f"Discord Server" - ), - } - - -# Quick processor for the discord invite link -# TODO: Could be made generic for all SiteSettings -def discord_invite_link(request): - invite = SiteSetting.objects.filter(key="discord_invite").first() - return {"discord_invite": invite.value if invite else ""} +def matrix_widget_link(request): + return {"matrix_widget": settings.MATRIX_WIDGET_URL} def ko_fi_url(request): diff --git a/snowsune/settings.py b/snowsune/settings.py index 56b77b8..315040f 100644 --- a/snowsune/settings.py +++ b/snowsune/settings.py @@ -121,8 +121,7 @@ "snowsune.context_processors.version_processor", "snowsune.context_processors.year_processor", "snowsune.context_processors.debug_mode", - "snowsune.context_processors.expiry_links", - "snowsune.context_processors.discord_invite_link", # TODO: Make generic! + "snowsune.context_processors.matrix_widget_link", "snowsune.context_processors.ko_fi_url", "snowsune.context_processors.google_analytics_id", "snowsune.context_processors.seasonal_css", @@ -161,6 +160,8 @@ "DISCORD_REDIRECT_URI", f"{SITE_URL}/fops/discord/callback" ) +MATRIX_WIDGET_URL = "https://matrix.kitsunehosting.net/widget?admins=snowsune.net" + # I'll use a custom user model for user-storage AUTH_USER_MODEL = "users.CustomUser" diff --git a/snowsune/templates/home.html b/snowsune/templates/home.html index e6cede1..7091bd0 100644 --- a/snowsune/templates/home.html +++ b/snowsune/templates/home.html @@ -58,7 +58,7 @@ "query-input": "required name=search_term_string" }, "sameAs": [ - "{{ discord_invite }}" + "{{ matrix_widget }}" ] } @@ -87,8 +87,8 @@

Welcome to Snowsune.net!

other furry stuff!

-

You can always contact me by joining my Discord - community or emailing me at vixi@snowsune.net!

+

You can always contact me by joining me on Matrix + or emailing me at vixi@snowsune.net!

diff --git a/snowsune/urls.py b/snowsune/urls.py index 606fec5..28f6e42 100644 --- a/snowsune/urls.py +++ b/snowsune/urls.py @@ -14,7 +14,7 @@ from snowsune.views.randal_fanclub import RandalFanclubView from snowsune.views.calendar import CalendarView, CalendarEventsAPIView from snowsune.views.health import health_check -from snowsune.views.redirects import discord_redirect +from snowsune.views.redirects import matrix_redirect from apps.thank_yous.views import thank_you_view @@ -22,7 +22,7 @@ # django path("admin/", admin.site.urls), # Redirect helpers - re_path(r"^discord(?:/.*)?$", discord_redirect, name="discord_redirect"), + re_path(r"^matrix(?:/.*)?$", matrix_redirect, name="matrix_redirect"), # "local" urls path("", HomeView.as_view(), name="home"), path("projects/", ProjectsView.as_view(), name="projects"), diff --git a/snowsune/views/redirects.py b/snowsune/views/redirects.py index fd419c7..528c623 100644 --- a/snowsune/views/redirects.py +++ b/snowsune/views/redirects.py @@ -1,30 +1,11 @@ -import os - +from django.conf import settings from django.http import HttpRequest, HttpResponseRedirect from django.views.decorators.http import require_http_methods -from snowsune.models import SiteSetting - @require_http_methods(["GET", "HEAD"]) -def discord_redirect(_request: HttpRequest, *_args, **_kwargs): +def matrix_redirect(_request: HttpRequest, *_args, **_kwargs): """ - Simple /discord* redirect. - - Returns an HTTP 302 to discord invite url + /matrix* redirect to the Matrix join widget. """ - target = "" - - try: - value = ( - SiteSetting.objects.filter(key="discord_invite") - .values_list("value", flat=True) - .first() - ) - if value: - target = value.strip() - except Exception: - target = "https://snowsune.net/discord_404".strip() - - return HttpResponseRedirect(target) - + return HttpResponseRedirect(settings.MATRIX_WIDGET_URL) diff --git a/static/css/base.css b/static/css/base.css index d2ea620..3f1268d 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -298,35 +298,71 @@ a:visited { align-items: flex-end; } -.discord-navbar-btn { +.matrix-navbar-btn { display: inline-flex; align-items: center; gap: 0.4em; - background: #5865F2; - color: #fff; + background: var(--accent-color); + color: var(--invert-text-color); font-weight: 600; border-radius: var(--radius-lg); padding: 0.35em 1em 0.35em 0.8em; font-size: 1em; text-decoration: none; - margin-bottom: 0em; + margin-bottom: 0; margin-right: 0; - box-shadow: 0 2px 8px rgba(88,101,242,0.08); + box-shadow: 0 2px 8px var(--shadow-color); transition: transform 0.12s, box-shadow 0.12s, background 0.12s; + cursor: pointer; + border: none; + font-family: inherit; } -.login .discord-navbar-btn { - background: #5865F2; - color: #fff; +.matrix-navbar-btn:visited { + color: var(--invert-text-color); +} +.login .matrix-navbar-btn { + background: var(--accent-color); + color: var(--invert-text-color); margin-bottom: 0.5em; } -.login a:not(.discord-navbar-btn) { +.login a:not(.matrix-navbar-btn) { background: #d90429; color: #fff; } -.login a:not(.discord-navbar-btn):hover { +.login a:not(.matrix-navbar-btn):hover { background: #ff616f; } +/* Matrix widget modal — bare iframe, sized to the widget card */ +.matrix-widget-modal { + border: none; + border-radius: 0; + padding: 0; + width: fit-content; + max-width: calc(100vw - 2em); + height: fit-content; + max-height: calc(100vh - 2em); + background: transparent; + box-shadow: none; + overflow: visible; +} +.matrix-widget-modal::backdrop { + background: rgba(0, 0, 0, 0.35); +} +.dark-mode .matrix-widget-modal::backdrop { + background: rgba(0, 0, 0, 0.6); +} +.matrix-widget-iframe { + display: block; + width: 22rem; + max-width: calc(100vw - 2em); + /* Fits expanded widget (room + join links) without an inner scrollbar */ + height: 22rem; + max-height: calc(100vh - 2em); + border: none; + background: transparent; +} + /* User Info Widget */ .user-info { display: flex; @@ -493,29 +529,21 @@ a:visited { } } -/* Remove old banner styles if present */ -.discord-invite-banner, .discord-animated-link, .discord-icon, .discord-text { - display: none !important; -} - -.discord-navbar-btn:hover { - background: #4752c4; +.matrix-navbar-btn:hover { + background: var(--accent-hover); + color: var(--invert-text-color); transform: scale(1.06); - box-shadow: 0 4px 16px rgba(88,101,242,0.18); + box-shadow: 0 4px 16px var(--shadow-hover); text-decoration: none; } -.discord-navbar-icon { +.matrix-navbar-icon { font-size: 1.2em; margin-right: 0.2em; - animation: discord-pulse 1.2s infinite alternate; -} -@keyframes discord-bounce { - 0% { transform: translateY(0); } - 100% { transform: translateY(-2px); } + animation: matrix-pulse 1.2s infinite alternate; } -@keyframes discord-pulse { +@keyframes matrix-pulse { 0% { filter: brightness(1); } - 100% { filter: brightness(1.4); } + 100% { filter: brightness(1.25); } } /* Responsive Navbar */ @@ -574,14 +602,16 @@ a:visited { border-bottom: 1px solid #fff2; margin-bottom: 0.5em; } -/* Discord button in mobile menu */ -.nav-mobile-links .discord-navbar-btn { +/* Matrix button in mobile menu */ +.nav-mobile-links .matrix-navbar-btn { display: inline-flex; + align-items: center; + justify-content: center; width: calc(100% - 2em); margin: 0.5em 1em; - justify-content: center; - border-bottom: 1px solid #fff2; padding: 0.6em 1em; + box-sizing: border-box; + border-bottom: 1px solid #fff2; } /* User info in mobile menu */ .nav-mobile-links .user-info { @@ -655,8 +685,8 @@ a:visited { .login .user-widget { display: none !important; /* Hide login buttons - moved to menu */ } - .login .discord-navbar-btn { - display: none !important; /* Hide discord button - moved to menu */ + .login .matrix-navbar-btn { + display: none !important; /* Hide matrix button - moved to menu */ } .login .nav-hamburger { display: block; /* Ensure hamburger is visible */ @@ -874,14 +904,14 @@ a:visited { margin-bottom: 0; } -.discord-link { +.matrix-link { color: var(--link-default); text-decoration: none; font-weight: 500; transition: color 0.2s ease; } -.discord-link:hover { +.matrix-link:hover { color: var(--link-hover); } diff --git a/static/js/matrix-widget.js b/static/js/matrix-widget.js new file mode 100644 index 0000000..80958d7 --- /dev/null +++ b/static/js/matrix-widget.js @@ -0,0 +1,43 @@ +/** + * Embedding modal for the matrix widget!~ + */ +(function () { + function init() { + const modal = document.getElementById("matrix-widget-modal"); + const iframe = document.getElementById("matrix-widget-iframe"); + if (!modal || !iframe) return; + + const openers = document.querySelectorAll(".js-matrix-widget-open"); + + function openModal(event) { + if (event) event.preventDefault(); + if (!iframe.getAttribute("src")) { + iframe.setAttribute("src", iframe.dataset.src); + } + modal.showModal(); + } + + function closeModal() { + if (modal.open) modal.close(); + } + + openers.forEach((el) => el.addEventListener("click", openModal)); + + // Close when clicking the backdrop (outside the dialog box) + modal.addEventListener("click", (event) => { + const rect = modal.getBoundingClientRect(); + const inside = + event.clientX >= rect.left && + event.clientX <= rect.right && + event.clientY >= rect.top && + event.clientY <= rect.bottom; + if (!inside) closeModal(); + }); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})(); diff --git a/templates/base.html b/templates/base.html index 29b0794..ec70f92 100644 --- a/templates/base.html +++ b/templates/base.html @@ -150,11 +150,9 @@ Apps/Tools Blog Webcomic - {% if discord_invite %} - - 💬 Join my Discord! + + 💬 Join me on Matrix! - {% endif %} {% include "users/widget.html" %} @@ -167,16 +165,19 @@
+ + + + {% include "includes/django_messages.html" %} @@ -296,6 +297,9 @@

Global Links

+ + + {% block extra_js %}{% endblock %}