mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #18338 from overleaf/ii-bs5-split-badges-and-tags
[web] Split badges and tags GitOrigin-RevId: fce5a93672f431ff74c2b63a67e249f5f7e7fecd
This commit is contained in:
parent
3a1560894a
commit
fe7de51827
15 changed files with 311 additions and 140 deletions
|
@ -48,7 +48,7 @@ export default function MemberRow({
|
||||||
>
|
>
|
||||||
<Badge
|
<Badge
|
||||||
bsStyle={null}
|
bsStyle={null}
|
||||||
className="badge-bs3"
|
className="badge-tag-bs3"
|
||||||
aria-label={t('pending_invite')}
|
aria-label={t('pending_invite')}
|
||||||
data-testid="badge-pending-invite"
|
data-testid="badge-pending-invite"
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
|
||||||
import { Modal } from 'react-bootstrap'
|
import { Modal } from 'react-bootstrap'
|
||||||
import Icon from '../../../../shared/components/icon'
|
import Icon from '../../../../shared/components/icon'
|
||||||
import Tooltip from '../../../../shared/components/tooltip'
|
import Tooltip from '../../../../shared/components/tooltip'
|
||||||
import Badge from '../../../../shared/components/badge'
|
|
||||||
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
||||||
import ModalError from './modal-error'
|
import ModalError from './modal-error'
|
||||||
import useAbortController from '../../../../shared/hooks/use-abort-controller'
|
import useAbortController from '../../../../shared/hooks/use-abort-controller'
|
||||||
|
@ -16,13 +15,14 @@ import { LoadedLabel } from '../../services/types/label'
|
||||||
import { debugConsole } from '@/utils/debugging'
|
import { debugConsole } from '@/utils/debugging'
|
||||||
import { formatTimeBasedOnYear } from '@/features/utils/format-date'
|
import { formatTimeBasedOnYear } from '@/features/utils/format-date'
|
||||||
import { useEditorContext } from '@/shared/context/editor-context'
|
import { useEditorContext } from '@/shared/context/editor-context'
|
||||||
|
import Tag from '@/shared/components/tag'
|
||||||
|
|
||||||
type TagProps = {
|
type TagProps = {
|
||||||
label: LoadedLabel
|
label: LoadedLabel
|
||||||
currentUserId: string
|
currentUserId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function Tag({ label, currentUserId, ...props }: TagProps) {
|
function ChangeTag({ label, currentUserId, ...props }: TagProps) {
|
||||||
const { isProjectOwner } = useEditorContext()
|
const { isProjectOwner } = useEditorContext()
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -70,22 +70,21 @@ function Tag({ label, currentUserId, ...props }: TagProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Badge
|
<Tag
|
||||||
prepend={<Icon type="tag" fw />}
|
prepend={<Icon type="tag" fw />}
|
||||||
closeBtnProps={
|
closeBtnProps={
|
||||||
showCloseButton
|
showCloseButton
|
||||||
? { 'aria-label': t('delete'), onClick: showConfirmationModal }
|
? { 'aria-label': t('delete'), onClick: showConfirmationModal }
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
bsStyle={null}
|
className="history-version-badge"
|
||||||
className="badge-bs3 history-version-badge"
|
|
||||||
data-testid="history-version-badge"
|
data-testid="history-version-badge"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{isPseudoCurrentStateLabel
|
{isPseudoCurrentStateLabel
|
||||||
? t('history_label_project_current_state')
|
? t('history_label_project_current_state')
|
||||||
: label.comment}
|
: label.comment}
|
||||||
</Badge>
|
</Tag>
|
||||||
{!isPseudoCurrentStateLabel && (
|
{!isPseudoCurrentStateLabel && (
|
||||||
<AccessibleModal
|
<AccessibleModal
|
||||||
show={showDeleteModal}
|
show={showDeleteModal}
|
||||||
|
@ -167,10 +166,10 @@ function TagTooltip({ label, currentUserId, showTooltip }: LabelBadgesProps) {
|
||||||
id={label.id}
|
id={label.id}
|
||||||
overlayProps={{ placement: 'left' }}
|
overlayProps={{ placement: 'left' }}
|
||||||
>
|
>
|
||||||
<Tag label={label} currentUserId={currentUserId} />
|
<ChangeTag label={label} currentUserId={currentUserId} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Tag label={label} currentUserId={currentUserId} />
|
<ChangeTag label={label} currentUserId={currentUserId} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import type { FileOperation } from '../../services/types/file-operation'
|
import type { FileOperation } from '../../services/types/file-operation'
|
||||||
import Badge from '../../../../shared/components/badge'
|
import Tag from '@/shared/components/tag'
|
||||||
|
|
||||||
type FileTreeItemProps = {
|
type FileTreeItemProps = {
|
||||||
name: string
|
name: string
|
||||||
|
@ -25,14 +25,9 @@ export default function HistoryFileTreeItem({
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
{operation ? (
|
{operation && (
|
||||||
<Badge
|
<Tag className="history-file-tree-item-badge">{operation}</Tag>
|
||||||
bsStyle={null}
|
)}
|
||||||
className="badge-bs3 history-file-tree-item-badge"
|
|
||||||
>
|
|
||||||
{operation}
|
|
||||||
</Badge>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import { Badge as BSBadge } from 'react-bootstrap-5'
|
import { Badge as BSBadge } from 'react-bootstrap-5'
|
||||||
import { MergeAndOverride } from '../../../../../../types/utils'
|
import { MergeAndOverride } from '../../../../../../types/utils'
|
||||||
import MaterialIcon from '@/shared/components/material-icon'
|
|
||||||
|
|
||||||
type BadgeProps = MergeAndOverride<
|
type BadgeProps = MergeAndOverride<
|
||||||
React.ComponentProps<typeof BSBadge>,
|
React.ComponentProps<typeof BSBadge>,
|
||||||
{
|
{
|
||||||
prepend?: React.ReactNode
|
prepend?: React.ReactNode
|
||||||
closeBtnProps?: React.ComponentProps<'button'>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
@ -14,12 +12,7 @@ function Badge({ prepend, children, closeBtnProps, ...rest }: BadgeProps) {
|
||||||
return (
|
return (
|
||||||
<BSBadge {...rest}>
|
<BSBadge {...rest}>
|
||||||
{prepend && <span className="badge-prepend">{prepend}</span>}
|
{prepend && <span className="badge-prepend">{prepend}</span>}
|
||||||
{children}
|
<span className="badge-content">{children}</span>
|
||||||
{closeBtnProps && (
|
|
||||||
<button type="button" className="badge-close" {...closeBtnProps}>
|
|
||||||
<MaterialIcon className="badge-close-icon" type="close" />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</BSBadge>
|
</BSBadge>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<typeof Badge>,
|
||||||
|
{
|
||||||
|
prepend?: React.ReactNode
|
||||||
|
closeBtnProps?: React.ComponentProps<'button'>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
|
||||||
|
function Tag({
|
||||||
|
prepend,
|
||||||
|
children,
|
||||||
|
closeBtnProps,
|
||||||
|
className,
|
||||||
|
...rest
|
||||||
|
}: TagProps) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge bg="light" className={classnames('badge-tag', className)} {...rest}>
|
||||||
|
{prepend && <span className="badge-prepend">{prepend}</span>}
|
||||||
|
<span className="badge-content">{children}</span>
|
||||||
|
{closeBtnProps && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="badge-close"
|
||||||
|
aria-label={t('remove_tag', { tagName: children })}
|
||||||
|
{...closeBtnProps}
|
||||||
|
>
|
||||||
|
<MaterialIcon className="badge-close-icon" type="close" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tag
|
|
@ -15,7 +15,6 @@ function OLBadge(props: OLBadgeProps) {
|
||||||
let bs3BadgeProps: React.ComponentProps<typeof BS3Badge> = {
|
let bs3BadgeProps: React.ComponentProps<typeof BS3Badge> = {
|
||||||
prepend: rest.prepend,
|
prepend: rest.prepend,
|
||||||
children: rest.children,
|
children: rest.children,
|
||||||
closeBtnProps: rest.closeBtnProps,
|
|
||||||
className: rest.className,
|
className: rest.className,
|
||||||
bsStyle: rest.bg,
|
bsStyle: rest.bg,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<typeof Tag> & {
|
||||||
|
bs3Props?: React.ComponentProps<typeof BS3Tag>
|
||||||
|
}
|
||||||
|
|
||||||
|
function OLTag(props: OLTagProps) {
|
||||||
|
const { bs3Props, ...rest } = props
|
||||||
|
|
||||||
|
const bs3TagProps: React.ComponentProps<typeof BS3Tag> = {
|
||||||
|
children: rest.children,
|
||||||
|
prepend: rest.prepend,
|
||||||
|
closeBtnProps: rest.closeBtnProps,
|
||||||
|
className: rest.className,
|
||||||
|
...bs3Props,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<BS3Tag {...bs3TagProps} />}
|
||||||
|
bs5={<Tag {...rest} />}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OLTag
|
|
@ -1,28 +1,18 @@
|
||||||
|
import { Label } from 'react-bootstrap'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { MergeAndOverride } from '../../../../types/utils'
|
import { MergeAndOverride } from '../../../../types/utils'
|
||||||
import OLBadge from '@/features/ui/components/ol/ol-badge'
|
|
||||||
|
|
||||||
type BadgeProps = MergeAndOverride<
|
type BadgeProps = MergeAndOverride<
|
||||||
React.ComponentProps<'span'>,
|
React.ComponentProps<'span'>,
|
||||||
{
|
{
|
||||||
prepend?: React.ReactNode
|
prepend?: React.ReactNode
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
closeBtnProps?: React.ComponentProps<'button'>
|
|
||||||
className?: string
|
className?: string
|
||||||
bsStyle?: NonNullable<
|
bsStyle?: React.ComponentProps<typeof Label>['bsStyle'] | null
|
||||||
React.ComponentProps<typeof OLBadge>['bs3Props']
|
|
||||||
>['bsStyle']
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
function Badge({
|
function Badge({ prepend, children, bsStyle, className, ...rest }: BadgeProps) {
|
||||||
prepend,
|
|
||||||
children,
|
|
||||||
closeBtnProps,
|
|
||||||
bsStyle,
|
|
||||||
className,
|
|
||||||
...rest
|
|
||||||
}: BadgeProps) {
|
|
||||||
const classNames =
|
const classNames =
|
||||||
bsStyle === null
|
bsStyle === null
|
||||||
? className
|
? className
|
||||||
|
@ -30,13 +20,8 @@ function Badge({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={classNames} {...rest}>
|
<span className={classNames} {...rest}>
|
||||||
{prepend && <span className="badge-bs3-prepend">{prepend}</span>}
|
{prepend && <span className="badge-tag-bs3-prepend">{prepend}</span>}
|
||||||
{children}
|
{children}
|
||||||
{closeBtnProps && (
|
|
||||||
<button type="button" className="badge-bs3-close" {...closeBtnProps}>
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
45
services/web/frontend/js/shared/components/tag.tsx
Normal file
45
services/web/frontend/js/shared/components/tag.tsx
Normal file
|
@ -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<typeof Label>['bsStyle'] | null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
|
||||||
|
function Tag({
|
||||||
|
prepend,
|
||||||
|
children,
|
||||||
|
closeBtnProps,
|
||||||
|
bsStyle,
|
||||||
|
className,
|
||||||
|
...rest
|
||||||
|
}: TagProps) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={classnames('badge-tag-bs3', className)} {...rest}>
|
||||||
|
{prepend && <span className="badge-tag-bs3-prepend">{prepend}</span>}
|
||||||
|
<span className="badge-tag-bs3-content">{children}</span>
|
||||||
|
{closeBtnProps && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="badge-tag-bs3-close"
|
||||||
|
aria-label={t('remove_tag', { tagName: children })}
|
||||||
|
{...closeBtnProps}
|
||||||
|
>
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tag
|
|
@ -1,11 +1,10 @@
|
||||||
import Badge from '@/shared/components/badge'
|
import BS3Badge from '@/shared/components/badge'
|
||||||
import Icon from '@/shared/components/icon'
|
import Icon from '@/shared/components/icon'
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
import classnames from 'classnames'
|
|
||||||
|
|
||||||
const meta: Meta<typeof Badge> = {
|
const meta: Meta<typeof BS3Badge> = {
|
||||||
title: 'Shared / Components / Badge / Bootstrap 3',
|
title: 'Shared / Components / Badge / Bootstrap 3',
|
||||||
component: Badge,
|
component: BS3Badge,
|
||||||
parameters: {
|
parameters: {
|
||||||
bootstrap5: false,
|
bootstrap5: false,
|
||||||
},
|
},
|
||||||
|
@ -19,7 +18,7 @@ const meta: Meta<typeof Badge> = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
bsStyle: {
|
bsStyle: {
|
||||||
options: [null, 'primary', 'warning', 'danger'],
|
options: ['info', 'primary', 'warning', 'danger'],
|
||||||
control: { type: 'radio' },
|
control: { type: 'radio' },
|
||||||
},
|
},
|
||||||
className: {
|
className: {
|
||||||
|
@ -27,67 +26,34 @@ const meta: Meta<typeof Badge> = {
|
||||||
disable: true,
|
disable: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
closeBtnProps: {
|
|
||||||
table: {
|
|
||||||
disable: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
export default meta
|
export default meta
|
||||||
|
|
||||||
type Story = StoryObj<typeof Badge>
|
type Story = StoryObj<typeof BS3Badge>
|
||||||
|
|
||||||
export const BadgeDefault: Story = {
|
export const BadgeDefault: Story = {
|
||||||
render: args => {
|
render: args => {
|
||||||
return (
|
return (
|
||||||
<Badge
|
<div className="small">
|
||||||
className={classnames({ 'badge-bs3': args.bsStyle === null })}
|
<BS3Badge {...args} />
|
||||||
{...args}
|
</div>
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
BadgeDefault.args = {
|
BadgeDefault.args = {
|
||||||
bsStyle: null,
|
bsStyle: meta.argTypes!.bsStyle!.options[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BadgePrepend: Story = {
|
export const BadgePrepend: Story = {
|
||||||
render: args => {
|
render: args => {
|
||||||
return (
|
return (
|
||||||
<Badge
|
<div className="small">
|
||||||
className={classnames({ 'badge-bs3': args.bsStyle === null })}
|
<BS3Badge prepend={<Icon type="star" fw />} {...args} />
|
||||||
prepend={<Icon type="tag" fw />}
|
</div>
|
||||||
{...args}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
BadgePrepend.args = {
|
BadgePrepend.args = {
|
||||||
bsStyle: null,
|
bsStyle: meta.argTypes!.bsStyle!.options[0],
|
||||||
}
|
|
||||||
|
|
||||||
export const BadgeWithCloseButton: Story = {
|
|
||||||
render: args => {
|
|
||||||
return (
|
|
||||||
<Badge
|
|
||||||
className={classnames({ 'badge-bs3': args.bsStyle === null })}
|
|
||||||
prepend={<Icon type="tag" fw />}
|
|
||||||
closeBtnProps={{
|
|
||||||
onClick: () => alert('Close triggered!'),
|
|
||||||
}}
|
|
||||||
{...args}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
BadgeWithCloseButton.args = {
|
|
||||||
bsStyle: null,
|
|
||||||
}
|
|
||||||
BadgeWithCloseButton.argTypes = {
|
|
||||||
bsStyle: {
|
|
||||||
table: {
|
|
||||||
disable: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export const BadgeDefault: Story = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
BadgeDefault.args = {
|
BadgeDefault.args = {
|
||||||
bg: 'light',
|
bg: meta.argTypes!.bg!.options[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BadgePrepend: Story = {
|
export const BadgePrepend: Story = {
|
||||||
|
@ -57,37 +57,12 @@ export const BadgePrepend: Story = {
|
||||||
return (
|
return (
|
||||||
<Badge
|
<Badge
|
||||||
className={classnames({ 'text-dark': args.bg === 'light' })}
|
className={classnames({ 'text-dark': args.bg === 'light' })}
|
||||||
prepend={<Icon type="tag" fw />}
|
prepend={<Icon type="star" fw />}
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
BadgePrepend.args = {
|
BadgePrepend.args = {
|
||||||
bg: 'light',
|
bg: meta.argTypes!.bg!.options[0],
|
||||||
}
|
|
||||||
|
|
||||||
export const BadgeWithCloseButton: Story = {
|
|
||||||
render: args => {
|
|
||||||
return (
|
|
||||||
<Badge
|
|
||||||
className={classnames({ 'text-dark': args.bg === 'light' })}
|
|
||||||
prepend={<Icon type="tag" fw />}
|
|
||||||
closeBtnProps={{
|
|
||||||
onClick: () => alert('Close triggered!'),
|
|
||||||
}}
|
|
||||||
{...args}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
BadgeWithCloseButton.args = {
|
|
||||||
bg: 'light',
|
|
||||||
}
|
|
||||||
BadgeWithCloseButton.argTypes = {
|
|
||||||
bg: {
|
|
||||||
table: {
|
|
||||||
disable: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
70
services/web/frontend/stories/ui/tag-bs3.stories.tsx
Normal file
70
services/web/frontend/stories/ui/tag-bs3.stories.tsx
Normal file
|
@ -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<typeof BS3Tag> = {
|
||||||
|
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<typeof BS3Tag>
|
||||||
|
|
||||||
|
export const TagDefault: Story = {
|
||||||
|
render: args => {
|
||||||
|
return (
|
||||||
|
<div className="small">
|
||||||
|
<BS3Tag {...args} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TagPrepend: Story = {
|
||||||
|
render: args => {
|
||||||
|
return (
|
||||||
|
<div className="small">
|
||||||
|
<BS3Tag prepend={<Icon type="tag" fw />} {...args} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TagWithCloseButton: Story = {
|
||||||
|
render: args => {
|
||||||
|
return (
|
||||||
|
<div className="small">
|
||||||
|
<BS3Tag
|
||||||
|
prepend={<Icon type="tag" fw />}
|
||||||
|
closeBtnProps={{
|
||||||
|
onClick: () => alert('Close triggered!'),
|
||||||
|
}}
|
||||||
|
{...args}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
60
services/web/frontend/stories/ui/tag-bs5.stories.tsx
Normal file
60
services/web/frontend/stories/ui/tag-bs5.stories.tsx
Normal file
|
@ -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<typeof Tag> = {
|
||||||
|
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<typeof Tag>
|
||||||
|
|
||||||
|
export const TagDefault: Story = {
|
||||||
|
render: args => {
|
||||||
|
return <Tag {...args} />
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TagPrepend: Story = {
|
||||||
|
render: args => {
|
||||||
|
return <Tag prepend={<Icon type="tag" fw />} {...args} />
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TagWithCloseButton: Story = {
|
||||||
|
render: args => {
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
prepend={<Icon type="tag" fw />}
|
||||||
|
closeBtnProps={{
|
||||||
|
onClick: () => alert('Close triggered!'),
|
||||||
|
}}
|
||||||
|
{...args}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,13 +1,16 @@
|
||||||
.badge {
|
.badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
overflow: hidden;
|
max-width: 100%;
|
||||||
line-height: var(--line-height-01);
|
line-height: var(--line-height-01);
|
||||||
|
padding: 0 var(--bs-badge-padding-x);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-prepend {
|
.badge-prepend {
|
||||||
margin-left: calc($spacing-01 / -2);
|
margin-left: calc($spacing-01 / -2);
|
||||||
margin-right: $spacing-01;
|
margin-right: $spacing-01;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-close {
|
.badge-close {
|
||||||
|
@ -16,15 +19,14 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
// a random number that would cause the close button to expand enough
|
padding: 0 $spacing-02;
|
||||||
// so that it won't be affected by badge's padding
|
margin: 0 (-$spacing-02) 0 $spacing-02;
|
||||||
$expand: 100px;
|
border-top-right-radius: inherit;
|
||||||
|
border-bottom-right-radius: inherit;
|
||||||
padding: $expand $spacing-01;
|
|
||||||
margin: (-$expand) (-$spacing-02) (-$expand) $spacing-02;
|
|
||||||
user-select: none;
|
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
.badge-close-icon {
|
.badge-close-icon {
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
|
@ -34,3 +36,17 @@
|
||||||
background-color: var(--neutral-40);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
.badge-bs3 {
|
.badge-tag-bs3 {
|
||||||
@size: 24px;
|
@size: 24px;
|
||||||
@padding: 4px;
|
@padding: 4px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
|
||||||
height: @size;
|
height: @size;
|
||||||
|
max-width: 100%;
|
||||||
min-height: @size;
|
min-height: @size;
|
||||||
padding: 0 @padding;
|
padding: 0 @padding;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -26,10 +26,14 @@
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
height: @size;
|
height: @size;
|
||||||
|
line-height: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
margin-right: -@padding;
|
margin-right: -@padding;
|
||||||
|
border-top-right-radius: inherit;
|
||||||
|
border-bottom-right-radius: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -37,13 +41,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-sm {
|
&-content {
|
||||||
@size-sm: 20px;
|
.text-overflow();
|
||||||
height: @size-sm;
|
|
||||||
font-size: @font-size-extra-small;
|
|
||||||
.badge-bs3-close {
|
|
||||||
width: @size-sm;
|
|
||||||
font-size: @size-sm;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue