akkoma-fe/docs/site/HACKING/index.html

797 lines
31 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" href="../images/pleroma_logo_vector_bg_32.png">
<meta name="generator" content="mkdocs-1.3.0, mkdocs-material-8.3.9">
<title>Hacking, tweaking, contributing - Pleroma-FE Documentation</title>
<link rel="stylesheet" href="../assets/stylesheets/main.1d29e8d0.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.cbb835fc.min.css">
<meta name="theme-color" content="#7e56c2">
<link rel="stylesheet" href="../css/extra.css">
<script>__md_scope=new URL("..",location),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="" data-md-color-primary="deep-purple" data-md-color-accent="blue-grey">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#hacking-tweaking-contributing" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="Pleroma-FE Documentation" class="md-header__button md-logo" aria-label="Pleroma-FE Documentation" data-md-component="logo">
<img src="../images/pleroma_logo_vector_nobg.svg" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Pleroma-FE Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Hacking, tweaking, contributing
</span>
</div>
</div>
</div>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<!--
Copyright (c) 2016-2019 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!--
Check whether the repository is hosted on one of the supported code hosting
platforms (GitHub, GitLab or Bitbucket) to show icon.
-->
<!-- Repository containing source -->
<a href="https://akkoma.dev/AkkomaGang/pleroma-fe" title="Go to repository"
class="md-source" data-md-source="">
<div class="md-source__repository">
AkkomaGang/pleroma-fe
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="Pleroma-FE Documentation" class="md-nav__button md-logo" aria-label="Pleroma-FE Documentation" data-md-component="logo">
<img src="../images/pleroma_logo_vector_nobg.svg" alt="logo">
</a>
Pleroma-FE Documentation
</label>
<div class="md-nav__source">
<!--
Copyright (c) 2016-2019 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!--
Check whether the repository is hosted on one of the supported code hosting
platforms (GitHub, GitLab or Bitbucket) to show icon.
-->
<!-- Repository containing source -->
<a href="https://akkoma.dev/AkkomaGang/pleroma-fe" title="Go to repository"
class="md-source" data-md-source="">
<div class="md-source__repository">
AkkomaGang/pleroma-fe
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
Introduction to Pleroma-FE
</a>
</li>
<li class="md-nav__item">
<a href="../CONFIGURATION/" class="md-nav__link">
Pleroma-FE configuration and customization for instance administrators
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Hacking, tweaking, contributing
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
Hacking, tweaking, contributing
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#what-pleromafe-even-is-how-it-works" class="md-nav__link">
What PleromaFE even is, how it works
</a>
</li>
<li class="md-nav__item">
<a href="#setting-up-develop-server" class="md-nav__link">
Setting up develop server
</a>
</li>
<li class="md-nav__item">
<a href="#setting-up-production-build" class="md-nav__link">
Setting up production build
</a>
<nav class="md-nav" aria-label="Setting up production build">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#replacing-your-instances-frontend-with-custom-fe-build" class="md-nav__link">
Replacing your instance's frontend with custom FE build
</a>
</li>
<li class="md-nav__item">
<a href="#running-production-build-locally-or-on-a-separate-server" class="md-nav__link">
Running production build locally or on a separate server
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#basic-architecture" class="md-nav__link">
Basic architecture
</a>
<nav class="md-nav" aria-label="Basic architecture">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#api-data-operations" class="md-nav__link">
API, Data, Operations
</a>
</li>
<li class="md-nav__item">
<a href="#themes" class="md-nav__link">
Themes
</a>
</li>
<li class="md-nav__item">
<a href="#still-image" class="md-nav__link">
Still Image
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#contributing" class="md-nav__link">
Contributing
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4" type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4">
User guide
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="User guide" data-md-level="1">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
User guide
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../user_guide/" class="md-nav__link">
General overview
</a>
</li>
<li class="md-nav__item">
<a href="../user_guide/posting_reading_basic_functions/" class="md-nav__link">
Posting, reading, basic functions.
</a>
</li>
<li class="md-nav__item">
<a href="../user_guide/settings/" class="md-nav__link">
Settings
</a>
</li>
<li class="md-nav__item">
<a href="../user_guide/timelines/" class="md-nav__link">
Timelines
</a>
</li>
<li class="md-nav__item">
<a href="../user_guide/users_follow_mute_block/" class="md-nav__link">
Users: follow, mute, block
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#what-pleromafe-even-is-how-it-works" class="md-nav__link">
What PleromaFE even is, how it works
</a>
</li>
<li class="md-nav__item">
<a href="#setting-up-develop-server" class="md-nav__link">
Setting up develop server
</a>
</li>
<li class="md-nav__item">
<a href="#setting-up-production-build" class="md-nav__link">
Setting up production build
</a>
<nav class="md-nav" aria-label="Setting up production build">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#replacing-your-instances-frontend-with-custom-fe-build" class="md-nav__link">
Replacing your instance's frontend with custom FE build
</a>
</li>
<li class="md-nav__item">
<a href="#running-production-build-locally-or-on-a-separate-server" class="md-nav__link">
Running production build locally or on a separate server
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#basic-architecture" class="md-nav__link">
Basic architecture
</a>
<nav class="md-nav" aria-label="Basic architecture">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#api-data-operations" class="md-nav__link">
API, Data, Operations
</a>
</li>
<li class="md-nav__item">
<a href="#themes" class="md-nav__link">
Themes
</a>
</li>
<li class="md-nav__item">
<a href="#still-image" class="md-nav__link">
Still Image
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#contributing" class="md-nav__link">
Contributing
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="hacking-tweaking-contributing">Hacking, tweaking, contributing<a class="headerlink" href="#hacking-tweaking-contributing" title="Permanent link">&para;</a></h1>
<h2 id="what-pleromafe-even-is-how-it-works">What PleromaFE even is, how it works<a class="headerlink" href="#what-pleromafe-even-is-how-it-works" title="Permanent link">&para;</a></h2>
<p>PleromaFE is an SPA (Single-Page Application) backed by <a href="https://vuejs.org/">Vue</a> framework. It means that it's just a nearly-empty HTML page with bunch of JavaScript that actually generates and controls DOM (i.e. html elements) in Runtime. Currently, there's no way around it - you have to have Javascript enabled in the browser to make it work, there is a theoretical possibility to generate some HTML server-side but it's not implemented yet.</p>
<p>You can serve static html page and everything from any HTTP(S) server but currently it will try to access /api/ path at same domain it's running on, meaning that as of right now you cannot put it on one domain and access the other without proxying requests.</p>
<p>Development server does exactly that - it serves static html page with javascript and all other assets, adds some code to automatically reload when changes to code are made and proxies requests to some other server.</p>
<h2 id="setting-up-develop-server">Setting up develop server<a class="headerlink" href="#setting-up-develop-server" title="Permanent link">&para;</a></h2>
<p>Setting up development server is fairly straight-forward.</p>
<ol>
<li>On your system you must have <strong><a href="https://nodejs.org/">Node.js</a> version 8</strong> and newer installed. For older systems or systems that do not package node you can try <a href="https://github.com/nodesource/distributions">NodeSource</a> repositories. <em>Windows support theoretically possible but isn't tested.</em></li>
<li>For fetching dependencies and running basic tasks you will <em><a href="https://yarnpkg.com/">Yarn</a></em> installed.</li>
<li>Clone the repository, <code>cd</code> into it and run <code>yarn</code> to fetch dependencies.</li>
<li>If you want to point development server at some instance you will need to copy <code>config/local.example.json</code> to <code>config/local.json</code> and change the <code>target</code> to point at instance you want, otherwise it will point to <code>localhost:4000</code> which is default address for locally-run Pleroma Backend</li>
<li>Run <code>yarn dev</code> - it will start the server.</li>
<li>Open <code>localhost:8080</code> in your browser, it might take a while initially until everything is built first time.</li>
</ol>
<h2 id="setting-up-production-build">Setting up production build<a class="headerlink" href="#setting-up-production-build" title="Permanent link">&para;</a></h2>
<p>This could be a bit trickier, you basically need steps 1-4 from <em>develop build</em> instructions, and run <code>yarn build</code> which will compile and copy eveything needed for production into <code>dist</code> folder. As said before, this technically could be used anywhere with some details.</p>
<h3 id="replacing-your-instances-frontend-with-custom-fe-build">Replacing your instance's frontend with custom FE build<a class="headerlink" href="#replacing-your-instances-frontend-with-custom-fe-build" title="Permanent link">&para;</a></h3>
<p>This is the most easiest way to use and test FE build: you just need to copy or symlink contents of <code>dist</code> folder into backend's <a href="https://docs.akkoma.dev/stable/configuration/static_dir/">static directory</a>, by default it is located in <code>instance/static</code>, or in <code>/var/lib/pleroma/static</code> for OTP release installations, create it if it doesn't exist already. Be aware that running <code>yarn build</code> wipes the contents of <code>dist</code> folder.</p>
<h3 id="running-production-build-locally-or-on-a-separate-server">Running production build locally or on a separate server<a class="headerlink" href="#running-production-build-locally-or-on-a-separate-server" title="Permanent link">&para;</a></h3>
<p>This is <strong>highly experimental</strong> and only tried once, with no actual simple solution available yet</p>
<p>You will need an HTTP server that can proxy requests for <code>/api</code>, <code>/instance</code>, <code>/nodeinfo</code> and show index.html for every 404 page.</p>
<p>For nginx you'll probably need something like this:</p>
<div class="highlight"><pre><span></span><code><span class="k">server</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kn">listen</span><span class="w"> </span><span class="mi">80</span><span class="w"> </span><span class="s">default_server</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kn">index</span><span class="w"> </span><span class="s">index.html</span><span class="w"> </span><span class="s">index.htm</span><span class="w"> </span><span class="s">index.nginx-debian.html</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kn">root</span><span class="w"> </span><span class="s">/var/www/html</span><span class="w"></span>
<span class="w"> </span><span class="s">location</span><span class="w"> </span><span class="s">/api</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kn">proxy_pass</span><span class="w"> </span><span class="s">https://example.tld</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="kn">location</span><span class="w"> </span><span class="s">/instance</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kn">proxy_pass</span><span class="w"> </span><span class="s">https://example.tld</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="kn">location</span><span class="w"> </span><span class="s">/nodeinfo</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kn">proxy_pass</span><span class="w"> </span><span class="s">https://example.tld</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="kn">location</span><span class="w"> </span><span class="s">/</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kn">try_files</span><span class="w"> </span><span class="nv">$uri</span><span class="w"> </span><span class="nv">$uri/</span><span class="w"> </span><span class="s">/index.html</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>(ed. note: this is close to what i used last time i had to do it, it may not work and need additions, i basically adjusted default nginx server in debian)</p>
<h2 id="basic-architecture">Basic architecture<a class="headerlink" href="#basic-architecture" title="Permanent link">&para;</a></h2>
<h3 id="api-data-operations">API, Data, Operations<a class="headerlink" href="#api-data-operations" title="Permanent link">&para;</a></h3>
<p>In 99% cases PleromaFE uses <a href="https://docs.joinmastodon.org/api/">MastoAPI</a> with <a href="https://docs.akkoma.dev/stable/differences_in_mastoapi_responses.md">Pleroma Extensions</a> to fetch the data. The rest is either QvitterAPI leftovers or pleroma-exclusive APIs. QvitterAPI doesn't exactly have documentation and uses different JSON structure and sometimes different parameters and workflows, <a href="https://twitter-api.readthedocs.io/en/latest/index.html">this</a> could be a good reference though. Some pleroma-exclusive API may still be using QvitterAPI JSON structure.</p>
<p>PleromaFE supports both formats by transforming them into internal format which is basically QvitterAPI one with some additions and renaming. All data is passed trough <a href="https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/src/services/entity_normalizer/entity_normalizer.service.js">Entity Normalizer</a> which can serve as a reference of API and what's actually used, it's also a host for all the hacks and data transformation.</p>
<p>For most part, PleromaFE tries to store all the info it can get in global vuex store - every user and post are passed trough updating mechanism where data is either added or merged with existing data, reactively updating the information throughout UI, so if in newest request user's post counter increased, it will be instantly updated in open user profile cards. This is also used to find users, posts and sometimes to build timelines and/or request parameters.</p>
<p>PleromaFE also tries to persist this store, however only stable data is stored, such as user authentication and preferences, user highlights. Persistence is performed by saving and loading chunk of vuex store in browser's LocalStorage/IndexedDB.</p>
<p>TODO: Refactor API code and document it here</p>
<h3 id="themes">Themes<a class="headerlink" href="#themes" title="Permanent link">&para;</a></h3>
<p>PleromaFE uses custom theme "framework" which is pretty much just a style tag rendered by vue which only contains CSS3 variables. Every color used in UI should be derived from theme. Theme is stored in a JSON object containing color, opacity, shadow and font information, with most of it being optional.</p>
<p>The most basic theme can consist of 4 to 8 "basic colors", which is also what previous version of themes allowed, with all other colors being derived from those basic colors, i.e. "light background" will be "background" color lightened/darkened, "panel header" will be same as "foreground". The idea is that you can specify just basic color palette and everything else will be generated automatically, but if you really need to tweak some specific color - you can.</p>
<p>As said before - older version only allowed 4 to 8 colors, it also used arrays instead of objects, we still support that. The basic colors are: background, foreground, text, links, red, orange, blue, green. First 4 are mandatory, last 4 have default fallbacks since ever more ancient theme formats only had 4 colors.</p>
<p>Note that with older version themes used different internal naming when persisting state.</p>
<p>Themes are meant to be backwards and somewhat forwards compatible - new colors should properly inherit from some existing one, making it compatible with older versions. When loading newer version of theme all unrecognized colors will be ignored, which for most part should be fine, however adding new features (gradients, masks, whatever it might be) might be breaky.</p>
<p>Lastly, pleroma provides some contrast information and generates readable text color automatically, which is done by tracking background/text color pairs and their contrast - if contrast too low it will try to use background color with inverted lightness, if it's still unacceptable it will fall back to pure black/white.</p>
<h3 id="still-image">Still Image<a class="headerlink" href="#still-image" title="Permanent link">&para;</a></h3>
<p>Most images are wrapped in a component called StillImage, which does one simple thing - tries to detect if image is a GIF and if it is (and user has enabled relevant setting) it will show <code>&lt;canvas&gt;</code> with that image instead of actual image. It uses standard method to render an image into canvas which renders first frame of a GIF if it's animated (obviously because canvas by itself isn't animated and you'd need to animate it yourself in JS), it will show actual image on hover. Statuses also allow playing animated avatars when you hover over a post, not just image itself.</p>
<h2 id="contributing">Contributing<a class="headerlink" href="#contributing" title="Permanent link">&para;</a></h2>
<p>Feel free to contribute, most preferred way is by starting a Merge Request in GitLab. Please try to use descriptive names for your branches and merge requests, avoid naming them "fix-issue-777" "777" and so on.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../CONFIGURATION/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Pleroma-FE configuration and customization for instance administrators" rel="prev">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</div>
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">
Previous
</span>
Pleroma-FE configuration and customization for instance administrators
</div>
</div>
</a>
<a href="../user_guide/" class="md-footer__link md-footer__link--next" aria-label="Next: General overview" rel="next">
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">
Next
</span>
General overview
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4Z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "..", "features": ["tabs"], "search": "../assets/javascripts/workers/search.b97dbffb.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version.title": "Select version"}}</script>
<script src="../assets/javascripts/bundle.6c7ad80a.min.js"></script>
</body>
</html>