...
 
Commits (38)
image: node:latest
before_script:
- 'curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -'
- 'echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list'
- apt-get update && apt-get install -y yarn
- yarn install
build:
script:
- npm run build
artifacts:
paths:
- public/packs
- public/assets
expire_in: 1 week
![Mastodon](https://i.imgur.com/NhZc40l.png)
========
# Mastodon Tootsuite / mastofe repository
[![Build Status](https://img.shields.io/circleci/project/github/tootsuite/mastodon.svg)][circleci]
[![Code Climate](https://img.shields.io/codeclimate/maintainability/tootsuite/mastodon.svg)][code_climate]
Here is a fork of mastodon. We could really just remove all of the code except
for the frontend, but to easily pull the upstream repo we'll just keep
everything. This is my fork for the moment with the idea of making the mastofe
just as polished as the pleromafe. If you want to get access, open an issue or
hit me up at howl@social.zxq.co.
[circleci]: https://circleci.com/gh/tootsuite/mastodon
[code_climate]: https://codeclimate.com/github/tootsuite/mastodon
# Deployement
Mastodon is a **free, open-source social network server** based on **open web protocols** like ActivityPub and OStatus. The social focus of the project is a viable decentralized alternative to commercial social media silos that returns the control of the content distribution channels to the people. The technical focus of the project is a good user interface, a clean REST API for 3rd party apps and robust anti-abuse tools.
This is what you want to do to update the mastofe bundled with pleroma.
Click on the screenshot below to watch a demo of the UI:
- Run ``build.sh`` at the root of this repo, you can set the ``TARGET`` environment variable if pleroma isn’t at ``../pleroma`` (default value of ``TARGET``)
- Go to pleroma repo:
- ``git add priv/static/sw.js priv/static/packs``
- ``git commit -m "update mastofe"``
[![Screenshot](https://i.imgur.com/pG3Nnz3.jpg)][youtube_demo]
# Development
[youtube_demo]: https://www.youtube.com/watch?v=YO1jQ8_rAMU
I use a combination of the pleroma backend + yarn + nginx to do local
development. I refuse to install Ruby. Here's how to get it running on your own
machine:
**Ruby on Rails** is used for the back-end, while **React.js** and Redux are used for the dynamic front-end. A static front-end for public resources (profiles and statuses) is also provided.
## Install yarn
If you would like, you can [support the development of this project on Patreon][patreon] or [Liberapay][liberapay]. Alternatively, you can donate to this BTC address: `17j2g7vpgHhLuXhN4bueZFCvdxxieyRVWd`
Yarn will be needed to set up the mastodon frontend for development. Check out
https://yarnpkg.com/lang/en/docs/install/ . For Debian, it's like this:
[patreon]: https://www.patreon.com/user?u=619786
[liberapay]: https://liberapay.com/Mastodon/
```sh
# import yarn pub key and repo
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install yarn
```
---
## Mastodon Frontend Setup
## Resources
```sh
# Install dependencies
yarn install -D
npm run dev
# check that http://localhost:3035/packs/common.css works in your browser once
# webpack is done compiling. if css shows up, then it should have worked!
```
- [Frequently Asked Questions](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md)
- [Use this tool to find Twitter friends on Mastodon](https://bridge.joinmastodon.org)
- [API overview](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md)
- [List of Mastodon instances](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/List-of-Mastodon-instances.md)
- [List of apps](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md)
- [List of sponsors](https://joinmastodon.org/sponsors)
## nginx setup
## Features
I'll assume that you have already fired up pleroma using the installation guide.
To work on the frontend while still having the backend up, use this nginx
config.
**No vendor lock-in: Fully interoperable with any conforming platform**
```
server {
listen 80;
server_name pleroma.testing;
It doesn't have to be Mastodon, whatever implements ActivityPub or OStatus is part of the social network!
location /packs {
add_header 'Access-Control-Allow-Origin' '*';
proxy_http_version 1.1;
proxy_set_header Host $http_host;
**Real-time timeline updates**
proxy_pass http://localhost:3035;
}
See the updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
location / {
add_header 'Access-Control-Allow-Origin' '*';
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
**Federated thread resolving**
proxy_pass http://localhost:4000;
}
}
```
If someone you follow replies to a user unknown to the server, the server fetches the full thread so you can view it without leaving the UI
Change the `server_name` if you like. I personally like to create a new entry
in /etc/hosts and add `127.0.0.1 pleroma.testing`, but you do what suits you.
**Media attachments like images and short videos**
Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos are looped - like vines!
**OAuth2 and a straightforward REST API**
Mastodon acts as an OAuth2 provider so 3rd party apps can use the API
**Fast response times**
Mastodon tries to be as fast and responsive as possible, so all long-running tasks are delegated to background processing
**Deployable via Docker**
You don't need to mess with dependencies and configuration if you want to try Mastodon, if you have Docker and Docker Compose the deployment is extremely easy
---
## Development
Please follow the [development guide](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Development-guide.md) from the documentation repository.
## Deployment
There are guides in the documentation repository for [deploying on various platforms](https://github.com/tootsuite/documentation#running-mastodon).
## Contributing
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository. [Here are the guidelines for code contributions](CONTRIBUTING.md)
**IRC channel**: #mastodon on irc.freenode.net
## License
Copyright (C) 2016-2018 Eugen Rochko & other Mastodon contributors (see AUTHORS.md)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
---
## Extra credits
The elephant friend illustrations are created by [Dopatwo](https://mastodon.social/@dopatwo)
If you have enough luck, navigating to your \<server\_name\>/web should show
you the mastodon frontend, and should also work with all the nice things of
webpack such as hot reloading. Have fun!
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124.12477 127.91685" width="124.12476" height="127.91685"><path d="M72.584191 46.815676c-2.3-2.2-4.2-2.5-6.6-.6-2.4 1.9-2.1 4.8.9 7.6 3.1 2.9 4.7 4.1 6.7 5 2.1.9 5.4 2.5 10.5-2s10.2-11.1 9.4-14.7c-.8-3.6-4.1-1.8-6.8 1.2s-3.7 4-5.4 5.2c-1.5 1.3-3.8 3-8.7-1.7z" class="st0" style="fill:#93a1b5;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M116.384191 75.015676c0 6.3-3.9 9.8-9.1 9.8-5.3 0-9.9-3.5-9.9-9.8 0-6.3 4.3-10.3 9.5-10.3s9.5 4 9.5 10.3z" style="fill:#3a434e;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M54.184191 16.615676c-23 1.2-30.5 14.1-32.8 27.8-3 18.2-8.2 44.2-9.2 53.2s-1 16 6 22 11 5 23 7 19 0 20-8l16.8-1.1s14.5 5.5 18.8 6.9c4.3 1.4 10.6.5 12.1-7.1s.2-12.5-6.6-14.4c-6.8-1.9-10.6-2.9-10.6-2.9l4.4-30.1s17.4 1.6 22.6-20c0 0 3.9 1.1 4.8-2.8.9-3.9-2.6-6.2-5.6-4.8l-2.5-1s-.2-3.8-3.5-4.2c-2.1-.2-6 3.4-3 7.4 0 0-3.4 8.9-12 7.8-8.6-1.1-12.5-11.2-15-18.2s-10.7-18.3-27.7-17.5z" class="st2" style="fill:#56606b;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M95.484191 69.915676c-.6 0-1.2 0-1.8-.1-4.2-.2-10.9-2.4-17-7.8-.7-1-.4-2-.2-2.5.5-1.1 1.7-1.8 3-1.8.8 0 1.5.3 2.2.8 3 2.2 7.8 5.1 13.8 5.1.9 0 1.8-.1 2.7-.2 7.2-1 12.1-5.8 14.3-9.9.6-1.2 1.3-2.5 1.8-3.5.2-.5.3-.7.6-.9.3-.2 1 .2 1 .2l2.1.8c-4.5 17.8-17.4 19.2-21.2 19.2h-1.3v.6z" class="st3" style="fill:#3a434e;opacity:.98;fill-opacity:1"/><path d="M48.884191 126.915676c-2.2 0-4.7-.2-7.6-.7-2.8-.5-5.1-.8-7.1-1-6.9-.9-10.3-1.3-15.6-5.9-7-6-6.8-13-5.8-21.6.3-2.3.8-5.9 1.7-11.2 3.1 1.4 6.1 2.2 8.7 2.2 3.1 0 5.4-1.2 6.6-3.4 1.6 1.9 6.9 7.3 13.3 7.3 1 0 1.9-.1 2.8-.4 3.5-1 19.8-2.1 46.9-3.4l-1.7 11.7.4.1s3.8 1 10.6 2.9c6.1 1.7 7.9 5.6 6.3 13.8-1.3 6.6-6.2 7.3-8.2 7.3-1.1 0-2.2-.2-3.3-.5-4.2-1.4-18.6-6.8-18.7-6.9h-.1l-17.3 1.2-.1.4c-.7 5.4-4.5 8.1-11.8 8.1z" class="st3" style="fill:#3a434e;fill-opacity:1"/><path d="M41.184191 103.415676c-3.8-1.4-6-1.4-7.7-1.4-1.8 0-4.6 3.3 1.4 5.4 6 2.1 10.3 3.4 10.3 3.4s1.8-2.1 3.5-2.9c1.6-.8 2.3-.9 2.3-.9l-9.8-3.6z" style="fill:#56606b;fill-opacity:1"/><path d="M27.584191 38.615676c1.2-5-2.1-8.2-5.7-9.2-3.5-1-8.4-1.7-13.9 6.9s-9.5 16.5-6.4 20.6c3.1 4.1 9.3 3.4 11.8-.8 0 0 5.7 3.8 9.5-4.2" class="st2" style="fill:#56606b;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M10.884191 45.115676c-1.6 2.5-.8 5 2 5.9 2.7 1 5-1.5 6.5-3.8 1.6-2.3 3.6-5.9 3.6-5.9s-3.7 1.2-5.6-.2c-2-1.4-1.5-3.8-1.5-3.8l-5 7.8z" class="st3" style="fill:#3a434e;fill-opacity:1"/><path d="M22.684191 41.415676c-2.6 1.1-6.8.6-6.9-4.1 0 0-5.1 7.6-5.9 9.6" class="st5" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10"/><path d="M67.584191 5.215676c0-3.4-3.9-2.6-3.9-2.6 0-1.2-2-3.5-8.5-.6-6.4 2.9-7.3 6-7.3 6-3.8-1.7-9.6-2.6-13.5.8-3.9 3.4-4.3 10 2.3 13.5 0 0 2.9.9 7.7-.4 4.8-1.3 7.7-3.3 7.7-3.3s3.7 2.3 9 .6c5.3-1.7 9.9-4.5 10.3-10.1.5-5.7-3.8-3.9-3.8-3.9z" style="fill:#56606b;fill-opacity:1"/><path d="M67.084191 16.315676c-1-5.5-7-3-7-3 .5-2.1-3-4.1-5.5-2.7-2.5 1.4-6.6-.1-6.6-.1-6.4-4.4-14.3-2.1-16.1 2-1.1 3.3.2 7.3 4.8 9.7 0 0 2.9.9 7.7-.4 4.8-1.3 7.7-3.3 7.7-3.3s3.7 2.3 9 .6c2.3-.6 4.3-1.5 6-2.8 0 .1 0 0 0 0z" style="fill:#3a434e;fill-opacity:1"/><path d="M36.684191 22.715676c-.1 0-.2 0-.2-.1-3.1-1.6-5-4.1-5.4-7-.3-2.7.8-5.4 3-7.3 3.9-3.3 9.5-2.8 13.6-1.1.5-1.1 2.2-3.5 7.3-5.8 4.5-2 6.9-1.5 8-.8.6.4.9.9 1.1 1.3.7-.1 2-.1 3 .7.5.4.9 1 1 1.8.7-.1 1.8-.2 2.7.4 1 .7 1.4 2.1 1.2 4.1-.4 5-3.9 8.5-10.7 10.6-5.5 1.7-9.3-.6-9.4-.7-.2-.1-.3-.5-.2-.7.1-.2.5-.3.7-.2 0 0 3.6 2.2 8.6.6 6.3-2 9.6-5.1 10-9.7.1-1.6-.2-2.8-.8-3.3-.9-.7-2.3-.1-2.3-.1-.2.1-.3 0-.5 0-.1-.1-.2-.2-.2-.4 0-.8-.2-1.3-.6-1.7-.9-.8-2.6-.4-2.7-.4-.1 0-.3 0-.4-.1-.1-.1-.2-.2-.2-.4 0-.3-.2-.7-.7-1-.6-.4-2.6-1.1-7.1.8-6.1 2.7-7 5.6-7 5.7 0 .1-.1.3-.3.3-.1.1-.3.1-.4 0-3.9-1.7-9.3-2.4-13 .8-1.9 1.7-2.9 4.1-2.6 6.4.3 2.5 2 4.7 4.8 6.2.2.1.3.4.2.7-.1.3-.3.4-.5.4z"/><path d="M40.584191 84.115676s6.3 16.8 7.1 19.3c.8 2.5 1.8 3.4 7.3 3 5.5-.4 6.7-21.5 6.7-21.5l-21.1-.8z" style="fill:#191b22;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M51.084191 103.415676c-1.7-2.1-1.9-4.2-1.9-4.2l2-10.9 3-1.4-3.1 16.5zm33.9-35.3l-23.9 1.9 1.2 8 25.2 1.1 4.6-9c-2.3-.3-4.7-.9-7.1-2z" class="st9" style="fill:#191b22;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M28.484191 82.915676c7.2 9.4 12.7 11.4 21.8 7.7 8.5-3.4 15.4-9 15.1-15-.3-6-2.1-10.3-9.1-9.8-2.3.2-6.8 2.8-9.6 4.4-1.8 1-4.2 2.2-6 .4-1.8-1.8-4.3-4.4-4.3-4.4" class="st2" style="fill:#56606b;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M49.284191 80.515676c-.3-.2-.5-.4-.7-.6-1.2.7-2.3 1.3-2.8 1.6-2 1.2-3.8.5-4.7-.3-.9-.9-2.3-2.4-5.5-1.5-3.7 1-4.5 5.7-2.5 8.4 6.5 6.1 12.8 4.1 15.2 3.3 2.4-.8 6.3-2.7 6.3-2.7l.6-6c-2-.8-4.1-.9-5.9-2.2z" class="st3" style="fill:#3a434e;fill-opacity:1"/><path d="M28.484191 82.915676c7.2 9.4 12.7 11.4 21.8 7.7 8.5-3.4 15.4-9 15.1-15-.3-6-2.1-10.3-9.1-9.8-2.3.2-6.8 2.8-9.6 4.4-1.8 1-4.2 2.2-6 .4-1.8-1.8-4.3-4.4-4.3-4.4m35.4-8.6c6.5 8.3 15.5 12.5 21.8 12.7" class="st5" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10"/><path d="M53.184191 104.415676c-1.6.1-2.7-1.1-2.4-2.7l4.9-25.9c.3-1.6 1.9-3 3.6-3.1l26.9-1.7c1.6-.1 3.6-1.4 4.4-2.9l.7-1.3c.7-1.5 2.7-2.8 4.4-2.9l4.5-.3c1.6-.1 3.1 1.1 3.3 2.8v.2c.2 1.6.5 3.7.7 4.6.2.9.3 3 .1 4.6l-2.2 21.3c-.2 1.6-1.7 3.1-3.3 3.3l-45.6 4z" style="fill:#191b22;fill-opacity:1"/><path d="M53.184191 104.415676c-1.6.1-2.7-1.1-2.4-2.7l4.9-25.9c.3-1.6 1.9-3 3.6-3.1l26.9-1.7c1.6-.1 3.6-1.4 4.4-2.9l.7-1.3c.7-1.5 2.7-2.8 4.4-2.9l4.5-.3c1.6-.1 3.1 1.1 3.3 2.8v.2c.2 1.6.5 3.7.7 4.6.2.9.3 3 .1 4.6l-2.2 21.3c-.2 1.6-1.7 3.1-3.3 3.3l-45.6 4z" class="st5" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10"/><path d="M55.684191 105.915676c-1.6.1-2.3-.4-2-2l4.4-25.6c.3-1.6 1.9-3 3.6-3.1l26.9-1.7c1.6-.1 3.6-1.4 4.4-2.9l.7-1.3c.7-1.5 2.7-2.8 4.4-2.9l4.5-.3c1.6-.1 3.1 1.1 3.3 2.8v.2c.2 1.6 1.3 2.9 2.5 2.8 1.2-.1 1.9 1.2 1.6 2.8l-5.2 24.9c-.3 1.6-2 3.1-3.6 3.2l-45.5 3.1z" style="fill:#191b22;fill-opacity:1"/><path d="M53.184191 104.315676l4.9-26c.3-1.6 1.9-3 3.6-3.1l26.9-1.7c1.6-.1 3.6-1.4 4.4-2.9l.7-1.3c.7-1.5 2.7-2.8 4.4-2.9l4.5-.3c1.6-.1 3.1 1.1 3.3 2.8v.2c.2 1.6 1.3 2.9 2.5 2.8 1.2-.1 1.9 1.2 1.6 2.8l-5.2 24.9c-.3 1.6-2 3.1-3.6 3.2l-46.7 3.7m9.2-103.9c-.3 2.9-2.9 4.9-4.1 5.8m8-3.2c-.7 3.5-4 6-4 6" class="st5" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10"/><path d="M39.884191 53.615676c-2.3-2.2-4.2-2.5-6.6-.6-2.4 1.9-2.1 4.8.9 7.6 3.1 2.9 4.7 4.1 6.7 5 2 .9 5.4 2.5 10.5-2s10.2-11.1 9.4-14.7c-.8-3.6-4.1-1.8-6.8 1.2s-3.7 4-5.4 5.2c-1.7 1.2-3.8 3-8.7-1.7z" class="st0" style="fill:#93a1b5;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;fill-opacity:1"/><path d="M44.384191 61.315676c-2.3 0-4.7-1.2-6.6-3.1-.9-.9-1.1-2-.7-2.9.3-.8 1.1-1.3 1.8-1.3.2 0 .5 0 .7.1 2.3 2.1 4.2 3.2 5.9 3.2 1.6 0 2.7-.8 3.5-1.4 1.7-1.3 2.8-2.3 5.5-5.3.9-1.1 1.9-1.9 2.7-2.4.3.2.6.4.7.8.2.8-.2 2-.7 2.7-.9 1.3-4.9 5.4-9 8.4-1.1.7-2.4 1.2-3.8 1.2z" style="fill:#b3bfcd;fill-opacity:1"/><path d="M45.784191 50.115676c-.7 0-1.4-.6-1.4-1.4v-6.1c0-.7.6-1.4 1.4-1.4.7 0 1.4.6 1.4 1.4v6.1c0 .8-.6 1.4-1.4 1.4z"/><path d="M61.184191 118.215676c.7-7.1-3.5-10.6-9.2-11.1-5.7-.5-10.2 6.8-9.1 13.1 1.1 6.3 6.7 7.2 6.7 7.2" class="st5" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10"/><path d="M52.084191 107.515676c-2.2-.7-4.3-1.4-6.5-2.2-2.1-.8-4.3-1.5-6.4-2.3-.1 0-.2-.2-.1-.3 0-.1.2-.2.3-.2 2.2.6 4.4 1.3 6.5 1.9 2.2.7 4.3 1.3 6.5 2 .3.1.4.4.3.6-.1.4-.4.6-.6.5zm25.4 10.1c-.2-1.4-.2-2.9.1-4.2.2-1.4.6-2.7 1.1-4-.3 1.3-.5 2.7-.6 4.1 0 1.4.1 2.7.4 4 .1.3-.1.5-.3.6-.2.1-.6-.1-.7-.5 0 .1 0 .1 0 0z"/><path d="M104.284191 103.615676c-3.6-.7-8.5 2.1-9.5 9.7s2.1 10.7 5.3 11.6m15.1-83.5l-.39999 1.4m-1.90001-1.2c2.4 1.7 6.4 3.4 6.4 3.4m-1.6-2.6l-.60001 1.59999" class="st5" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10"/><path d="M47.484191 79.215676c3.2 2.7 7 3.3 7 3.3" style="fill:none;stroke:#000;stroke-miterlimit:10"/><path d="M69.284191 24.315676c-3.5.4-2.7 2.9-1.2 3.5 1.5.6 3.7.1 4.3-1.6.4-1.6-1.3-2.1-3.1-1.9z" style="fill:#4f5862;fill-opacity:1"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.4144 232.00976"><path d="M211.80734 139.0875c-3.18125 16.36625-28.4925 34.2775-57.5625 37.74875-15.15875 1.80875-30.08375 3.47125-45.99875 2.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125 0 2.53375.15625 4.94625.46875 7.2025 3.38375 25.68625 25.47 27.225 46.39125 27.9425 21.11625.7225 39.91875-5.20625 39.91875-5.20625l.8675 19.09s-14.77 7.93125-41.08125 9.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234 213.82 1.40609 165.31125.20859 116.09125c-.365-14.61375-.14-28.39375-.14-39.91875 0-50.33 32.97625-65.0825 32.97625-65.0825C49.67234 3.45375 78.20359.2425 107.86484 0h.72875c29.66125.2425 58.21125 3.45375 74.8375 11.09 0 0 32.975 14.7525 32.975 65.0825 0 0 .41375 37.13375-4.59875 62.915" fill="#3088d4"/><path d="M177.50984 80.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025 0-17.4175 7.5075-17.4175 22.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375 0-15.74 6.32875-15.74 18.7975v59.15H38.90484V80.077c0-12.455 3.17125-22.3525 9.54125-29.675 6.56875-7.3225 15.17125-11.07625 25.85-11.07625 12.355 0 21.71125 4.74875 27.8975 14.2475l6.01375 10.08125 6.015-10.08125c6.185-9.49875 15.54125-14.2475 27.8975-14.2475 10.6775 0 19.28 3.75375 25.85 11.07625 6.36875 7.3225 9.54 17.22 9.54 29.675" fill="#fff"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.41507 232.00976"><path d="M211.80683 139.0875c-3.1825 16.36625-28.4925 34.2775-57.5625 37.74875-15.16 1.80875-30.0825 3.47125-45.99875 2.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125 0 2.53375.15625 4.94625.46875 7.2025 3.38375 25.68625 25.47 27.225 46.3925 27.9425 21.115.7225 39.91625-5.20625 39.91625-5.20625l.86875 19.09s-14.77 7.93125-41.08125 9.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23183 213.82 1.40558 165.31125.20808 116.09125c-.36375-14.61375-.14-28.39375-.14-39.91875 0-50.33 32.97625-65.0825 32.97625-65.0825C49.67058 3.45375 78.20308.2425 107.86433 0h.72875c29.66125.2425 58.21125 3.45375 74.8375 11.09 0 0 32.97625 14.7525 32.97625 65.0825 0 0 .4125 37.13375-4.6 62.915" fill="#3088d4"/><path d="M65.68743 96.45938c0 9.01375-7.3075 16.32125-16.3225 16.32125-9.01375 0-16.32-7.3075-16.32-16.32125 0-9.01375 7.30625-16.3225 16.32-16.3225 9.015 0 16.3225 7.30875 16.3225 16.3225M124.52893 96.45938c0 9.01375-7.30875 16.32125-16.3225 16.32125-9.01375 0-16.32125-7.3075-16.32125-16.32125 0-9.01375 7.3075-16.3225 16.32125-16.3225 9.01375 0 16.3225 7.30875 16.3225 16.3225M183.36933 96.45938c0 9.01375-7.3075 16.32125-16.32125 16.32125-9.01375 0-16.32125-7.3075-16.32125-16.32125 0-9.01375 7.3075-16.3225 16.32125-16.3225 9.01375 0 16.32125 7.30875 16.32125 16.3225" fill="#fff"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 713.35878 175.8678"><path d="M160.55476 105.43125c-2.4125 12.40625-21.5975 25.9825-43.63375 28.61375-11.49125 1.3725-22.80375 2.63125-34.8675 2.07875-19.73-.90375-35.2975-4.71-35.2975-4.71 0 1.92125.11875 3.75.355 5.46 2.565 19.47 19.3075 20.6375 35.16625 21.18125 16.00625.5475 30.2575-3.9475 30.2575-3.9475l.65875 14.4725s-11.19625 6.01125-31.14 7.11625c-10.99875.605-24.65375-.27625-40.56-4.485C6.99851 162.08 1.06601 125.31.15851 88-.11899 76.9225.05226 66.47625.05226 57.74125c0-38.1525 24.99625-49.335 24.99625-49.335C37.65226 2.6175 59.27976.18375 81.76351 0h.5525c22.48375.18375 44.125 2.6175 56.72875 8.40625 0 0 24.99625 11.1825 24.99625 49.335 0 0 .3125 28.1475-3.48625 47.69" fill="#3088d4"/><path d="M34.65751 48.494c0-5.55375 4.5025-10.055 10.055-10.055 5.55375 0 10.055 4.50125 10.055 10.055 0 5.5525-4.50125 10.055-10.055 10.055-5.5525 0-10.055-4.5025-10.055-10.055M178.86476 60.69975v46.195h-18.30125v-44.8375c0-9.4525-3.9775-14.24875-11.9325-14.24875-8.79375 0-13.2025 5.69125-13.2025 16.94375V89.2935h-18.19375V64.75225c0-11.2525-4.40875-16.94375-13.2025-16.94375-7.955 0-11.9325 4.79625-11.9325 14.24875v44.8375H73.79851v-46.195c0-9.44125 2.40375-16.94375 7.2325-22.495 4.98-5.55 11.50125-8.395 19.595-8.395 9.36625 0 16.45875 3.59875 21.14625 10.79875l4.56 7.6425 4.55875-7.6425c4.68875-7.2 11.78-10.79875 21.1475-10.79875 8.09375 0 14.61375 2.845 19.59375 8.395 4.82875 5.55125 7.2325 13.05375 7.2325 22.495M241.91276 83.663625c3.77625-3.99 5.595-9.015 5.595-15.075 0-6.06-1.81875-11.085-5.595-14.9275-3.63625-3.99125-8.25375-5.91125-13.84875-5.91125-5.59625 0-10.2125 1.92-13.84875 5.91125-3.6375 3.8425-5.45625 8.8675-5.45625 14.9275 0 6.06 1.81875 11.085 5.45625 15.075 3.63625 3.8425 8.2525 5.76375 13.84875 5.76375 5.595 0 10.2125-1.92125 13.84875-5.76375m5.595-52.025h18.04625v73.9h-18.04625v-8.72125c-5.455 7.2425-13.01 10.79-22.80125 10.79-9.3725 0-17.34625-3.695-24.06125-11.23375-6.57375-7.5375-9.93125-16.84875-9.93125-27.785 0-10.78875 3.3575-20.10125 9.93125-27.63875 6.715-7.5375 14.68875-11.38 24.06125-11.38 9.79125 0 17.34625 3.5475 22.80125 10.78875v-8.72zM326.26951 67.258625c5.315 3.99 7.97375 9.60625 7.83375 16.7 0 7.53875-2.65875 13.45-8.11375 17.58875-5.45625 3.99125-12.03 6.06-20.00375 6.06-14.40875 0-24.20125-5.9125-29.3775-17.58875l15.66875-9.31c2.0975 6.35375 6.71375 9.60625 13.70875 9.60625 6.43375 0 9.6525-2.07 9.6525-6.35625 0-3.10375-4.1975-5.91125-12.73-8.1275-3.21875-.8875-5.87625-1.77375-7.97375-2.51375-2.9375-1.18125-5.455-2.5125-7.55375-4.1375-5.17625-3.99-7.83375-9.3125-7.83375-16.11 0-7.2425 2.5175-13.00625 7.55375-17.145 5.17625-4.28625 11.47-6.355 19.025-6.355 12.03 0 20.84375 5.1725 26.5775 15.66625l-15.38625 8.8675c-2.23875-5.02375-6.015-7.53625-11.19125-7.53625-5.45625 0-8.11375 2.06875-8.11375 6.05875 0 3.10375 4.19625 5.91125 12.73 8.12875 6.575 1.4775 11.75 3.695 15.5275 6.50375M383.626635 49.966125h-15.8075v30.7425c0 3.695 1.4 5.91125 4.0575 6.945 1.95875.74 5.875.8875 11.75.59125v17.29375c-12.16875 1.4775-20.9825.295-26.15875-3.69625-5.175-3.8425-7.69375-10.93625-7.69375-21.13375v-30.7425h-12.17v-18.3275h12.17v-14.9275l18.045-5.76375v20.69125h15.8075v18.3275zM441.124885 83.2205c3.6375-3.84375 5.455-8.72125 5.455-14.6325 0-5.91125-1.8175-10.78875-5.455-14.63125-3.6375-3.84375-8.11375-5.76375-13.57-5.76375-5.455 0-9.93125 1.92-13.56875 5.76375-3.4975 3.99-5.31625 8.8675-5.31625 14.63125 0 5.765 1.81875 10.6425 5.31625 14.6325 3.6375 3.8425 8.11375 5.76375 13.56875 5.76375 5.45625 0 9.9325-1.92125 13.57-5.76375m-39.86875 13.15375c-7.13375-7.5375-10.63125-16.70125-10.63125-27.78625 0-10.9375 3.4975-20.1 10.63125-27.6375 7.13375-7.5375 15.9475-11.38 26.29875-11.38 10.3525 0 19.165 3.8425 26.3 11.38 7.135 7.5375 10.77125 16.84875 10.77125 27.6375 0 10.9375-3.63625 20.24875-10.77125 27.78625-7.135 7.53875-15.8075 11.2325-26.3 11.2325-10.49125 0-19.165-3.69375-26.29875-11.2325M524.92126 83.663625c3.6375-3.99 5.455-9.015 5.455-15.075 0-6.06-1.8175-11.085-5.455-14.9275-3.63625-3.99125-8.25375-5.91125-13.84875-5.91125-5.59625 0-10.2125 1.92-13.98875 5.91125-3.63625 3.8425-5.45625 8.8675-5.45625 14.9275 0 6.06 1.82 11.085 5.45625 15.075 3.77625 3.8425 8.5325 5.76375 13.98875 5.76375 5.595 0 10.2125-1.92125 13.84875-5.76375m5.455-81.585h18.04625v103.46h-18.04625v-8.72125c-5.315 7.2425-12.87 10.79-22.66125 10.79-9.3725 0-17.485-3.695-24.2-11.23375-6.575-7.5375-9.9325-16.84875-9.9325-27.785 0-10.78875 3.3575-20.10125 9.9325-27.63875 6.715-7.5375 14.8275-11.38 24.2-11.38 9.79125 0 17.34625 3.5475 22.66125 10.78875v-38.28zM611.79626 83.2205c3.63625-3.84375 5.455-8.72125 5.455-14.6325 0-5.91125-1.81875-10.78875-5.455-14.63125-3.6375-3.84375-8.11375-5.76375-13.57-5.76375-5.455 0-9.9325 1.92-13.56875 5.76375-3.49875 3.99-5.31625 8.8675-5.31625 14.63125 0 5.765 1.8175 10.6425 5.31625 14.6325 3.63625 3.8425 8.11375 5.76375 13.56875 5.76375 5.45625 0 9.9325-1.92125 13.57-5.76375m-39.86875 13.15375c-7.135-7.5375-10.63125-16.70125-10.63125-27.78625 0-10.9375 3.49625-20.1 10.63125-27.6375 7.135-7.5375 15.9475-11.38 26.29875-11.38 10.3525 0 19.165 3.8425 26.3 11.38 7.135 7.5375 10.77125 16.84875 10.77125 27.6375 0 10.9375-3.63625 20.24875-10.77125 27.78625-7.135 7.53875-15.8075 11.2325-26.3 11.2325-10.49125 0-19.16375-3.69375-26.29875-11.2325M713.35876 60.163875v45.37375h-18.04625v-43.00875c0-4.8775-1.25875-8.5725-3.77625-11.38-2.37875-2.5125-5.73625-3.84375-10.0725-3.84375-10.2125 0-15.3875 6.06-15.3875 18.3275v39.905h-18.04625v-73.89875h18.04625v8.27625c4.33625-6.94625 11.19-10.345 20.84375-10.345 7.69375 0 13.98875 2.66 18.885 8.12875 5.035 5.46875 7.55375 12.85875 7.55375 22.465" fill="#fff"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.4144 232.00976"><path d="M107.86523 0C78.203984.2425 49.672422 3.4535937 33.044922 11.089844c0 0-32.97656262 14.752031-32.97656262 65.082031 0 11.525-.224375 25.306175.140625 39.919925 1.19750002 49.22 9.02375002 97.72843 54.53124962 109.77343 20.9825 5.55375 38.99711 6.71547 53.505856 5.91797 26.31125-1.45875 41.08203-9.38867 41.08203-9.38867l-.86914-19.08984s-18.80171 5.92758-39.91796 5.20508c-20.921254-.7175-43.006879-2.25516-46.390629-27.94141-.3125-2.25625-.46875-4.66938-.46875-7.20313 0 0 20.536953 5.0204 46.564449 6.21289 15.915.73001 30.8393-.93343 45.99805-2.74218 29.07-3.47125 54.38125-21.3818 57.5625-37.74805 5.0125-25.78125 4.59961-62.916015 4.59961-62.916015 0-50.33-32.97461-65.082031-32.97461-65.082031C166.80539 3.4535938 138.255.2425 108.59375 0h-.72852zM74.296875 39.326172c12.355 0 21.710234 4.749297 27.896485 14.248047l6.01367 10.080078 6.01563-10.080078c6.185-9.49875 15.54023-14.248047 27.89648-14.248047 10.6775 0 19.28156 3.753672 25.85156 11.076172 6.36875 7.3225 9.53907 17.218828 9.53907 29.673828v60.941408h-24.14454V81.869141c0-12.46875-5.24453-18.798829-15.73828-18.798829-11.6025 0-17.41797 7.508516-17.41797 22.353516v32.375002H96.207031V85.423828c0-14.845-5.815468-22.353515-17.417969-22.353516-10.49375 0-15.740234 6.330079-15.740234 18.798829v59.148439H38.904297V80.076172c0-12.455 3.171016-22.351328 9.541015-29.673828 6.568751-7.3225 15.172813-11.076172 25.851563-11.076172z" fill="#fff"/></svg>
\ No newline at end of file
......@@ -4,7 +4,6 @@ import { throttle } from 'lodash';
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
import { tagHistory } from '../settings';
import { useEmoji } from './emojis';
import resizeImage from '../utils/resize_image';
import { importFetchedAccounts } from './importer';
import { updateTimeline } from './timelines';
import { showAlertForError } from './alerts';
......@@ -183,14 +182,18 @@ export function uploadCompose(files) {
dispatch(uploadComposeRequest());
resizeImage(files[0]).then(file => {
const data = new FormData();
data.append('file', file);
let data = new FormData();
data.append('file', files[0]);
return api(getState).post('/api/v1/media', data, {
onUploadProgress: ({ loaded, total }) => dispatch(uploadComposeProgress(loaded, total)),
}).then(({ data }) => dispatch(uploadComposeSuccess(data)));
}).catch(error => dispatch(uploadComposeFail(error)));
api(getState).post('/api/v1/media', data, {
onUploadProgress: function (e) {
dispatch(uploadComposeProgress(e.loaded, e.total));
},
}).then(function (response) {
dispatch(uploadComposeSuccess(response.data));
}).catch(function (error) {
dispatch(uploadComposeFail(error));
});
};
};
......
import api from '../api';
export const TOS_FETCH_REQUEST = 'TOS_FETCH_REQUEST';
export const TOS_FETCH_SUCCESS = 'TOS_FETCH_SUCCESS';
export const TOS_FETCH_FAIL = 'TOS_FETCH_FAIL';
export const PANEL_FETCH_REQUEST = 'PANEL_FETCH_REQUEST';
export const PANEL_FETCH_SUCCESS = 'PANEL_FETCH_SUCCESS';
export const PANEL_FETCH_FAIL = 'PANEL_FETCH_FAIL';
export const PLEROMA_CONFIG_FETCH_REQUEST = 'PLEROMA_CONFIG_FETCH_REQUEST';
export const PLEROMA_CONFIG_FETCH_SUCCESS = 'PLEROMA_CONFIG_FETCH_SUCCESS';
export const PLEROMA_CONFIG_FETCH_FAIL = 'PLEROMA_CONFIG_FETCH_FAIL';
export function fetchTOS() {
return (dispatch, getState) => {
dispatch(fetchTOSRequest());
api(getState).get('/static/terms-of-service.html').then(response => {
dispatch(fetchTOSSuccess(response.data));
}).catch(error => {
dispatch(fetchTOSFail(error));
});
};
};
export function fetchPanel() {
return (dispatch, getState) => {
dispatch(fetchPanelRequest());
api(getState).get('/instance/panel.html').then(response => {
dispatch(fetchPanelSuccess(response.data));
}).catch(error => {
dispatch(fetchPanelFail(error));
});
};
};
export function fetchPleromaConfig() {
return (dispatch, getState) => {
dispatch(fetchPleromaConfigRequest());
api(getState).get('/api/statusnet/config.json').then(response => {
dispatch(fetchPleromaConfigSuccess(response.data));
}).catch(error => {
dispatch(fetchPleromaConfigFail(error));
});
};
};
export function fetchTOSRequest() {
return {
type: TOS_FETCH_REQUEST,
};
};
export function fetchTOSSuccess(tos) {
return {
type: TOS_FETCH_SUCCESS,
tos,
};
};
export function fetchTOSFail(error) {
return {
type: TOS_FETCH_FAIL,
error,
};
};
export function fetchPanelRequest() {
return {
type: PANEL_FETCH_REQUEST,
};
};
export function fetchPanelSuccess(panel) {
return {
type: PANEL_FETCH_SUCCESS,
panel,
};
};
export function fetchPanelFail(error) {
return {
type: PANEL_FETCH_FAIL,
error,
};
};
export function fetchPleromaConfigRequest() {
return {
type: PLEROMA_CONFIG_FETCH_REQUEST,
};
};
export function fetchPleromaConfigSuccess(config) {
return {
type: PLEROMA_CONFIG_FETCH_SUCCESS,
config,
};
};
export function fetchPleromaConfigFail(error) {
return {
type: PLEROMA_CONFIG_FETCH_FAIL,
error,
};
};
......@@ -14,7 +14,10 @@ const urlBase64ToUint8Array = (base64String) => {
return decodeBase64(base64);
};
const getApplicationServerKey = () => document.querySelector('[name="applicationServerKey"]').getAttribute('content');
const getApplicationServerKey = () => {
const k = document.querySelector('[name="applicationServerKey"]');
return k === null ? '' : k.getAttribute('content');
}
const getRegistration = () => navigator.serviceWorker.ready;
......
import axios from 'axios';
import ready from './ready';
import LinkHeader from './link_header';
export const getLinks = response => {
......@@ -12,17 +11,10 @@ export const getLinks = response => {
return LinkHeader.parse(value);
};
let csrfHeader = {};
function setCSRFHeader() {
const csrfToken = document.querySelector('meta[name=csrf-token]').content;
csrfHeader['X-CSRF-Token'] = csrfToken;
}
ready(setCSRFHeader);
export default getState => axios.create({
headers: Object.assign(csrfHeader, getState ? {
headers: getState ? {
'Authorization': `Bearer ${getState().getIn(['meta', 'access_token'], '')}`,
} : {}),
} : {},
transformResponse: [function (data) {
try {
......
......@@ -20,7 +20,7 @@ const Hashtag = ({ hashtag }) => (
</div>
<div className='trends__item__sparkline'>
<Sparklines width={50} height={28} data={hashtag.get('history').reverse().map(day => day.get('uses')).toArray()}>
<Sparklines width={50} height={28} data={hashtag.get('history') && hashtag.get('history').reverse().map(day => day.get('uses')).toArray()}>
<SparklinesCurve style={{ fill: 'none' }} />
</Sparklines>
</div>
......
......@@ -146,6 +146,18 @@ class Item extends React.PureComponent {
/>
</a>
);
} else if (attachment.get('type') === 'audio') {
thumbnail = (
<div className='media-gallery__audio'>
<audio
className='media-gallery__item-audio-thumbnail'
aria-label={attachment.get('description')}
role='application'
src={attachment.get('url')}
controls
/>
</div>
);
} else if (attachment.get('type') === 'gifv') {
const autoPlay = !isIOS() && autoPlayGif;
......
......@@ -249,7 +249,7 @@ export default class Status extends ImmutablePureComponent {
</a>
</div>
<StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
<StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} collapsable />
{media}
......
......@@ -5,7 +5,7 @@ import IconButton from './icon_button';
import DropdownMenuContainer from '../containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me } from '../initial_state';
import { me, deleteOthersNotice } from '../initial_state';
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
......@@ -171,7 +171,9 @@ export default class StatusActionBar extends ImmutablePureComponent {
menu.push(null);
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
if ( deleteOthersNotice ) {
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
}
}
if (status.get('visibility') === 'direct') {
......
......@@ -17,11 +17,14 @@ export default class StatusContent extends React.PureComponent {
expanded: PropTypes.bool,
onExpandedToggle: PropTypes.func,
onClick: PropTypes.func,
collapsable: PropTypes.bool,
};
state = {
hidden: true,
collapsed: null,
};
// `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't).
_updateStatusLinks () {
const node = this.node;
......@@ -53,6 +56,13 @@ export default class StatusContent extends React.PureComponent {
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener');
}
if (
this.props.collapsable
&& this.state.collapsed === null
&& node.clientHeight > 200
&& this.props.status.get('spoiler_text').length === 0
) this.setState({ collapsed: true });
}
componentDidMount () {
......@@ -113,6 +123,11 @@ export default class StatusContent extends React.PureComponent {
}
}
handleCollapsedClick = (e) => {
e.preventDefault();
this.setState({ collapsed: !this.state.collapsed });
}
setRef = (c) => {
this.node = c;
}
......@@ -132,6 +147,8 @@ export default class StatusContent extends React.PureComponent {
const classNames = classnames('status__content', {
'status__content--with-action': this.props.onClick && this.context.router,
'status__content--with-spoiler': status.get('spoiler_text').length > 0,
'status__content--collapsed': this.state.collapsed === true,
'status__content--expanded': this.state.collapsed === false,
});
if (isRtl(status.get('search_index'))) {
......@@ -175,8 +192,17 @@ export default class StatusContent extends React.PureComponent {
style={directionStyle}
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
dangerouslySetInnerHTML={content}
/>
>
<div dangerouslySetInnerHTML={content} />
{this.state.collapsed !== null ?
<button
className='status__content__collapse-button'
onClick={this.handleCollapsedClick}
>
<i className='fa fa-fw fa-angle-double-down' />
</button>
: null}
</div>
);
} else {
return (
......
......@@ -75,8 +75,7 @@ export default class ActionBar extends React.PureComponent {
}
if (account.get('id') === me) {
menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });
menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });
menu.push({ text: intl.formatMessage(messages.preferences), href: '/user-settings' });
menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
menu.push(null);
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
......
......@@ -76,7 +76,7 @@ export default class Header extends ImmutablePureComponent {
};
openEditProfile = () => {
window.open('/settings/profile', '_blank');
window.open('/user-settings', '_blank');
}
render () {
......
......@@ -29,8 +29,7 @@ export default class ActionBar extends React.PureComponent {
let menu = [];
menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });
menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });
menu.push({ text: intl.formatMessage(messages.preferences), href: '/user-settings' });
menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
menu.push(null);
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
......
......@@ -16,7 +16,7 @@ import WarningContainer from '../containers/warning_container';
import { isMobile } from '../../../is_mobile';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz';
import { countableText } from '../util/counter';
import { maxChars } from '../../../initial_state';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
......@@ -78,9 +78,9 @@ export default class ComposeForm extends ImmutablePureComponent {
// Submit disabled:
const { is_submitting, is_uploading, anyMedia } = this.props;
const fulltext = [this.props.spoiler_text, countableText(this.props.text)].join('');
const fulltext = [this.props.spoiler_text, this.props.text].join('');
if (is_submitting || is_uploading || length(fulltext) > 500 || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
if (is_submitting || is_uploading || length(fulltext) > maxChars || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
return;
}
......@@ -155,8 +155,8 @@ export default class ComposeForm extends ImmutablePureComponent {
render () {
const { intl, onPaste, showSearch, anyMedia } = this.props;
const disabled = this.props.is_submitting;
const text = [this.props.spoiler_text, countableText(this.props.text)].join('');
const disabledButton = disabled || this.props.is_uploading || length(text) > 500 || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
const text = [this.props.spoiler_text, this.props.text].join('');
const disabledButton = disabled || this.props.is_uploading || length(text) > maxChars || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
let publishText = '';
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
......@@ -208,7 +208,7 @@ export default class ComposeForm extends ImmutablePureComponent {
<SensitiveButtonContainer />
<SpoilerButtonContainer />
</div>
<div className='character-counter__wrapper'><CharacterCounter max={500} text={text} /></div>
<div className='character-counter__wrapper'><CharacterCounter max={maxChars} text={text} /></div>
</div>
<div className='compose-form__publish'>
......
......@@ -27,8 +27,6 @@ export default class NavigationBar extends ImmutablePureComponent {
<Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`}>
<strong className='navigation-bar__profile-account'>@{this.props.account.get('acct')}</strong>
</Permalink>
<a href='/settings/profile' className='navigation-bar__profile-edit'><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
</div>
<div className='navigation-bar__actions'>
......
......@@ -20,7 +20,7 @@ class SearchPopout extends React.PureComponent {
const { style } = this.props;
const extraInformation = searchEnabled ? <FormattedMessage id='search_popout.tips.full_text' defaultMessage='Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' /> : <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' />;
return (
<div style={{ ...style, position: 'absolute', width: 285 }}>
<div style={{ ...style, position: 'absolute', width: 315 }}>
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
{({ opacity, scaleX, scaleY }) => (
<div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
......
......@@ -15,7 +15,7 @@ const mapStateToProps = state => ({
const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {
if (needsLockWarning) {
return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/settings/profile'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />;
return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/user-settings'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />;
}
if (hashtagWarning) {
......
......@@ -12,7 +12,6 @@ import Motion from '../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import SearchResultsContainer from './containers/search_results_container';
import { changeComposing } from '../../actions/compose';
import elephantUIPlane from '../../../images/elephant_ui_plane.svg';
const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
......@@ -88,7 +87,7 @@ export default class Compose extends React.PureComponent {
{!columns.some(column => column.get('id') === 'PUBLIC') && (
<Link to='/timelines/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><i role='img' className='fa fa-fw fa-globe' /></Link>
)}
<a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><i role='img' className='fa fa-fw fa-cog' /></a>
<a href='/user-settings' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><i role='img' className='fa fa-fw fa-cog' /></a>
<a href='/auth/sign_out' className='drawer__tab' data-method='delete' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)}><i role='img' className='fa fa-fw fa-sign-out' /></a>
</nav>
);
......@@ -104,11 +103,6 @@ export default class Compose extends React.PureComponent {
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
<NavigationContainer onClose={this.onBlur} />
<ComposeFormContainer />
{multiColumn && (
<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={elephantUIPlane} />
</div>
)}
</div>}
<Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
......
import { urlRegex } from './url_regex';
const urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx';
export function countableText(inputText) {
return inputText
.replace(urlRegex, urlPlaceholder)
.replace(/(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/ig, '$1@$3');
};
......@@ -9,6 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me, invitesEnabled } from '../../initial_state';
import { fetchFollowRequests } from '../../actions/accounts';
import { fetchPanel, fetchPleromaConfig } from '../../actions/pleroma';
import { List as ImmutableList } from 'immutable';
import { Link } from 'react-router-dom';
import NavigationBar from '../compose/components/navigation_bar';
......@@ -36,10 +37,14 @@ const messages = defineMessages({
const mapStateToProps = state => ({
myAccount: state.getIn(['accounts', me]),
unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
customPanelEnabled: state.getIn(['custom_panel', 'enabled']),
customPanel: state.getIn(['custom_panel', 'panel']),
});
const mapDispatchToProps = dispatch => ({
fetchFollowRequests: () => dispatch(fetchFollowRequests()),
fetchPanel: () => dispatch(fetchPanel()),
fetchPleromaConfig: () => dispatch(fetchPleromaConfig()),
});
const badgeDisplay = (number, limit) => {
......@@ -62,20 +67,27 @@ export default class GettingStarted extends ImmutablePureComponent {
columns: ImmutablePropTypes.list,
multiColumn: PropTypes.bool,
fetchFollowRequests: PropTypes.func.isRequired,
fetchPanel: PropTypes.func.isRequired,
fetchPleromaConfig: PropTypes.func.isRequired,
unreadFollowRequests: PropTypes.number,
unreadNotifications: PropTypes.number,
customPanelEnabled: PropTypes.bool,
customPanel: PropTypes.string.isRequired,
};
componentDidMount () {
const { myAccount, fetchFollowRequests } = this.props;
const { myAccount, fetchFollowRequests, fetchPleromaConfig, fetchPanel } = this.props;
if (myAccount.get('locked')) {
fetchFollowRequests();
}
fetchPleromaConfig();
fetchPanel();
}
render () {
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
const { intl, myAccount, multiColumn, unreadFollowRequests, customPanelEnabled, customPanel } = this.props;
const navItems = [];
let i = 1;
......@@ -108,13 +120,25 @@ export default class GettingStarted extends ImmutablePureComponent {
if (!multiColumn) {
navItems.push(
<ColumnSubheading key={i++} text={intl.formatMessage(messages.settings_subheading)} />,
<ColumnLink key={i++} icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
<ColumnLink key={i++} icon='lock' text={intl.formatMessage(messages.security)} href='/auth/edit' />
<ColumnLink key={i++} icon='gears' text={intl.formatMessage(messages.preferences)} href='/user-settings' />,
);
height += 34 + 48*2;
}
const dot = '';
const staticContent = (customPanelEnabled ? <div dangerouslySetInnerHTML={{__html: customPanel}} style={{marginLeft: -12, marginRight: -12}} /> :
<p>
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.faq' defaultMessage='FAQ' /></a>
{dot}
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' /></a>
{dot}
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' /></a>
{dot}
<a href='https://pleroma.social'><FormattedMessage id='getting_started.pleroma' defaultMessage='Pleroma' /></a>
</p>
);
return (
<Column>
{multiColumn && <div className='column-header__wrapper'>
......@@ -126,31 +150,32 @@ export default class GettingStarted extends ImmutablePureComponent {
</h1>
</div>}
<div className='getting-started__wrapper' style={{ height }}>
<div className='getting-started getting-started__wrapper scrollable'>
{!multiColumn && <NavigationBar account={myAccount} />}
{navItems}
</div>
{!multiColumn && <div className='flex-spacer' />}
<div className='getting-started getting-started__footer'>
<ul>
<li><a href='https://bridge.joinmastodon.org/' target='_blank'><FormattedMessage id='getting_started.find_friends' defaultMessage='Find friends from Twitter' /></a> · </li>
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li>
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
<li><a href='https://github.com/tootsuite/documentation#documentation' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
</ul>
<div className='getting-started getting-started__panel scrollable'>
{staticContent}
</div>
<div className='getting-started getting-started__footer scrollable'>
{(invitesEnabled || multiColumn) &&
<ul>
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a></li>}
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link></li>}
</ul>
}
<p>
<FormattedMessage
id='getting_started.open_source_notice'
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }}
id='getting_started.mastofe_notice'
defaultMessage='{mastofe} is libre software based on {mastodon} frontend adapted for {pleroma}.'
values={{
mastofe: <a href='https://git.pleroma.social/pleroma/mastofe' rel='noopener' target='_blank'>Mastofe</a>,
mastodon: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>Mastodon</a>,
pleroma: <a href='https://pleroma.social' rel='noopener' target='_blank'>Pleroma</a>
}}
/>
</p>
</div>
......
......@@ -2,6 +2,7 @@ const element = document.getElementById('initial-state');
const initialState = element && JSON.parse(element.textContent);
const getMeta = (prop) => initialState && initialState.meta && initialState.meta[prop];
const getRight = (prop) => initialState && initialState.rights && initialState.rights[prop];
export const reduceMotion = getMeta('reduce_motion');
export const autoPlayGif = getMeta('auto_play_gif');
......@@ -12,5 +13,8 @@ export const deleteModal = getMeta('delete_modal');
export const me = getMeta('me');
export const searchEnabled = getMeta('search_enabled');
export const invitesEnabled = getMeta('invites_enabled');
export const maxChars = getMeta('max_toot_chars') || getMeta('char_limit') || 5000;
export const deleteOthersNotice = getRight('delete_others_notice');
export default initialState;
......@@ -120,6 +120,7 @@
"getting_started.heading": "Getting started",
"getting_started.invite": "Invite people",
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
"getting_started.mastofe_notice": "{mastofe} is libre software based on {mastodon} frontend adapted for {pleroma}.",
"getting_started.security": "Security",
"getting_started.terms": "Terms of service",
"home.column_settings.advanced": "Advanced",
......
......@@ -120,6 +120,7 @@
"getting_started.heading": "Pour commencer",
"getting_started.invite": "Inviter des gens",
"getting_started.open_source_notice": "Mastodon est un logiciel libre. Vous pouvez contribuer et envoyer vos commentaires et rapports de bogues via {github} sur GitHub.",
"getting_started.mastofe_notice": "{mastofe} est un logiciel libre basé sur l’interface de {mastodon} adapté pour {pleroma}.",
"getting_started.security": "Sécurité",
"getting_started.terms": "Conditions d’utilisation",
"home.column_settings.advanced": "Avancé",
......
......@@ -12,7 +12,7 @@ function main() {
if (window.history && history.replaceState) {
const { pathname, search, hash } = window.location;
const path = pathname + search + hash;
if (!(/^\/web[$/]/).test(path)) {
if (!(/^\/web($|\/)/).test(path)) {
history.replaceState(null, document.title, `/web${path}`);
}
}
......
......@@ -26,6 +26,7 @@ import height_cache from './height_cache';
import custom_emojis from './custom_emojis';
import lists from './lists';
import listEditor from './list_editor';
import { custom_panel } from './pleroma';
const reducers = {
dropdown_menu,
......@@ -55,6 +56,7 @@ const reducers = {
custom_emojis,
lists,
listEditor,
custom_panel,
};
export default combineReducers(reducers);
import { Map as ImmutableMap } from 'immutable';
import { PANEL_FETCH_SUCCESS, PLEROMA_CONFIG_FETCH_SUCCESS } from '../actions/pleroma';
const initialPanel = ImmutableMap({
enabled: false,
panel: ''
});
export function custom_panel(state = initialPanel, action) {
switch (action.type) {
case PANEL_FETCH_SUCCESS:
return state.set('panel', action.panel); break;
case PLEROMA_CONFIG_FETCH_SUCCESS:
return state.set('enabled', (action.config || {}).site.pleromafe.showInstanceSpecificPanel || false);
}
return state;
};
......@@ -10,7 +10,7 @@ function openWebCache() {
}
function fetchRoot() {
return fetch('/', { credentials: 'include', redirect: 'manual' });
return fetch('/web', { credentials: 'include', redirect: 'manual' });
}
const firefox = navigator.userAgent.match(/Firefox\/(\d+)/);
......@@ -19,7 +19,7 @@ const invalidOnlyIfCached = firefox && firefox[1] < 60;
// Cause a new version of a registered Service Worker to replace an existing one
// that is already installed, and replace the currently active worker on open pages.
self.addEventListener('install', function(event) {
event.waitUntil(Promise.all([openWebCache(), fetchRoot()]).then(([cache, root]) => cache.put('/', root)));
event.waitUntil(Promise.all([openWebCache(), fetchRoot()]).then(([cache, root]) => cache.put('/web', root)));
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim());
......@@ -27,14 +27,18 @@ self.addEventListener('activate', function(event) {
self.addEventListener('fetch', function(event) {
const url = new URL(event.request.url);
if (url.pathname.startsWith('/web/')) {
if (url.pathname.startsWith('/web')) {
// we always make /web/login go through
if (url.pathname.startsWith('/web/login')) {
return;
}
const asyncResponse = fetchRoot();
const asyncCache = openWebCache();
event.respondWith(asyncResponse.then(
response => asyncCache.then(cache => cache.put('/', response.clone()))
response => asyncCache.then(cache => cache.put('/web', response.clone()))
.then(() => response),
() => asyncCache.then(cache => cache.match('/'))));
() => asyncCache.then(cache => cache.match('/web'))));
} else if (url.pathname === '/auth/sign_out') {
const asyncResponse = fetch(event.request);
const asyncCache = openWebCache();
......@@ -42,7 +46,7 @@ self.addEventListener('fetch', function(event) {
event.respondWith(asyncResponse.then(response => {
if (response.ok || response.type === 'opaqueredirect') {
return Promise.all([
asyncCache.then(cache => cache.delete('/')),
asyncCache.then(cache => cache.delete('/web')),
indexedDB.deleteDatabase('mastodon'),
]).then(() => response);
}
......
......@@ -74,7 +74,10 @@ export default function getStream(streamingAPIBaseURL, accessToken, stream, { co
const ws = new WebSocketClient(`${streamingAPIBaseURL}/api/v1/streaming/?${params.join('&')}`);
ws.onopen = connected;
ws.onmessage = e => received(JSON.parse(e.data));
ws.onmessage = e => {
if (e.data !== '')
received(JSON.parse(e.data));
}
ws.onclose = disconnected;
ws.onreconnect = reconnected;
......
......@@ -619,14 +619,33 @@
.status__content,
.reply-indicator__content {
position: relative;
font-size: 15px;
line-height: 20px;
word-wrap: break-word;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre-wrap;
padding-top: 2px;
strong {
font-weight: bold;
}
em {
font-style: italic;
}
/* green-texting */
blockquote {
color: #00d600;
&::before {
content: ">";
}
}
&:focus {
outline: 0;
}
......@@ -654,7 +673,7 @@
}
a {
color: $secondary-text-color;
color: $pleroma-links;
text-decoration: none;
&:hover {
......@@ -708,6 +727,55 @@
}
}
.status__content.status__content--collapsed {
padding-bottom: 25px;
max-height: 200px;
i {
transform: rotateX(0);
}
}
.status__content.status__content--expanded, {
padding-bottom: 25px;
height: auto;
i {
transform: rotateX(180deg);
}
}
.status__content__collapse-button {
display: block;
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 25px;
font-size: 18px;
line-height: 25px;
color: $inverted-text-color;
text-align: center;
background: $action-button-color;
transition: background .2s ease-in-out, color .2s ease-in-out;
border: 0;
border-radius: 2px;
&:hover {
background: lighten($action-button-color, 7%);
}
i {
transition: transform .2s ease-in-out;
&,
&:hover {
color: $inverted-text-color !important;
}
}
}
.status__content__spoiler-link {
display: inline-block;
border-radius: 2px;
......@@ -1365,6 +1433,7 @@ a.account__display-name {
}
.muted {
.status__content,
.status__content p,
.status__content a {
color: $dark-text-color;
......@@ -1743,6 +1812,8 @@ a.account__display-name {
> .scrollable {
background: $ui-base-color;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
}
......@@ -1756,7 +1827,7 @@ a.account__display-name {
}
.drawer {
width: 300px;
width: 330px;
box-sizing: border-box;
display: flex;
flex-direction: column;
......@@ -1786,11 +1857,19 @@ a.account__display-name {
margin-bottom: 0;
}
.getting-started__wrapper,
.getting-started__trends,
.search {
margin-bottom: 10px;
}
.getting-started__panel {
margin: 10px 0;
}
.column,
.drawer {
min-width: 330px;
}
}
@media screen and (max-width: 630px) {
......@@ -1817,7 +1896,7 @@ a.account__display-name {
.column,
.drawer {
flex: 0 0 auto;
flex: 1 1 auto;
padding: 10px;
padding-left: 5px;
padding-right: 5px;
......@@ -1862,6 +1941,7 @@ a.account__display-name {
overflow-y: auto;
width: 100%;
height: 100%;
border-radius: 2px;
&.darker {
background: $ui-base-color;
......@@ -1898,6 +1978,7 @@ a.account__display-name {
margin-bottom: 10px;
display: flex;
flex-direction: row;
border-radius: 2px;
a {
transition: background 100ms ease-in;
......@@ -2196,21 +2277,16 @@ a.account__display-name {
background: $ui-base-color;
}
.getting-started__wrapper {
flex: 0 0 auto;
}
.flex-spacer {
flex: 1 1 auto;
}
.getting-started {
color: $dark-text-color;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
p {
color: $dark-text-color;
font-size: 13px;
margin-bottom: 20px;
a {
color: $dark-text-color;
......@@ -2229,10 +2305,16 @@ a.account__display-name {
}
}
&__wrapper,
&__panel,
&__footer {
flex: 0 0 auto;
height: min-content;
}
&__panel, &__footer {
padding: 10px;
padding-top: 20px;
flex-grow: 0;
ul {
margin-bottom: 10px;
......@@ -2243,6 +2325,10 @@ a.account__display-name {
}
}
&__wrapper, &__footer {
color: $dark-text-color;
}
&__trends {
background: $ui-base-color;
flex: 0 1 auto;
......@@ -2527,7 +2613,6 @@ a.status-card {
}
&__figure {
background: url('../images/elephant_ui_working.svg') no-repeat center 0;
width: 100%;
height: 160px;
background-size: contain;
......@@ -2539,10 +2624,6 @@ a.status-card {
&.missing-indicator {
padding-top: 20px + 48px;
.regeneration-indicator__figure {
background-image: url('../images/elephant_ui_disappointed.svg');
}
}
&__label {
......@@ -2593,6 +2674,8 @@ a.status-card {
z-index: 2;
outline: 0;
overflow: hidden;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
& > button {
margin: 0;
......@@ -3338,6 +3421,7 @@ a.status-card {
color: $darker-text-color;
font-size: 14px;
margin: 0;
border-radius: 2px;
&::-moz-focus-inner {
border: 0;
......@@ -3836,7 +3920,6 @@ a.status-card {
}
.onboarding-modal__page__wrapper-0 {
background: url('../images/elephant_ui_greeting.svg') no-repeat left bottom / auto 250px;
height: 100%;
padding: 0;
}
......@@ -4315,6 +4398,14 @@ a.status-card {
}
}
.media-gallery__audio {
margin-top: 32px;
audio {
width: 100%;
}
}
.attachment-list {
display: flex;
font-size: 14px;
......
......@@ -15,6 +15,5 @@
> * {
flex: 1;
max-height: 235px;
background: url('../images/elephant_ui_plane.svg') no-repeat left bottom / contain;
}
}
......@@ -6,11 +6,17 @@ $error-red: #df405a !default; // Cerise
$warning-red: #ff5050 !default; // Sunset Orange
$gold-star: #ca8f04 !default; // Dark Goldenrod
// Pleroma-Dark colors
$pleroma-bg: #121a24;
$pleroma-fg: #182230;
$pleroma-text: #b9b9ba;
$pleroma-links: #d8a070;
// Values from the classic Mastodon UI
$classic-base-color: #282c37; // Midnight Express
$classic-primary-color: #9baec8; // Echo Blue
$classic-secondary-color: #d9e1e8; // Pattens Blue
$classic-highlight-color: #2b90d9; // Summer Sky
$classic-base-color: $pleroma-bg;
$classic-primary-color: #9baec8;
$classic-secondary-color: #d9e1e8;
$classic-highlight-color: #d8a070;
// Variables for defaults in UI
$base-shadow-color: $black !default;
......