diff --git a/services/web/.storybook/utils/with-bootstrap-switcher.tsx b/services/web/.storybook/utils/with-bootstrap-switcher.tsx index 1424c5d512..ce7c512ea3 100644 --- a/services/web/.storybook/utils/with-bootstrap-switcher.tsx +++ b/services/web/.storybook/utils/with-bootstrap-switcher.tsx @@ -11,4 +11,7 @@ export const bsVersionDecorator: Meta = { options: ['3', '5'], }, }, + args: { + [bootstrapVersionArg]: '3', + }, } diff --git a/services/web/frontend/js/features/project-list/components/table/project-list-table.tsx b/services/web/frontend/js/features/project-list/components/table/project-list-table.tsx index c0a75344e3..0a3302b343 100644 --- a/services/web/frontend/js/features/project-list/components/table/project-list-table.tsx +++ b/services/web/frontend/js/features/project-list/components/table/project-list-table.tsx @@ -47,7 +47,7 @@ function ProjectListTable() { selectOrUnselectAllProjects, } = useProjectListContext() const { handleSort } = useSort() - const checkAllRef = useRef() + const checkAllRef = useRef(null) const handleAllProjectsCheckboxChange = useCallback( (event: React.ChangeEvent) => { diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-add-comment.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-add-comment.tsx index 9d1c976f20..ebafb0cfc4 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-add-comment.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-add-comment.tsx @@ -9,12 +9,12 @@ import { useThreadsActionsContext } from '../context/threads-context' import { removeNewCommentRangeEffect } from '@/features/source-editor/extensions/add-comment' import useSubmittableTextInput from '../hooks/use-submittable-text-input' import AutoExpandingTextArea from '@/shared/components/auto-expanding-text-area' -import { Button } from 'react-bootstrap' import { ReviewPanelEntry } from './review-panel-entry' import { ThreadId } from '../../../../../types/review-panel/review-panel' import { Decoration } from '@codemirror/view' import { useModalsContext } from '@/features/ide-react/context/modals-context' import { debugConsole } from '@/utils/debugging' +import OLButton from '@/features/ui/components/ol/ol-button' export const ReviewPanelAddComment: FC<{ docId: string @@ -148,23 +148,23 @@ export const ReviewPanelAddComment: FC<{ disabled={submitting} />
- - +
diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-change.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-change.tsx index 799032a9cd..5e5947bd70 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-change.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-change.tsx @@ -8,8 +8,7 @@ import { import { useTranslation } from 'react-i18next' import classnames from 'classnames' import { usePermissionsContext } from '@/features/ide-react/context/permissions-context' -import { Button } from 'react-bootstrap' -import Tooltip from '@/shared/components/tooltip' +import OLTooltip from '@/features/ui/components/ol/ol-tooltip' import MaterialIcon from '@/shared/components/material-icon' import { formatTimeBasedOnYear } from '@/features/utils/format-date' import { useChangesUsersContext } from '../context/changes-users-context' @@ -109,29 +108,30 @@ export const ReviewPanelChange = memo<{ {editable && permissions.write && (
- - - + + - - - + +
)} diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-comment-options.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-comment-options.tsx index 03d078df8d..790ba0f906 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-comment-options.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-comment-options.tsx @@ -1,29 +1,80 @@ import ControlledDropdown from '@/shared/components/controlled-dropdown' import MaterialIcon from '@/shared/components/material-icon' -import { FC, memo } from 'react' -import { Dropdown, MenuItem } from 'react-bootstrap' +import { FC, memo, forwardRef } from 'react' +import { + Dropdown as BS3Dropdown, + MenuItem as BS3MenuItem, +} from 'react-bootstrap' import { useTranslation } from 'react-i18next' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import { + Dropdown, + DropdownItem, + DropdownMenu, + DropdownToggle, +} from '@/features/ui/components/bootstrap-5/dropdown-menu' +import classnames from 'classnames' + +const ReviewPanelCommentDropdownToggleButton = forwardRef< + HTMLButtonElement, + React.ButtonHTMLAttributes +>((props, ref) => ( + - - - + + + ) } diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-expandable-content.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-expandable-content.tsx index 1ceba0328c..ed8f837826 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-expandable-content.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-expandable-content.tsx @@ -1,6 +1,6 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react' import classNames from 'classnames' -import { Button } from 'react-bootstrap' +import OLButton from '@/features/ui/components/ol/ol-button' import { useTranslation } from 'react-i18next' export const ExpandableContent: FC<{ className?: string }> = ({ @@ -49,22 +49,22 @@ export const ExpandableContent: FC<{ className?: string }> = ({ {children} {isExpanded ? ( - + ) : ( isOverflowing && ( - + ) )} diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-header.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-header.tsx index facf40e81c..83d68486c3 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-header.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-header.tsx @@ -2,7 +2,6 @@ import { FC, memo, useState } from 'react' import { ReviewPanelResolvedThreadsButton } from './review-panel-resolved-threads-button' import { ReviewPanelTrackChangesMenu } from './review-panel-track-changes-menu' import ReviewPanelTrackChangesMenuButton from './review-panel-track-changes-menu-button' -import { Button } from 'react-bootstrap' import MaterialIcon from '@/shared/components/material-icon' import { useLayoutContext } from '@/shared/context/layout-context' import SplitTestBadge from '@/shared/components/split-test-badge' @@ -26,14 +25,13 @@ const ReviewPanelHeader: FC = () => { /> - +
diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-message.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-message.tsx index 0cabe3177d..8cedaa2436 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-message.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-message.tsx @@ -5,8 +5,7 @@ import { } from '../../../../../types/review-panel/review-panel' import { useTranslation } from 'react-i18next' import { formatTimeBasedOnYear } from '@/features/utils/format-date' -import Tooltip from '@/shared/components/tooltip' -import { Button } from 'react-bootstrap' +import OLTooltip from '@/features/ui/components/ol/ol-tooltip' import MaterialIcon from '@/shared/components/material-icon' import AutoExpandingTextArea from '@/shared/components/auto-expanding-text-area' import { buildName } from '../utils/build-name' @@ -90,26 +89,27 @@ export const ReviewPanelMessage: FC<{
{!isReply && !isThreadResolved && ( - - - + + )} {!isThreadResolved && ( )}
diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-more-comments-button.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-more-comments-button.tsx index 164d07b2a0..75bd8632ca 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-more-comments-button.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-more-comments-button.tsx @@ -1,8 +1,9 @@ import { FC, memo } from 'react' -import { Button } from 'react-bootstrap' import MaterialIcon from '@/shared/components/material-icon' import classNames from 'classnames' import { useTranslation } from 'react-i18next' +import OLButton from '@/features/ui/components/ol/ol-button' +import { bsVersion } from '@/features/utils/bootstrap-5' const MoreCommentsButton: FC<{ onClick: () => void @@ -17,14 +18,18 @@ const MoreCommentsButton: FC<{ upwards: direction === 'upward', })} > - +
) } diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-overview-file.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-overview-file.tsx index 15a87548d7..e1b46e64da 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-overview-file.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-overview-file.tsx @@ -11,7 +11,6 @@ import { } from '../../../../../types/change' import { canAggregate } from '../utils/can-aggregate' -import { Button } from 'react-bootstrap' import MaterialIcon from '@/shared/components/material-icon' import useOverviewFileCollapsed from '../hooks/use-overview-file-collapsed' import { useThreadsContext } from '../context/threads-context' @@ -61,9 +60,9 @@ export const ReviewPanelOverviewFile: FC<{ return ( <>
-
- + {!collapsed && (
diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-thread.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-thread.tsx index 21252a6fdb..30b9d84ccd 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-thread.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-thread.tsx @@ -2,12 +2,11 @@ import React, { FC, useCallback, useState } from 'react' import { useTranslation, Trans } from 'react-i18next' import { ThreadId } from '../../../../../types/review-panel/review-panel' import { useThreadsActionsContext } from '../context/threads-context' -import { Button } from 'react-bootstrap' +import OLTooltip from '@/features/ui/components/ol/ol-tooltip' import MaterialIcon from '@/shared/components/material-icon' import { ExpandableContent } from './review-panel-expandable-content' import { ReviewPanelCommentContent } from './review-panel-comment-content' import { Change, CommentOperation } from '../../../../../types/change' -import Tooltip from '@/shared/components/tooltip' import classNames from 'classnames' import { debugConsole } from '@/utils/debugging' import { useModalsContext } from '@/features/ide-react/context/modals-context' @@ -73,25 +72,25 @@ export const ReviewPanelResolvedThread: FC<{ />
- - - + + - - - + +
diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-button.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-button.tsx index 96fbfc1710..8cf1cc6c31 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-button.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-button.tsx @@ -1,9 +1,12 @@ import React, { FC, useRef, useState } from 'react' import Icon from '@/shared/components/icon' +import OLOverlay from '@/features/ui/components/ol/ol-overlay' +import OLPopover from '@/features/ui/components/ol/ol-popover' +import OLTooltip from '@/features/ui/components/ol/ol-tooltip' import { ReviewPanelResolvedThreadsMenu } from './review-panel-resolved-threads-menu' -import { Overlay, Popover } from 'react-bootstrap' -import Tooltip from '@/shared/components/tooltip' import { useTranslation } from 'react-i18next' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import MaterialIcon from '@/shared/components/material-icon' export const ReviewPanelResolvedThreadsButton: FC = () => { const [expanded, setExpanded] = useState(false) @@ -12,7 +15,7 @@ export const ReviewPanelResolvedThreadsButton: FC = () => { return ( <> - { ref={buttonRef} onClick={() => setExpanded(true)} > - + } + bs5={} + /> - + {expanded && ( - setExpanded(false)} - animation={false} + transition={false} container={this} containerPadding={0} placement="bottom" rootClose - target={buttonRef.current ?? undefined} + target={buttonRef.current} > - - - + + )} ) diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-menu.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-menu.tsx index 16b38425b0..15d42b796e 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-menu.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-menu.tsx @@ -4,9 +4,9 @@ import { useTranslation } from 'react-i18next' import { ReviewPanelResolvedThread } from './review-panel-resolved-thread' import useProjectRanges from '../hooks/use-project-ranges' import { useFileTreeData } from '@/shared/context/file-tree-data-context' -import Icon from '@/shared/components/icon' import { Change, CommentOperation } from '../../../../../types/change' import { ThreadId } from '../../../../../types/review-panel/review-panel' +import LoadingSpinner from '@/shared/components/loading-spinner' export const ReviewPanelResolvedThreadsMenu: FC = () => { const { t } = useTranslation() @@ -59,11 +59,7 @@ export const ReviewPanelResolvedThreadsMenu: FC = () => { }, [threads]) if (loading) { - return ( -
- -
- ) + return } if (!resolvedThreads.length) { diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel-track-changes-menu-button.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel-track-changes-menu-button.tsx index cb8de09b97..c2adaaff5e 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel-track-changes-menu-button.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel-track-changes-menu-button.tsx @@ -2,6 +2,8 @@ import { FC, memo } from 'react' import { Trans } from 'react-i18next' import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context' import Icon from '@/shared/components/icon' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import MaterialIcon from '@/shared/components/material-icon' const ReviewPanelTrackChangesMenuButton: FC<{ menuExpanded: boolean @@ -26,7 +28,12 @@ const ReviewPanelTrackChangesMenuButton: FC<{ components={{ strong: }} /> )} - + } + bs5={ + + } + /> ) } diff --git a/services/web/frontend/js/features/review-panel-new/components/review-panel.tsx b/services/web/frontend/js/features/review-panel-new/components/review-panel.tsx index 72250fda24..4f82351ffd 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-panel.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-panel.tsx @@ -24,7 +24,7 @@ const ReviewPanel: FC<{ mini?: boolean }> = ({ mini = false }) => { return (
-
+
{!mini && } {activeSubView === 'cur_file' && } diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/toolbar/track-changes-toggle.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/toolbar/track-changes-toggle.tsx index d0601b0940..52c8ae7b0d 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/toolbar/track-changes-toggle.tsx +++ b/services/web/frontend/js/features/source-editor/components/review-panel/toolbar/track-changes-toggle.tsx @@ -1,3 +1,5 @@ +import OLFormSwitch from '@/features/ui/components/ol/ol-form-switch' + type TrackChangesToggleProps = { id: string description: string @@ -14,20 +16,13 @@ function TrackChangesToggle({ value, }: TrackChangesToggleProps) { return ( -
- - -
+ ) } diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/dropdown-menu.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/dropdown-menu.tsx index 0ba364a19e..60c9d22850 100644 --- a/services/web/frontend/js/features/ui/components/bootstrap-5/dropdown-menu.tsx +++ b/services/web/frontend/js/features/ui/components/bootstrap-5/dropdown-menu.tsx @@ -103,9 +103,11 @@ const ForwardReferredDropdownItem = fixedForwardRef(DropdownItem, { export { ForwardReferredDropdownItem as DropdownItem } -export function DropdownToggle(props: DropdownToggleProps) { - return -} +export const DropdownToggle = forwardRef< + typeof BS5DropdownToggle, + DropdownToggleProps +>((props, ref) => ) +DropdownToggle.displayName = 'DropdownToggle' export const DropdownMenu = forwardRef< typeof BS5DropdownMenu, diff --git a/services/web/frontend/js/features/ui/components/ol/ol-form-checkbox.tsx b/services/web/frontend/js/features/ui/components/ol/ol-form-checkbox.tsx index e89ea75b34..5577d1016d 100644 --- a/services/web/frontend/js/features/ui/components/ol/ol-form-checkbox.tsx +++ b/services/web/frontend/js/features/ui/components/ol/ol-form-checkbox.tsx @@ -4,7 +4,7 @@ import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/boots import { getAriaAndDataProps } from '@/features/utils/bootstrap-5' type OLFormCheckboxProps = React.ComponentProps<(typeof Form)['Check']> & { - inputRef?: React.MutableRefObject + inputRef?: React.MutableRefObject bs3Props?: Record } diff --git a/services/web/frontend/js/features/ui/components/ol/ol-form-switch.tsx b/services/web/frontend/js/features/ui/components/ol/ol-form-switch.tsx new file mode 100644 index 0000000000..b751642d8b --- /dev/null +++ b/services/web/frontend/js/features/ui/components/ol/ol-form-switch.tsx @@ -0,0 +1,54 @@ +import { FormCheck, FormCheckProps, FormLabel } from 'react-bootstrap-5' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import { getAriaAndDataProps } from '@/features/utils/bootstrap-5' + +type OLFormSwitchProps = FormCheckProps & { + inputRef?: React.MutableRefObject + bs3Props?: React.InputHTMLAttributes +} + +function OLFormSwitch(props: OLFormSwitchProps) { + const { bs3Props, inputRef, label, id, ...rest } = props + + const bs3FormSwitchProps: React.InputHTMLAttributes = { + id, + checked: rest.checked, + required: rest.required, + readOnly: rest.readOnly, + disabled: rest.disabled, + autoComplete: rest.autoComplete, + defaultChecked: rest.defaultChecked, + onChange: rest.onChange as (e: React.ChangeEvent) => void, + ...getAriaAndDataProps(rest), + ...bs3Props, + } + + return ( + + + +
+ } + bs5={ + <> + + + {label} + + + } + /> + ) +} + +export default OLFormSwitch diff --git a/services/web/frontend/stories/input-switch.stories.tsx b/services/web/frontend/stories/input-switch.stories.tsx new file mode 100644 index 0000000000..7d7707716c --- /dev/null +++ b/services/web/frontend/stories/input-switch.stories.tsx @@ -0,0 +1,31 @@ +import OLFormSwitch from '@/features/ui/components/ol/ol-form-switch' +import { bsVersionDecorator } from '../../.storybook/utils/with-bootstrap-switcher' +import { disableControlsOf } from './utils/arg-types' + +export const Unchecked = () => { + return {}} checked={false} /> +} + +export const UncheckedDisabled = () => { + return {}} checked={false} disabled /> +} + +export const Checked = () => { + return {}} checked /> +} + +export const CheckedDisabled = () => { + return {}} checked disabled /> +} + +export default { + title: 'Shared / Components / Input Switch', + component: OLFormSwitch, + argTypes: { + ...bsVersionDecorator.argTypes, + ...disableControlsOf('inputRef', 'bs3Props'), + }, + args: { + ...bsVersionDecorator.args, + }, +} diff --git a/services/web/frontend/stories/switch.stories.tsx b/services/web/frontend/stories/switch.stories.tsx deleted file mode 100644 index 5997f88ede..0000000000 --- a/services/web/frontend/stories/switch.stories.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import Switch from '../js/shared/components/switch' - -export const Unchecked = () => { - return {}} checked={false} /> -} - -export const Checked = () => { - return {}} checked /> -} - -export default { - title: 'Shared / Components / Switch', - component: Switch, -} diff --git a/services/web/frontend/stylesheets/app/editor/review-panel-new.less b/services/web/frontend/stylesheets/app/editor/review-panel-new.less index c8ec25a36f..9022cf159f 100644 --- a/services/web/frontend/stylesheets/app/editor/review-panel-new.less +++ b/services/web/frontend/stylesheets/app/editor/review-panel-new.less @@ -86,7 +86,7 @@ .review-panel-entry-actions-icon { padding: @spacing-01; - font-size: 20px; + font-size: @font-size-05; } } } @@ -111,7 +111,7 @@ .review-panel-entry-icon { border-radius: @border-radius-base-new; padding: @spacing-02; - font-size: 16px; + font-size: @font-size-03; } .review-panel-entry-change-icon { @@ -138,7 +138,6 @@ top: var(--review-panel-top); width: var(--review-panel-width); height: @review-panel-header-height; - z-index: 2; display: flex; flex-direction: column; justify-content: center; @@ -187,7 +186,7 @@ display: flex; align-items: center; gap: 4px; - font-size: 14px; + font-size: @font-size-02; i { width: 8px; @@ -202,7 +201,7 @@ .review-panel-label { font-family: Lato, sans-serif; - font-size: 14px; + font-size: @font-size-02; font-weight: bold; margin: 0; } @@ -245,10 +244,6 @@ pointer-events: none; } - .review-panel-resolved-comments-loading { - text-align: center; - } - .review-panel-resolved-comments-empty { text-align: center; } @@ -472,7 +467,7 @@ width: var(--review-panel-width); z-index: 2; background-color: white; - border-top: 1px solid #d9d9d9; + border-top: 1px solid @rp-border-grey; display: flex; .review-panel-tab { @@ -507,11 +502,6 @@ min-height: 44px; } - .review-panel-add-comment { - position: absolute; - z-index: 2; - } - .review-panel-add-comment-buttons { display: flex; justify-content: flex-end; @@ -545,12 +535,11 @@ } } + // Would not be migrated .review-panel-more-comments-button { display: flex; justify-content: center; align-items: center; - padding: 2px 8px; - height: 24px; } &.review-panel-subview-overview { diff --git a/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss b/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss index 43404b3009..cff3359e88 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss @@ -6,6 +6,7 @@ $prefix: bs-; // Quickly modify global styling by enabling or disabling optional features. $enable-validation-icons: false; +$component-active-color: $white; // Fonts $font-family-sans-serif: 'Noto Sans', sans-serif; @@ -115,6 +116,15 @@ $form-check-input-border-radius: $border-radius-base; $form-check-input-focus-border: var(--border-primary); $form-check-input-disabled-opacity: 1; +// form-switch-variables +$form-switch-width: 34px; +$form-switch-padding-start: $spacing-03; +$form-switch-color: $component-active-color; +$form-switch-width: 34px; +$form-switch-padding-start: $spacing-03; +$form-switch-focus-color: $component-active-color; +$form-switch-checked-color: $component-active-color; + // Form validation // form-feedback-variables diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/form.scss b/services/web/frontend/stylesheets/bootstrap-5/components/form.scss index 6a844d1422..9c1a49ea18 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/components/form.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/components/form.scss @@ -73,6 +73,32 @@ } } +.form-switch { + .form-check-input { + --bs-form-check-bg: var(--bg-dark-tertiary); + + height: 20px; + margin: 0; + border: 0; + + &:hover { + cursor: pointer; + } + + &:disabled { + opacity: 0.32; + background-color: var(--bg-dark-tertiary); + + &:checked { + background-color: var(--bg-accent-01); + background-image: #{escape-svg( + url("data:image/svg+xml,") + )}; + } + } + } +} + .form-text { display: inline-flex; gap: $spacing-02; diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss index f3f7e0e844..67ad493407 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss @@ -22,6 +22,7 @@ @import 'editor/publish-modal'; @import 'editor/share'; @import 'editor/tags-input'; +@import 'editor/review-panel-new'; @import 'website-redesign'; @import 'group-settings'; @import 'templates-v2'; diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel-new.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel-new.scss new file mode 100644 index 0000000000..902be693d3 --- /dev/null +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel-new.scss @@ -0,0 +1,638 @@ +.review-panel-new { + $review-panel-header-height: 69px; + + &.review-panel-container { + height: 100%; + flex-shrink: 0; + position: relative; + } + + .review-panel-inner { + z-index: 6; + flex-shrink: 0; + background-color: var(--neutral-10); + border-left: solid 0 var(--neutral-20); + color: var(--content-primary); + font-family: $font-family-base; + line-height: $line-height-base; + font-size: var(--font-size-01); + box-sizing: content-box; + width: var(--review-panel-width); + min-height: var(--review-panel-height); + + .dropdown-menu { + z-index: 1; + min-width: var(--bs-dropdown-min-width); + } + } + + .review-panel-entry { + background-color: var(--white); + border-radius: var(--border-radius-base); + border: 1px solid var(--neutral-20); + padding: var(--spacing-04); + width: calc(100% - var(--spacing-04)); + margin-left: var(--spacing-02); + z-index: 1; + } + + .review-panel-entry.review-panel-entry-disabled { + opacity: 0.5; + pointer-events: none; + } + + .review-panel-entry-indicator { + display: none; + } + + .review-panel-entry-content { + display: flex; + flex-direction: column; + font-size: var(--font-size-01); + gap: var(--spacing-04); + } + + .review-panel-entry-focused, + .review-panel-entry-highlighted { + margin-left: var(--spacing-01); + border: 1px solid var(--border-active); + } + + .review-panel-entry-header { + display: flex; + justify-content: space-between; + margin-bottom: var(--spacing-01); + + .review-panel-entry-user { + color: var(--bg-info-01); + font-size: 110%; + } + + .review-panel-entry-time { + color: var(--content-secondary); + } + + .review-panel-entry-actions { + display: flex; + align-items: center; + gap: var(--spacing-03); + + .btn { + background-color: transparent; + border-width: 0; + padding: 0; + height: 24px; + width: 24px; + + &:hover, + &:focus { + background-color: var(--neutral-20); + color: var(--content-primary); + } + } + + .dropdown-toggle::after { + display: none; + } + + .review-panel-entry-actions-icon { + padding: var(--spacing-01); + font-size: var(--font-size-05); + } + } + } + + .review-panel-change-body { + display: flex; + align-items: flex-start; + color: var(--content-secondary); + gap: var(--spacing-02); + overflow-wrap: anywhere; + } + + .review-panel-content-highlight { + color: var(--content-primary); + text-decoration: none; + } + + del.review-panel-content-highlight { + text-decoration: line-through; + } + + .review-panel-entry-icon { + border-radius: var(--border-radius-base); + padding: var(--spacing-02); + font-size: var(--font-size-03); + } + + .review-panel-entry-change-icon { + margin-top: calc(-1 * var(--spacing-01)); + } + + .review-panel-entry-icon-accept { + background-color: var(--bg-accent-03); + color: var(--bg-accent-01); + } + + .review-panel-entry-icon-reject { + background-color: var(--bg-danger-03); + color: var(--bg-danger-01); + } + + .review-panel-entry-icon-changed { + background-color: var(--neutral-20); + color: var(--content-secondary); + } + + .review-panel-header { + position: fixed; + top: var(--review-panel-top); + width: var(--review-panel-width); + height: $review-panel-header-height; + display: flex; + flex-direction: column; + justify-content: center; + border-bottom: 1px solid var(--rp-border-grey); + background-color: white; + text-align: center; + z-index: 4; + } + + // TODO: Update this when we move the track changes menu to the new design + .rp-tc-state { + background-color: var(--white); + max-height: calc( + 100vh - var(--review-panel-top) - $review-panel-header-height + ); + overflow-y: auto; + } + + .review-panel-tools { + display: flex; + align-items: center; + justify-content: space-between; + padding-left: var(--spacing-02); + padding-right: var(--spacing-05); + flex-shrink: 0; + flex-basis: 32px; + } + + .resolved-comments-toggle { + display: flex; + align-items: center; + justify-content: center; + } + + .track-changes-indicator-circle { + width: 8px; + height: 8px; + border-radius: 100%; + background-color: var(--bg-accent-01); + } + + .track-changes-menu-button { + border: none; + background: none; + padding: 0; + display: flex; + align-items: center; + gap: var(--spacing-02); + font-size: var(--font-size-02); + + i { + width: 8px; + } + } + + .review-panel-heading { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-03) var(--spacing-02); + + .review-panel-label { + font-size: var(--font-size-02); + font-weight: bold; + margin: 0; + } + + .review-panel-split-test-badge { + margin-left: var(--spacing-02); + } + + .review-panel-close-button { + display: flex; + align-items: center; + border: none; + background-color: transparent; + color: var(--content-primary); + padding: var(--spacing-01); + + &:hover, + &:focus { + background-color: var(--neutral-20); + } + } + } + + &.review-panel-resolved-comments { + --bs-popover-border-width: 1px; + --bs-popover-bg: var(--bg-light-secondary); + --bs-popover-body-color: var(--content-secondary); + + width: 280px; + + .popover-body { + overflow-y: auto; + max-height: calc(100vh - 180px); + display: flex; + flex-direction: column; + gap: var(--spacing-02); + padding: var(--spacing-04) var(--spacing-03); + } + } + + .review-panel-resolved-disabled { + opacity: 0.5; + pointer-events: none; + } + + .review-panel-resolved-comments-empty { + text-align: center; + } + + .review-panel-resolved-comments-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-02) 0; + } + + .review-panel-resolved-comments-label { + font-weight: bold; + font-size: var(--font-size-02); + } + + .review-panel-resolved-comments-count { + background-color: var(--neutral-20); + border-radius: var(--border-radius-base); + padding: var(--spacing-01); + } + + .review-panel-resolved-comment { + background-color: var(--white); + border-radius: var(--border-radius-base); + padding: var(--spacing-04); + display: flex; + flex-direction: column; + gap: var(--spacing-04); + } + + .review-panel-resolved-comment-header { + display: flex; + justify-content: space-between; + align-items: center; + color: var(--content-secondary); + font-size: var(--font-size-01); + } + + .review-panel-resolved-comment-filename { + color: var(--content-primary); + } + + .review-panel-resolved-comment-buttons { + display: flex; + align-items: center; + gap: var(--spacing-03); + + .btn { + background-color: transparent; + border-width: 0; + color: var(--content-primary); + padding: var(--spacing-01); + height: 24px; + width: 24px; + + &:hover, + &:focus { + background-color: var(--neutral-20); + } + } + + .material-symbols { + font-size: var(--font-size-05); + } + } + + .review-panel-resolved-comment-quoted-text { + background-color: var(--neutral-20); + border-radius: var(--border-radius-base); + padding: var(--spacing-02) var(--spacing-04); + } + + .review-panel-resolved-comment-quoted-text-label { + color: var(--content-secondary); + font-size: var(--font-size-01); + } + + .review-panel-resolved-comment-quoted-text-quote { + overflow-wrap: anywhere; + font-size: var(--font-size-02); + } + + .review-panel-comment-wrapper { + display: flex; + gap: var(--spacing-04); + } + + .review-panel-comment { + flex-grow: 1; + } + + .review-panel-comment-reply-divider { + border-left: 2px solid var(--yellow-20); + } + + .review-panel-comment-body { + font-size: var(--font-size-02); + color: var(--content-primary); + overflow-wrap: anywhere; + } + + .review-panel-content-expandable { + display: -webkit-box; + text-overflow: ellipsis; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + line-clamp: 3; + overflow: hidden; + } + + .review-panel-content-expanded { + display: block; + } + + .review-panel-comment-input { + width: 100%; + font-size: var(--rp-base-font-size); + padding: 2px var(--spacing-03); + border-radius: var(--border-radius-base); + border: solid 1px var(--neutral-60); + resize: vertical; + color: var(--rp-type-darkgrey); + background-color: var(--white); + height: 25px; + min-height: 25px; + overflow-x: hidden; + max-height: 400px; + } + + .review-panel-empty-state { + position: fixed; + width: var(--review-panel-width); + top: 0; + bottom: 0; + pointer-events: none; + } + + .review-panel-empty-state-inner { + position: sticky; + top: 50%; + transform: translateY(-50%); + width: 100%; + padding-left: var(--spacing-06); + padding-right: var(--spacing-06); + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + + p { + margin-bottom: 0; + text-align: center; + } + } + + .review-panel-empty-state-comment-icon { + width: 80px; + height: 80px; + background-color: white; + border-radius: 100%; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: var(--spacing-06); + + .material-symbols { + font-size: 32px; + } + } + + .review-panel-overview { + padding: var(--spacing-02); + position: absolute; + top: $review-panel-header-height; + bottom: 59px; + width: 100%; + overflow: auto; + overscroll-behavior-block: none; + + .review-panel-entry { + margin-left: 0; + width: 100%; + } + } + + .review-panel-overview-file-header { + all: unset; + padding: var(--spacing-03) var(--spacing-04); + font-size: var(--font-size-02); + cursor: pointer; + display: flex; + align-items: center; + gap: var(--spacing-04); + box-sizing: border-box; + width: 100%; + } + + .review-panel-overfile-divider { + border-bottom: 1px solid var(--border-divider); + margin: var(--spacing-01) 0; + } + + .review-panel-overview-file-entries { + overflow: hidden; + padding-top: var(--spacing-02); + padding-bottom: var(--spacing-03); + } + + .review-panel-overview-file-entry-count { + background-color: var(--neutral-20); + padding: var(--spacing-01) var(--spacing-02); + margin-left: auto; + border-radius: var(--border-radius-base); + } + + .review-panel-footer { + position: fixed; + height: 60px; + bottom: 0; + width: var(--review-panel-width); + z-index: 2; + background-color: white; + border-top: 1px solid var(--rp-border-grey); + display: flex; + + .review-panel-tab { + flex: 0 0 50%; + padding: var(--spacing-03) 0; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--spacing-02); + border: 0; + border-top: solid 3px transparent; + background: none; + color: var(--content-secondary); + font-size: var(--font-size-02); + + &:hover, + &:focus { + text-decoration: none; + color: var(--content-primary); + } + + &-active { + color: var(--content-primary); + border-top: solid 3px var(--bg-accent-01); + } + } + } + + .review-panel-add-comment-textarea { + padding: var(--spacing-01) var(--spacing-03); + resize: vertical; + min-height: 44px; + } + + .review-panel-add-comment-buttons { + display: flex; + justify-content: flex-end; + gap: var(--spacing-04); + } + + .review-panel-add-comment-cancel-button { + background-color: transparent; + + &:hover, + &:focus { + background-color: var(--neutral-20); + color: var(--content-primary); + } + } + + .review-panel-more-comments-button-container { + position: fixed; + width: var(--review-panel-width); + display: flex; + justify-content: center; + z-index: 3; + + &.downwards { + // TODO: fix this to not use a magic number when we have updated the footer ui + top: calc(100% - 102px); + } + + &.upwards { + top: calc(var(--review-panel-top) + $review-panel-header-height + 16px); + } + } + + &.review-panel-subview-overview { + &.review-panel-container { + overflow-y: hidden; + position: sticky; + top: 0; + } + + .review-panel-inner { + min-height: auto; + height: 100%; + overflow: hidden; + } + } + + &.review-panel-mini { + overflow: visible !important; + + .review-panel-inner { + width: 24px; + } + + .review-panel-entry { + margin-left: 0; + background-color: transparent; + border: none; + width: 100%; + } + + .review-panel-entry-indicator { + position: absolute; + left: 0; + top: 0; + display: flex; + color: var(--content-secondary); + cursor: pointer; + } + + .review-panel-entry-content { + display: none; + background: var(--white); + border: 1px solid var(--rp-border-grey); + border-radius: var(--border-radius-base); + width: 200px; + padding: var(--spacing-02); + } + + .review-panel-entry-hover { + .review-panel-entry-content { + display: initial; + position: absolute; + left: -200px; + top: 0; + } + } + + .review-panel-more-comments-button-container { + display: none; + } + + .review-panel-footer { + display: none; + } + } +} + +.review-tooltip-menu { + box-shadow: 0 2px 4px 0 #1e253029; + border: none; + border-radius: var(--border-radius-base); + padding: var(--spacing-02); +} + +.review-tooltip-menu-button { + background-color: inherit; + border: none; + display: flex; + align-items: center; + gap: var(--spacing-01); + padding: var(--spacing-01); +} + +.review-tooltip-add-comment-button { + padding: var(--spacing-01) var(--spacing-04); +} + +.review-panel-tooltip { + pointer-events: none; // this is to prevent mouseLeave event from firing when hovering over the tooltip +} diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel.scss index 0aee1bdf17..b0cb15d5c5 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel.scss @@ -1,5 +1,11 @@ +@use 'sass:color'; + :root { --review-icon: url('../../../../../public/img/ol-icons/review-icon-dark-theme.svg'); + --rp-base-font-size: var(--font-size-01); + --rp-bg-dim-blue: #fafafa; + --rp-border-grey: #d9d9d9; + --rp-type-darkgrey: #3f3f3f; } @include theme('light') { @@ -15,6 +21,43 @@ } } +$rp-type-blue: #6b7797; + +.rp-tc-state { + position: absolute; + top: 100%; + left: 0; + right: 0; + overflow: hidden; + list-style: none; + padding: 0 var(--spacing-03); + margin: 0; + border-bottom: 1px solid var(--rp-border-grey); + background-color: var(--rp-bg-dim-blue); + text-align: left; +} + +.rp-tc-state-item { + display: flex; + align-items: center; + padding: var(--spacing-02) 0; + + &:last-of-type { + padding-bottom: var(--spacing-03); + } +} + +.rp-tc-state-item-name { + @extend .text-truncate; + + flex-grow: 1; + font-weight: 600; +} + +.rp-tc-state-item-name-disabled { + opacity: 0.35; +} + .review-icon { display: inline-block; background-image: var(--review-icon); @@ -27,3 +70,22 @@ content: '\00a0'; // Non-breakable space. A non-breakable character here makes this icon work like font-awesome. } } + +.resolved-comments-toggle { + background-color: var(--bg-light-secondary); + font-size: var(--font-size-02); + color: color.adjust($rp-type-blue, $lightness: 25%); + border: solid 1px var(--rp-border-grey); + border-radius: var(--border-radius-base); + padding: 0 var(--spacing-02); + display: block; + height: 22px; + width: 22px; + line-height: 1.4; + + &:hover, + &:focus { + text-decoration: none; + color: $rp-type-blue; + } +} diff --git a/services/web/frontend/stylesheets/components/input-switch.less b/services/web/frontend/stylesheets/components/input-switch.less index ecdfa632e7..b7c29e70fe 100644 --- a/services/web/frontend/stylesheets/components/input-switch.less +++ b/services/web/frontend/stylesheets/components/input-switch.less @@ -1,6 +1,5 @@ .input-switch { display: inline-block; - vertical-align: middle; padding-left: 5px; } .input-switch-hidden-input {