From 3bbe39f233274cb64d3c2b04fa737ab5408bd7ac Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 8 Jul 2023 20:01:08 +0200 Subject: [PATCH 1/5] [Glitch] Add toast with option to open post after publishing in web UI Port a7ca33ad96d4ff8ae3b714d7dfbaebc962a86c27 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/alerts.js | 64 +++++++++---------- .../flavours/glitch/actions/compose.js | 18 ++++-- .../containers/column_settings_container.js | 4 +- .../ui/containers/notifications_container.js | 37 +++++------ .../flavours/glitch/reducers/alerts.js | 19 +++--- .../flavours/glitch/selectors/index.js | 28 +++----- .../glitch/styles/components/misc.scss | 59 +++++++++++++++++ 7 files changed, 144 insertions(+), 85 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/alerts.js b/app/javascript/flavours/glitch/actions/alerts.js index 0220b0af58..051a9675b3 100644 --- a/app/javascript/flavours/glitch/actions/alerts.js +++ b/app/javascript/flavours/glitch/actions/alerts.js @@ -12,52 +12,48 @@ export const ALERT_DISMISS = 'ALERT_DISMISS'; export const ALERT_CLEAR = 'ALERT_CLEAR'; export const ALERT_NOOP = 'ALERT_NOOP'; -export function dismissAlert(alert) { - return { - type: ALERT_DISMISS, - alert, - }; -} +export const dismissAlert = alert => ({ + type: ALERT_DISMISS, + alert, +}); -export function clearAlert() { - return { - type: ALERT_CLEAR, - }; -} +export const clearAlert = () => ({ + type: ALERT_CLEAR, +}); -export function showAlert(title = messages.unexpectedTitle, message = messages.unexpectedMessage, message_values = undefined) { - return { - type: ALERT_SHOW, - title, - message, - message_values, - }; -} +export const showAlert = alert => ({ + type: ALERT_SHOW, + alert, +}); -export function showAlertForError(error, skipNotFound = false) { +export const showAlertForError = (error, skipNotFound = false) => { if (error.response) { const { data, status, statusText, headers } = error.response; + // Skip these errors as they are reflected in the UI if (skipNotFound && (status === 404 || status === 410)) { - // Skip these errors as they are reflected in the UI return { type: ALERT_NOOP }; } + // Rate limit errors if (status === 429 && headers['x-ratelimit-reset']) { - const reset_date = new Date(headers['x-ratelimit-reset']); - return showAlert(messages.rateLimitedTitle, messages.rateLimitedMessage, { 'retry_time': reset_date }); + return showAlert({ + title: messages.rateLimitedTitle, + message: messages.rateLimitedMessage, + values: { 'retry_time': new Date(headers['x-ratelimit-reset']) }, + }); } - let message = statusText; - let title = `${status}`; - - if (data.error) { - message = data.error; - } - - return showAlert(title, message); - } else { - console.error(error); - return showAlert(); + return showAlert({ + title: `${status}`, + message: data.error || statusText, + }); } + + console.error(error); + + return showAlert({ + title: messages.unexpectedTitle, + message: messages.unexpectedMessage, + }); } diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 8242ec6c84..69eb77881a 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -89,6 +89,8 @@ export const COMPOSE_FOCUS = 'COMPOSE_FOCUS'; const messages = defineMessages({ uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' }, uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, + open: { id: 'compose.published.open', defaultMessage: 'Open' }, + published: { id: 'compose.published.body', defaultMessage: 'Post published.' }, }); export const ensureComposeIsVisible = (getState, routerHistory) => { @@ -274,6 +276,13 @@ export function submitCompose(routerHistory) { } else if (statusId === null && response.data.visibility === 'direct') { insertIfOnline('direct'); } + + dispatch(showAlert({ + message: messages.published, + action: messages.open, + dismissAfter: 10000, + onClick: () => routerHistory.push(`/@${response.data.account.username}/${response.data.id}`), + })); }).catch(function (error) { dispatch(submitComposeFail(error)); }); @@ -310,18 +319,19 @@ export function doodleSet(options) { export function uploadCompose(files) { return function (dispatch, getState) { const uploadLimit = 4; - const media = getState().getIn(['compose', 'media_attachments']); - const pending = getState().getIn(['compose', 'pending_media_attachments']); + const media = getState().getIn(['compose', 'media_attachments']); + const pending = getState().getIn(['compose', 'pending_media_attachments']); const progress = new Array(files.length).fill(0); + let total = Array.from(files).reduce((a, v) => a + v.size, 0); if (files.length + media.size + pending > uploadLimit) { - dispatch(showAlert(undefined, messages.uploadErrorLimit)); + dispatch(showAlert({ message: messages.uploadErrorLimit })); return; } if (getState().getIn(['compose', 'poll'])) { - dispatch(showAlert(undefined, messages.uploadErrorPoll)); + dispatch(showAlert({ message: messages.uploadErrorPoll })); return; } diff --git a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js index b63796a8b2..1e62ed9a5a 100644 --- a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js @@ -32,7 +32,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ if (permission === 'granted') { dispatch(changePushNotifications(path.slice(1), checked)); } else { - dispatch(showAlert(undefined, messages.permissionDenied)); + dispatch(showAlert({ message: messages.permissionDenied })); } })); } else { @@ -47,7 +47,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ if (permission === 'granted') { dispatch(changeSetting(['notifications', ...path], checked)); } else { - dispatch(showAlert(undefined, messages.permissionDenied)); + dispatch(showAlert({ message: messages.permissionDenied })); } })); } else { diff --git a/app/javascript/flavours/glitch/features/ui/containers/notifications_container.js b/app/javascript/flavours/glitch/features/ui/containers/notifications_container.js index c1d19f7100..3d60cfdad1 100644 --- a/app/javascript/flavours/glitch/features/ui/containers/notifications_container.js +++ b/app/javascript/flavours/glitch/features/ui/containers/notifications_container.js @@ -7,26 +7,27 @@ import { NotificationStack } from 'react-notification'; import { dismissAlert } from '../../../actions/alerts'; import { getAlerts } from '../../../selectors'; -const mapStateToProps = (state, { intl }) => { - const notifications = getAlerts(state); +const formatIfNeeded = (intl, message, values) => { + if (typeof message === 'object') { + return intl.formatMessage(message, values); + } - notifications.forEach(notification => ['title', 'message'].forEach(key => { - const value = notification[key]; - - if (typeof value === 'object') { - notification[key] = intl.formatMessage(value, notification[`${key}_values`]); - } - })); - - return { notifications }; + return message; }; -const mapDispatchToProps = (dispatch) => { - return { - onDismiss: alert => { - dispatch(dismissAlert(alert)); - }, - }; -}; +const mapStateToProps = (state, { intl }) => ({ + notifications: getAlerts(state).map(alert => ({ + ...alert, + action: formatIfNeeded(intl, alert.action, alert.values), + title: formatIfNeeded(intl, alert.title, alert.values), + message: formatIfNeeded(intl, alert.message, alert.values), + })), +}); + +const mapDispatchToProps = (dispatch) => ({ + onDismiss (alert) { + dispatch(dismissAlert(alert)); + }, +}); export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(NotificationStack)); diff --git a/app/javascript/flavours/glitch/reducers/alerts.js b/app/javascript/flavours/glitch/reducers/alerts.js index bd49d748f9..1ca9b62a02 100644 --- a/app/javascript/flavours/glitch/reducers/alerts.js +++ b/app/javascript/flavours/glitch/reducers/alerts.js @@ -1,4 +1,4 @@ -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { List as ImmutableList } from 'immutable'; import { ALERT_SHOW, @@ -8,17 +8,20 @@ import { const initialState = ImmutableList([]); +let id = 0; + +const addAlert = (state, alert) => + state.push({ + key: id++, + ...alert, + }); + export default function alerts(state = initialState, action) { switch(action.type) { case ALERT_SHOW: - return state.push(ImmutableMap({ - key: state.size > 0 ? state.last().get('key') + 1 : 0, - title: action.title, - message: action.message, - message_values: action.message_values, - })); + return addAlert(state, action.alert); case ALERT_DISMISS: - return state.filterNot(item => item.get('key') === action.alert.key); + return state.filterNot(item => item.key === action.alert.key); case ALERT_CLEAR: return state.clear(); default: diff --git a/app/javascript/flavours/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js index 74188aff6d..943804eed6 100644 --- a/app/javascript/flavours/glitch/selectors/index.js +++ b/app/javascript/flavours/glitch/selectors/index.js @@ -85,26 +85,16 @@ export const makeGetPictureInPicture = () => { })); }; -const getAlertsBase = state => state.get('alerts'); +const ALERT_DEFAULTS = { + dismissAfter: 5000, + style: false, +}; -export const getAlerts = createSelector([getAlertsBase], (base) => { - let arr = []; - - base.forEach(item => { - arr.push({ - message: item.get('message'), - message_values: item.get('message_values'), - title: item.get('title'), - key: item.get('key'), - dismissAfter: 5000, - barStyle: { - zIndex: 200, - }, - }); - }); - - return arr; -}); +export const getAlerts = createSelector(state => state.get('alerts'), alerts => + alerts.map(item => ({ + ...ALERT_DEFAULTS, + ...item, + })).toArray()); export const makeGetNotification = () => createSelector([ (_, base) => base, diff --git a/app/javascript/flavours/glitch/styles/components/misc.scss b/app/javascript/flavours/glitch/styles/components/misc.scss index f16504c93e..6c0f6f77e1 100644 --- a/app/javascript/flavours/glitch/styles/components/misc.scss +++ b/app/javascript/flavours/glitch/styles/components/misc.scss @@ -1675,3 +1675,62 @@ noscript { opacity: 1; } } + +.notification-list { + position: fixed; + bottom: 2rem; + inset-inline-start: 0; + z-index: 999; + display: flex; + flex-direction: column; + gap: 4px; +} + +.notification-bar { + flex: 0 0 auto; + position: relative; + inset-inline-start: -100%; + width: auto; + padding: 15px; + margin: 0; + color: $primary-text-color; + background: rgba($black, 0.85); + backdrop-filter: blur(8px); + border: 1px solid rgba(lighten($ui-base-color, 4%), 0.85); + border-radius: 8px; + box-shadow: 0 10px 15px -3px rgba($base-shadow-color, 0.25), + 0 4px 6px -4px rgba($base-shadow-color, 0.25); + cursor: default; + transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1); + transform: translateZ(0); + font-size: 15px; + line-height: 21px; + + &.notification-bar-active { + inset-inline-start: 1rem; + } +} + +.notification-bar-title { + margin-inline-end: 5px; +} + +.notification-bar-title, +.notification-bar-action { + font-weight: 700; +} + +.notification-bar-action { + text-transform: uppercase; + margin-inline-start: 10px; + cursor: pointer; + color: $highlight-text-color; + border-radius: 4px; + padding: 0 4px; + + &:hover, + &:focus, + &:active { + background: rgba($ui-base-color, 0.85); + } +} From 811b8b200e30c6bfba015b465bb1ad98de4d8b1e Mon Sep 17 00:00:00 2001 From: Stanislas Signoud Date: Tue, 11 Jul 2023 23:30:21 +0200 Subject: [PATCH 2/5] [Glitch] Use invariant colors on notification toasts Port ca955ada0bd69970191f3c1f2ac345f8bcb3fffc to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components/misc.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/components/misc.scss b/app/javascript/flavours/glitch/styles/components/misc.scss index 6c0f6f77e1..9a1ba64537 100644 --- a/app/javascript/flavours/glitch/styles/components/misc.scss +++ b/app/javascript/flavours/glitch/styles/components/misc.scss @@ -1693,10 +1693,10 @@ noscript { width: auto; padding: 15px; margin: 0; - color: $primary-text-color; + color: $white; background: rgba($black, 0.85); backdrop-filter: blur(8px); - border: 1px solid rgba(lighten($ui-base-color, 4%), 0.85); + border: 1px solid rgba(lighten($classic-base-color, 4%), 0.85); border-radius: 8px; box-shadow: 0 10px 15px -3px rgba($base-shadow-color, 0.25), 0 4px 6px -4px rgba($base-shadow-color, 0.25); @@ -1724,7 +1724,7 @@ noscript { text-transform: uppercase; margin-inline-start: 10px; cursor: pointer; - color: $highlight-text-color; + color: $blurple-300; border-radius: 4px; padding: 0 4px; From ea004108b8564eb17151adba7500d39cca5aa568 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Thu, 28 Sep 2023 10:39:38 +0200 Subject: [PATCH 3/5] [Glitch] Make notification respect reduce-motion Port 6d0767558a86c1ae3c42cb5ab0f6f78a2e93c1eb to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components/misc.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/components/misc.scss b/app/javascript/flavours/glitch/styles/components/misc.scss index 9a1ba64537..24ac12e16a 100644 --- a/app/javascript/flavours/glitch/styles/components/misc.scss +++ b/app/javascript/flavours/glitch/styles/components/misc.scss @@ -1701,14 +1701,17 @@ noscript { box-shadow: 0 10px 15px -3px rgba($base-shadow-color, 0.25), 0 4px 6px -4px rgba($base-shadow-color, 0.25); cursor: default; - transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1); - transform: translateZ(0); font-size: 15px; line-height: 21px; &.notification-bar-active { inset-inline-start: 1rem; } + + .no-reduce-motion & { + transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1); + transform: translateZ(0); + } } .notification-bar-title { From 9ac73a1fbf0f6290a5c477ab4efe1deb8e01077b Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 9 Oct 2023 13:38:29 +0200 Subject: [PATCH 4/5] [Glitch] Change `eslint` config to autofix missing comma and indentation in JS files Partial port of 774e1189d26fffd914107a4236f6287043c988f8 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/alerts.js | 2 +- app/javascript/flavours/glitch/styles/components/misc.scss | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/alerts.js b/app/javascript/flavours/glitch/actions/alerts.js index 051a9675b3..42834146bf 100644 --- a/app/javascript/flavours/glitch/actions/alerts.js +++ b/app/javascript/flavours/glitch/actions/alerts.js @@ -56,4 +56,4 @@ export const showAlertForError = (error, skipNotFound = false) => { title: messages.unexpectedTitle, message: messages.unexpectedMessage, }); -} +}; diff --git a/app/javascript/flavours/glitch/styles/components/misc.scss b/app/javascript/flavours/glitch/styles/components/misc.scss index 24ac12e16a..5ec55b1d4d 100644 --- a/app/javascript/flavours/glitch/styles/components/misc.scss +++ b/app/javascript/flavours/glitch/styles/components/misc.scss @@ -1698,7 +1698,8 @@ noscript { backdrop-filter: blur(8px); border: 1px solid rgba(lighten($classic-base-color, 4%), 0.85); border-radius: 8px; - box-shadow: 0 10px 15px -3px rgba($base-shadow-color, 0.25), + box-shadow: + 0 10px 15px -3px rgba($base-shadow-color, 0.25), 0 4px 6px -4px rgba($base-shadow-color, 0.25); cursor: default; font-size: 15px; From cede2f533c12975fbc70ad4ca35f9ac5f50bb1d2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 25 Aug 2023 22:03:04 +0200 Subject: [PATCH 5/5] [Glitch] Fix toast saying "published" instead of "saved" after editing post in web UI Port 71641766f2ca6555fe19b309e9bd9f2455575bcc to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/compose.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 69eb77881a..707c21c380 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -91,6 +91,7 @@ const messages = defineMessages({ uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, open: { id: 'compose.published.open', defaultMessage: 'Open' }, published: { id: 'compose.published.body', defaultMessage: 'Post published.' }, + saved: { id: 'compose.saved.body', defaultMessage: 'Post saved.' }, }); export const ensureComposeIsVisible = (getState, routerHistory) => { @@ -278,7 +279,7 @@ export function submitCompose(routerHistory) { } dispatch(showAlert({ - message: messages.published, + message: statusId === null ? messages.published : messages.saved, action: messages.open, dismissAfter: 10000, onClick: () => routerHistory.push(`/@${response.data.account.username}/${response.data.id}`),