[web] Changes to recompile button in Bootstrap 5 (#21586)

* Add Story for `PdfCompileButton`

* Set the CompileButton height so it's similar to BS3

* Add the CompileButton animations

* Remove `sm` from CompileButton: makes font size bigger

* Use MaterialIcon in compile-button dropdown-toggle

* Use MaterialIcon in LayoutDropdown

* Fix stripe alignment on Recompile button

* Set padding around dropdown caret

Per Alexandru's instructions

* Prevent border from disappearing on hover

* Set the padding of the compile button even on both sides

Before: left 12px, right 16px;
After: left 16px, right 16px;

* Change px values to spacing var

* Add some button classes for BS5 only

* Don't render the hidden "Compiling…" in BS5, it changes the button width

* Prevent `loading="[object Object]"` in the DOM

Co-authored-by: Rebeka <rebeka.dekany@overleaf.com>

---------

Co-authored-by: Rebeka <rebeka.dekany@overleaf.com>
GitOrigin-RevId: 34f1eed03e63f3459243a37c878612a623f321f8
This commit is contained in:
Antoine Clausse 2024-11-14 15:55:53 +01:00 committed by Copybot
parent b0419a86f2
commit 1d4737ac69
8 changed files with 164 additions and 14 deletions

View file

@ -10,6 +10,7 @@ import {
DropdownItem, DropdownItem,
DropdownMenu, DropdownMenu,
DropdownToggle, DropdownToggle,
DropdownToggleCustom,
} from '@/features/ui/components/bootstrap-5/dropdown-menu' } from '@/features/ui/components/bootstrap-5/dropdown-menu'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import Tooltip from '../../../shared/components/tooltip' import Tooltip from '../../../shared/components/tooltip'
@ -136,7 +137,7 @@ const LayoutDropdownToggleButton = forwardRef<
onClick(e) onClick(e)
} }
return <button {...props} ref={ref} onClick={handleClick} /> return <DropdownToggleCustom {...props} ref={ref} onClick={handleClick} />
}) })
LayoutDropdownToggleButton.displayName = 'LayoutDropdownToggleButton' LayoutDropdownToggleButton.displayName = 'LayoutDropdownToggleButton'

View file

@ -46,7 +46,7 @@ function DetachCompileButton() {
size="sm" size="sm"
isLoading={compiling} isLoading={compiling}
bs3Props={{ bs3Props={{
loading: ( loading: compiling && (
<> <>
<Icon type="refresh" spin={compiling} /> <Icon type="refresh" spin={compiling} />
<span className="detach-compile-button-label"> <span className="detach-compile-button-label">
@ -58,11 +58,14 @@ function DetachCompileButton() {
> >
<BootstrapVersionSwitcher <BootstrapVersionSwitcher
bs3={ bs3={
<>
<Icon type="refresh" spin={compiling} />
<span className="detach-compile-button-label"> <span className="detach-compile-button-label">
{compileButtonLabel} {compileButtonLabel}
</span> </span>
</>
} }
bs5={compileButtonLabel} bs5={t('recompile')}
/> />
</OLButton> </OLButton>
</OLTooltip> </OLTooltip>

View file

@ -9,6 +9,7 @@ import * as eventTracking from '../../../infrastructure/event-tracking'
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip' import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import { import {
DropdownToggleCustom,
Dropdown, Dropdown,
DropdownDivider, DropdownDivider,
DropdownHeader, DropdownHeader,
@ -18,7 +19,7 @@ import {
} from '@/features/ui/components/bootstrap-5/dropdown-menu' } from '@/features/ui/components/bootstrap-5/dropdown-menu'
import OLButton from '@/features/ui/components/ol/ol-button' import OLButton from '@/features/ui/components/ol/ol-button'
import OLButtonGroup from '@/features/ui/components/ol/ol-button-group' import OLButtonGroup from '@/features/ui/components/ol/ol-button-group'
import { bsVersion } from '@/features/utils/bootstrap-5' import { bsVersion, isBootstrap5 } from '@/features/utils/bootstrap-5'
import { useLayoutContext } from '@/shared/context/layout-context' import { useLayoutContext } from '@/shared/context/layout-context'
const modifierKey = /Mac/i.test(navigator.platform) ? 'Cmd' : 'Ctrl' const modifierKey = /Mac/i.test(navigator.platform) ? 'Cmd' : 'Ctrl'
@ -78,15 +79,18 @@ function PdfCompileButton() {
{ {
'detach-compile-button-animate': animateCompileDropdownArrow, 'detach-compile-button-animate': animateCompileDropdownArrow,
'btn-striped-animated': hasChanges, 'btn-striped-animated': hasChanges,
'no-left-border': true,
}, },
'no-left-border',
bsVersion({ bs5: 'dropdown-button-toggle' }) bsVersion({ bs5: 'dropdown-button-toggle' })
) )
const buttonClassName = classNames({ const buttonClassName = classNames(
{
'btn-striped-animated': hasChanges, 'btn-striped-animated': hasChanges,
'no-left-radius': true, 'align-items-center py-0': isBootstrap5(),
}) },
'no-left-radius px-3'
)
return ( return (
<BootstrapVersionSwitcher <BootstrapVersionSwitcher
@ -207,7 +211,11 @@ function PdfCompileButton() {
</SplitMenu> </SplitMenu>
} }
bs5={ bs5={
<Dropdown as={OLButtonGroup} autoClose="outside"> <Dropdown
as={OLButtonGroup}
autoClose="outside"
className="compile-button-group"
>
<OLTooltip <OLTooltip
description={tooltipElement} description={tooltipElement}
id="compile" id="compile"
@ -219,7 +227,6 @@ function PdfCompileButton() {
> >
<OLButton <OLButton
variant="primary" variant="primary"
size="sm"
disabled={compiling} disabled={compiling}
isLoading={compiling} isLoading={compiling}
onClick={() => startCompile()} onClick={() => startCompile()}
@ -230,6 +237,7 @@ function PdfCompileButton() {
</OLTooltip> </OLTooltip>
<DropdownToggle <DropdownToggle
as={DropdownToggleCustom}
split split
variant="primary" variant="primary"
id="pdf-recompile-dropdown" id="pdf-recompile-dropdown"

View file

@ -6,6 +6,8 @@ import {
DropdownItem as BS5DropdownItem, DropdownItem as BS5DropdownItem,
DropdownDivider as BS5DropdownDivider, DropdownDivider as BS5DropdownDivider,
DropdownHeader as BS5DropdownHeader, DropdownHeader as BS5DropdownHeader,
Button as BS5Button,
type ButtonProps,
} from 'react-bootstrap-5' } from 'react-bootstrap-5'
import type { import type {
DropdownProps, DropdownProps,
@ -103,6 +105,20 @@ const ForwardReferredDropdownItem = fixedForwardRef(DropdownItem, {
export { ForwardReferredDropdownItem as DropdownItem } export { ForwardReferredDropdownItem as DropdownItem }
export const DropdownToggleCustom = forwardRef<HTMLButtonElement, ButtonProps>(
({ children, className, ...props }, ref) => (
<BS5Button
ref={ref}
className={classnames('custom-toggle', className)}
{...props}
>
{children}
<MaterialIcon type="expand_more" />
</BS5Button>
)
)
DropdownToggleCustom.displayName = 'CustomCaret'
export const DropdownToggle = forwardRef< export const DropdownToggle = forwardRef<
typeof BS5DropdownToggle, typeof BS5DropdownToggle,
DropdownToggleProps DropdownToggleProps

View file

@ -0,0 +1,56 @@
import { FC } from 'react'
import type { Meta } from '@storybook/react'
import PdfCompileButton from '@/features/pdf-preview/components/pdf-compile-button'
import { ScopeDecorator } from '../decorators/scope'
import { CompileContext } from '@/shared/context/local-compile-context'
import { DetachCompileContext } from '@/shared/context/detach-compile-context'
import { bsVersionDecorator } from '../../../.storybook/utils/with-bootstrap-switcher'
export const CompileButton: FC<CompileContext> = (props: CompileContext) => (
<DetachCompileContext.Provider value={props}>
<div className="pdf m-5">
<div className="toolbar toolbar-pdf toolbar-pdf-hybrid btn-toolbar">
<div className="toolbar-pdf-left">
<PdfCompileButton />
</div>
</div>
</div>
</DetachCompileContext.Provider>
)
const args: Partial<CompileContext> = {
autoCompile: false,
compiling: false,
draft: false,
hasChanges: false,
stopOnFirstError: false,
stopOnValidationError: false,
animateCompileDropdownArrow: false,
}
const meta: Meta<typeof CompileButton> = {
title: 'Editor / Toolbar / Compile Button',
component: CompileButton,
// @ts-ignore
decorators: [ScopeDecorator],
argTypes: {
...bsVersionDecorator.argTypes,
startCompile: { action: 'startCompile' },
setAutoCompile: { action: 'setAutoCompile' },
setCompiling: { action: 'setCompiling' },
setDraft: { action: 'setDraft' },
setStopOnFirstError: { action: 'setStopOnFirstError' },
setError: { action: 'setError' },
setHasLintingError: { action: 'setHasLintingError' },
setPosition: { action: 'setPosition' },
setStopOnValidationError: { action: 'setStopOnValidationError' },
recompileFromScratch: { action: 'recompileFromScratch' },
stopCompile: { action: 'stopCompile' },
setAnimateCompileDropdownArrow: {
action: 'setAnimateCompileDropdownArrow',
},
},
args,
}
export default meta

View file

@ -1,5 +1,20 @@
.dropdown { .dropdown {
display: inline-flex; display: inline-flex;
.no-left-border {
border-left: none;
}
.custom-toggle {
&::after {
content: none !important;
}
padding-left: var(--spacing-04);
padding-right: var(--spacing-05);
display: flex;
align-items: center;
}
} }
.dropdown-header { .dropdown-header {

View file

@ -29,3 +29,43 @@ $stripe-width: 20px;
cursor: not-allowed; cursor: not-allowed;
} }
} }
@keyframes compile-button-flash {
0%,
100% {
background: rgb(0 0 0 / 0%);
}
25%,
75% {
background: rgb(0 0 0 / 20%);
}
}
@keyframes compile-button-bounce {
0%,
50%,
100% {
transform: translateY(0);
}
25%,
75% {
transform: translateY(2px);
}
}
.detach-compile-button-animate {
animation-duration: 1.2s;
animation-fill-mode: both;
animation-timing-function: ease-in-out;
animation-name: compile-button-flash;
}
.detach-compile-button-animate .material-symbols {
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;
}

View file

@ -26,6 +26,17 @@
.toolbar-pdf-left { .toolbar-pdf-left {
gap: var(--spacing-02); gap: var(--spacing-02);
.compile-button-group {
height: 28px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
background-color: var(--bg-accent-01);
.btn-primary:hover {
z-index: auto; // prevents border from being hidden
}
}
.dropdown > .btn { .dropdown > .btn {
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;