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 BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
|
|
||||||
// This wraps the Bootstrap 5 Card component but is restricted to the very
|
// 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
|
// 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"
|
// Bootstrap 3 equivalent in our codebase is a div with class "card"
|
||||||
const OLCard: FC = ({ children }) => {
|
const OLCard: FC<CardProps> = ({ children, ...rest }) => {
|
||||||
return (
|
return (
|
||||||
<BootstrapVersionSwitcher
|
<BootstrapVersionSwitcher
|
||||||
bs3={<div className="card">{children}</div>}
|
bs3={
|
||||||
|
<div className="card" {...rest}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
bs5={
|
bs5={
|
||||||
<Card>
|
<Card {...rest}>
|
||||||
<CardBody>{children}</CardBody>
|
<CardBody>{children}</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ function OLFormLabel(props: OLFormLabelProps) {
|
||||||
children: rest.children,
|
children: rest.children,
|
||||||
htmlFor: rest.htmlFor,
|
htmlFor: rest.htmlFor,
|
||||||
srOnly: rest.visuallyHidden,
|
srOnly: rest.visuallyHidden,
|
||||||
|
className: rest.className,
|
||||||
...bs3Props,
|
...bs3Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { forwardRef } from 'react'
|
||||||
import { Form, FormSelectProps } from 'react-bootstrap-5'
|
import { Form, FormSelectProps } from 'react-bootstrap-5'
|
||||||
import {
|
import {
|
||||||
FormControl as BS3FormControl,
|
FormControl as BS3FormControl,
|
||||||
|
@ -10,38 +11,48 @@ type OLFormSelectProps = FormSelectProps & {
|
||||||
bs3Props?: Record<string, unknown>
|
bs3Props?: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
function OLFormSelect(props: OLFormSelectProps) {
|
const OLFormSelect = forwardRef<HTMLSelectElement, OLFormSelectProps>(
|
||||||
const { bs3Props, ...bs5Props } = props
|
(props, ref) => {
|
||||||
|
const { bs3Props, ...bs5Props } = props
|
||||||
|
|
||||||
const bs3FormSelectProps: BS3FormControlProps = {
|
const bs3FormSelectProps: BS3FormControlProps = {
|
||||||
children: bs5Props.children,
|
children: bs5Props.children,
|
||||||
bsSize: bs5Props.size,
|
bsSize: bs5Props.size,
|
||||||
name: bs5Props.name,
|
name: bs5Props.name,
|
||||||
value: bs5Props.value,
|
value: bs5Props.value,
|
||||||
defaultValue: bs5Props.defaultValue,
|
defaultValue: bs5Props.defaultValue,
|
||||||
disabled: bs5Props.disabled,
|
disabled: bs5Props.disabled,
|
||||||
onChange: bs5Props.onChange as BS3FormControlProps['onChange'],
|
onChange: bs5Props.onChange as BS3FormControlProps['onChange'],
|
||||||
required: bs5Props.required,
|
required: bs5Props.required,
|
||||||
placeholder: bs5Props.placeholder,
|
placeholder: bs5Props.placeholder,
|
||||||
className: bs5Props.className,
|
className: bs5Props.className,
|
||||||
...bs3Props,
|
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
|
OLFormSelect.displayName = 'OLFormSelect'
|
||||||
const extraProps = getAriaAndDataProps(bs5Props)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BootstrapVersionSwitcher
|
|
||||||
bs3={
|
|
||||||
<BS3FormControl
|
|
||||||
componentClass="select"
|
|
||||||
{...bs3FormSelectProps}
|
|
||||||
{...extraProps}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
bs5={<Form.Select {...bs5Props} />}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default OLFormSelect
|
export default OLFormSelect
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Icon from './icon'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
import { Spinner } from 'react-bootstrap-5'
|
import { Spinner } from 'react-bootstrap-5'
|
||||||
|
import { setTimeout } from '@/utils/window'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
function LoadingSpinner({
|
function LoadingSpinner({
|
||||||
|
@ -21,7 +22,7 @@ function LoadingSpinner({
|
||||||
const [show, setShow] = useState(false)
|
const [show, setShow] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = window.setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
setShow(true)
|
setShow(true)
|
||||||
}, delay)
|
}, 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 {
|
.modal-body-publish {
|
||||||
@label-column-width: 10em;
|
input[type='checkbox'] {
|
||||||
@control-left-margin: 1em;
|
margin-top: 6px;
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.no-label {
|
.gallery-export-license {
|
||||||
margin-left: @label-column-width + @control-left-margin;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
#search-input-container {
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 5px 0 10px;
|
|
||||||
}
|
}
|
||||||
.table-content-name {
|
.table-content-name {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -70,6 +34,7 @@
|
||||||
.button-as-link {
|
.button-as-link {
|
||||||
color: green;
|
color: green;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
|
text-decoration: none;
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -101,12 +66,10 @@
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
}
|
}
|
||||||
.content-as-table {
|
.content-as-table {
|
||||||
.table-content,
|
.table-content-main {
|
||||||
.table-content > * {
|
display: flex;
|
||||||
display: table;
|
|
||||||
}
|
}
|
||||||
.table-content-icon {
|
.table-content-icon {
|
||||||
float: left;
|
|
||||||
height: 100px;
|
height: 100px;
|
||||||
width: 106px;
|
width: 106px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -118,7 +81,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.table-content-text {
|
.table-content-text {
|
||||||
float: right;
|
|
||||||
width: calc(~'100% - 106px');
|
width: calc(~'100% - 106px');
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
@import 'subscription';
|
@import 'subscription';
|
||||||
@import 'editor/pdf';
|
@import 'editor/pdf';
|
||||||
@import 'editor/compile-button';
|
@import 'editor/compile-button';
|
||||||
|
@import 'editor/publish-modal';
|
||||||
@import 'editor/share';
|
@import 'editor/share';
|
||||||
@import 'editor/tags-input';
|
@import 'editor/tags-input';
|
||||||
@import 'website-redesign';
|
@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