about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/javascript/mastodon/features/ui/util/optional_motion.js58
-rwxr-xr-xapp/views/layouts/application.html.haml1
2 files changed, 41 insertions, 18 deletions
diff --git a/app/javascript/mastodon/features/ui/util/optional_motion.js b/app/javascript/mastodon/features/ui/util/optional_motion.js
index 4276eeaa4..af6368738 100644
--- a/app/javascript/mastodon/features/ui/util/optional_motion.js
+++ b/app/javascript/mastodon/features/ui/util/optional_motion.js
@@ -1,34 +1,56 @@
 // Like react-motion's Motion, but checks to see if the user prefers
 // reduced motion and uses a cross-fade in those cases.
 
+import React from 'react';
 import Motion from 'react-motion/lib/Motion';
-import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
 
 const stylesToKeep = ['opacity', 'backgroundOpacity'];
 
+let reduceMotion;
+
 const extractValue = (value) => {
   // This is either an object with a "val" property or it's a number
   return (typeof value === 'object' && value && 'val' in value) ? value.val : value;
 };
 
-const mapStateToProps = (state, ownProps) => {
-  const reduceMotion = state.getIn(['meta', 'reduce_motion']);
-
-  if (reduceMotion) {
-    const { style, defaultStyle } = ownProps;
+class OptionalMotion extends React.Component {
 
-    Object.keys(style).forEach(key => {
-      if (stylesToKeep.includes(key)) {
-        return;
-      }
-      // If it's setting an x or height or scale or some other value, we need
-      // to preserve the end-state value without actually animating it
-      style[key] = defaultStyle[key] = extractValue(style[key]);
-    });
+  static propTypes = {
+    defaultStyle: PropTypes.object,
+    style: PropTypes.object,
+    children: PropTypes.func,
+  }
 
-    return { style, defaultStyle };
+  render() {
+
+    const { style, defaultStyle, children } = this.props;
+
+    if (typeof reduceMotion !== 'boolean') {
+      // This never changes without a page reload, so we can just grab it
+      // once from the body classes as opposed to using Redux's connect(),
+      // which would unnecessarily update every state change
+      reduceMotion = document.body.classList.contains('reduce-motion');
+    }
+    if (reduceMotion) {
+      Object.keys(style).forEach(key => {
+        if (stylesToKeep.includes(key)) {
+          return;
+        }
+        // If it's setting an x or height or scale or some other value, we need
+        // to preserve the end-state value without actually animating it
+        style[key] = defaultStyle[key] = extractValue(style[key]);
+      });
+    }
+
+    return (
+      <Motion style={style} defaultStyle={defaultStyle}>
+        {children}
+      </Motion>
+    );
   }
-  return {};
-};
 
-export default connect(mapStateToProps)(Motion);
+}
+
+
+export default OptionalMotion;
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 24b74c787..b1fd9ef40 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -29,6 +29,7 @@
     = yield :header_tags
 
   - body_classes ||= @body_classes || ''
+  - body_classes += ' reduce-motion' if current_account&.user&.setting_reduce_motion
   - body_classes += ' system-font' if current_account&.user&.setting_system_font_ui
 
   %body{ class: add_rtl_body_class(body_classes) }