Commit 74c3be9f authored by Agate's avatar Agate 💬

Merge branch '143-themes' into 'develop'

Resolve "External stylesheets"

Closes #456

See merge request funkwhale/funkwhale!357
parents 14e0ac97 d7f12caf
Make funkwhale themable by loading external stylesheets (#456)
Custom themes for Funkwhale
If you ever wanted to give a custom look and feel to your instance, this is now possible.
Check if you want to know more!
......@@ -158,3 +158,79 @@ permissions are:
There is no dedicated interface to manage users permissions, but superusers
can login on the Django's admin at ``/api/admin/`` and grant permissions
to users at ``/api/admin/users/user/``.
Funkwhale supports custom themes, which are great if you want to personnalize the
look and feel of your instance. Theming is achieved by declaring
additionnal stylesheets you want to load in the front-end.
Customize the settings
In order to know what stylesheets to load, the front-end requests the following
url: ``https://your.instance/settings.json``. On typical deployments, this url
returns a 404 error, which is simply ignored.
However, if you return the appropriate payload on this url, you can make the magic
work. We will store the necessary files in the ``/srv/funkwhale/custom`` directory:
.. code-block:: shell
cd /srv/funkwhale/
mkdir custom
cat <<EOF > custom/settings.json
"additionalStylesheets": ["/custom/custom.css"]
cat <<EOF > custom/custom.css
body {
background-color: red;
By executing the previous commands, you will end up with two files in your ``/srv/funkwhale/custom``
- ``settings.json`` will tell the front-end what stylesheets you want to load (``/custom/custom.css`` in this example)
- ``custom.css`` will hold your custom CSS
The last step to make this work is to ensure both files are served by the reverse proxy.
On nginx, add the following snippet to your vhost config::
location /settings.json {
alias /srv/funkwhale/custom/settings.json;
location /custom {
alias /srv/funkwhale/custom;
On apache, use the following one::
Alias /settings.json /srv/funkwhale/custom/settings.json
Alias /custom /srv/funkwhale/custom
<Directory "/srv/funkwhale/custom">
Options FollowSymLinks
AllowOverride None
Require all granted
Once done, reload your reverse proxy, refresh Funkwhale in your web browser, and you should see
a red background.
.. note::
You can reference external urls as well in ``settings.json``, simply use
the full urls. Be especially careful with external urls as they may affect your users
.. warning::
Loading additional stylesheets and CSS rules can affect the performance and
usability of your instance. If you encounter issues with the interfaces and use
custom stylesheets, try to disable those to ensure the issue is not caused
by your customizations.
......@@ -29,6 +29,9 @@ module.exports = {
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/settings.json': {
target: '',
'**': {
target: 'http://nginx:6001',
changeOrigin: true,
<div id="app">
<!-- here, we display custom stylesheets, if any -->
<link v-for="url in customStylesheets" rel="stylesheet" property="stylesheet" :href="url" :key="url">
<div class="ui main text container instance-chooser" v-if="!$store.state.instance.instanceUrl">
<div class="ui padded segment">
<h1 class="ui header"><translate>Choose your instance</translate></h1>
......@@ -175,6 +177,11 @@ export default {
return null
return _.get(this.nodeinfo, 'software.version')
customStylesheets () {
if (this.$store.state.instance.frontSettings) {
return this.$store.state.instance.frontSettings.additionalStylesheets || []
watch: {
......@@ -126,6 +126,8 @@ axios.interceptors.response.use(function (response) {
return Promise.reject(error)
/* eslint-disable no-new */
new Vue({
el: '#app',
......@@ -6,6 +6,7 @@ export default {
namespaced: true,
state: {
maxEvents: 200,
frontSettings: {},
instanceUrl: process.env.INSTANCE_URL,
events: [],
settings: {
......@@ -53,6 +54,9 @@ export default {
events: (state, value) => { = value
frontSettings: (state, value) => {
state.frontSettings = value
instanceUrl: (state, value) => {
if (value && !value.endsWith('/')) {
value = value + '/'
......@@ -110,6 +114,13 @@ export default {
}, response => {
logger.default.error('Error while fetching settings',
fetchFrontSettings ({commit}) {
return axios.get('/settings.json').then(response => {
}, response => {
logger.default.error('Error when fetching front-end configuration (or no customization available)')
/* This is a custom CSS file that can be loaded thanks to settings.json */
"additionalStylesheets": ["/static/custom.css"]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment