diff --git a/app/templates/_side_pane.html b/app/templates/_side_pane.html index 73453a0f..8c0d424e 100644 --- a/app/templates/_side_pane.html +++ b/app/templates/_side_pane.html @@ -32,7 +32,7 @@

{{ community.title }}

-

{{ community.description_html|safe if community.description_html else '' }}

+

{{ community.description_html|community_links|safe if community.description_html else '' }}

{{ community.rules_html|safe if community.rules_html else '' }}

{% if len(mods) > 0 and not community.private_mods -%}

Moderators

diff --git a/app/templates/themes/x_api/base.html b/app/templates/themes/x_api/base.html new file mode 100644 index 00000000..80190a66 --- /dev/null +++ b/app/templates/themes/x_api/base.html @@ -0,0 +1,165 @@ + + + + + + {% if not debug_mode %}{{ g.site.name }}{% endif %} + {{ bootstrap.load_css() }} + + + + + + + + + + + +
+ {% block app_content %}{% endblock %} +
+
+ + + + {{ bootstrap.load_js() }} + {% if debug_mode %} + + {% endif %} + + diff --git a/app/templates/themes/x_api/css/color-modes.css b/app/templates/themes/x_api/css/color-modes.css new file mode 100644 index 00000000..9e9beed0 --- /dev/null +++ b/app/templates/themes/x_api/css/color-modes.css @@ -0,0 +1,29 @@ +.bi { + vertical-align: -.125em; + fill: currentColor; +} + +.btn-bd-primary { + --bd-violet-bg: #712cf9; + --bd-violet-rgb: 112.520718, 44.062154, 249.437846; + + --bs-btn-font-weight: 600; + --bs-btn-color: var(--bs-white); + --bs-btn-bg: var(--bd-violet-bg); + --bs-btn-border-color: var(--bd-violet-bg); + --bs-btn-hover-color: var(--bs-white); + --bs-btn-hover-bg: #6528e0; + --bs-btn-hover-border-color: #6528e0; + --bs-btn-focus-shadow-rgb: var(--bd-violet-rgb); + --bs-btn-active-color: var(--bs-btn-hover-color); + --bs-btn-active-bg: #5a23c8; + --bs-btn-active-border-color: #5a23c8; +} + +.bd-mode-toggle { + z-index: 1500; +} + +.bd-mode-toggle .dropdown-menu .active .bi { + display: block !important; +} diff --git a/app/templates/themes/x_api/css/navbars.css b/app/templates/themes/x_api/css/navbars.css new file mode 100644 index 00000000..e717c1cd --- /dev/null +++ b/app/templates/themes/x_api/css/navbars.css @@ -0,0 +1,8 @@ +body { + padding-bottom: 20px; +} + +.navbar { + margin-bottom: 20px; +} + diff --git a/app/templates/themes/x_api/index.html b/app/templates/themes/x_api/index.html new file mode 100644 index 00000000..d71960d9 --- /dev/null +++ b/app/templates/themes/x_api/index.html @@ -0,0 +1,21 @@ +{% extends 'themes/' + theme() + '/base.html' %} + +{% block app_content %} +

Site Info from API

+ + {% if not debug_mode %} +

(API only available in debug mode)

+ {% else %} + + {% endif %} +{% endblock%} diff --git a/app/templates/themes/x_api/js/color-modes.js b/app/templates/themes/x_api/js/color-modes.js new file mode 100644 index 00000000..f5d5dbf3 --- /dev/null +++ b/app/templates/themes/x_api/js/color-modes.js @@ -0,0 +1,81 @@ +/*! + * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + */ + +(() => { + 'use strict' + + const getStoredTheme = () => localStorage.getItem('theme') + const setStoredTheme = theme => localStorage.setItem('theme', theme) + + const getPreferredTheme = () => { + const storedTheme = getStoredTheme() + if (storedTheme) { + return storedTheme + } + + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + } + + const setTheme = theme => { + if (theme === 'auto') { + document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) + } else { + document.documentElement.setAttribute('data-bs-theme', theme) + } + } + + setTheme(getPreferredTheme()) + + const showActiveTheme = (theme, focus = false) => { + const themeSwitcher = document.querySelector('#bd-theme') + + if (!themeSwitcher) { + return + } + + const themeSwitcherText = document.querySelector('#bd-theme-text') + const activeThemeIcon = document.querySelector('.theme-icon-active use') + const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`) + const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href') + + document.querySelectorAll('[data-bs-theme-value]').forEach(element => { + element.classList.remove('active') + element.setAttribute('aria-pressed', 'false') + }) + + btnToActive.classList.add('active') + btnToActive.setAttribute('aria-pressed', 'true') + activeThemeIcon.setAttribute('href', svgOfActiveBtn) + const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})` + themeSwitcher.setAttribute('aria-label', themeSwitcherLabel) + + if (focus) { + themeSwitcher.focus() + } + } + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = getStoredTheme() + if (storedTheme !== 'light' && storedTheme !== 'dark') { + setTheme(getPreferredTheme()) + } + }) + + window.addEventListener('DOMContentLoaded', () => { + showActiveTheme(getPreferredTheme()) + + document.querySelectorAll('[data-bs-theme-value]') + .forEach(toggle => { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value') + setStoredTheme(theme) + setTheme(theme) + showActiveTheme(theme, true) + }) + }) + }) +})() + diff --git a/app/templates/themes/x_api/js/site.js b/app/templates/themes/x_api/js/site.js new file mode 100644 index 00000000..7aa10161 --- /dev/null +++ b/app/templates/themes/x_api/js/site.js @@ -0,0 +1,30 @@ +const url = new URL(window.location.href); +const baseUrl = `${url.protocol}//${url.host}`; +const api = baseUrl + '/api/alpha/site' + +fetch(api) + .then(response => response.json()) + .then(data => { + // navbar + document.querySelector('#head-title').textContent = data.site.name + document.querySelector('#navbar-title').innerHTML = 'Logo' + ' ' + data.site.name + + // site info + document.querySelector('#site_version').textContent = data.version + document.querySelector('#site_actor_id').textContent = data.site.actor_id + document.querySelector('#site_description').textContent = data.site.description + document.querySelector('#site_enable_downvotes').textContent = data.site.enable_downvotes + document.querySelector('#site_icon').textContent = data.site.icon + document.querySelector('#site_name').textContent = data.site.name + document.querySelector('#site_sidebar').textContent = data.site.sidebar + document.querySelector('#site_user_count').textContent = data.site.user_count + + let lang_names = data.site.all_languages[0].name; + let lang_count = data.site.all_languages.length; + + for (let i = 1; i < lang_count; i++) { + lang_names += ", " + data.site.all_languages[i].name; + } + + document.querySelector('#site_all_languages').textContent = lang_names + }) diff --git a/app/templates/themes/x_api/svg/color-modes.svg b/app/templates/themes/x_api/svg/color-modes.svg new file mode 100644 index 00000000..9c9a3e88 --- /dev/null +++ b/app/templates/themes/x_api/svg/color-modes.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/templates/themes/x_api/x_api.json b/app/templates/themes/x_api/x_api.json new file mode 100644 index 00000000..eb0ad78c --- /dev/null +++ b/app/templates/themes/x_api/x_api.json @@ -0,0 +1,4 @@ +{ + "name": "X API", + "debug": true +} diff --git a/app/utils.py b/app/utils.py index fb5a6a70..6b3bb600 100644 --- a/app/utils.py +++ b/app/utils.py @@ -1048,6 +1048,8 @@ def theme_list(): for dir in dirs: if os.path.exists(f'app/templates/themes/{dir}/{dir}.json'): theme_settings = json.loads(file_get_contents(f'app/templates/themes/{dir}/{dir}.json')) + if 'debug' in theme_settings and theme_settings['debug'] == True and not current_app.debug: + continue result.append((dir, theme_settings['name'])) return result