Merge pull request #21477 from overleaf/ii-bs5-table-generator

[web] BS5 table generator

GitOrigin-RevId: 3fe10c05fa36f026c47ff4f54b15f5d76f7c509e
This commit is contained in:
ilkin-overleaf 2024-11-01 14:10:50 +02:00 committed by Copybot
parent ba7d11d854
commit 1033e73844
12 changed files with 238 additions and 224 deletions

View file

@ -1,9 +1,8 @@
import MaterialIcon from '@/shared/components/material-icon' import MaterialIcon from '@/shared/components/material-icon'
import { WidthSelection } from './toolbar/column-width-modal/column-width' import { WidthSelection } from './toolbar/column-width-modal/column-width'
import { useMemo } from 'react' import { useMemo } from 'react'
import { Button } from 'react-bootstrap'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Tooltip from '@/shared/components/tooltip' import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import { useSelectionContext } from './contexts/selection-context' import { useSelectionContext } from './contexts/selection-context'
function roundIfNeeded(width: number) { function roundIfNeeded(width: number) {
@ -32,7 +31,7 @@ export const ColumnSizeIndicator = ({
} }
return ( return (
<Tooltip <OLTooltip
id="tooltip-column-width-button" id="tooltip-column-width-button"
description={ description={
unit === 'custom' unit === 'custom'
@ -43,9 +42,8 @@ export const ColumnSizeIndicator = ({
} }
overlayProps={{ delay: 0, placement: 'bottom' }} overlayProps={{ delay: 0, placement: 'bottom' }}
> >
<Button <button
bsStyle={null} className="btn table-generator-column-indicator-button"
className="table-generator-column-indicator-button"
onClick={onClick} onClick={onClick}
> >
<MaterialIcon <MaterialIcon
@ -55,7 +53,7 @@ export const ColumnSizeIndicator = ({
<span className="table-generator-column-indicator-label"> <span className="table-generator-column-indicator-label">
{formattedWidth} {formattedWidth}
</span> </span>
</Button> </button>
</Tooltip> </OLTooltip>
) )
} }

View file

@ -1,5 +1,10 @@
import { Button, Modal } from 'react-bootstrap' import OLModal, {
import AccessibleModal from '../../../../shared/components/accessible-modal' OLModalBody,
OLModalFooter,
OLModalHeader,
OLModalTitle,
} from '@/features/ui/components/ol/ol-modal'
import OLButton from '@/features/ui/components/ol/ol-button'
import { useTabularContext } from './contexts/tabular-context' import { useTabularContext } from './contexts/tabular-context'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
@ -9,15 +14,15 @@ export const TableGeneratorHelpModal = () => {
if (!helpShown) return null if (!helpShown) return null
return ( return (
<AccessibleModal <OLModal
show={helpShown} show={helpShown}
onHide={hideHelp} onHide={hideHelp}
className="table-generator-help-modal" className="table-generator-help-modal"
> >
<Modal.Header closeButton> <OLModalHeader closeButton>
<Modal.Title>{t('help')}</Modal.Title> <OLModalTitle>{t('help')}</OLModalTitle>
</Modal.Header> </OLModalHeader>
<Modal.Body> <OLModalBody>
<p> <p>
<Trans <Trans
i18nKey="this_tool_helps_you_insert_simple_tables_into_your_project_without_writing_latex_code_give_feedback" i18nKey="this_tool_helps_you_insert_simple_tables_into_your_project_without_writing_latex_code_give_feedback"
@ -83,10 +88,12 @@ export const TableGeneratorHelpModal = () => {
]} ]}
/> />
</p> </p>
</Modal.Body> </OLModalBody>
<Modal.Footer> <OLModalFooter>
<Button onClick={hideHelp}>{t('close')}</Button> <OLButton variant="secondary" onClick={hideHelp}>
</Modal.Footer> {t('close')}
</AccessibleModal> </OLButton>
</OLModalFooter>
</OLModal>
) )
} }

View file

@ -14,7 +14,6 @@ import {
} from './contexts/editing-context' } from './contexts/editing-context'
import { EditorView } from '@codemirror/view' import { EditorView } from '@codemirror/view'
import { ErrorBoundary } from 'react-error-boundary' import { ErrorBoundary } from 'react-error-boundary'
import { Alert, Button } from 'react-bootstrap'
import { EditorSelection } from '@codemirror/state' import { EditorSelection } from '@codemirror/state'
import { import {
CodeMirrorViewContext, CodeMirrorViewContext,
@ -22,13 +21,14 @@ import {
} from '../codemirror-context' } from '../codemirror-context'
import { TableProvider } from './contexts/table-context' import { TableProvider } from './contexts/table-context'
import { TabularProvider, useTabularContext } from './contexts/tabular-context' import { TabularProvider, useTabularContext } from './contexts/tabular-context'
import Icon from '../../../../shared/components/icon'
import { BorderTheme } from './toolbar/commands' import { BorderTheme } from './toolbar/commands'
import { TableGeneratorHelpModal } from './help-modal' import { TableGeneratorHelpModal } from './help-modal'
import { SplitTestProvider } from '../../../../shared/context/split-test-context' import { SplitTestProvider } from '../../../../shared/context/split-test-context'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { ColumnWidthModal } from './toolbar/column-width-modal/modal' import { ColumnWidthModal } from './toolbar/column-width-modal/modal'
import { WidthSelection } from './toolbar/column-width-modal/column-width' import { WidthSelection } from './toolbar/column-width-modal/column-width'
import Notification from '@/shared/components/notification'
import OLButton from '@/features/ui/components/ol/ol-button'
export type ColumnDefinition = { export type ColumnDefinition = {
alignment: 'left' | 'center' | 'right' | 'paragraph' alignment: 'left' | 'center' | 'right' | 'paragraph'
@ -198,35 +198,40 @@ export const TableRenderingError: FC<{
codePosition?: number codePosition?: number
}> = ({ view, codePosition }) => { }> = ({ view, codePosition }) => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<Alert className="table-generator-error"> <Notification
<span className="table-generator-error-icon"> type="info"
<Icon type="exclamation-circle" /> content={
</span> <>
<div className="table-generator-error-message"> <p>
<p className="table-generator-error-message-header"> <strong>
{t('sorry_your_table_cant_be_displayed_at_the_moment')} {t('sorry_your_table_cant_be_displayed_at_the_moment')}
</p> </strong>
<p> </p>
{t( <p>
'this_could_be_because_we_cant_support_some_elements_of_the_table' {t(
)} 'this_could_be_because_we_cant_support_some_elements_of_the_table'
</p> )}
</div> </p>
{codePosition !== undefined && ( </>
<Button }
bsStyle={null} action={
className="btn-secondary table-generator-error-show-code-button" codePosition !== undefined ? (
onClick={() => <OLButton
view.dispatch({ variant="secondary"
selection: EditorSelection.cursor(codePosition), onClick={() =>
}) view.dispatch({
} selection: EditorSelection.cursor(codePosition),
> })
{t('view_code')} }
</Button> size="sm"
)} >
</Alert> {t('view_code')}
</OLButton>
) : undefined
}
/>
) )
} }

View file

@ -1,5 +1,3 @@
import AccessibleModal from '@/shared/components/accessible-modal'
import { Button, Modal, Form, FormGroup } from 'react-bootstrap'
import { useTabularContext } from '../../contexts/tabular-context' import { useTabularContext } from '../../contexts/tabular-context'
import { Select } from '@/shared/components/select' import { Select } from '@/shared/components/select'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
@ -18,8 +16,24 @@ import { setColumnWidth } from '../commands'
import { UNITS, WidthSelection, WidthUnit } from './column-width' import { UNITS, WidthSelection, WidthUnit } from './column-width'
import { useCodeMirrorViewContext } from '../../../codemirror-context' import { useCodeMirrorViewContext } from '../../../codemirror-context'
import { CopyToClipboard } from '@/shared/components/copy-to-clipboard' import { CopyToClipboard } from '@/shared/components/copy-to-clipboard'
import Tooltip from '@/shared/components/tooltip'
import Icon from '@/shared/components/icon' import Icon from '@/shared/components/icon'
import OLModal, {
OLModalBody,
OLModalFooter,
OLModalHeader,
OLModalTitle,
} from '@/features/ui/components/ol/ol-modal'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import OLButton from '@/features/ui/components/ol/ol-button'
import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
import OLFormControl from '@/features/ui/components/ol/ol-form-control'
import OLCol from '@/features/ui/components/ol/ol-col'
import OLRow from '@/features/ui/components/ol/ol-row'
import OLForm from '@/features/ui/components/ol/ol-form'
import { bsVersion } from '@/features/utils/bootstrap-5'
import MaterialIcon from '@/shared/components/material-icon'
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
type UnitDescription = { label: string; tooltip?: string } | undefined type UnitDescription = { label: string; tooltip?: string } | undefined
@ -93,7 +107,7 @@ const ColumnWidthModalBody = () => {
} }
}, [columnWidthModalShown, selection, table]) }, [columnWidthModalShown, selection, table])
const onSubmit: FormEventHandler<Form> = useCallback( const onSubmit: FormEventHandler<HTMLFormElement> = useCallback(
e => { e => {
e.preventDefault() e.preventDefault()
if (selection && currentUnit) { if (selection && currentUnit) {
@ -121,60 +135,67 @@ const ColumnWidthModalBody = () => {
) )
return ( return (
<AccessibleModal <OLModal
show={columnWidthModalShown} show={columnWidthModalShown}
onHide={closeColumnWidthModal} onHide={closeColumnWidthModal}
className="table-generator-width-modal" className="table-generator-width-modal"
> >
<Form onSubmit={onSubmit}> <OLModalHeader closeButton>
<Modal.Header closeButton> <OLModalTitle>{t('set_column_width')}</OLModalTitle>
<Modal.Title>{t('set_column_width')}</Modal.Title> </OLModalHeader>
</Modal.Header> <OLModalBody>
<Modal.Body> <OLForm id="table-generator-width-form" onSubmit={onSubmit}>
<div className="clearfix"> <OLRow className={bsVersion({ bs5: 'g-3' })}>
<FormGroup className="col-md-8 p-0 mb-0"> <OLCol lg={8}>
<label <OLFormGroup
className="table-generator-width-label" controlId="column-width-modal-width"
htmlFor="column-width-modal-width" className="mb-0"
> >
{t('column_width')} <OLFormLabel>{t('column_width')}</OLFormLabel>
</label> <OLFormControl
<input value={currentWidth}
id="column-width-modal-width" required
value={currentWidth} onChange={e => setCurrentWidth(e.target.value)}
required type={currentUnit === 'custom' ? 'text' : 'number'}
onChange={e => setCurrentWidth(e.target.value)} ref={inputRef}
type={currentUnit === 'custom' ? 'text' : 'number'} />
className="form-control" </OLFormGroup>
ref={inputRef} </OLCol>
/> <OLCol lg={4}>
</FormGroup> <OLFormGroup className="mb-0">
<FormGroup className="col-md-4 mb-0"> <Select
<Select label={
label={ <>
<> &nbsp;<span className="sr-only">{t('length_unit')}</span>
&nbsp;<span className="sr-only">{t('length_unit')}</span> </>
</> }
} items={UNITS}
items={UNITS} itemToKey={x => x ?? ''}
itemToKey={x => x ?? ''} itemToString={x => (x === 'custom' ? t('custom') : (x ?? ''))}
itemToString={x => (x === 'custom' ? t('custom') : (x ?? ''))} onSelectedItemChanged={item => setCurrentUnit(item)}
onSelectedItemChanged={item => setCurrentUnit(item)} defaultItem={currentUnit}
defaultItem={currentUnit} />
/> </OLFormGroup>
</FormGroup> </OLCol>
</div> </OLRow>
{unitHelp && ( {unitHelp && (
<p className="my-1"> <p className="my-1">
{unitHelp.label}{' '} {unitHelp.label}{' '}
{unitHelp.tooltip && ( {unitHelp.tooltip && (
<Tooltip <OLTooltip
id="table-generator-unit-tooltip" id="table-generator-unit-tooltip"
description={unitHelp.tooltip} description={unitHelp.tooltip}
overlayProps={{ delay: 0, placement: 'top' }} overlayProps={{ delay: 0, placement: 'top' }}
> >
<Icon type="question-circle" fw /> <span>
</Tooltip> <BootstrapVersionSwitcher
bs3={<Icon type="question-circle" />}
bs5={
<MaterialIcon type="help" className="align-middle" />
}
/>
</span>
</OLTooltip>
)} )}
</p> </p>
)} )}
@ -196,22 +217,25 @@ const ColumnWidthModalBody = () => {
tooltipId="table-generator-array-copy" tooltipId="table-generator-array-copy"
/> />
</div> </div>
</Modal.Body> </OLForm>
<Modal.Footer> </OLModalBody>
<Button <OLModalFooter>
bsStyle={null} <OLButton
className="btn-secondary" variant="secondary"
onClick={() => { onClick={() => {
closeColumnWidthModal() closeColumnWidthModal()
}} }}
> >
{t('cancel')} {t('cancel')}
</Button> </OLButton>
<Button bsStyle={null} className="btn-primary" type="submit"> <OLButton
{t('ok')} variant="primary"
</Button> form="table-generator-width-form"
</Modal.Footer> type="submit"
</Form> >
</AccessibleModal> {t('ok')}
</OLButton>
</OLModalFooter>
</OLModal>
) )
} }

View file

@ -1,9 +1,12 @@
import { FC, memo, useRef } from 'react' import { FC, memo, useRef } from 'react'
import useDropdown from '../../../../../shared/hooks/use-dropdown' import useDropdown from '../../../../../shared/hooks/use-dropdown'
import { ListGroup, Overlay, Popover } from 'react-bootstrap' import OLListGroup from '@/features/ui/components/ol/ol-list-group'
import Tooltip from '../../../../../shared/components/tooltip' 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 MaterialIcon from '../../../../../shared/components/material-icon' import MaterialIcon from '../../../../../shared/components/material-icon'
import { useTabularContext } from '../contexts/tabular-context' import { useTabularContext } from '../contexts/tabular-context'
import { bsVersion } from '@/features/utils/bootstrap-5'
export const ToolbarButtonMenu: FC<{ export const ToolbarButtonMenu: FC<{
id: string id: string
@ -45,36 +48,37 @@ export const ToolbarButtonMenu: FC<{
) )
const overlay = tableContainerRef.current && ( const overlay = tableContainerRef.current && (
<Overlay <OLOverlay
show={open} show={open}
target={target.current} target={target.current}
placement="bottom" placement="bottom"
container={tableContainerRef.current} container={tableContainerRef.current}
containerPadding={0} containerPadding={0}
animation transition
rootClose rootClose
onHide={() => onToggle(false)} onHide={() => onToggle(false)}
> >
<Popover <OLPopover
id={`${id}-menu`} id={`${id}-menu`}
ref={ref} ref={ref}
className="table-generator-button-menu-popover" className="table-generator-button-menu-popover"
> >
<ListGroup <OLListGroup
role="menu" role="menu"
onClick={() => { onClick={() => {
onToggle(false) onToggle(false)
}} }}
className={bsVersion({ bs5: 'd-block' })}
> >
{children} {children}
</ListGroup> </OLListGroup>
</Popover> </OLPopover>
</Overlay> </OLOverlay>
) )
return ( return (
<> <>
<Tooltip <OLTooltip
hidden={open} hidden={open}
id={id} id={id}
description={ description={
@ -83,7 +87,7 @@ export const ToolbarButtonMenu: FC<{
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
{button} {button}
</Tooltip> </OLTooltip>
{overlay} {overlay}
</> </>
) )

View file

@ -1,7 +1,7 @@
import { EditorView } from '@codemirror/view' import { EditorView } from '@codemirror/view'
import classNames from 'classnames' import classNames from 'classnames'
import { memo, useCallback } from 'react' import { memo, useCallback } from 'react'
import Tooltip from '../../../../../shared/components/tooltip' import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import MaterialIcon from '../../../../../shared/components/material-icon' import MaterialIcon from '../../../../../shared/components/material-icon'
import { useCodeMirrorViewContext } from '../../codemirror-context' import { useCodeMirrorViewContext } from '../../codemirror-context'
import { emitTableGeneratorEvent } from '../analytics' import { emitTableGeneratorEvent } from '../analytics'
@ -64,12 +64,12 @@ export const ToolbarButton = memo<{
disabled && disabledLabel ? <div>{disabledLabel}</div> : <div>{label}</div> disabled && disabledLabel ? <div>{disabledLabel}</div> : <div>{label}</div>
return ( return (
<Tooltip <OLTooltip
id={id} id={id}
description={description} description={description}
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
{button} {button}
</Tooltip> </OLTooltip>
) )
}) })

View file

@ -1,8 +1,9 @@
import { ButtonHTMLAttributes, FC, useCallback, useRef } from 'react' import { ButtonHTMLAttributes, FC, useCallback, useRef } from 'react'
import useDropdown from '../../../../../shared/hooks/use-dropdown' import useDropdown from '../../../../../shared/hooks/use-dropdown'
import { Overlay, Popover } from 'react-bootstrap' import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import OLOverlay from '@/features/ui/components/ol/ol-overlay'
import OLPopover from '@/features/ui/components/ol/ol-popover'
import MaterialIcon from '../../../../../shared/components/material-icon' import MaterialIcon from '../../../../../shared/components/material-icon'
import Tooltip from '../../../../../shared/components/tooltip'
import { useTabularContext } from '../contexts/tabular-context' import { useTabularContext } from '../contexts/tabular-context'
import { emitTableGeneratorEvent } from '../analytics' import { emitTableGeneratorEvent } from '../analytics'
import { useCodeMirrorViewContext } from '../../codemirror-context' import { useCodeMirrorViewContext } from '../../codemirror-context'
@ -55,17 +56,17 @@ export const ToolbarDropdown: FC<{
</button> </button>
) )
const overlay = tabularRef.current && ( const overlay = tabularRef.current && (
<Overlay <OLOverlay
show={open} show={open}
target={toggleButtonRef.current ?? undefined} target={toggleButtonRef.current}
placement="bottom" placement="bottom"
container={tabularRef.current} container={tabularRef.current}
animation transition
rootClose rootClose
containerPadding={0} containerPadding={0}
onHide={() => onToggle(false)} onHide={() => onToggle(false)}
> >
<Popover <OLPopover
id={`${id}-popover`} id={`${id}-popover`}
ref={ref} ref={ref}
className="table-generator-toolbar-dropdown-popover" className="table-generator-toolbar-dropdown-popover"
@ -82,21 +83,21 @@ export const ToolbarDropdown: FC<{
> >
{children} {children}
</div> </div>
</Popover> </OLPopover>
</Overlay> </OLOverlay>
) )
if (tooltip || (disabled && disabledTooltip)) { if (tooltip || (disabled && disabledTooltip)) {
return ( return (
<> <>
<Tooltip <OLTooltip
hidden={open} hidden={open}
id={id} id={id}
description={disabled && disabledTooltip ? disabledTooltip : tooltip} description={disabled && disabledTooltip ? disabledTooltip : tooltip}
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
{button} {button}
</Tooltip> </OLTooltip>
{overlay} {overlay}
</> </>
) )

View file

@ -1,4 +1,5 @@
import { EditorView } from '@codemirror/view' import { EditorView } from '@codemirror/view'
import { isBootstrap5 } from '@/features/utils/bootstrap-5'
export const tableGeneratorTheme = EditorView.baseTheme({ export const tableGeneratorTheme = EditorView.baseTheme({
'&dark .table-generator': { '&dark .table-generator': {
@ -309,14 +310,14 @@ export const tableGeneratorTheme = EditorView.baseTheme({
'.table-generator-button-menu-popover': { '.table-generator-button-menu-popover': {
'background-color': 'var(--table-generator-toolbar-background) !important', 'background-color': 'var(--table-generator-toolbar-background) !important',
'& .popover-content': { '& .popover-content, & .popover-body': {
padding: '4px', padding: '4px',
}, },
'& .list-group': { '& .list-group': {
margin: '0', margin: '0',
padding: '0', padding: '0',
}, },
'& > .arrow': { '& > .arrow, & > .popover-arrow': {
display: 'none', display: 'none',
}, },
}, },
@ -348,7 +349,7 @@ export const tableGeneratorTheme = EditorView.baseTheme({
gap: '6px', gap: '6px',
'align-items': 'flex-start', 'align-items': 'flex-start',
'max-width': '240px', 'max-width': '240px',
'font-family': 'Lato', 'font-family': isBootstrap5() ? 'var(--bs-body-font-family)' : 'Lato',
'& .info-icon': { '& .info-icon': {
flex: ' 0 0 24px', flex: ' 0 0 24px',
@ -369,7 +370,7 @@ export const tableGeneratorTheme = EditorView.baseTheme({
display: 'flex', display: 'flex',
'align-items': 'center', 'align-items': 'center',
'justify-content': 'space-between', 'justify-content': 'space-between',
'font-family': 'Lato', 'font-family': isBootstrap5() ? 'var(--bs-body-font-family)' : 'Lato',
height: '36px', height: '36px',
'&:not(:first-child)': { '&:not(:first-child)': {
@ -387,11 +388,11 @@ export const tableGeneratorTheme = EditorView.baseTheme({
'max-width': '300px', 'max-width': '300px',
background: 'var(--table-generator-toolbar-background) !important', background: 'var(--table-generator-toolbar-background) !important',
'& .popover-content': { '& .popover-content, & .popover-body': {
padding: '0', padding: '0',
}, },
'& > .arrow': { '& > .arrow, & > .popover-arrow': {
display: 'none', display: 'none',
}, },
}, },
@ -416,7 +417,7 @@ export const tableGeneratorTheme = EditorView.baseTheme({
'column-gap': '8px', 'column-gap': '8px',
'align-self': 'stretch', 'align-self': 'stretch',
padding: '12px 8px', padding: '12px 8px',
'font-family': 'Lato', 'font-family': isBootstrap5() ? 'var(--bs-body-font-family)' : 'Lato',
'& .table-generator-button-label': { '& .table-generator-button-label': {
'align-self': 'stretch', 'align-self': 'stretch',
@ -482,32 +483,9 @@ export const tableGeneratorTheme = EditorView.baseTheme({
'.ol-cm-environment-table.table-generator-error-container, .ol-cm-environment-table.ol-cm-tabular': '.ol-cm-environment-table.table-generator-error-container, .ol-cm-environment-table.ol-cm-tabular':
{ {
background: 'rgba(125, 125, 125, 0.05)', background: 'rgba(125, 125, 125, 0.05)',
'font-family': isBootstrap5() ? 'var(--bs-body-font-family)' : 'Lato',
}, },
'.table-generator-error': {
background: 'var(--table-generator-error-background)',
display: 'flex',
'justify-content': 'space-between',
color: 'var(--table-generator-error-color)',
border: '1px solid var(--table-generator-error-border-color)',
'font-family': 'Lato',
margin: '0 16px 0 16px',
'& .table-generator-error-message': {
flex: '1 1 auto',
},
'& .table-generator-error-message-header': {
fontWeight: 'bold',
marginBottom: '2px',
},
'& .table-generator-error-show-code-button': {
alignSelf: 'baseline',
},
'& .table-generator-error-icon': {
color: '#3265B2',
'margin-right': '12px',
},
},
'.table-generator-filler-row': { '.table-generator-filler-row': {
border: 'none !important', border: 'none !important',
'& td': { '& td': {

View file

@ -10,28 +10,34 @@ export class TableRenderingErrorWidget extends WidgetType {
toDOM(view: EditorView): HTMLElement { toDOM(view: EditorView): HTMLElement {
const warning = document.createElement('div') const warning = document.createElement('div')
warning.classList.add('table-generator-error', 'alert') warning.classList.add('notification', 'notification-type-info')
warning.role = 'alert' warning.role = 'alert'
const icon = document.createElement('span') const icon = document.createElement('div')
icon.classList.add('table-generator-error-icon') icon.classList.add('notification-icon')
const iconType = document.createElement('i') const iconType = document.createElement('span')
iconType.classList.add('fa', 'fa-info-circle') iconType.classList.add('material-symbols')
iconType.setAttribute('aria-hidden', 'true')
iconType.textContent = 'info'
icon.appendChild(iconType) icon.appendChild(iconType)
warning.appendChild(icon) warning.appendChild(icon)
const messageWrapper = document.createElement('div')
messageWrapper.classList.add('notification-content-and-cta')
const message = document.createElement('div') const message = document.createElement('div')
message.classList.add('table-generator-error-message') message.classList.add('notification-content')
const messageHeader = document.createElement('p') const messageHeader = document.createElement('p')
messageHeader.classList.add('table-generator-error-message-header') const messageHeaderInner = document.createElement('strong')
messageHeader.textContent = view.state.phrase( messageHeaderInner.textContent = view.state.phrase(
'sorry_your_table_cant_be_displayed_at_the_moment' 'sorry_your_table_cant_be_displayed_at_the_moment'
) )
messageHeader.appendChild(messageHeaderInner)
const messageBody = document.createElement('p') const messageBody = document.createElement('p')
messageBody.textContent = view.state.phrase( messageBody.textContent = view.state.phrase(
'this_could_be_because_we_cant_support_some_elements_of_the_table' 'this_could_be_because_we_cant_support_some_elements_of_the_table'
) )
message.appendChild(messageHeader) message.appendChild(messageHeader)
message.appendChild(messageBody) message.appendChild(messageBody)
warning.appendChild(message) messageWrapper.appendChild(message)
warning.appendChild(messageWrapper)
const element = document.createElement('div') const element = document.createElement('div')
element.classList.add('table-generator', 'table-generator-error-container') element.classList.add('table-generator', 'table-generator-error-container')
element.appendChild(warning) element.appendChild(warning)

View file

@ -1,4 +1,4 @@
import { FC, memo, MouseEventHandler, useCallback, useState } from 'react' import { memo, useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import OLButton from '@/features/ui/components/ol/ol-button' import OLButton from '@/features/ui/components/ol/ol-button'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip' import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
@ -33,54 +33,31 @@ export const CopyToClipboard = memo<{
description={copied ? `${t('copied')}!` : t('copy')} description={copied ? `${t('copied')}!` : t('copy')}
overlayProps={{ delay: copied ? 1000 : 250 }} overlayProps={{ delay: copied ? 1000 : 250 }}
> >
<span> {kind === 'text' ? (
{kind === 'text' ? ( <OLButton
<TextButton handleClick={handleClick} /> onClick={handleClick}
) : ( size="sm"
<IconButton handleClick={handleClick} copied={copied} /> variant="secondary"
)} className="copy-button"
</span> bs3Props={{ bsSize: 'xsmall' }}
>
{t('copy')}
</OLButton>
) : (
<OLIconButton
onClick={handleClick}
variant="link"
size="sm"
accessibilityLabel={t('copy')}
className="copy-button"
bs3Props={{ bsSize: 'xsmall' }}
icon={bsVersion({
bs5: copied ? 'check' : 'content_copy',
bs3: copied ? 'check' : 'clipboard',
})}
/>
)}
</OLTooltip> </OLTooltip>
) )
}) })
CopyToClipboard.displayName = 'CopyToClipboard' CopyToClipboard.displayName = 'CopyToClipboard'
const TextButton: FC<{
handleClick: MouseEventHandler<HTMLButtonElement>
}> = ({ handleClick }) => {
const { t } = useTranslation()
return (
<OLButton
onClick={handleClick}
size="sm"
variant="secondary"
className="copy-button"
bs3Props={{ bsSize: 'xsmall' }}
>
{t('copy')}
</OLButton>
)
}
const IconButton: FC<{
handleClick: MouseEventHandler<HTMLButtonElement>
copied: boolean
}> = ({ handleClick, copied }) => {
const { t } = useTranslation()
return (
<OLIconButton
onClick={handleClick}
variant="link"
size="sm"
accessibilityLabel={t('copy')}
className="copy-button"
bs3Props={{ bsSize: 'xsmall' }}
icon={bsVersion({
bs5: copied ? 'check' : 'content_copy',
bs3: copied ? 'check' : 'clipboard',
})}
/>
)
}

View file

@ -24,6 +24,7 @@
@import 'editor/share'; @import 'editor/share';
@import 'editor/tags-input'; @import 'editor/tags-input';
@import 'editor/review-panel-new'; @import 'editor/review-panel-new';
@import 'editor/table-generator-column-width-modal';
@import 'website-redesign'; @import 'website-redesign';
@import 'group-settings'; @import 'group-settings';
@import 'templates-v2'; @import 'templates-v2';

View file

@ -0,0 +1,13 @@
.table-generator-width-modal {
.table-generator-width-label {
width: 100%;
}
.table-generator-usepackage-copy {
display: flex;
justify-content: space-between;
padding: var(--spacing-03) var(--spacing-05);
background: var(--bg-light-secondary);
border: 1px solid var(--border-primary-dark);
}
}