diff --git a/services/web/frontend/js/features/ui/components/ol/ol-card.tsx b/services/web/frontend/js/features/ui/components/ol/ol-card.tsx index 7af8dd54e8..3e5d7e5547 100644 --- a/services/web/frontend/js/features/ui/components/ol/ol-card.tsx +++ b/services/web/frontend/js/features/ui/components/ol/ol-card.tsx @@ -1,16 +1,20 @@ -import { Card, CardBody } from 'react-bootstrap-5' +import { Card, CardBody, CardProps } from 'react-bootstrap-5' import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' import { FC } from 'react' // This wraps the Bootstrap 5 Card component but is restricted to the very // basic way we're using it, which is as a container for page content. The // Bootstrap 3 equivalent in our codebase is a div with class "card" -const OLCard: FC = ({ children }) => { +const OLCard: FC = ({ children, ...rest }) => { return ( {children}} + bs3={ +
+ {children} +
+ } bs5={ - + {children} } diff --git a/services/web/frontend/js/features/ui/components/ol/ol-form-label.tsx b/services/web/frontend/js/features/ui/components/ol/ol-form-label.tsx index 4565936450..5ce2f7e556 100644 --- a/services/web/frontend/js/features/ui/components/ol/ol-form-label.tsx +++ b/services/web/frontend/js/features/ui/components/ol/ol-form-label.tsx @@ -13,6 +13,7 @@ function OLFormLabel(props: OLFormLabelProps) { children: rest.children, htmlFor: rest.htmlFor, srOnly: rest.visuallyHidden, + className: rest.className, ...bs3Props, } diff --git a/services/web/frontend/js/features/ui/components/ol/ol-form-select.tsx b/services/web/frontend/js/features/ui/components/ol/ol-form-select.tsx index f21098ef47..f9f757abcb 100644 --- a/services/web/frontend/js/features/ui/components/ol/ol-form-select.tsx +++ b/services/web/frontend/js/features/ui/components/ol/ol-form-select.tsx @@ -1,3 +1,4 @@ +import { forwardRef } from 'react' import { Form, FormSelectProps } from 'react-bootstrap-5' import { FormControl as BS3FormControl, @@ -10,38 +11,48 @@ type OLFormSelectProps = FormSelectProps & { bs3Props?: Record } -function OLFormSelect(props: OLFormSelectProps) { - const { bs3Props, ...bs5Props } = props +const OLFormSelect = forwardRef( + (props, ref) => { + const { bs3Props, ...bs5Props } = props - const bs3FormSelectProps: BS3FormControlProps = { - children: bs5Props.children, - bsSize: bs5Props.size, - name: bs5Props.name, - value: bs5Props.value, - defaultValue: bs5Props.defaultValue, - disabled: bs5Props.disabled, - onChange: bs5Props.onChange as BS3FormControlProps['onChange'], - required: bs5Props.required, - placeholder: bs5Props.placeholder, - className: bs5Props.className, - ...bs3Props, + const bs3FormSelectProps: BS3FormControlProps = { + children: bs5Props.children, + bsSize: bs5Props.size, + name: bs5Props.name, + value: bs5Props.value, + defaultValue: bs5Props.defaultValue, + disabled: bs5Props.disabled, + onChange: bs5Props.onChange as BS3FormControlProps['onChange'], + required: bs5Props.required, + placeholder: bs5Props.placeholder, + className: bs5Props.className, + inputRef: (inputElement: HTMLInputElement) => { + if (typeof ref === 'function') { + ref(inputElement as unknown as HTMLSelectElement) + } else if (ref) { + ref.current = inputElement as unknown as HTMLSelectElement + } + }, + ...bs3Props, + } + + // Get all `aria-*` and `data-*` attributes + const extraProps = getAriaAndDataProps(bs5Props) + + return ( + + } + bs5={} + /> + ) } - - // Get all `aria-*` and `data-*` attributes - const extraProps = getAriaAndDataProps(bs5Props) - - return ( - - } - bs5={} - /> - ) -} +) +OLFormSelect.displayName = 'OLFormSelect' export default OLFormSelect diff --git a/services/web/frontend/js/shared/components/loading-spinner.tsx b/services/web/frontend/js/shared/components/loading-spinner.tsx index f5bdeb34dd..7eb0a02b32 100644 --- a/services/web/frontend/js/shared/components/loading-spinner.tsx +++ b/services/web/frontend/js/shared/components/loading-spinner.tsx @@ -3,6 +3,7 @@ import Icon from './icon' import { useEffect, useState } from 'react' import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' import { Spinner } from 'react-bootstrap-5' +import { setTimeout } from '@/utils/window' import classNames from 'classnames' function LoadingSpinner({ @@ -21,7 +22,7 @@ function LoadingSpinner({ const [show, setShow] = useState(false) useEffect(() => { - const timer = window.setTimeout(() => { + const timer = setTimeout(() => { setShow(true) }, delay) diff --git a/services/web/frontend/js/utils/window.ts b/services/web/frontend/js/utils/window.ts new file mode 100644 index 0000000000..c76f4dd0e0 --- /dev/null +++ b/services/web/frontend/js/utils/window.ts @@ -0,0 +1,3 @@ +// Allows easy mocking of `window` methods in tests + +export const setTimeout = window.setTimeout diff --git a/services/web/frontend/stylesheets/app/editor/publish-modal.less b/services/web/frontend/stylesheets/app/editor/publish-modal.less index 6eebd6e76f..40c3248720 100644 --- a/services/web/frontend/stylesheets/app/editor/publish-modal.less +++ b/services/web/frontend/stylesheets/app/editor/publish-modal.less @@ -1,46 +1,10 @@ .modal-body-publish { - @label-column-width: 10em; - @control-left-margin: 1em; - .form-control-box { - margin-bottom: 1.5ex; - margin-left: @control-left-margin; - label { - display: inline-block; - width: @label-column-width; - vertical-align: baseline; - } - label.checkbox-label { - width: auto; - } - .form-control { - display: inline-block; - width: 60%; - } - input[type='checkbox'] { - margin-right: 0.5em; - } - textarea { - vertical-align: baseline; - } - select { - padding-top: 1ex; - padding-bottom: 1ex; - padding-left: 1em; - padding-right: 1em; - } - option { - margin-left: -4px; - } - a.help { - margin-left: 0.6em; - } + input[type='checkbox'] { + margin-top: 6px; } - .no-label { - margin-left: @label-column-width + @control-left-margin; - } - #search-input-container { - overflow: hidden; - margin: 5px 0 10px; + .gallery-export-license { + display: flex; + align-items: center; } .table-content-name { width: 100%; @@ -70,6 +34,7 @@ .button-as-link { color: green; text-transform: none; + text-decoration: none; background: none; padding: 0; border: none; @@ -101,12 +66,10 @@ border-radius: 9px; } .content-as-table { - .table-content, - .table-content > * { - display: table; + .table-content-main { + display: flex; } .table-content-icon { - float: left; height: 100px; width: 106px; display: flex; @@ -118,7 +81,6 @@ } } .table-content-text { - float: right; width: calc(~'100% - 106px'); vertical-align: top; padding-left: 15px; diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss index 038c314f54..d25ea086a7 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss @@ -18,6 +18,7 @@ @import 'subscription'; @import 'editor/pdf'; @import 'editor/compile-button'; +@import 'editor/publish-modal'; @import 'editor/share'; @import 'editor/tags-input'; @import 'website-redesign'; diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/publish-modal.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/publish-modal.scss new file mode 100644 index 0000000000..68db7cdf38 --- /dev/null +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/publish-modal.scss @@ -0,0 +1,84 @@ +.modal-body-publish { + .gallery-export-license { + display: flex; + align-items: center; + } + + .table-content-name { + width: 100%; + margin-bottom: var(--spacing-05); + font-weight: 300; + } + + .table-content-category { + float: right; + font-weight: 300; + text-align: right; + font-style: italic; + width: 30%; + text-transform: capitalize; + } + + .table-content-category ~ .table-content-name { + width: 70%; + display: inline-block; + } + + .affix-content-title { + color: var(--neutral-40); + font-size: var(--spacing-07); + padding-left: var(--spacing-05); + } + + .affix-subcontent { + margin: var(--spacing-03) 0 var(--spacing-11); + } + + .card { + margin-top: calc(var(--line-height-03) / 2); + border: 1px solid var(--neutral-30); + border-radius: var(--border-radius-medium); + + .card-body { + padding: calc(var(--line-height-03) / 2); + } + } + + .content-as-table { + .table-content-main { + display: flex; + } + + .table-content-icon { + height: 100px; + width: 106px; + display: flex; + align-items: flex-start; + overflow: hidden; + + * { + border: 1px solid var(--neutral-10); + width: 100%; + } + } + + .table-content-text { + width: calc(100% - 106px); + vertical-align: top; + padding-left: 15px; + } + + .table-content-slogan { + height: 100px; + overflow: hidden; + } + + .table-content-link { + padding-top: var(--spacing-05); + + .btn { + white-space: normal; + } + } + } +}