mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-14 20:40:17 -05:00
Merge pull request #20880 from overleaf/ii-bs5-submit-modal
[web] BS5 submit modal GitOrigin-RevId: 1c66b3874844d9bdbe129acd18480af6e6e0ef6e
This commit is contained in:
parent
f590d6d9a2
commit
d71f82b1fa
8 changed files with 149 additions and 82 deletions
|
@ -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<CardProps> = ({ children, ...rest }) => {
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<div className="card">{children}</div>}
|
||||
bs3={
|
||||
<div className="card" {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
bs5={
|
||||
<Card>
|
||||
<Card {...rest}>
|
||||
<CardBody>{children}</CardBody>
|
||||
</Card>
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ function OLFormLabel(props: OLFormLabelProps) {
|
|||
children: rest.children,
|
||||
htmlFor: rest.htmlFor,
|
||||
srOnly: rest.visuallyHidden,
|
||||
className: rest.className,
|
||||
...bs3Props,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<string, unknown>
|
||||
}
|
||||
|
||||
function OLFormSelect(props: OLFormSelectProps) {
|
||||
const { bs3Props, ...bs5Props } = props
|
||||
const OLFormSelect = forwardRef<HTMLSelectElement, OLFormSelectProps>(
|
||||
(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 (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={
|
||||
<BS3FormControl
|
||||
componentClass="select"
|
||||
{...bs3FormSelectProps}
|
||||
{...extraProps}
|
||||
/>
|
||||
}
|
||||
bs5={<Form.Select ref={ref} {...bs5Props} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
// Get all `aria-*` and `data-*` attributes
|
||||
const extraProps = getAriaAndDataProps(bs5Props)
|
||||
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={
|
||||
<BS3FormControl
|
||||
componentClass="select"
|
||||
{...bs3FormSelectProps}
|
||||
{...extraProps}
|
||||
/>
|
||||
}
|
||||
bs5={<Form.Select {...bs5Props} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
OLFormSelect.displayName = 'OLFormSelect'
|
||||
|
||||
export default OLFormSelect
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
3
services/web/frontend/js/utils/window.ts
Normal file
3
services/web/frontend/js/utils/window.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
// Allows easy mocking of `window` methods in tests
|
||||
|
||||
export const setTimeout = window.setTimeout
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue