{user.allowedFreeTrial ? (
diff --git a/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/add-collaborators-upgrade.tsx b/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/add-collaborators-upgrade.tsx
index ace42c327a..4ef7427803 100644
--- a/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/add-collaborators-upgrade.tsx
+++ b/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/add-collaborators-upgrade.tsx
@@ -33,7 +33,7 @@ export default function AddCollaboratorsUpgrade() {
{user.allowedFreeTrial ? (
diff --git a/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/collaborators-limit-upgrade.tsx b/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/collaborators-limit-upgrade.tsx
index 53812066dc..a551005e6f 100644
--- a/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/collaborators-limit-upgrade.tsx
+++ b/services/web/frontend/js/features/share-project-modal/components/restricted-link-sharing/collaborators-limit-upgrade.tsx
@@ -37,7 +37,7 @@ export default function CollaboratorsLimitUpgrade() {
action={
user.allowedFreeTrial ? (
@@ -71,7 +71,7 @@ export default function CollaboratorsLimitUpgrade() {
action={
user.allowedFreeTrial ? (
diff --git a/services/web/frontend/js/features/source-editor/components/switch-to-pdf-button.jsx b/services/web/frontend/js/features/source-editor/components/switch-to-pdf-button.jsx
index 16d2b1e81e..93b8d2461b 100644
--- a/services/web/frontend/js/features/source-editor/components/switch-to-pdf-button.jsx
+++ b/services/web/frontend/js/features/source-editor/components/switch-to-pdf-button.jsx
@@ -25,7 +25,7 @@ function SwitchToPDFButton() {
return (
,
+ BSBadgeProps,
{
prepend?: React.ReactNode
}
>
-function Badge({ prepend, children, closeBtnProps, ...rest }: BadgeProps) {
+function Badge({ prepend, children, ...rest }: BadgeProps) {
return (
{prepend && {prepend}}
diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/button.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/button.tsx
index 0d80f8aab8..1e21058d28 100644
--- a/services/web/frontend/js/features/ui/components/bootstrap-5/button.tsx
+++ b/services/web/frontend/js/features/ui/components/bootstrap-5/button.tsx
@@ -5,12 +5,6 @@ import classNames from 'classnames'
import { useTranslation } from 'react-i18next'
import MaterialIcon from '@/shared/components/material-icon'
-const sizeClasses = new Map([
- ['small', 'btn-sm'],
- ['default', ''],
- ['large', 'btn-lg'],
-])
-
const Button = forwardRef(
(
{
@@ -19,7 +13,6 @@ const Button = forwardRef(
leadingIcon,
isLoading = false,
loadingLabel,
- size = 'default',
trailingIcon,
variant = 'primary',
...props
@@ -28,13 +21,28 @@ const Button = forwardRef(
) => {
const { t } = useTranslation()
- const sizeClass = sizeClasses.get(size)
- const buttonClassName = classNames('d-inline-grid', sizeClass, className, {
+ const buttonClassName = classNames('d-inline-grid', className, {
'button-loading': isLoading,
})
+
const loadingSpinnerClassName =
- size === 'large' ? 'loading-spinner-large' : 'loading-spinner-small'
- const materialIconClassName = size === 'large' ? 'icon-large' : 'icon-small'
+ props.size === 'lg' ? 'loading-spinner-large' : 'loading-spinner-small'
+ const materialIconClassName =
+ props.size === 'lg' ? 'icon-large' : 'icon-small'
+
+ const leadingIconComponent =
+ leadingIcon && typeof leadingIcon === 'string' ? (
+
+ ) : (
+ leadingIcon
+ )
+
+ const trailingIconComponent =
+ trailingIcon && typeof trailingIcon === 'string' ? (
+
+ ) : (
+ trailingIcon
+ )
return (
(
)}
- {leadingIcon && (
-
- )}
+ {leadingIconComponent}
{children}
- {trailingIcon && (
-
- )}
+ {trailingIconComponent}
)
diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/split-button.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/split-button.tsx
deleted file mode 100644
index 8c80aafd44..0000000000
--- a/services/web/frontend/js/features/ui/components/bootstrap-5/split-button.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import classNames from 'classnames'
-import Button from './button'
-import {
- Dropdown,
- DropdownItem,
- DropdownMenu,
- DropdownToggle,
-} from './dropdown-menu'
-import MaterialIcon from '@/shared/components/material-icon'
-import type { SplitButtonProps } from '@/features/ui/components/types/split-button-props'
-
-export function SplitButton({
- accessibilityLabel,
- align,
- id,
- items,
- text,
- variant,
- ...props
-}: SplitButtonProps) {
- const buttonClassName = classNames('split-button')
-
- return (
-
-
-
-
-
-
-
- {items.map((item, index) => (
-
- {item.label}
-
- ))}
-
-
-
- )
-}
diff --git a/services/web/frontend/js/features/ui/components/ol/ol-button-group.tsx b/services/web/frontend/js/features/ui/components/ol/ol-button-group.tsx
index f4f0ede217..c9a9d1188b 100644
--- a/services/web/frontend/js/features/ui/components/ol/ol-button-group.tsx
+++ b/services/web/frontend/js/features/ui/components/ol/ol-button-group.tsx
@@ -10,7 +10,7 @@ type OLButtonGroupProps = ButtonGroupProps & {
bs3Props?: Record
}
-function OlButtonGroup({ bs3Props, as, ...rest }: OLButtonGroupProps) {
+function OLButtonGroup({ bs3Props, as, ...rest }: OLButtonGroupProps) {
const bs3ButtonGroupProps: BS3ButtonGroupProps = {
children: rest.children,
className: rest.className,
@@ -27,4 +27,4 @@ function OlButtonGroup({ bs3Props, as, ...rest }: OLButtonGroupProps) {
)
}
-export default OlButtonGroup
+export default OLButtonGroup
diff --git a/services/web/frontend/js/features/ui/components/ol/ol-button.tsx b/services/web/frontend/js/features/ui/components/ol/ol-button.tsx
index 1e377ee3c0..524b3e3353 100644
--- a/services/web/frontend/js/features/ui/components/ol/ol-button.tsx
+++ b/services/web/frontend/js/features/ui/components/ol/ol-button.tsx
@@ -1,3 +1,4 @@
+import { forwardRef } from 'react'
import BootstrapVersionSwitcher from '../bootstrap-5/bootstrap-version-switcher'
import { Button as BS3Button } from 'react-bootstrap'
import type { ButtonProps } from '@/features/ui/components/types/button-props'
@@ -5,7 +6,7 @@ import type { ButtonProps as BS3ButtonPropsBase } from 'react-bootstrap'
import Button from '../bootstrap-5/button'
import classnames from 'classnames'
import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
-
+import { callFnsInSequence } from '@/utils/functions'
export type BS3ButtonSize = 'xsmall' | 'sm' | 'medium' | 'lg'
export type OLButtonProps = ButtonProps & {
@@ -14,6 +15,10 @@ export type OLButtonProps = ButtonProps & {
bsSize?: BS3ButtonSize
block?: boolean
className?: string
+ onMouseOver?: React.MouseEventHandler
+ onMouseOut?: React.MouseEventHandler
+ onFocus?: React.FocusEventHandler
+ onBlur?: React.FocusEventHandler
}
}
@@ -25,7 +30,7 @@ export type BS3ButtonProps = Omit & {
export function bs3ButtonProps(props: ButtonProps) {
const bs3ButtonProps: BS3ButtonProps = {
bsStyle: null,
- bsSize: mapBsButtonSizes(props.size),
+ bsSize: props.size,
className: classnames(`btn-${props.variant || 'primary'}`, props.className),
disabled: props.isLoading || props.disabled,
form: props.form,
@@ -34,38 +39,51 @@ export function bs3ButtonProps(props: ButtonProps) {
rel: props.rel,
onClick: props.onClick,
type: props.type,
+ draggable: props.draggable,
+ download: props.download,
+ style: props.style,
+ active: props.active,
}
return bs3ButtonProps
}
-// maps Bootstrap 5 sizes to Bootstrap 3 sizes
-export const mapBsButtonSizes = (
- size: ButtonProps['size']
-): 'sm' | 'lg' | undefined =>
- size === 'small' ? 'sm' : size === 'large' ? 'lg' : undefined
+const OLButton = forwardRef(
+ ({ bs3Props = {}, ...rest }, ref) => {
+ const { className: _, ...restBs3Props } = bs3Props
-export default function OLButton({ bs3Props = {}, ...rest }: OLButtonProps) {
- const { className: _, ...restBs3Props } = bs3Props
+ // BS3 OverlayTrigger automatically provides 'onMouseOver', 'onMouseOut', 'onFocus', 'onBlur' event handlers
+ const bs3FinalProps = {
+ ...restBs3Props,
+ onMouseOver: callFnsInSequence(bs3Props?.onMouseOver, rest.onMouseOver),
+ onMouseOut: callFnsInSequence(bs3Props?.onMouseOut, rest.onMouseOut),
+ onFocus: callFnsInSequence(bs3Props?.onFocus, rest.onFocus),
+ onBlur: callFnsInSequence(bs3Props?.onBlur, rest.onBlur),
+ }
- // Get all `aria-*` and `data-*` attributes
- const extraProps = getAriaAndDataProps(rest)
+ // Get all `aria-*` and `data-*` attributes
+ const extraProps = getAriaAndDataProps(rest)
- return (
-
- {bs3Props?.loading || rest.children}
-
- }
- bs5={}
- />
- )
-}
+ return (
+ | undefined}
+ >
+ {bs3Props?.loading || rest.children}
+
+ }
+ bs5={}
+ />
+ )
+ }
+)
+OLButton.displayName = 'OLButton'
+
+export default OLButton
diff --git a/services/web/frontend/js/features/ui/components/ol/ol-tooltip.tsx b/services/web/frontend/js/features/ui/components/ol/ol-tooltip.tsx
index 99df8d0828..97458008fa 100644
--- a/services/web/frontend/js/features/ui/components/ol/ol-tooltip.tsx
+++ b/services/web/frontend/js/features/ui/components/ol/ol-tooltip.tsx
@@ -9,10 +9,13 @@ type OLTooltipProps = React.ComponentProps & {
function OLTooltip(props: OLTooltipProps) {
const { bs3Props, ...bs5Props } = props
- const bs3TooltipProps: React.ComponentProps = {
+ type BS3TooltipProps = React.ComponentProps
+
+ const bs3TooltipProps: BS3TooltipProps = {
children: bs5Props.children,
id: bs5Props.id,
description: bs5Props.description,
+ tooltipProps: bs5Props.tooltipProps as BS3TooltipProps,
overlayProps: {
placement: bs5Props.overlayProps?.placement,
},
diff --git a/services/web/frontend/js/features/ui/components/types/button-props.ts b/services/web/frontend/js/features/ui/components/types/button-props.ts
index 5d76cbf4c6..d719381a79 100644
--- a/services/web/frontend/js/features/ui/components/types/button-props.ts
+++ b/services/web/frontend/js/features/ui/components/types/button-props.ts
@@ -4,8 +4,10 @@ export type ButtonProps = {
children?: ReactNode
className?: string
disabled?: boolean
+ download?: boolean
+ draggable?: boolean
form?: string
- leadingIcon?: string
+ leadingIcon?: string | React.ReactNode
href?: string
target?: string
rel?: string
@@ -16,8 +18,10 @@ export type ButtonProps = {
onMouseOut?: React.MouseEventHandler
onFocus?: React.FocusEventHandler
onBlur?: React.FocusEventHandler
- size?: 'small' | 'default' | 'large'
- trailingIcon?: string
+ size?: 'sm' | 'lg' | undefined
+ style?: Record
+ active?: boolean
+ trailingIcon?: string | React.ReactNode
type?: 'button' | 'reset' | 'submit'
variant?:
| 'primary'
diff --git a/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts b/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts
index 4e67b22dd4..981e127f31 100644
--- a/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts
+++ b/services/web/frontend/js/features/ui/components/types/dropdown-menu-props.ts
@@ -1,5 +1,10 @@
import type { ElementType, ReactNode, PropsWithChildren } from 'react'
-import type { SplitButtonVariants } from './split-button-props'
+import type { ButtonProps } from '@/features/ui/components/types/button-props'
+
+type SplitButtonVariants = Extract<
+ ButtonProps['variant'],
+ 'primary' | 'secondary' | 'danger' | 'link'
+>
export type DropdownProps = {
align?:
@@ -47,7 +52,7 @@ export type DropdownToggleProps = PropsWithChildren<{
id?: string // necessary for assistive technologies
variant?: SplitButtonVariants
as?: ElementType
- size?: 'sm' | 'lg'
+ size?: 'sm' | 'lg' | undefined
}>
export type DropdownMenuProps = PropsWithChildren<{
diff --git a/services/web/frontend/js/features/ui/components/types/split-button-props.ts b/services/web/frontend/js/features/ui/components/types/split-button-props.ts
deleted file mode 100644
index 9059216543..0000000000
--- a/services/web/frontend/js/features/ui/components/types/split-button-props.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { PropsWithChildren } from 'react'
-import type {
- DropdownItemProps,
- DropdownProps,
- DropdownToggleProps,
-} from './dropdown-menu-props'
-import type { ButtonProps } from './button-props'
-
-type SplitButtonItemProps = Pick<
- DropdownItemProps,
- 'eventKey' | 'leadingIcon'
-> & {
- label: React.ReactNode
-}
-
-export type SplitButtonVariants = Extract<
- ButtonProps['variant'],
- 'primary' | 'secondary' | 'danger' | 'link'
->
-
-export type SplitButtonProps = PropsWithChildren<{
- accessibilityLabel?: string
- align?: DropdownProps['align']
- disabled?: boolean
- id: DropdownToggleProps['id']
- items: SplitButtonItemProps[]
- text: string
- variant: SplitButtonVariants
-}>
diff --git a/services/web/frontend/js/shared/components/copy-to-clipboard.tsx b/services/web/frontend/js/shared/components/copy-to-clipboard.tsx
index 3b7e2aeaa7..78b23f3233 100644
--- a/services/web/frontend/js/shared/components/copy-to-clipboard.tsx
+++ b/services/web/frontend/js/shared/components/copy-to-clipboard.tsx
@@ -53,7 +53,7 @@ const TextButton: FC<{
return (
{
- setOpen(value)
+ setOpen(Boolean(value))
}, [])
// close the dropdown on click outside the dropdown
diff --git a/services/web/frontend/stories/start-free-trial-button.stories.jsx b/services/web/frontend/stories/start-free-trial-button.stories.jsx
index 2db9054a4a..6da53dc4cd 100644
--- a/services/web/frontend/stories/start-free-trial-button.stories.jsx
+++ b/services/web/frontend/stories/start-free-trial-button.stories.jsx
@@ -17,7 +17,7 @@ export const ButtonStyle = args => {
{...args}
buttonProps={{
variant: 'danger',
- size: 'large',
+ size: 'lg',
}}
/>
)
diff --git a/services/web/frontend/stories/ui/badge-bs5.stories.tsx b/services/web/frontend/stories/ui/badge-bs5.stories.tsx
index e5468c7c66..737cf96c14 100644
--- a/services/web/frontend/stories/ui/badge-bs5.stories.tsx
+++ b/services/web/frontend/stories/ui/badge-bs5.stories.tsx
@@ -27,11 +27,6 @@ const meta: Meta = {
disable: true,
},
},
- closeBtnProps: {
- table: {
- disable: true,
- },
- },
},
}
export default meta
diff --git a/services/web/frontend/stories/ui/split-button.stories.tsx b/services/web/frontend/stories/ui/split-button.stories.tsx
index 883ec80a94..c1423bbb80 100644
--- a/services/web/frontend/stories/ui/split-button.stories.tsx
+++ b/services/web/frontend/stories/ui/split-button.stories.tsx
@@ -1,33 +1,60 @@
-import { SplitButton } from '@/features/ui/components/bootstrap-5/split-button'
+import { Fragment } from 'react'
import type { Meta } from '@storybook/react'
import { useTranslation } from 'react-i18next'
+import {
+ Dropdown,
+ DropdownHeader,
+ DropdownItem,
+ DropdownMenu,
+ DropdownToggle,
+} from '@/features/ui/components/bootstrap-5/dropdown-menu'
+import Button from '@/features/ui/components/bootstrap-5/button'
+import { ButtonGroup } from 'react-bootstrap-5'
-type Args = React.ComponentProps
+type Args = React.ComponentProps
-export const Dropdown = (args: Args) => {
+export const Sizes = (args: Args) => {
const { t } = useTranslation()
+ const sizes = {
+ Large: 'lg',
+ Regular: undefined,
+ Small: 'sm',
+ } as const
+ const variants = ['primary', 'secondary', 'danger'] as const
- return
+ return Object.entries(sizes).map(([label, size]) => (
+
+ {label}
+
+ {variants.map(variant => (
+
+
+
+
+ Header
+ Action 1
+ Action 2
+ Action 3
+
+
+ ))}
+
+
+ ))
}
-const meta: Meta = {
+const meta: Meta = {
title: 'Shared/Components/Bootstrap 5/SplitButton',
- component: SplitButton,
+ component: Dropdown,
args: {
align: { sm: 'start' },
- id: 'split-button',
- items: [
- { eventKey: '1', label: 'Action 1' },
- { eventKey: '2', label: 'Action 2' },
- { eventKey: '3', label: 'Action 3' },
- ],
- text: 'Split Button',
- },
- argTypes: {
- id: {
- table: {
- disable: true,
- },
- },
},
parameters: {
bootstrap5: true,
diff --git a/services/web/frontend/stylesheets/app/editor/pdf.less b/services/web/frontend/stylesheets/app/editor/pdf.less
index a63766279b..cd4eeb8288 100644
--- a/services/web/frontend/stylesheets/app/editor/pdf.less
+++ b/services/web/frontend/stylesheets/app/editor/pdf.less
@@ -53,9 +53,6 @@
outline: none;
}
}
-.btn-toggle-logs-label {
- padding-left: @line-height-computed / 4;
-}
.pdf-toolbar-btn {
display: inline-block;
@@ -64,7 +61,6 @@
padding: 4px 2px;
line-height: 1;
height: 24px;
- border-radius: 2px;
border-radius: @border-radius-base;
&:hover,
diff --git a/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss b/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss
index 2110f6541a..9747dd7027 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss
@@ -67,11 +67,11 @@
// Toolbar
@mixin toolbar-sm-height {
- height: 32px;
+ height: var(--toolbar-small-height);
}
@mixin toolbar-alt-bg() {
- background-color: var(--bg-dark-secondary);
+ background-color: var(--toolbar-alt-bg-color);
}
@mixin theme($name) {
@@ -87,3 +87,20 @@
@mixin box-shadow-button-input {
box-shadow: 0 0 0 2px var(--blue-30);
}
+
+@mixin animation($animation) {
+ animation: $animation;
+}
+
+@mixin striped($color: rgba(255, 255, 255, 0.15), $angle: 45deg) {
+ background-image: linear-gradient(
+ $angle,
+ $color 25%,
+ transparent 25%,
+ transparent 50%,
+ $color 50%,
+ $color 75%,
+ transparent 75%,
+ transparent
+ );
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss
index f2a738a566..7f6b184cf8 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss
@@ -2,7 +2,6 @@
@import 'button-group';
@import 'dropdown-menu';
@import 'image';
-@import 'split-button';
@import 'notifications';
@import 'system-messages';
@import 'tooltip';
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/button-group.scss b/services/web/frontend/stylesheets/bootstrap-5/components/button-group.scss
index e0de77102f..5825a57ca6 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/components/button-group.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/button-group.scss
@@ -1,10 +1,10 @@
.btn-group {
> .btn {
- &:first-child {
+ &:first-of-type {
padding-left: var(--spacing-05);
}
- &:last-child {
+ &:last-of-type {
padding-right: var(--spacing-05);
}
}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss b/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss
index f07165a1db..d8b30248de 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/dropdown-menu.scss
@@ -138,6 +138,7 @@
border-top-left-radius: 0;
padding-right: var(--spacing-05);
padding-left: var(--spacing-05);
+ margin-left: 0;
&.btn-primary,
&.btn-danger {
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/split-button.scss b/services/web/frontend/stylesheets/bootstrap-5/components/split-button.scss
deleted file mode 100644
index 544a4a4b34..0000000000
--- a/services/web/frontend/stylesheets/bootstrap-5/components/split-button.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.split-button {
- border-bottom-right-radius: 0;
- border-top-right-radius: 0;
- border-right: none;
-}
-
-.split-button-caret {
- vertical-align: middle;
-}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss
index ea5e4c10c2..f9ac9aba51 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss
@@ -12,5 +12,7 @@
@import 'editor/file-tree';
@import 'editor/figure-modal';
@import 'subscription';
+@import 'editor/pdf';
+@import 'editor/compile-button';
@import 'website-redesign';
@import 'group-settings';
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/compile-button.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/compile-button.scss
new file mode 100644
index 0000000000..fd29d70acf
--- /dev/null
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/compile-button.scss
@@ -0,0 +1,31 @@
+$stripe-width: 20px;
+
+@keyframes pdf-toolbar-stripes {
+ from {
+ background-position: 0 0;
+ }
+
+ to {
+ background-position: $stripe-width 0;
+ }
+}
+
+.btn-striped-animated {
+ @include striped;
+
+ background-size: $stripe-width $stripe-width;
+ background-origin: content-box;
+
+ @include animation(pdf-toolbar-stripes 2s linear infinite);
+}
+
+.detach-compile-button {
+ &[disabled],
+ &[disabled]:active {
+ background-color: var(--bs-btn-bg);
+ color: var(--bs-btn-color);
+ opacity: 1;
+ pointer-events: auto;
+ cursor: not-allowed;
+ }
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss
new file mode 100644
index 0000000000..dd41048115
--- /dev/null
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss
@@ -0,0 +1,357 @@
+:root {
+ --pdf-bg: var(--neutral-10);
+ --pdf-toolbar-btn-hover-color: rgb(125 125 125 / 20%);
+}
+
+@include theme('light') {
+ --pdf-toolbar-btn-hover-color: var(--neutral-10);
+}
+
+.pdf .toolbar.toolbar-pdf {
+ @include toolbar-sm-height;
+ @include toolbar-alt-bg;
+
+ padding-right: var(--spacing-03);
+ margin-left: 0;
+
+ .btn.disabled,
+ .btn[disabled] {
+ pointer-events: auto;
+ cursor: not-allowed;
+ opacity: 1;
+ }
+}
+
+.toolbar-pdf-left {
+ gap: var(--spacing-02);
+
+ .dropdown > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+
+ &[disabled],
+ &[disabled]:active {
+ background-color: var(--bs-btn-bg);
+ color: var(--bs-btn-color);
+ opacity: 1;
+ pointer-events: auto;
+ cursor: not-allowed;
+ }
+ }
+}
+
+.toolbar-pdf-orphan,
+.toolbar-pdf-left,
+.toolbar-pdf-right,
+.toolbar-pdf-controls {
+ display: flex;
+ align-items: center;
+ align-self: stretch;
+}
+
+.toolbar-pdf-orphan,
+.toolbar-pdf-controls {
+ flex: 1 1 100%;
+}
+
+.toolbar-pdf-controls {
+ margin-right: var(--spacing-02);
+ justify-content: flex-end;
+}
+
+.toolbar-pdf-right {
+ flex: 1;
+ justify-content: flex-end;
+}
+
+.toolbar-pdf-orphan {
+ justify-content: center;
+ color: var(--toolbar-btn-color);
+
+ .btn {
+ margin-left: var(--spacing-03);
+ }
+}
+
+.btn.pdf-toolbar-btn {
+ display: inline-block;
+ color: var(--toolbar-btn-color);
+ background-color: transparent;
+ padding: 0 var(--spacing-01);
+ line-height: 1;
+ height: 24px;
+ border-radius: var(--border-radius-base);
+ text-decoration: none;
+
+ &:hover,
+ &:active,
+ &:focus {
+ color: var(--toolbar-btn-color);
+ }
+
+ &:hover {
+ &:not(:disabled) {
+ background-color: var(--pdf-toolbar-btn-hover-color);
+ }
+ }
+
+ &:active {
+ background-color: transparent;
+ }
+
+ .button-content {
+ align-self: center;
+ }
+
+ .badge {
+ font-size: 60%;
+ }
+
+ &.log-btn {
+ border: none;
+
+ &.active {
+ color: var(--white);
+ background-color: var(--link-color);
+ box-shadow: none;
+ opacity: 0.65;
+
+ &:hover {
+ &:not(:disabled) {
+ background-color: transparent;
+ color: var(--toolbar-btn-color);
+ }
+ }
+ }
+
+ &:focus {
+ outline: none;
+ }
+ }
+}
+
+.pdf {
+ background-color: var(--pdf-bg);
+}
+
+.pdf-viewer,
+.pdf-logs,
+.pdf-errors,
+.pdf-uncompiled {
+ @extend .full-size;
+
+ top: var(--toolbar-small-height);
+}
+
+.pdf-viewer {
+ iframe {
+ width: 100%;
+ height: 100%;
+ border: none;
+ }
+
+ .pdfjs-viewer {
+ @extend .full-size;
+
+ background-color: transparent;
+ overflow: scroll;
+
+ /* stylelint-disable-next-line selector-class-pattern */
+ .canvasWrapper > canvas,
+ div.pdf-canvas {
+ background: white;
+ box-shadow: 0 0 10px rgb(0 0 0 / 50%);
+ }
+
+ div.pdf-canvas.pdfng-empty {
+ background-color: var(--white);
+ }
+
+ div.pdf-canvas.pdfng-loading {
+ background-color: var(--white);
+ }
+
+ .page-container {
+ margin: var(--spacing-05) auto;
+ padding: 0 var(--spacing-05);
+ box-sizing: content-box;
+ user-select: none;
+ }
+
+ .page {
+ box-sizing: content-box;
+ margin: var(--spacing-05) auto;
+ box-shadow: 0 0 8px #bbb;
+ border: none;
+ }
+
+ .pdfjs-viewer-inner {
+ position: absolute;
+ overflow-y: scroll;
+ width: 100%;
+ height: 100%;
+ -webkit-font-smoothing: initial;
+ -moz-osx-font-smoothing: initial;
+
+ /* fix review-panel overflow issue, see: https://github.com/overleaf/internal/issues/6781#issuecomment-1112708638 */
+ /* stylelint-disable-next-line selector-class-pattern */
+ .pdfViewer {
+ min-height: 100%;
+ }
+ }
+
+ &:focus-within {
+ outline: none;
+ }
+
+ /* Avoids https://github.com/mozilla/pdf.js/issues/13840 in Chrome */
+ /* stylelint-disable-next-line selector-class-pattern */
+ .textLayer br::selection {
+ background: transparent;
+ }
+ }
+
+ .progress-thin {
+ position: absolute;
+ top: -2px;
+ height: 3px;
+ left: 0;
+ right: 0;
+
+ .progress-bar {
+ height: 100%;
+ background-color: var(--link-color);
+ }
+ }
+}
+
+.pdfjs-viewer-controls {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ width: 100%;
+}
+
+.pdfjs-zoom-controls {
+ display: inline-flex;
+ border-left: 1px solid rgb(125 125 125 / 30%);
+}
+
+.pdfjs-toolbar-buttons {
+ display: flex;
+ gap: var(--spacing-04);
+ margin-left: var(--spacing-04);
+ margin-right: var(--spacing-04);
+}
+
+.pdfjs-toolbar-button {
+ padding: var(--spacing-01) !important;
+ display: flex;
+ align-items: center;
+}
+
+.pdfjs-zoom-dropdown-button {
+ width: 60px;
+ text-align: right;
+ font-weight: normal;
+}
+
+.pdfjs-zoom-dropdown-mac-shortcut-char {
+ display: inline-block;
+ width: 1em;
+ text-align: center;
+}
+
+.pdfjs-custom-zoom-menu-item {
+ display: block;
+ pointer-events: initial !important;
+
+ &:hover {
+ background-color: initial !important;
+ color: initial !important;
+ cursor: initial !important;
+ }
+}
+
+.pdfjs-page-number-input {
+ color: var(--toolbar-btn-color);
+ font-size: var(--font-size-02);
+ padding-right: var(--spacing-04);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-02);
+
+ input {
+ color: initial;
+ border: 1px solid var(--neutral-60);
+ width: 32px;
+ height: 24px;
+ border-radius: var(--border-radius-base);
+ text-align: center;
+ }
+}
+
+.pdfjs-viewer-controls-small {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-04);
+}
+
+.pdfjs-toolbar-popover-button {
+ padding: var(--spacing-01) !important;
+}
+
+.pdfjs-toolbar-popover {
+ background-color: var(--editor-toolbar-bg);
+ border-radius: var(--border-radius-base);
+
+ .popover-arrow {
+ display: none;
+ }
+
+ button {
+ background-color: transparent;
+ color: var(--toolbar-btn-color);
+ }
+
+ .popover-body {
+ display: flex;
+ align-items: center;
+ padding: var(--spacing-04) 0;
+ }
+}
+
+// The new viewer UI has overflow on the inner element,
+// so disable the overflow on the outer element
+.pdf-viewer .pdfjs-viewer.pdfjs-viewer-outer {
+ overflow: hidden;
+}
+
+:fullscreen {
+ .pdfjs-viewer-inner {
+ overflow-y: hidden !important;
+ }
+}
+
+.synctex-control {
+ > .synctex-control-icon {
+ display: inline-block;
+ font:
+ normal normal normal 14px/1 FontAwesome,
+ sans-serif;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+
+ > .synctex-spin-icon {
+ margin-top: var(--spacing-01);
+ }
+}
+
+.keyboard-tooltip {
+ .tooltip-inner {
+ max-width: none;
+ }
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/toolbar.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/toolbar.scss
index 4c03c0147d..f0ed2e720c 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/toolbar.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/toolbar.scss
@@ -7,6 +7,8 @@
--toolbar-btn-hover-color: var(--white);
--toolbar-btn-active-color: var(--white);
--toolbar-btn-active-bg-color: var(--green-50);
+ --toolbar-small-height: 32px;
+ --toolbar-alt-bg-color: var(--neutral-80);
--formatting-btn-color: var(--white);
--formatting-btn-bg: var(--neutral-80);
--formatting-btn-border: var(--neutral-70);
@@ -27,6 +29,7 @@
--toolbar-btn-hover-bg-color: var(--neutral-10);
--toolbar-btn-hover-color: var(--neutral-70);
--toolbar-btn-active-bg-color: var(--green-50);
+ --toolbar-alt-bg-color: var(--white);
--formatting-btn-color: var(--neutral-70);
--formatting-btn-bg: transparent;
--formatting-btn-border: var(--neutral-20);
@@ -43,7 +46,6 @@
display: flex;
align-items: center;
height: var(--toolbar-height);
- min-height: var(--toolbar-height);
border-bottom: 1px solid var(--toolbar-border-color);
button {
diff --git a/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx b/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx
index 5d494fbbd5..e7cf681034 100644
--- a/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx
+++ b/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx
@@ -44,7 +44,7 @@ describe('start free trial button', function () {
source="cypress-test"
buttonProps={{
variant: 'danger',
- size: 'large',
+ size: 'lg',
}}
/>
)