From fe7de51827ee689e62dc3cee618b3ed3fc732fc1 Mon Sep 17 00:00:00 2001 From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> Date: Mon, 27 May 2024 15:46:48 +0300 Subject: [PATCH] Merge pull request #18338 from overleaf/ii-bs5-split-badges-and-tags [web] Split badges and tags GitOrigin-RevId: fce5a93672f431ff74c2b63a67e249f5f7e7fecd --- .../components/members-table/member-row.tsx | 2 +- .../components/change-list/tag-tooltip.tsx | 15 ++-- .../file-tree/history-file-tree-item.tsx | 13 ++-- .../ui/components/bootstrap-5/badge.tsx | 9 +-- .../ui/components/bootstrap-5/tag.tsx | 42 +++++++++++ .../js/features/ui/components/ol/ol-badge.tsx | 1 - .../js/features/ui/components/ol/ol-tag.tsx | 28 ++++++++ .../frontend/js/shared/components/badge.tsx | 23 ++---- .../web/frontend/js/shared/components/tag.tsx | 45 ++++++++++++ .../frontend/stories/ui/badge-bs3.stories.tsx | 60 ++++------------ .../frontend/stories/ui/badge-bs5.stories.tsx | 31 +------- .../frontend/stories/ui/tag-bs3.stories.tsx | 70 +++++++++++++++++++ .../frontend/stories/ui/tag-bs5.stories.tsx | 60 ++++++++++++++++ .../bootstrap-5/components/badge.scss | 34 ++++++--- .../stylesheets/components/badge.less | 18 +++-- 15 files changed, 311 insertions(+), 140 deletions(-) create mode 100644 services/web/frontend/js/features/ui/components/bootstrap-5/tag.tsx create mode 100644 services/web/frontend/js/features/ui/components/ol/ol-tag.tsx create mode 100644 services/web/frontend/js/shared/components/tag.tsx create mode 100644 services/web/frontend/stories/ui/tag-bs3.stories.tsx create mode 100644 services/web/frontend/stories/ui/tag-bs5.stories.tsx diff --git a/services/web/frontend/js/features/group-management/components/members-table/member-row.tsx b/services/web/frontend/js/features/group-management/components/members-table/member-row.tsx index 75b7b17ed5..97e71c5705 100644 --- a/services/web/frontend/js/features/group-management/components/members-table/member-row.tsx +++ b/services/web/frontend/js/features/group-management/components/members-table/member-row.tsx @@ -48,7 +48,7 @@ export default function MemberRow({ > diff --git a/services/web/frontend/js/features/history/components/change-list/tag-tooltip.tsx b/services/web/frontend/js/features/history/components/change-list/tag-tooltip.tsx index 05f0625531..afe9c8fc16 100644 --- a/services/web/frontend/js/features/history/components/change-list/tag-tooltip.tsx +++ b/services/web/frontend/js/features/history/components/change-list/tag-tooltip.tsx @@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next' import { Modal } from 'react-bootstrap' import Icon from '../../../../shared/components/icon' import Tooltip from '../../../../shared/components/tooltip' -import Badge from '../../../../shared/components/badge' import AccessibleModal from '../../../../shared/components/accessible-modal' import ModalError from './modal-error' import useAbortController from '../../../../shared/hooks/use-abort-controller' @@ -16,13 +15,14 @@ import { LoadedLabel } from '../../services/types/label' import { debugConsole } from '@/utils/debugging' import { formatTimeBasedOnYear } from '@/features/utils/format-date' import { useEditorContext } from '@/shared/context/editor-context' +import Tag from '@/shared/components/tag' type TagProps = { label: LoadedLabel currentUserId: string } -function Tag({ label, currentUserId, ...props }: TagProps) { +function ChangeTag({ label, currentUserId, ...props }: TagProps) { const { isProjectOwner } = useEditorContext() const { t } = useTranslation() @@ -70,22 +70,21 @@ function Tag({ label, currentUserId, ...props }: TagProps) { return ( <> - } closeBtnProps={ showCloseButton ? { 'aria-label': t('delete'), onClick: showConfirmationModal } : undefined } - bsStyle={null} - className="badge-bs3 history-version-badge" + className="history-version-badge" data-testid="history-version-badge" {...props} > {isPseudoCurrentStateLabel ? t('history_label_project_current_state') : label.comment} - + {!isPseudoCurrentStateLabel && ( - + ) : ( - + ) } diff --git a/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx index 2e1e3ff8b8..19282593f2 100644 --- a/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx +++ b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames' import type { ReactNode } from 'react' import type { FileOperation } from '../../services/types/file-operation' -import Badge from '../../../../shared/components/badge' +import Tag from '@/shared/components/tag' type FileTreeItemProps = { name: string @@ -25,14 +25,9 @@ export default function HistoryFileTreeItem({ > {name} - {operation ? ( - - {operation} - - ) : null} + {operation && ( + {operation} + )} ) diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/badge.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/badge.tsx index 54ec335099..e3c58f345b 100644 --- a/services/web/frontend/js/features/ui/components/bootstrap-5/badge.tsx +++ b/services/web/frontend/js/features/ui/components/bootstrap-5/badge.tsx @@ -1,12 +1,10 @@ import { Badge as BSBadge } from 'react-bootstrap-5' import { MergeAndOverride } from '../../../../../../types/utils' -import MaterialIcon from '@/shared/components/material-icon' type BadgeProps = MergeAndOverride< React.ComponentProps, { prepend?: React.ReactNode - closeBtnProps?: React.ComponentProps<'button'> } > @@ -14,12 +12,7 @@ function Badge({ prepend, children, closeBtnProps, ...rest }: BadgeProps) { return ( {prepend && {prepend}} - {children} - {closeBtnProps && ( - - )} + {children} ) } diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/tag.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/tag.tsx new file mode 100644 index 0000000000..38cb2962d3 --- /dev/null +++ b/services/web/frontend/js/features/ui/components/bootstrap-5/tag.tsx @@ -0,0 +1,42 @@ +import { useTranslation } from 'react-i18next' +import { Badge } from 'react-bootstrap-5' +import MaterialIcon from '@/shared/components/material-icon' +import { MergeAndOverride } from '../../../../../../types/utils' +import classnames from 'classnames' + +type TagProps = MergeAndOverride< + React.ComponentProps, + { + prepend?: React.ReactNode + closeBtnProps?: React.ComponentProps<'button'> + } +> + +function Tag({ + prepend, + children, + closeBtnProps, + className, + ...rest +}: TagProps) { + const { t } = useTranslation() + + return ( + + {prepend && {prepend}} + {children} + {closeBtnProps && ( + + )} + + ) +} + +export default Tag diff --git a/services/web/frontend/js/features/ui/components/ol/ol-badge.tsx b/services/web/frontend/js/features/ui/components/ol/ol-badge.tsx index a30e6f08cb..0e88529a86 100644 --- a/services/web/frontend/js/features/ui/components/ol/ol-badge.tsx +++ b/services/web/frontend/js/features/ui/components/ol/ol-badge.tsx @@ -15,7 +15,6 @@ function OLBadge(props: OLBadgeProps) { let bs3BadgeProps: React.ComponentProps = { prepend: rest.prepend, children: rest.children, - closeBtnProps: rest.closeBtnProps, className: rest.className, bsStyle: rest.bg, } diff --git a/services/web/frontend/js/features/ui/components/ol/ol-tag.tsx b/services/web/frontend/js/features/ui/components/ol/ol-tag.tsx new file mode 100644 index 0000000000..6b99313b06 --- /dev/null +++ b/services/web/frontend/js/features/ui/components/ol/ol-tag.tsx @@ -0,0 +1,28 @@ +import Tag from '@/features/ui/components/bootstrap-5/tag' +import BS3Tag from '@/shared/components/tag' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' + +type OLTagProps = React.ComponentProps & { + bs3Props?: React.ComponentProps +} + +function OLTag(props: OLTagProps) { + const { bs3Props, ...rest } = props + + const bs3TagProps: React.ComponentProps = { + children: rest.children, + prepend: rest.prepend, + closeBtnProps: rest.closeBtnProps, + className: rest.className, + ...bs3Props, + } + + return ( + } + bs5={} + /> + ) +} + +export default OLTag diff --git a/services/web/frontend/js/shared/components/badge.tsx b/services/web/frontend/js/shared/components/badge.tsx index 78d0934367..2fc184ab4c 100644 --- a/services/web/frontend/js/shared/components/badge.tsx +++ b/services/web/frontend/js/shared/components/badge.tsx @@ -1,28 +1,18 @@ +import { Label } from 'react-bootstrap' import classnames from 'classnames' import { MergeAndOverride } from '../../../../types/utils' -import OLBadge from '@/features/ui/components/ol/ol-badge' type BadgeProps = MergeAndOverride< React.ComponentProps<'span'>, { prepend?: React.ReactNode children: React.ReactNode - closeBtnProps?: React.ComponentProps<'button'> className?: string - bsStyle?: NonNullable< - React.ComponentProps['bs3Props'] - >['bsStyle'] + bsStyle?: React.ComponentProps['bsStyle'] | null } > -function Badge({ - prepend, - children, - closeBtnProps, - bsStyle, - className, - ...rest -}: BadgeProps) { +function Badge({ prepend, children, bsStyle, className, ...rest }: BadgeProps) { const classNames = bsStyle === null ? className @@ -30,13 +20,8 @@ function Badge({ return ( - {prepend && {prepend}} + {prepend && {prepend}} {children} - {closeBtnProps && ( - - )} ) } diff --git a/services/web/frontend/js/shared/components/tag.tsx b/services/web/frontend/js/shared/components/tag.tsx new file mode 100644 index 0000000000..491771b20e --- /dev/null +++ b/services/web/frontend/js/shared/components/tag.tsx @@ -0,0 +1,45 @@ +import { useTranslation } from 'react-i18next' +import { Label } from 'react-bootstrap' +import { MergeAndOverride } from '../../../../types/utils' +import classnames from 'classnames' + +type TagProps = MergeAndOverride< + React.ComponentProps<'span'>, + { + prepend?: React.ReactNode + children: React.ReactNode + closeBtnProps?: React.ComponentProps<'button'> + className?: string + bsStyle?: React.ComponentProps['bsStyle'] | null + } +> + +function Tag({ + prepend, + children, + closeBtnProps, + bsStyle, + className, + ...rest +}: TagProps) { + const { t } = useTranslation() + + return ( + + {prepend && {prepend}} + {children} + {closeBtnProps && ( + + )} + + ) +} + +export default Tag diff --git a/services/web/frontend/stories/ui/badge-bs3.stories.tsx b/services/web/frontend/stories/ui/badge-bs3.stories.tsx index c50b314905..2a062c4467 100644 --- a/services/web/frontend/stories/ui/badge-bs3.stories.tsx +++ b/services/web/frontend/stories/ui/badge-bs3.stories.tsx @@ -1,11 +1,10 @@ -import Badge from '@/shared/components/badge' +import BS3Badge from '@/shared/components/badge' import Icon from '@/shared/components/icon' import type { Meta, StoryObj } from '@storybook/react' -import classnames from 'classnames' -const meta: Meta = { +const meta: Meta = { title: 'Shared / Components / Badge / Bootstrap 3', - component: Badge, + component: BS3Badge, parameters: { bootstrap5: false, }, @@ -19,7 +18,7 @@ const meta: Meta = { }, }, bsStyle: { - options: [null, 'primary', 'warning', 'danger'], + options: ['info', 'primary', 'warning', 'danger'], control: { type: 'radio' }, }, className: { @@ -27,67 +26,34 @@ const meta: Meta = { disable: true, }, }, - closeBtnProps: { - table: { - disable: true, - }, - }, }, } export default meta -type Story = StoryObj +type Story = StoryObj export const BadgeDefault: Story = { render: args => { return ( - +
+ +
) }, } BadgeDefault.args = { - bsStyle: null, + bsStyle: meta.argTypes!.bsStyle!.options[0], } export const BadgePrepend: Story = { render: args => { return ( - } - {...args} - /> +
+ } {...args} /> +
) }, } BadgePrepend.args = { - bsStyle: null, -} - -export const BadgeWithCloseButton: Story = { - render: args => { - return ( - } - closeBtnProps={{ - onClick: () => alert('Close triggered!'), - }} - {...args} - /> - ) - }, -} -BadgeWithCloseButton.args = { - bsStyle: null, -} -BadgeWithCloseButton.argTypes = { - bsStyle: { - table: { - disable: true, - }, - }, + bsStyle: meta.argTypes!.bsStyle!.options[0], } diff --git a/services/web/frontend/stories/ui/badge-bs5.stories.tsx b/services/web/frontend/stories/ui/badge-bs5.stories.tsx index 45b88a0928..e5468c7c66 100644 --- a/services/web/frontend/stories/ui/badge-bs5.stories.tsx +++ b/services/web/frontend/stories/ui/badge-bs5.stories.tsx @@ -49,7 +49,7 @@ export const BadgeDefault: Story = { }, } BadgeDefault.args = { - bg: 'light', + bg: meta.argTypes!.bg!.options[0], } export const BadgePrepend: Story = { @@ -57,37 +57,12 @@ export const BadgePrepend: Story = { return ( } + prepend={} {...args} /> ) }, } BadgePrepend.args = { - bg: 'light', -} - -export const BadgeWithCloseButton: Story = { - render: args => { - return ( - } - closeBtnProps={{ - onClick: () => alert('Close triggered!'), - }} - {...args} - /> - ) - }, -} -BadgeWithCloseButton.args = { - bg: 'light', -} -BadgeWithCloseButton.argTypes = { - bg: { - table: { - disable: true, - }, - }, + bg: meta.argTypes!.bg!.options[0], } diff --git a/services/web/frontend/stories/ui/tag-bs3.stories.tsx b/services/web/frontend/stories/ui/tag-bs3.stories.tsx new file mode 100644 index 0000000000..5f7a661755 --- /dev/null +++ b/services/web/frontend/stories/ui/tag-bs3.stories.tsx @@ -0,0 +1,70 @@ +import Icon from '@/shared/components/icon' +import BS3Tag from '@/shared/components/tag' +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'Shared / Components / Tag / Bootstrap 3', + component: BS3Tag, + parameters: { + bootstrap5: false, + }, + args: { + children: 'Tag', + }, + argTypes: { + prepend: { + table: { + disable: true, + }, + }, + className: { + table: { + disable: true, + }, + }, + closeBtnProps: { + table: { + disable: true, + }, + }, + }, +} +export default meta + +type Story = StoryObj + +export const TagDefault: Story = { + render: args => { + return ( +
+ +
+ ) + }, +} + +export const TagPrepend: Story = { + render: args => { + return ( +
+ } {...args} /> +
+ ) + }, +} + +export const TagWithCloseButton: Story = { + render: args => { + return ( +
+ } + closeBtnProps={{ + onClick: () => alert('Close triggered!'), + }} + {...args} + /> +
+ ) + }, +} diff --git a/services/web/frontend/stories/ui/tag-bs5.stories.tsx b/services/web/frontend/stories/ui/tag-bs5.stories.tsx new file mode 100644 index 0000000000..b1d87edd19 --- /dev/null +++ b/services/web/frontend/stories/ui/tag-bs5.stories.tsx @@ -0,0 +1,60 @@ +import Icon from '@/shared/components/icon' +import Tag from '@/features/ui/components/bootstrap-5/tag' +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'Shared / Components / Tag / Bootstrap 5', + component: Tag, + parameters: { + bootstrap5: true, + }, + args: { + children: 'Tag', + }, + argTypes: { + prepend: { + table: { + disable: true, + }, + }, + className: { + table: { + disable: true, + }, + }, + closeBtnProps: { + table: { + disable: true, + }, + }, + }, +} +export default meta + +type Story = StoryObj + +export const TagDefault: Story = { + render: args => { + return + }, +} + +export const TagPrepend: Story = { + render: args => { + return } {...args} /> + }, +} + +export const TagWithCloseButton: Story = { + render: args => { + return ( + } + closeBtnProps={{ + onClick: () => alert('Close triggered!'), + }} + {...args} + /> + ) + }, +} diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/badge.scss b/services/web/frontend/stylesheets/bootstrap-5/components/badge.scss index 4971d2ae66..f6c0fa999d 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/components/badge.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/components/badge.scss @@ -1,13 +1,16 @@ .badge { display: inline-flex; - align-items: center; - overflow: hidden; + align-items: stretch; + max-width: 100%; line-height: var(--line-height-01); + padding: 0 var(--bs-badge-padding-x); } .badge-prepend { margin-left: calc($spacing-01 / -2); margin-right: $spacing-01; + display: flex; + align-items: center; } .badge-close { @@ -16,15 +19,14 @@ display: flex; align-items: center; justify-content: center; + flex-shrink: 0; - // a random number that would cause the close button to expand enough - // so that it won't be affected by badge's padding - $expand: 100px; - - padding: $expand $spacing-01; - margin: (-$expand) (-$spacing-02) (-$expand) $spacing-02; - user-select: none; + padding: 0 $spacing-02; + margin: 0 (-$spacing-02) 0 $spacing-02; + border-top-right-radius: inherit; + border-bottom-right-radius: inherit; color: inherit; + user-select: none; .badge-close-icon { font-size: $font-size-base; @@ -34,3 +36,17 @@ background-color: var(--neutral-40); } } + +.badge-content { + @include text-truncate; + padding: var(--bs-badge-padding-y) 0; +} + +.badge-tag { + @include body-sm; + color: $dark; + + &:hover { + background-color: var(--neutral-30) !important; + } +} diff --git a/services/web/frontend/stylesheets/components/badge.less b/services/web/frontend/stylesheets/components/badge.less index 762cad8964..4190215c5b 100644 --- a/services/web/frontend/stylesheets/components/badge.less +++ b/services/web/frontend/stylesheets/components/badge.less @@ -1,10 +1,10 @@ -.badge-bs3 { +.badge-tag-bs3 { @size: 24px; @padding: 4px; display: inline-flex; align-items: center; - overflow: hidden; height: @size; + max-width: 100%; min-height: @size; padding: 0 @padding; white-space: nowrap; @@ -26,10 +26,14 @@ margin-left: 4px; font-size: 20px; height: @size; + line-height: 1; display: flex; align-items: center; justify-content: center; + flex-shrink: 0; margin-right: -@padding; + border-top-right-radius: inherit; + border-bottom-right-radius: inherit; color: inherit; &:hover { @@ -37,13 +41,7 @@ } } - &-sm { - @size-sm: 20px; - height: @size-sm; - font-size: @font-size-extra-small; - .badge-bs3-close { - width: @size-sm; - font-size: @size-sm; - } + &-content { + .text-overflow(); } }