Mementomori.social is not your yet another instance with defaults. It is packed with small, but groundbreaking modifications. This page lists all of them.
On top of the regular Mastodon features like per-post visibility, content warnings and real time feed, Mementomori.social has the following features.
Mastodon Bird UI is something I've been designing since March, 2023. It's a new kind of modern Mastodon UI, inspired by Twitter UI in its good era. Yes, I know, the word bird and Twitter may be a turn-off for some, but I actually like what Twitter made to its UI in 2021 . The changes after that are not that good, so I took the UI in 2021 as an inspiration and created this:
The UI can be found on GitHub and its updates can be followed under hashtags #BirdUI and #MastodonBirdUI on Mastodon.
ronilaukkarinen/mastodon-bird-ui Repository on GitHub
Algorithmic home feed as an opt-in experiment. Same idea as Twitter's open sourced ranking pipeline (candidates, score, mix) but stripped to what a single instance actually needs. Chronological stays the default, nothing changes if you do not turn this on.
mementomori-social/mastodon #4 Pull request on GitHub
On Mementomori.social you get to choose from two major themes with variations:
Original Mastodon UI (Dark, Light and High contrast versions)
Mastodon Bird UI (Dark, Light, High contrast, Ultra accessible versions)
On our instance we have focused to accessibility with a special touch towards users with acromatopsia, vision impairment or age vision. Mastodon Bird UI (Ultra accessible) theme consists of features such as
Hashtags, links and mentions are in different colors
Contrast is even starker than in default High contrast themes, black background with white text
Font sizes are much larger throughout the site
The font size is even larger on mobile
All input boxes and modals have color to distinguish them from the background
All colors are tested with a contrast checker and with a real person so that they have sufficient contrast ratios
Default Mastodon has small link previews for URLs. I wanted to make them big and was inspired by this ongoing feature request . This is actually now in the Mastodon core, so our instance just follows the core card, but styles it to be more minimal.
--- app/javascript/mastodon/features/status/components/card.jsx
@@ -165,8 +165,8 @@ export default class Card extends PureComponent {
const description = (
<div className='status-card__content' lang={language}>
{title}
- {!(horizontal || compact) && <p className='status-card__description' title={card.get('description')}>{card.get('description')}</p>}
<span className='status-card__host'>{provider}</span>
+ {<p className='status-card__description' title={card.get('description')}>{card.get('description')}</p>}
</div>
);
@@ -231,7 +231,7 @@ export default class Card extends PureComponent {
return (
<div className={className} ref={this.setRef} onClick={revealed ? null : this.handleReveal} role={revealed ? 'button' : null}>
{embed}
- {!compact && description}
+ {description}
</div>
);
} else if (card.get('image')) {
A subtle change, suggested by ikkeT . See the post presenting it. See JavaScript changes here and Style changes here .
The default Mastodon Advanced interface allows 4 hashtags per column. We allow 15. There is a closed issue that is still an issue on 4.1.4.
--- app/javascript/mastodon/features/hashtag_timeline/components/column_settings.jsx
@@ -48,7 +48,7 @@ class ColumnSettings extends PureComponent {
// Prevent changes that add more than 4 tags, but allow removing
// tags that were already added before
- if ((value.length > 4) && !(value < oldValue)) {
+ if ((value.length > 15) && !(value < oldValue)) {
return;
}
--- app/models/tag_feed.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class TagFeed < PublicFeed
- LIMIT_PER_MODE = 4
+ LIMIT_PER_MODE = 15
# @param [Tag] tag
# @param [Account] account
Mementomori.social has a lot of custom emojis. You can also request your own by sending a post to @rolle . Good emoji source: Slackmojis .
Default Mastodon allows max. 4 options and 50 character limit per option. I have increased them so that posting polls is not too strict.
--- app/javascript/mastodon/features/compose/components/poll_form.jsx
@@ -164,7 +164,7 @@ class PollForm extends ImmutablePureComponent {
</ul>
<div className='poll__footer'>
- <button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
+ <button type='button' disabled={options.size >= 15} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
<select value={expiresIn} onChange={this.handleSelectDuration}>
--- app/validators/poll_validator.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
class PollValidator < ActiveModel::Validator
- MAX_OPTIONS = 4
- MAX_OPTION_CHARS = 50
+ MAX_OPTIONS = 15
+ MAX_OPTION_CHARS = 150
MAX_EXPIRATION = 1.month.freeze
MIN_EXPIRATION = 5.minutes.freeze
Mastodon's default is 500. We have 10000. Never have to think about the lenght of your posts any more.
--- app/javascript/mastodon/features/compose/components/compose_form.jsx
@@ -100,7 +100,7 @@ class ComposeForm extends ImmutablePureComponent {
const fulltext = this.getFulltextForCharacterCounting();
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
- return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia));
+ return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 10000 || (isOnlyWhitespace && !anyMedia));
};
handleSubmit = (e) => {
@@ -298,7 +298,7 @@ class ComposeForm extends ImmutablePureComponent {
</div>
<div className='character-counter__wrapper'>
- <CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} />
+ <CharacterCounter max={10000} text={this.getFulltextForCharacterCounting()} />
</div>
</div>
</div>
--- app/serializers/rest/instance_serializer.rb
@@ -11,7 +11,7 @@ class ContactSerializer < ActiveModel::Serializer
attributes :domain, :title, :version, :source_url, :description,
:usage, :thumbnail, :languages, :configuration,
- :registrations
+ :registrations, :max_toot_chars
has_one :contact, serializer: ContactSerializer
has_many :rules, serializer: REST::RuleSerializer
@@ -89,6 +89,10 @@ def registrations
}
end
+ def max_toot_chars
+ 10_000
+ end
+
private
def registrations_enabled?
View full diff on GitHub
The Vanilla Mastodon doesn't show these amounts and will likely never show them natively as per this comment . However as an OCD person the metrics matter so on Mementomori.social you'll see full amount of comments. (Related issue on Mastodon )
Metrics show up on Explore, Bookmarks and Favourites from 31st of July, 2023 . Comment count is accurate everywhere.
Please note, currently this is reversed to default due to unreliable method.
--- app/javascript/mastodon/components/status_action_bar.jsx
@@ -361,9 +361,9 @@ class StatusActionBar extends ImmutablePureComponent {
return (
<div className='status__action-bar'>
- <IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} obfuscateCount />
- <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
- <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
+ <IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
+ <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
+ <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
{filterButton}
--- app/javascript/mastodon/features/bookmarked_statuses/index.jsx
@@ -98,6 +98,7 @@ class Bookmarks extends ImmutablePureComponent {
onLoadMore={this.handleLoadMore}
emptyMessage={emptyMessage}
bindToDocument={!multiColumn}
+ withCounters
/>
<Helmet>
--- app/javascript/mastodon/features/favourited_statuses/index.jsx
@@ -98,6 +98,7 @@ class Favourites extends ImmutablePureComponent {
onLoadMore={this.handleLoadMore}
emptyMessage={emptyMessage}
bindToDocument={!multiColumn}
+ withCounters
/>
<Helmet>
--- app/javascript/mastodon/features/pinned_statuses/index.jsx
@@ -57,6 +57,7 @@ class PinnedStatuses extends ImmutablePureComponent {
scrollKey='pinned_statuses'
hasMore={hasMore}
bindToDocument={!multiColumn}
+ withCounters
/>
<Helmet>
View full diff on GitHub
--- app/javascript/mastodon/components/animated_number.tsx
@@ -12,7 +12,7 @@ const obfuscatedCount = (count: number) => {
} else if (count <= 1) {
return count;
} else {
- return '1+';
+ return count;
}
};
By default Mastodon searches only for your own posts and the ones you have answered to, if that. Search provided by Elasticsearch. On Mementomori.social you can search all posts the Mastodon instance is aware of, from the users who want to be found ("Include public posts in search results" enabled on settings). This is actually now in the Mastodon core, so our instance just follows the core feature.
VyrCossont/mastodon #8 Pull request on GitHub
For posts other than your language (set in profile) a "Translate" link is shown, by pressing it you can see accurate translation provided by DeepL .
By default Mastodon shows 100 posts on the Explore tab. We show 500.
--- app/models/trends/statuses.rb
@@ -3,7 +3,7 @@
class Trends::Statuses < Trends::Base
PREFIX = 'trending_statuses'
- BATCH_SIZE = 100
+ BATCH_SIZE = 500
self.default_options = {
threshold: 5,
Let it snow! ❄️ See update .
--- app/javascript/mastodon/common.js
@@ -10,6 +10,115 @@ export function start() {
}
}
+function animate(ctx, snowflakes, canvas, maxFlakes) {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // Add new snowflake if we haven't reached the maximum
+ if (snowflakes.length < maxFlakes && Math.random() < 0.05) { // 5% chance each frame to add a new flake
+ snowflakes.push({
+ x: Math.random() * canvas.width,
+ y: 0, // Start from top
+ radius: Math.random() * 7 + 3,
+ speed: Math.random() * 0.5 + 0.3,
+ opacity: Math.random() * 0.6 + 0.4
+ });
+ }
+
+ snowflakes.forEach(flake => {
+ // Draw snowflake shape
+ ctx.save();
+ ctx.beginPath();
+ for (let i = 0; i < 6; i++) {
+ ctx.moveTo(flake.x, flake.y);
+ ctx.lineTo(
+ flake.x + Math.cos(Math.PI * 2 * i / 6) * flake.radius,
+ flake.y + Math.sin(Math.PI * 2 * i / 6) * flake.radius
+ );
+ }
+ ctx.strokeStyle = `rgba(255, 255, 255, ${flake.opacity})`;
+ ctx.lineWidth = 1.5;
+ ctx.stroke();
+ ctx.restore();
+
+ // Update position with gentler movement
+ flake.x += Math.sin(flake.y / 50) * 0.3;
+ flake.y += flake.speed * 0.5;
+
+ if (flake.y > canvas.height) {
View full diff on GitHub
--- app/services/fetch_link_card_service.rb
@@ -57,7 +57,11 @@ def html
headers = {
'Accept' => 'text/html',
'Accept-Language' => "#{I18n.default_locale}, *;q=0.5",
- 'User-Agent' => "#{Mastodon::Version.user_agent} Bot",
+ 'User-Agent' => if @url.match?(/\b(youtube\.com|youtu\.be|m\.youtube\.com)\b/)
+ "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discord.com)"
+ else
+ "#{Mastodon::Version.user_agent} Bot"
+ end
}
@html = Request.new(:get, @url).add_headers(headers).perform do |res|
In the core version, only www.youtube.com previews work. On mementomori.social, all YouTube link variations generate a preview.
Vanilla Mastodon doesn't have a feature for this, gifs and videos are not autoplaying - especially for guests.
--- app/models/user_settings.rb
@@ -35,7 +35,7 @@ class KeyError < Error; end
setting :reduce_motion, default: false
setting :expand_content_warnings, default: false
setting :display_media, default: 'default', in: %w(default show_all hide_all)
- setting :auto_play, default: false
+ setting :auto_play, default: true
setting :emoji_style, default: 'auto', in: %w(auto native twemoji)
end
--- config/settings.yml
@@ -33,6 +33,8 @@ defaults: &defaults
backups_retention_period: 7
captcha_enabled: false
allow_referrer_origin: false
+ auto_play_gif: true
+ reduce_motion: false
development:
<<: *defaults
--- app/javascript/mastodon/components/gif.tsx
@@ -1,12 +1,12 @@
import { useHovering } from 'mastodon/hooks/useHovering';
-import { autoPlayGif } from 'mastodon/initial_state';
+import { autoPlayGif, reduceMotion } from 'mastodon/initial_state';
export const GIF: React.FC<{
src: string;
staticSrc: string;
className: string;
animate?: boolean;
-}> = ({ src, staticSrc, className, animate = autoPlayGif }) => {
+}> = ({ src, staticSrc, className, animate = autoPlayGif || !reduceMotion }) => {
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
return (
--- app/javascript/mastodon/components/media_gallery.jsx
@@ -15,7 +15,7 @@ import { Blurhash } from 'mastodon/components/blurhash';
import { SpoilerButton } from 'mastodon/components/spoiler_button';
import { formatTime } from 'mastodon/features/video';
-import { autoPlayGif, displayMedia, useBlurhash } from '../initial_state';
+import { autoPlayGif, displayMedia, reduceMotion, useBlurhash } from '../initial_state';
class Item extends PureComponent {
@@ -56,7 +56,7 @@ class Item extends PureComponent {
};
getAutoPlay() {
- return this.props.autoplay || autoPlayGif;
+ return this.props.autoplay || autoPlayGif || !reduceMotion;
}
hoverToPlay () {
--- app/javascript/mastodon/features/account_gallery/components/media_item.tsx
@@ -9,7 +9,7 @@ import { AltTextBadge } from 'mastodon/components/alt_text_badge';
import { Blurhash } from 'mastodon/components/blurhash';
import { Icon } from 'mastodon/components/icon';
import { formatTime } from 'mastodon/features/video';
View full diff on GitHub