Compare commits

...

149 Commits

Author SHA1 Message Date
David Yip
1b3ff6a92f Cascade mute/block destruction to notes (#193) 2018-01-27 01:31:22 -06:00
David Yip
2ce4af84e9 Put the less-specific column on the left-hand side (#193)
Some database systems can make better use of an index if the index
columns are ordered left-to-right in increasing specificity.  I'm not
sure if Postgres is one of those databases, but it also makes sense to
me to read an index as "ordered by type and then ID".
2018-01-27 01:25:22 -06:00
David Yip
c17c07158a Introduce Glitch::AccountRelationships (#193)
Where possible, it is a good idea to add new backend code in ways that
will minimize conflict with upstream changes.  We can't do that
everywhere, but we can move our custom methods to a module that won't
be modified upstream, and that's a start.

This commit also gets the block/mute note maps into
REST::RelationshipSerializer under the "block_notes" and "mute_notes"
keys.
2018-01-27 01:23:14 -06:00
David Yip
8f476ee39e Do not render note in RelationshipSerializer (#193)
RelationshipSerializer is used to render an Account's
block/mute/follow/etc. relationships; there won't be a note present on
an Account.  We'll need to look at a different serializer to render
notes.
2018-01-26 10:13:17 -06:00
David Yip
041168df31 Make Account#mute! spec expect returned Mute (#193) 2018-01-26 10:09:20 -06:00
David Yip
5e6a09498a Add notes to blocks (#193)
In this commit, we also push note creation into the AccountInteractions
concern, where we can:

1. create and persist model objects inside transactions without having
   to include job queuing inside the transaction
2. commonize the don't-add-a-blank-note check

Finally, this commit resolves a invocation-on-nil in
REST::RelationshipSerializer.
2018-01-26 04:05:42 -06:00
David Yip
1704e0066a Don't save mute notes if the note is blank (#193) 2018-01-25 22:42:19 -06:00
David Yip
27f8d2c739 Add notes to /api/v1/accounts/:id/mute (#193) 2018-01-25 22:38:02 -06:00
David Yip
47ec2eff65 Add notes to domain blocks and mutes (#193) 2018-01-25 22:07:14 -06:00
David Yip
a37753179d Introduce Glitch::Note (#193)
This is a model for attaching a single note to a single other entity.
For #193, we'll use it for annotating blocks, mutes, and account-level
domain blocks.
2018-01-25 22:07:11 -06:00
David Yip
00ce2be148 Merge remote-tracking branch 'origin/master' into gs-master
Conflicts:
	.travis.yml
2018-01-24 23:10:19 -06:00
Akihiko Odaki
7e07e61a30 Do not manually update system RubyGems (#6355)
Travis CI ships compatible system RubyGems now:
https://github.com/travis-ci/travis-ci/issues/8969#issuecomment-360288970
> I have repackaged the 2.5.0 archive for Linux to include RubyGems 2.7.4,
> which should have the fix for this issue. Please restart the affected
> jobs, and let us know how they go for you.
2018-01-25 04:23:29 +01:00
Akihiko Odaki
4a974c6db1 Do not require sudo on Travis CI (#6356)
The issue which the workaround for is now addressed:
https://github.com/travis-ci/travis-ci/issues/7941#issuecomment-310667894
> We've pushed out new stable trusty images to production with a patch.
2018-01-25 04:23:08 +01:00
Jenkins
0e10667fbe Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master 2018-01-24 19:17:11 +00:00
David Yip
1b4d79acf8 Merge pull request #346 from KnzkDev/fix/travis
Fix travis.yml
2018-01-24 13:09:13 -06:00
beatrix
5a4de1cf0f Merge pull request #349 from codl/patch-1
remove escapes from server-side ɣaml handler
2018-01-24 08:56:38 -05:00
abcang
a3c0a20373 Fix initial_state me in push_notification_register (#6349) 2018-01-24 14:37:46 +01:00
codl
9abb5becf4 remove escapes from server-side γaml handler
this matches a change that was made in the client-side equivalent
2018-01-24 14:23:25 +01:00
abcang
8cd2828e91 Fix hide and show media button on admin page (#6347) 2018-01-24 13:29:46 +01:00
Yamagishi Kazutoshi
3d881eed27 Add packs volume to docker-compose.yml (#6348) 2018-01-24 13:29:32 +01:00
Quenty31
7650506b39 l10n Occitan language update (#6346)
* Small changes

* update for email templates

* Digest changed

* Update oc.yml

waiting to finish

* Update oc.yml

* Update oc.yml

* Update oc.yml

* Update oc.json
2018-01-24 13:29:03 +01:00
Eugen Rochko
e6db3427b7 Bump to 2.2.0rc2 2018-01-24 04:16:30 +01:00
Eugen Rochko
daefbd66a6 Fix style of legacy column headers (#6342)
* Fix regression from #6199: Style of legacy column headers

* Fix tests

* Clean up variables
2018-01-24 04:03:51 +01:00
Eugen Rochko
b1daa71da5 Fix #6311: Replace relative URLs in CSS only for Premailer (#6335) 2018-01-24 02:57:14 +01:00
Eugen Rochko
1cc44cba81 Fix #6331 (#6341)
UserTrackingConcern is circumvented by SessionsController#create
because it calls warden, which calls the User#update_tracked_fields!
method directly. Move returning user logic to that method.
2018-01-23 20:52:30 +01:00
David Yip
c53d7196e6 Merge pull request #334 from ThibG/glitch-soc/cleanup-leftover-code
Remove some leftover code
2018-01-23 10:27:13 -06:00
ThibG
4ec9d8b4d9 Display deleted users' role as “Suspended” (#6339)
Follow-up to 6eb60260b1 which missed a spot where
the same error occurs.
2018-01-23 14:31:31 +01:00
Eugen Rochko
d966878e87 Update goldfinger, ostatus2 and http.rb versions (#6337) 2018-01-23 14:30:42 +01:00
Eugen Rochko
2fc2725076 Fix e-mail icon for reblog being stretched (#6336) 2018-01-23 14:30:28 +01:00
Thibaut Girka
2107891edb Remove some leftover code, I guess 2018-01-23 09:20:18 +01:00
ncls7615
16d5f9e162 Fix travis.yml 2018-01-23 15:50:59 +09:00
Eugen Rochko
69f13e7bca Fix regression from #6199: Make entire column header clickable (#6334) 2018-01-23 05:06:29 +01:00
Akihiko Odaki
613e7c7521 Rename ResolveRemoteAccountService to ResolveAccountService (#6327)
The service used to be named ResolveRemoteAccountService resolves local
accounts as well.
2018-01-22 14:25:09 +01:00
Akihiko Odaki
17cecd75ca Rename FetchRemoteResourceService to ResolveURLService (#6328)
The service used to be named FetchRemoteResourceService resolves local
URL as well.
2018-01-22 14:24:22 +01:00
Akihiko Odaki
8cc65cde27 Resolve URL for local account in follow authorization success view (#6324) 2018-01-22 14:22:14 +01:00
Renato "Lond" Cerqueira
b7f6ddeaf1 Weblate translations (#6323)
* Translated using Weblate (Galician)

Currently translated at 100.0% (56 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/gl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (543 of 543 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/gl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (543 of 543 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/gl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/gl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/gl/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/pt_BR/

* Translated using Weblate (Catalan)

Currently translated at 95.2% (517 of 543 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ca/

* Translated using Weblate (Catalan)

Currently translated at 99.6% (259 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ca/

* Translated using Weblate (Dutch)

Currently translated at 97.1% (543 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (559 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/gl/

* Translated using Weblate (Japanese)

Currently translated at 99.1% (554 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/

* Translated using Weblate (French)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (558 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/

* Translated using Weblate (Polish)

Currently translated at 99.8% (558 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pl/

* Translated using Weblate (Catalan)

Currently translated at 94.6% (529 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ca/

* Translated using Weblate (Catalan)

Currently translated at 95.3% (533 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ca/

* Translated using Weblate (Dutch)

Currently translated at 98.2% (55 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/nl/

* Translated using Weblate (Dutch)

Currently translated at 98.3% (550 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/

* Translated using Weblate (Catalan)

Currently translated at 95.3% (533 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ca/

* Translated using Weblate (Japanese)

Currently translated at 0.0% (0 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ja/

* Translated using Weblate (Japanese)

Currently translated at 1.7% (1 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ja/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/

* Translated using Weblate (Japanese)

Currently translated at 1.7% (52 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (558 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (558 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/

* Translated using Weblate (Galician)

Currently translated at 100.0% (261 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/gl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (261 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/gl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (261 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/pl/

* Translated using Weblate (Catalan)

Currently translated at 99.6% (260 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ca/

* Translated using Weblate (Japanese)

Currently translated at 99.6% (260 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (558 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.6% (260 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/

* Translated using Weblate (French)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (261 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (261 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (French)

Currently translated at 99.2% (555 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/fr/

* Translated using Weblate (French)

Currently translated at 99.8% (558 of 559 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (261 of 261 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Normalize translations
Ran i18n-tasks normalize && yarn manage:translations

* Add back values removed by weblate
2018-01-22 14:20:58 +01:00
David Yip
a90d0419d9 Merge pull request #343 from glitch-soc/merge-upstream-20180121
Merge upstream
2018-01-21 18:00:08 -06:00
Jeong Arm
143fb54ab9 Korean translation (#6322)
Related to #6273
2018-01-22 08:49:57 +09:00
David Yip
48d79007f6 Merge remote-tracking branch 'origin/master' into merge-upstream-20180121 2018-01-21 16:26:50 -06:00
David Yip
81b78fac54 Update Vagrantfile to ubuntu/xenial64.
The version of Redis that ships with Ubuntu Trusty is too old to support
the HyperLogLog commands.  I guess we could add a custom apt repo for
this, but it seems a lot easier to just use the latest Ubuntu LTS
release (i.e. xenial), which has a recent-enough Redis in its archives.
2018-01-21 16:09:40 -06:00
Norayr Chilingarian
48cd6dc6ca armenian translations initial commit (#6320)
* adding armenian translations

* updating config files for armenian translations

* armenian translation fix

* fixing spaces
2018-01-22 05:02:23 +09:00
David Yip
1253279feb Merge remote-tracking branch 'origin/master' into merge-upstream
Conflicts:
	app/controllers/settings/two_factor_authentication/confirmations_controller.rb
2018-01-21 13:36:10 -06:00
codl
cfd2b06821 fix filter search index being too strict when looking for line breaks (#6318) 2018-01-21 13:23:17 +01:00
ThibG
d613dda91d Fix assets loading when WEB_DOMAIN ≠ LOCAL_DOMAIN (#6319)
Since 872a0d5bd8, assets URL are absolute and
not relative. Unfortunately, the domain used to build such URLs is the wrong
one: LOCAL_DOMAIN, and not WEB_DOMAIN, where the assets are stored.
2018-01-21 13:22:31 +01:00
Aboobacker MK
112b1fa265 Redirect to 2FA creation page when otp_secret is not available (#6314) 2018-01-21 13:21:28 +01:00
Eugen Rochko
31d1485887 Display number of follow requests in getting started menu, and (#6313)
if notifications column is not mounted, also display number of
unread notifications there.
2018-01-21 13:20:20 +01:00
Eugen Rochko
1287de1b83 Fix invalid value passed to full_asset_url in mailers (#6312) 2018-01-21 13:20:00 +01:00
David Yip
2c578a01d8 Merge remote-tracking branch 'origin/master' into gs-master 2018-01-20 16:42:57 -06:00
David Yip
e7a0840f8c Merge pull request #336 from ThibG/glitch-soc/features/tag-warning
Display a warning when composing unlisted toots with something looking like a hashtag
2018-01-20 16:37:52 -06:00
David Yip
24b6e4121f Merge pull request #342 from glitch-soc/merge-upstream
Merge upstream
2018-01-20 16:37:35 -06:00
Iijima Yasushi
72f9eab3d6 Change mailer avatar url (#6309)
* Change mailer avatar url

* Use full_asset_url method
2018-01-20 19:27:13 +01:00
David Yip
3cae362214 Merge new onboarding styles; delete refs to PNGs. 2018-01-20 11:23:06 -06:00
David Yip
38f6d8130d Eliminate stray conflict markers. 2018-01-20 10:46:43 -06:00
David Yip
071c2c9c85 Merge remote-tracking branch 'origin/master' into merge-upstream
Conflicts:
	app/javascript/styles/mastodon/components.scss
2018-01-20 10:45:43 -06:00
Eugen Rochko
0b7a0d15c7 Bump version to 2.2.0rc1 2018-01-20 16:27:19 +01:00
SerCom_KC
80b3ca0f6f Update Simplified Chinese translations (#6306)
* i18n: (zh-CN) Add translations of #6251

* i18n: (zh-CN) Improve translations for #6291

* Fix en.json

* i18n: (zh-CN) Update translations for #6303

* i18n: (zh-CN) Add translations of #6273
with minor adjustment

* Minor fix

* Minor fix
2018-01-21 00:11:21 +09:00
Eugen Rochko
45afdf1781 Fix #6269 - Render LOCAL_DOMAIN as unicode in presentational views (#6305) 2018-01-20 03:49:06 +01:00
Eugen Rochko
79b34a0fa2 Restore onboarding modal (#6303)
* Restore onboarding modal
Revert 5ba8b3a396895ecec083c5258aaf9084d584a7c4

* Change greeting elephant graphic, fix up some design issues

* Fix wrong link color in onboarding modal
2018-01-20 01:32:37 +01:00
Eugen Rochko
872a0d5bd8 Improve HTML e-mails based on Litmus tests (#6301)
* Use PNG images in HTML e-mails

* Make webpack use URLs with host so fonts load inside HTML e-mails

Convert this back to a relative URL in the premailer CSS loader
since local requests are quicker

* Improve responsive design

* Add missing PNG icon
2018-01-20 01:32:21 +01:00
Eugen Rochko
01421999ae Make text e-mails consistent with HTML ones in UserMailer (#6291)
* Make text e-mails consistent with HTML ones in UserMailer

* Fix UserMailer specs
2018-01-20 01:32:05 +01:00
David Yip
2ca965c704 Merge remote-tracking branch 'origin/master' into merge-upstream
Conflicts:
	app/javascript/styles/mastodon/components.scss
	app/javascript/styles/mastodon/modal.scss
2018-01-19 15:22:10 -06:00
David Yip
b8c6656ce9 Merge pull request #339 from ThibG/glitch-soc/features/timeline-tweaks
Do not discard statuses obtained via websocket when API request finishes
2018-01-19 15:17:20 -06:00
Thibaut Girka
1619efd735 Do not discard statuses obtained via websocket when API request finishes
This backports 0b888acfd4
2018-01-19 21:59:12 +01:00
ThibG
0b888acfd4 Do not throw away statuses obtained via websocket when API request finishes (#6302) 2018-01-19 21:48:00 +01:00
Yamagishi Kazutoshi
238de58e65 Change belongs_to_required_by_default to true (#5888) 2018-01-19 20:56:47 +01:00
Yamagishi Kazutoshi
7233ac07d2 Add support Ruby v2.5.0 (#6097) 2018-01-19 20:53:30 +01:00
ThibG
b1e03197fa Process mentions and reblogs even from resolved threads (#6299)
This may lead to out-of-order notifications, but this is better than not having
notifications at all.
2018-01-19 19:11:35 +01:00
Pierre Ozoux
7be53a10b0 Fix "tzinfo-data is not present" docker error (#6300)
when starting the container.
2018-01-19 19:11:19 +01:00
ThibG
a0de3222dd Retry delivering toots over ActivityPub for about 2 days (#6298)
Currently, Mastodon will retry delivering toots for a bit over 1 hour.
This is a very short timespan when considering private and direct toots, which
cannot be seen by the recipient at all after the delivery attempts have failed.

Ideally, private and direct toots should have a different number of retries,
but I do not know how to do that.
2018-01-19 15:49:48 +01:00
Eugen Rochko
540b3f37ae Replace drawer elephant graphic with a vector image (#6286)
* Replace drawer elephant graphic with a vector image

* Replace wave graphic with SVG

* Remove unused elephant graphic
2018-01-19 15:25:27 +01:00
Marcin Mikołajczak
852b48295f i18n: Update Polish translation (#6297) 2018-01-19 21:49:25 +09:00
Thibaut Girka
1287b2782b Display a warning when composing unlisted toots with something looking like a hashtag
This is a backport of b6af88192f to the glitch flavour.
2018-01-19 12:59:33 +01:00
David Yip
2b2de41bc7 Merge remote-tracking branch 'personal/merge/tootsuite/master' into gs-master 2018-01-18 23:40:37 -06:00
David Yip
26ecee79bf Merge pull request #332 from glitch-soc/merge-upstream
Merge in home feed regeneration changes from upstream
2018-01-18 22:00:11 -06:00
David Yip
ae369bceb3 Merge pull request #333 from glitch-soc/win95-update
Update win95 theme from cybrespace/mastodon
2018-01-18 13:35:24 -06:00
Eugen Rochko
9b3b40df66 Fix regeneration marker not expiring (#6290)
* Fix regeneration key not getting expired

* Add rake task to remove old regeneration markers
2018-01-18 20:29:56 +01:00
Eugen Rochko
d799921c75 Replace tutorial modal with welcome e-mail (#6273)
* Remove onboarding modal

* Welcome e-mail

* Send welcome e-mail after confirmation

* Remove obsolete translations
2018-01-18 19:17:25 +01:00
David Yip
766d6aac44 Strip trailing whitespace on win95.scss 2018-01-18 10:54:50 -06:00
David Yip
d3f64812a6 Merge remote-tracking branch 'cybrespace/theme_win95' into win95-update
Conflicts:
	app/javascript/styles/win95.scss
	config/themes.yml
2018-01-18 10:54:12 -06:00
David Yip
3896cd5d79 Use absolute paths for new working/not-found SVGs
This allows these component styles to be used in i.e. the win95 skin.
2018-01-18 10:25:54 -06:00
David Yip
bcd86404da Port 7badad7797 to glitch frontend 2018-01-18 10:25:37 -06:00
David Yip
1964a0f941 Merge remote-tracking branch 'origin/master' into merge-upstream 2018-01-18 09:17:58 -06:00
David Yip
e27eedbd08 Merge branch 'gs-master' into merge-upstream 2018-01-18 09:14:28 -06:00
David Yip
708ec07e27 Style fixes to make eslint happier, hopefully 2018-01-18 09:13:07 -06:00
Renato "Lond" Cerqueira
e56404be41 When must_be_following_dm is on, only notify if recipient dm'ed user (#6283)
* When must_be_following_dm is on, only notify if recipient dm'ed user
Currently, when must_be_following_dm is on, if a user sends a direct
message replying to any status from the recipient, the recipient gets a
notification. This should not be the case, as if the recipient posted
something publicly this can be used to spam their notifications.

* Refactor replied_to_status_is_direct_message?
Following suggestion in PR
2018-01-18 16:12:10 +01:00
David Yip
201e82686f Merge remote-tracking branch 'origin/master' into merge-upstream
Conflicts:
      app/javascript/styles/mastodon/components.scss
2018-01-17 18:37:09 -06:00
Eugen Rochko
7badad7797 Fix home regeneration (#6251)
* Fix regeneration marker not being removed after completion

* Return HTTP 206 from /api/v1/timelines/home if regeneration in progress
Prioritize RegenerationWorker by putting it into default queue

* Display loading indicator and poll home timeline while it regenerates

* Add graphic to regeneration message

* Make "not found" indicator consistent with home regeneration
2018-01-17 23:56:03 +01:00
Jenkins
fe5c1f0803 Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master 2018-01-17 22:17:14 +00:00
Renato "Lond" Cerqueira
59797ee233 Weblate translations (#6284)
* Translated using Weblate (French)

Currently translated at 100.0% (56 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/fr/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (56 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ca/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (45 of 45 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/pt_BR/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (529 of 529 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (45 of 45 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/nl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (529 of 529 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/gl/

* Translated using Weblate (Galician)

Currently translated at 100.0% (45 of 45 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/gl/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.6% (527 of 529 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (528 of 529 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (45 of 45 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/pt_BR/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (56 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/sk/

* Translated using Weblate (Slovak)

Currently translated at 37.2% (197 of 529 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (260 of 260 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sk/

* Translated using Weblate (Russian)

Currently translated at 99.0% (526 of 531 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ru/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (45 of 45 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/ca/

* Translated using Weblate (Catalan)

Currently translated at 99.8% (530 of 531 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ca/

* Translated using Weblate (Japanese)

Currently translated at 92.8% (52 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ja/

* Translated using Weblate (Japanese)

Currently translated at 75.8% (47 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/ja/

* Translated using Weblate (Polish)

Currently translated at 77.4% (48 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/pl/

* Translated using Weblate (Slovak)

Currently translated at 38.3% (204 of 532 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/ja/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/ca/

* Translated using Weblate (Polish)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/pl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (75 of 75 strings)

Translation: Mastodon/Doorkeeper
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/pl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/pl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (56 of 56 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/pl/

* Translated using Weblate (Russian)

Currently translated at 96.8% (525 of 542 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ru/

* Translated using Weblate (Japanese)

Currently translated at 99.0% (537 of 542 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/

* Translated using Weblate (Polish)

Currently translated at 99.8% (541 of 542 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pl/

* Translated using Weblate (Japanese)

Currently translated at 99.0% (538 of 543 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/

* Translated using Weblate (Dutch)

Currently translated at 97.4% (529 of 543 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/

* Normalize translations
Ran i18n-tasks normalize && yarn manage:translations
2018-01-18 07:00:23 +09:00
Jenkins
aa2bf07281 Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master 2018-01-17 16:17:10 +00:00
りんすき
fbe7756da6 implement web share target (#6278)
* web share target

* fix

* fix
2018-01-17 17:08:10 +01:00
Yamagishi Kazutoshi
0a103c7749 Upgrade ESLint to version 4.x (#6276) 2018-01-17 16:57:15 +01:00
SerCom_KC
fb16c37d2a Update Simplified Chinese translations (#6280)
* i18n: (zh-CN) Update translation for #6252

* e-mail -> email

* i18n: (zh-CN) Update translations for #6256

* i18n: (zh-CN) Minor Improvements

* i18n: (zh-CN) Update translations for #6263

* i18n: (zh-CN) Update translations for #6279
2018-01-17 16:47:25 +01:00
Eugen Rochko
6f244ba82c Use better reblog icon and improve contrast in HTML e-mails (#6272) 2018-01-17 14:12:59 +01:00
Mike Burns
ea75ae2d1f Use be_within instead of eq for a to_f test match (#6275)
Floating point values are notoriously hard to pin down, so use the
`be_within` matcher to verify the approximate value.
2018-01-17 12:45:09 +01:00
Jeong Arm
acb982fc66 Korean translate (#6277)
* Translate Korean

* Translate Korean #6263
2018-01-17 12:42:11 +01:00
mayaeh
eed7484cd6 Change mailer image url (#6279)
* Change image URL in mailer to full path

* Add application_mailer.view_profile localization.
2018-01-17 12:41:24 +01:00
Eugen Rochko
02194838dd HTML e-mails for NotificationMailer (#6263)
* HTML e-mails for NotificationMailer (except digest)

* Add HTML template for digest

* Fix build
2018-01-16 20:20:15 +01:00
SerCom_KC
3323b4173e Change disclaimer in email according to #5817 (#6266) 2018-01-16 06:44:57 +01:00
Yamagishi Kazutoshi
9a28052e92 Change image URL in mailer to full path (#6264) 2018-01-16 06:26:46 +01:00
kibi!
60ff086960 Fixed improper mailer import 2018-01-15 21:23:26 -08:00
kibi!
cda845ae0e Fix mailer to use webpack core 2018-01-15 21:17:03 -08:00
Yamagishi Kazutoshi
e6fd4bea35 Stop duplicate CI with Pull Request (#6265)
see also https://blog.travis-ci.com/2012-08-13-build-workflow-around-pull-requests
2018-01-16 06:15:28 +01:00
David Yip
89a9d629f7 Merge remote-tracking branch 'origin/master' into gs-master
Conflicts:
	Gemfile.lock
2018-01-15 22:17:48 -06:00
Eugen Rochko
5276c0a090 HTML e-mails for UserMailer (#6256)
- premailer gem to turn CSS into inline styles automatically
- rework UserMailer templates
- reword UserMailer templates
2018-01-16 03:29:11 +01:00
Eugen Rochko
7861c5f108 Surround mid-text display names with bdi tags (#6257)
* Fix #1095 - Surround mid-text display names with bdi tags

* Update jest snapshot
2018-01-15 18:55:10 +01:00
Eugen Rochko
3987bd18a4 Fix #6128 - Display unfollow button even if account moved (#6258) 2018-01-15 18:42:15 +01:00
Jenkins
0c7dc6c781 Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master 2018-01-15 06:17:15 +00:00
puckipedia
74c1c9ec01 Allow attributedTo in a status to be an embedded object (#6238) 2018-01-15 06:51:46 +01:00
Patrick Figel
537d2939b1 Suppress CSRF token warnings (#6240)
CSRF token checking was enabled for API controllers in #6223,
producing "Can't verify CSRF token authenticity" log spam. This
disables logging of failed CSRF checks.

This also changes the protection strategy for
PushSubscriptionsController to use exceptions, making it consistent
with other controllers that use sessions.
2018-01-15 06:51:23 +01:00
neetshin
2091ae92be Make columns-area unscrollable when modal opened (#6241)
* Add aria-autocomplete='list' in Textaria

ref: https://www.w3.org/TR/wai-aria-1.1/#aria-autocomplete

* Make detect empty string brefore assign upload description

* Change code elements in keyboard-shortcuts component to kbd

* Add validation for onMuteNotifications

* Make columns-area unscrollable when modal opend

* Make columns-area unscrollable when modal opened
2018-01-15 06:51:00 +01:00
Jeong Arm
dcc614f869 Add some browsers (#6246)
Related: #6165
2018-01-15 06:50:29 +01:00
Eugen Rochko
ed867eca9d Move e-mail digest task to sidekiq, reduce workload, improve hint (#6252) 2018-01-15 04:34:28 +01:00
Gô Shoemake
08e4c78e78 Fix column headers accessibility (#6199)
* Fix accessibility of column headers

As a screen reader user new to Mastodon, I encountered the following issues with the column headers as designed:
 * Jumping between them was difficult. FOr instance, passing my home timeline to reach notification settings was difficult to impossible, especially considering infinite scrolling.
 * There doesn't appear to be any means for triggering the control via the keyboard. the `titleClick` handler only responds to mouse clicks.
 * I didn't even realize there was a Settings toggle until I made this change.

Thanks for using ARIA in your designs. It's a huge help. But adding a `button` role doesn't add keyboard handling and other button behavior. Also, because the role was on the heading container, it obscured the controls within the container itself. This fix resolve that. It also exposes the headings as headings rather than buttons, enabling skipping columns by using screen readers' heading navigation commands.

Since I myself am blind, if this fix requires additional visual styling, I'd like help applying that so it can be merged. I'd consider it an essential accessibility fix for my and other blind users' existence on the platform. Thanks!

* Styling fixes

* Fixed overflow issue
2018-01-15 04:33:06 +01:00
kibi!
8ee6ed358f Increase priority of favstar gold 2018-01-14 16:05:44 -08:00
kibi!
1ee0e91fb6 Fixes to notification styling 2018-01-14 15:48:54 -08:00
kibi!
b9f4896830 Fixes to drawer and CWs 2018-01-14 15:31:00 -08:00
beatrix
cd6674606f Merge pull request #329 from KnzkDev/scss-refactor
SCSS Refactor
2018-01-14 17:48:02 -05:00
beatrix
39f231f3da Merge pull request #328 from glitch-soc/feature/glitchy-elephant-friend
Add glitchy elephant friend
2018-01-14 17:40:27 -05:00
kibi!
0fb3bd09e9 Oops this should have been a part of last commit 2018-01-14 14:21:41 -08:00
kibi!
1fa03e026a Fixes onboarding modal (#318) 2018-01-14 14:13:24 -08:00
kibi!
a5931e1f48 Fixed autocollapse detection 2018-01-14 13:29:51 -08:00
David Yip
c2669f93d0 Fix eslint errors. #294. 2018-01-14 05:56:43 -06:00
David Yip
756a9cd139 Run slightly less afoul of accessibility checks. #294.
This makes the clickable element an interactive element, but doesn't add
alt text and makes it not-obvious that you can click the elefriend.  On
one hand, this goes against good practice; on the other hand, it's not
*supposed* to be obvious that you can click the elefriend.
2018-01-14 05:07:08 -06:00
David Yip
e64cc311dd Introduce a bit of luck into the elefriend selection. #294. 2018-01-14 04:46:21 -06:00
David Yip
53cbc9933e Add wave background; blend elefriend in a bit more. #294. 2018-01-14 04:00:21 -06:00
David Yip
cd1377de7f Bind click event to elefriend cycling. #294. 2018-01-14 03:35:25 -06:00
David Yip
1dbb6b5e08 Set glitchy elephant friend variant in initial state. #294.
Also lay some groundwork needed to interactively change the
glitchfriend.

The codebase uses "elefriend" because it's shorter and didn't require me
to realign the actions in actions/compose.js.  Same idea, though.
2018-01-14 03:06:11 -06:00
David Yip
1e0b707018 Add the shrinking glitchy elefriend. #294. 2018-01-13 21:27:39 -06:00
David Yip
835eec8a4c Prototype out glitchy elephant friend. #294.
Glitched elephant friends kindly provided by @ncls7615.
2018-01-13 21:27:14 -06:00
ncls7615
f9b08e2142 Fix collapsed toot style 2018-01-14 11:13:55 +09:00
ncls7615
1ebe66b78c Fix un-fullwidth media style 2018-01-14 11:07:32 +09:00
ncls7615
be2bac05aa Fix media detailed style 2018-01-14 10:38:51 +09:00
ncls7615
b5476f6c75 Fix confirmation modal bug 2018-01-14 09:51:01 +09:00
ncls7615
bc0524834e Fix letterbox bug 2018-01-14 09:25:35 +09:00
ncls7615
6ecf81cacf Improve scss refactor 5 2018-01-14 09:17:38 +09:00
ncls7615
64425dbb77 Improve scss refactor 4 2018-01-14 09:12:10 +09:00
ncls7615
a16d885ac9 Improve scss refactor 3 2018-01-14 08:47:59 +09:00
ncls7615
5f35b39f6f Improve scss refactor 2 2018-01-14 07:48:18 +09:00
ncls7615
bb2ca23839 Improve scss refactor 1 2018-01-14 07:18:50 +09:00
ncls7615
a9be680807 Fix padded-blocks error 2018-01-14 04:12:41 +09:00
ncls7615
6a73c8c8a2 Initial scss refactor 2018-01-14 03:41:20 +09:00
beatrix
9526aababc Merge pull request #324 from glitch-soc/load-public-on-admin
Load public javascripts on admin pages
2018-01-12 23:52:41 -05:00
Andrew
fe6663ef50 Minor style fixes 2018-01-08 11:49:08 -08:00
Andrew
56312df73b Z indexes and colors 2018-01-06 18:38:19 -08:00
Andrew
7a93acd803 To 2.1.2 2018-01-06 18:25:19 -08:00
Andrew
077f2e600c Win95 to 2.1 2018-01-05 16:22:58 -08:00
Andrew
39c0b6ceb3 Updates and fixes to win95 theme 2018-01-05 16:22:58 -08:00
Andrew
ed574fbc09 Theme: Windows 95 2018-01-05 16:22:58 -08:00
528 changed files with 8291 additions and 5705 deletions

View File

@@ -27,6 +27,7 @@ plugins:
enabled: true
eslint:
enabled: true
channel: eslint-4
rubocop:
enabled: true
scss-lint:

View File

@@ -17,11 +17,9 @@ plugins:
parserOptions:
sourceType: module
ecmaFeatures:
arrowFunctions: true
experimentalObjectRestSpread: true
jsx: true
destructuring: true
modules: true
spread: true
ecmaVersion: 2018
settings:
import/extensions:
@@ -114,6 +112,7 @@ rules:
react/self-closing-comp: error
jsx-a11y/accessible-emoji: warn
jsx-a11y/alt-text: warn
jsx-a11y/anchor-has-content: warn
jsx-a11y/aria-activedescendant-has-tabindex: warn
jsx-a11y/aria-props: warn
@@ -124,16 +123,22 @@ rules:
jsx-a11y/href-no-hash: warn
jsx-a11y/html-has-lang: warn
jsx-a11y/iframe-has-title: warn
jsx-a11y/img-has-alt: warn
jsx-a11y/img-redundant-alt: warn
jsx-a11y/interactive-supports-focus: warn
jsx-a11y/label-has-for: off
jsx-a11y/mouse-events-have-key-events: warn
jsx-a11y/no-access-key: warn
jsx-a11y/no-distracting-elements: warn
jsx-a11y/no-noninteractive-element-interactions:
- warn
- handlers:
- onClick
jsx-a11y/no-onchange: warn
jsx-a11y/no-redundant-roles: warn
jsx-a11y/onclick-has-focus: warn
jsx-a11y/onclick-has-role: warn
jsx-a11y/no-static-element-interactions:
- warn
- handlers:
- onClick
jsx-a11y/role-has-required-aria-props: warn
jsx-a11y/role-supports-aria-props: off
jsx-a11y/scope: warn

View File

@@ -1 +1 @@
2.4.2
2.5.0

View File

@@ -8,7 +8,7 @@ cache:
- public/packs-test
- tmp/cache/babel-loader
dist: trusty
sudo: required
sudo: false
notifications:
email: false
@@ -37,8 +37,8 @@ addons:
- yarn
rvm:
- 2.3.4
- 2.4.2
- 2.5.0
services:
- redis-server
@@ -49,8 +49,7 @@ install:
- yarn install
before_script:
- bundle exec rake parallel:create parallel:load_schema parallel:prepare
- bundle exec rails assets:precompile
- ./bin/rails parallel:create parallel:load_schema parallel:prepare assets:precompile
- ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++"
script:

View File

@@ -1,4 +1,4 @@
FROM ruby:2.4.2-alpine3.6
FROM ruby:2.5.0-alpine3.7
LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="A GNU Social-compatible microblogging server"
@@ -40,6 +40,7 @@ RUN apk -U upgrade \
protobuf \
su-exec \
tini \
tzdata \
&& update-ca-certificates \
&& mkdir -p /tmp/src /opt \
&& wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '>= 2.3.0', '< 2.5.0'
ruby '>= 2.3.0', '< 2.6.0'
gem 'pkg-config', '~> 1.2'
@@ -29,15 +29,15 @@ gem 'browser'
gem 'charlock_holmes', '~> 0.7.5'
gem 'iso-639'
gem 'cld3', '~> 3.2.0'
gem 'devise', '~> 4.3'
gem 'devise', '~> 4.4'
gem 'devise-two-factor', '~> 3.0'
gem 'doorkeeper', '~> 4.2'
gem 'fast_blank', '~> 1.0'
gem 'goldfinger', '~> 2.0'
gem 'goldfinger', '~> 2.1'
gem 'hiredis', '~> 0.6'
gem 'redis-namespace', '~> 1.5'
gem 'htmlentities', '~> 4.3'
gem 'http', '~> 2.2'
gem 'http', '~> 3.0'
gem 'http_accept_language', '~> 2.1'
gem 'httplog', '~> 0.99'
gem 'idn-ruby', require: 'idn'
@@ -50,6 +50,7 @@ gem 'oj', '~> 3.3'
gem 'ostatus2', '~> 2.0'
gem 'ox', '~> 2.8'
gem 'pundit', '~> 1.1'
gem 'premailer-rails'
gem 'rack-attack', '~> 5.0'
gem 'rack-cors', '~> 0.4', require: 'rack/cors'
gem 'rack-timeout', '~> 0.4'

View File

@@ -70,7 +70,7 @@ GEM
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
binding_of_caller (0.7.3)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bootsnap (1.1.5)
msgpack (~> 1.0)
@@ -110,7 +110,7 @@ GEM
activesupport
charlock_holmes (0.7.5)
chunky_png (1.3.8)
cld3 (3.2.1)
cld3 (3.2.2)
ffi (>= 1.1.0, < 1.10.0)
climate_control (0.2.0)
cocaine (0.5.8)
@@ -122,8 +122,10 @@ GEM
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.3)
css_parser (1.6.0)
addressable
debug_inspector (0.0.3)
devise (4.3.0)
devise (4.4.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.2)
@@ -179,9 +181,9 @@ GEM
ruby-progressbar (~> 1.4)
globalid (0.4.1)
activesupport (>= 4.2.0)
goldfinger (2.0.1)
goldfinger (2.1.0)
addressable (~> 2.5)
http (~> 2.2)
http (~> 3.0)
nokogiri (~> 1.8)
oj (~> 3.0)
hamlit (2.8.5)
@@ -200,14 +202,14 @@ GEM
hiredis (0.6.1)
hkdf (0.3.0)
htmlentities (4.3.4)
http (2.2.2)
http (3.0.0)
addressable (~> 2.3)
http-cookie (~> 1.0)
http-form_data (~> 1.0.1)
http-form_data (>= 2.0.0.pre.pre2, < 3)
http_parser.rb (~> 0.6.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
http-form_data (1.0.3)
http-form_data (2.0.0)
http_accept_language (2.1.1)
http_parser.rb (0.6.0)
httplog (0.99.7)
@@ -298,12 +300,12 @@ GEM
concurrent-ruby (~> 1.0.0)
sidekiq (>= 3.5.0)
statsd-ruby (~> 1.2.0)
oj (3.3.9)
oj (3.3.10)
orm_adapter (0.5.0)
ostatus2 (2.0.2)
addressable (~> 2.4)
http (~> 2.0)
nokogiri (~> 1.6)
ostatus2 (2.0.3)
addressable (~> 2.5)
http (~> 3.0)
nokogiri (~> 1.8)
ox (2.8.2)
paperclip (5.1.0)
activemodel (>= 4.2.0)
@@ -325,6 +327,13 @@ GEM
pkg-config (1.2.8)
posix-spawn (0.3.13)
powerpack (0.1.1)
premailer (1.11.1)
addressable
css_parser (>= 1.6.0)
htmlentities (>= 4.0.0)
premailer-rails (1.10.1)
actionmailer (>= 3, < 6)
premailer (~> 1.7, >= 1.7.9)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
@@ -560,7 +569,7 @@ DEPENDENCIES
charlock_holmes (~> 0.7.5)
cld3 (~> 3.2.0)
climate_control (~> 0.2)
devise (~> 4.3)
devise (~> 4.4)
devise-two-factor (~> 3.0)
doorkeeper (~> 4.2)
dotenv-rails (~> 2.2)
@@ -571,11 +580,11 @@ DEPENDENCIES
fog-local (~> 0.4)
fog-openstack (~> 0.1)
fuubar (~> 2.2)
goldfinger (~> 2.0)
goldfinger (~> 2.1)
hamlit-rails (~> 0.2)
hiredis (~> 0.6)
htmlentities (~> 4.3)
http (~> 2.2)
http (~> 3.0)
http_accept_language (~> 2.1)
httplog (~> 0.99)
i18n-tasks (~> 0.9)
@@ -602,6 +611,7 @@ DEPENDENCIES
pghero (~> 1.7)
pkg-config (~> 1.2)
posix-spawn
premailer-rails
pry-rails (~> 0.3)
puma (~> 3.10)
pundit (~> 1.1)
@@ -641,7 +651,7 @@ DEPENDENCIES
webpush
RUBY VERSION
ruby 2.4.2p198
ruby 2.5.0p0
BUNDLED WITH
1.16.1

2
Vagrantfile vendored
View File

@@ -79,7 +79,7 @@ VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.box = "ubuntu/xenial64"
config.vm.provider :virtualbox do |vb|
vb.name = "mastodon"

View File

@@ -28,7 +28,7 @@ class ActivityPub::InboxesController < Api::BaseController
def upgrade_account
if signed_request_account.ostatus?
signed_request_account.update(last_webfingered_at: nil)
ResolveRemoteAccountWorker.perform_async(signed_request_account.acct)
ResolveAccountWorker.perform_async(signed_request_account.acct)
end
Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?

View File

@@ -21,12 +21,12 @@ class Api::V1::AccountsController < Api::BaseController
end
def block
BlockService.new.call(current_user.account, @account)
BlockService.new.call(current_user.account, @account, note: params[:note])
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end
def mute
MuteService.new.call(current_user.account, @account, notifications: params[:notifications])
MuteService.new.call(current_user.account, @account, notifications: params[:notifications], note: params[:note])
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end

View File

@@ -9,7 +9,11 @@ class Api::V1::Timelines::HomeController < Api::BaseController
def show
@statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
render json: @statuses,
each_serializer: REST::StatusSerializer,
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
status: regeneration_in_progress? ? 206 : 200
end
private
@@ -57,4 +61,8 @@ class Api::V1::Timelines::HomeController < Api::BaseController
def pagination_since_id
@statuses.first.id
end
def regeneration_in_progress?
Redis.current.exists("account:#{current_account.id}:regeneration")
end
end

View File

@@ -4,6 +4,7 @@ class Api::Web::PushSubscriptionsController < Api::BaseController
respond_to :json
before_action :require_user!
protect_from_forgery with: :exception
def create
params.require(:subscription).require(:endpoint)

View File

@@ -46,7 +46,7 @@ class AuthorizeFollowsController < ApplicationController
end
def account_from_remote_follow
ResolveRemoteAccountService.new.call(acct_without_prefix)
ResolveAccountService.new.call(acct_without_prefix)
end
def acct_param_is_url?

View File

@@ -114,7 +114,7 @@ module SignatureVerification
def account_from_key_id(key_id)
if key_id.start_with?('acct:')
ResolveRemoteAccountService.new.call(key_id.gsub(/\Aacct:/, ''))
ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, ''))
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)
account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false)

View File

@@ -3,7 +3,6 @@
module UserTrackingConcern
extend ActiveSupport::Concern
REGENERATE_FEED_DAYS = 14
UPDATE_SIGN_IN_HOURS = 24
included do
@@ -14,25 +13,10 @@ module UserTrackingConcern
def set_user_activity
return unless user_needs_sign_in_update?
# Mark as signed-in today
current_user.update_tracked_fields!(request)
ActivityTracker.record('activity:logins', current_user.id)
# Regenerate feed if needed
regenerate_feed! if user_needs_feed_update?
end
def user_needs_sign_in_update?
user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago)
end
def user_needs_feed_update?
current_user.last_sign_in_at < REGENERATE_FEED_DAYS.days.ago
end
def regenerate_feed!
Redis.current.setnx("account:#{current_user.account_id}:regeneration", true) == 1 && Redis.current.expire("account:#{current_user.account_id}:regeneration", 3_600 * 24)
RegenerationWorker.perform_async(current_user.account_id)
end
end

View File

@@ -3,6 +3,8 @@
module Settings
module TwoFactorAuthentication
class ConfirmationsController < BaseController
before_action :ensure_otp_secret
def new
prepare_two_factor_form
end
@@ -34,6 +36,10 @@ module Settings
@provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Rails.configuration.x.local_domain)
@qrcode = RQRCode::QRCode.new(@provision_url)
end
def ensure_otp_secret
redirect_to settings_two_factor_authentication_path unless current_user.otp_secret
end
end
end
end

View File

@@ -15,13 +15,14 @@ class SharesController < ApplicationController
private
def initial_state_params
text = [params[:title], params[:text], params[:url]].compact.join(' ')
{
settings: Web::Setting.find_by(user: current_user)&.data || {},
push_subscription: current_account.user.web_push_subscription(current_session),
current_account: current_account,
token: current_session.token,
admin: Account.find_local(Setting.site_contact_username),
text: params[:text],
text: text,
}
end

View File

@@ -6,6 +6,6 @@ module InstanceHelper
end
def site_hostname
Rails.configuration.x.local_domain
@site_hostname ||= Addressable::URI.parse("//#{Rails.configuration.x.local_domain}").display_uri.host
end
end

View File

@@ -0,0 +1,4 @@
# frozen_string_literal: true
module MailerHelper
end

View File

@@ -16,6 +16,7 @@ module SettingsHelper
he: 'עברית',
hr: 'Hrvatski',
hu: 'Magyar',
hy: 'Հայերեն',
id: 'Bahasa Indonesia',
io: 'Ido',
it: 'Italiano',

View File

@@ -30,13 +30,13 @@ delegate(document, batchCheckboxClassName, 'change', () => {
});
delegate(document, '.media-spoiler-show-button', 'click', () => {
[].forEach.call(document.querySelectorAll('.activity-stream .media-spoiler-wrapper'), (content) => {
content.classList.add('media-spoiler-wrapper__visible');
[].forEach.call(document.querySelectorAll('button.media-spoiler'), (element) => {
element.click();
});
});
delegate(document, '.media-spoiler-hide-button', 'click', () => {
[].forEach.call(document.querySelectorAll('.activity-stream .media-spoiler-wrapper'), (content) => {
content.classList.remove('media-spoiler-wrapper__visible');
[].forEach.call(document.querySelectorAll('.spoiler-button.spoiler-button--visible button'), (element) => {
element.click();
});
});

View File

@@ -0,0 +1 @@
import 'styles/mailer.scss';

View File

@@ -10,6 +10,9 @@ pack:
embed: embed.js
error:
home:
mailer:
filename: mailer.js
stylesheet: true
modal:
public: public.js
settings: settings.js

View File

@@ -12,6 +12,7 @@ import {
} from './timelines';
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
export const COMPOSE_CYCLE_ELEFRIEND = 'COMPOSE_CYCLE_ELEFRIEND';
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
@@ -54,6 +55,12 @@ export function changeCompose(text) {
};
};
export function cycleElefriendCompose() {
return {
type: COMPOSE_CYCLE_ELEFRIEND,
};
};
export function replyCompose(status, router) {
return (dispatch, getState) => {
dispatch({

View File

@@ -19,13 +19,14 @@ export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE';
export function refreshTimelineSuccess(timeline, statuses, skipLoading, next) {
export function refreshTimelineSuccess(timeline, statuses, skipLoading, next, partial) {
return {
type: TIMELINE_REFRESH_SUCCESS,
timeline,
statuses,
skipLoading,
next,
partial,
};
};
@@ -88,7 +89,7 @@ export function refreshTimeline(timelineId, path, params = {}) {
return function (dispatch, getState) {
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
if (timeline.get('isLoading') || timeline.get('online')) {
if (timeline.get('isLoading') || (timeline.get('online') && !timeline.get('isPartial'))) {
return;
}
@@ -104,8 +105,12 @@ export function refreshTimeline(timelineId, path, params = {}) {
dispatch(refreshTimelineRequest(timelineId, skipLoading));
api(getState).get(path, { params }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null));
if (response.status === 206) {
dispatch(refreshTimelineSuccess(timelineId, [], skipLoading, null, true));
} else {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null, false));
}
}).catch(error => {
dispatch(refreshTimelineFail(timelineId, error, skipLoading));
});

View File

@@ -132,7 +132,7 @@ export default class Account extends ImmutablePureComponent {
<div className='account__relationship'>
{buttons}
</div>
: null}
: null}
</div>
</div>
);

View File

@@ -21,9 +21,9 @@ export default class AttachmentList extends ImmutablePureComponent {
<ul className='attachment-list__list'>
{media.map(attachment =>
<li key={attachment.get('id')}>
(<li key={attachment.get('id')}>
<a href={attachment.get('remote_url')} target='_blank' rel='noopener'>{filename(attachment.get('remote_url'))}</a>
</li>
</li>)
)}
</ul>
</div>

View File

@@ -6,9 +6,9 @@ import PropTypes from 'prop-types';
const Collapsable = ({ fullHeight, isVisible, children }) => (
<Motion defaultStyle={{ opacity: !isVisible ? 0 : 100, height: isVisible ? fullHeight : 0 }} style={{ opacity: spring(!isVisible ? 0 : 100), height: spring(!isVisible ? 0 : fullHeight) }}>
{({ opacity, height }) =>
<div style={{ height: `${height}px`, overflow: 'hidden', opacity: opacity / 100, display: Math.floor(opacity) === 0 ? 'none' : 'block' }}>
(<div style={{ height: `${height}px`, overflow: 'hidden', opacity: opacity / 100, display: Math.floor(opacity) === 0 ? 'none' : 'block' }}>
{children}
</div>
</div>)
}
</Motion>
);

View File

@@ -116,7 +116,7 @@ export default class IconButton extends React.PureComponent {
return (
<Motion defaultStyle={motionDefaultStyle} style={motionStyle}>
{({ rotate }) =>
<button
(<button
aria-label={title}
aria-pressed={pressed}
aria-expanded={expanded}
@@ -128,7 +128,7 @@ export default class IconButton extends React.PureComponent {
>
<i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${icon}`} aria-hidden='true' />
{this.props.label}
</button>
</button>)
}
</Motion>
);

View File

@@ -2,9 +2,14 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
const MissingIndicator = () => (
<div className='missing-indicator'>
<div className='regeneration-indicator missing-indicator'>
<div>
<FormattedMessage id='missing_indicator.label' defaultMessage='Not found' />
<div className='regeneration-indicator__figure' />
<div className='regeneration-indicator__label'>
<FormattedMessage id='missing_indicator.label' tagName='strong' defaultMessage='Not found' />
<FormattedMessage id='missing_indicator.sublabel' defaultMessage='This resource could not be found' />
</div>
</div>
</div>
);

View File

@@ -47,7 +47,6 @@ export default class Status extends ImmutablePureComponent {
state = {
isExpanded: null,
markedForDelete: false,
}
// Avoid checking props that are functions (and whose equality will always
@@ -67,7 +66,6 @@ export default class Status extends ImmutablePureComponent {
updateOnStates = [
'isExpanded',
'markedForDelete',
]
// If our settings have changed to disable collapsed statuses, then we
@@ -121,15 +119,15 @@ export default class Status extends ImmutablePureComponent {
if (function () {
switch (true) {
case collapse:
case autoCollapseSettings.get('all'):
case autoCollapseSettings.get('notifications') && muted:
case !!collapse:
case !!autoCollapseSettings.get('all'):
case autoCollapseSettings.get('notifications') && !!muted:
case autoCollapseSettings.get('lengthy') && node.clientHeight > (
status.get('media_attachments').size && !muted ? 650 : 400
):
case autoCollapseSettings.get('reblogs') && prepend === 'reblogged_by':
case autoCollapseSettings.get('replies') && status.get('in_reply_to_id', null) !== null:
case autoCollapseSettings.get('media') && !(status.get('spoiler_text').length) && status.get('media_attachments').size:
case autoCollapseSettings.get('media') && !(status.get('spoiler_text').length) && !!status.get('media_attachments').size:
return true;
default:
return false;
@@ -318,14 +316,14 @@ export default class Status extends ImmutablePureComponent {
media = (
<Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
{Component => <Component
{Component => (<Component
preview={video.get('preview_url')}
src={video.get('url')}
sensitive={status.get('sensitive')}
letterbox={settings.getIn(['media', 'letterbox'])}
fullwidth={settings.getIn(['media', 'fullwidth'])}
onOpenVideo={this.handleOpenVideo}
/>}
/>)}
</Bundle>
);
mediaIcon = 'video-camera';
@@ -382,7 +380,6 @@ export default class Status extends ImmutablePureComponent {
const computedClass = classNames('status', `status-${status.get('visibility')}`, {
collapsed: isExpanded === false,
'has-background': isExpanded === false && background,
'marked-for-delete': this.state.markedForDelete,
muted,
}, 'focusable');

View File

@@ -104,8 +104,8 @@ export default class StatusHeader extends React.PureComponent {
active={collapsed}
title={
collapsed ?
intl.formatMessage(messages.uncollapse) :
intl.formatMessage(messages.collapse)
intl.formatMessage(messages.uncollapse) :
intl.formatMessage(messages.collapse)
}
icon='angle-double-up'
onClick={this.handleCollapsedClick}

View File

@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import StatusContainer from 'flavours/glitch/containers/status_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ScrollableList from './scrollable_list';
import { FormattedMessage } from 'react-intl';
export default class StatusList extends ImmutablePureComponent {
@@ -16,6 +17,7 @@ export default class StatusList extends ImmutablePureComponent {
trackScroll: PropTypes.bool,
shouldUpdateScroll: PropTypes.func,
isLoading: PropTypes.bool,
isPartial: PropTypes.bool,
hasMore: PropTypes.bool,
prepend: PropTypes.node,
emptyMessage: PropTypes.node,
@@ -48,8 +50,23 @@ export default class StatusList extends ImmutablePureComponent {
}
render () {
const { statusIds, ...other } = this.props;
const { isLoading } = other;
const { statusIds, ...other } = this.props;
const { isLoading, isPartial } = other;
if (isPartial) {
return (
<div className='regeneration-indicator'>
<div>
<div className='regeneration-indicator__figure' />
<div className='regeneration-indicator__label'>
<FormattedMessage id='regeneration_indicator.label' tagName='strong' defaultMessage='Loading&hellip;' />
<FormattedMessage id='regeneration_indicator.sublabel' defaultMessage='Your home feed is being prepared!' />
</div>
</div>
</div>
);
}
const scrollableContent = (isLoading || statusIds.size > 0) ? (
statusIds.map((statusId) => (

View File

@@ -64,11 +64,11 @@ export default class Header extends ImmutablePureComponent {
<div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
<div>
<a
href={account.get('url')}
className='account__header__avatar'
role='presentation'
target='_blank'
rel='noopener'
href={account.get('url')}
className='account__header__avatar'
role='presentation'
target='_blank'
rel='noopener'
>
<Avatar account={account} size={90} />
</a>

View File

@@ -95,10 +95,10 @@ export default class AccountGallery extends ImmutablePureComponent {
<div className='account-gallery__container'>
{medias.map(media =>
<MediaItem
(<MediaItem
key={media.get('id')}
media={media}
/>
/>)
)}
{loadMore}
</div>

View File

@@ -0,0 +1,49 @@
import React from 'react';
import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { defineMessages, FormattedMessage } from 'react-intl';
// This is the spring used with our motion.
const motionSpring = spring(1, { damping: 35, stiffness: 400 });
// Messages.
const messages = defineMessages({
disclaimer: {
defaultMessage: 'This toot won\'t be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.',
id: 'compose_form.hashtag_warning',
},
});
// The component.
export default function ComposerHashtagWarning () {
return (
<Motion
defaultStyle={{
opacity: 0,
scaleX: 0.85,
scaleY: 0.75,
}}
style={{
opacity: motionSpring,
scaleX: motionSpring,
scaleY: motionSpring,
}}
>
{({ opacity, scaleX, scaleY }) => (
<div
className='composer--warning'
style={{
opacity: opacity,
transform: `scale(${scaleX}, ${scaleY})`,
}}
>
<FormattedMessage
{...messages.disclaimer}
/>
</div>
)}
</Motion>
);
}
ComposerHashtagWarning.propTypes = {};

View File

@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\S+)/i;
// Actions.
import {
cancelReplyCompose,
@@ -36,6 +38,7 @@ import ComposerSpoiler from './spoiler';
import ComposerTextarea from './textarea';
import ComposerUploadForm from './upload_form';
import ComposerWarning from './warning';
import ComposerHashtagWarning from './hashtag_warning';
// Utils.
import { countableText } from 'flavours/glitch/util/counter';
@@ -312,6 +315,7 @@ class Composer extends React.Component {
text={spoilerText}
/>
{privacy === 'private' && amUnlocked ? <ComposerWarning /> : null}
{privacy !== 'public' && APPROX_HASHTAG_RE.test(text) ? <ComposerHashtagWarning /> : null}
{replyContent ? (
<ComposerReply
account={replyAccount}
@@ -350,10 +354,10 @@ class Composer extends React.Component {
acceptContentTypes={acceptContentTypes}
advancedOptions={advancedOptions}
disabled={isSubmitting}
full={media.size >= 4 || media.some(
full={media ? media.size >= 4 || media.some(
item => item.get('type') === 'video'
)}
hasMedia={!!media.size}
) : false}
hasMedia={media && !!media.size}
intl={intl}
onChangeAdvancedOption={onChangeAdvancedOption}
onChangeSensitivity={onChangeSensitivity}
@@ -369,7 +373,7 @@ class Composer extends React.Component {
spoiler={spoiler}
/>
<ComposerPublisher
countText={`${spoilerText}${countableText(text)}${advancedOptions.get('do_not_federate') ? ' 👁️' : ''}`}
countText={`${spoilerText}${countableText(text)}${advancedOptions && advancedOptions.get('do_not_federate') ? ' 👁️' : ''}`}
disabled={isSubmitting || isUploading || !!text.length && !text.trim().length}
intl={intl}
onSecondarySubmit={handleSecondarySubmit}

View File

@@ -96,7 +96,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
transform: `scale(${scaleX}, ${scaleY})`,
}}
>
{items.map(
{items ? items.map(
({
name,
...rest
@@ -110,7 +110,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
options={rest}
/>
)
)}
) : null}
</div>
)}
</Motion>
@@ -127,7 +127,7 @@ ComposerOptionsDropdownContent.propTypes = {
name: PropTypes.string.isRequired,
on: PropTypes.bool,
text: PropTypes.node,
})).isRequired,
})),
onChange: PropTypes.func,
onClose: PropTypes.func,
style: PropTypes.object,

View File

@@ -292,31 +292,29 @@ export default class ComposerOptions extends React.PureComponent {
onClick={onToggleSpoiler}
title={intl.formatMessage(messages.spoiler)}
/>
{advancedOptions ? (
<Dropdown
active={advancedOptions.some(value => !!value)}
disabled={disabled}
icon='ellipsis-h'
items={[
{
meta: <FormattedMessage {...messages.local_only_long} />,
name: 'do_not_federate',
on: advancedOptions.get('do_not_federate'),
text: <FormattedMessage {...messages.local_only_short} />,
},
{
meta: <FormattedMessage {...messages.threaded_mode_long} />,
name: 'threaded_mode',
on: advancedOptions.get('threaded_mode'),
text: <FormattedMessage {...messages.threaded_mode_short} />,
},
]}
onChange={onChangeAdvancedOption}
onModalClose={onModalClose}
onModalOpen={onModalOpen}
title={intl.formatMessage(messages.advanced_options_icon_title)}
/>
) : null}
<Dropdown
active={advancedOptions && advancedOptions.some(value => !!value)}
disabled={disabled}
icon='ellipsis-h'
items={advancedOptions ? [
{
meta: <FormattedMessage {...messages.local_only_long} />,
name: 'do_not_federate',
on: advancedOptions.get('do_not_federate'),
text: <FormattedMessage {...messages.local_only_short} />,
},
{
meta: <FormattedMessage {...messages.threaded_mode_long} />,
name: 'threaded_mode',
on: advancedOptions.get('threaded_mode'),
text: <FormattedMessage {...messages.threaded_mode_short} />,
},
] : null}
onChange={onChangeAdvancedOption}
onModalClose={onModalClose}
onModalOpen={onModalOpen}
title={intl.formatMessage(messages.advanced_options_icon_title)}
/>
</div>
);
}

View File

@@ -36,10 +36,10 @@ export default function ComposerUploadFormProgress ({ progress }) {
style={{ width: spring(progress) }}
>
{({ width }) =>
<div
(<div
className='tracker'
style={{ width: `${width}%` }}
/>
/>)
}
</Motion>
</div>

View File

@@ -2,6 +2,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import classNames from 'classnames';
// Actions.
import { openModal } from 'flavours/glitch/actions/modal';
@@ -11,6 +12,7 @@ import {
showSearch,
submitSearch,
} from 'flavours/glitch/actions/search';
import { cycleElefriendCompose } from 'flavours/glitch/actions/compose';
// Components.
import Composer from 'flavours/glitch/features/composer';
@@ -27,6 +29,7 @@ import { wrap } from 'flavours/glitch/util/redux_helpers';
const mapStateToProps = state => ({
account: state.getIn(['accounts', me]),
columns: state.getIn(['settings', 'columns']),
elefriend: state.getIn(['compose', 'elefriend']),
results: state.getIn(['search', 'results']),
searchHidden: state.getIn(['search', 'hidden']),
searchValue: state.getIn(['search', 'value']),
@@ -37,6 +40,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = {
onChange: changeSearch,
onClear: clearSearch,
onClickElefriend: cycleElefriendCompose,
onShow: showSearch,
onSubmit: submitSearch,
onOpenSettings: openModal.bind(null, 'SETTINGS', {}),
@@ -55,10 +59,12 @@ class Drawer extends React.Component {
const {
account,
columns,
elefriend,
intl,
multiColumn,
onChange,
onClear,
onClickElefriend,
onOpenSettings,
onShow,
onSubmit,
@@ -67,10 +73,11 @@ class Drawer extends React.Component {
searchValue,
submitted,
} = this.props;
const computedClass = classNames('drawer', `mbstobon-${elefriend}`);
// The result.
return (
<div className='drawer'>
<div className={computedClass}>
{multiColumn ? (
<DrawerHeader
columns={columns}
@@ -90,6 +97,7 @@ class Drawer extends React.Component {
<div className='contents'>
<DrawerAccount account={account} />
<Composer />
{multiColumn && <button className='mastodon' onClick={onClickElefriend} />}
<DrawerResults
results={results}
visible={submitted && !searchHidden}
@@ -110,6 +118,7 @@ Drawer.propTypes = {
account: ImmutablePropTypes.map,
columns: ImmutablePropTypes.list,
results: ImmutablePropTypes.map,
elefriend: PropTypes.number,
searchHidden: PropTypes.bool,
searchValue: PropTypes.string,
submitted: PropTypes.bool,
@@ -117,6 +126,7 @@ Drawer.propTypes = {
// Dispatch props.
onChange: PropTypes.func,
onClear: PropTypes.func,
onClickElefriend: PropTypes.func,
onShow: PropTypes.func,
onSubmit: PropTypes.func,
onOpenSettings: PropTypes.func,

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import { expandHomeTimeline } from 'flavours/glitch/actions/timelines';
import { expandHomeTimeline, refreshHomeTimeline } from 'flavours/glitch/actions/timelines';
import PropTypes from 'prop-types';
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
import Column from 'flavours/glitch/components/column';
@@ -16,6 +16,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
isPartial: state.getIn(['timelines', 'home', 'isPartial'], false),
});
@connect(mapStateToProps)
@@ -26,6 +27,7 @@ export default class HomeTimeline extends React.PureComponent {
dispatch: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
hasUnread: PropTypes.bool,
isPartial: PropTypes.bool,
columnId: PropTypes.string,
multiColumn: PropTypes.bool,
};
@@ -57,6 +59,39 @@ export default class HomeTimeline extends React.PureComponent {
this.props.dispatch(expandHomeTimeline());
}
componentDidMount () {
this._checkIfReloadNeeded(false, this.props.isPartial);
}
componentDidUpdate (prevProps) {
this._checkIfReloadNeeded(prevProps.isPartial, this.props.isPartial);
}
componentWillUnmount () {
this._stopPolling();
}
_checkIfReloadNeeded (wasPartial, isPartial) {
const { dispatch } = this.props;
if (wasPartial === isPartial) {
return;
} else if (!wasPartial && isPartial) {
this.polling = setInterval(() => {
dispatch(refreshHomeTimeline());
}, 3000);
} else if (wasPartial && !isPartial) {
this._stopPolling();
}
}
_stopPolling () {
if (this.polling) {
clearInterval(this.polling);
this.polling = null;
}
}
render () {
const { intl, hasUnread, columnId, multiColumn } = this.props;
const pinned = !!columnId;

View File

@@ -67,9 +67,9 @@ export default class ListEditor extends ImmutablePureComponent {
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
{({ x }) =>
<div className='drawer__inner backdrop' style={{ transform: x === 0 ? null : `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
(<div className='drawer__inner backdrop' style={{ transform: x === 0 ? null : `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}
</div>
</div>)
}
</Motion>
</div>

View File

@@ -120,13 +120,17 @@ export default class ListTimeline extends React.PureComponent {
if (typeof list === 'undefined') {
return (
<Column>
<LoadingIndicator />
<div className='scrollable'>
<LoadingIndicator />
</div>
</Column>
);
} else if (list === false) {
return (
<Column>
<MissingIndicator />
<div className='scrollable'>
<MissingIndicator />
</div>
</Column>
);
}

View File

@@ -124,7 +124,7 @@ export default class ModalRoot extends React.PureComponent {
(<BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}>
{(SpecificComponent) => <SpecificComponent {...props} onClose={onClose} />}
</BundleContainer>) :
null
null
}
</div>
</div>

View File

@@ -38,11 +38,6 @@ PageOne.propTypes = {
domain: PropTypes.string.isRequired,
};
const composerState = {
showSearch: true,
text: 'Awoo! #introductions',
};
const PageTwo = ({ intl, myAccount }) => (
<div className='onboarding-modal__page onboarding-modal__page-two'>
<div className='figure non-interactive'>
@@ -50,7 +45,8 @@ const PageTwo = ({ intl, myAccount }) => (
<DrawerAccount account={myAccount} />
<RawComposer
intl={intl}
state={composerState}
privacy='public'
text='Awoo! #introductions'
/>
</div>
</div>

View File

@@ -38,12 +38,12 @@ export default class UploadArea extends React.PureComponent {
return (
<Motion defaultStyle={{ backgroundOpacity: 0, backgroundScale: 0.95 }} style={{ backgroundOpacity: spring(active ? 1 : 0, { stiffness: 150, damping: 15 }), backgroundScale: spring(active ? 1 : 0.95, { stiffness: 200, damping: 3 }) }}>
{({ backgroundOpacity, backgroundScale }) =>
<div className='upload-area' style={{ visibility: active ? 'visible' : 'hidden', opacity: backgroundOpacity }}>
(<div className='upload-area' style={{ visibility: active ? 'visible' : 'hidden', opacity: backgroundOpacity }}>
<div className='upload-area__drop'>
<div className='upload-area__background' style={{ transform: `scale(${backgroundScale})` }} />
<div className='upload-area__content'><FormattedMessage id='upload_area.title' defaultMessage='Drag & drop to upload' /></div>
</div>
</div>
</div>)
}
</Motion>
);

View File

@@ -23,6 +23,7 @@ export default class VideoModal extends ImmutablePureComponent {
src={media.get('url')}
startTime={time}
onCloseVideo={onClose}
detailed
description={media.get('description')}
/>
</div>

View File

@@ -51,6 +51,7 @@ const makeMapStateToProps = () => {
const mapStateToProps = (state, { timelineId }) => ({
statusIds: getStatusIds(state, { type: timelineId }),
isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
hasMore: !!state.getIn(['timelines', timelineId, 'next']),
});

View File

@@ -17,6 +17,17 @@ const messages = defineMessages({
exit_fullscreen: { id: 'video.exit_fullscreen', defaultMessage: 'Exit full screen' },
});
const formatTime = secondsNum => {
let hours = Math.floor(secondsNum / 3600);
let minutes = Math.floor((secondsNum - (hours * 3600)) / 60);
let seconds = secondsNum - (hours * 3600) - (minutes * 60);
if (hours < 10) hours = '0' + hours;
if (minutes < 10) minutes = '0' + minutes;
if (seconds < 10) seconds = '0' + seconds;
return (hours === '00' ? '' : `${hours}:`) + `${minutes}:${seconds}`;
};
const findElementPosition = el => {
let box;
@@ -85,11 +96,13 @@ export default class Video extends React.PureComponent {
onCloseVideo: PropTypes.func,
letterbox: PropTypes.bool,
fullwidth: PropTypes.bool,
detailed: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
state = {
progress: 0,
currentTime: 0,
duration: 0,
paused: true,
dragging: false,
fullscreen: false,
@@ -119,7 +132,10 @@ export default class Video extends React.PureComponent {
}
handleTimeUpdate = () => {
this.setState({ progress: 100 * (this.video.currentTime / this.video.duration) });
this.setState({
currentTime: Math.floor(this.video.currentTime),
duration: Math.floor(this.video.duration),
});
}
handleMouseDown = e => {
@@ -145,8 +161,10 @@ export default class Video extends React.PureComponent {
handleMouseMove = throttle(e => {
const { x } = getPointerPosition(this.seek, e);
this.video.currentTime = this.video.duration * x;
this.setState({ progress: x * 100 });
const currentTime = Math.floor(this.video.duration * x);
this.video.currentTime = currentTime;
this.setState({ currentTime });
}, 60);
togglePlay = () => {
@@ -228,11 +246,12 @@ export default class Video extends React.PureComponent {
}
render () {
const { preview, src, width, height, startTime, onOpenVideo, onCloseVideo, intl, alt, letterbox, fullwidth } = this.props;
const { progress, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state;
const { preview, src, width, height, startTime, onOpenVideo, onCloseVideo, intl, alt, letterbox, fullwidth, detailed } = this.props;
const { currentTime, duration, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state;
const progress = (currentTime / duration) * 100;
return (
<div className={classNames('video-player', { inactive: !revealed, inline: !fullscreen, fullscreen, letterbox, 'full-width': fullwidth })} ref={this.setPlayerRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<div className={classNames('video-player', { inactive: !revealed, detailed, inline: width && height && !fullscreen, fullscreen, letterbox, 'full-width': fullwidth })} style={{ width, height }} ref={this.setPlayerRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<video
ref={this.setVideoRef}
src={src}
@@ -269,16 +288,27 @@ export default class Video extends React.PureComponent {
/>
</div>
<div className='video-player__buttons left'>
<button aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button>
<button aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button>
{!onCloseVideo && <button aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>}
</div>
<div className='video-player__buttons-bar'>
<div className='video-player__buttons left'>
<button aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button>
<button aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button>
<div className='video-player__buttons right'>
{(!fullscreen && onOpenVideo) && <button aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>}
{onCloseVideo && <button aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-times' /></button>}
<button aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button>
{!onCloseVideo && <button aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>}
{(detailed || fullscreen) &&
<span>
<span className='video-player__time-current'>{formatTime(currentTime)}</span>
<span className='video-player__time-sep'>/</span>
<span className='video-player__time-total'>{formatTime(duration)}</span>
</span>
}
</div>
<div className='video-player__buttons right'>
{(!fullscreen && onOpenVideo) && <button aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>}
{onCloseVideo && <button aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-compress' /></button>}
<button aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button>
</div>
</div>
</div>
</div>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -2,6 +2,7 @@ import {
COMPOSE_MOUNT,
COMPOSE_UNMOUNT,
COMPOSE_CHANGE,
COMPOSE_CYCLE_ELEFRIEND,
COMPOSE_REPLY,
COMPOSE_REPLY_CANCEL,
COMPOSE_MENTION,
@@ -35,6 +36,12 @@ import uuid from 'flavours/glitch/util/uuid';
import { me } from 'flavours/glitch/util/initial_state';
import { overwrite } from 'flavours/glitch/util/js_helpers';
const totalElefriends = 3;
// ~4% chance you'll end up with an unexpected friend
// glitch-soc/mastodon repo created_at date: 2017-04-20T21:55:28Z
const glitchProbability = 1 - 0.0420215528;
const initialState = ImmutableMap({
mounted: false,
advanced_options: ImmutableMap({
@@ -42,6 +49,7 @@ const initialState = ImmutableMap({
threaded_mode: false,
}),
sensitive: false,
elefriend: Math.random() < glitchProbability ? Math.floor(Math.random() * totalElefriends) : totalElefriends,
spoiler: false,
spoiler_text: '',
privacy: null,
@@ -259,6 +267,9 @@ export default function compose(state = initialState, action) {
return state
.set('text', action.text)
.set('idempotencyKey', uuid());
case COMPOSE_CYCLE_ELEFRIEND:
return state
.set('elefriend', (state.get('elefriend') + 1) % totalElefriends);
case COMPOSE_REPLY:
return state.withMutations(map => {
map.set('in_reply_to', action.status.get('id'));

View File

@@ -30,7 +30,7 @@ const initialTimeline = ImmutableMap({
items: ImmutableList(),
});
const normalizeTimeline = (state, timeline, statuses, next) => {
const normalizeTimeline = (state, timeline, statuses, next, isPartial) => {
const oldIds = state.getIn([timeline, 'items'], ImmutableList());
const ids = ImmutableList(statuses.map(status => status.get('id'))).filter(newId => !oldIds.includes(newId));
const wasLoaded = state.getIn([timeline, 'loaded']);
@@ -40,7 +40,8 @@ const normalizeTimeline = (state, timeline, statuses, next) => {
mMap.set('loaded', true);
mMap.set('isLoading', false);
if (!hadNext) mMap.set('next', next);
mMap.set('items', wasLoaded ? ids.concat(oldIds) : ids);
mMap.set('items', wasLoaded ? ids.concat(oldIds) : oldIds.concat(ids));
mMap.set('isPartial', isPartial);
}));
};
@@ -125,7 +126,7 @@ export default function timelines(state = initialState, action) {
case TIMELINE_EXPAND_FAIL:
return state.update(action.timeline, initialTimeline, map => map.set('isLoading', false));
case TIMELINE_REFRESH_SUCCESS:
return normalizeTimeline(state, action.timeline, fromJS(action.statuses), action.next);
return normalizeTimeline(state, action.timeline, fromJS(action.statuses), action.next, action.partial);
case TIMELINE_EXPAND_SUCCESS:
return appendNormalizedTimeline(state, action.timeline, fromJS(action.statuses), action.next);
case TIMELINE_UPDATE:

View File

@@ -19,7 +19,7 @@
display: inline;
margin: 0;
padding: 0;
font-weight: 500;
font-weight: 700;
background: transparent;
font-family: inherit;
font-size: inherit;
@@ -424,14 +424,19 @@
text-align: center;
.avatar {
@include avatar-size(80px);
width: 80px;
height: 80px;
margin: 0 auto;
margin-bottom: 15px;
@include avatar-size(80px);
img {
display: block;
width: 80px;
height: 80px;
border-radius: 48px;
@include avatar-radius();
@include avatar-size(80px);
display: block;
}
}

View File

@@ -68,7 +68,7 @@
font-weight: 500;
position: relative;
z-index: 2;
margin-bottom: 30px;
margin-bottom: 15px;
overflow: hidden;
text-overflow: ellipsis;
@@ -83,16 +83,20 @@
}
.avatar {
@include avatar-size(120px);
width: 120px;
margin: 0 auto;
position: relative;
z-index: 2;
@include avatar-size(120px);
img {
width: 120px;
height: 120px;
display: block;
border-radius: 120px;
box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
@include avatar-radius();
@include avatar-size(120px);
display: block;
box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
}
}
@@ -123,7 +127,7 @@
}
.roles {
margin-bottom: 30px;
margin-bottom: 15px;
padding: 0 15px;
}
@@ -203,53 +207,10 @@
font-size: 14px;
line-height: 18px;
padding: 0 15px;
text-align: center;
color: $ui-secondary-color;
}
.metadata {
$meta-table-border: darken($classic-highlight-color, 20%);//#174f77;
border-collapse: collapse;
padding: 0;
margin: 15px -15px -10px -15px;
border: 0 none;
border-top: 1px solid $meta-table-border;
border-bottom: 1px solid $meta-table-border;
td, th {
padding: 10px;
border: 0 none;
border-bottom: 1px solid $meta-table-border;
vertical-align: middle;
}
tr:last-child {
td, th {
border-bottom: 0 none;
}
}
td {
color: $ui-primary-color;
width:100%; // makes it stretch
padding-left: 0;
}
th {
padding-left: 15px;
font-weight: bold;
text-align: left;
width: 94px;
color: $ui-secondary-color;
background: darken($ui-base-color, 8%);
//background: #131415;
}
a {
color: $classic-highlight-color;
}
}
@media screen and (max-width: 480px) {
display: block;
@@ -260,7 +221,7 @@
.name,
.roles {
text-align: center;
margin-bottom: 15px;
margin-bottom: 5px;
}
.bio {
@@ -407,14 +368,19 @@
}
.avatar {
width: 80px;
height: 80px;
@include avatar-size(80px);
img {
display: block;
@include avatar-radius();
@include avatar-size(80px);
width: 80px;
height: 80px;
border-radius: 80px;
border: 2px solid $simple-background-color;
background: $simple-background-color;
@include avatar-radius();
@include avatar-size(80px);
}
}
@@ -492,14 +458,17 @@
}
& > div {
@include avatar-size(48px);
float: left;
margin-right: 10px;
width: 48px;
height: 48px;
@include avatar-size(48px);
}
.avatar {
@include avatar-radius();
display: block;
border-radius: 4px;
@include avatar-radius();
}
.display-name {
@@ -513,6 +482,12 @@
strong {
font-weight: 500;
color: $ui-base-color;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
span {
@@ -587,3 +562,5 @@
border-color: rgba(lighten($error-red, 12%), 0.5);
}
}
@import 'metadata';

View File

@@ -121,6 +121,12 @@
strong {
color: $primary-text-color;
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
}
@@ -222,6 +228,12 @@
font-weight: 500;
text-transform: uppercase;
font-size: 12px;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
a {
@@ -281,6 +293,12 @@
font-size: 14px;
line-height: 18px;
color: $ui-secondary-color;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
.account-card {

View File

@@ -0,0 +1,463 @@
.account {
padding: 10px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
color: inherit;
text-decoration: none;
.account__display-name {
flex: 1 1 auto;
display: block;
color: $ui-primary-color;
overflow: hidden;
text-decoration: none;
font-size: 14px;
}
&.small {
border: none;
padding: 0;
& > .account__avatar-wrapper { margin: 0 8px 0 0 }
& > .display-name {
height: 24px;
line-height: 24px;
}
}
}
.account__wrapper {
display: flex;
}
.account__avatar-wrapper {
float: left;
margin: 6px 16px 6px 6px;
}
.account__avatar {
@include avatar-radius();
position: relative;
cursor: pointer;
&-inline {
display: inline-block;
vertical-align: middle;
margin-right: 5px;
}
}
.account__avatar-overlay {
position: relative;
@include avatar-size(48px);
&-base {
@include avatar-radius();
@include avatar-size(36px);
}
&-overlay {
@include avatar-radius();
@include avatar-size(24px);
position: absolute;
bottom: 0;
right: 0;
z-index: 1;
}
}
.account__relationship {
height: 18px;
padding: 10px;
white-space: nowrap;
}
.account__header__wrapper {
flex: 0 0 auto;
background: lighten($ui-base-color, 4%);
}
.account__header {
flex: 0 0 auto;
background: lighten($ui-base-color, 4%);
text-align: center;
background-size: cover;
background-position: center;
position: relative;
.account__avatar {
@include avatar-radius();
@include avatar-size(90px);
display: block;
margin: 0 auto 10px;
overflow: hidden;
}
&.inactive {
opacity: 0.5;
.account__header__avatar {
filter: grayscale(100%);
}
.account__header__username {
color: $ui-primary-color;
}
}
& > div {
background: rgba(lighten($ui-base-color, 4%), 0.9);
padding: 20px 10px;
}
.account__header__content {
color: $ui-secondary-color;
}
.account__header__display-name {
color: $primary-text-color;
display: inline-block;
width: 100%;
font-size: 20px;
line-height: 27px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
}
.account__header__username {
color: $ui-highlight-color;
font-size: 14px;
font-weight: 400;
display: block;
margin-bottom: 10px;
overflow: hidden;
text-overflow: ellipsis;
}
}
.account__disclaimer {
padding: 10px;
border-top: 1px solid lighten($ui-base-color, 8%);
color: $ui-base-lighter-color;
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
a {
font-weight: 500;
color: inherit;
text-decoration: underline;
&:hover,
&:focus,
&:active {
text-decoration: none;
}
}
}
.account__header__content {
color: $ui-primary-color;
font-size: 14px;
font-weight: 400;
overflow: hidden;
word-break: normal;
word-wrap: break-word;
p {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
a {
color: inherit;
text-decoration: underline;
&:hover {
text-decoration: none;
}
}
}
.account__header__display-name {
.emojione {
width: 25px;
height: 25px;
}
}
.account__action-bar {
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
line-height: 36px;
overflow: hidden;
flex: 0 0 auto;
display: flex;
}
.account__action-bar-dropdown {
flex: 0 1 calc(50% - 140px);
padding: 10px;
.dropdown--active {
.dropdown__content.dropdown__right {
left: 6px;
right: initial;
}
&::after {
bottom: initial;
margin-left: 11px;
margin-top: -7px;
right: initial;
}
}
}
.account__action-bar-links {
display: flex;
flex: 1 1 auto;
line-height: 18px;
}
.account__action-bar__tab {
text-decoration: none;
overflow: hidden;
flex: 0 1 80px;
border-left: 1px solid lighten($ui-base-color, 8%);
padding: 10px 5px;
& > span {
display: block;
text-transform: uppercase;
font-size: 11px;
color: $ui-primary-color;
}
strong {
display: block;
font-size: 15px;
font-weight: 500;
color: $primary-text-color;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
abbr {
color: $ui-base-lighter-color;
}
}
.account__header__avatar {
background-size: 90px 90px;
display: block;
height: 90px;
margin: 0 auto 10px;
overflow: hidden;
width: 90px;
}
.account-authorize {
padding: 14px 10px;
.detailed-status__display-name {
display: block;
margin-bottom: 15px;
overflow: hidden;
}
}
.account-authorize__avatar {
float: left;
margin-right: 10px;
}
.notification__message {
margin-left: 42px;
padding: 8px 0 0 26px;
cursor: default;
color: $ui-primary-color;
font-size: 15px;
position: relative;
.fa {
color: $ui-highlight-color;
}
> span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
.account--panel {
background: lighten($ui-base-color, 4%);
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
display: flex;
flex-direction: row;
padding: 10px 0;
}
.account--panel__button,
.detailed-status__button {
flex: 1 1 auto;
text-align: center;
}
.column-settings__outer {
background: lighten($ui-base-color, 8%);
padding: 15px;
}
.column-settings__section {
color: $ui-primary-color;
cursor: default;
display: block;
font-weight: 500;
margin-bottom: 10px;
}
.column-settings__row {
.text-btn {
margin-bottom: 15px;
}
}
.account--follows-info {
color: $primary-text-color;
position: absolute;
top: 10px;
left: 10px;
opacity: 0.7;
display: inline-block;
vertical-align: top;
background-color: rgba($base-overlay-background, 0.4);
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
padding: 4px;
border-radius: 4px;
}
.account--action-button {
position: absolute;
top: 10px;
right: 20px;
}
.account-gallery__container {
margin: -2px;
padding: 4px;
display: flex;
flex-wrap: wrap;
}
.account-gallery__item {
flex: 1 1 auto;
width: calc(100% / 3 - 4px);
height: 95px;
margin: 2px;
a {
display: block;
width: 100%;
height: 100%;
background-color: $base-overlay-background;
background-size: cover;
background-position: center;
position: relative;
color: inherit;
text-decoration: none;
&:hover,
&:active,
&:focus {
outline: 0;
}
}
}
.account-section-headline {
color: $ui-base-lighter-color;
background: lighten($ui-base-color, 2%);
border-bottom: 1px solid lighten($ui-base-color, 4%);
padding: 15px 10px;
font-size: 14px;
font-weight: 500;
position: relative;
cursor: default;
&::before,
&::after {
display: block;
content: "";
position: absolute;
bottom: 0;
left: 18px;
width: 0;
height: 0;
border-style: solid;
border-width: 0 10px 10px;
border-color: transparent transparent lighten($ui-base-color, 4%);
}
&::after {
bottom: -1px;
border-color: transparent transparent $ui-base-color;
}
}
.account__moved-note {
padding: 14px 10px;
padding-bottom: 16px;
background: lighten($ui-base-color, 4%);
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
&__message {
position: relative;
margin-left: 58px;
color: $ui-base-lighter-color;
padding: 8px 0;
padding-top: 0;
padding-bottom: 4px;
font-size: 14px;
> span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
&__icon-wrapper {
left: -26px;
position: absolute;
}
.detailed-status__display-avatar {
position: relative;
}
.detailed-status__display-name {
margin-bottom: 0;
}
}

View File

@@ -0,0 +1,503 @@
.column__wrapper {
display: flex;
flex: 1 1 auto;
position: relative;
}
.column-icon {
background: lighten($ui-base-color, 4%);
color: $ui-primary-color;
cursor: pointer;
font-size: 16px;
padding: 15px;
position: absolute;
right: 0;
top: -48px;
z-index: 3;
&:hover {
color: lighten($ui-primary-color, 7%);
}
}
.columns-area {
display: flex;
flex: 1 1 auto;
flex-direction: row;
justify-content: flex-start;
overflow-x: auto;
position: relative;
}
@include limited-single-column('screen and (max-width: 360px)', $parent: null) {
.columns-area {
padding: 10px;
}
.react-swipeable-view-container .columns-area {
height: calc(100% - 20px) !important;
}
}
.react-swipeable-view-container {
&,
.columns-area,
.column {
height: 100%;
}
}
.react-swipeable-view-container > * {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.column {
width: 330px;
position: relative;
box-sizing: border-box;
display: flex;
flex-direction: column;
> .scrollable {
background: $ui-base-color;
}
}
.ui {
flex: 0 0 auto;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
background: darken($ui-base-color, 7%);
}
.column {
overflow: hidden;
}
@include limited-single-column('screen and (max-width: 360px)', $parent: null) {
.tabs-bar {
margin: 0;
}
}
:root { // Overrides .wide stylings for mobile view
@include single-column('screen and (max-width: 630px)', $parent: null) {
.column {
flex: auto;
width: 100%;
min-width: 0;
max-width: none;
padding: 0;
}
.columns-area {
flex-direction: column;
}
.search__input,
.autosuggest-textarea__textarea {
font-size: 16px;
}
}
}
@include multi-columns('screen and (min-width: 631px)', $parent: null) {
.columns-area {
padding: 0;
}
.column {
flex: 0 0 auto;
padding: 10px;
padding-left: 5px;
padding-right: 5px;
&:first-child {
padding-left: 10px;
}
&:last-child {
padding-right: 10px;
}
}
.columns-area > div {
.column {
padding-left: 5px;
padding-right: 5px;
}
}
}
.column-back-button {
background: lighten($ui-base-color, 4%);
color: $ui-highlight-color;
cursor: pointer;
flex: 0 0 auto;
font-size: 16px;
border: 0;
text-align: unset;
padding: 15px;
margin: 0;
z-index: 3;
&:hover {
text-decoration: underline;
}
}
.column-header__back-button {
background: lighten($ui-base-color, 4%);
border: 0;
font-family: inherit;
color: $ui-highlight-color;
cursor: pointer;
flex: 0 0 auto;
font-size: 16px;
padding: 0 5px 0 0;
z-index: 3;
&:hover {
text-decoration: underline;
}
&:last-child {
padding: 0 15px 0 0;
}
}
.column-back-button__icon {
display: inline-block;
margin-right: 5px;
}
.column-back-button--slim {
position: relative;
}
.column-back-button--slim-button {
cursor: pointer;
flex: 0 0 auto;
font-size: 16px;
padding: 15px;
position: absolute;
right: 0;
top: -48px;
}
.column-link {
background: lighten($ui-base-color, 8%);
color: $primary-text-color;
display: block;
font-size: 16px;
padding: 15px;
text-decoration: none;
&:hover {
background: lighten($ui-base-color, 11%);
}
}
.column-link__icon {
display: inline-block;
margin-right: 5px;
}
.column-subheading {
background: $ui-base-color;
color: $ui-base-lighter-color;
padding: 8px 20px;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
cursor: default;
}
.column-header__wrapper {
position: relative;
flex: 0 0 auto;
&.active {
&::before {
display: block;
content: "";
position: absolute;
top: 35px;
left: 0;
right: 0;
margin: 0 auto;
width: 60%;
pointer-events: none;
height: 28px;
z-index: 1;
background: radial-gradient(ellipse, rgba($ui-highlight-color, 0.23) 0%, rgba($ui-highlight-color, 0) 60%);
}
}
}
.column-header {
display: flex;
padding: 15px;
font-size: 16px;
background: lighten($ui-base-color, 4%);
flex: 0 0 auto;
cursor: pointer;
position: relative;
z-index: 2;
outline: 0;
&.active {
box-shadow: 0 1px 0 rgba($ui-highlight-color, 0.3);
.column-header__icon {
color: $ui-highlight-color;
text-shadow: 0 0 10px rgba($ui-highlight-color, 0.4);
}
}
&:focus,
&:active {
outline: 0;
}
}
.column {
width: 330px;
position: relative;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: hidden;
.wide & {
flex: auto;
min-width: 330px;
max-width: 400px;
}
> .scrollable {
background: $ui-base-color;
}
}
.column-header__buttons {
height: 48px;
display: flex;
margin: -15px;
margin-left: 0;
}
.column-header__links .text-btn {
margin-right: 10px;
}
.column-header__button {
background: lighten($ui-base-color, 4%);
border: 0;
color: $ui-primary-color;
cursor: pointer;
font-size: 16px;
padding: 0 15px;
&:hover {
color: lighten($ui-primary-color, 7%);
}
&.active {
color: $primary-text-color;
background: lighten($ui-base-color, 8%);
&:hover {
color: $primary-text-color;
background: lighten($ui-base-color, 8%);
}
}
// glitch - added focus ring for keyboard navigation
&:focus {
text-shadow: 0 0 4px darken($ui-highlight-color, 5%);
}
}
.column-header__notif-cleaning-buttons {
display: flex;
align-items: stretch;
justify-content: space-around;
button {
@extend .column-header__button;
background: transparent;
text-align: center;
padding: 10px 0;
white-space: pre-wrap;
}
b {
font-weight: bold;
}
}
// The notifs drawer with no padding to have more space for the buttons
.column-header__collapsible-inner.nopad-drawer {
padding: 0;
}
.column-header__collapsible {
max-height: 70vh;
overflow: hidden;
overflow-y: auto;
color: $ui-primary-color;
transition: max-height 150ms ease-in-out, opacity 300ms linear;
opacity: 1;
&.collapsed {
max-height: 0;
opacity: 0.5;
}
&.animating {
overflow-y: hidden;
}
hr {
height: 0;
background: transparent;
border: 0;
border-top: 1px solid lighten($ui-base-color, 12%);
margin: 10px 0;
}
// notif cleaning drawer
&.ncd {
transition: none;
&.collapsed {
max-height: 0;
opacity: 0.7;
}
}
}
.column-header__collapsible-inner {
background: lighten($ui-base-color, 8%);
padding: 15px;
}
.column-header__setting-btn {
&:hover {
color: lighten($ui-primary-color, 4%);
text-decoration: underline;
}
}
.column-header__setting-arrows {
float: right;
.column-header__setting-btn {
padding: 0 10px;
&:last-child {
padding-right: 0;
}
}
}
.column-header__title {
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
flex: 1;
}
.column-header__icon {
display: inline-block;
margin-right: 5px;
}
.empty-column-indicator,
.error-column {
color: lighten($ui-base-color, 20%);
background: $ui-base-color;
text-align: center;
padding: 20px;
font-size: 15px;
font-weight: 400;
cursor: default;
display: flex;
flex: 1 1 auto;
align-items: center;
justify-content: center;
@supports(display: grid) { // hack to fix Chrome <57
contain: strict;
}
a {
color: $ui-highlight-color;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
.error-column {
flex-direction: column;
}
// more fixes for the navbar-under mode
@mixin fix-margins-for-navbar-under {
.tabs-bar {
margin-top: 0 !important;
margin-bottom: -6px !important;
}
}
.single-column.navbar-under {
@include fix-margins-for-navbar-under;
}
.auto-columns.navbar-under {
@media screen and (max-width: 360px) {
@include fix-margins-for-navbar-under;
}
}
.auto-columns.navbar-under .react-swipeable-view-container .columns-area,
.single-column.navbar-under .react-swipeable-view-container .columns-area {
@media screen and (max-width: 360px) {
height: 100% !important;
}
}
.column-inline-form {
padding: 7px 15px;
padding-right: 5px;
display: flex;
justify-content: flex-start;
align-items: center;
background: lighten($ui-base-color, 4%);
label {
flex: 1 1 auto;
input {
width: 100%;
margin-bottom: 6px;
&:focus {
outline: 0;
}
}
}
.icon-button {
flex: 0 0 auto;
margin-left: 5px;
}
}

View File

@@ -1,4 +1,6 @@
.composer { padding: 10px }
.composer {
padding: 10px;
}
.composer--spoiler {
input {
@@ -102,6 +104,17 @@
}
}
.emoji-picker-dropdown {
position: absolute;
right: 5px;
top: 5px;
::-webkit-scrollbar-track:hover,
::-webkit-scrollbar-track:active {
background-color: rgba($base-overlay-background, 0.3);
}
}
.composer--textarea {
position: relative;

View File

@@ -40,7 +40,9 @@
.react-swipeable-view-container & { height: 100% }
& > .contents {
display: flex;
position: relative;
flex-direction: column;
padding: 0;
width: 100%;
height: 100%;
@@ -48,6 +50,30 @@
overflow-x: hidden;
overflow-y: auto;
contain: strict;
& > .mastodon {
flex: 1;
border: none;
cursor: inherit;
}
}
@for $i from 0 through 3 {
&.mbstobon-#{$i} > .contents {
@if $i == 3 {
background: url('~flavours/glitch/images/wave-drawer.png') no-repeat bottom / 100% auto, lighten($ui-base-color, 13%);
} @else {
background: url('~flavours/glitch/images/wave-drawer-glitched.png') no-repeat bottom / 100% auto, lighten($ui-base-color, 13%);
}
& > .mastodon {
background: url("~flavours/glitch/images/mbstobon-ui-#{$i}.png") no-repeat left bottom / contain;
@if $i != 3 {
filter: contrast(50%) brightness(50%);
}
}
}
}
}
@@ -256,3 +282,52 @@
}
}
}
.drawer__pager {
box-sizing: border-box;
padding: 0;
flex-grow: 1;
position: relative;
overflow: hidden;
display: flex;
}
.drawer__inner {
position: absolute;
top: 0;
left: 0;
background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto;
box-sizing: border-box;
padding: 0;
display: flex;
flex-direction: column;
overflow: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
&.darker {
background: $ui-base-color;
}
> .mastodon {
background: url('~images/elephant_ui_plane.svg') no-repeat left bottom / contain;
flex: 1;
}
}
.pseudo-drawer {
background: lighten($ui-base-color, 13%);
font-size: 13px;
text-align: left;
}
.drawer__backdrop {
cursor: pointer;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba($base-overlay-background, 0.5);
}

View File

@@ -0,0 +1,105 @@
.emojione {
display: inline-block;
font-size: inherit;
vertical-align: middle;
object-fit: contain;
margin: -.2ex .15em .2ex;
width: 16px;
height: 16px;
img {
width: auto;
}
}
.emoji-picker-dropdown__menu {
background: $simple-background-color;
position: absolute;
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
border-radius: 4px;
margin-top: 5px;
.emoji-mart-scroll {
transition: opacity 200ms ease;
}
&.selecting .emoji-mart-scroll {
opacity: 0.5;
}
}
.emoji-picker-dropdown__modifiers {
position: absolute;
top: 60px;
right: 11px;
cursor: pointer;
}
.emoji-picker-dropdown__modifiers__menu {
position: absolute;
z-index: 4;
top: -4px;
left: -8px;
background: $simple-background-color;
border-radius: 4px;
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
overflow: hidden;
button {
display: block;
cursor: pointer;
border: 0;
padding: 4px 8px;
background: transparent;
&:hover,
&:focus,
&:active {
background: rgba($ui-secondary-color, 0.4);
}
}
.emoji-mart-emoji {
height: 22px;
}
}
.emoji-mart-emoji {
span {
background-repeat: no-repeat;
}
}
.emoji-button {
display: block;
font-size: 24px;
line-height: 24px;
margin-left: 2px;
width: 24px;
outline: 0;
cursor: pointer;
&:active,
&:focus {
outline: 0 !important;
}
img {
filter: grayscale(100%);
opacity: 0.8;
display: block;
margin: 0;
width: 22px;
height: 22px;
margin-top: 2px;
}
&:hover,
&:active,
&:focus {
img {
opacity: 1;
filter: none;
}
}
}

View File

@@ -95,6 +95,11 @@
padding: 0 6px 6px;
background: $simple-background-color;
will-change: transform;
&::-webkit-scrollbar-track:hover,
&::-webkit-scrollbar-track:active {
background-color: rgba($base-overlay-background, 0.3);
}
}
.emoji-mart-search {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
.attachment-list {
display: flex;
font-size: 14px;
border: 1px solid lighten($ui-base-color, 8%);
border-radius: 4px;
margin-top: 14px;
overflow: hidden;
}
.attachment-list__icon {
flex: 0 0 auto;
color: $ui-base-lighter-color;
padding: 8px 18px;
cursor: default;
border-right: 1px solid lighten($ui-base-color, 8%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 26px;
.fa {
display: block;
}
}
.attachment-list__list {
list-style: none;
padding: 4px 0;
padding-left: 8px;
display: flex;
flex-direction: column;
justify-content: center;
li {
display: block;
padding: 4px 0;
}
a {
text-decoration: none;
color: $ui-base-lighter-color;
font-weight: 500;
&:hover {
text-decoration: underline;
}
}
}
.list-editor {
background: $ui-base-color;
flex-direction: column;
border-radius: 8px;
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
width: 380px;
overflow: hidden;
@media screen and (max-width: 420px) {
width: 90%;
}
h4 {
padding: 15px 0;
background: lighten($ui-base-color, 13%);
font-weight: 500;
font-size: 16px;
text-align: center;
border-radius: 8px 8px 0 0;
}
.drawer__pager {
height: 50vh;
}
.drawer__inner {
border-radius: 0 0 8px 8px;
&.backdrop {
width: calc(100% - 60px);
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
border-radius: 0 0 0 8px;
}
}
&__accounts {
overflow-y: auto;
}
.account__display-name {
&:hover strong {
text-decoration: none;
}
}
.account__avatar {
cursor: default;
}
.search {
margin-bottom: 0;
}
}

View File

@@ -0,0 +1,485 @@
.video-error-cover {
align-items: center;
background: $base-overlay-background;
color: $primary-text-color;
cursor: pointer;
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
margin-top: 8px;
position: relative;
text-align: center;
z-index: 100;
}
.media-spoiler {
background: $base-overlay-background;
color: $ui-primary-color;
border: 0;
width: 100%;
height: 100%;
&:hover,
&:active,
&:focus {
color: lighten($ui-primary-color, 8%);
}
.status__content > & {
margin-top: 15px; // Add margin when used bare for NSFW video player
}
@include fullwidth-gallery;
}
.media-spoiler__warning {
display: block;
font-size: 14px;
}
.media-spoiler__trigger {
display: block;
font-size: 11px;
font-weight: 500;
}
.media-gallery__gifv__label {
display: block;
position: absolute;
color: $primary-text-color;
background: rgba($base-overlay-background, 0.5);
bottom: 6px;
left: 6px;
padding: 2px 6px;
border-radius: 2px;
font-size: 11px;
font-weight: 600;
z-index: 1;
pointer-events: none;
opacity: 0.9;
transition: opacity 0.1s ease;
}
.media-gallery__gifv {
&.autoplay {
.media-gallery__gifv__label {
display: none;
}
}
&:hover {
.media-gallery__gifv__label {
opacity: 1;
}
}
}
.media-gallery {
box-sizing: border-box;
margin-top: 8px;
overflow: hidden;
position: relative;
background: $base-shadow-color;
width: 100%;
height: 110px;
.detailed-status & {
margin-left: -22px;
width: calc(100% + 44px);
height: 250px;
}
@include fullwidth-gallery;
}
.media-gallery__item {
border: none;
box-sizing: border-box;
display: block;
float: left;
position: relative;
&.standalone {
.media-gallery__item-gifv-thumbnail {
transform: none;
}
}
}
.media-gallery__item-thumbnail {
cursor: zoom-in;
display: block;
text-decoration: none;
height: 100%;
line-height: 0;
&,
img {
height: 100%;
width: 100%;
object-fit: contain;
&:not(.letterbox) {
height: 100%;
object-fit: cover;
}
}
}
.media-gallery__gifv {
height: 100%;
overflow: hidden;
position: relative;
width: 100%;
display: flex;
justify-content: center;
}
.media-gallery__item-gifv-thumbnail {
cursor: zoom-in;
height: 100%;
width: 100%;
position: relative;
z-index: 1;
object-fit: contain;
&:not(.letterbox) {
height: 100%;
object-fit: cover;
}
}
.media-gallery__item-thumbnail-label {
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
overflow: hidden;
position: absolute;
}
.media-modal {
max-width: 80vw;
max-height: 80vh;
position: relative;
.extended-video-player,
img,
canvas,
video {
max-width: 80vw;
max-height: 80vh;
width: auto;
height: auto;
margin: auto;
}
.extended-video-player,
video {
display: flex;
width: 80vw;
height: 80vh;
}
img,
canvas {
display: block;
background: url('~images/void.png') repeat;
object-fit: contain;
}
.react-swipeable-view-container {
max-width: 80vw;
}
}
.media-modal__content {
background: $base-overlay-background;
}
.media-modal__pagination {
width: 100%;
text-align: center;
position: absolute;
left: 0;
bottom: -40px;
}
.media-modal__page-dot {
display: inline-block;
}
.media-modal__button {
background-color: $white;
height: 12px;
width: 12px;
border-radius: 6px;
margin: 10px;
padding: 0;
border: 0;
font-size: 0;
}
.media-modal__button--active {
background-color: $ui-highlight-color;
}
.media-modal__close {
position: absolute;
right: 4px;
top: 4px;
z-index: 100;
}
.video-player {
overflow: hidden;
position: relative;
background: $base-shadow-color;
max-width: 100%;
.detailed-status & {
width: 100%;
height: 100%;
}
@include fullwidth-gallery;
video {
height: 100%;
width: 100%;
z-index: 1;
object-fit: cover;
position: relative;
}
&.fullscreen {
width: 100% !important;
height: 100% !important;
margin: 0;
video {
max-width: 100% !important;
max-height: 100% !important;
}
}
&.inline {
video {
object-fit: cover;
position: relative;
top: 50%;
transform: translateY(-50%);
}
}
&__controls {
position: absolute;
z-index: 2;
bottom: 0;
left: 0;
right: 0;
box-sizing: border-box;
background: linear-gradient(0deg, rgba($base-shadow-color, 0.85) 0, rgba($base-shadow-color, 0.45) 60%, transparent);
padding: 0 15px;
opacity: 0;
transition: opacity .1s ease;
&.active {
opacity: 1;
}
}
&.inactive {
video,
.video-player__controls {
visibility: hidden;
}
}
&__spoiler {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 4;
border: 0;
background: $base-shadow-color;
color: $ui-primary-color;
transition: none;
pointer-events: none;
&.active {
display: block;
pointer-events: auto;
&:hover,
&:active,
&:focus {
color: lighten($ui-primary-color, 8%);
}
}
&__title {
display: block;
font-size: 14px;
}
&__subtitle {
display: block;
font-size: 11px;
font-weight: 500;
}
}
&__buttons-bar {
display: flex;
justify-content: space-between;
padding-bottom: 10px;
}
&__buttons {
font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.left {
button {
padding-left: 0;
}
}
&.right {
button {
padding-right: 0;
}
}
button {
background: transparent;
padding: 2px 10px;
font-size: 16px;
border: 0;
color: rgba($white, 0.75);
&:active,
&:hover,
&:focus {
color: $white;
}
}
}
&__time-sep,
&__time-total,
&__time-current {
font-size: 14px;
font-weight: 500;
}
&__time-current {
color: $white;
margin-left: 10px;
}
&__time-sep {
display: inline-block;
margin: 0 6px;
}
&__time-sep,
&__time-total {
color: $white;
}
&__seek {
cursor: pointer;
height: 24px;
position: relative;
&::before {
content: "";
width: 100%;
background: rgba($white, 0.35);
border-radius: 4px;
display: block;
position: absolute;
height: 4px;
top: 10px;
}
&__progress,
&__buffer {
display: block;
position: absolute;
height: 4px;
border-radius: 4px;
top: 10px;
background: lighten($ui-highlight-color, 8%);
}
&__buffer {
background: rgba($white, 0.2);
}
&__handle {
position: absolute;
z-index: 3;
opacity: 0;
border-radius: 50%;
width: 12px;
height: 12px;
top: 6px;
margin-left: -6px;
transition: opacity .1s ease;
background: lighten($ui-highlight-color, 8%);
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
pointer-events: none;
&.active {
opacity: 1;
}
}
&:hover {
.video-player__seek__handle {
opacity: 1;
}
}
}
&.detailed,
&.fullscreen {
.video-player__buttons {
button {
padding-top: 10px;
padding-bottom: 10px;
}
}
}
}
.media-spoiler-video {
background-size: cover;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
margin-top: 8px;
position: relative;
@include fullwidth-gallery;
border: 0;
display: block;
}
.media-spoiler-video-play-icon {
border-radius: 100px;
color: rgba($primary-text-color, 0.8);
font-size: 36px;
left: 50%;
padding: 5px;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}

View File

@@ -0,0 +1,52 @@
.account__metadata {
width: 100%;
font-size: 15px;
line-height: 20px;
overflow: hidden;
border-collapse: collapse;
a {
text-decoration: none;
&:hover{
text-decoration: underline;
}
}
tr {
border-top: 1px solid lighten($ui-base-color, 8%);
text-align: center;
}
th, td {
padding: 14px 20px;
vertical-align: middle;
& > div {
max-height: 40px;
overflow-y: auto;
white-space: pre-wrap;
text-overflow: ellipsis;
}
}
th {
color: $ui-primary-color;
background: lighten($ui-base-color, 13%);
max-width: 120px;
a {
color: $primary-text-color;
}
}
td {
flex: auto;
color: $primary-text-color;
background: $ui-base-color;
a {
color: $ui-highlight-color;
}
}
}

View File

@@ -0,0 +1,699 @@
.modal-container--preloader {
background: lighten($ui-base-color, 8%);
}
.modal-container__nav {
align-items: center;
background: rgba($base-overlay-background, 0.5);
box-sizing: border-box;
border: 0;
color: $primary-text-color;
cursor: pointer;
display: flex;
font-size: 24px;
height: 100%;
padding: 30px 15px;
position: absolute;
top: 0;
}
.modal-container__nav--left {
left: -61px;
}
.modal-container__nav--right {
right: -61px;
}
.modal-root {
transition: opacity 0.3s linear;
will-change: opacity;
z-index: 9999;
}
.modal-root__overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba($base-overlay-background, 0.7);
}
.modal-root__container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
align-content: space-around;
z-index: 9999;
pointer-events: none;
user-select: none;
}
.modal-root__modal {
pointer-events: auto;
display: flex;
z-index: 9999;
}
.onboarding-modal,
.error-modal,
.embed-modal {
background: $ui-secondary-color;
color: $ui-base-color;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.onboarding-modal__pager {
height: 80vh;
width: 80vw;
max-width: 520px;
max-height: 470px;
.react-swipeable-view-container > div {
width: 100%;
height: 100%;
box-sizing: border-box;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
display: flex;
user-select: text;
}
}
.error-modal__body {
height: 80vh;
width: 80vw;
max-width: 520px;
max-height: 420px;
position: relative;
& > div {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 25px;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
display: flex;
opacity: 0;
user-select: text;
}
}
.error-modal__body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
@media screen and (max-width: 550px) {
.onboarding-modal {
width: 100%;
height: 100%;
border-radius: 0;
}
.onboarding-modal__pager {
width: 100%;
height: auto;
max-width: none;
max-height: none;
flex: 1 1 auto;
}
}
.onboarding-modal__paginator,
.error-modal__footer {
flex: 0 0 auto;
background: darken($ui-secondary-color, 8%);
display: flex;
padding: 25px;
& > div {
min-width: 33px;
}
.onboarding-modal__nav,
.error-modal__nav {
color: darken($ui-secondary-color, 34%);
border: 0;
font-size: 14px;
font-weight: 500;
padding: 10px 25px;
line-height: inherit;
height: auto;
margin: -10px;
border-radius: 4px;
background-color: transparent;
&:hover,
&:focus,
&:active {
color: darken($ui-secondary-color, 38%);
background-color: darken($ui-secondary-color, 16%);
}
&.onboarding-modal__done,
&.onboarding-modal__next {
color: $ui-base-color;
&:hover,
&:focus,
&:active {
color: darken($ui-base-color, 4%);
}
}
}
}
.error-modal__footer {
justify-content: center;
}
.onboarding-modal__dots {
flex: 1 1 auto;
display: flex;
align-items: center;
justify-content: center;
}
.onboarding-modal__dot {
width: 14px;
height: 14px;
border-radius: 14px;
background: darken($ui-secondary-color, 16%);
margin: 0 3px;
cursor: pointer;
&:hover {
background: darken($ui-secondary-color, 18%);
}
&.active {
cursor: default;
background: darken($ui-secondary-color, 24%);
}
}
.onboarding-modal__page__wrapper {
pointer-events: none;
padding: 25px;
padding-bottom: 0;
&.onboarding-modal__page__wrapper--active {
pointer-events: auto;
}
}
.onboarding-modal__page {
cursor: default;
line-height: 21px;
h1 {
font-size: 18px;
font-weight: 500;
color: $ui-base-color;
margin-bottom: 20px;
}
a {
color: $ui-highlight-color;
&:hover,
&:focus,
&:active {
color: lighten($ui-highlight-color, 4%);
}
}
.navigation-bar a {
color: inherit;
}
p {
font-size: 16px;
color: lighten($ui-base-color, 8%);
margin-top: 10px;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
strong {
font-weight: 500;
background: $ui-base-color;
color: $ui-secondary-color;
border-radius: 4px;
font-size: 14px;
padding: 3px 6px;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
}
}
.onboarding-modal__page__wrapper-0 {
background: url('~images/elephant_ui_greeting.svg') no-repeat left bottom / auto 250px;
height: 100%;
padding: 0;
}
.onboarding-modal__page-one {
&__lead {
padding: 65px;
padding-top: 45px;
padding-bottom: 0;
margin-bottom: 10px;
h1 {
font-size: 26px;
line-height: 36px;
margin-bottom: 8px;
}
p {
margin-bottom: 0;
}
}
&__extra {
padding-right: 65px;
padding-left: 185px;
text-align: center;
}
}
.display-case {
text-align: center;
font-size: 15px;
margin-bottom: 15px;
&__label {
font-weight: 500;
color: $ui-base-color;
margin-bottom: 5px;
text-transform: uppercase;
font-size: 12px;
}
&__case {
background: $ui-base-color;
color: $ui-secondary-color;
font-weight: 500;
padding: 10px;
border-radius: 4px;
}
}
.onboarding-modal__page-two,
.onboarding-modal__page-three,
.onboarding-modal__page-four,
.onboarding-modal__page-five {
p {
text-align: left;
}
.figure {
background: darken($ui-base-color, 8%);
color: $ui-secondary-color;
margin-bottom: 20px;
border-radius: 4px;
padding: 10px;
text-align: center;
font-size: 14px;
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.3);
.onboarding-modal__image {
border-radius: 4px;
margin-bottom: 10px;
}
&.non-interactive {
pointer-events: none;
text-align: left;
}
}
}
.onboarding-modal__page-four__columns {
.row {
display: flex;
margin-bottom: 20px;
& > div {
flex: 1 1 0;
margin: 0 10px;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
p {
text-align: center;
}
}
&:last-child {
margin-bottom: 0;
}
}
.column-header {
color: $primary-text-color;
}
}
@media screen and (max-width: 320px) and (max-height: 600px) {
.onboarding-modal__page p {
font-size: 14px;
line-height: 20px;
}
.onboarding-modal__page-two .figure,
.onboarding-modal__page-three .figure,
.onboarding-modal__page-four .figure,
.onboarding-modal__page-five .figure {
font-size: 12px;
margin-bottom: 10px;
}
.onboarding-modal__page-four__columns .row {
margin-bottom: 10px;
}
.onboarding-modal__page-four__columns .column-header {
padding: 5px;
font-size: 12px;
}
}
.onboard-sliders {
display: inline-block;
max-width: 30px;
max-height: auto;
margin-left: 10px;
}
.boost-modal,
.favourite-modal,
.confirmation-modal,
.report-modal,
.actions-modal,
.mute-modal {
background: lighten($ui-secondary-color, 8%);
color: $ui-base-color;
border-radius: 8px;
overflow: hidden;
max-width: 90vw;
width: 480px;
position: relative;
flex-direction: column;
.status__display-name {
display: flex;
}
.status__avatar {
height: 28px;
left: 10px;
top: 10px;
width: 48px;
}
}
.actions-modal {
.status {
background: $white;
border-bottom-color: $ui-secondary-color;
padding-top: 10px;
padding-bottom: 10px;
}
.dropdown-menu__separator {
border-bottom-color: $ui-secondary-color;
}
}
.boost-modal__container,
.favourite-modal__container {
overflow-x: scroll;
padding: 10px;
.status {
user-select: text;
border-bottom: 0;
}
}
.boost-modal__action-bar,
.favourite-modal__action-bar,
.confirmation-modal__action-bar,
.mute-modal__action-bar,
.report-modal__action-bar {
display: flex;
justify-content: space-between;
background: $ui-secondary-color;
padding: 10px;
line-height: 36px;
& > div {
flex: 1 1 auto;
text-align: right;
color: lighten($ui-base-color, 33%);
padding-right: 10px;
}
.button {
flex: 0 0 auto;
}
}
.boost-modal__status-header,
.favourite-modal__status-header {
font-size: 15px;
}
.boost-modal__status-time,
.favourite-modal__status-time {
float: right;
font-size: 14px;
}
.confirmation-modal {
max-width: 85vw;
@media screen and (min-width: 480px) {
max-width: 380px;
}
}
.mute-modal {
line-height: 24px;
}
.mute-modal .react-toggle {
vertical-align: middle;
}
.report-modal__statuses,
.report-modal__comment {
padding: 10px;
}
.report-modal__statuses {
min-height: 20vh;
max-height: 40vh;
overflow-y: auto;
overflow-x: hidden;
}
.report-modal__comment {
.setting-text {
margin-top: 10px;
}
}
.actions-modal {
.status {
overflow-y: auto;
max-height: 300px;
}
strong {
display: block;
font-weight: 500;
}
max-height: 80vh;
max-width: 80vw;
.actions-modal__item-label {
font-weight: 500;
}
ul {
overflow-y: auto;
flex-shrink: 0;
li:empty {
margin: 0;
}
li:not(:empty) {
a {
color: $ui-base-color;
display: flex;
padding: 12px 16px;
font-size: 15px;
align-items: center;
text-decoration: none;
&,
button {
transition: none;
}
&.active,
&:hover,
&:active,
&:focus {
&,
button {
background: $ui-highlight-color;
color: $primary-text-color;
}
}
& > .react-toggle,
& > .icon,
button:first-child {
margin-right: 10px;
}
}
}
}
}
.confirmation-modal__action-bar,
.mute-modal__action-bar {
.confirmation-modal__cancel-button,
.mute-modal__cancel-button {
background-color: transparent;
color: darken($ui-secondary-color, 34%);
font-size: 14px;
font-weight: 500;
&:hover,
&:focus,
&:active {
color: darken($ui-secondary-color, 38%);
}
}
}
.confirmation-modal__container,
.mute-modal__container,
.report-modal__target {
padding: 30px;
font-size: 16px;
text-align: center;
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
}
.embed-modal {
max-width: 80vw;
max-height: 80vh;
h4 {
padding: 30px;
font-weight: 500;
font-size: 16px;
text-align: center;
}
.embed-modal__container {
padding: 10px;
.hint {
margin-bottom: 15px;
}
.embed-modal__html {
color: $ui-secondary-color;
outline: 0;
box-sizing: border-box;
display: block;
width: 100%;
border: none;
padding: 10px;
font-family: 'mastodon-font-monospace', monospace;
background: $ui-base-color;
color: $ui-primary-color;
font-size: 14px;
margin: 0;
margin-bottom: 15px;
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
@media screen and (max-width: 600px) {
font-size: 16px;
}
}
.embed-modal__iframe {
width: 400px;
max-width: 100%;
overflow: hidden;
border: 0;
}
}
}

View File

@@ -0,0 +1,53 @@
.regeneration-indicator {
text-align: center;
font-size: 16px;
font-weight: 500;
color: lighten($ui-base-color, 16%);
background: $ui-base-color;
cursor: default;
display: flex;
flex: 1 1 auto;
align-items: center;
justify-content: center;
padding: 20px;
& > div {
width: 100%;
background: transparent;
padding-top: 0;
}
&__figure {
background: url('~flavours/glitch/images/elephant_ui_working.svg') no-repeat center 0;
width: 100%;
height: 160px;
background-size: contain;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
&.missing-indicator {
padding-top: 20px + 48px;
.regeneration-indicator__figure {
background-image: url('~flavours/glitch/images/elephant_ui_disappointed.svg');
}
}
&__label {
margin-top: 200px;
strong {
display: block;
margin-bottom: 10px;
color: lighten($ui-base-color, 34%);
}
span {
font-size: 15px;
font-weight: 400;
}
}
}

View File

@@ -0,0 +1,105 @@
.search {
position: relative;
}
.search__input {
outline: 0;
box-sizing: border-box;
display: block;
width: 100%;
border: none;
padding: 10px;
padding-right: 30px;
font-family: inherit;
background: $ui-base-color;
color: $ui-primary-color;
font-size: 14px;
margin: 0;
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
@media screen and (max-width: 600px) {
font-size: 16px;
}
}
.search__icon {
.fa {
position: absolute;
top: 10px;
right: 10px;
z-index: 2;
display: inline-block;
opacity: 0;
transition: all 100ms linear;
font-size: 18px;
width: 18px;
height: 18px;
color: $ui-secondary-color;
cursor: default;
pointer-events: none;
&.active {
pointer-events: auto;
opacity: 0.3;
}
}
.fa-search {
transform: rotate(90deg);
&.active {
pointer-events: none;
transform: rotate(0deg);
}
}
.fa-times-circle {
top: 11px;
transform: rotate(0deg);
cursor: pointer;
&.active {
transform: rotate(90deg);
}
&:hover {
color: $primary-text-color;
}
}
}
.search-results__header {
color: $ui-base-lighter-color;
background: lighten($ui-base-color, 2%);
border-bottom: 1px solid darken($ui-base-color, 4%);
padding: 15px 10px;
font-size: 14px;
font-weight: 500;
}
.search-results__hashtag {
display: block;
padding: 10px;
color: $ui-secondary-color;
text-decoration: none;
&:hover,
&:active,
&:focus {
color: lighten($ui-secondary-color, 4%);
text-decoration: underline;
}
}

View File

@@ -0,0 +1,24 @@
.sensitive-info {
display: flex;
flex-direction: row;
align-items: center;
position: absolute;
top: 4px;
left: 4px;
z-index: 100;
}
.sensitive-marker {
margin: 0 3px;
border-radius: 2px;
padding: 2px 6px;
color: rgba($primary-text-color, 0.8);
background: rgba($base-overlay-background, 0.5);
font-size: 12px;
line-height: 15px;
text-transform: uppercase;
opacity: .9;
transition: opacity .1s ease;
.media-gallery:hover & { opacity: 1 }
}

View File

@@ -0,0 +1,698 @@
.status__content--with-action {
cursor: pointer;
}
.status__content {
position: relative;
margin: 10px 0;
padding: 0 12px;
font-size: 15px;
line-height: 20px;
color: $primary-text-color;
word-wrap: break-word;
font-weight: 400;
overflow: visible;
padding-top: 5px;
&:focus {
outline: 0;
}
.emojione {
width: 20px;
height: 20px;
margin: -3px 0 0;
}
p {
margin-bottom: 20px;
white-space: pre-wrap;
&:last-child {
margin-bottom: 0;
}
}
a {
color: $ui-secondary-color;
text-decoration: none;
&:hover {
text-decoration: underline;
.fa {
color: lighten($ui-base-color, 40%);
}
}
&.mention {
&:hover {
text-decoration: none;
span {
text-decoration: underline;
}
}
}
.fa {
color: lighten($ui-base-color, 30%);
}
}
.status__content__spoiler {
display: none;
&.status__content__spoiler--visible {
display: block;
}
}
.status__content__spoiler-link {
background: lighten($ui-base-color, 30%);
&:hover {
background: lighten($ui-base-color, 33%);
text-decoration: none;
}
}
}
.status__content__spoiler-link {
display: inline-block;
border-radius: 2px;
background: lighten($ui-base-color, 30%);
border: none;
color: lighten($ui-base-color, 8%);
font-weight: 500;
font-size: 11px;
padding: 0 5px;
text-transform: uppercase;
line-height: inherit;
cursor: pointer;
vertical-align: bottom;
&:hover {
background: lighten($ui-base-color, 33%);
text-decoration: none;
}
.status__content__spoiler-icon {
display: inline-block;
margin: 0 0 0 5px;
border-left: 1px solid currentColor;
padding: 0 0 0 4px;
font-size: 16px;
vertical-align: -2px;
}
}
.notif-cleaning {
.status, .notification-follow {
padding-right: ($dismiss-overlay-width + 0.5rem);
}
}
.status__prepend-icon-wrapper {
float: left;
margin: 0 10px 0 -58px;
width: 48px;
text-align: right;
}
.notification-follow {
position: relative;
// same like Status
border-bottom: 1px solid lighten($ui-base-color, 8%);
.account {
border-bottom: 0 none;
}
}
.focusable {
&:focus {
outline: 0;
background: lighten($ui-base-color, 4%);
.status.status-direct {
background: lighten($ui-base-color, 12%);
&.muted {
background: transparent;
}
}
.detailed-status,
.detailed-status__action-bar {
background: lighten($ui-base-color, 8%);
}
}
}
.status {
padding: 8px 10px;
position: relative;
height: auto;
min-height: 48px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
cursor: default;
@supports (-ms-overflow-style: -ms-autohiding-scrollbar) {
// Add margin to avoid Edge auto-hiding scrollbar appearing over content.
// On Edge 16 this is 16px and Edge <=15 it's 12px, so aim for 16px.
padding-right: 26px; // 10px + 16px
}
@keyframes fade {
0% { opacity: 0; }
100% { opacity: 1; }
}
opacity: 1;
animation: fade 150ms linear;
.video-player {
margin-top: 8px;
}
&.status-direct {
background: lighten($ui-base-color, 8%);
.icon-button.disabled {
color: lighten($ui-base-color, 16%);
}
}
&.light {
.status__relative-time {
color: $ui-primary-color;
}
.status__display-name {
color: $ui-base-color;
}
.display-name {
strong {
color: $ui-base-color;
}
span {
color: $ui-primary-color;
}
}
.status__content {
color: $ui-base-color;
a {
color: $ui-highlight-color;
}
a.status__content__spoiler-link {
color: $primary-text-color;
background: $ui-primary-color;
&:hover {
background: lighten($ui-primary-color, 8%);
}
}
}
}
&.collapsed {
background-position: center;
background-size: cover;
user-select: none;
&.has-background::before {
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient(to bottom, rgba($base-shadow-color, .75), rgba($base-shadow-color, .65) 24px, rgba($base-shadow-color, .8));
content: "";
}
.display-name:hover .display-name__html {
text-decoration: none;
}
.status__content {
height: 20px;
overflow: hidden;
text-overflow: ellipsis;
a:hover {
text-decoration: none;
}
}
}
.notification__message {
margin: -10px 0px 10px 32px;
}
}
.notification-favourite {
.status.status-direct {
background: transparent;
.icon-button.disabled {
color: lighten($ui-base-color, 13%);
}
}
}
.status__relative-time {
display: inline-block;
margin-left: auto;
padding-left: 18px;
width: 120px;
color: $ui-base-lighter-color;
font-size: 14px;
text-align: right;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.status__display-name {
margin: 0 auto 0 0;
color: $ui-base-lighter-color;
overflow: hidden;
}
.status__info .status__display-name {
display: block;
max-width: 100%;
padding-right: 25px;
}
.status__info {
display: flex;
margin: 2px 0 5px;
font-size: 15px;
line-height: 24px;
}
.status__info__icons {
flex: none;
position: relative;
color: lighten($ui-base-color, 26%);
.status__visibility-icon {
padding-left: 6px;
}
}
.status-check-box {
border-bottom: 1px solid $ui-secondary-color;
display: flex;
.status__content {
flex: 1 1 auto;
padding: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.status__content {
color: #3a3a3a;
a {
color: #005aa9;
}
}
}
}
.status-check-box-toggle {
align-items: center;
display: flex;
flex: 0 0 auto;
justify-content: center;
padding: 10px;
}
.status__prepend {
margin: -10px -10px 10px;
color: $ui-base-lighter-color;
padding: 8px 10px 0 68px;
font-size: 14px;
position: relative;
.status__display-name strong {
color: $ui-base-lighter-color;
}
> span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
.status__action-bar {
align-items: center;
display: flex;
margin-top: 8px;
}
.status__action-bar-button {
float: left;
margin-right: 18px;
}
.status__action-bar-dropdown {
float: left;
height: 23.15px;
width: 23.15px;
}
.detailed-status__action-bar-dropdown {
flex: 1 1 auto;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.detailed-status {
background: lighten($ui-base-color, 4%);
padding: 14px 10px;
.status__content {
font-size: 19px;
line-height: 24px;
.emojione {
width: 24px;
height: 24px;
margin: -1px 0 0;
}
}
.video-player {
margin-top: 8px;
}
}
.detailed-status__meta {
margin-top: 15px;
color: $ui-base-lighter-color;
font-size: 14px;
line-height: 18px;
}
.detailed-status__action-bar {
background: lighten($ui-base-color, 4%);
border-top: 1px solid lighten($ui-base-color, 8%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
display: flex;
flex-direction: row;
padding: 10px 0;
}
.detailed-status__link {
color: inherit;
text-decoration: none;
}
.detailed-status__favorites,
.detailed-status__reblogs {
display: inline-block;
font-weight: 500;
font-size: 12px;
margin-left: 6px;
}
.status__display-name,
.status__relative-time,
.detailed-status__display-name,
.detailed-status__datetime,
.detailed-status__application,
.account__display-name {
text-decoration: none;
}
.status__display-name,
.account__display-name {
strong {
color: $primary-text-color;
}
}
.muted {
.emojione {
opacity: 0.5;
}
}
.status__display-name,
.reply-indicator__display-name,
.detailed-status__display-name,
.account__display-name {
&:hover strong {
text-decoration: underline;
}
}
.account__display-name strong {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
.detailed-status__application,
.detailed-status__datetime {
color: inherit;
}
.detailed-status__display-name {
color: $ui-secondary-color;
display: block;
line-height: 24px;
margin-bottom: 15px;
overflow: hidden;
strong,
span {
display: block;
text-overflow: ellipsis;
overflow: hidden;
}
strong {
font-size: 16px;
color: $primary-text-color;
}
}
.detailed-status__display-avatar {
float: left;
margin-right: 10px;
}
.status__avatar {
flex: none;
margin: 0 10px 0 0;
height: 48px;
width: 48px;
}
.muted {
.status__content p,
.status__content a {
color: $ui-base-lighter-color;
}
.status__display-name strong {
color: $ui-base-lighter-color;
}
.status__avatar {
opacity: 0.5;
}
a.status__content__spoiler-link {
background: $ui-base-lighter-color;
color: lighten($ui-base-color, 4%);
&:hover {
background: lighten($ui-base-color, 29%);
text-decoration: none;
}
}
}
.status__relative-time,
.detailed-status__datetime {
&:hover {
text-decoration: underline;
}
}
.status-card {
display: flex;
cursor: pointer;
font-size: 14px;
border: 1px solid lighten($ui-base-color, 8%);
border-radius: 4px;
color: $ui-base-lighter-color;
margin-top: 14px;
text-decoration: none;
overflow: hidden;
&:hover {
background: lighten($ui-base-color, 8%);
}
}
.status-card-video,
.status-card-rich,
.status-card-photo {
margin-top: 14px;
overflow: hidden;
iframe {
width: 100%;
height: auto;
}
}
.status-card-photo {
cursor: zoom-in;
display: block;
text-decoration: none;
width: 100%;
height: auto;
margin: 0;
}
.status-card-video {
iframe {
width: 100%;
height: 100%;
}
}
.status-card__title {
display: block;
font-weight: 500;
margin-bottom: 5px;
color: $ui-primary-color;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status-card__content {
flex: 1 1 auto;
overflow: hidden;
padding: 14px 14px 14px 8px;
}
.status-card__description {
color: $ui-primary-color;
}
.status-card__host {
display: block;
margin-top: 5px;
font-size: 13px;
}
.status-card__image {
flex: 0 0 100px;
background: lighten($ui-base-color, 8%);
}
.status-card.horizontal {
display: block;
.status-card__image {
width: 100%;
}
.status-card__image-image {
border-radius: 4px 4px 0 0;
}
.status-card__title {
white-space: inherit;
}
}
.status-card__image-image {
border-radius: 4px 0 0 4px;
display: block;
margin: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.status__video-player {
display: flex;
align-items: center;
background: $base-shadow-color;
box-sizing: border-box;
cursor: default; /* May not be needed */
margin-top: 8px;
overflow: hidden;
position: relative;
@include fullwidth-gallery;
}
.status__video-player-video {
height: 100%;
object-fit: cover;
position: relative;
top: 50%;
transform: translateY(-50%);
width: 100%;
z-index: 1;
&:not(.letterbox) {
height: 100%;
object-fit: cover;
}
}
.status__video-player-expand,
.status__video-player-mute {
color: $primary-text-color;
opacity: 0.8;
position: absolute;
right: 4px;
text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color;
}
.status__video-player-spoiler {
display: none;
color: $primary-text-color;
left: 4px;
position: absolute;
text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color;
top: 4px;
z-index: 100;
&.status__video-player-spoiler--visible {
display: block;
}
}
.status__video-player-expand {
bottom: 4px;
z-index: 100;
}
.status__video-player-mute {
top: 4px;
z-index: 5;
}

View File

@@ -56,6 +56,12 @@ code {
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
.label_input {
@@ -395,6 +401,12 @@ code {
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
@media screen and (max-width: 740px) and (min-width: 441px) {
@@ -430,6 +442,12 @@ code {
strong {
color: $ui-secondary-color;
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
@media screen and (max-width: 740px) and (min-width: 441px) {
@@ -474,6 +492,12 @@ code {
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
}
}
@@ -506,6 +530,12 @@ code {
display: block;
margin-bottom: 5px;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
.fa {
font-weight: 400;
}

View File

@@ -8,6 +8,7 @@
@import 'basics';
@import 'containers';
@import 'lists';
@import 'modal';
@import 'footer';
@import 'compact_header';
@import 'landing_strip';

View File

@@ -12,6 +12,12 @@
strong,
a {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
a {
@@ -34,3 +40,72 @@
.memoriam-strip {
background: rgba($base-shadow-color, 0.7);
}
.moved-strip {
padding: 14px;
border-radius: 4px;
background: rgba(darken($ui-base-color, 7%), 0.8);
color: $ui-secondary-color;
font-weight: 400;
margin-bottom: 20px;
strong,
a {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
a {
color: inherit;
text-decoration: underline;
&.mention {
text-decoration: none;
span {
text-decoration: none;
}
&:focus,
&:hover,
&:active {
text-decoration: none;
span {
text-decoration: underline;
}
}
}
}
&__message {
margin-bottom: 15px;
.fa {
margin-right: 5px;
color: $ui-primary-color;
}
}
&__card {
.detailed-status__display-avatar {
position: relative;
cursor: pointer;
}
.detailed-status__display-name {
margin-bottom: 0;
text-decoration: none;
span {
color: $ui-highlight-color;
font-weight: 400;
}
}
}
}

View File

@@ -0,0 +1,43 @@
.metadata {
$meta-table-border: lighten($ui-base-color, 8%);
border-collapse: collapse;
padding: 0;
margin: 15px -15px -15px -15px;
border: 0 none;
border-top: 1px solid $meta-table-border;
border-bottom: 1px solid $meta-table-border;
td, th {
padding: 15px;
border: 0 none;
border-bottom: 1px solid $meta-table-border;
vertical-align: middle;
}
tr:last-child {
td, th {
border-bottom: 0 none;
}
}
td {
color: $ui-primary-color;
text-align: center;
width:100%;
padding-left: 0;
}
th {
padding-left: 15px;
font-weight: bold;
text-align: center;
width: 94px;
color: $ui-secondary-color;
background: darken($ui-base-color, 8%);
}
a {
color: $classic-highlight-color;
}
}

View File

@@ -0,0 +1,20 @@
.modal-layout {
background: $ui-base-color url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-lighter-color)}"/></svg>') repeat-x bottom fixed;
display: flex;
flex-direction: column;
height: 100vh;
padding: 0;
}
.modal-layout__mastodon {
display: flex;
flex: 1;
flex-direction: column;
justify-content: flex-end;
> * {
flex: 1;
max-height: 235px;
background: url('~images/elephant_ui_plane.svg') no-repeat left bottom / contain;
}
}

View File

@@ -8,7 +8,7 @@ body.rtl {
}
.compose-form .compose-form__buttons-wrapper .character-counter__wrapper {
margin-right: 0px;
margin-right: 0;
margin-left: 4px;
}

View File

@@ -93,16 +93,22 @@
.status__avatar {
position: absolute;
left: 14px;
top: 14px;
width: 48px;
height: 48px;
@include avatar-size(48px);
margin-left: -62px;
& > div {
width: 48px;
height: 48px;
@include avatar-size(48px);
}
img {
@include avatar-radius();
display: block;
border-radius: 4px;
@include avatar-radius();
}
}
@@ -116,6 +122,12 @@
strong {
font-weight: 500;
color: $ui-base-color;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
span {
@@ -167,6 +179,12 @@
strong {
font-weight: 500;
color: $ui-base-color;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
span {
@@ -177,11 +195,14 @@
}
.avatar {
width: 48px;
height: 48px;
@include avatar-size(48px);
img {
@include avatar-radius();
display: block;
border-radius: 4px;
@include avatar-radius();
}
}

View File

@@ -40,6 +40,12 @@
strong {
font-weight: 500;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
font-weight: 700;
}
}
}
&.inline-table > tbody > tr:nth-child(odd) > td,

View File

@@ -28,6 +28,9 @@ $ui-primary-color: $classic-primary-color !default; // Lighter
$ui-secondary-color: $classic-secondary-color !default; // Lightest
$ui-highlight-color: $classic-highlight-color !default; // Vibrant
// Language codes that uses CJK fonts
$cjk-langs: ja, ko, zh-CN, zh-HK, zh-TW;
// Avatar border size (8% default, 100% for rounded avatars)
$ui-avatar-border-size: 8%;

View File

@@ -15,6 +15,7 @@ pack:
- flavours/glitch/async/getting_started
- flavours/glitch/async/home_timeline
- flavours/glitch/async/notifications
mailer:
modal:
public: packs/public.js
settings:

View File

@@ -97,8 +97,8 @@ const rexstr = exp => '(?:' + exp.source + ')';
const DOCUMENT_START = /^/;
const DOCUMENT_END = /$/;
const ALLOWED_CHAR = unirex( // `c-printable` in the YAML 1.2 spec.
compat_mode ? '[\t\n\r\x20-\x7e\x85\xa0-\ufffd]' : '[\t\n\r\x20-\x7e\x85\xa0-\ud7ff\ue000-\ufffd\u{10000}-\u{10FFFF}]'
);
compat_mode ? '[\t\n\r\x20-\x7e\x85\xa0-\ufffd]' : '[\t\n\r\x20-\x7e\x85\xa0-\ud7ff\ue000-\ufffd\u{10000}-\u{10FFFF}]'
);
const WHITE_SPACE = /[ \t]/;
const LINE_BREAK = /\r?\n|\r|<br\s*\/?>/;
const INDICATOR = /[-?:,[\]{}&#*!|>'"%@`]/;

View File

@@ -40,7 +40,7 @@ export const urlRegex = (function() {
regexen.validSubdomain = regexSupplant(/(?:(?:#{validDomainChars}(?:[_-]|#{validDomainChars})*)?#{validDomainChars}\.)/);
regexen.validDomainName = regexSupplant(/(?:(?:#{validDomainChars}(?:-|#{validDomainChars})*)?#{validDomainChars}\.)/);
regexen.validGTLD = regexSupplant(RegExp(
'(?:(?:' +
'(?:(?:' +
'삼성|닷컴|닷넷|香格里拉|餐厅|食品|飞利浦|電訊盈科|集团|通販|购物|谷歌|诺基亚|联通|网络|网站|网店|网址|组织机构|移动|珠宝|点看|游戏|淡马锡|机构|書籍|时尚|新闻|政府|' +
'政务|手表|手机|我爱你|慈善|微博|广东|工行|家電|娱乐|天主教|大拿|大众汽车|在线|嘉里大酒店|嘉里|商标|商店|商城|公益|公司|八卦|健康|信息|佛山|企业|中文网|中信|世界|' +
'ポイント|ファッション|セール|ストア|コム|グーグル|クラウド|みんな|คอม|संगठन|नेट|कॉम|همراه|موقع|موبايلي|كوم|كاثوليك|عرب|شبكة|' +
@@ -131,7 +131,7 @@ export const urlRegex = (function() {
'academy|abudhabi|abogado|able|abc|abbvie|abbott|abb|abarth|aarp|aaa|onion' +
')(?=[^0-9a-zA-Z@]|$))'));
regexen.validCCTLD = regexSupplant(RegExp(
'(?:(?:' +
'(?:(?:' +
'한국|香港|澳門|新加坡|台灣|台湾|中國|中国|გე|ไทย|ලංකා|ഭാരതം|ಭಾರತ|భారత్|சிங்கப்பூர்|இலங்கை|இந்தியா|ଭାରତ|ભારત|ਭਾਰਤ|' +
'ভাৰত|ভারত|বাংলা|भारोत|भारतम्|भारत|ڀارت|پاکستان|مليسيا|مصر|قطر|فلسطين|عمان|عراق|سورية|سودان|تونس|' +
'بھارت|بارت|ایران|امارات|المغرب|السعودية|الجزائر|الاردن|հայ|қаз|укр|срб|рф|мон|мкд|ею|бел|бг|ελ|' +
@@ -169,7 +169,7 @@ export const urlRegex = (function() {
')' +
')' +
'\\)'
, 'i');
, 'i');
// Valid end-of-path chracters (so /foo. does not gobble the period).
// 1. Allow =&# for empty URL parameters and other URL-join artifacts
regexen.validUrlPathEndingChars = regexSupplant(/[^#{spaces_group}\(\)\?!\*';:=\,\.\$%\[\]#{pd}~&\|@]|(?:#{validUrlBalancedParens})/i);
@@ -191,6 +191,6 @@ export const urlRegex = (function() {
'(\\/#{validUrlPath}*)?' + // $5 URL Path
'(\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?' + // $6 Query String
')'
, 'gi');
, 'gi');
return regexen.validUrl;
}());

View File

@@ -15,6 +15,7 @@ pack:
- features/compose
- features/home_timeline
- features/notifications
mailer:
modal:
public: public.js
settings:

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="2048" height="1792" viewBox="0 0 2048 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1344 1504q0 13-9.5 22.5t-22.5 9.5h-960q-8 0-13.5-2t-9-7-5.5-8-3-11.5-1-11.5v-600h-192q-26 0-45-19t-19-45q0-24 15-41l320-384q19-22 49-22t49 22l320 384q15 17 15 41 0 26-19 45t-45 19h-192v384h576q16 0 25 11l160 192q7 10 7 21zm640-416q0 24-15 41l-320 384q-20 23-49 23t-49-23l-320-384q-15-17-15-41 0-26 19-45t45-19h192v-384h-576q-16 0-25-12l-160-192q-7-9-7-20 0-13 9.5-22.5t22.5-9.5h960q8 0 13.5 2t9 7 5.5 8 3 11.5 1 11.5v600h192q26 0 45 19t19 45z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 604 B

Some files were not shown because too many files have changed in this diff Show More