From d8fbd74c47de3148d6693b5cb15e7e868f72448e Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 28 Aug 2018 12:01:04 +0200 Subject: [Glitch] Add aria-label to column regions Port 66dbb59aa16981643e3bfa3f94d441bc3166eab3 to glitch-soc --- app/javascript/flavours/glitch/components/column.js | 5 +++-- .../flavours/glitch/features/community_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/direct_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/drawer/index.js | 8 +++++++- .../flavours/glitch/features/favourited_statuses/index.js | 2 +- app/javascript/flavours/glitch/features/getting_started/index.js | 3 ++- app/javascript/flavours/glitch/features/hashtag_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/home_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/list_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/notifications/index.js | 1 + app/javascript/flavours/glitch/features/public_timeline/index.js | 2 +- .../glitch/features/standalone/community_timeline/index.js | 2 +- .../flavours/glitch/features/standalone/public_timeline/index.js | 2 +- app/javascript/flavours/glitch/features/status/index.js | 3 ++- 14 files changed, 24 insertions(+), 14 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/components/column.js b/app/javascript/flavours/glitch/components/column.js index 57c4c7a40..dc87818a5 100644 --- a/app/javascript/flavours/glitch/components/column.js +++ b/app/javascript/flavours/glitch/components/column.js @@ -9,6 +9,7 @@ export default class Column extends React.PureComponent { children: PropTypes.node, extraClasses: PropTypes.string, name: PropTypes.string, + label: PropTypes.string, }; scrollTop () { @@ -42,10 +43,10 @@ export default class Column extends React.PureComponent { } render () { - const { children, extraClasses, name } = this.props; + const { children, extraClasses, name, label } = this.props; return ( -
+
{children}
); diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js index e5006b4d3..5bd9d037c 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.js +++ b/app/javascript/flavours/glitch/features/community_timeline/index.js @@ -80,7 +80,7 @@ export default class CommunityTimeline extends React.PureComponent { const pinned = !!columnId; return ( - + + ({ account: state.getIn(['accounts', me]), @@ -92,7 +98,7 @@ class Drawer extends React.Component { // The result. return ( -
+
{multiColumn ? ( + { @@ -148,7 +149,7 @@ export default class GettingStarted extends ImmutablePureComponent { ]); return ( - +
diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index b3e8b7a6e..f710456d5 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -92,7 +92,7 @@ export default class HashtagTimeline extends React.PureComponent { const pinned = !!columnId; return ( - + + + + + + { @@ -387,7 +388,7 @@ export default class Status extends ImmutablePureComponent { }; return ( - + Date: Tue, 28 Aug 2018 12:03:49 +0200 Subject: [Glitch] Fix off-by-one error in aria-posinset Port 885711afb97b772f7c970ed16e17de799a74c923 to glitch-soc --- .../flavours/glitch/components/intersection_observer_article.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/components/intersection_observer_article.js b/app/javascript/flavours/glitch/components/intersection_observer_article.js index f7f6b0a53..6eeca5598 100644 --- a/app/javascript/flavours/glitch/components/intersection_observer_article.js +++ b/app/javascript/flavours/glitch/components/intersection_observer_article.js @@ -107,7 +107,7 @@ export default class IntersectionObserverArticle extends ImmutablePureComponent return (
+
{children && React.cloneElement(children, { hidden: false })}
); -- cgit From 530da545a532d7e3cbcc5168e97410bd86d92117 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 28 Aug 2018 12:10:40 +0200 Subject: [Glitch] Give focused status a sensible aria-label for screen readers Port 248df68c36a2f1ffd9c214afe7d1b0c62b4a5f27 to glitch-soc --- .../flavours/glitch/components/status.js | 29 +++++++++++++++++++++- .../flavours/glitch/features/status/index.js | 3 ++- 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index 9f47abfef..13ff781fe 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -7,7 +7,7 @@ import StatusIcons from './status_icons'; import StatusContent from './status_content'; import StatusActionBar from './status_action_bar'; import AttachmentList from './attachment_list'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { MediaGallery, Video } from 'flavours/glitch/util/async-components'; import { HotKeys } from 'react-hotkeys'; @@ -19,6 +19,24 @@ import { autoUnfoldCW } from 'flavours/glitch/util/content_warning'; // to use the progress bar to show download progress import Bundle from '../features/ui/components/bundle'; +export const textForScreenReader = (intl, status, rebloggedByText = false, expanded = false) => { + const displayName = status.getIn(['account', 'display_name']); + + const values = [ + displayName.length === 0 ? status.getIn(['account', 'acct']).split('@')[0] : displayName, + status.get('spoiler_text') && !expanded ? status.get('spoiler_text') : status.get('search_index').slice(status.get('spoiler_text').length), + intl.formatDate(status.get('created_at'), { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }), + status.getIn(['account', 'acct']), + ]; + + if (rebloggedByText) { + values.push(rebloggedByText); + } + + return values.join(', '); +}; + +@injectIntl export default class Status extends ImmutablePureComponent { static contextTypes = { @@ -52,6 +70,7 @@ export default class Status extends ImmutablePureComponent { getScrollPosition: PropTypes.func, updateScrollBottom: PropTypes.func, expanded: PropTypes.bool, + intl: PropTypes.object.isRequired, }; state = { @@ -337,6 +356,7 @@ export default class Status extends ImmutablePureComponent { } = this; const { router } = this.context; const { + intl, status, account, settings, @@ -473,6 +493,12 @@ export default class Status extends ImmutablePureComponent { selectorAttribs[`data-${notifKind}-by`] = `@${account.get('acct')}`; } + let rebloggedByText; + + if (prepend === 'reblog') { + rebloggedByText = intl.formatMessage({ id: 'status.reblogged_by', defaultMessage: '{name} boosted' }, { name: account.get('acct') }); + } + const handlers = { reply: this.handleHotkeyReply, favourite: this.handleHotkeyFavourite, @@ -501,6 +527,7 @@ export default class Status extends ImmutablePureComponent { ref={handleRef} tabIndex='0' data-featured={featured ? 'true' : null} + aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))} >
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 565b4b725..0697b49ad 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -39,6 +39,7 @@ import { HotKeys } from 'react-hotkeys'; import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state'; import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen'; import { autoUnfoldCW } from 'flavours/glitch/util/content_warning'; +import { textForScreenReader } from 'flavours/glitch/components/status'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -401,7 +402,7 @@ export default class Status extends ImmutablePureComponent { {ancestors} -
+
Date: Thu, 6 Sep 2018 22:00:25 +0200 Subject: Fix dropdown arrow position --- app/javascript/flavours/glitch/styles/components/index.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 834839632..1419888fa 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -415,14 +415,14 @@ &.top { bottom: -5px; - margin-left: -13px; + margin-left: -7px; border-width: 5px 7px 0; border-top-color: $ui-secondary-color; } &.bottom { top: -5px; - margin-left: -13px; + margin-left: -7px; border-width: 0 7px 5px; border-bottom-color: $ui-secondary-color; } -- cgit From f4ca3262f287b9b18114201d6b68161fdf324e19 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 18:33:49 +0200 Subject: [Glitch] Audio.prototype.seek is undefined Port f08e6e9ab54a72cc20b33b270789c245b5cfde39 to glitch-soc --- app/javascript/flavours/glitch/middleware/sounds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/middleware/sounds.js b/app/javascript/flavours/glitch/middleware/sounds.js index 3d1e3eaba..9f1bc02b9 100644 --- a/app/javascript/flavours/glitch/middleware/sounds.js +++ b/app/javascript/flavours/glitch/middleware/sounds.js @@ -15,7 +15,7 @@ const play = audio => { if (typeof audio.fastSeek === 'function') { audio.fastSeek(0); } else { - audio.seek(0); + audio.currentTime = 0; } } -- cgit From 711826cb37604df98d8e27c3415855ad298d49d9 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Wed, 5 Sep 2018 15:20:40 +0200 Subject: Accurately count deleted unread notifications --- .../flavours/glitch/reducers/notifications.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index dc820b476..b712aaa67 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -25,6 +25,7 @@ const initialState = ImmutableMap({ hasMore: true, top: true, unread: 0, + lastReadId: '0', isLoading: false, cleaningMode: false, // notification removal mark of new notifs loaded whilst cleaningMode is true. @@ -42,7 +43,9 @@ const notificationToMap = (state, notification) => ImmutableMap({ const normalizeNotification = (state, notification) => { const top = state.get('top'); - if (!top) { + if (top) { + state = state.set('lastReadId', notification.id); + } else { state = state.update('unread', unread => unread + 1); } @@ -56,6 +59,8 @@ const normalizeNotification = (state, notification) => { }; const expandNormalizedNotifications = (state, notifications, next) => { + const top = state.get('top'); + const lastReadId = state.get('lastReadId'); let items = ImmutableList(); notifications.forEach((n, i) => { @@ -77,6 +82,14 @@ const expandNormalizedNotifications = (state, notifications, next) => { }); } + if (top) { + if (!items.isEmpty()) { + mutable.update('lastReadId', id => compareId(id, items.first().get('id')) > 0 ? id : items.first().get('id')); + } + } else { + mutable.update('unread', unread => unread + items.filter(item => compareId(item.get('id'), lastReadId) > 0).size); + } + if (!next) { mutable.set('hasMore', true); } @@ -92,12 +105,19 @@ const filterNotifications = (state, relationship) => { const updateTop = (state, top) => { if (top) { state = state.set('unread', 0); + const lastNotification = state.get('items').find(item => item !== null); + state = state.set('lastReadId', lastNotification ? lastNotification.get('id') : '0'); } return state.set('top', top); }; const deleteByStatus = (state, statusId) => { + if (!state.get('top')) { + const lastReadId = state.get('lastReadId'); + const deletedUnread = state.get('items').filter(item => item !== null && item.get('status') === statusId && compareId(item.get('id'), lastReadId) > 0); + state = state.update('unread', unread => unread - deletedUnread.size); + } return state.update('items', list => list.filterNot(item => item !== null && item.get('status') === statusId)); }; -- cgit From c8875b4d8aa00abd0ef432c025d479a8990202f1 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 15:47:13 +0200 Subject: Keep track of unread notifications when the notification column isn't mounted --- .../flavours/glitch/actions/notifications.js | 15 +++++++++++++ .../glitch/features/notifications/index.js | 24 ++++++++++++++++++++ .../flavours/glitch/reducers/notifications.js | 26 ++++++++++++++++------ 3 files changed, 58 insertions(+), 7 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index e88eda78f..ee148e4ef 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -25,6 +25,9 @@ export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL'; export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; +export const NOTIFICATIONS_MOUNT = 'NOTIFICATIONS_MOUNT'; +export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT'; + defineMessages({ mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, }); @@ -216,3 +219,15 @@ export function deleteMarkedNotificationsSuccess() { type: NOTIFICATIONS_DELETE_MARKED_SUCCESS, }; }; + +export function mountNotifications() { + return { + type: NOTIFICATIONS_MOUNT, + }; +}; + +export function unmountNotifications() { + return { + type: NOTIFICATIONS_UNMOUNT, + }; +}; diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 266d6807d..ee711bd8a 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -8,6 +8,8 @@ import { enterNotificationClearingMode, expandNotifications, scrollTopNotifications, + mountNotifications, + unmountNotifications, } from 'flavours/glitch/actions/notifications'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import NotificationContainer from './containers/notification_container'; @@ -42,6 +44,12 @@ const mapDispatchToProps = dispatch => ({ onEnterCleaningMode(yes) { dispatch(enterNotificationClearingMode(yes)); }, + onMount() { + dispatch(mountNotifications()); + }, + onUnmount() { + dispatch(unmountNotifications()); + }, dispatch, }); @@ -62,6 +70,8 @@ export default class Notifications extends React.PureComponent { localSettings: ImmutablePropTypes.map, notifCleaningActive: PropTypes.bool, onEnterCleaningMode: PropTypes.func, + onMount: PropTypes.func, + onUnmount: PropTypes.func, }; static defaultProps = { @@ -126,6 +136,20 @@ export default class Notifications extends React.PureComponent { } } + componentDidMount () { + const { onMount } = this.props; + if (onMount) { + onMount(); + } + } + + componentWillUnmount () { + const { onUnmount } = this.props; + if (onUnmount) { + onUnmount(); + } + } + render () { const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore } = this.props; const pinned = !!columnId; diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index b712aaa67..9087e226c 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -1,4 +1,6 @@ import { + NOTIFICATIONS_MOUNT, + NOTIFICATIONS_UNMOUNT, NOTIFICATIONS_UPDATE, NOTIFICATIONS_EXPAND_SUCCESS, NOTIFICATIONS_EXPAND_REQUEST, @@ -24,6 +26,7 @@ const initialState = ImmutableMap({ items: ImmutableList(), hasMore: true, top: true, + mounted: 0, unread: 0, lastReadId: '0', isLoading: false, @@ -41,7 +44,7 @@ const notificationToMap = (state, notification) => ImmutableMap({ }); const normalizeNotification = (state, notification) => { - const top = state.get('top'); + const top = state.get('top') && state.get('mounted') > 0; if (top) { state = state.set('lastReadId', notification.id); @@ -59,7 +62,7 @@ const normalizeNotification = (state, notification) => { }; const expandNormalizedNotifications = (state, notifications, next) => { - const top = state.get('top'); + const top = state.get('top') && state.get('mounted') > 0; const lastReadId = state.get('lastReadId'); let items = ImmutableList(); @@ -102,18 +105,23 @@ const filterNotifications = (state, relationship) => { return state.update('items', list => list.filterNot(item => item !== null && item.get('account') === relationship.id)); }; +const clearUnread = (state) => { + state = state.set('unread', 0); + const lastNotification = state.get('items').find(item => item !== null); + return state.set('lastReadId', lastNotification ? lastNotification.get('id') : '0'); +} + const updateTop = (state, top) => { - if (top) { - state = state.set('unread', 0); - const lastNotification = state.get('items').find(item => item !== null); - state = state.set('lastReadId', lastNotification ? lastNotification.get('id') : '0'); + if (top && state.get('mounted') > 0) { + state = clearUnread(state); } return state.set('top', top); }; const deleteByStatus = (state, statusId) => { - if (!state.get('top')) { + const top = state.get('top') && state.get('mounted') > 0; + if (!top) { const lastReadId = state.get('lastReadId'); const deletedUnread = state.get('items').filter(item => item !== null && item.get('status') === statusId && compareId(item.get('id'), lastReadId) > 0); state = state.update('unread', unread => unread - deletedUnread.size); @@ -153,6 +161,10 @@ export default function notifications(state = initialState, action) { let st; switch(action.type) { + case NOTIFICATIONS_MOUNT: + return (state.get('top') ? clearUnread(state) : state).update('mounted', count => count + 1); + case NOTIFICATIONS_UNMOUNT: + return state.update('mounted', count => count - 1); case NOTIFICATIONS_EXPAND_REQUEST: case NOTIFICATIONS_DELETE_MARKED_REQUEST: return state.set('isLoading', true); -- cgit From d315f1dc02f15b55585a853ac19aefbe6983d87d Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 17:47:33 +0200 Subject: Count unread notifications when window loses focus --- .../flavours/glitch/actions/notifications.js | 9 ++++++ .../flavours/glitch/features/ui/index.js | 26 +++++++++++++++- .../flavours/glitch/reducers/notifications.js | 36 +++++++++++++++++++--- 3 files changed, 65 insertions(+), 6 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index ee148e4ef..fb84cd01e 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -28,6 +28,8 @@ export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; export const NOTIFICATIONS_MOUNT = 'NOTIFICATIONS_MOUNT'; export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT'; +export const NOTIFICATIONS_SET_VISIBILITY = 'NOTIFICATIONS_SET_VISIBILITY'; + defineMessages({ mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, }); @@ -231,3 +233,10 @@ export function unmountNotifications() { type: NOTIFICATIONS_UNMOUNT, }; }; + +export function notificationsSetVisibility(visibility) { + return { + type: NOTIFICATIONS_SET_VISIBILITY, + visibility: visibility, + }; +}; diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 1cff94321..c41436090 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -10,7 +10,7 @@ import { isMobile } from 'flavours/glitch/util/is_mobile'; import { debounce } from 'lodash'; import { uploadCompose, resetCompose } from 'flavours/glitch/actions/compose'; import { expandHomeTimeline } from 'flavours/glitch/actions/timelines'; -import { expandNotifications } from 'flavours/glitch/actions/notifications'; +import { expandNotifications, notificationsSetVisibility } from 'flavours/glitch/actions/notifications'; import { fetchFilters } from 'flavours/glitch/actions/filters'; import { clearHeight } from 'flavours/glitch/actions/height_cache'; import { WrappedSwitch, WrappedRoute } from 'flavours/glitch/util/react_router_helpers'; @@ -206,7 +206,27 @@ export default class UI extends React.Component { } } + handleVisibilityChange = () => { + const visibility = !document[this.visibilityHiddenProp]; + this.props.dispatch(notificationsSetVisibility(visibility)); + } + componentWillMount () { + if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support + this.visibilityHiddenProp = 'hidden'; + this.visibilityChange = 'visibilitychange'; + } else if (typeof document.msHidden !== 'undefined') { + this.visibilityHiddenProp = 'msHidden'; + this.visibilityChange = 'msvisibilitychange'; + } else if (typeof document.webkitHidden !== 'undefined') { + this.visibilityHiddenProp = 'webkitHidden'; + this.visibilityChange = 'webkitvisibilitychange'; + } + if (this.visibilityChange !== undefined) { + document.addEventListener(this.visibilityChange, this.handleVisibilityChange, false); + this.handleVisibilityChange(); + } + window.addEventListener('beforeunload', this.handleBeforeUnload, false); window.addEventListener('resize', this.handleResize, { passive: true }); document.addEventListener('dragenter', this.handleDragEnter, false); @@ -250,6 +270,10 @@ export default class UI extends React.Component { } componentWillUnmount () { + if (this.visibilityChange !== undefined) { + document.removeEventListener(this.visibilityChange, this.handleVisibilityChange); + } + window.removeEventListener('beforeunload', this.handleBeforeUnload); window.removeEventListener('resize', this.handleResize); document.removeEventListener('dragenter', this.handleDragEnter); diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index 9087e226c..0b816e85e 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -1,6 +1,7 @@ import { NOTIFICATIONS_MOUNT, NOTIFICATIONS_UNMOUNT, + NOTIFICATIONS_SET_VISIBILITY, NOTIFICATIONS_UPDATE, NOTIFICATIONS_EXPAND_SUCCESS, NOTIFICATIONS_EXPAND_REQUEST, @@ -31,6 +32,7 @@ const initialState = ImmutableMap({ lastReadId: '0', isLoading: false, cleaningMode: false, + isTabVisible: true, // notification removal mark of new notifs loaded whilst cleaningMode is true. markNewForDelete: false, }); @@ -44,7 +46,7 @@ const notificationToMap = (state, notification) => ImmutableMap({ }); const normalizeNotification = (state, notification) => { - const top = state.get('top') && state.get('mounted') > 0; + const top = !shouldCountUnreadNotifications(state); if (top) { state = state.set('lastReadId', notification.id); @@ -62,7 +64,7 @@ const normalizeNotification = (state, notification) => { }; const expandNormalizedNotifications = (state, notifications, next) => { - const top = state.get('top') && state.get('mounted') > 0; + const top = !(shouldCountUnreadNotifications(state)); const lastReadId = state.get('lastReadId'); let items = ImmutableList(); @@ -112,7 +114,9 @@ const clearUnread = (state) => { } const updateTop = (state, top) => { - if (top && state.get('mounted') > 0) { + state = state.set('top', top); + + if (!shouldCountUnreadNotifications(state)) { state = clearUnread(state); } @@ -120,7 +124,7 @@ const updateTop = (state, top) => { }; const deleteByStatus = (state, statusId) => { - const top = state.get('top') && state.get('mounted') > 0; + const top = !(shouldCountUnreadNotifications(state)); if (!top) { const lastReadId = state.get('lastReadId'); const deletedUnread = state.get('items').filter(item => item !== null && item.get('status') === statusId && compareId(item.get('id'), lastReadId) > 0); @@ -157,14 +161,36 @@ const deleteMarkedNotifs = (state) => { return state.update('items', list => list.filterNot(item => item.get('markedForDelete'))); }; +const updateMounted = (state) => { + state = state.update('mounted', count => count + 1); + if (!shouldCountUnreadNotifications(state)) { + state = clearUnread(state); + } + return state; +}; + +const updateVisibility = (state, visibility) => { + state = state.set('isTabVisible', visibility); + if (!shouldCountUnreadNotifications(state)) { + state = clearUnread(state); + } + return state; +}; + +const shouldCountUnreadNotifications = (state) => { + return !(state.get('isTabVisible') && state.get('top') && state.get('mounted') > 0); +}; + export default function notifications(state = initialState, action) { let st; switch(action.type) { case NOTIFICATIONS_MOUNT: - return (state.get('top') ? clearUnread(state) : state).update('mounted', count => count + 1); + return updateMounted(state); case NOTIFICATIONS_UNMOUNT: return state.update('mounted', count => count - 1); + case NOTIFICATIONS_SET_VISIBILITY: + return updateVisibility(state, action.visibility); case NOTIFICATIONS_EXPAND_REQUEST: case NOTIFICATIONS_DELETE_MARKED_REQUEST: return state.set('isLoading', true); -- cgit From 0f155af32a330bc8eb79c6e3ccec5331a1e37922 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 16:09:57 +0200 Subject: Add notification badge to favicon --- app/javascript/flavours/glitch/features/ui/index.js | 10 ++++++++++ package.json | 1 + yarn.lock | 4 ++++ 3 files changed, 15 insertions(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index c41436090..3dd894383 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -17,6 +17,7 @@ import { WrappedSwitch, WrappedRoute } from 'flavours/glitch/util/react_router_h import UploadArea from './components/upload_area'; import ColumnsAreaContainer from './containers/columns_area_container'; import classNames from 'classnames'; +import Favico from 'favico.js'; import { Drawer, Status, @@ -64,6 +65,7 @@ const mapStateToProps = state => ({ isWide: state.getIn(['local_settings', 'stretch']), navbarUnder: state.getIn(['local_settings', 'navbar_under']), dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null, + unreadNotifications: state.getIn(['notifications', 'unread']), }); const keyMap = { @@ -115,6 +117,7 @@ export default class UI extends React.Component { history: PropTypes.object.isRequired, intl: PropTypes.object.isRequired, dropdownMenuIsOpen: PropTypes.bool, + unreadNotifications: PropTypes.number, }; state = { @@ -239,6 +242,8 @@ export default class UI extends React.Component { navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage); } + this.favicon = new Favico({ animation:"none" }); + this.props.dispatch(expandHomeTimeline()); this.props.dispatch(expandNotifications()); setTimeout(() => this.props.dispatch(fetchFilters()), 500); @@ -267,6 +272,11 @@ export default class UI extends React.Component { if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { this.columnsAreaNode.handleChildrenContentChange(); } + if (this.props.unreadNotifications != prevProps.unreadNotifications) { + if (this.favicon) { + this.favicon.badge(this.props.unreadNotifications); + } + } } componentWillUnmount () { diff --git a/package.json b/package.json index 3f6f4c7fd..5636cb883 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "escape-html": "^1.0.3", "exif-js": "^2.3.0", "express": "^4.16.2", + "favico.js": "^0.3.10", "file-loader": "^1.1.11", "font-awesome": "^4.7.0", "glob": "^7.1.1", diff --git a/yarn.lock b/yarn.lock index e8c41786d..6b83d0544 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3091,6 +3091,10 @@ fastparse@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" +favico.js@^0.3.10: + version "0.3.10" + resolved "https://registry.yarnpkg.com/favico.js/-/favico.js-0.3.10.tgz#80586e27a117f24a8d51c18a99bdc714d4339301" + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" -- cgit From 2cdc00bc8b41235b06090d34187ca71b8749aa27 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 19:17:14 +0200 Subject: Add unread notifications badge to the navigation bar --- .../flavours/glitch/features/drawer/header/index.js | 9 ++++++++- app/javascript/flavours/glitch/features/drawer/index.js | 4 ++++ .../flavours/glitch/styles/components/index.scss | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/drawer/header/index.js b/app/javascript/flavours/glitch/features/drawer/header/index.js index deec42435..435538de4 100644 --- a/app/javascript/flavours/glitch/features/drawer/header/index.js +++ b/app/javascript/flavours/glitch/features/drawer/header/index.js @@ -46,6 +46,7 @@ const messages = defineMessages({ // The component. export default function DrawerHeader ({ columns, + unreadNotifications, intl, onSettingsClick, }) { @@ -77,7 +78,12 @@ export default function DrawerHeader ({ aria-label={intl.formatMessage(messages.notifications)} title={intl.formatMessage(messages.notifications)} to='/notifications' - > + > + + + { unreadNotifications > 0 &&
} + + ))} {renderForColumn('COMMUNITY', ( ({ searchHidden: state.getIn(['search', 'hidden']), searchValue: state.getIn(['search', 'value']), submitted: state.getIn(['search', 'submitted']), + unreadNotifications: state.getIn(['notifications', 'unread']), }); // Dispatch mapping. @@ -87,6 +88,7 @@ class Drawer extends React.Component { searchValue, submitted, isSearchPage, + unreadNotifications, } = this.props; const computedClass = classNames('drawer', `mbstobon-${elefriend}`); @@ -96,6 +98,7 @@ class Drawer extends React.Component { {multiColumn ? ( @@ -139,6 +142,7 @@ Drawer.propTypes = { searchHidden: PropTypes.bool, searchValue: PropTypes.string, submitted: PropTypes.bool, + unreadNotifications: PropTypes.number, // Dispatch props. onChange: PropTypes.func, diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 1419888fa..52fe90885 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -1121,6 +1121,22 @@ left: 0; } +.icon-badge-wrapper { + position: relative; +} + +.icon-badge { + position: absolute; + display: block; + right: -.25em; + top: -.25em; + background-color: $ui-highlight-color; + border-radius: 50%; + font-size: 75%; + width: 1em; + height: 1em; +} + ::-webkit-scrollbar-thumb { border-radius: 0; } -- cgit From b28cbb8b25f3363bded6d6cbb8791ee80b24eeef Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 19:42:16 +0200 Subject: Add unread notifications badge to the mobile navbar --- .../glitch/features/ui/components/tabs_bar.js | 24 +++++++++++++++++++++- .../flavours/glitch/styles/components/index.scss | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js index b2fee21e1..6b9cf27e1 100644 --- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js +++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js @@ -4,10 +4,32 @@ import { NavLink, withRouter } from 'react-router-dom'; import { FormattedMessage, injectIntl } from 'react-intl'; import { debounce } from 'lodash'; import { isUserTouching } from 'flavours/glitch/util/is_mobile'; +import { connect } from 'react-redux'; + +const mapStateToProps = state => ({ + unreadNotifications: state.getIn(['notifications', 'unread']), +}); + +@connect(mapStateToProps) +class NotificationsIcon extends React.PureComponent { + static propTypes = { + unreadNotifications: PropTypes.number, + }; + + render() { + const { unreadNotifications } = this.props; + return ( + + + { unreadNotifications > 0 &&
} + + ); + } +} export const links = [ , - , + , , , diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 52fe90885..81405f4b5 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -571,7 +571,7 @@ } } - span { + span:last-child { margin-left: 5px; display: none; } -- cgit From ba4521b175a2d0906e2a62e93e39cb80fa9286c9 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 20:46:42 +0200 Subject: Move compose box options to their own page --- .../features/local_settings/navigation/index.js | 19 +++-- .../glitch/features/local_settings/page/index.js | 97 +++++++++++----------- 2 files changed, 63 insertions(+), 53 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js index 0c1040290..a992b1ffc 100644 --- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js @@ -10,6 +10,7 @@ import LocalSettingsNavigationItem from './item'; const messages = defineMessages({ general: { id: 'settings.general', defaultMessage: 'General' }, + compose: { id: 'settings.compose_box_opts', defaultMessage: 'Compose box options' }, content_warnings: { id: 'settings.content_warnings', defaultMessage: 'Content Warnings' }, collapsed: { id: 'settings.collapsed_statuses', defaultMessage: 'Collapsed toots' }, media: { id: 'settings.media', defaultMessage: 'Media' }, @@ -43,31 +44,37 @@ export default class LocalSettingsNavigation extends React.PureComponent { active={index === 1} index={1} onNavigate={onNavigate} - title={intl.formatMessage(messages.content_warnings)} + title={intl.formatMessage(messages.compose)} /> + diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index 0db49ba5d..9f300e7e9 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -74,53 +74,56 @@ export default class LocalSettingsPage extends React.PureComponent { -
-

- - - - - - - - - - - - -
+
+ ), + ({ intl, onChange, settings }) => ( +
+
+

+ + + + + + + + + + + +
), ({ intl, onChange, settings }) => ( -- cgit From 324ce93368bbac88a5b53083c8932ec175450f55 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 6 Sep 2018 20:55:11 +0200 Subject: Add preferences for notification badges --- .../flavours/glitch/features/drawer/header/index.js | 4 +++- .../flavours/glitch/features/drawer/index.js | 4 ++++ .../glitch/features/local_settings/page/index.js | 20 +++++++++++++++++++- .../glitch/features/ui/components/tabs_bar.js | 6 ++++-- app/javascript/flavours/glitch/features/ui/index.js | 7 +++++-- .../flavours/glitch/reducers/local_settings.js | 4 ++++ 6 files changed, 39 insertions(+), 6 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/drawer/header/index.js b/app/javascript/flavours/glitch/features/drawer/header/index.js index 435538de4..7fefd32c9 100644 --- a/app/javascript/flavours/glitch/features/drawer/header/index.js +++ b/app/javascript/flavours/glitch/features/drawer/header/index.js @@ -47,6 +47,7 @@ const messages = defineMessages({ export default function DrawerHeader ({ columns, unreadNotifications, + showNotificationsBadge, intl, onSettingsClick, }) { @@ -81,7 +82,7 @@ export default function DrawerHeader ({ > - { unreadNotifications > 0 &&
} + { showNotificationsBadge && unreadNotifications > 0 &&
} ))} @@ -119,6 +120,7 @@ export default function DrawerHeader ({ DrawerHeader.propTypes = { columns: ImmutablePropTypes.list, unreadNotifications: PropTypes.number, + showNotificationsBadge: PropTypes.bool, intl: PropTypes.object, onSettingsClick: PropTypes.func, }; diff --git a/app/javascript/flavours/glitch/features/drawer/index.js b/app/javascript/flavours/glitch/features/drawer/index.js index e8d9c86cb..72b36fcae 100644 --- a/app/javascript/flavours/glitch/features/drawer/index.js +++ b/app/javascript/flavours/glitch/features/drawer/index.js @@ -35,6 +35,7 @@ const mapStateToProps = state => ({ searchValue: state.getIn(['search', 'value']), submitted: state.getIn(['search', 'submitted']), unreadNotifications: state.getIn(['notifications', 'unread']), + showNotificationsBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']), }); // Dispatch mapping. @@ -89,6 +90,7 @@ class Drawer extends React.Component { submitted, isSearchPage, unreadNotifications, + showNotificationsBadge, } = this.props; const computedClass = classNames('drawer', `mbstobon-${elefriend}`); @@ -99,6 +101,7 @@ class Drawer extends React.Component { @@ -143,6 +146,7 @@ Drawer.propTypes = { searchValue: PropTypes.string, submitted: PropTypes.bool, unreadNotifications: PropTypes.number, + showNotificationsBadge: PropTypes.bool, // Dispatch props. onChange: PropTypes.func, diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index 9f300e7e9..2e14c9dd5 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -42,6 +42,25 @@ export default class LocalSettingsPage extends React.PureComponent { > +
+

+ + + + + + +

(
-

({ unreadNotifications: state.getIn(['notifications', 'unread']), + showBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']), }); @connect(mapStateToProps) class NotificationsIcon extends React.PureComponent { static propTypes = { unreadNotifications: PropTypes.number, + showBadge: PropTypes.bool, }; render() { - const { unreadNotifications } = this.props; + const { unreadNotifications, showBadge } = this.props; return ( - { unreadNotifications > 0 &&
} + { showBadge && unreadNotifications > 0 &&
} ); } diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 3dd894383..064804b79 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -66,6 +66,7 @@ const mapStateToProps = state => ({ navbarUnder: state.getIn(['local_settings', 'navbar_under']), dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null, unreadNotifications: state.getIn(['notifications', 'unread']), + showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']), }); const keyMap = { @@ -118,6 +119,7 @@ export default class UI extends React.Component { intl: PropTypes.object.isRequired, dropdownMenuIsOpen: PropTypes.bool, unreadNotifications: PropTypes.number, + showFaviconBadge: PropTypes.bool, }; state = { @@ -272,9 +274,10 @@ export default class UI extends React.Component { if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { this.columnsAreaNode.handleChildrenContentChange(); } - if (this.props.unreadNotifications != prevProps.unreadNotifications) { + if (this.props.unreadNotifications != prevProps.unreadNotifications || + this.props.showFaviconBadge != prevProps.showFaviconBadge) { if (this.favicon) { - this.favicon.badge(this.props.unreadNotifications); + this.favicon.badge(this.props.showFaviconBadge ? this.props.unreadNotifications : 0); } } } diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js index 063ae3943..f5f7220b9 100644 --- a/app/javascript/flavours/glitch/reducers/local_settings.js +++ b/app/javascript/flavours/glitch/reducers/local_settings.js @@ -37,6 +37,10 @@ const initialState = ImmutableMap({ letterbox : true, fullwidth : true, }), + notifications : ImmutableMap({ + favicon_badge : false, + tab_badge : true, + }), }); const hydrate = (state, localSettings) => state.mergeDeep(localSettings); -- cgit From 49eaf72faf5b8b6f574a759a990c230f82c3b891 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 10 Sep 2018 17:49:45 +0200 Subject: [Glitch] Add embed_url to preview cards Port front-end changes from c083816c2479dcdfa6674c47a75a8293bf64a947 to glitch-soc --- app/javascript/flavours/glitch/features/status/components/card.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js index 680bf63ab..d3e322c36 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.js +++ b/app/javascript/flavours/glitch/features/status/components/card.js @@ -101,7 +101,7 @@ export default class Card extends React.PureComponent { onClick={this.handlePhotoClick} role='button' tabIndex='0' - src={card.get('url')} + src={card.get('embed_url')} alt={card.get('title')} width={card.get('width')} height={card.get('height')} -- cgit From cc5826521619e64022a965e2d414fd29c834612c Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 10 Sep 2018 17:51:00 +0200 Subject: [Glitch] Ensure link thumbnails are not stretched to super low quality Port front-end changes from c36b9cc5a6cf3feacb925213f5530c90dd31fa7a to glitch-soc --- .../flavours/glitch/features/status/components/card.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js index d3e322c36..f7d980066 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.js +++ b/app/javascript/flavours/glitch/features/status/components/card.js @@ -59,6 +59,8 @@ export default class Card extends React.PureComponent { renderLink () { const { card, maxDescription } = this.props; + const { width } = this.state; + const horizontal = card.get('width') > card.get('height') && (card.get('width') + 100 >= width); let image = ''; let provider = card.get('provider_name'); @@ -75,17 +77,15 @@ export default class Card extends React.PureComponent { provider = decodeIDNA(getHostname(card.get('url'))); } - const className = classnames('status-card', { - 'horizontal': card.get('width') > card.get('height'), - }); + const className = classnames('status-card', { horizontal }); return ( - + {image}
{card.get('title')} -

{(card.get('description') || '').substring(0, maxDescription)}

+ {!horizontal &&

{(card.get('description') || '').substring(0, maxDescription)}

} {provider}
-- cgit From dfa6fb49277d385b6de93ea43e428d53eb7721a9 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 10 Sep 2018 17:52:40 +0200 Subject: [Glitch] Fix oEmbed image_modal src. Port 25b0d7538eb83c5fd02409ca22345c9af752b3ed to glitch-soc --- app/javascript/flavours/glitch/features/status/components/card.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js index f7d980066..2f6a7831e 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.js +++ b/app/javascript/flavours/glitch/features/status/components/card.js @@ -43,7 +43,7 @@ export default class Card extends React.PureComponent { Immutable.fromJS([ { type: 'image', - url: card.get('url'), + url: card.get('embed_url'), description: card.get('title'), meta: { original: { -- cgit From bc5009cd45a4fd8fb2178909e1da981e878b879e Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 10 Sep 2018 17:53:28 +0200 Subject: [Glitch] Click card to embed external content Port front-end changes from f7765acf9d92951a616f41b738d5d23ede58c162 to glitch-soc --- .../glitch/features/status/components/card.js | 150 ++++++++++++--------- .../flavours/glitch/styles/components/status.scss | 63 +++++++-- 2 files changed, 141 insertions(+), 72 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js index 2f6a7831e..8a6383471 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.js +++ b/app/javascript/flavours/glitch/features/status/components/card.js @@ -20,6 +20,16 @@ const getHostname = url => { return parser.hostname; }; +const trim = (text, len) => { + const cut = text.indexOf(' ', len); + + if (cut === -1) { + return text; + } + + return text.substring(0, cut) + (text.length > len ? '…' : ''); +}; + export default class Card extends React.PureComponent { static propTypes = { @@ -33,9 +43,16 @@ export default class Card extends React.PureComponent { }; state = { - width: 0, + width: 280, + embedded: false, }; + componentWillReceiveProps (nextProps) { + if (this.props.card !== nextProps.card) { + this.setState({ embedded: false }); + } + } + handlePhotoClick = () => { const { card, onOpenMedia } = this.props; @@ -57,56 +74,14 @@ export default class Card extends React.PureComponent { ); }; - renderLink () { - const { card, maxDescription } = this.props; - const { width } = this.state; - const horizontal = card.get('width') > card.get('height') && (card.get('width') + 100 >= width); - - let image = ''; - let provider = card.get('provider_name'); - - if (card.get('image')) { - image = ( -
- {card.get('title')} -
- ); - } - - if (provider.length < 1) { - provider = decodeIDNA(getHostname(card.get('url'))); - } - - const className = classnames('status-card', { horizontal }); - - return ( - - {image} - -
- {card.get('title')} - {!horizontal &&

{(card.get('description') || '').substring(0, maxDescription)}

} - {provider} -
-
- ); - } - - renderPhoto () { + handleEmbedClick = () => { const { card } = this.props; - return ( - {card.get('title')} - ); + if (card.get('type') === 'photo') { + this.handlePhotoClick(); + } else { + this.setState({ embedded: true }); + } } setRef = c => { @@ -125,7 +100,7 @@ export default class Card extends React.PureComponent { return (
@@ -133,23 +108,76 @@ export default class Card extends React.PureComponent { } render () { - const { card } = this.props; + const { card, maxDescription } = this.props; + const { width, embedded } = this.state; if (card === null) { return null; } - switch(card.get('type')) { - case 'link': - return this.renderLink(); - case 'photo': - return this.renderPhoto(); - case 'video': - return this.renderVideo(); - case 'rich': - default: - return null; + const provider = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name'); + const horizontal = card.get('width') > card.get('height') && (card.get('width') + 100 >= width) || card.get('type') !== 'link'; + const className = classnames('status-card', { horizontal }); + const interactive = card.get('type') !== 'link'; + const title = interactive ? {card.get('title')} : {card.get('title')}; + const ratio = card.get('width') / card.get('height'); + const height = card.get('width') > card.get('height') ? (width / ratio) : (width * ratio); + + const description = ( +
+ {title} + {!horizontal &&

{trim(card.get('description') || '', maxDescription)}

} + {provider} +
+ ); + + let embed = ''; + let thumbnail =
; + + if (interactive) { + if (embedded) { + embed = this.renderVideo(); + } else { + let iconVariant = 'play'; + + if (card.get('type') === 'photo') { + iconVariant = 'search-plus'; + } + + embed = ( +
+ {thumbnail} + +
+
+ + +
+
+
+ ); + } + + return ( +
+ {embed} + {description} +
+ ); + } else if (card.get('image')) { + embed = ( +
+ {thumbnail} +
+ ); } + + return ( + + {embed} + {description} + + ); } } diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss index b841d73c4..5c1cb62a8 100644 --- a/app/javascript/flavours/glitch/styles/components/status.scss +++ b/app/javascript/flavours/glitch/styles/components/status.scss @@ -623,7 +623,6 @@ .status-card { display: flex; - cursor: pointer; font-size: 14px; border: 1px solid lighten($ui-base-color, 8%); border-radius: 4px; @@ -632,20 +631,58 @@ text-decoration: none; overflow: hidden; - &:hover { - background: lighten($ui-base-color, 8%); + &__actions { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + display: flex; + justify-content: center; + align-items: center; + + & > div { + background: rgba($base-shadow-color, 0.6); + border-radius: 4px; + padding: 12px 9px; + flex: 0 0 auto; + display: flex; + justify-content: center; + align-items: center; + } + + button, + a { + display: inline; + color: $primary-text-color; + background: transparent; + border: 0; + padding: 0 5px; + text-decoration: none; + opacity: 0.6; + font-size: 18px; + line-height: 18px; + + &:hover, + &:active, + &:focus { + opacity: 1; + } + } + + a { + font-size: 19px; + position: relative; + bottom: -1px; + } } } -.status-card-video, -.status-card-rich, -.status-card-photo { - margin-top: 14px; - overflow: hidden; +a.status-card { + cursor: pointer; - iframe { - width: 100%; - height: auto; + &:hover { + background: lighten($ui-base-color, 8%); } } @@ -673,6 +710,7 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + text-decoration: none; } .status-card__content { @@ -694,6 +732,7 @@ .status-card__image { flex: 0 0 100px; background: lighten($ui-base-color, 8%); + position: relative; } .status-card.horizontal { @@ -719,6 +758,8 @@ width: 100%; height: 100%; object-fit: cover; + background-size: cover; + background-position: center center; } .status__video-player { -- cgit From d9a92d504053568ce424f23667c7dc6121d9b20d Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 10 Sep 2018 17:58:21 +0200 Subject: [Glitch] After click to embed video, autoplay it Port 478ca39e5e8463044a259388459da56d2141e104 to glitch-soc --- .../glitch/features/status/components/card.js | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js index 8a6383471..b52f3c4fa 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.js +++ b/app/javascript/flavours/glitch/features/status/components/card.js @@ -30,6 +30,29 @@ const trim = (text, len) => { return text.substring(0, cut) + (text.length > len ? '…' : ''); }; +const domParser = new DOMParser(); + +const addAutoPlay = html => { + const document = domParser.parseFromString(html, 'text/html').documentElement; + const iframe = document.querySelector('iframe'); + + if (iframe) { + if (iframe.src.indexOf('?') !== -1) { + iframe.src += '&'; + } else { + iframe.src += '?'; + } + + iframe.src += 'autoplay=1&auto_play=1'; + + // DOM parser creates html/body elements around original HTML fragment, + // so we need to get innerHTML out of the body and not the entire document + return document.querySelector('body').innerHTML; + } + + return html; +}; + export default class Card extends React.PureComponent { static propTypes = { @@ -92,7 +115,7 @@ export default class Card extends React.PureComponent { renderVideo () { const { card } = this.props; - const content = { __html: card.get('html') }; + const content = { __html: addAutoPlay(card.get('html')) }; const { width } = this.state; const ratio = card.get('width') / card.get('height'); const height = card.get('width') > card.get('height') ? (width / ratio) : (width * ratio); -- cgit From e36f6f48e5091699c74b969e994ce6a15af66068 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 10 Sep 2018 18:07:27 +0200 Subject: Fix status embed card links color --- app/javascript/flavours/glitch/styles/components/status.scss | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss index 5c1cb62a8..aa49aba55 100644 --- a/app/javascript/flavours/glitch/styles/components/status.scss +++ b/app/javascript/flavours/glitch/styles/components/status.scss @@ -675,6 +675,10 @@ position: relative; bottom: -1px; } + + a .fa, a:hover .fa { + color: inherit; + } } } -- cgit From 65f625cf237feb55a21495606d5e2c258bbe50cc Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 16:11:26 +0200 Subject: [Glitch] Hide floating action button on thread views Port f66a7860291e6b2fef1844b580c22296dbad9202 to glitch-soc --- app/javascript/flavours/glitch/features/ui/components/columns_area.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js index f87c078ec..71cb7e8c9 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -30,6 +30,8 @@ const componentMap = { 'LIST': ListTimeline, }; +const shouldHideFAB = path => path.match(/^\/statuses\//); + const messages = defineMessages({ publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }, }); @@ -158,7 +160,7 @@ export default class ColumnsArea extends ImmutablePureComponent { this.pendingIndex = null; if (singleColumn) { - const floatingActionButton = this.context.router.history.location.pathname === '/statuses/new' ? null : ; + const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : ; return columnIndex !== -1 ? [ -- cgit From ac6fb758b975ec2858c53be24f8e9be8e2d40e90 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 17:24:31 +0200 Subject: Fix incorrect disabled boost button color when reduce-motion is set --- app/javascript/flavours/glitch/styles/components/index.scss | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 81405f4b5..cbf968ec4 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -827,6 +827,10 @@ color: $highlight-text-color; } +.reduce-motion button.icon-button.disabled i.fa-retweet { + color: darken($action-button-color, 13%); +} + .load-more { display: block; color: $dark-text-color; -- cgit From 59de2868c13a61bce08923f841024fefebe3b3da Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 15:45:51 +0200 Subject: Fix media description in various media modals --- app/javascript/flavours/glitch/features/ui/components/media_modal.js | 2 +- app/javascript/flavours/glitch/features/ui/components/video_modal.js | 2 +- .../flavours/glitch/features/ui/components/zoomable_image.js | 1 + app/javascript/flavours/glitch/features/video/index.js | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js index d4fd45d4d..1f3ac18ea 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js @@ -129,7 +129,7 @@ export default class MediaModal extends ImmutablePureComponent { startTime={time || 0} onCloseVideo={onClose} detailed - description={image.get('description')} + alt={image.get('description')} key={image.get('url')} /> ); diff --git a/app/javascript/flavours/glitch/features/ui/components/video_modal.js b/app/javascript/flavours/glitch/features/ui/components/video_modal.js index e0cb7fc09..69e0ee46e 100644 --- a/app/javascript/flavours/glitch/features/ui/components/video_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/video_modal.js @@ -24,7 +24,7 @@ export default class VideoModal extends ImmutablePureComponent { startTime={time} onCloseVideo={onClose} detailed - description={media.get('description')} + alt={media.get('description')} />
diff --git a/app/javascript/flavours/glitch/features/ui/components/zoomable_image.js b/app/javascript/flavours/glitch/features/ui/components/zoomable_image.js index 0a0a4d41a..3f6562bc9 100644 --- a/app/javascript/flavours/glitch/features/ui/components/zoomable_image.js +++ b/app/javascript/flavours/glitch/features/ui/components/zoomable_image.js @@ -137,6 +137,7 @@ export default class ZoomableImage extends React.PureComponent { role='presentation' ref={this.setImageRef} alt={alt} + title={alt} src={src} style={{ transform: `scale(${scale})`, diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js index 44aba797c..65e10e0cf 100644 --- a/app/javascript/flavours/glitch/features/video/index.js +++ b/app/javascript/flavours/glitch/features/video/index.js @@ -261,11 +261,12 @@ export default class Video extends React.PureComponent { } handleOpenVideo = () => { - const { src, preview, width, height } = this.props; + const { src, preview, width, height, alt } = this.props; const media = fromJS({ type: 'video', url: src, preview_url: preview, + description: alt, width, height, }); -- cgit From 49734c03fd7623d007980a2c4d9a7ce4c46e78ae Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 21:18:23 +0200 Subject: Fix action modal links --- app/javascript/flavours/glitch/containers/dropdown_menu_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js index dccd93dab..626d500f0 100644 --- a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js +++ b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js @@ -18,7 +18,7 @@ const mapDispatchToProps = (dispatch, { status, items }) => ({ (item, i) => item ? { ...item, name: `${item.text}-${i}`, - onClick: (e) => { return onItemClick(i, e) }, + onClick: item.action ? ((e) => { return onItemClick(i, e) }) : null, } : null ), }) : openDropdownMenu(id, dropdownPlacement)); -- cgit From 307fb338ee4432a933ad8c8efe70b1a78d8b3bc0 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 21:34:07 +0200 Subject: Fix composer actions modal --- app/javascript/flavours/glitch/features/composer/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js index 77f9ee0c1..ff01408e7 100644 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ b/app/javascript/flavours/glitch/features/composer/index.js @@ -146,7 +146,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ onMount() { dispatch(mountCompose()); }, - onOpenActionModal(props) { + onOpenActionsModal(props) { dispatch(openModal('ACTIONS', props)); }, onOpenDoodleModal() { -- cgit From b3c698d6f4c0e35006173877db750841f96a2674 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 13 Sep 2018 11:55:41 +0200 Subject: Auto-focus emoji picker's search field --- app/javascript/flavours/glitch/features/emoji_picker/index.js | 1 + 1 file changed, 1 insertion(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/emoji_picker/index.js b/app/javascript/flavours/glitch/features/emoji_picker/index.js index d22a50848..a78117971 100644 --- a/app/javascript/flavours/glitch/features/emoji_picker/index.js +++ b/app/javascript/flavours/glitch/features/emoji_picker/index.js @@ -340,6 +340,7 @@ class EmojiPickerMenu extends React.PureComponent { skin={skinTone} showPreview={false} backgroundImageFn={backgroundImageFn} + autoFocus emojiTooltip /> -- cgit From 1cb3af21c5bb8f944a88c4e89ab28ff6b7e02552 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 13 Sep 2018 12:05:18 +0200 Subject: Autofocus comment textarea in report modal --- app/javascript/flavours/glitch/features/ui/components/report_modal.js | 1 + 1 file changed, 1 insertion(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/ui/components/report_modal.js b/app/javascript/flavours/glitch/features/ui/components/report_modal.js index 81643b6c2..a139394ac 100644 --- a/app/javascript/flavours/glitch/features/ui/components/report_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/report_modal.js @@ -106,6 +106,7 @@ export default class ReportModal extends ImmutablePureComponent { onChange={this.handleCommentChange} onKeyDown={this.handleKeyDown} disabled={isSubmitting} + autoFocus /> {domain && ( -- cgit From cf142e85569be5e7e0dae7e02f490c737a238319 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 13 Sep 2018 11:20:21 +0200 Subject: [Glitch] Highlight active tab in action bar Port 7b7c26063e3fcf9e75a61780d81bd60b7c398ead to glitch-soc --- .../glitch/features/account/components/action_bar.js | 14 +++++++------- .../flavours/glitch/styles/components/accounts.scss | 5 +++++ 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js index 26717ee49..e60b25855 100644 --- a/app/javascript/flavours/glitch/features/account/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js @@ -2,7 +2,7 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container'; -import { Link } from 'react-router-dom'; +import { NavLink } from 'react-router-dom'; import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl'; import { me, isStaff } from 'flavours/glitch/util/initial_state'; @@ -136,20 +136,20 @@ export default class ActionBar extends React.PureComponent {
- + - + - + - + - + - +
diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss index b2b6248ff..3eddd7fb4 100644 --- a/app/javascript/flavours/glitch/styles/components/accounts.scss +++ b/app/javascript/flavours/glitch/styles/components/accounts.scss @@ -239,6 +239,11 @@ flex: 0 1 100%; border-left: 1px solid lighten($ui-base-color, 8%); padding: 10px 0; + border-bottom: 4px solid transparent; + + &.active { + border-bottom: 4px solid $ui-highlight-color; + } & > span { display: block; -- cgit From 5ff733b614fee51eebbc5f3f8aa2b96339181235 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 22:35:17 +0200 Subject: Only focus first item of dropdown if it was opened via keyboard --- app/javascript/flavours/glitch/actions/dropdown_menu.js | 4 ++-- .../flavours/glitch/components/dropdown_menu.js | 17 ++++++++++++----- .../glitch/containers/dropdown_menu_container.js | 5 +++-- .../flavours/glitch/reducers/dropdown_menu.js | 4 ++-- 4 files changed, 19 insertions(+), 11 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/actions/dropdown_menu.js b/app/javascript/flavours/glitch/actions/dropdown_menu.js index 217ba4e74..14f2939c7 100644 --- a/app/javascript/flavours/glitch/actions/dropdown_menu.js +++ b/app/javascript/flavours/glitch/actions/dropdown_menu.js @@ -1,8 +1,8 @@ export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN'; export const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE'; -export function openDropdownMenu(id, placement) { - return { type: DROPDOWN_MENU_OPEN, id, placement }; +export function openDropdownMenu(id, placement, keyboard) { + return { type: DROPDOWN_MENU_OPEN, id, placement, keyboard }; } export function closeDropdownMenu(id) { diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.js b/app/javascript/flavours/glitch/components/dropdown_menu.js index 1c2b0bf25..cc63f7d98 100644 --- a/app/javascript/flavours/glitch/components/dropdown_menu.js +++ b/app/javascript/flavours/glitch/components/dropdown_menu.js @@ -23,6 +23,7 @@ class DropdownMenu extends React.PureComponent { placement: PropTypes.string, arrowOffsetLeft: PropTypes.string, arrowOffsetTop: PropTypes.string, + openedViaKeyboard: PropTypes.bool, }; static defaultProps = { @@ -43,7 +44,7 @@ class DropdownMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); - if (this.focusedItem) this.focusedItem.focus(); + if (this.focusedItem && this.props.openedviaKeyBoard) this.focusedItem.focus(); this.setState({ mounted: true }); } @@ -170,6 +171,7 @@ export default class Dropdown extends React.PureComponent { onClose: PropTypes.func.isRequired, dropdownPlacement: PropTypes.string, openDropdownId: PropTypes.number, + openedViaKeyboard: PropTypes.bool, }; static defaultProps = { @@ -180,14 +182,14 @@ export default class Dropdown extends React.PureComponent { id: id++, }; - handleClick = ({ target }) => { + handleClick = ({ target, type }) => { if (this.state.id === this.props.openDropdownId) { this.handleClose(); } else { const { top } = target.getBoundingClientRect(); const placement = top * 2 < innerHeight ? 'bottom' : 'top'; - this.props.onOpen(this.state.id, this.handleItemClick, placement); + this.props.onOpen(this.state.id, this.handleItemClick, placement, type !== 'click'); } } @@ -197,6 +199,11 @@ export default class Dropdown extends React.PureComponent { handleKeyDown = e => { switch(e.key) { + case ' ': + case 'Enter': + this.handleClick(e); + e.preventDefault(); + break; case 'Escape': this.handleClose(); break; @@ -232,7 +239,7 @@ export default class Dropdown extends React.PureComponent { } render () { - const { icon, items, size, ariaLabel, disabled, dropdownPlacement, openDropdownId } = this.props; + const { icon, items, size, ariaLabel, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard } = this.props; const open = this.state.id === openDropdownId; return ( @@ -248,7 +255,7 @@ export default class Dropdown extends React.PureComponent { /> - +
); diff --git a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js index 626d500f0..b2419a0fd 100644 --- a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js +++ b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js @@ -8,10 +8,11 @@ const mapStateToProps = state => ({ isModalOpen: state.get('modal').modalType === 'ACTIONS', dropdownPlacement: state.getIn(['dropdown_menu', 'placement']), openDropdownId: state.getIn(['dropdown_menu', 'openId']), + openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), }); const mapDispatchToProps = (dispatch, { status, items }) => ({ - onOpen(id, onItemClick, dropdownPlacement) { + onOpen(id, onItemClick, dropdownPlacement, keyboard) { dispatch(isUserTouching() ? openModal('ACTIONS', { status, actions: items.map( @@ -21,7 +22,7 @@ const mapDispatchToProps = (dispatch, { status, items }) => ({ onClick: item.action ? ((e) => { return onItemClick(i, e) }) : null, } : null ), - }) : openDropdownMenu(id, dropdownPlacement)); + }) : openDropdownMenu(id, dropdownPlacement, keyboard)); }, onClose(id) { dispatch(closeModal()); diff --git a/app/javascript/flavours/glitch/reducers/dropdown_menu.js b/app/javascript/flavours/glitch/reducers/dropdown_menu.js index 5449884cc..36fd4f132 100644 --- a/app/javascript/flavours/glitch/reducers/dropdown_menu.js +++ b/app/javascript/flavours/glitch/reducers/dropdown_menu.js @@ -4,12 +4,12 @@ import { DROPDOWN_MENU_CLOSE, } from '../actions/dropdown_menu'; -const initialState = Immutable.Map({ openId: null, placement: null }); +const initialState = Immutable.Map({ openId: null, placement: null, keyboard: false }); export default function dropdownMenu(state = initialState, action) { switch (action.type) { case DROPDOWN_MENU_OPEN: - return state.merge({ openId: action.id, placement: action.placement }); + return state.merge({ openId: action.id, placement: action.placement, keyboard: action.keyboard }); case DROPDOWN_MENU_CLOSE: return state.get('openId') === action.id ? state.set('openId', null) : state; default: -- cgit From c3ab2973c5383f66fa64b95d2036b89cb5dc6678 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 11 Sep 2018 22:44:20 +0200 Subject: Improve keyboard VS mouse navigation of dropdown menus --- .../flavours/glitch/components/dropdown_menu.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.js b/app/javascript/flavours/glitch/components/dropdown_menu.js index cc63f7d98..05611c135 100644 --- a/app/javascript/flavours/glitch/components/dropdown_menu.js +++ b/app/javascript/flavours/glitch/components/dropdown_menu.js @@ -43,13 +43,15 @@ class DropdownMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); + document.addEventListener('keydown', this.handleKeyDown, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); - if (this.focusedItem && this.props.openedviaKeyBoard) this.focusedItem.focus(); + if (this.focusedItem && this.props.openedViaKeyboard) this.focusedItem.focus(); this.setState({ mounted: true }); } componentWillUnmount () { document.removeEventListener('click', this.handleDocumentClick, false); + document.removeEventListener('keydown', this.handleKeyDown, false); document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); } @@ -63,13 +65,10 @@ class DropdownMenu extends React.PureComponent { handleKeyDown = e => { const items = Array.from(this.node.getElementsByTagName('a')); - const index = items.indexOf(e.currentTarget); + const index = items.indexOf(document.activeElement); let element; switch(e.key) { - case 'Enter': - this.handleClick(e); - break; case 'ArrowDown': element = items[index+1]; if (element) { @@ -97,6 +96,12 @@ class DropdownMenu extends React.PureComponent { } } + handleItemKeyDown = e => { + if (e.key === 'Enter') { + this.handleClick(e); + } + } + handleClick = e => { const i = Number(e.currentTarget.getAttribute('data-index')); const { action, to } = this.props.items[i]; @@ -121,7 +126,7 @@ class DropdownMenu extends React.PureComponent { return (
  • - + {text}
  • -- cgit From 8433bd89e431d5834e4252c7ca197771944aa6d1 Mon Sep 17 00:00:00 2001 From: Igor Galić Date: Wed, 12 Sep 2018 14:22:06 +0200 Subject: prepend re: to replies to spoiler-text if spoiler-text doesn't already start with re:, we prepend `re: ` ourselves in replies. This implements https://github.com/tootsuite/mastodon/issues/8667 Following Plemora's example: https://git.pleroma.social/pleroma/pleroma-fe/merge_requests/318 --- app/javascript/flavours/glitch/reducers/compose.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index 594d70ee2..0ddff707e 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -314,8 +314,12 @@ export default function compose(state = initialState, action) { map.set('idempotencyKey', uuid()); if (action.status.get('spoiler_text').length > 0) { + let spoiler_text = action.status.get('spoiler_text'); + if (!spoiler_text.match(/^re[: ]/i)) { + spoiler_text = 're: '.concat(spoiler_text); + } map.set('spoiler', true); - map.set('spoiler_text', action.status.get('spoiler_text')); + map.set('spoiler_text', spoiler_text); } else { map.set('spoiler', false); map.set('spoiler_text', ''); -- cgit From 657805f444ffd8d1cc0a36e0c37276a01611dc26 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 16 Sep 2018 12:15:58 +0200 Subject: Fix thread CW expansion not being reset when changing threads --- app/javascript/flavours/glitch/features/status/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 3d309976a..33a7bd075 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -103,7 +103,7 @@ export default class Status extends ImmutablePureComponent { if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { this._scrolledIntoView = false; this.props.dispatch(fetchStatus(nextProps.params.statusId)); - this.setState({ isExpanded: autoUnfoldCW(nextProps.settings, nextProps.status) }); + this.setState({ isExpanded: autoUnfoldCW(nextProps.settings, nextProps.status), threadExpanded: undefined }); } } -- cgit From 022d96c99954eeb282ffddc628b10e9d2baea7ef Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 20 Sep 2018 17:54:04 +0200 Subject: [Glitch] Group reports by target account Port SCSS from 011437dcb5c4719ad6627f3a4dc07a5ce1bd9db8 to glitch-soc --- app/javascript/flavours/glitch/styles/admin.scss | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 7fe5e4a19..eb3eaf11a 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -578,3 +578,102 @@ a.name-tag, color: $dark-text-color; } } + +.report-card { + background: $ui-base-color; + border-radius: 4px; + margin-bottom: 20px; + + &__profile { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px; + + .account { + padding: 0; + border: 0; + + &__avatar-wrapper { + margin-left: 0; + } + } + + &__stats { + flex: 0 0 auto; + font-weight: 500; + color: $darker-text-color; + text-transform: uppercase; + text-align: right; + + a { + color: inherit; + text-decoration: none; + + &:focus, + &:hover, + &:active { + color: lighten($darker-text-color, 8%); + } + } + + .red { + color: $error-value-color; + } + } + } + + &__summary { + &__item { + display: flex; + justify-content: flex-start; + border-top: 1px solid darken($ui-base-color, 4%); + + &:hover { + background: lighten($ui-base-color, 2%); + } + + &__reported-by, + &__assigned { + padding: 15px; + flex: 0 0 auto; + box-sizing: border-box; + width: 150px; + color: $darker-text-color; + + &, + .username { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + &__content { + flex: 1 1 auto; + max-width: calc(100% - 300px); + + &__icon { + color: $dark-text-color; + margin-right: 4px; + font-weight: 500; + } + } + + &__content a { + display: block; + box-sizing: border-box; + width: 100%; + padding: 15px; + text-decoration: none; + color: $darker-text-color; + } + } + } +} + +.one-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} -- cgit From a6d47ac5f5e7f747c6a5211110cfa4c7730eea3c Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 20 Sep 2018 18:07:52 +0200 Subject: [Glitch] Port SCSS changes from upstream Port SCSS changes from: - a58ec29631f74259364dc71b408a8d66df657149 - cdfe51e3253edc219116e9276f9416cda95c4461 - 1f6ed4f86ab2aa98bb271b40bf381370fab4fdf2 - 617f40fc2bb6057aa6a823b1750a53e8bd1504f6 - 6a0d4d36adb3b2efbd145a40248ee40bdbbb163f - 2374a00c1062a70e9092d88579e1351e4c8128f9 - a2cabf3f4af9271d8bfdb13c1ae2b7a8b4e6fb88 --- app/javascript/flavours/glitch/styles/forms.scss | 44 +++++++++++++++++++++--- app/javascript/flavours/glitch/styles/rtl.scss | 8 ++++- 2 files changed, 47 insertions(+), 5 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index f97890187..18019c29c 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -50,6 +50,12 @@ code { color: $highlight-text-color; } } + + code { + border-radius: 3px; + padding: 0.2em 0.4em; + background: darken($ui-base-color, 12%); + } } .card { @@ -136,6 +142,8 @@ code { } .input.with_block_label { + padding-top: 15px; + & > label { font-family: inherit; font-size: 16px; @@ -148,9 +156,8 @@ code { margin-bottom: 15px; } - li { - float: left; - width: 50%; + ul { + columns: 2; } } @@ -346,7 +353,7 @@ code { position: relative; .input input { - padding-right: 127px; + padding-right: 142px; } .append { @@ -360,6 +367,20 @@ code { font-family: inherit; pointer-events: none; cursor: default; + max-width: 140px; + white-space: nowrap; + overflow: hidden; + + &::after { + content: ''; + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 1px; + width: 5px; + background-image: linear-gradient(to right, rgba($ui-base-color, 0), $ui-base-color); + } } } } @@ -592,3 +613,18 @@ code { display: block; } } + +.scope-danger { + color: $warning-red; +} + +.form_admin_settings_site_short_description, +.form_admin_settings_site_description, +.form_admin_settings_site_extended_description, +.form_admin_settings_site_terms, +.form_admin_settings_custom_css, +.form_admin_settings_closed_registrations_message { + textarea { + font-family: 'mastodon-font-monospace', monospace; + } +} diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss index e9099a9e9..b8c0efad8 100644 --- a/app/javascript/flavours/glitch/styles/rtl.scss +++ b/app/javascript/flavours/glitch/styles/rtl.scss @@ -206,13 +206,19 @@ body.rtl { } .simple_form .input-with-append .input input { - padding-left: 127px; + padding-left: 142px; padding-right: 0; } .simple_form .input-with-append .append { right: auto; left: 0; + + &::after { + right: auto; + left: 0; + background-image: linear-gradient(to left, rgba($ui-base-color, 0), $ui-base-color); + } } .table th, -- cgit From fba0200765c14d0ada47a44b5a8603001c92e069 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 20 Sep 2018 18:21:58 +0200 Subject: [Glitch] Redesign forms, verify link ownership with rel="me" Port SCSS changes from f4d549d30081478b1fe2bde9d340262e132bb891 --- .../flavours/glitch/styles/accounts.scss | 14 + app/javascript/flavours/glitch/styles/admin.scss | 84 +++-- app/javascript/flavours/glitch/styles/basics.scss | 7 + .../flavours/glitch/styles/components/boost.scss | 7 - .../flavours/glitch/styles/containers.scss | 8 + app/javascript/flavours/glitch/styles/forms.scss | 357 ++++++++++++++------- 6 files changed, 318 insertions(+), 159 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/accounts.scss b/app/javascript/flavours/glitch/styles/accounts.scss index ac1989832..9568581ec 100644 --- a/app/javascript/flavours/glitch/styles/accounts.scss +++ b/app/javascript/flavours/glitch/styles/accounts.scss @@ -267,6 +267,20 @@ } } + .verified { + border: 1px solid rgba($valid-value-color, 0.5); + background: rgba($valid-value-color, 0.25); + + a { + color: $valid-value-color; + font-weight: 500; + } + + &__mark { + color: $valid-value-color; + } + } + dl:last-child { border-bottom: 0; } diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index eb3eaf11a..b8cc33039 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -1,3 +1,5 @@ +$no-columns-breakpoint: 600px; + .admin-wrapper { display: flex; justify-content: center; @@ -24,12 +26,22 @@ height: 100px; } + @media screen and (max-width: $no-columns-breakpoint) { + & > a:first-child { + display: none; + } + } + ul { list-style: none; border-radius: 4px 0 0 4px; overflow: hidden; margin-bottom: 20px; + @media screen and (max-width: $no-columns-breakpoint) { + margin-bottom: 0; + } + a { display: block; padding: 15px; @@ -62,20 +74,24 @@ a { border: 0; padding: 15px 35px; + } + } - &.selected { - color: $primary-text-color; - background-color: $ui-highlight-color; - border-bottom: 0; - border-radius: 0; + .simple-navigation-active-leaf a { + color: $primary-text-color; + background-color: $ui-highlight-color; + border-bottom: 0; + border-radius: 0; - &:hover { - background-color: lighten($ui-highlight-color, 5%); - } - } + &:hover { + background-color: lighten($ui-highlight-color, 5%); } } } + + & > ul > .simple-navigation-active-leaf a { + border-radius: 4px 0 0 4px; + } } .content-wrapper { @@ -89,11 +105,19 @@ padding-top: 60px; padding-left: 25px; + @media screen and (max-width: $no-columns-breakpoint) { + max-width: none; + padding: 15px; + padding-top: 30px; + } + h2 { color: $secondary-text-color; font-size: 24px; line-height: 28px; font-weight: 400; + padding-bottom: 40px; + border-bottom: 1px solid lighten($ui-base-color, 8%); margin-bottom: 40px; } @@ -108,7 +132,7 @@ h4 { text-transform: uppercase; font-size: 13px; - font-weight: 500; + font-weight: 700; color: $darker-text-color; padding-bottom: 8px; margin-bottom: 8px; @@ -122,6 +146,11 @@ font-weight: 400; } + .fields-group h6 { + color: $primary-text-color; + font-weight: 500; + } + & > p { font-size: 14px; line-height: 18px; @@ -167,30 +196,7 @@ } } - .simple_form { - max-width: 400px; - - &.edit_user, - &.new_form_admin_settings, - &.new_form_two_factor_confirmation, - &.new_form_delete_confirmation, - &.new_import, - &.new_domain_block, - &.edit_domain_block { - max-width: none; - } - - .form_two_factor_confirmation_code, - .form_delete_confirmation_password { - max-width: 400px; - } - - .actions { - max-width: 400px; - } - } - - @media screen and (max-width: 600px) { + @media screen and (max-width: $no-columns-breakpoint) { display: block; overflow-y: auto; -webkit-overflow-scrolling: touch; @@ -204,16 +210,8 @@ .sidebar { width: 100%; - padding: 10px 0; + padding: 0; height: auto; - - .logo { - margin: 20px auto; - } - } - - .content { - padding-top: 20px; } } } diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss index 11c91bbc9..9c2499ac4 100644 --- a/app/javascript/flavours/glitch/styles/basics.scss +++ b/app/javascript/flavours/glitch/styles/basics.scss @@ -1,3 +1,10 @@ +@function hex-color($color) { + @if type-of($color) == 'color' { + $color: str-slice(ie-hex-str($color), 4); + } + @return '%23' + unquote($color) +} + body { font-family: 'mastodon-font-sans-serif', sans-serif; background: darken($ui-base-color, 8%); diff --git a/app/javascript/flavours/glitch/styles/components/boost.scss b/app/javascript/flavours/glitch/styles/components/boost.scss index d92444042..f1ad041e9 100644 --- a/app/javascript/flavours/glitch/styles/components/boost.scss +++ b/app/javascript/flavours/glitch/styles/components/boost.scss @@ -1,10 +1,3 @@ -@function hex-color($color) { - @if type-of($color) == 'color' { - $color: str-slice(ie-hex-str($color), 4); - } - @return '%23' + unquote($color) -} - button.icon-button i.fa-retweet { background-image: url("data:image/svg+xml;utf8,"); diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index 17901f233..d1b9934d7 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -724,6 +724,14 @@ a { color: lighten($ui-highlight-color, 8%); } + + dl:first-child .verified { + border-radius: 0 4px 0 0; + } + + .verified a { + color: $valid-value-color; + } } .account__header__content { diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index 18019c29c..cbd3de94c 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -1,3 +1,5 @@ +$no-columns-breakpoint: 600px; + code { font-family: 'mastodon-font-monospace', monospace; font-weight: 400; @@ -13,6 +15,60 @@ code { .input { margin-bottom: 15px; overflow: hidden; + + &.hidden { + margin: 0; + } + + &.radio_buttons { + .radio { + margin-bottom: 15px; + + &:last-child { + margin-bottom: 0; + } + } + + .radio > label { + position: relative; + padding-left: 28px; + + input { + position: absolute; + top: -2px; + left: 0; + } + } + } + + &.boolean { + position: relative; + margin-bottom: 0; + + .label_input > label { + font-family: inherit; + font-size: 14px; + padding-top: 5px; + color: $primary-text-color; + display: block; + width: auto; + } + + .label_input, + .hint { + padding-left: 28px; + } + + .label_input__wrapper { + position: static; + } + + label.checkbox { + position: absolute; + top: 2px; + left: 0; + } + } } .row { @@ -27,9 +83,22 @@ code { } } + .hint { + color: $darker-text-color; + + a { + color: $highlight-text-color; + } + + code { + border-radius: 3px; + padding: 0.2em 0.4em; + background: darken($ui-base-color, 12%); + } + } + span.hint { display: block; - color: $darker-text-color; font-size: 12px; margin-top: 4px; } @@ -44,17 +113,6 @@ code { line-height: 18px; margin-top: 15px; margin-bottom: 0; - color: $darker-text-color; - - a { - color: $highlight-text-color; - } - } - - code { - border-radius: 3px; - padding: 0.2em 0.4em; - background: darken($ui-base-color, 12%); } } @@ -72,83 +130,60 @@ code { } } - .label_input { - display: flex; + .input.with_floating_label { + .label_input { + display: flex; - label { - flex: 0 0 auto; + & > label { + font-family: inherit; + font-size: 14px; + color: $primary-text-color; + font-weight: 500; + min-width: 150px; + flex: 0 0 auto; + } + + input, + select { + flex: 1 1 auto; + } } - input { - flex: 1 1 auto; + &.select .hint { + margin-top: 6px; + margin-left: 150px; } } .input.with_label { - padding: 15px 0; - margin-bottom: 0; - - .label_input { - flex-wrap: wrap; - align-items: flex-start; - } - - &.select .label_input { - align-items: initial; - } - .label_input > label { font-family: inherit; - font-size: 16px; + font-size: 14px; color: $primary-text-color; display: block; - padding-top: 5px; - margin-bottom: 5px; - flex: 1; - min-width: 150px; + margin-bottom: 8px; word-wrap: break-word; + font-weight: 500; + } - &.select { - flex: 0; - } - - & ~ * { - margin-left: 10px; - } + .hint { + margin-top: 6px; } ul { flex: 390px; } - - &.boolean { - padding: initial; - margin-bottom: initial; - - .label_input > label { - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; - } - - label.checkbox { - position: relative; - padding-left: 25px; - flex: 1 1 auto; - } - } } .input.with_block_label { - padding-top: 15px; + max-width: none; & > label { font-family: inherit; font-size: 16px; color: $primary-text-color; display: block; + font-weight: 500; padding-top: 5px; } @@ -161,49 +196,70 @@ code { } } + .required abbr { + text-decoration: none; + color: lighten($error-value-color, 12%); + } + .fields-group { margin-bottom: 25px; - } - .input.radio_buttons .radio label { - margin-bottom: 5px; - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; + .input:last-child { + margin-bottom: 0; + } } - .input.boolean { - margin-bottom: 5px; + .fields-row { + display: flex; + margin: 0 -10px; + padding-top: 5px; + margin-bottom: 25px; - label { - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; + .input { + max-width: none; } - label.checkbox { - position: relative; - padding-left: 25px; + &__column { + box-sizing: border-box; + padding: 0 10px; flex: 1 1 auto; + min-height: 1px; + + &-6 { + max-width: 50%; + } } - input[type=checkbox] { - position: absolute; - left: 0; - top: 5px; - margin: 0; + .fields-group:last-child, + .fields-row__column.fields-group { + margin-bottom: 0; } - .hint { - padding-left: 25px; - margin-left: 0; + @media screen and (max-width: $no-columns-breakpoint) { + display: block; + margin-bottom: 0; + + &__column { + max-width: none; + } + + .fields-group:last-child, + .fields-row__column.fields-group, + .fields-row__column { + margin-bottom: 25px; + } } } + .input.radio_buttons .radio label { + margin-bottom: 5px; + font-family: inherit; + font-size: 14px; + color: $primary-text-color; + display: block; + width: auto; + } + .check_boxes { .checkbox { label { @@ -232,12 +288,7 @@ code { input[type=email], input[type=password], textarea { - background: transparent; box-sizing: border-box; - border: 0; - border-bottom: 2px solid $ui-primary-color; - border-radius: 2px 2px 0 0; - padding: 7px 4px; font-size: 16px; color: $primary-text-color; display: block; @@ -245,23 +296,31 @@ code { outline: 0; font-family: inherit; resize: vertical; + background: darken($ui-base-color, 10%); + border: 1px solid darken($ui-base-color, 14%); + border-radius: 4px; + padding: 10px; &:invalid { box-shadow: none; } &:focus:invalid { - border-bottom-color: lighten($error-red, 12%); + border-color: lighten($error-red, 12%); } &:required:valid { - border-bottom-color: $valid-value-color; + border-color: $valid-value-color; + } + + &:hover { + border-color: darken($ui-base-color, 20%); } &:active, &:focus { - border-bottom-color: $highlight-text-color; - background: rgba($base-overlay-background, 0.1); + border-color: $highlight-text-color; + background: darken($ui-base-color, 8%); } } @@ -345,22 +404,32 @@ code { } select { + appearance: none; + box-sizing: border-box; font-size: 16px; - max-height: 29px; + color: $primary-text-color; + display: block; + width: 100%; + outline: 0; + font-family: inherit; + resize: vertical; + background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,") no-repeat right 8px center / auto 16px; + border: 1px solid darken($ui-base-color, 14%); + border-radius: 4px; + padding: 10px; + height: 41px; } - .input-with-append { - position: relative; - - .input input { - padding-right: 142px; + .label_input { + &__wrapper { + position: relative; } - .append { + &__append { position: absolute; - right: 0; - top: 0; - padding: 7px 4px; + right: 1px; + top: 1px; + padding: 10px; padding-bottom: 9px; font-size: 16px; color: $dark-text-color; @@ -379,7 +448,7 @@ code { right: 0; bottom: 1px; width: 5px; - background-image: linear-gradient(to right, rgba($ui-base-color, 0), $ui-base-color); + background-image: linear-gradient(to right, rgba(darken($ui-base-color, 10%), 0), darken($ui-base-color, 10%)); } } } @@ -455,6 +524,30 @@ code { } } +.quick-nav { + list-style: none; + margin-bottom: 25px; + font-size: 14px; + + li { + display: inline-block; + margin-right: 10px; + } + + a { + color: $highlight-text-color; + text-transform: uppercase; + text-decoration: none; + font-weight: 700; + + &:hover, + &:focus, + &:active { + color: lighten($highlight-text-color, 8%); + } + } +} + .oauth-prompt, .follow-prompt { margin-bottom: 30px; @@ -628,3 +721,49 @@ code { font-family: 'mastodon-font-monospace', monospace; } } + +.input-copy { + background: darken($ui-base-color, 10%); + border: 1px solid darken($ui-base-color, 14%); + border-radius: 4px; + display: flex; + align-items: center; + padding-right: 4px; + position: relative; + top: 1px; + transition: border-color 300ms linear; + + &__wrapper { + flex: 1 1 auto; + } + + input[type=text] { + background: transparent; + border: 0; + padding: 10px; + font-size: 14px; + font-family: 'mastodon-font-monospace', monospace; + } + + button { + flex: 0 0 auto; + margin: 4px; + text-transform: none; + font-weight: 400; + font-size: 14px; + padding: 7px 18px; + padding-bottom: 6px; + width: auto; + transition: background 300ms linear; + } + + &.copied { + border-color: $valid-value-color; + transition: none; + + button { + background: $valid-value-color; + transition: none; + } + } +} -- cgit From 5c6271887d8e1536029c954fe0784e628d152509 Mon Sep 17 00:00:00 2001 From: 霧島ひなた Date: Fri, 21 Sep 2018 15:28:21 +0900 Subject: translation glitch's features [ja] --- app/javascript/flavours/glitch/locales/ja.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/locales/ja.js b/app/javascript/flavours/glitch/locales/ja.js index f558d7ab7..209a02d1d 100644 --- a/app/javascript/flavours/glitch/locales/ja.js +++ b/app/javascript/flavours/glitch/locales/ja.js @@ -11,6 +11,7 @@ const messages = { 'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。', 'onboarding.page_one.welcome': '{domain}へようこそ!', 'onboarding.page_six.github': '{domain}はGlitchsocを使用しています。Glitchsocは{Mastodon}のフレンドリーな{fork}で、どんなMastodonアプリやインスタンスとも互換性があります。Glitchsocは完全に無料で、オープンソースです。{github}でバグ報告や機能要望あるいは貢獻をすることが可能です。', + 'settings.always_show_spoilers_field': '常にコンテンツワーニング設定を表示する(指定がない場合は通常投稿)', 'settings.auto_collapse': '自動折りたたみ', 'settings.auto_collapse_all': 'すべて', 'settings.auto_collapse_lengthy': '長いトゥート', @@ -20,7 +21,12 @@ const messages = { 'settings.auto_collapse_replies': '返信', 'settings.close': '閉じる', 'settings.collapsed_statuses': 'トゥート', + 'settings.confirm_missing_media_description': '画像に対する補助記載がないときに投稿前の警告を表示する', + 'settings.content_warnings': 'コンテンツワーニング', + 'settings.content_warnings_filter': '説明に指定した文字が含まれているものを自動で展開しないようにする', + 'settings.content_warnings.regexp': '正規表現', 'settings.enable_collapsed': 'トゥート折りたたみを有効にする', + 'settings.enable_content_warnings_auto_unfold': 'コンテンツワーニング指定されている投稿を常に表示する', 'settings.general': '一般', 'settings.image_backgrounds': '画像背景', 'settings.image_backgrounds_media': '折りたまれたメディア付きトゥートをプレビュー', @@ -28,15 +34,28 @@ const messages = { 'settings.media': 'メディア', 'settings.media_letterbox': 'メディアをレターボックス式で表示', 'settings.media_fullwidth': '全幅メディアプレビュー', + 'settings.notifications.favicon_badge': '通知アイコンに未読件数を表示する', + 'settings.notifications_opts': '通知の設定', + 'settings.notifications.tab_badge': '未読の通知があるとき、通知アイコンにマークを表示する', 'settings.preferences': 'ユーザー設定', 'settings.wide_view': 'ワイドビュー(Desktopレイアウトのみ)', 'settings.navbar_under': 'ナビを画面下部に移動させる(Mobileレイアウトのみ)', 'settings.compose_box_opts': 'コンポーズボックス設定', + 'settings.show_reply_counter': '投稿に対するリプライの数を表示する', 'settings.side_arm': 'セカンダリートゥートボタン', + 'settings.side_arm.none': '表示しない', + 'settings.side_arm_reply_mode': '返信時の投稿範囲', + 'settings.side_arm_reply_mode.copy': '返信先の投稿範囲を利用する', + 'settings.side_arm_reply_mode.keep': 'セカンダリートゥートボタンの設定を維持する', + 'settings.side_arm_reply_mode.restrict': '返信先の投稿範囲に制限する', 'settings.layout': 'レイアウト', + 'settings.layout_opts': 'レイアウトの設定', 'status.collapse': '折りたたむ', 'status.uncollapse': '折りたたみを解除', + 'confirmations.missing_media_description.message': '少なくとも1つの画像に視聴覚障害者のための画像説明が付与されていません。すべての画像に対して説明を付与することを望みます。', + 'confirmations.missing_media_description.confirm': 'このまま投稿', + 'favourite_modal.combo': '次からは {combo} を押せば、これをスキップできます。', 'home.column_settings.show_direct': 'DMを表示', @@ -68,4 +87,4 @@ const messages = { 'column.bookmarks': 'ブックマーク' }; -export default Object.assign({}, inherited, messages); +export default Object.assign({}, inherited, messages); \ No newline at end of file -- cgit From 5c9a2f5d77387792c6953a205de06cbe3bcbcac0 Mon Sep 17 00:00:00 2001 From: 霧島ひなた Date: Fri, 21 Sep 2018 15:29:42 +0900 Subject: change translation glitch's features [ja] --- app/javascript/flavours/glitch/locales/ja.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/locales/ja.js b/app/javascript/flavours/glitch/locales/ja.js index 209a02d1d..c323956c6 100644 --- a/app/javascript/flavours/glitch/locales/ja.js +++ b/app/javascript/flavours/glitch/locales/ja.js @@ -4,8 +4,8 @@ const messages = { 'getting_started.open_source_notice': 'Glitchsocは{Mastodon}によるフリーなオープンソースソフトウェアです。誰でもGitHub({github})から開発に參加したり、問題を報告したりできます。', 'layout.auto': '自動', 'layout.current_is': 'あなたの現在のレイアウト:', - 'layout.desktop': 'Desktop', - 'layout.mobile': 'Mobile', + 'layout.desktop': 'デスクトップ', + 'layout.single': 'モバイル', 'navigation_bar.app_settings': 'アプリ設定', 'getting_started.onboarding': '解説を表示', 'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。', @@ -34,12 +34,12 @@ const messages = { 'settings.media': 'メディア', 'settings.media_letterbox': 'メディアをレターボックス式で表示', 'settings.media_fullwidth': '全幅メディアプレビュー', + 'settings.navbar_under': 'ナビを画面下部に移動させる(モバイル レイアウトのみ)', 'settings.notifications.favicon_badge': '通知アイコンに未読件数を表示する', 'settings.notifications_opts': '通知の設定', 'settings.notifications.tab_badge': '未読の通知があるとき、通知アイコンにマークを表示する', 'settings.preferences': 'ユーザー設定', - 'settings.wide_view': 'ワイドビュー(Desktopレイアウトのみ)', - 'settings.navbar_under': 'ナビを画面下部に移動させる(Mobileレイアウトのみ)', + 'settings.wide_view': 'ワイドビュー(デスクトップ レイアウトのみ)', 'settings.compose_box_opts': 'コンポーズボックス設定', 'settings.show_reply_counter': '投稿に対するリプライの数を表示する', 'settings.side_arm': 'セカンダリートゥートボタン', -- cgit From 925c185ef9cfba24cdeb7c3555b7f75c55738cab Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 17 Sep 2018 14:19:35 +0200 Subject: Prevent clicks on video from initiating selections --- app/javascript/flavours/glitch/components/media_gallery.js | 6 ++++++ app/javascript/flavours/glitch/features/video/index.js | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index 1de12c5e0..605a2862b 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -78,6 +78,11 @@ class Item extends React.PureComponent { e.stopPropagation(); } + handleMouseDown = (e) => { + e.preventDefault(); + e.stopPropagation(); + } + render () { const { attachment, index, size, standalone, letterbox, displayWidth } = this.props; @@ -181,6 +186,7 @@ class Item extends React.PureComponent { onClick={this.handleClick} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} + onMouseDown={this.handleMouseDown} autoPlay={autoPlay} loop muted diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js index 65e10e0cf..5cbe01f26 100644 --- a/app/javascript/flavours/glitch/features/video/index.js +++ b/app/javascript/flavours/glitch/features/video/index.js @@ -135,7 +135,10 @@ export default class Video extends React.PureComponent { this.seek = c; } - handleClickRoot = e => e.stopPropagation(); + handleMouseDownRoot = e => { + e.preventDefault(); + e.stopPropagation(); + } handlePlay = () => { this.setState({ paused: false }); @@ -319,7 +322,7 @@ export default class Video extends React.PureComponent { ref={this.setPlayerRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} - onClick={this.handleClickRoot} + onMouseDown={this.handleMouseDownRoot} tabIndex={0} >
    - + -- cgit From 5833cc41c2a3e53332968dbeed384f565472eba4 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 21 Sep 2018 07:25:46 +0200 Subject: [Glitch] Add edit profile action button to profile Port some parts from 1a7a74ff76a129031a3fd6d73688ab9409899002 --- .../flavours/glitch/features/account/components/header.js | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js index eda0d637e..9cf2e9131 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.js +++ b/app/javascript/flavours/glitch/features/account/components/header.js @@ -15,6 +15,7 @@ const messages = defineMessages({ follow: { id: 'account.follow', defaultMessage: 'Follow' }, requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, + edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, }); @injectIntl @@ -27,6 +28,10 @@ export default class Header extends ImmutablePureComponent { intl: PropTypes.object.isRequired, }; + openEditProfile = () => { + window.open('/settings/profile', '_blank'); + } + render () { const { account, intl } = this.props; @@ -77,6 +82,12 @@ export default class Header extends ImmutablePureComponent {
    ); } + } else { + actionBtn = ( +
    + +
    + ); } if (account.get('moved') && !account.getIn(['relationship', 'following'])) { -- cgit From 9e8d776a77731598c1ad57c5d61d8c74dc04b5a4 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 21 Sep 2018 07:37:37 +0200 Subject: [Glitch] Display verified links in glitch flavor Port front-end changes from f4d549d30081478b1fe2bde9d340262e132bb891 to glitch-soc --- .../glitch/features/account/components/header.js | 14 +++++++++++++- .../flavours/glitch/styles/components/metadata.scss | 21 ++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js index 9cf2e9131..f0d36947d 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.js +++ b/app/javascript/flavours/glitch/features/account/components/header.js @@ -16,8 +16,18 @@ const messages = defineMessages({ requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, + link_verified_on: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' }, }); +const dateFormatOptions = { + month: 'short', + day: 'numeric', + year: 'numeric', + hour12: false, + hour: '2-digit', + minute: '2-digit', +}; + @injectIntl export default class Header extends ImmutablePureComponent { @@ -122,7 +132,9 @@ export default class Header extends ImmutablePureComponent { {fields.map((pair, i) => (
    -
    +
    + {pair.get('verified_at') && } +
    ))}
    diff --git a/app/javascript/flavours/glitch/styles/components/metadata.scss b/app/javascript/flavours/glitch/styles/components/metadata.scss index 2efe6cd66..32bdcdcf1 100644 --- a/app/javascript/flavours/glitch/styles/components/metadata.scss +++ b/app/javascript/flavours/glitch/styles/components/metadata.scss @@ -4,17 +4,11 @@ overflow: hidden; margin: 20px -10px -20px; border-bottom: 0; - - a { - text-decoration: none; - - &:hover{ - text-decoration: underline; - } - } + border-top: 0; dl { - border-top: 1px solid lighten($ui-base-color, 8%); + border-top: 1px solid lighten($ui-base-color, 4%); + border-bottom: 0; display: flex; } @@ -35,10 +29,6 @@ width: 120px; flex: 0 0 auto; font-weight: 500; - - a { - color: $primary-text-color; - } } dd { @@ -46,8 +36,9 @@ color: $primary-text-color; background: $ui-base-color; - a { - color: $highlight-text-color; + &.verified { + border: 1px solid rgba($valid-value-color, 0.5); + background: rgba($valid-value-color, 0.25); } } } -- cgit From 23e7c1c765f5e500d369fcef9f020e4eb5b337d5 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 21 Sep 2018 08:38:39 +0200 Subject: Fix background being transparent for verified link fields --- app/javascript/flavours/glitch/styles/components/metadata.scss | 1 + 1 file changed, 1 insertion(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/styles/components/metadata.scss b/app/javascript/flavours/glitch/styles/components/metadata.scss index 32bdcdcf1..da045574a 100644 --- a/app/javascript/flavours/glitch/styles/components/metadata.scss +++ b/app/javascript/flavours/glitch/styles/components/metadata.scss @@ -7,6 +7,7 @@ border-top: 0; dl { + background: $ui-base-color; border-top: 1px solid lighten($ui-base-color, 4%); border-bottom: 0; display: flex; -- cgit From d3426ed87ab3be29dece3f8d2c22bece9dda32dc Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 21 Sep 2018 23:20:06 +0200 Subject: Disable the “TOOT” button (and secondary toot button) if the toot text is empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/javascript/flavours/glitch/features/composer/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js index ff01408e7..c1bd77844 100644 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ b/app/javascript/flavours/glitch/features/composer/index.js @@ -242,7 +242,7 @@ const handlers = { } // Submit disabled: - if (isSubmitting || isUploading || (!!text.length && !text.trim().length && !anyMedia)) { + if (isSubmitting || isUploading || (!text.trim().length && !anyMedia)) { return; } @@ -415,7 +415,7 @@ class Composer extends React.Component { spoilersAlwaysOn, } = this.props; - let disabledButton = isSubmitting || isUploading || (!!text.length && !text.trim().length && !anyMedia); + let disabledButton = isSubmitting || isUploading || (!text.trim().length && !anyMedia); return (
    -- cgit From fa18859b206bbfd61e08a8f8b39de972dcf3b440 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 22 Sep 2018 23:08:03 +0200 Subject: [Glitch] Adjust beforeUnload conditions Port 05f90e3695c410526fc7fa79fc6a9bdaa717cb87 to glitch-soc --- app/javascript/flavours/glitch/features/ui/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 064804b79..ecbac1f8f 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -60,7 +60,8 @@ const messages = defineMessages({ }); const mapStateToProps = state => ({ - hasComposingText: state.getIn(['compose', 'text']) !== '', + hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0, + hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0, layout: state.getIn(['local_settings', 'layout']), isWide: state.getIn(['local_settings', 'stretch']), navbarUnder: state.getIn(['local_settings', 'navbar_under']), @@ -113,6 +114,7 @@ export default class UI extends React.Component { navbarUnder: PropTypes.bool, isComposing: PropTypes.bool, hasComposingText: PropTypes.bool, + hasMediaAttachments: PropTypes.bool, match: PropTypes.object.isRequired, location: PropTypes.object.isRequired, history: PropTypes.object.isRequired, @@ -128,9 +130,9 @@ export default class UI extends React.Component { }; handleBeforeUnload = (e) => { - const { intl, hasComposingText } = this.props; + const { intl, hasComposingText, hasMediaAttachments } = this.props; - if (hasComposingText) { + if (hasComposingText || hasMediaAttachments) { // Setting returnValue to any string causes confirmation dialog. // Many browsers no longer display this text to users, // but we set user-friendly message for other browsers, e.g. Edge. -- cgit From 9594c68532b3baeba340c426cf3490fa826fc017 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 28 Sep 2018 18:44:55 +0200 Subject: Scroll to textarea when composing a toot --- app/javascript/flavours/glitch/features/composer/index.js | 1 + 1 file changed, 1 insertion(+) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js index ff01408e7..0820ab2e3 100644 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ b/app/javascript/flavours/glitch/features/composer/index.js @@ -347,6 +347,7 @@ class Composer extends React.Component { if (textarea) { textarea.setSelectionRange(selectionStart, selectionEnd); textarea.focus(); + textarea.scrollIntoView(); } // Refocuses the textarea after submitting. -- cgit From 15134beb1e45be35a5c0091220c9074b79f64653 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 28 Sep 2018 18:18:57 +0200 Subject: Fix styling issue in “Compose box options” local settings page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/javascript/flavours/glitch/features/local_settings/page/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index 2e14c9dd5..3859c1947 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -96,7 +96,7 @@ export default class LocalSettingsPage extends React.PureComponent {
    ), ({ intl, onChange, settings }) => ( -
    +

    Date: Fri, 28 Sep 2018 20:58:03 +0200 Subject: Make pre-selection of usernames optional when replying to a toot Fixes #751 --- app/javascript/flavours/glitch/features/composer/index.js | 5 ++++- .../flavours/glitch/features/local_settings/page/index.js | 8 ++++++++ app/javascript/flavours/glitch/reducers/local_settings.js | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js index ff01408e7..1280af75e 100644 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ b/app/javascript/flavours/glitch/features/composer/index.js @@ -102,6 +102,7 @@ function mapStateToProps (state) { anyMedia: state.getIn(['compose', 'media_attachments']).size > 0, spoilersAlwaysOn: spoilersAlwaysOn, mediaDescriptionConfirmation: state.getIn(['local_settings', 'confirm_missing_media_description']), + preselectOnReply: state.getIn(['local_settings', 'preselect_on_reply']), }; }; @@ -328,13 +329,14 @@ class Composer extends React.Component { isSubmitting, preselectDate, text, + preselectOnReply, } = this.props; let selectionEnd, selectionStart; // Caret/selection handling. if (focusDate !== prevProps.focusDate) { switch (true) { - case preselectDate !== prevProps.preselectDate: + case preselectDate !== prevProps.preselectDate && preselectOnReply: selectionStart = text.search(/\s/) + 1; selectionEnd = text.length; break; @@ -533,6 +535,7 @@ Composer.propTypes = { anyMedia: PropTypes.bool, spoilersAlwaysOn: PropTypes.bool, mediaDescriptionConfirmation: PropTypes.bool, + preselectOnReply: PropTypes.bool, // Dispatch props. onCancelReply: PropTypes.func, diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index 3859c1947..5b4e0cb01 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -106,6 +106,14 @@ export default class LocalSettingsPage extends React.PureComponent { > + + + Date: Sat, 29 Sep 2018 16:44:02 -0700 Subject: Add option to hide action bar in collapsed toots --- app/javascript/flavours/glitch/components/status.js | 2 +- .../flavours/glitch/features/local_settings/page/index.js | 12 ++++++++++++ app/javascript/flavours/glitch/locales/en.js | 1 + app/javascript/flavours/glitch/reducers/local_settings.js | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch') diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index 4d47660c2..665aa457a 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -566,7 +566,7 @@ export default class Status extends ImmutablePureComponent { parseClick={parseClick} disabled={!router} /> - {!isCollapsed || !muted ? ( + {!isCollapsed || !(muted || !settings.getIn(['collapsed', 'show_action_bar'])) ? ( +
    +

    + + + +
    ), ({ onChange, settings }) => ( diff --git a/app/javascript/flavours/glitch/locales/en.js b/app/javascript/flavours/glitch/locales/en.js index fb3763ced..90e924d4a 100644 --- a/app/javascript/flavours/glitch/locales/en.js +++ b/app/javascript/flavours/glitch/locales/en.js @@ -18,6 +18,7 @@ const messages = { 'settings.auto_collapse_notifications': 'Notifications', 'settings.auto_collapse_reblogs': 'Boosts', 'settings.auto_collapse_replies': 'Replies', + 'settings.show_action_bar': 'Show action buttons in collapsed toots', 'settings.close': 'Close', 'settings.collapsed_statuses': 'Collapsed toots', 'settings.enable_collapsed': 'Enable collapsed toots', diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js index 260a9f08f..19233a963 100644 --- a/app/javascript/flavours/glitch/reducers/local_settings.js +++ b/app/javascript/flavours/glitch/reducers/local_settings.js @@ -33,6 +33,7 @@ const initialState = ImmutableMap({ user_backgrounds : false, preview_images : false, }), + show_action_bar : true, }), media : ImmutableMap({ letterbox : true, -- cgit