aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'FrontEnd/src/views')
-rw-r--r--FrontEnd/src/views/admin/Admin.tsx5
-rw-r--r--FrontEnd/src/views/admin/UserAdmin.tsx17
-rw-r--r--FrontEnd/src/views/center/CenterBoards.tsx25
-rw-r--r--FrontEnd/src/views/center/index.tsx24
-rw-r--r--FrontEnd/src/views/common/ConfirmDialog.tsx18
-rw-r--r--FrontEnd/src/views/common/button/Button.css0
-rw-r--r--FrontEnd/src/views/common/button/Button.tsx30
-rw-r--r--FrontEnd/src/views/common/button/FlatButton.tsx31
-rw-r--r--FrontEnd/src/views/common/button/TextButton.tsx31
-rw-r--r--FrontEnd/src/views/common/button/common.ts31
-rw-r--r--FrontEnd/src/views/login/index.tsx5
-rw-r--r--FrontEnd/src/views/search/index.tsx9
-rw-r--r--FrontEnd/src/views/settings/ChangeAvatarDialog.tsx133
-rw-r--r--FrontEnd/src/views/settings/index.tsx33
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineMember.tsx35
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx4
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx11
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx13
18 files changed, 248 insertions, 207 deletions
diff --git a/FrontEnd/src/views/admin/Admin.tsx b/FrontEnd/src/views/admin/Admin.tsx
index 34e7e2f6..9393a61f 100644
--- a/FrontEnd/src/views/admin/Admin.tsx
+++ b/FrontEnd/src/views/admin/Admin.tsx
@@ -1,6 +1,5 @@
import React, { Fragment } from "react";
import { Redirect, Route, Switch, useRouteMatch, match } from "react-router";
-import { Container } from "react-bootstrap";
import { useTranslation } from "react-i18next";
import { AuthUser } from "@/services/user";
@@ -29,7 +28,7 @@ const Admin: React.FC<AdminProps> = ({ user }) => {
const match = p.match as match<{ name: string }>;
const name = match.params["name"];
return (
- <Container>
+ <div className="container">
<AdminNav />
{(() => {
if (name === "users") {
@@ -38,7 +37,7 @@ const Admin: React.FC<AdminProps> = ({ user }) => {
return <MoreAdmin user={user} />;
}
})()}
- </Container>
+ </div>
);
}}
</Route>
diff --git a/FrontEnd/src/views/admin/UserAdmin.tsx b/FrontEnd/src/views/admin/UserAdmin.tsx
index eb141520..2a123a76 100644
--- a/FrontEnd/src/views/admin/UserAdmin.tsx
+++ b/FrontEnd/src/views/admin/UserAdmin.tsx
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import classnames from "classnames";
-import { ListGroup, Row, Col, Spinner, Button } from "react-bootstrap";
import OperationDialog, {
OperationDialogBoolInput,
@@ -14,6 +13,7 @@ import {
UserPermission,
} from "@/http/user";
import { Trans, useTranslation } from "react-i18next";
+import Button from "../common/button/Button";
import TextButton from "../common/button/TextButton";
interface DialogProps<TData = undefined, TReturn = undefined> {
@@ -372,20 +372,19 @@ const UserAdmin: React.FC<UserAdminProps> = () => {
return (
<>
- <Row className="justify-content-end my-2">
- <Col xs="auto">
+ <div className="row justify-content-end my-2">
+ <div className="col col-auto">
<Button
- variant="outline-success"
+ text="admin:create"
+ color="success"
onClick={() =>
setDialog({
type: "create",
})
}
- >
- {t("admin:create")}
- </Button>
- </Col>
- </Row>
+ />
+ </div>
+ </div>
{userComponents}
{dialogNode}
</>
diff --git a/FrontEnd/src/views/center/CenterBoards.tsx b/FrontEnd/src/views/center/CenterBoards.tsx
index f5200415..392c2d08 100644
--- a/FrontEnd/src/views/center/CenterBoards.tsx
+++ b/FrontEnd/src/views/center/CenterBoards.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import { Row, Col } from "react-bootstrap";
import { useTranslation } from "react-i18next";
import { pushAlert } from "@/services/alert";
@@ -18,10 +17,10 @@ const CenterBoards: React.FC = () => {
return (
<>
- <Row className="justify-content-center">
- <Col xs="12" md="6">
- <Row>
- <Col xs="12" className="my-2">
+ <div className="row justify-content-center">
+ <div className="col col-12 col-md-6">
+ <div className="row">
+ <div className="col col-12 my-2">
<TimelineBoard
title={t("home.bookmarkTimeline")}
load={() => getHttpBookmarkClient().list()}
@@ -52,8 +51,8 @@ const CenterBoards: React.FC = () => {
},
}}
/>
- </Col>
- <Col xs="12" className="my-2">
+ </div>
+ <div className="col col-12 my-2">
<TimelineBoard
title={t("home.highlightTimeline")}
load={() => getHttpHighlightClient().list()}
@@ -88,18 +87,18 @@ const CenterBoards: React.FC = () => {
: undefined
}
/>
- </Col>
- </Row>
- </Col>
- <Col xs="12" md="6" className="my-2">
+ </div>
+ </div>
+ </div>
+ <div className="col-12 col-md-6 my-2">
<TimelineBoard
title={t("home.relatedTimeline")}
load={() =>
getHttpTimelineClient().listTimeline({ relate: user.username })
}
/>
- </Col>
- </Row>
+ </div>
+ </div>
</>
);
};
diff --git a/FrontEnd/src/views/center/index.tsx b/FrontEnd/src/views/center/index.tsx
index 28d8b372..dfad082a 100644
--- a/FrontEnd/src/views/center/index.tsx
+++ b/FrontEnd/src/views/center/index.tsx
@@ -1,11 +1,10 @@
import React from "react";
import { useHistory } from "react-router";
-import { useTranslation } from "react-i18next";
-import { Row, Container, Button, Col } from "react-bootstrap";
import { useUserLoggedIn } from "@/services/user";
import SearchInput from "../common/SearchInput";
+import Button from "../common/button/Button";
import CenterBoards from "./CenterBoards";
import TimelineCreateDialog from "./TimelineCreateDialog";
@@ -14,8 +13,6 @@ import "./index.css";
const HomePage: React.FC = () => {
const history = useHistory();
- const { t } = useTranslation();
-
const user = useUserLoggedIn();
const [navText, setNavText] = React.useState<string>("");
@@ -24,9 +21,9 @@ const HomePage: React.FC = () => {
return (
<>
- <Container>
- <Row className="my-3 justify-content-center">
- <Col xs={12} sm={8} lg={6}>
+ <div>
+ <div className="row my-3 justify-content-center">
+ <div className="col col-12 col-sm-8 col-lg-6">
<SearchInput
className="justify-content-center"
value={navText}
@@ -37,20 +34,19 @@ const HomePage: React.FC = () => {
additionalButton={
user != null && (
<Button
- variant="outline-success"
+ text="home.createButton"
+ color="success"
onClick={() => {
setDialog("create");
}}
- >
- {t("home.createButton")}
- </Button>
+ />
)
}
/>
- </Col>
- </Row>
+ </div>
+ </div>
<CenterBoards />
- </Container>
+ </div>
{dialog === "create" && (
<TimelineCreateDialog
open
diff --git a/FrontEnd/src/views/common/ConfirmDialog.tsx b/FrontEnd/src/views/common/ConfirmDialog.tsx
index 72940c51..70dc83f5 100644
--- a/FrontEnd/src/views/common/ConfirmDialog.tsx
+++ b/FrontEnd/src/views/common/ConfirmDialog.tsx
@@ -1,8 +1,9 @@
import { convertI18nText, I18nText } from "@/common";
import React from "react";
-import { Modal, Button } from "react-bootstrap";
import { useTranslation } from "react-i18next";
+import Button from "./button/Button";
+
const ConfirmDialog: React.FC<{
onClose: () => void;
onConfirm: () => void;
@@ -20,18 +21,19 @@ const ConfirmDialog: React.FC<{
</Modal.Header>
<Modal.Body>{convertI18nText(body, t)}</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={onClose}>
- {t("operationDialog.cancel")}
- </Button>
<Button
- variant="danger"
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={onClose}
+ />
+ <Button
+ text="operationDialog.confirm"
+ color="danger"
onClick={() => {
onConfirm();
onClose();
}}
- >
- {t("operationDialog.confirm")}
- </Button>
+ />
</Modal.Footer>
</Modal>
);
diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/FrontEnd/src/views/common/button/Button.css
diff --git a/FrontEnd/src/views/common/button/Button.tsx b/FrontEnd/src/views/common/button/Button.tsx
new file mode 100644
index 00000000..11710647
--- /dev/null
+++ b/FrontEnd/src/views/common/button/Button.tsx
@@ -0,0 +1,30 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+import { calculateProps, CommonButtonProps } from "./common";
+
+import "./Button.css";
+
+function _Button(
+ props: CommonButtonProps & { customButtonClassName?: string },
+ ref: React.ForwardedRef<HTMLButtonElement>
+): React.ReactElement | null {
+ const { t } = useTranslation();
+
+ const { customButtonClassName, ...otherProps } = props;
+
+ const { newProps, children } = calculateProps(
+ otherProps,
+ customButtonClassName ?? "cru-button",
+ t
+ );
+
+ return (
+ <button ref={ref} {...newProps}>
+ {children}
+ </button>
+ );
+}
+
+const Button = React.forwardRef(_Button);
+export default Button;
diff --git a/FrontEnd/src/views/common/button/FlatButton.tsx b/FrontEnd/src/views/common/button/FlatButton.tsx
index 6351971a..266ea908 100644
--- a/FrontEnd/src/views/common/button/FlatButton.tsx
+++ b/FrontEnd/src/views/common/button/FlatButton.tsx
@@ -1,39 +1,16 @@
import React from "react";
-import { useTranslation } from "react-i18next";
-import classNames from "classnames";
-import { convertI18nText, I18nText } from "@/common";
-import { PaletteColorType } from "@/palette";
+import { CommonButtonProps } from "./common";
+import Button from "./Button";
import "./FlatButton.css";
function _FlatButton(
- {
- text,
- color,
- onClick,
- className,
- style,
- }: {
- text: I18nText;
- color?: PaletteColorType;
- onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
- className?: string;
- style?: React.CSSProperties;
- },
+ props: CommonButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>
): React.ReactElement | null {
- const { t } = useTranslation();
-
return (
- <button
- ref={ref}
- className={classNames("cru-flat-button", color ?? "primary", className)}
- onClick={onClick}
- style={style}
- >
- {convertI18nText(text, t)}
- </button>
+ <Button ref={ref} customButtonClassName="cru-flat-button" {...props} />
);
}
diff --git a/FrontEnd/src/views/common/button/TextButton.tsx b/FrontEnd/src/views/common/button/TextButton.tsx
index 1a2bac94..1d8e7a4b 100644
--- a/FrontEnd/src/views/common/button/TextButton.tsx
+++ b/FrontEnd/src/views/common/button/TextButton.tsx
@@ -1,39 +1,16 @@
import React from "react";
-import { useTranslation } from "react-i18next";
-import classNames from "classnames";
-import { convertI18nText, I18nText } from "@/common";
-import { PaletteColorType } from "@/palette";
+import { CommonButtonProps } from "./common";
+import Button from "./Button";
import "./TextButton.css";
function _TextButton(
- {
- text,
- color,
- onClick,
- className,
- style,
- }: {
- text: I18nText;
- color?: PaletteColorType;
- onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
- className?: string;
- style?: React.CSSProperties;
- },
+ props: CommonButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>
): React.ReactElement | null {
- const { t } = useTranslation();
-
return (
- <button
- ref={ref}
- className={classNames("cru-text-button", color ?? "primary", className)}
- onClick={onClick}
- style={style}
- >
- {convertI18nText(text, t)}
- </button>
+ <Button ref={ref} customButtonClassName="cru-flat-button" {...props} />
);
}
diff --git a/FrontEnd/src/views/common/button/common.ts b/FrontEnd/src/views/common/button/common.ts
new file mode 100644
index 00000000..a9db959e
--- /dev/null
+++ b/FrontEnd/src/views/common/button/common.ts
@@ -0,0 +1,31 @@
+import React from "react";
+import classNames from "classnames";
+import { TFunction } from "i18next";
+
+import { convertI18nText, I18nText } from "@/common";
+import { PaletteColorType } from "@/palette";
+
+export type CommonButtonProps = {
+ text?: I18nText;
+ color?: PaletteColorType;
+} & React.ButtonHTMLAttributes<HTMLButtonElement>;
+
+export function calculateProps(
+ props: CommonButtonProps,
+ buttonClassName: string,
+ t: TFunction
+): {
+ children: React.ReactNode;
+ newProps: React.ButtonHTMLAttributes<HTMLButtonElement>;
+} {
+ const { text, color, className, children, ...otherProps } = props;
+ const newProps = {
+ className: classNames(buttonClassName, color ?? "primary", className),
+ ...otherProps,
+ };
+
+ return {
+ children: text != null ? convertI18nText(text, t) : children,
+ newProps: newProps,
+ };
+}
diff --git a/FrontEnd/src/views/login/index.tsx b/FrontEnd/src/views/login/index.tsx
index a39a9972..55bd2f8c 100644
--- a/FrontEnd/src/views/login/index.tsx
+++ b/FrontEnd/src/views/login/index.tsx
@@ -1,7 +1,6 @@
import React from "react";
import { useHistory } from "react-router";
import { useTranslation } from "react-i18next";
-import { Container, Form } from "react-bootstrap";
import { useUser, userService } from "@/services/user";
@@ -79,7 +78,7 @@ const LoginPage: React.FC = (_) => {
};
return (
- <Container fluid className="login-container mt-2">
+ <div className="login-container container-fluid mt-2">
<h1 className="text-center">{t("welcome")}</h1>
<Form>
<Form.Group>
@@ -146,7 +145,7 @@ const LoginPage: React.FC = (_) => {
</LoadingButton>
</div>
</Form>
- </Container>
+ </div>
);
};
diff --git a/FrontEnd/src/views/search/index.tsx b/FrontEnd/src/views/search/index.tsx
index e849a95d..509fd8c0 100644
--- a/FrontEnd/src/views/search/index.tsx
+++ b/FrontEnd/src/views/search/index.tsx
@@ -1,6 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
-import { Container, Row } from "react-bootstrap";
import { useHistory, useLocation } from "react-router";
import { Link } from "react-router-dom";
@@ -80,8 +79,8 @@ const SearchPage: React.FC = () => {
}, [queryParam, forceResearchKey]);
return (
- <Container className="my-3">
- <Row className="justify-content-center">
+ <div className="container my-3">
+ <div className="row justify-content-center">
<SearchInput
className="col-12 col-sm-9 col-md-6"
value={searchText}
@@ -95,7 +94,7 @@ const SearchPage: React.FC = () => {
}
}}
/>
- </Row>
+ </div>
{(() => {
switch (state) {
case "init": {
@@ -123,7 +122,7 @@ const SearchPage: React.FC = () => {
}
}
})()}
- </Container>
+ </div>
);
};
diff --git a/FrontEnd/src/views/settings/ChangeAvatarDialog.tsx b/FrontEnd/src/views/settings/ChangeAvatarDialog.tsx
index c4f6f492..1baab1cc 100644
--- a/FrontEnd/src/views/settings/ChangeAvatarDialog.tsx
+++ b/FrontEnd/src/views/settings/ChangeAvatarDialog.tsx
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { AxiosError } from "axios";
-import { Modal, Row, Button } from "react-bootstrap";
import { UiLogicError } from "@/common";
@@ -10,6 +9,7 @@ import { useUserLoggedIn } from "@/services/user";
import { getHttpUserClient } from "@/http/user";
import ImageCropper, { Clip, applyClipToImage } from "../common/ImageCropper";
+import Button from "../common/button/Button";
export interface ChangeAvatarDialogProps {
open: boolean;
@@ -148,13 +148,13 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
throw new UiLogicError();
}
return (
- <Row className="justify-content-center">
+ <div className="row justify-content-center">
<img
className="change-avatar-img"
src={resultUrl}
alt={t("settings.dialogChangeAvatar.previewImgAlt")}
/>
- </Row>
+ </div>
);
};
@@ -168,15 +168,19 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
return (
<>
<Modal.Body className="container">
- <Row>{t("settings.dialogChangeAvatar.prompt.select")}</Row>
- <Row>
+ <div className="row">
+ {t("settings.dialogChangeAvatar.prompt.select")}
+ </div>
+ <div className="row">
<input type="file" accept="image/*" onChange={onSelectFile} />
- </Row>
+ </div>
</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={close}>
- {t("operationDialog.cancel")}
- </Button>
+ <Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={close}
+ />
</Modal.Footer>
</>
);
@@ -187,32 +191,37 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
return (
<>
<Modal.Body className="container">
- <Row className="justify-content-center">
+ <div className="row justify-content-center">
<ImageCropper
clip={clip}
onChange={setClip}
imageUrl={fileUrl}
imageElementCallback={setCropImgElement}
/>
- </Row>
- <Row>{t("settings.dialogChangeAvatar.prompt.crop")}</Row>
+ </div>
+ <div className="row">
+ {t("settings.dialogChangeAvatar.prompt.crop")}
+ </div>
</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={close}>
- {t("operationDialog.cancel")}
- </Button>
- <Button variant="secondary" onClick={onCropPrevious}>
- {t("operationDialog.previousStep")}
- </Button>
<Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={close}
+ />
+ <Button
+ text="operationDialog.previousStep"
+ color="secondary"
+ onClick={onCropPrevious}
+ />
+ <Button
+ text="operationDialog.nextStep"
color="primary"
onClick={onCropNext}
disabled={
cropImgElement == null || clip == null || clip.width === 0
}
- >
- {t("operationDialog.nextStep")}
- </Button>
+ />
</Modal.Footer>
</>
);
@@ -220,17 +229,21 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
return (
<>
<Modal.Body className="container">
- <Row>
+ <div className="row">
{t("settings.dialogChangeAvatar.prompt.processingCrop")}
- </Row>
+ </div>
</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={close}>
- {t("operationDialog.cancel")}
- </Button>
- <Button variant="secondary" onClick={onPreviewPrevious}>
- {t("operationDialog.previousStep")}
- </Button>
+ <Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={close}
+ />
+ <Button
+ text="operationDialog.previousStep"
+ color="secondary"
+ onClick={onPreviewPrevious}
+ />
</Modal.Footer>
</>
);
@@ -239,18 +252,26 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
<>
<Modal.Body className="container">
{createPreviewRow()}
- <Row>{t("settings.dialogChangeAvatar.prompt.preview")}</Row>
+ <div className="row">
+ {t("settings.dialogChangeAvatar.prompt.preview")}
+ </div>
</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={close}>
- {t("operationDialog.cancel")}
- </Button>
- <Button variant="secondary" onClick={onPreviewPrevious}>
- {t("operationDialog.previousStep")}
- </Button>
- <Button variant="primary" onClick={upload}>
- {t("settings.dialogChangeAvatar.upload")}
- </Button>
+ <Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={close}
+ />
+ <Button
+ text="operationDialog.previousStep"
+ color="secondary"
+ onClick={onPreviewPrevious}
+ />
+ <Button
+ text="settings.dialogChangeAvatar.upload"
+ color="primary"
+ onClick={upload}
+ />
</Modal.Footer>
</>
);
@@ -259,7 +280,9 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
<>
<Modal.Body className="container">
{createPreviewRow()}
- <Row>{t("settings.dialogChangeAvatar.prompt.uploading")}</Row>
+ <div className="row">
+ {t("settings.dialogChangeAvatar.prompt.uploading")}
+ </div>
</Modal.Body>
<Modal.Footer></Modal.Footer>
</>
@@ -268,14 +291,16 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
return (
<>
<Modal.Body className="container">
- <Row className="p-4 text-success">
+ <div className="row p-4 text-success">
{t("operationDialog.success")}
- </Row>
+ </div>
</Modal.Body>
<Modal.Footer>
- <Button variant="success" onClick={close}>
- {t("operationDialog.ok")}
- </Button>
+ <Button
+ text="operationDialog.ok"
+ color="success"
+ onClick={close}
+ />
</Modal.Footer>
</>
);
@@ -284,15 +309,19 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
<>
<Modal.Body className="container">
{createPreviewRow()}
- <Row className="text-danger">{trueMessage}</Row>
+ <div className="row text-danger">{trueMessage}</div>
</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={close}>
- {t("operationDialog.cancel")}
- </Button>
- <Button variant="primary" onClick={upload}>
- {t("operationDialog.retry")}
- </Button>
+ <Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={close}
+ />
+ <Button
+ text="operationDialog.retry"
+ color="primary"
+ onClick={upload}
+ />
</Modal.Footer>
</>
);
diff --git a/FrontEnd/src/views/settings/index.tsx b/FrontEnd/src/views/settings/index.tsx
index 840bb7e8..b78e071a 100644
--- a/FrontEnd/src/views/settings/index.tsx
+++ b/FrontEnd/src/views/settings/index.tsx
@@ -1,7 +1,6 @@
import React, { useState } from "react";
import { useHistory } from "react-router";
import { useTranslation } from "react-i18next";
-import { Container, Form, Row, Col, Button, Modal } from "react-bootstrap";
import { useUser, userService } from "@/services/user";
@@ -27,12 +26,16 @@ const ConfirmLogoutDialog: React.FC<{
</Modal.Header>
<Modal.Body>{t("settings.dialogConfirmLogout.prompt")}</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={onClose}>
- {t("operationDialog.cancel")}
- </Button>
- <Button variant="danger" onClick={onConfirm}>
- {t("operationDialog.confirm")}
- </Button>
+ <Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={onClose}
+ />
+ <Button
+ text="operationDialog.confirm"
+ variant="danger"
+ onClick={onConfirm}
+ />
</Modal.Footer>
</Modal>
);
@@ -51,7 +54,7 @@ const SettingsPage: React.FC = (_) => {
return (
<>
- <Container>
+ <div className="container">
{user ? (
<Card className="my-3 py-3">
<h3 className="px-3 mb-3 text-primary">
@@ -89,14 +92,14 @@ const SettingsPage: React.FC = (_) => {
<h3 className="px-3 mb-3 text-primary">
{t("settings.subheaders.customization")}
</h3>
- <Row className="settings-item first mx-0">
- <Col xs="12" sm="auto">
+ <div className="row settings-item first mx-0">
+ <div className="col col-12 col-sm-auto">
<div>{t("settings.languagePrimary")}</div>
<small className="d-block text-secondary">
{t("settings.languageSecondary")}
</small>
- </Col>
- <Col xs="auto" className="ms-auto">
+ </div>
+ <div className="col col-12 col-sm-auto">
<Form.Control
as="select"
value={language}
@@ -107,10 +110,10 @@ const SettingsPage: React.FC = (_) => {
<option value="zh">中文</option>
<option value="en">English</option>
</Form.Control>
- </Col>
- </Row>
+ </div>
+ </div>
</Card>
- </Container>
+ </div>
{(() => {
switch (dialog) {
case "changepassword":
diff --git a/FrontEnd/src/views/timeline-common/TimelineMember.tsx b/FrontEnd/src/views/timeline-common/TimelineMember.tsx
index 299d6a53..830ecd45 100644
--- a/FrontEnd/src/views/timeline-common/TimelineMember.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineMember.tsx
@@ -1,6 +1,5 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
-import { Container, ListGroup, Modal, Row, Col, Button } from "react-bootstrap";
import { convertI18nText, I18nText } from "@/common";
@@ -10,6 +9,7 @@ import { getHttpSearchClient } from "@/http/search";
import SearchInput from "../common/SearchInput";
import UserAvatar from "../common/user/UserAvatar";
import { getHttpTimelineClient, HttpTimelineInfo } from "@/http/timeline";
+import Button from "../common/button/Button";
const TimelineMemberItem: React.FC<{
user: HttpUser;
@@ -20,29 +20,28 @@ const TimelineMemberItem: React.FC<{
return (
<ListGroup.Item className="container">
- <Row>
- <Col xs="auto">
+ <div className="row">
+ <div className="col col-auto">
<UserAvatar username={user.username} className="avatar small" />
- </Col>
- <Col>
- <Row>{user.nickname}</Row>
- <Row>
+ </div>
+ <div className="col">
+ <div className="row">{user.nickname}</div>
+ <div className="row">
<small>{"@" + user.username}</small>
- </Row>
- </Col>
+ </div>
+ </div>
{onAction ? (
- <Col xs="auto">
+ <div className="col col-auto">
<Button
- variant={add ? "success" : "danger"}
+ text={`timeline.member.${add ? "add" : "remove"}`}
+ color={add ? "success" : "danger"}
onClick={() => {
onAction(user.username);
}}
- >
- {t(`timeline.member.${add ? "add" : "remove"}`)}
- </Button>
- </Col>
+ />
+ </div>
) : null}
- </Row>
+ </div>
</ListGroup.Item>
);
};
@@ -152,7 +151,7 @@ const TimelineMember: React.FC<TimelineMemberProps> = (props) => {
const members = [timeline.owner, ...timeline.members];
return (
- <Container className="px-4 py-3">
+ <div className="container px-4 py-3">
<ListGroup>
{members.map((member, index) => (
<TimelineMemberItem
@@ -173,7 +172,7 @@ const TimelineMember: React.FC<TimelineMemberProps> = (props) => {
{timeline.manageable ? (
<TimelineMemberUserSearch timeline={timeline} onChange={onChange} />
) : null}
- </Container>
+ </div>
);
};
diff --git a/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
index 6f032eae..d05f18d4 100644
--- a/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
@@ -75,7 +75,7 @@ const TimelinePageTemplate: React.FC<TimelinePageTemplateProps> = (props) => {
connectionStatus={connectionStatus}
/>
) : null}
- <Container>
+ <div className="container">
<Timeline
timelineName={timelineName}
reloadKey={reloadKey}
@@ -83,7 +83,7 @@ const TimelinePageTemplate: React.FC<TimelinePageTemplateProps> = (props) => {
onTimelineLoaded={(t) => setTimeline(t)}
onConnectionStateChanged={setConnectionStatus}
/>
- </Container>
+ </div>
</>
);
};
diff --git a/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx b/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
index b2c7a470..e04bb7e1 100644
--- a/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
@@ -1,7 +1,8 @@
import React from "react";
-import { Modal, Button } from "react-bootstrap";
import { useTranslation } from "react-i18next";
+import Button from "../common/button/Button";
+
const TimelinePostDeleteConfirmDialog: React.FC<{
onClose: () => void;
onConfirm: () => void;
@@ -17,9 +18,11 @@ const TimelinePostDeleteConfirmDialog: React.FC<{
</Modal.Header>
<Modal.Body>{t("timeline.post.deleteDialog.prompt")}</Modal.Body>
<Modal.Footer>
- <Button variant="secondary" onClick={onClose}>
- {t("operationDialog.cancel")}
- </Button>
+ <Button
+ text="operationDialog.cancel"
+ color="secondary"
+ onClick={onClose}
+ />
<Button
variant="danger"
onClick={() => {
diff --git a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
index 14cd50d4..b522f288 100644
--- a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
@@ -1,7 +1,6 @@
import React from "react";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
-import { Row, Col, Form } from "react-bootstrap";
import { UiLogicError } from "@/common";
@@ -212,8 +211,8 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
onPostError={onPostError}
/>
) : (
- <Row>
- <Col className="px-1 py-1">
+ <div className="row">
+ <div className="col px-1 py-1">
{(() => {
if (kind === "text") {
return (
@@ -239,8 +238,8 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
);
}
})()}
- </Col>
- <Col xs="auto" className="align-self-end m-1">
+ </div>
+ <div className="col col-auto align-self-end m-1">
<div className="d-block text-center mt-1 mb-2">
<PopupMenu
items={(["text", "image", "markdown"] as const).map(
@@ -274,8 +273,8 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
>
{t("timeline.send")}
</LoadingButton>
- </Col>
- </Row>
+ </div>
+ </div>
)}
</Card>
</div>