Add absolute time setting
This commit is contained in:
parent
498cef91c6
commit
d73a197f61
14 changed files with 95 additions and 9 deletions
|
@ -112,6 +112,7 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
:setting_disable_clear_all_notifications,
|
||||
:setting_disable_account_delete,
|
||||
:setting_prohibited_words,
|
||||
:setting_disable_relative_time,
|
||||
setting_prohibited_visibilities: [],
|
||||
notification_emails: %i(follow follow_request reblog favourite emoji_reaction status_reference mention digest report pending_account trending_tag),
|
||||
interactions: %i(must_be_follower must_be_following must_be_following_dm must_be_dm_to_send_email must_be_following_reference)
|
||||
|
|
68
app/javascript/mastodon/components/absolute_timestamp.js
Normal file
68
app/javascript/mastodon/components/absolute_timestamp.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
import React from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const dateFormatOptions = {
|
||||
hour12: false,
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
};
|
||||
|
||||
const shortDateFormatOptions = {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
};
|
||||
|
||||
const shortTimeFormatOptions = {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
};
|
||||
|
||||
const DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
export const timeString = (intl, date, year) => {
|
||||
const delta = intl.now() - date.getTime();
|
||||
|
||||
let absoluteTime;
|
||||
|
||||
if (Math.abs(delta) < DAY) {
|
||||
absoluteTime = intl.formatDate(date, shortTimeFormatOptions);
|
||||
} else if (date.getFullYear() === year) {
|
||||
absoluteTime = intl.formatDate(date, shortDateFormatOptions);
|
||||
} else {
|
||||
absoluteTime = intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' });
|
||||
}
|
||||
|
||||
return absoluteTime;
|
||||
};
|
||||
|
||||
export default @injectIntl
|
||||
class AbsoluteTimestamp extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
timestamp: PropTypes.string.isRequired,
|
||||
year: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
year: (new Date()).getFullYear(),
|
||||
};
|
||||
|
||||
render () {
|
||||
const { timestamp, intl, year } = this.props;
|
||||
|
||||
const date = new Date(timestamp);
|
||||
const absoluteTime = timeString(intl, date, year);
|
||||
|
||||
return (
|
||||
<time dateTime={timestamp} title={intl.formatDate(date, dateFormatOptions)}>
|
||||
{absoluteTime}
|
||||
</time>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
|
|||
import Avatar from './avatar';
|
||||
import AvatarOverlay from './avatar_overlay';
|
||||
import AvatarComposite from './avatar_composite';
|
||||
import AbsoluteTimestamp from './absolute_timestamp';
|
||||
import RelativeTimestamp from './relative_timestamp';
|
||||
import DisplayName from './display_name';
|
||||
import StatusContent from './status_content';
|
||||
|
@ -19,7 +20,7 @@ import classNames from 'classnames';
|
|||
import Icon from 'mastodon/components/icon';
|
||||
import EmojiReactionsBar from 'mastodon/components/emoji_reactions_bar';
|
||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||
import { displayMedia, enableReaction, compactReaction, show_reply_tree_button, enableStatusReference } from 'mastodon/initial_state';
|
||||
import { displayMedia, enableReaction, compactReaction, show_reply_tree_button, enableStatusReference, disableRelativeTime } from 'mastodon/initial_state';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
// We use the component (and not the container) since we do not want
|
||||
|
@ -755,7 +756,7 @@ class Status extends ImmutablePureComponent {
|
|||
{status.get('expires_at') && <span className='status__expiration-time'><time dateTime={expires_at} title={intl.formatDate(expires_date, dateFormatOptions)}><i className="fa fa-clock-o" aria-hidden="true"></i></time></span>}
|
||||
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
|
||||
{threadMark}
|
||||
<RelativeTimestamp timestamp={status.get('created_at')} />
|
||||
{disableRelativeTime ? <AbsoluteTimestamp timestamp={status.get('created_at')} /> : <RelativeTimestamp timestamp={status.get('created_at')} /> }
|
||||
</a>
|
||||
<span className='status__visibility-icon'>{visibilityLink}</span>
|
||||
|
||||
|
|
|
@ -9,9 +9,10 @@ import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
|
|||
import AvatarComposite from 'mastodon/components/avatar_composite';
|
||||
import Permalink from 'mastodon/components/permalink';
|
||||
import IconButton from 'mastodon/components/icon_button';
|
||||
import AbsoluteTimestamp from 'mastodon/components/absolute_timestamp';
|
||||
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
import { autoPlayGif } from 'mastodon/initial_state';
|
||||
import { autoPlayGif, disableRelativeTime } from 'mastodon/initial_state';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -153,7 +154,8 @@ class Conversation extends ImmutablePureComponent {
|
|||
<div className='conversation__content'>
|
||||
<div className='conversation__content__info'>
|
||||
<div className='conversation__content__relative-time'>
|
||||
{unread && <span className='conversation__unread' />} <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
|
||||
{unread && <span className='conversation__unread' />}
|
||||
{disableRelativeTime ? <AbsoluteTimestamp timestamp={lastStatus.get('created_at')} /> : <RelativeTimestamp timestamp={lastStatus.get('created_at')} /> }
|
||||
</div>
|
||||
|
||||
<div className='conversation__content__names' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|||
import Button from '../../../components/button';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import AbsoluteTimestamp from '../../../components/absolute_timestamp';
|
||||
import RelativeTimestamp from '../../../components/relative_timestamp';
|
||||
import DisplayName from '../../../components/display_name';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
@ -14,6 +15,7 @@ import AttachmentList from 'mastodon/components/attachment_list';
|
|||
import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
|
||||
import classNames from 'classnames';
|
||||
import { changeBoostPrivacy } from 'mastodon/actions/boosts';
|
||||
import { disableRelativeTime } from 'mastodon/initial_state';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||
|
@ -109,7 +111,9 @@ class BoostModal extends ImmutablePureComponent {
|
|||
<div className={classNames('status', `status-${status.get('visibility')}`, 'light')}>
|
||||
<div className='boost-modal__status-header'>
|
||||
<div className='boost-modal__status-time'>
|
||||
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
|
||||
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
|
||||
{disableRelativeTime ? <AbsoluteTimestamp timestamp={status.get('created_at')} /> : <RelativeTimestamp timestamp={status.get('created_at')} /> }
|
||||
</a>
|
||||
</div>
|
||||
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import AbsoluteTimestamp from '../../../components/absolute_timestamp';
|
||||
import RelativeTimestamp from '../../../components/relative_timestamp';
|
||||
import DisplayName from '../../../components/display_name';
|
||||
|
||||
|
@ -12,7 +13,7 @@ import { supportsPassiveEvents } from 'detect-passive-events';
|
|||
import { EmojiPicker as EmojiPickerAsync } from '../util/async-components';
|
||||
import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji';
|
||||
import { assetHost } from 'mastodon/utils/config';
|
||||
import { pickerEmojiSize } from 'mastodon/initial_state';
|
||||
import { pickerEmojiSize, disableRelativeTime } from 'mastodon/initial_state';
|
||||
|
||||
const messages = defineMessages({
|
||||
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
|
||||
|
@ -233,7 +234,7 @@ export default class ReactionModal extends ImmutablePureComponent {
|
|||
<div className='boost-modal__status-header'>
|
||||
<div className='boost-modal__status-time'>
|
||||
<a href={this.props.status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
|
||||
<RelativeTimestamp timestamp={this.props.status.get('created_at')} />
|
||||
{disableRelativeTime ? <AbsoluteTimestamp timestamp={this.props.status.get('created_at')} /> : <RelativeTimestamp timestamp={this.props.status.get('created_at')} /> }
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ export const disableBlock = getMeta('disable_block');
|
|||
export const disableDomainBlock = getMeta('disable_domain_block');
|
||||
export const disableClearAllNotifications = getMeta('disable_clear_all_notifications');
|
||||
export const disableAccountDelete = getMeta('disable_account_delete');
|
||||
export const disableRelativeTime = getMeta('disable_relative_time');
|
||||
|
||||
export const maxChars = initialState?.max_toot_chars ?? 500;
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ class UserSettingsDecorator
|
|||
disable_domain_block
|
||||
disable_clear_all_notifications
|
||||
disable_account_delete
|
||||
disable_relative_time
|
||||
).freeze
|
||||
|
||||
STRING_KEYS = %w(
|
||||
|
|
|
@ -145,6 +145,7 @@ class User < ApplicationRecord
|
|||
:show_reload_button, :default_column_width,
|
||||
:disable_post, :disable_reactions, :disable_follow, :disable_unfollow, :disable_block, :disable_domain_block, :disable_clear_all_notifications, :disable_account_delete,
|
||||
:prohibited_visibilities, :prohibited_words,
|
||||
:disable_relative_time,
|
||||
|
||||
to: :settings, prefix: :setting, allow_nil: false
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:disable_domain_block] = object.current_account.user.setting_disable_domain_block
|
||||
store[:disable_clear_all_notifications] = object.current_account.user.setting_disable_clear_all_notifications
|
||||
store[:disable_account_delete] = object.current_account.user.setting_disable_account_delete
|
||||
store[:disable_relative_time] = object.current_account.user.setting_disable_relative_time
|
||||
else
|
||||
store[:auto_play_gif] = Setting.auto_play_gif
|
||||
store[:display_media] = Setting.display_media
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
.fields-group
|
||||
= f.input :setting_show_reload_button, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||
|
||||
-# .fields-group
|
||||
-# = f.input :setting_show_target, as: :boolean, wrapper: :with_label
|
||||
.fields-group
|
||||
= f.input :setting_disable_relative_time, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||
|
||||
%h4= t 'preferences.public_timelines'
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ en:
|
|||
setting_disable_joke_appearance: Disable April Fools' Day and other joke functions
|
||||
setting_disable_post: Restricts you from accidentally posting
|
||||
setting_disable_reactions: Restrict reactions for favorites, boosts ,emoji reactions and polls
|
||||
setting_disable_relative_time:
|
||||
setting_disable_unfollow: Restricts you from accidentally unfollowing
|
||||
setting_display_media_default: Hide media marked as sensitive
|
||||
setting_display_media_hide_all: Always hide media
|
||||
|
@ -261,6 +262,7 @@ en:
|
|||
setting_disable_joke_appearance: Disable joke feature to change appearance
|
||||
setting_disable_post: Disable post
|
||||
setting_disable_reactions: Disable reactions
|
||||
setting_disable_relative_time: Disable relative time on posts
|
||||
setting_disable_swiping: Disable swiping motions
|
||||
setting_disable_unfollow: Disable unfollow
|
||||
setting_display_media: Media display
|
||||
|
|
|
@ -74,6 +74,7 @@ ja:
|
|||
setting_disable_joke_appearance: エイプリルフール等のジョーク機能を無効にします
|
||||
setting_disable_post: 誤って投稿することを防ぎます
|
||||
setting_disable_reactions: 誤ってお気に入り・ブースト・絵文字リアクション・投票することを防ぎます
|
||||
setting_disable_relative_time: 投稿日時を相対表示する機能を無効にし、日時をそのまま表示します
|
||||
setting_disable_unfollow: 誤ってフォロー解除することを防ぎます
|
||||
setting_display_media_default: 閲覧注意としてマークされたメディアは隠す
|
||||
setting_display_media_hide_all: メディアを常に隠す
|
||||
|
@ -257,6 +258,7 @@ ja:
|
|||
setting_disable_joke_appearance: ジョーク機能による見た目の変更を無効にする
|
||||
setting_disable_post: 投稿を無効にする
|
||||
setting_disable_reactions: リアクションを無効にする
|
||||
setting_disable_relative_time: 投稿の相対日時を無効にする
|
||||
setting_disable_swiping: スワイプでの切り替えを無効にする
|
||||
setting_disable_unfollow: フォロー解除を無効にする
|
||||
setting_display_media: メディアの表示
|
||||
|
|
|
@ -128,6 +128,7 @@ defaults: &defaults
|
|||
disable_account_delete: false
|
||||
prohibited_visibilities: []
|
||||
prohibited_words: ''
|
||||
disable_relative_time: false
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
|
|
Loading…
Reference in a new issue