فهرست منبع

Merge pull request #8354 from overleaf/em-halt-on-error-animation

Animation when setting "Stop on first error"

GitOrigin-RevId: 9639e2c815d1eaf57f3392131f9a484a6a1a0a9e
Eric Mc Sween 4 سال پیش
والد
کامیت
a2532ef968

+ 9 - 1
services/web/frontend/js/features/pdf-preview/components/pdf-compile-button.js

@@ -11,10 +11,12 @@ import getMeta from '../../../utils/meta'
 
 function PdfCompileButton() {
   const {
+    animateCompileDropdownArrow,
     autoCompile,
     compiling,
     draft,
     hasChanges,
+    setAnimateCompileDropdownArrow,
     setAutoCompile,
     setDraft,
     setStopOnValidationError,
@@ -46,8 +48,14 @@ function PdfCompileButton() {
 
       <Dropdown.Toggle
         aria-label={t('toggle_compile_options_menu')}
-        className="btn-recompile"
+        className={classnames({
+          'btn-recompile': true,
+          'btn-recompile-animate': animateCompileDropdownArrow,
+        })}
         bsStyle="success"
+        onAnimationEnd={() => {
+          setAnimateCompileDropdownArrow(false)
+        }}
       />
 
       <Dropdown.Menu>

+ 4 - 2
services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.js

@@ -168,13 +168,15 @@ function TimedOutLogEntry() {
   const { enableStopOnFirstError } = useStopOnFirstError({
     eventSource: 'timeout',
   })
-  const { startCompile, lastCompileOptions } = useCompileContext()
+  const { startCompile, lastCompileOptions, setAnimateCompileDropdownArrow } =
+    useCompileContext()
   const showStopOnFirstError = getMeta('ol-showStopOnFirstError')
 
   const handleEnableStopOnFirstErrorClick = useCallback(() => {
     enableStopOnFirstError()
     startCompile({ stopOnFirstError: true })
-  }, [enableStopOnFirstError, startCompile])
+    setAnimateCompileDropdownArrow(true)
+  }, [enableStopOnFirstError, startCompile, setAnimateCompileDropdownArrow])
 
   if (showStopOnFirstError) {
     return (

+ 3 - 2
services/web/frontend/js/features/pdf-preview/components/stop-on-first-error-prompt.js

@@ -7,7 +7,7 @@ import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-err
 
 export default function StopOnFirstErrorPrompt() {
   const { t } = useTranslation()
-  const { startCompile } = useCompileContext()
+  const { startCompile, setAnimateCompileDropdownArrow } = useCompileContext()
   const { disableStopOnFirstError } = useStopOnFirstError({
     eventSource: 'logs-pane',
   })
@@ -15,7 +15,8 @@ export default function StopOnFirstErrorPrompt() {
   const handleDisableButtonClick = useCallback(() => {
     disableStopOnFirstError()
     startCompile({ stopOnFirstError: false })
-  }, [disableStopOnFirstError, startCompile])
+    setAnimateCompileDropdownArrow(true)
+  }, [disableStopOnFirstError, startCompile, setAnimateCompileDropdownArrow])
 
   return (
     <PdfLogEntry

+ 4 - 2
services/web/frontend/js/features/preview/components/preview-logs-pane-max-entries.js

@@ -11,7 +11,8 @@ import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-err
 function PreviewLogsPaneMaxEntries({ totalEntries, entriesShown, hasErrors }) {
   const { t } = useTranslation()
   const showStopOnFirstError = getMeta('ol-showStopOnFirstError')
-  const { startCompile, stoppedOnFirstError } = useCompileContext()
+  const { startCompile, stoppedOnFirstError, setAnimateCompileDropdownArrow } =
+    useCompileContext()
   const { enableStopOnFirstError } = useStopOnFirstError({
     eventSource: 'too-many-logs',
   })
@@ -24,7 +25,8 @@ function PreviewLogsPaneMaxEntries({ totalEntries, entriesShown, hasErrors }) {
   const handleEnableStopOnFirstErrorClick = useCallback(() => {
     enableStopOnFirstError()
     startCompile({ stopOnFirstError: true })
-  }, [enableStopOnFirstError, startCompile])
+    setAnimateCompileDropdownArrow(true)
+  }, [enableStopOnFirstError, startCompile, setAnimateCompileDropdownArrow])
 
   return (
     <div className="log-entry" aria-label={t('log_entry_maximum_entries')}>

+ 18 - 0
services/web/frontend/js/shared/context/detach-compile-context.js

@@ -20,6 +20,7 @@ export function DetachCompileProvider({ children }) {
   }
 
   const {
+    animateCompileDropdownArrow: _animateCompileDropdownArrow,
     autoCompile: _autoCompile,
     clearingCache: _clearingCache,
     clsiServerId: _clsiServerId,
@@ -38,6 +39,7 @@ export function DetachCompileProvider({ children }) {
     pdfViewer: _pdfViewer,
     position: _position,
     rawLog: _rawLog,
+    setAnimateCompileDropdownArrow: _setAnimateCompileDropdownArrow,
     setAutoCompile: _setAutoCompile,
     setDraft: _setDraft,
     setError: _setError,
@@ -64,6 +66,12 @@ export function DetachCompileProvider({ children }) {
     clearCache: _clearCache,
   } = localCompileContext
 
+  const [animateCompileDropdownArrow] = useDetachStateWatcher(
+    'animateCompileDropdownArrow',
+    _animateCompileDropdownArrow,
+    'detacher',
+    'detached'
+  )
   const [autoCompile] = useDetachStateWatcher(
     'autoCompile',
     _autoCompile,
@@ -199,6 +207,12 @@ export function DetachCompileProvider({ children }) {
     'detached'
   )
 
+  const setAnimateCompileDropdownArrow = useDetachAction(
+    'setAnimateCompileDropdownArrow',
+    _setAnimateCompileDropdownArrow,
+    'detached',
+    'detacher'
+  )
   const setAutoCompile = useDetachAction(
     'setAutoCompile',
     _setAutoCompile,
@@ -310,6 +324,7 @@ export function DetachCompileProvider({ children }) {
 
   const value = useMemo(
     () => ({
+      animateCompileDropdownArrow,
       autoCompile,
       clearCache,
       clearingCache,
@@ -330,6 +345,7 @@ export function DetachCompileProvider({ children }) {
       position,
       rawLog,
       recompileFromScratch,
+      setAnimateCompileDropdownArrow,
       setAutoCompile,
       setCompiling,
       setDraft,
@@ -354,6 +370,7 @@ export function DetachCompileProvider({ children }) {
       cleanupCompileResult,
     }),
     [
+      animateCompileDropdownArrow,
       autoCompile,
       clearCache,
       clearingCache,
@@ -374,6 +391,7 @@ export function DetachCompileProvider({ children }) {
       position,
       rawLog,
       recompileFromScratch,
+      setAnimateCompileDropdownArrow,
       setAutoCompile,
       setCompiling,
       setDraft,

+ 8 - 0
services/web/frontend/js/shared/context/local-compile-context.js

@@ -121,6 +121,10 @@ export function LocalCompileProvider({ children }) {
   // whether the logs should be visible
   const [showLogs, setShowLogs] = useState(false)
 
+  // whether the compile dropdown arrow should be animated
+  const [animateCompileDropdownArrow, setAnimateCompileDropdownArrow] =
+    useState(false)
+
   const toggleLogs = useCallback(() => {
     setShowLogs(prev => {
       if (!prev) {
@@ -468,6 +472,7 @@ export function LocalCompileProvider({ children }) {
 
   const value = useMemo(
     () => ({
+      animateCompileDropdownArrow,
       autoCompile,
       clearCache,
       clearingCache,
@@ -488,6 +493,7 @@ export function LocalCompileProvider({ children }) {
       position,
       rawLog,
       recompileFromScratch,
+      setAnimateCompileDropdownArrow,
       setAutoCompile,
       setCompiling,
       setDraft,
@@ -512,6 +518,7 @@ export function LocalCompileProvider({ children }) {
       cleanupCompileResult,
     }),
     [
+      animateCompileDropdownArrow,
       autoCompile,
       clearCache,
       clearingCache,
@@ -532,6 +539,7 @@ export function LocalCompileProvider({ children }) {
       pdfViewer,
       rawLog,
       recompileFromScratch,
+      setAnimateCompileDropdownArrow,
       setAutoCompile,
       setDraft,
       setError,

+ 40 - 0
services/web/frontend/stylesheets/app/editor/pdf.less

@@ -187,6 +187,46 @@
   margin-left: @line-height-computed / 4;
 }
 
+@keyframes compile-button-flash {
+  from,
+  to {
+    background: rgba(0, 0, 0, 0);
+  }
+
+  25%,
+  75% {
+    background: rgba(0, 0, 0, 0.2);
+  }
+}
+
+@keyframes compile-button-bounce {
+  from,
+  50%,
+  to {
+    transform: translateY(0);
+  }
+
+  25%,
+  75% {
+    transform: translateY(2px);
+  }
+}
+
+.btn-recompile-animate {
+  animation-duration: 1.2s;
+  animation-fill-mode: both;
+  animation-timing-function: ease-in-out;
+  animation-name: compile-button-flash;
+}
+
+.btn-recompile-animate .caret {
+  animation-duration: 0.6s;
+  animation-delay: 0.4s;
+  animation-fill-mode: both;
+  animation-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
+  animation-name: compile-button-bounce;
+}
+
 .toolbar-text {
   padding-left: @padding-xs;
 }