diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..f30ab0a1 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,41 @@ +kind: pipeline +type: docker +name: Deploy + +clone: + disable: true + +steps: + - name: Clone + image: woodpeckerci/plugin-git + settings: + recursive: true + + - name: Build + depends_on: + - Clone + image: node:16 + commands: + - yarn + - yarn build + when: + event: + - push + + - name: Execute deploy script + depends_on: + - Build + image: ubuntu:latest + environment: + SSH_KEY: + from_secret: SSH_KEY + commands: + - apt update && apt install -y openssh-client rsync + - ./ci/add-key.sh + - ./ci/deploy.sh + when: + event: + - push + branch: + - froth + - froth-akkoma diff --git a/.gitignore b/.gitignore index a0be5c16..58d698c1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ selenium-debug.log config/local.json config/local.*.json docs/site/ -.vscode/ \ No newline at end of file +.vscode/ + +.dccache diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..4c1c6e39 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "instance/pleroma-mods/pleroma-mod-syntax"] + path = instance/pleroma-mods/pleroma-mod-syntax + url = https://git.pleroma.social/absturztaube/pleroma-mod-syntax.git +[submodule "instance/pleroma-mods/pleroma-mod-imgsearch"] + path = instance/pleroma-mods/pleroma-mod-imgsearch + url = https://gitlab.com/SamTherapy/pleroma-mod-imgsearch +[submodule "instance/pleroma-mods/pleroma-mod-math"] + path = instance/pleroma-mods/pleroma-mod-math + url = https://git.pleroma.social/absturztaube/pleroma-mod-math diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index cad4b698..00000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,81 +0,0 @@ -pipeline: - lint: - when: - event: - - pull_request - image: node:18 - commands: - - yarn - - yarn lint - #- yarn stylelint - - test: - when: - event: - - pull_request - image: node:18 - commands: - - apt update - - apt install firefox-esr -y --no-install-recommends - - yarn - - yarn unit - - build: - when: - event: - - push - branch: - - develop - - stable - image: node:18 - commands: - - yarn - - yarn build - - release: - when: - event: - - push - branch: - - develop - - stable - image: node:18 - secrets: - - SCW_ACCESS_KEY - - SCW_SECRET_KEY - - SCW_DEFAULT_ORGANIZATION_ID - commands: - - apt-get update && apt-get install -y rclone wget zip - - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64 - - mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli - - chmod +x scaleway-cli - - ./scaleway-cli object config install type=rclone - - zip akkoma-fe.zip -r dist - - rclone copyto akkoma-fe.zip scaleway:akkoma-updates/frontend/$CI_COMMIT_BRANCH/akkoma-fe.zip - - docs: - when: - event: - - push - branch: - - develop - - stable - environment: - CI: "true" - image: python:3.10-slim - secrets: - - SCW_ACCESS_KEY - - SCW_SECRET_KEY - - SCW_DEFAULT_ORGANIZATION_ID - commands: - - apt-get update && apt-get install -y rclone wget git zip - - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64 - - mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli - - chmod +x scaleway-cli - - ./scaleway-cli object config install type=rclone - - cd docs - - pip install -r requirements.txt - - mkdocs build - - zip -r docs.zip site/* - - cd site - - rclone copy . scaleway:akkoma-docs/frontend/$CI_COMMIT_BRANCH/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 59961078..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,24 +0,0 @@ -# Akkoma Code of Conduct - -The Akkoma project aims to be **enjoyable** for anyone to participate in, regardless of their identity or level of expertise. To achieve this, the community must create an environment which is **safe** and **equitable**; the following guidelines have been created with these goals in mind. - -1. **Treat individuals with respect.** Differing experiences and viewpoints deserve to be respected, and bigotry and harassment are not tolerated under any circumstances. - - Individuals should at all times be treated as equals, regardless of their age, gender, sexuality, race, ethnicity, _or any other characteristic_, intrinsic or otherwise. - - Behaviour that is harmful in nature should be addressed and corrected *regardless of intent*. - - Respect personal boundaries and ask for clarification whenever they are unclear. - - (Obviously, hate does not count as merely a "differing viewpoint", because it is harmful in nature.) - -2. **Be understanding of differences in communication.** Not everyone is aware of unspoken social cues, and speech that is not intended to be offensive should not be treated as such simply due to an atypical manner of communication. - - Somebody who speaks bluntly is not necessarily rude, and somebody who swears a lot is not necessarily volatile. - - Try to confirm your interpretation of their intent rather than assuming bad faith. - - Someone may not communicate as, or come across as a picture of "professionalism", but this should not be seen as a reason to dismiss them. This is a **casual** space, and communication styles can reflect that. - -3. **"Uncomfortable" does not mean "unsafe".** In an ideal world, the community would be safe, equitable, enjoyable, *and* comfortable for all members at all times. Unfortunately, this is not always possible in reality. - - Safety and equity will be prioritized over comfort whenever it is necessary to do so. - - Weaponizing one's own discomfort to deflect accountability or censor an individual (e.g. "white fragility") is a form of discriminatory conduct. - -4. **Let people grow from their mistakes.** Nobody is perfect; even the most well-meaning individual can do something hurtful. Everyone should be given a fair opportunity to explain themselves and correct their behaviour. Portraying someone as inherently malicious prevents improvement and shifts focus away from the *action* that was problematic. - - Avoid bringing up past events that do not accurately reflect an individual's current actions or beliefs. (This is, of course, different from providing evidence of a recurring pattern of behaviour.) - ---- -This document was adapted from one created by ~keith as part of punks default repository template, and is licensed under CC-BY-SA 4.0. The original template is here: diff --git a/COFE_OF_CONDUCT.md b/COFE_OF_CONDUCT.md new file mode 100644 index 00000000..1ba85c5f --- /dev/null +++ b/COFE_OF_CONDUCT.md @@ -0,0 +1,49 @@ +``` + o$$$$$$oo + o$" "$oo + $ o""""$o "$o + "$ o "o "o $ + "$ $o $ $ o$ + "$ o$"$ o$ + "$ooooo$$ $ o$ + o$ """ $ " $$$ " $ + o$ $o $$" " " + $$ $ " $ $$$o"$ o o$" + $" o "" $ $" " o" $$ + $o " " $ o$" o" o$" + "$o $$ $ o" o$$" + ""o$o"$" $oo" o$" + o$$ $ $$$ o$$ + o" o oo"" "" "$o + o$o" "" $ + $" " o" " " " "o + $$ " " o$ o$o " $ + o$ $ $ o$$ " " "" + o $ $" " "o o$ + $ o $o$oo$"" + $o $ o o o"$$ + $o o $ $ "$o + $o $ o $ $ "o + $ $ "o $ "o"$o + $ " o $ o $$ + $o$o$o$o$$o$$$o$$o$o$$o$$o$$$o$o$o$o$o$o$o$o$o$ooo + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ " $$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ "$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ o$$$$" + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ooooo$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$""""" + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" +"$o$o$o$o$o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$""" + """"""""""""""""""""""""""""""""""""""""""""""""""""" +``` \ No newline at end of file diff --git a/ci/add-key.sh b/ci/add-key.sh new file mode 100755 index 00000000..64614f90 --- /dev/null +++ b/ci/add-key.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# only execute this script as part of the pipeline. +[ -z "$CI" ] && echo "missing ci environment variable" && exit 2 + +# only execute the script when github token exists. +[ -z "$SSH_KEY" ] && echo "missing ssh key" && exit 3 + +# write the ssh key. +mkdir /root/.ssh +echo -n "${SSH_KEY}" > /root/.ssh/id_ed25519 +chmod 600 /root/.ssh/id_ed25519 + +# add froth.zone to our known hosts. +touch /root/.ssh/known_hosts +chmod 600 /root/.ssh/known_hosts +ssh-keyscan -H froth.zone > /etc/ssh/ssh_known_hosts 2> /dev/null diff --git a/ci/deploy.sh b/ci/deploy.sh new file mode 100755 index 00000000..9625d473 --- /dev/null +++ b/ci/deploy.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +TARGET="pleroma@froth.zone:/opt/pleroma" + +#rsync -ra public/ "${TARGET}/instance/static" +#cp dist/index.html "${TARGET}/instance/static/index.html" +rsync --update -Pr dist/ "${TARGET}/instance/static/" +rsync --update -ra dist/static/ "${TARGET}/instance/static/static" +#rsync --delete -ra images/ "${TARGET}/instance/static/images" +#rsync --delete -ra sounds/ "${TARGET}/instance/static/sounds" +rsync -ra instance/ "${TARGET}/instance/static/instance" +#rsync --delete -ra pages/ "${TARGET}/instance/static/pages" diff --git a/index.html b/index.html index b166bcec..466e6c7f 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - Akkoma + The Froth Zone @@ -14,7 +14,7 @@ - +
diff --git a/instance/favicon.png b/instance/favicon.png new file mode 100644 index 00000000..e9ead3fd Binary files /dev/null and b/instance/favicon.png differ diff --git a/instance/panel.html b/instance/panel.html new file mode 100644 index 00000000..08cb75a9 --- /dev/null +++ b/instance/panel.html @@ -0,0 +1,33 @@ +
+

+ Welcome to the Froth Zone! +
+
+ Now available on + OpenNIC! + (Functionality not guaranteed) +
+
+ Bloat FE + | + Masto FE + | + Pleroma FE + | + Soapbox FE + | + Treebird FE +
+
+ Gitea + | + Funkwhale + | + Misskey + | + PeerTube +
+
+ Everything else I host +

+
diff --git a/instance/pleroma-mod-config.json b/instance/pleroma-mod-config.json new file mode 100644 index 00000000..7e01c824 --- /dev/null +++ b/instance/pleroma-mod-config.json @@ -0,0 +1,7 @@ +{ + "modDirectory": "/instance/pleroma-mods/", + "mods": [ + "math", + "syntax" + ] +} diff --git a/instance/pleroma-mod-loader.js b/instance/pleroma-mod-loader.js new file mode 100644 index 00000000..52c375e7 --- /dev/null +++ b/instance/pleroma-mod-loader.js @@ -0,0 +1,479 @@ +class PleromaModLoader { + constructor () { + this.config = { + modDirectory: '/instance/pleroma-mods/', + mods: [] + } + this.loadConfig() + this.loadedMods = {} + this.classes = {} + } + + loadMods () { + this.config.mods.forEach((mod) => { + this.loadMod(mod) + }) + } + + loadMod (modName) { + return PleromaModLoader.includeScript( + this.config.modDirectory + 'pleroma-mod-' + modName + '/mod.js' + ).then(() => { + this.loadedMods[modName] = new this.classes[PleromaModLoader.getClassName(modName)]() + }) + } + + loadConfig () { + window.fetch('/instance/pleroma-mod-config.json').then((response) => { + return response.json() + }).then((json) => { + Object.keys(json).forEach((key) => { + this.config[key] = json[key] + }) + this.loadMods() + }).catch((error) => { + console.error("can't load loader config") + console.error(error) + }) + } + + registerClass (className, object) { + this.classes[className] = object + } + + waitUntilReady () { + const postPanel = document.querySelector('.status-container') + const loginPanel = document.querySelector('.login-form') + if (postPanel || loginPanel) { + Object.keys(this.loadedMods).forEach((modName) => { + const settings = document.querySelector('.settings-modal div[label]:first-child') + if (settings) { + if (!settings.querySelector('.mod-settings')) { + this.appendModSettings(settings) + } + } + + const mod = this.loadedMods[modName] + if (mod.isEnabled) { + mod.ready() + } + }) + + this.createObserver() + } else { + console.warn('not ready, trying again in 1s') + window.setTimeout(() => { this.waitUntilReady() }, 1000) + } + } + + createCheckbox (label, mod) { + const labelElement = document.createElement('label') + labelElement.classList.add('checkbox') + + const input = document.createElement('input') + input.setAttribute('type', 'checkbox') + input.checked = mod.isEnabled + input.addEventListener('change', (event) => { + if (event.target.checked) { + mod.enable() + } else { + mod.disable() + } + }) + labelElement.appendChild(input) + + const fakeCheckbox = document.createElement('i') + fakeCheckbox.classList.add('checkbox-indicator') + labelElement.appendChild(fakeCheckbox) + + const text = document.createElement('span') + text.classList.add('label') + text.innerText = label + labelElement.appendChild(text) + + return labelElement + } + + appendModSettings (element) { + const container = document.createElement('div') + container.classList.add('setting-item') + container.classList.add('mod-settings') + + const title = document.createElement('h2') + title.innerText = 'Pleroma Mods' + container.appendChild(title) + + const optionList = document.createElement('ul') + optionList.classList.add('setting-list') + + Object.keys(this.loadedMods).sort().forEach((modName) => { + const li = document.createElement('li') + + const enable = this.createCheckbox('enable ' + modName, this.loadedMods[modName]) + li.appendChild(enable) + + const ulConfig = document.createElement('ul') + ulConfig.classList.add('setting-list') + + Object.keys(this.loadedMods[modName].config).forEach((key) => { + if (key === 'includes' || key === 'filter') { + return + } + + this.loadedMods[modName].onSettingInit(key, ulConfig, document.createElement('li')) + }) + + li.appendChild(ulConfig) + + optionList.appendChild(li) + }) + + container.appendChild(optionList) + + element.appendChild(container) + } + + createObserver () { + this.containers = { + main: document.querySelector('.main'), + notifications: document.querySelector('.notifications'), + userPanel: document.querySelector('.user-panel'), + settingsModal: document.querySelector('.settings-modal') + } + + const observerConfig = { + subtree: true, + childList: true + } + + this.observer = new MutationObserver((mutations, observer) => { + const modal = document.querySelector('.settings-modal div[label]:first-child') + if (modal && !modal.querySelector('.mod-settings')) { + this.appendModSettings(modal) + } + + Object.values(this.loadedMods).forEach((mod) => { + if (mod.isEnabled) { + mutations.forEach((mutation) => { + mod.mutate(mutation, observer) + }) + } + }) + }) + + this.observer.observe(this.containers.main, observerConfig) + if (this.containers.notifications) { + this.observer.observe(this.containers.notifications, observerConfig) + } + if (this.containers.userPanel) { + this.observer.observe(this.containers.userPanel, observerConfig) + } + if (this.containers.settingsModal) { + this.observer.observe(this.containers.settingsModal, observerConfig) + } + } + + static registerMod (mod) { + window.__pleromaModLoader.registerClass(mod.name, mod) + } + + static includeScript (src) { + console.log('include ' + src) + return new Promise((resolve) => { + const script = document.createElement('script') + script.setAttribute('src', src) + script.setAttribute('type', 'text/javascript') + script.onload = () => { + resolve() + } + document.querySelector('body').appendChild(script) + }) + } + + static includeCss (src) { + console.log('include ' + src) + return new Promise((resolve) => { + const link = document.createElement('link') + link.setAttribute('href', src) + link.setAttribute('rel', 'stylesheet') + link.setAttribute('type', 'text/css') + link.onload = () => { + resolve() + } + document.querySelector('head').appendChild(link) + }) + } + + static excludeScript (src) { + return new Promise((resolve) => { + const script = document.querySelector('script[src="' + src + '"]') + if (script) { + script.remove() + } + resolve() + }) + } + + static excludeCss (src) { + return new Promise((resolve) => { + const link = document.querySelector('link[href="' + src + '"]') + if (link) { + link.remove() + } + resolve() + }) + } + + static getVueScope (element) { + if (!element) { + return null + } + if (element.__vue__) { + console.warn('old vue version, please update pleroma-fe') + return element.__vue__ + } + if (element._vnode) { + return element._vnode + } + if (element.__vnode) { + return element.__vnode + } + if (element.parentNode) { + return PleromaModLoader.getVueScope(element.parentNode) + } + return null + } + + static getVueComponent (element) { + if (!element) { + return null + } + if (element.__vnode && element.__vnode.component) { + return element.__vnode.component + } + if (element.__vueParentComponent) { + return element.__vueParentComponent.ctx + } + if (element.__vueComponent__) { + return element.__vueComponent__ + } + if (element.parentNode) { + return PleromaModLoader.getVueComponent(element.parentNode) + } + return null + } + + static getRootVueScope () { + return PleromaModLoader.getVueScope(document.querySelector('#app')) + } + + static getToken () { + return PleromaModLoader.getRootVueScope().appContext.provides.store.getters.getUserToken() + } + + static getModDir () { + return window.__pleromaModLoader.config.modDirectory + } + + static getClassName (name) { + let className = 'PleromaMod' + name.split('-').forEach((namePart) => { + className += namePart.substring(0, 1).toUpperCase() + className += namePart.substring(1) + }) + return className + } + + static api (method, path, params) { + return new Promise((resolve, reject) => { + const token = PleromaModLoader.getToken() + const xhr = new XMLHttpRequest() + xhr.responseType = 'json' + xhr.open(method, path) + xhr.setRequestHeader('Content-Type', 'application/json') + xhr.setRequestHeader('Authorization', 'Bearer ' + token) + xhr.onreadstatechange = () => { + if (xhr.readyState === 4) { + if (xhr.status !== 200) { + reject(new Error({ + status: xhr.status, + response: xhr.response, + xhr + })) + } + } + } + xhr.onload = () => { + resolve(xhr.response) + } + xhr.send(JSON.stringify(params)) + }) + } +} + +class PleromaMod { // eslint-disable-line no-unused-vars + constructor (name) { + this.name = name + this.config = {} + this.isRunning = false + } + + get isEnabled () { + return localStorage.getItem('pleroma_mod_' + this.name + '_enabled') !== 'false' || true + } + + getClassName () { + return PleromaModLoader.getClassName(this.name) + } + + getModDir () { + return PleromaModLoader.getModDir() + this.name + '/' + } + + ready () { + this.onReady() + this.run() + } + + destroy () { + this.isRunning = false + if (this.config.includes) { + const styles = this.config.includes.css || [] + const scripts = this.config.includes.js || [] + + Promise.all(styles.map((style) => { + return this.excludeCss(style) + }).concat(scripts.map((script) => { + return this.excludeScript(script) + }))).then(() => { + this.onDestroy() + }) + + return + } + + this.onDestroy() + } + + run () { + if (this.config.includes) { + const styles = this.config.includes.css || [] + const scripts = this.config.includes.js || [] + + Promise.all(styles.map((style) => { + return this.includeCss(style) + }).concat(scripts.map((script) => { + return this.includeScript(script) + })).concat([ + this.loadConfig(), + this.onCreate() + ])).then(() => { + this.isRunning = true + this.onRun() + }) + + return + } + + this.isRunning = true + this.onRun() + } + + mutate (mutation, observer) { + if (this.isRunning) { + this.onMutation(mutation, observer) + } + } + + saveConfig () { + const storedConfig = {} + Object.keys(this.config).filter((key) => { + return key !== 'includes' && key !== 'filter' + }).forEach((key) => { + storedConfig[key] = this.config[key] + }) + localStorage.setItem(this.name + '_config', JSON.stringify(storedConfig)) + } + + mergeConfig (newConfig) { + Object.keys(newConfig).forEach((key) => { + this.config[key] = JSON.parse(JSON.stringify(newConfig[key])) + }) + } + + loadConfig () { + return new Promise((resolve) => { + // TODO: use structuredClone when its more supported + this.defaultConfig = JSON.parse(JSON.stringify(this.config)) + + const storedConfig = JSON.parse(localStorage.getItem(this.name + '_config')) + + this.onConfigLoad().then((json) => { + this.mergeConfig(json) + if (storedConfig) { + this.mergeConfig(storedConfig) + } + this.saveConfig() + resolve() + }) + }) + } + + onReady () {} + onCreate () { + return new Promise((resolve) => { + resolve() + }) + } + + onDestroy () {} + onRun () {} + onMutation (mutation, observer) {} + onConfigLoad () { + return new Promise((resolve) => { + resolve({}) + }) + } + + onSettingInit (key, ul, li) {} + + includeCss (src) { + return PleromaModLoader.includeCss(PleromaModLoader.getModDir() + this.name + '/' + src) + } + + includeScript (src) { + return PleromaModLoader.includeScript(PleromaModLoader.getModDir() + this.name + '/' + src) + } + + excludeCss (src) { + return PleromaModLoader.excludeCss(PleromaModLoader.getModDir() + this.name + '/' + src) + } + + excludeScript (src) { + return PleromaModLoader.excludeScript(PleromaModLoader.getModDir() + this.name + '/' + src) + } + + fetchJson (src) { + console.log('loading ' + src) + return window.fetch(PleromaModLoader.getModDir() + this.name + '/' + src).then((response) => { + return response.json() + }) + } + + api (method, path, params) { + return PleromaModLoader.api(method, path, params) + } + + enable () { + this.ready() + localStorage.setItem('pleroma_mod_' + this.name + '_enabled', true) + } + + disable () { + this.destroy() + localStorage.setItem('pleroma_mod_' + this.name + '_enabled', false) + } +} + +window.__pleromaModLoader = new PleromaModLoader() +window.__pleromaModLoader.waitUntilReady() diff --git a/instance/pleroma-mods/pleroma-mod-imgsearch b/instance/pleroma-mods/pleroma-mod-imgsearch new file mode 160000 index 00000000..cfd4dd64 --- /dev/null +++ b/instance/pleroma-mods/pleroma-mod-imgsearch @@ -0,0 +1 @@ +Subproject commit cfd4dd6404d2df6e07e646aff5ff1d606ed48228 diff --git a/instance/pleroma-mods/pleroma-mod-math b/instance/pleroma-mods/pleroma-mod-math new file mode 160000 index 00000000..5d7ac570 --- /dev/null +++ b/instance/pleroma-mods/pleroma-mod-math @@ -0,0 +1 @@ +Subproject commit 5d7ac570770bd7f1d5cba1279c444b53626add3c diff --git a/instance/pleroma-mods/pleroma-mod-syntax b/instance/pleroma-mods/pleroma-mod-syntax new file mode 160000 index 00000000..440dd5dc --- /dev/null +++ b/instance/pleroma-mods/pleroma-mod-syntax @@ -0,0 +1 @@ +Subproject commit 440dd5dcb4c97d58726a2a52abbe9c54a8b2f3fb diff --git a/src/components/about/about.vue b/src/components/about/about.vue index df9bb196..edf16b0b 100644 --- a/src/components/about/about.vue +++ b/src/components/about/about.vue @@ -9,7 +9,7 @@ - + diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue index 126f6fa9..656fe802 100644 --- a/src/components/account_actions/account_actions.vue +++ b/src/components/account_actions/account_actions.vue @@ -6,7 +6,7 @@ :bound-to="{ x: 'container' }" remove-padding > -