diff options
author | crupest <crupest@outlook.com> | 2020-09-03 18:10:02 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-09-03 18:10:02 +0800 |
commit | ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559 (patch) | |
tree | ed843d6075b8c7667f1a402dfddf3f892fba3ffa /Timeline/ClientApp/src/app/views/common | |
parent | b027f7d2793999159b362041b2f697df74e4b1b9 (diff) | |
download | timeline-ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559.tar.gz timeline-ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559.tar.bz2 timeline-ac40d9c18e2ac7b4995dac38d5da04a3ea7f1559.zip |
Migrate to react-bootstrap.
Diffstat (limited to 'Timeline/ClientApp/src/app/views/common')
4 files changed, 48 insertions, 92 deletions
diff --git a/Timeline/ClientApp/src/app/views/common/AppBar.tsx b/Timeline/ClientApp/src/app/views/common/AppBar.tsx index 464747c0..ee4ead8f 100644 --- a/Timeline/ClientApp/src/app/views/common/AppBar.tsx +++ b/Timeline/ClientApp/src/app/views/common/AppBar.tsx @@ -17,7 +17,7 @@ const AppBar: React.FC = (_) => { const isAdministrator = user && user.administrator; return ( - <Navbar bg="primary" variant="dark" expand="md"> + <Navbar bg="primary" variant="dark" expand="md" sticky="top"> <LinkContainer to="/"> <Navbar.Brand className="d-flex align-items-center"> <TimelineLogo style={{ height: "1em" }} /> diff --git a/Timeline/ClientApp/src/app/views/common/FileInput.tsx b/Timeline/ClientApp/src/app/views/common/FileInput.tsx deleted file mode 100644 index 7b053d5c..00000000 --- a/Timeline/ClientApp/src/app/views/common/FileInput.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import clsx from "clsx"; - -export interface FileInputProps - extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "id"> { - inputId?: string; - labelText: string; - color?: string; - className?: string; -} - -const FileInput: React.FC<FileInputProps> = (props) => { - const { inputId, labelText, color, className, ...otherProps } = props; - - const realInputId = React.useMemo<string>(() => { - if (inputId != null) return inputId; - return ( - "file-input-" + - (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1) - ); - }, [inputId]); - - return ( - <> - <input className="d-none" type="file" id={realInputId} {...otherProps} /> - <label - htmlFor={realInputId} - className={clsx("btn", "btn-" + (color ?? "primary"), className)} - > - {labelText} - </label> - </> - ); -}; - -export default FileInput; diff --git a/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx b/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx index 402ffbec..6f97eb15 100644 --- a/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx +++ b/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx @@ -1,26 +1,13 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; -import { - Spinner, - Container, - ModalBody, - Label, - Input, - FormGroup, - FormFeedback, - ModalFooter, - Button, - Modal, - ModalHeader, - FormText, -} from "reactstrap"; +import { Spinner, Container, Form, Button, Modal } from "react-bootstrap"; import { UiLogicError } from "@/common"; const DefaultProcessPrompt: React.FC = (_) => { return ( <Container className="justify-content-center align-items-center"> - <Spinner /> + <Spinner animation="border" variant="success" /> </Container> ); }; @@ -233,7 +220,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { body = ( <> - <ModalBody> + <Modal.Body> {inputPrompt} {inputScheme.map((item, index) => { const value = values[index]; @@ -242,9 +229,9 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { if (item.type === "text") { return ( - <FormGroup key={index}> - {item.label && <Label>{t(item.label)}</Label>} - <Input + <Form.Group key={index}> + {item.label && <Form.Label>{t(item.label)}</Form.Label>} + <Form.Control type={item.password === true ? "password" : "text"} value={value as string} onChange={(e) => { @@ -258,35 +245,35 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { ) ); }} - invalid={error != null} - {...item.textFieldProps} + isInvalid={error != null} /> - {error != null && <FormFeedback>{error}</FormFeedback>} - {item.helperText && <FormText>{t(item.helperText)}</FormText>} - </FormGroup> + {error != null && ( + <Form.Control.Feedback>{error}</Form.Control.Feedback> + )} + {item.helperText && ( + <Form.Text>{t(item.helperText)}</Form.Text> + )} + </Form.Group> ); } else if (item.type === "bool") { return ( - <FormGroup check key={index}> - <Input + <Form.Group key={index}> + <Form.Check<"input"> type="checkbox" - value={value as string} - onChange={(e) => { - updateValue( - index, - (e.target as HTMLInputElement).checked - ); + checked={value as boolean} + onChange={(event) => { + updateValue(index, event.currentTarget.checked); }} + label={t(item.label)} /> - <Label check>{t(item.label)}</Label> - </FormGroup> + </Form.Group> ); } else if (item.type === "select") { return ( - <FormGroup key={index}> - <Label>{t(item.label)}</Label> - <Input - type="select" + <Form.Group key={index}> + <Form.Label>{t(item.label)}</Form.Label> + <Form.Control + as="select" value={value as string} onChange={(event) => { updateValue(index, event.target.value); @@ -300,18 +287,18 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { </option> ); })} - </Input> - </FormGroup> + </Form.Control> + </Form.Group> ); } })} - </ModalBody> - <ModalFooter> - <Button color="secondary" onClick={close}> + </Modal.Body> + <Modal.Footer> + <Button variant="secondary" onClick={close}> {t("operationDialog.cancel")} </Button> <Button - color="primary" + variant="primary" disabled={testErrorInfo(inputError)} onClick={() => { if (validateAll()) { @@ -321,14 +308,14 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { > {t("operationDialog.confirm")} </Button> - </ModalFooter> + </Modal.Footer> </> ); } else if (step === "process") { body = ( - <ModalBody> + <Modal.Body> {props.processPrompt?.() ?? <DefaultProcessPrompt />} - </ModalBody> + </Modal.Body> ); } else { let content: React.ReactNode; @@ -345,12 +332,12 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { } body = ( <> - <ModalBody>{content}</ModalBody> - <ModalFooter> - <Button color="primary" onClick={close}> + <Modal.Body>{content}</Modal.Body> + <Modal.Footer> + <Button variant="primary" onClick={close}> {t("operationDialog.ok")} </Button> - </ModalFooter> + </Modal.Footer> </> ); } @@ -359,7 +346,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { return ( <Modal isOpen={props.open} toggle={close}> - <ModalHeader + <Modal.Header className={ props.titleColor != null ? "text-" + @@ -372,7 +359,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => { } > {title} - </ModalHeader> + </Modal.Header> {body} </Modal> ); diff --git a/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx b/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx index 31c0fb86..c74f18e2 100644 --- a/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx +++ b/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx @@ -1,8 +1,8 @@ import React, { useCallback } from "react"; -import { Alert } from "reactstrap"; import without from "lodash/without"; import concat from "lodash/concat"; import { useTranslation } from "react-i18next"; +import { Alert } from "react-bootstrap"; import { alertService, @@ -37,7 +37,12 @@ export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => { }, [dismissTime, props.close]); return ( - <Alert className="m-3" color={alert.type ?? "primary"} toggle={props.close}> + <Alert + className="m-3" + variant={alert.type ?? "primary"} + onClose={props.close} + dismissible + > {(() => { const { message } = alert; if (typeof message === "function") { |