admin/plugins: animation on stop button

Massimo Melina committed Nov 29, 2024 at 20:27 UTC 5717e6fc0a2de5a66332e3cccb6b55130647bd41
3 files changed +10 -10
admin/src/InstalledPlugins.ts
+2 -4
@@ -76,10 +76,8 @@ export default function InstalledPlugins({ updates }: { updates?: true }) {
76 'aria-label': `Stop ${id}`,
77 size,
78 color: 'success',
79 - async onClick() {
80 - await apiCall('stop_plugin', { id })
81 - toast("Plugin stopped", h(StopCircle, { color: 'warning' }))
82 - }
79 + doneAnimation: true,
80 + onClick: () => apiCall('stop_plugin', { id }),
81 } : {
82 icon: PlayCircle,
83 title: `Start ${id}`,
admin/src/index.scss
+1 -1
@@ -68,7 +68,7 @@ h2.MuiDialogTitle-root { /* less padding */
68 @keyframes animate-dash { to { background-position: 20px 0; } }
69
70 @keyframes success {
71 - 50% { transform: scale(1.5); color: var(--success); }
71 + 50% { transform: scale(1.3); color: var(--success); }
72 100% { transform: inherit; color: inherit; }
73 }
74
admin/src/mui.ts
+7 -5
@@ -107,6 +107,7 @@ export function propsForModifiedValues(modified: boolean | undefined) {
107 return modified ? { sx: { outline: '2px solid' } } : undefined
108 }
109
110 +// use ref.pass as prop
111 function useRefPass<T=unknown>(forwarded: ForwardedRef<any>) {
112 const ref = useRef<T | null>(null)
113 return Object.assign(ref, {
@@ -117,7 +118,6 @@ function useRefPass<T=unknown>(forwarded: ForwardedRef<any>) {
118 else if (forwarded)
119 forwarded.current = el
120 },
120 -
121 })
122 }
123
@@ -134,13 +134,15 @@ export interface BtnProps extends Omit<ButtonProps & IconButtonProps,'disabled'|
134 confirm?: boolean | ReactNode
135 labelIf?: Breakpoint | boolean
136 doneMessage?: boolean | string // displayed only if the result of onClick !== false
137 + doneAnimation?: boolean
138 tooltipProps?: Partial<TooltipProps>
139 modified?: boolean
140 loading?: boolean
141 onClick?: (...args: Parameters<NonNullable<ButtonProps['onClick']>>) => Promisable<any>
142 }
143
143 -export const Btn = forwardRef(({ icon, title, onClick, disabled, progress, link, tooltipProps, confirm, doneMessage, labelIf, children, modified, loading, ...rest }: BtnProps, forwarded: ForwardedRef<HTMLButtonElement>) => {
144 +export const Btn = forwardRef(({ icon, title, onClick, disabled, progress, link, tooltipProps, confirm, doneMessage,
145 + doneAnimation, labelIf, children, modified, loading, ...rest }: BtnProps, forwarded: ForwardedRef<HTMLButtonElement>) => {
146 const [loadingState, setLoadingState] = useStateMounted(false)
147 if (typeof disabled === 'string')
148 title = disabled
@@ -152,7 +154,7 @@ export const Btn = forwardRef(({ icon, title, onClick, disabled, progress, link,
154 title = children
155 const ref = useRefPass<HTMLButtonElement>(forwarded)
156 const common = _.merge(propsForModifiedValues(modified), {
155 - ref,
157 + ref: ref.pass,
158 disabled,
159 'aria-hidden': disabled,
160 async onClick(...args: any[]) {
@@ -161,7 +163,7 @@ export const Btn = forwardRef(({ icon, title, onClick, disabled, progress, link,
163 const ret = onClick?.apply(this, args as any)
164 if (ret && ret instanceof Promise) {
165 setLoadingState(true)
164 - ret.then(x => x !== false && execDoneMessage(doneMessage), alertDialog)
166 + ret.then(x => x !== false && execDoneMessage(doneMessage, doneAnimation && ref.current), alertDialog)
167 .finally(()=> setLoadingState(false))
168 }
169 },
@@ -194,7 +196,7 @@ export const Btn = forwardRef(({ icon, title, onClick, disabled, progress, link,
196 return ret
197 })
198
197 -function execDoneMessage(msg: boolean | string | undefined, el?: HTMLElement | null) {
199 +function execDoneMessage(msg: boolean | string | undefined, el?: HTMLElement | null | false) {
200 if (el)
201 restartAnimation(el, 'success .5s')
202 if (msg)