Most of #137 done.
- Use FastClick to make everything feel more responsive
- Use transforms for animations to make them silky smooth
- Style the drawer the same as the header to keep things simple
- Revert to fixed composer, but allow it to be minimised
- Add a separate notifications page for mobile so it’s easy to go back
- Add indicator to the menu button when there are unread notifications
- Close the drawer when navigating away
- Make dropdowns/modals scrollable
- Many other mobile tweaks and bug fixes
Didn’t take much care to keep CSS clean, due to #103
Also disallow the first post in a discussion to be deleted or hidden
(thus preventing discussions with zero posts)
closesflarum/core#90closesflarum/core#92
Only preloading data for basic requests w/o query params, at least for
the moment - if we have to preload for something like
/?q=test&sort=newest, we end up having to duplicate a whole lot of
logic between JS/PHP.
Ditched the idea of having language packs as extensions. Reasoning:
1. Because we use machine keys for translations (rather than English
keys), extensions need to be able to define default translations. If
English translations are to be included in extensions and not in a
language pack extension, then it doesn’t make sense to have other
languages as language pack extensions. Inconsistency → complexity.
2. Translations should maintain version parity with their respective
extensions. There’s no way to do this if extension translations are
external to the extension.
Instead, localisation will be a core effort, as well as a per-extension
effort. Translators will be encouraged to send PRs to core + extensions.
In core, each locale has a directory containing three files:
- translations.yml
- config.js: contains pluralisation logic for the JS app, as well as
moment.js localisation if necessary
- config.php: contains pluralisation logic for the PHP app
Extensions can use the Flarum\Extend\Locale extender to add/override
translations/config to a locale.
Asset compilation has been completely refactored with a better
architecture. Translations + config.js are compiled and cached for the
currently active locale.
It works but it’s not the most pretty thing in the world. @franzliedke
Would be great if you could take a look at the whole formatting API and
work your magic on it sometime… my brain is fried!
They can be out of order in the payload due to relationship loading,
e.g. post #1 includes post #14 that has mentioned it, therefore #14
will be the first post in the payload. The new post stream doesn’t take
kindly to out of order posts.
Originally the user activity feed was implemented using UNIONs. I was
looking at make an API to add activity “sources”, or extra UNION
queries (select from posts, mentions, etc.) but quickly realised that
this is too slow and there’s no way to make it scale.
So I’ve implemented an API which is very similar to how notifications
work (see previous commit). The `activity` table is an aggregation of
stuff that happens, and it’s kept in sync by an ActivitySyncer which is
used whenever a post it created/edited/deleted, a user is
mentioned/unmentioned, etc.
Again, the API is very simple (see Core\Activity\PostedActivity +
Core\Handlers\Events\UserActivitySyncer)
It turns out that the idea of “sending” a notification is flawed. (What
happens if the notification subject is deleted shortly after? The
notified user would end up with a dud notification which would be
confusing. What about if a post is edited to mention an extra user? If
you sent out notifications, the users who’ve already been mentioned
would get a duplicate notification.)
Instead, I’ve introduced the idea of notification “syncing”. Whenever a
change is made to a piece of data (e.g. a post is created, edited, or
deleted), you make a common notification and “sync” it to a set of
users. The users who’ve received this notification before won’t get it
again. It will be sent out to new users, and hidden from users who’ve
received it before but are no longer recipients (e.g. users who’ve been
“unmentioned” in a post).
To keep track of this, we use the existing notifications database
table, with an added `is_deleted` column. The syncing/diffing is
handled all behind the scenes; the API is extremely simple (see
Core\Notifications\DiscussionRenamedNotification +
Core\Events\Handlers\DiscussionRenamedNotifier)