init
This commit is contained in:
56
src/component/Navbar/DarkModeSwitcher.js
Normal file
56
src/component/Navbar/DarkModeSwitcher.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { IconButton, makeStyles } from "@material-ui/core";
|
||||
import DayIcon from "@material-ui/icons/Brightness7";
|
||||
import NightIcon from "@material-ui/icons/Brightness4";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import classNames from "classnames";
|
||||
import { toggleDaylightMode } from "../../redux/explorer";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
icon: {
|
||||
color: "rgb(255, 255, 255)",
|
||||
opacity: "0.54",
|
||||
},
|
||||
}));
|
||||
|
||||
const DarkModeSwitcher = ({ position }) => {
|
||||
const { t } = useTranslation();
|
||||
const ThemeType = useSelector(
|
||||
(state) => state.siteConfig.theme.palette.type
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const ToggleThemeMode = useCallback(() => dispatch(toggleDaylightMode()), [
|
||||
dispatch,
|
||||
]);
|
||||
const isDayLight = (ThemeType && ThemeType === "light") || !ThemeType;
|
||||
const isDark = ThemeType && ThemeType === "dark";
|
||||
const toggleMode = () => {
|
||||
Auth.SetPreference("theme_mode", isDayLight ? "dark" : "light");
|
||||
ToggleThemeMode();
|
||||
};
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
isDayLight ? t("navbar.toDarkMode") : t("navbar.toLightMode")
|
||||
}
|
||||
placement="bottom"
|
||||
>
|
||||
<IconButton
|
||||
className={classNames({
|
||||
[classes.icon]: "left" === position,
|
||||
})}
|
||||
onClick={toggleMode}
|
||||
color="inherit"
|
||||
>
|
||||
{isDayLight && <NightIcon />}
|
||||
{isDark && <DayIcon />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default DarkModeSwitcher;
|
407
src/component/Navbar/FileTags.js
Normal file
407
src/component/Navbar/FileTags.js
Normal file
@@ -0,0 +1,407 @@
|
||||
import React, { Suspense, useCallback, useState } from "react";
|
||||
import {
|
||||
Divider,
|
||||
List,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
makeStyles,
|
||||
withStyles,
|
||||
} from "@material-ui/core";
|
||||
import { Clear, KeyboardArrowRight } from "@material-ui/icons";
|
||||
import classNames from "classnames";
|
||||
import FolderShared from "@material-ui/icons/FolderShared";
|
||||
import UploadIcon from "@material-ui/icons/CloudUpload";
|
||||
import VideoIcon from "@material-ui/icons/VideoLibraryOutlined";
|
||||
import ImageIcon from "@material-ui/icons/CollectionsOutlined";
|
||||
import MusicIcon from "@material-ui/icons/LibraryMusicOutlined";
|
||||
import DocIcon from "@material-ui/icons/FileCopyOutlined";
|
||||
import { useHistory, useLocation } from "react-router";
|
||||
import pathHelper from "../../utils/page";
|
||||
import MuiExpansionPanel from "@material-ui/core/ExpansionPanel";
|
||||
import MuiExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
|
||||
import MuiExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
|
||||
import MuiListItem from "@material-ui/core/ListItem";
|
||||
import { useDispatch } from "react-redux";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import {
|
||||
Circle,
|
||||
CircleOutline,
|
||||
FolderHeartOutline,
|
||||
Heart,
|
||||
HeartOutline,
|
||||
Hexagon,
|
||||
HexagonOutline,
|
||||
Hexagram,
|
||||
HexagramOutline,
|
||||
Rhombus,
|
||||
RhombusOutline,
|
||||
Square,
|
||||
SquareOutline,
|
||||
TagPlus,
|
||||
Triangle,
|
||||
TriangleOutline,
|
||||
} from "mdi-material-ui";
|
||||
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import API from "../../middleware/Api";
|
||||
import { navigateTo, searchMyFile, toggleSnackbar } from "../../redux/explorer";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const ListItem = withStyles((theme) => ({
|
||||
root: {
|
||||
borderRadius:theme.shape.borderRadius,
|
||||
},
|
||||
}))(MuiListItem);
|
||||
|
||||
const ExpansionPanel = withStyles({
|
||||
root: {
|
||||
maxWidth: "100%",
|
||||
boxShadow: "none",
|
||||
"&:not(:last-child)": {
|
||||
borderBottom: 0,
|
||||
},
|
||||
"&:before": {
|
||||
display: "none",
|
||||
},
|
||||
"&$expanded": { margin: 0 },
|
||||
},
|
||||
expanded: {},
|
||||
})(MuiExpansionPanel);
|
||||
|
||||
const ExpansionPanelSummary = withStyles((theme) =>({
|
||||
root: {
|
||||
minHeight: 0,
|
||||
padding: 0,
|
||||
"&$expanded": {
|
||||
minHeight: 0,
|
||||
},
|
||||
},
|
||||
content: {
|
||||
maxWidth: "100%",
|
||||
margin: 0,
|
||||
display: "block",
|
||||
"&$expanded": {
|
||||
margin: "0",
|
||||
},
|
||||
},
|
||||
expanded: {},
|
||||
}))(MuiExpansionPanelSummary);
|
||||
|
||||
const ExpansionPanelDetails = withStyles((theme) => ({
|
||||
root: {
|
||||
display: "block",
|
||||
padding: theme.spacing(0),
|
||||
},
|
||||
}))(MuiExpansionPanelDetails);
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
expand: {
|
||||
display: "none",
|
||||
transition: ".15s all ease-in-out",
|
||||
},
|
||||
expanded: {
|
||||
display: "block",
|
||||
transform: "rotate(90deg)",
|
||||
},
|
||||
iconFix: {
|
||||
marginLeft: "16px",
|
||||
},
|
||||
hiddenButton: {
|
||||
display: "none",
|
||||
},
|
||||
subMenu: {
|
||||
marginLeft: theme.spacing(2),
|
||||
},
|
||||
overFlow: {
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
},
|
||||
paddingList:{
|
||||
padding:theme.spacing(1),
|
||||
},
|
||||
paddingSummary:{
|
||||
paddingLeft:theme.spacing(1),
|
||||
paddingRight:theme.spacing(1),
|
||||
}
|
||||
}));
|
||||
|
||||
const icons = {
|
||||
Circle: Circle,
|
||||
CircleOutline: CircleOutline,
|
||||
Heart: Heart,
|
||||
HeartOutline: HeartOutline,
|
||||
Hexagon: Hexagon,
|
||||
HexagonOutline: HexagonOutline,
|
||||
Hexagram: Hexagram,
|
||||
HexagramOutline: HexagramOutline,
|
||||
Rhombus: Rhombus,
|
||||
RhombusOutline: RhombusOutline,
|
||||
Square: Square,
|
||||
SquareOutline: SquareOutline,
|
||||
Triangle: Triangle,
|
||||
TriangleOutline: TriangleOutline,
|
||||
FolderHeartOutline: FolderHeartOutline,
|
||||
};
|
||||
|
||||
const AddTag = React.lazy(() => import("../Modals/AddTag"));
|
||||
|
||||
export default function FileTag() {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
|
||||
const isHomePage = pathHelper.isHomePage(location.pathname);
|
||||
|
||||
const [tagOpen, setTagOpen] = useState(true);
|
||||
const [addTagModal, setAddTagModal] = useState(false);
|
||||
const [tagHover, setTagHover] = useState(null);
|
||||
const [tags, setTags] = useState(
|
||||
Auth.GetUser().tags ? Auth.GetUser().tags : []
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const SearchMyFile = useCallback((k, p) => dispatch(searchMyFile(k, p)), [
|
||||
dispatch,
|
||||
]);
|
||||
const NavigateTo = useCallback((k) => dispatch(navigateTo(k)), [dispatch]);
|
||||
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const getIcon = (icon, color) => {
|
||||
if (icons[icon]) {
|
||||
const IconComponent = icons[icon];
|
||||
return (
|
||||
<IconComponent
|
||||
className={[classes.iconFix]}
|
||||
style={
|
||||
color
|
||||
? {
|
||||
color: color,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Circle className={[classes.iconFix]} />;
|
||||
};
|
||||
|
||||
const submitSuccess = (tag) => {
|
||||
const newTags = [...tags, tag];
|
||||
setTags(newTags);
|
||||
const user = Auth.GetUser();
|
||||
user.tags = newTags;
|
||||
Auth.SetUser(user);
|
||||
};
|
||||
|
||||
const submitDelete = (id) => {
|
||||
API.delete("/tag/" + id)
|
||||
.then(() => {
|
||||
const newTags = tags.filter((v) => {
|
||||
return v.id !== id;
|
||||
});
|
||||
setTags(newTags);
|
||||
const user = Auth.GetUser();
|
||||
user.tags = newTags;
|
||||
Auth.SetUser(user);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={""}>
|
||||
<AddTag
|
||||
onSuccess={submitSuccess}
|
||||
open={addTagModal}
|
||||
onClose={() => setAddTagModal(false)}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExpansionPanel
|
||||
square
|
||||
expanded={tagOpen && isHomePage}
|
||||
onChange={() => isHomePage && setTagOpen(!tagOpen)}
|
||||
>
|
||||
<ExpansionPanelSummary
|
||||
aria-controls="panel1d-content"
|
||||
id="panel1d-header"
|
||||
>
|
||||
<div className={classes.paddingSummary}>
|
||||
<ListItem
|
||||
button
|
||||
key="我的文件"
|
||||
onClick={() =>
|
||||
!isHomePage && history.push("/home?path=%2F")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<KeyboardArrowRight
|
||||
className={classNames(
|
||||
{
|
||||
[classes.expanded]:
|
||||
tagOpen && isHomePage,
|
||||
[classes.iconFix]: true,
|
||||
},
|
||||
classes.expand
|
||||
)}
|
||||
/>
|
||||
{!(tagOpen && isHomePage) && (
|
||||
<FolderShared className={classes.iconFix} />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("navbar.myFiles")} />
|
||||
</ListItem>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
</ExpansionPanelSummary>
|
||||
|
||||
<ExpansionPanelDetails>
|
||||
<List className={classes.paddingList} onMouseLeave={() => setTagHover(null)}>
|
||||
<ListItem
|
||||
button
|
||||
id="pickfiles"
|
||||
className={classes.hiddenButton}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
<ListItem
|
||||
button
|
||||
id="pickfolder"
|
||||
className={classes.hiddenButton}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
{[
|
||||
{
|
||||
key: t("navbar.videos"),
|
||||
id: "video",
|
||||
icon: (
|
||||
<VideoIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconVideo,
|
||||
]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: t("navbar.photos"),
|
||||
id: "image",
|
||||
icon: (
|
||||
<ImageIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconImg,
|
||||
]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: t("navbar.music"),
|
||||
id: "audio",
|
||||
icon: (
|
||||
<MusicIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconAudio,
|
||||
]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: t("navbar.documents"),
|
||||
id: "doc",
|
||||
icon: (
|
||||
<DocIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconDoc,
|
||||
]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
].map((v) => (
|
||||
<ListItem
|
||||
button
|
||||
key={v.key}
|
||||
onClick={() =>
|
||||
SearchMyFile(v.id + "/internal", "")
|
||||
}
|
||||
>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
{v.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={v.key} />
|
||||
</ListItem>
|
||||
))}
|
||||
{tags.map((v) => (
|
||||
<ListItem
|
||||
button
|
||||
key={v.id}
|
||||
onMouseEnter={() => setTagHover(v.id)}
|
||||
onClick={() => {
|
||||
if (v.type === 0) {
|
||||
SearchMyFile("tag/" + v.id, "");
|
||||
} else {
|
||||
NavigateTo(v.expression);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
{getIcon(
|
||||
v.type === 0
|
||||
? v.icon
|
||||
: "FolderHeartOutline",
|
||||
v.type === 0 ? v.color : null
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={classes.overFlow}
|
||||
primary={v.name}
|
||||
/>
|
||||
|
||||
{tagHover === v.id && (
|
||||
<ListItemSecondaryAction
|
||||
onClick={() => submitDelete(v.id)}
|
||||
>
|
||||
<IconButton
|
||||
size={"small"}
|
||||
edge="end"
|
||||
aria-label="delete"
|
||||
>
|
||||
<Clear />
|
||||
</IconButton>
|
||||
</ListItemSecondaryAction>
|
||||
)}
|
||||
</ListItem>
|
||||
))}
|
||||
|
||||
<ListItem button onClick={() => setAddTagModal(true)}>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
<TagPlus className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("navbar.addATag")} />
|
||||
</ListItem>
|
||||
</List>{" "}
|
||||
<Divider />
|
||||
</ExpansionPanelDetails>
|
||||
</ExpansionPanel>
|
||||
</>
|
||||
);
|
||||
}
|
984
src/component/Navbar/Navbar.js
Normal file
984
src/component/Navbar/Navbar.js
Normal file
@@ -0,0 +1,984 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
import { connect } from "react-redux";
|
||||
import ShareIcon from "@material-ui/icons/Share";
|
||||
import MusicNote from "@material-ui/icons/MusicNote";
|
||||
import BackIcon from "@material-ui/icons/ArrowBack";
|
||||
import SdStorage from "@material-ui/icons/SdStorage";
|
||||
import OpenIcon from "@material-ui/icons/OpenInNew";
|
||||
import DownloadIcon from "@material-ui/icons/CloudDownload";
|
||||
import RenameIcon from "@material-ui/icons/BorderColor";
|
||||
import MoveIcon from "@material-ui/icons/Input";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import MenuIcon from "@material-ui/icons/Menu";
|
||||
import { isPreviewable } from "../../config";
|
||||
import { changeThemeColor, sizeToString, vhCheck } from "../../utils";
|
||||
import Uploader from "../Uploader/Uploader.js";
|
||||
import pathHelper from "../../utils/page";
|
||||
import SezrchBar from "./SearchBar";
|
||||
import StorageBar from "./StorageBar";
|
||||
import UserAvatar from "./UserAvatar";
|
||||
import UserInfo from "./UserInfo";
|
||||
import {
|
||||
FolderDownload,
|
||||
AccountArrowRight,
|
||||
AccountPlus,
|
||||
LogoutVariant,
|
||||
} from "mdi-material-ui";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import {
|
||||
AppBar,
|
||||
Drawer,
|
||||
Grow,
|
||||
Hidden,
|
||||
IconButton,
|
||||
List,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
SwipeableDrawer,
|
||||
Toolbar,
|
||||
Tooltip,
|
||||
Typography,
|
||||
withStyles,
|
||||
withTheme
|
||||
} from "@material-ui/core";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import API from "../../middleware/Api";
|
||||
import FileTag from "./FileTags";
|
||||
import { Assignment, Devices, MoreHoriz, Settings } from "@material-ui/icons";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import SubActions from "../FileManager/Navigator/SubActions";
|
||||
import {
|
||||
audioPreviewSetIsOpen,
|
||||
changeContextMenu,
|
||||
drawerToggleAction,
|
||||
navigateTo,
|
||||
openCreateFolderDialog,
|
||||
openLoadingDialog,
|
||||
openMoveDialog,
|
||||
openMusicDialog,
|
||||
openPreview,
|
||||
openRemoveDialog,
|
||||
openRenameDialog,
|
||||
openShareDialog,
|
||||
saveFile,
|
||||
setSelectedTarget,
|
||||
setSessionStatus,
|
||||
showImgPreivew,
|
||||
toggleSnackbar,
|
||||
} from "../../redux/explorer";
|
||||
import {
|
||||
startBatchDownload,
|
||||
startDirectoryDownload,
|
||||
startDownload,
|
||||
} from "../../redux/explorer/action";
|
||||
import PolicySwitcher from "./PolicySwitcher";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import MuiListItem from "@material-ui/core/ListItem";
|
||||
|
||||
vhCheck();
|
||||
const drawerWidth = 240;
|
||||
const drawerWidthMobile = 270;
|
||||
|
||||
const ListItem = withStyles((theme) => ({
|
||||
root: {
|
||||
borderRadius:theme.shape.borderRadius,
|
||||
},
|
||||
}))(MuiListItem);
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
desktopOpen: state.viewUpdate.open,
|
||||
selected: state.explorer.selected,
|
||||
isMultiple: state.explorer.selectProps.isMultiple,
|
||||
withFolder: state.explorer.selectProps.withFolder,
|
||||
withFile: state.explorer.selectProps.withFile,
|
||||
path: state.navigator.path,
|
||||
title: state.siteConfig.title,
|
||||
subTitle: state.viewUpdate.subTitle,
|
||||
loadUploader: state.viewUpdate.loadUploader,
|
||||
isLogin: state.viewUpdate.isLogin,
|
||||
shareInfo: state.viewUpdate.shareInfo,
|
||||
registerEnabled: state.siteConfig.registerEnabled,
|
||||
audioPreviewPlayingName: state.explorer.audioPreview.playingName,
|
||||
audioPreviewIsOpen: state.explorer.audioPreview.isOpen,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
handleDesktopToggle: (open) => {
|
||||
dispatch(drawerToggleAction(open));
|
||||
},
|
||||
setSelectedTarget: (targets) => {
|
||||
dispatch(setSelectedTarget(targets));
|
||||
},
|
||||
navigateTo: (path) => {
|
||||
dispatch(navigateTo(path));
|
||||
},
|
||||
openCreateFolderDialog: () => {
|
||||
dispatch(openCreateFolderDialog());
|
||||
},
|
||||
changeContextMenu: (type, open) => {
|
||||
dispatch(changeContextMenu(type, open));
|
||||
},
|
||||
saveFile: () => {
|
||||
dispatch(saveFile());
|
||||
},
|
||||
openMusicDialog: () => {
|
||||
dispatch(openMusicDialog());
|
||||
},
|
||||
showImgPreivew: (first) => {
|
||||
dispatch(showImgPreivew(first));
|
||||
},
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
},
|
||||
openRenameDialog: () => {
|
||||
dispatch(openRenameDialog());
|
||||
},
|
||||
openMoveDialog: () => {
|
||||
dispatch(openMoveDialog());
|
||||
},
|
||||
openRemoveDialog: () => {
|
||||
dispatch(openRemoveDialog());
|
||||
},
|
||||
openShareDialog: () => {
|
||||
dispatch(openShareDialog());
|
||||
},
|
||||
openLoadingDialog: (text) => {
|
||||
dispatch(openLoadingDialog(text));
|
||||
},
|
||||
setSessionStatus: () => {
|
||||
dispatch(setSessionStatus());
|
||||
},
|
||||
openPreview: (share) => {
|
||||
dispatch(openPreview(share));
|
||||
},
|
||||
audioPreviewOpen: () => {
|
||||
dispatch(audioPreviewSetIsOpen(true));
|
||||
},
|
||||
startBatchDownload: (share) => {
|
||||
dispatch(startBatchDownload(share));
|
||||
},
|
||||
startDirectoryDownload: (share) => {
|
||||
dispatch(startDirectoryDownload(share));
|
||||
},
|
||||
startDownload: (share, file) => {
|
||||
dispatch(startDownload(share, file));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const styles = (theme) => ({
|
||||
appBar: {
|
||||
marginLeft: drawerWidth,
|
||||
[theme.breakpoints.down("xs")]: {
|
||||
marginLeft: drawerWidthMobile,
|
||||
},
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
transition: " background-color 250ms",
|
||||
},
|
||||
|
||||
drawer: {
|
||||
width: 0,
|
||||
flexShrink: 0,
|
||||
},
|
||||
drawerDesktop: {
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
},
|
||||
icon: {
|
||||
marginRight: theme.spacing(2),
|
||||
},
|
||||
menuButton: {
|
||||
marginRight: 20,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
menuButtonDesktop: {
|
||||
marginRight: 20,
|
||||
[theme.breakpoints.down("xs")]: {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
menuIcon: {
|
||||
marginRight: 20,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
drawerPaper: {
|
||||
width: drawerWidthMobile,
|
||||
},
|
||||
drawerPaperDesktop: {
|
||||
width: drawerWidth,
|
||||
},
|
||||
upDrawer: {
|
||||
overflowX: "hidden",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
},
|
||||
drawerOpen: {
|
||||
width: drawerWidth,
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
},
|
||||
drawerClose: {
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
width: 0,
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing(3),
|
||||
},
|
||||
grow: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
badge: {
|
||||
top: 1,
|
||||
right: -15,
|
||||
},
|
||||
nested: {
|
||||
paddingLeft: theme.spacing(4),
|
||||
},
|
||||
sectionForFile: {
|
||||
display: "flex",
|
||||
},
|
||||
extendedIcon: {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
addButton: {
|
||||
marginLeft: "40px",
|
||||
marginTop: "25px",
|
||||
marginBottom: "15px",
|
||||
},
|
||||
fabButton: {
|
||||
borderRadius: "100px",
|
||||
},
|
||||
badgeFix: {
|
||||
right: "10px",
|
||||
},
|
||||
iconFix: {
|
||||
marginLeft: "16px",
|
||||
},
|
||||
dividerFix: {
|
||||
marginTop: "8px",
|
||||
},
|
||||
folderShareIcon: {
|
||||
verticalAlign: "sub",
|
||||
marginRight: "5px",
|
||||
},
|
||||
shareInfoContainer: {
|
||||
display: "flex",
|
||||
marginTop: "15px",
|
||||
marginBottom: "20px",
|
||||
marginLeft: "28px",
|
||||
textDecoration: "none",
|
||||
},
|
||||
shareAvatar: {
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
},
|
||||
stickFooter: {
|
||||
bottom: "0px",
|
||||
position: "absolute",
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
width: "100%",
|
||||
},
|
||||
ownerInfo: {
|
||||
marginLeft: "10px",
|
||||
width: "150px",
|
||||
},
|
||||
minStickDrawer: {
|
||||
overflowY: "auto",
|
||||
},
|
||||
paddingList:{
|
||||
padding:theme.spacing(1),
|
||||
}
|
||||
});
|
||||
class NavbarCompoment extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
mobileOpen: false,
|
||||
};
|
||||
this.UploaderRef = React.createRef();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.unlisten = this.props.history.listen(() => {
|
||||
this.setState(() => ({ mobileOpen: false }));
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
changeThemeColor(
|
||||
this.props.selected.length <= 1 &&
|
||||
!(!this.props.isMultiple && this.props.withFile)
|
||||
? this.props.theme.palette.primary.main
|
||||
: this.props.theme.palette.background.default
|
||||
);
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps = (nextProps) => {
|
||||
if (
|
||||
(this.props.selected.length === 0) !==
|
||||
(nextProps.selected.length === 0)
|
||||
) {
|
||||
changeThemeColor(
|
||||
!(this.props.selected.length === 0)
|
||||
? this.props.theme.palette.type === "dark"
|
||||
? this.props.theme.palette.background.default
|
||||
: this.props.theme.palette.primary.main
|
||||
: this.props.theme.palette.background.default
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
handleDrawerToggle = () => {
|
||||
this.setState((state) => ({ mobileOpen: !state.mobileOpen }));
|
||||
};
|
||||
|
||||
openDownload = () => {
|
||||
this.props.startDownload(this.props.shareInfo, this.props.selected[0]);
|
||||
};
|
||||
|
||||
openDirectoryDownload = (e) => {
|
||||
this.props.startDirectoryDownload(this.props.shareInfo);
|
||||
};
|
||||
|
||||
archiveDownload = (e) => {
|
||||
this.props.startBatchDownload(this.props.shareInfo);
|
||||
};
|
||||
|
||||
signOut = () => {
|
||||
API.delete("/user/session/")
|
||||
.then(() => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
this.props.t("login.loggedOut"),
|
||||
"success"
|
||||
);
|
||||
Auth.signout();
|
||||
window.location.reload();
|
||||
this.props.setSessionStatus(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"warning"
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
this.handleClose();
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, t } = this.props;
|
||||
const user = Auth.GetUser(this.props.isLogin);
|
||||
const isHomePage = pathHelper.isHomePage(this.props.location.pathname);
|
||||
const isSharePage = pathHelper.isSharePage(
|
||||
this.props.location.pathname
|
||||
);
|
||||
|
||||
const drawer = (
|
||||
<div id="container" className={classes.upDrawer}>
|
||||
{pathHelper.isMobile() && <UserInfo />}
|
||||
|
||||
{Auth.Check(this.props.isLogin) && (
|
||||
<>
|
||||
<div className={classes.minStickDrawer}>
|
||||
<FileTag />
|
||||
<List className={classes.paddingList}>
|
||||
<ListItem
|
||||
button
|
||||
key="我的分享"
|
||||
onClick={() =>
|
||||
this.props.history.push("/shares?")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ShareIcon
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t("navbar.myShare")}
|
||||
/>
|
||||
</ListItem>
|
||||
{user.group.allowRemoteDownload && (
|
||||
<ListItem
|
||||
button
|
||||
key="离线下载"
|
||||
onClick={() =>
|
||||
this.props.history.push("/aria2?")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DownloadIcon
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t("navbar.remoteDownload")}
|
||||
/>
|
||||
</ListItem>
|
||||
)}
|
||||
<ListItem
|
||||
button
|
||||
key="容量配额"
|
||||
onClick={() =>
|
||||
this.props.history.push("/quota?")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SdStorage
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("vas.quota")} />
|
||||
</ListItem>
|
||||
<ListItem
|
||||
button
|
||||
key="WebDAV"
|
||||
onClick={() =>
|
||||
this.props.history.push("/connect?")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Devices className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t("navbar.connect")}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem
|
||||
button
|
||||
key="任务队列"
|
||||
onClick={() =>
|
||||
this.props.history.push("/tasks?")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Assignment
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t("navbar.taskQueue")}
|
||||
/>
|
||||
</ListItem>
|
||||
{pathHelper.isMobile() && (
|
||||
<>
|
||||
<Divider />
|
||||
<ListItem
|
||||
button
|
||||
key="个人设置"
|
||||
onClick={() =>
|
||||
this.props.history.push(
|
||||
"/setting?"
|
||||
)
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Settings
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t("navbar.setting")}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem
|
||||
button
|
||||
key="退出登录"
|
||||
onClick={this.signOut}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<LogoutVariant
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t("login.logout")}
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
</div>
|
||||
<div>
|
||||
<StorageBar></StorageBar>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{!Auth.Check(this.props.isLogin) && (
|
||||
<div>
|
||||
<ListItem
|
||||
button
|
||||
key="登录"
|
||||
onClick={() => this.props.history.push("/login")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccountArrowRight
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("login.signIn")} />
|
||||
</ListItem>
|
||||
{this.props.registerEnabled && (
|
||||
<ListItem
|
||||
button
|
||||
key="注册"
|
||||
onClick={() =>
|
||||
this.props.history.push("/signup")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccountPlus className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("login.signUp")} />
|
||||
</ListItem>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const iOS =
|
||||
process.browser && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
||||
return (
|
||||
<div>
|
||||
<AppBar
|
||||
position="fixed"
|
||||
className={classes.appBar}
|
||||
color={
|
||||
this.props.theme.palette.type !== "dark" &&
|
||||
this.props.selected.length === 0
|
||||
? "primary"
|
||||
: "default"
|
||||
}
|
||||
>
|
||||
<Toolbar>
|
||||
{this.props.selected.length === 0 && (
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="Open drawer"
|
||||
onClick={this.handleDrawerToggle}
|
||||
className={classes.menuButton}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
{this.props.selected.length === 0 && (
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="Open drawer"
|
||||
onClick={() =>
|
||||
this.props.handleDesktopToggle(
|
||||
!this.props.desktopOpen
|
||||
)
|
||||
}
|
||||
className={classes.menuButtonDesktop}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
{this.props.selected.length > 0 &&
|
||||
(isHomePage ||
|
||||
pathHelper.isSharePage(
|
||||
this.props.location.pathname
|
||||
)) && (
|
||||
<Grow in={this.props.selected.length > 0}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
className={classes.menuIcon}
|
||||
onClick={() =>
|
||||
this.props.setSelectedTarget([])
|
||||
}
|
||||
>
|
||||
<BackIcon />
|
||||
</IconButton>
|
||||
</Grow>
|
||||
)}
|
||||
{this.props.selected.length === 0 && (
|
||||
<Typography
|
||||
variant="h6"
|
||||
color="inherit"
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
}}
|
||||
noWrap
|
||||
onClick={() => {
|
||||
this.props.history.push("/");
|
||||
}}
|
||||
>
|
||||
{this.props.subTitle
|
||||
? this.props.subTitle
|
||||
: this.props.title}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{!this.props.isMultiple &&
|
||||
(this.props.withFile || this.props.withFolder) &&
|
||||
!pathHelper.isMobile() && (
|
||||
<Typography variant="h6" color="inherit" noWrap>
|
||||
{this.props.selected[0].name}{" "}
|
||||
{this.props.withFile &&
|
||||
(isHomePage ||
|
||||
pathHelper.isSharePage(
|
||||
this.props.location.pathname
|
||||
)) &&
|
||||
"(" +
|
||||
sizeToString(
|
||||
this.props.selected[0].size
|
||||
) +
|
||||
")"}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{this.props.selected.length > 1 &&
|
||||
!pathHelper.isMobile() && (
|
||||
<Typography variant="h6" color="inherit" noWrap>
|
||||
{t("navbar.objectsSelected", {
|
||||
num: this.props.selected.length,
|
||||
})}
|
||||
</Typography>
|
||||
)}
|
||||
{this.props.selected.length === 0 && <SezrchBar />}
|
||||
<div className={classes.grow} />
|
||||
{this.props.selected.length > 0 &&
|
||||
(isHomePage || isSharePage) && (
|
||||
<div className={classes.sectionForFile}>
|
||||
{!this.props.isMultiple &&
|
||||
this.props.withFile &&
|
||||
isPreviewable(
|
||||
this.props.selected[0].name
|
||||
) && (
|
||||
<Grow
|
||||
in={
|
||||
!this.props.isMultiple &&
|
||||
this.props.withFile &&
|
||||
isPreviewable(
|
||||
this.props.selected[0]
|
||||
.name
|
||||
)
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.open"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.props.openPreview(
|
||||
this.props
|
||||
.shareInfo
|
||||
)
|
||||
}
|
||||
>
|
||||
<OpenIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
{!this.props.isMultiple &&
|
||||
this.props.withFile && (
|
||||
<Grow
|
||||
in={
|
||||
!this.props.isMultiple &&
|
||||
this.props.withFile
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.download"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.openDownload()
|
||||
}
|
||||
>
|
||||
<DownloadIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
{(this.props.isMultiple ||
|
||||
this.props.withFolder) &&
|
||||
window.showDirectoryPicker &&
|
||||
window.isSecureContext && (
|
||||
<Grow
|
||||
in={
|
||||
(this.props.isMultiple ||
|
||||
this.props
|
||||
.withFolder) &&
|
||||
window.showDirectoryPicker &&
|
||||
window.isSecureContext
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.download"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.openDirectoryDownload()
|
||||
}
|
||||
>
|
||||
<FolderDownload />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
{(this.props.isMultiple ||
|
||||
this.props.withFolder) && (
|
||||
<Grow
|
||||
in={
|
||||
this.props.isMultiple ||
|
||||
this.props.withFolder
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.batchDownload"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
disableClickAway
|
||||
onClick={() =>
|
||||
this.archiveDownload()
|
||||
}
|
||||
>
|
||||
<DownloadIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
{!this.props.isMultiple &&
|
||||
!pathHelper.isMobile() &&
|
||||
!isSharePage && (
|
||||
<Grow in={!this.props.isMultiple}>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.share"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.props.openShareDialog()
|
||||
}
|
||||
>
|
||||
<ShareIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
{!this.props.isMultiple && !isSharePage && (
|
||||
<Grow in={!this.props.isMultiple}>
|
||||
<Tooltip
|
||||
title={t("fileManager.rename")}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.props.openRenameDialog()
|
||||
}
|
||||
>
|
||||
<RenameIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
{!isSharePage && (
|
||||
<div style={{ display: "flex" }}>
|
||||
{!pathHelper.isMobile() && (
|
||||
<Grow
|
||||
in={
|
||||
this.props.selected
|
||||
.length !== 0 &&
|
||||
!pathHelper.isMobile()
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.move"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.props.openMoveDialog()
|
||||
}
|
||||
>
|
||||
<MoveIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
|
||||
<Grow
|
||||
in={
|
||||
this.props.selected
|
||||
.length !== 0
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.delete"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.props.openRemoveDialog()
|
||||
}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
|
||||
{pathHelper.isMobile() && (
|
||||
<Grow
|
||||
in={
|
||||
this.props.selected
|
||||
.length !== 0 &&
|
||||
pathHelper.isMobile()
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
title={t(
|
||||
"fileManager.moreActions"
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() =>
|
||||
this.props.changeContextMenu(
|
||||
"file",
|
||||
true
|
||||
)
|
||||
}
|
||||
>
|
||||
<MoreHoriz />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{this.props.selected.length <= 1 &&
|
||||
!(!this.props.isMultiple && this.props.withFile) &&
|
||||
this.props.audioPreviewPlayingName != null && (
|
||||
<IconButton
|
||||
title={t("navbar.music")}
|
||||
className={classes.sideButton}
|
||||
onClick={this.props.audioPreviewOpen}
|
||||
color={"inherit"}
|
||||
>
|
||||
<MusicNote fontSize={"default"} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
{this.props.selected.length === 0 && <UserAvatar />}
|
||||
{this.props.selected.length === 0 &&
|
||||
pathHelper.isMobile() && (
|
||||
<>
|
||||
{isHomePage && <PolicySwitcher />}
|
||||
{(isHomePage || this.props.shareInfo) && (
|
||||
<SubActions inherit />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<Uploader />
|
||||
|
||||
<Hidden smUp implementation="css">
|
||||
<SwipeableDrawer
|
||||
container={this.props.container}
|
||||
variant="temporary"
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
}}
|
||||
anchor="left"
|
||||
open={this.state.mobileOpen}
|
||||
onClose={this.handleDrawerToggle}
|
||||
onOpen={() =>
|
||||
this.setState(() => ({ mobileOpen: true }))
|
||||
}
|
||||
disableDiscovery={iOS}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
</SwipeableDrawer>
|
||||
</Hidden>
|
||||
<Hidden xsDown implementation="css">
|
||||
<Drawer
|
||||
classes={{
|
||||
paper: classes.drawerPaperDesktop,
|
||||
}}
|
||||
className={classNames(classes.drawer, {
|
||||
[classes.drawerOpen]: this.props.desktopOpen,
|
||||
[classes.drawerClose]: !this.props.desktopOpen,
|
||||
})}
|
||||
variant="persistent"
|
||||
anchor="left"
|
||||
open={this.props.desktopOpen}
|
||||
>
|
||||
<div className={classes.toolbar} />
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</Hidden>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
NavbarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const Navbar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
withTheme(
|
||||
withStyles(styles)(withRouter(withTranslation()(NavbarCompoment)))
|
||||
)
|
||||
);
|
||||
|
||||
export default Navbar;
|
202
src/component/Navbar/PolicySwitcher.js
Normal file
202
src/component/Navbar/PolicySwitcher.js
Normal file
@@ -0,0 +1,202 @@
|
||||
import React, { useCallback } from "react";
|
||||
import {
|
||||
Avatar,
|
||||
CircularProgress,
|
||||
IconButton,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
makeStyles,
|
||||
} from "@material-ui/core";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import { Nas } from "mdi-material-ui";
|
||||
import Popover from "@material-ui/core/Popover";
|
||||
import API from "../../middleware/Api";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Backup, Check } from "@material-ui/icons";
|
||||
import { blue, green } from "@material-ui/core/colors";
|
||||
import List from "@material-ui/core/List";
|
||||
import { refreshFileList, toggleSnackbar } from "../../redux/explorer";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import Link from "@material-ui/core/Link";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import pathHelper from "../../utils/page";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
uploadFromFile: {
|
||||
backgroundColor: blue[100],
|
||||
color: blue[600],
|
||||
},
|
||||
policySelected: {
|
||||
backgroundColor: green[100],
|
||||
color: green[800],
|
||||
},
|
||||
header: {
|
||||
padding: "8px 16px",
|
||||
fontSize: 14,
|
||||
},
|
||||
list: {
|
||||
minWidth: 300,
|
||||
maxHeight: 600,
|
||||
overflow: "auto",
|
||||
},
|
||||
}));
|
||||
|
||||
const PolicySwitcher = () => {
|
||||
const { t } = useTranslation();
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
const [policies, setPolicies] = React.useState([]);
|
||||
const [loading, setLoading] = React.useState(null);
|
||||
const policy = useSelector((state) => state.explorer.currentPolicy);
|
||||
const path = useSelector((state) => state.navigator.path);
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||||
[dispatch]
|
||||
);
|
||||
const RefreshFileList = useCallback(() => dispatch(refreshFileList()), [
|
||||
dispatch,
|
||||
]);
|
||||
const search = useSelector((state) => state.explorer.search);
|
||||
|
||||
const handleClick = (event) => {
|
||||
if (policies.length === 0) {
|
||||
API.get("/user/setting/policies", {})
|
||||
.then((response) => {
|
||||
setPolicies(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
}
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const switchTo = (id) => {
|
||||
if (id === policy.id) {
|
||||
handleClose();
|
||||
return;
|
||||
}
|
||||
setLoading(id);
|
||||
API.post("/webdav/mount", {
|
||||
path: path,
|
||||
policy: id,
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
t("vas.folderPolicySwitched"),
|
||||
"success"
|
||||
);
|
||||
RefreshFileList();
|
||||
setLoading(null);
|
||||
handleClose();
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
setLoading(null);
|
||||
handleClose();
|
||||
});
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "simple-popover" : undefined;
|
||||
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<>
|
||||
{pathHelper.isHomePage(location.pathname) && !search && (
|
||||
<Tooltip title={t("vas.switchFolderPolicy")} placement="bottom">
|
||||
<IconButton onClick={handleClick} color="inherit">
|
||||
<Nas />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Popover
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
}}
|
||||
>
|
||||
<div className={classes.header}>
|
||||
<Box color={"text.secondary"}>
|
||||
{t("vas.setPolicyForFolder")}
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
<List className={classes.list}>
|
||||
{policies.map((value, index) => (
|
||||
<ListItem
|
||||
button
|
||||
component="label"
|
||||
key={index}
|
||||
onClick={() => switchTo(value.id)}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
{value.id === loading && (
|
||||
<CircularProgress
|
||||
size={35}
|
||||
color="secondary"
|
||||
/>
|
||||
)}
|
||||
{value.id !== loading && (
|
||||
<>
|
||||
{value.id === policy.id && (
|
||||
<Avatar
|
||||
className={
|
||||
classes.policySelected
|
||||
}
|
||||
>
|
||||
<Check />
|
||||
</Avatar>
|
||||
)}
|
||||
{value.id !== policy.id && (
|
||||
<Avatar
|
||||
className={
|
||||
classes.uploadFromFile
|
||||
}
|
||||
>
|
||||
<Backup />
|
||||
</Avatar>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={value.name} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Divider />
|
||||
<div className={classes.header}>
|
||||
<Link
|
||||
onClick={() => handleClose()}
|
||||
component={RouterLink}
|
||||
to={"/connect?tab=1"}
|
||||
color={"secondary"}
|
||||
>
|
||||
{t("vas.manageMount")}
|
||||
</Link>
|
||||
</div>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PolicySwitcher;
|
283
src/component/Navbar/SearchBar.js
Normal file
283
src/component/Navbar/SearchBar.js
Normal file
@@ -0,0 +1,283 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
import FileIcon from "@material-ui/icons/InsertDriveFile";
|
||||
import ShareIcon from "@material-ui/icons/Share";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
Fade,
|
||||
InputBase,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography,
|
||||
withStyles,
|
||||
} from "@material-ui/core";
|
||||
import { withRouter } from "react-router";
|
||||
import pathHelper from "../../utils/page";
|
||||
import { configure, HotKeys } from "react-hotkeys";
|
||||
import { searchMyFile } from "../../redux/explorer";
|
||||
import FolderIcon from "@material-ui/icons/Folder";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
|
||||
configure({
|
||||
ignoreTags: [],
|
||||
});
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
path: state.navigator.path,
|
||||
search: state.explorer.search,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
searchMyFile: (keywords, path) => {
|
||||
dispatch(searchMyFile(keywords, path));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const styles = (theme) => ({
|
||||
search: {
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display: "none",
|
||||
},
|
||||
position: "relative",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: fade(theme.palette.common.white, 0.15),
|
||||
"&:hover": {
|
||||
backgroundColor: fade(theme.palette.common.white, 0.25),
|
||||
},
|
||||
marginRight: theme.spacing(2),
|
||||
marginLeft: 0,
|
||||
width: "100%",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
marginLeft: theme.spacing(7.2),
|
||||
width: "auto",
|
||||
},
|
||||
},
|
||||
searchIcon: {
|
||||
width: theme.spacing(9),
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
pointerEvents: "none",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
inputRoot: {
|
||||
color: "inherit",
|
||||
width: "100%",
|
||||
},
|
||||
inputInput: {
|
||||
paddingTop: theme.spacing(1),
|
||||
paddingRight: theme.spacing(1),
|
||||
paddingBottom: theme.spacing(1),
|
||||
paddingLeft: theme.spacing(7),
|
||||
transition: theme.transitions.create("width"),
|
||||
width: "100%",
|
||||
[theme.breakpoints.up("md")]: {
|
||||
width: 200,
|
||||
"&:focus": {
|
||||
width: 300,
|
||||
},
|
||||
},
|
||||
},
|
||||
suggestBox: {
|
||||
zIndex: "9999",
|
||||
width: 364,
|
||||
},
|
||||
});
|
||||
|
||||
const keyMap = {
|
||||
SEARCH: "enter",
|
||||
};
|
||||
|
||||
class SearchBarCompoment extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
anchorEl: null,
|
||||
input: "",
|
||||
};
|
||||
}
|
||||
|
||||
handlers = {
|
||||
SEARCH: (e) => {
|
||||
if (pathHelper.isHomePage(this.props.location.pathname)) {
|
||||
this.searchMyFile("")();
|
||||
} else {
|
||||
this.searchShare();
|
||||
}
|
||||
e.target.blur();
|
||||
},
|
||||
};
|
||||
|
||||
handleChange = (event) => {
|
||||
const { currentTarget } = event;
|
||||
this.input = event.target.value;
|
||||
this.setState({
|
||||
anchorEl: currentTarget,
|
||||
input: event.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
cancelSuggest = () => {
|
||||
this.setState({
|
||||
input: "",
|
||||
});
|
||||
};
|
||||
|
||||
searchMyFile = (path) => () => {
|
||||
this.props.searchMyFile("keywords/" + this.input, path);
|
||||
};
|
||||
|
||||
searchShare = () => {
|
||||
this.props.history.push(
|
||||
"/search?keywords=" + encodeURIComponent(this.input)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, t } = this.props;
|
||||
const { anchorEl } = this.state;
|
||||
const id = this.state.input !== "" ? "simple-popper" : null;
|
||||
const isHomePage = pathHelper.isHomePage(this.props.location.pathname);
|
||||
|
||||
return (
|
||||
<div className={classes.search}>
|
||||
<div className={classes.searchIcon}>
|
||||
<SearchIcon />
|
||||
</div>
|
||||
<HotKeys keyMap={keyMap} handlers={this.handlers}>
|
||||
<InputBase
|
||||
placeholder={t("navbar.searchPlaceholder")}
|
||||
classes={{
|
||||
root: classes.inputRoot,
|
||||
input: classes.inputInput,
|
||||
}}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.cancelSuggest}
|
||||
value={this.state.input}
|
||||
/>
|
||||
</HotKeys>
|
||||
<Popper
|
||||
id={id}
|
||||
open={this.state.input !== ""}
|
||||
anchorEl={anchorEl}
|
||||
className={classes.suggestBox}
|
||||
transition
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Fade {...TransitionProps} timeout={350}>
|
||||
<Paper square={true}>
|
||||
{isHomePage && (
|
||||
<MenuItem onClick={this.searchMyFile("")}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<FileIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
classes={{
|
||||
primary: classes.primary,
|
||||
}}
|
||||
primary={
|
||||
<Typography noWrap>
|
||||
<Trans
|
||||
i18nKey="navbar.searchInFiles"
|
||||
values={{
|
||||
name: this.state
|
||||
.input,
|
||||
}}
|
||||
components={[
|
||||
<strong key={0} />,
|
||||
]}
|
||||
/>
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</MenuItem>
|
||||
)}
|
||||
|
||||
{isHomePage &&
|
||||
this.props.path !== "/" &&
|
||||
!this.props.search && (
|
||||
<MenuItem
|
||||
onClick={this.searchMyFile(
|
||||
this.props.path
|
||||
)}
|
||||
>
|
||||
<ListItemIcon
|
||||
className={classes.icon}
|
||||
>
|
||||
<FolderIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
classes={{
|
||||
primary: classes.primary,
|
||||
}}
|
||||
primary={
|
||||
<Typography noWrap>
|
||||
<Trans
|
||||
i18nKey="navbar.searchInFolders"
|
||||
values={{
|
||||
name: this.state
|
||||
.input,
|
||||
}}
|
||||
components={[
|
||||
<strong
|
||||
key={0}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</MenuItem>
|
||||
)}
|
||||
|
||||
<MenuItem onClick={this.searchShare}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<ShareIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
classes={{ primary: classes.primary }}
|
||||
primary={
|
||||
<Typography noWrap>
|
||||
<Trans
|
||||
i18nKey="navbar.searchInShares"
|
||||
values={{
|
||||
name: this.state.input,
|
||||
}}
|
||||
components={[
|
||||
<strong key={0} />,
|
||||
]}
|
||||
/>
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</MenuItem>
|
||||
</Paper>
|
||||
</Fade>
|
||||
)}
|
||||
</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchBarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const SearchBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(withRouter(withTranslation()(SearchBarCompoment))));
|
||||
|
||||
export default SearchBar;
|
208
src/component/Navbar/StorageBar.js
Normal file
208
src/component/Navbar/StorageBar.js
Normal file
@@ -0,0 +1,208 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import StorageIcon from "@material-ui/icons/Storage";
|
||||
import { connect } from "react-redux";
|
||||
import API from "../../middleware/Api";
|
||||
import { sizeToString } from "../../utils";
|
||||
|
||||
import {
|
||||
Divider,
|
||||
LinearProgress,
|
||||
Tooltip,
|
||||
Typography,
|
||||
withStyles,
|
||||
} from "@material-ui/core";
|
||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||
import Link from "@material-ui/core/Link";
|
||||
import { withRouter } from "react-router";
|
||||
import { toggleSnackbar } from "../../redux/explorer";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
refresh: state.viewUpdate.storageRefresh,
|
||||
isLogin: state.viewUpdate.isLogin,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const styles = (theme) => ({
|
||||
iconFix: {
|
||||
marginLeft: "32px",
|
||||
marginRight: "17px",
|
||||
color: theme.palette.text.secondary,
|
||||
marginTop: "2px",
|
||||
},
|
||||
textFix: {
|
||||
padding: " 0 0 0 16px",
|
||||
},
|
||||
storageContainer: {
|
||||
display: "flex",
|
||||
marginTop: "15px",
|
||||
textAlign: "left",
|
||||
marginBottom: "11px",
|
||||
},
|
||||
detail: {
|
||||
width: "100%",
|
||||
marginRight: "35px",
|
||||
},
|
||||
info: {
|
||||
width: "131px",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
[theme.breakpoints.down("xs")]: {
|
||||
width: "162px",
|
||||
},
|
||||
marginTop: "5px",
|
||||
},
|
||||
bar: {
|
||||
marginTop: "5px",
|
||||
},
|
||||
stickFooter: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
});
|
||||
|
||||
// TODO 使用 hooks 重构
|
||||
class StorageBarCompoment extends Component {
|
||||
state = {
|
||||
percent: 0,
|
||||
used: null,
|
||||
total: null,
|
||||
showExpand: false,
|
||||
};
|
||||
|
||||
firstLoad = true;
|
||||
|
||||
componentDidMount = () => {
|
||||
if (this.firstLoad && this.props.isLogin) {
|
||||
this.firstLoad = !this.firstLoad;
|
||||
this.updateStatus();
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
this.firstLoad = false;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps = (nextProps) => {
|
||||
if (
|
||||
(this.props.isLogin && this.props.refresh !== nextProps.refresh) ||
|
||||
(this.props.isLogin !== nextProps.isLogin && nextProps.isLogin)
|
||||
) {
|
||||
this.updateStatus();
|
||||
}
|
||||
};
|
||||
|
||||
updateStatus = () => {
|
||||
let percent = 0;
|
||||
API.get("/user/storage")
|
||||
.then((response) => {
|
||||
if (response.data.used / response.data.total >= 1) {
|
||||
percent = 100;
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
this.props.t("vas.exceedQuota"),
|
||||
"warning"
|
||||
);
|
||||
} else {
|
||||
percent = (response.data.used / response.data.total) * 100;
|
||||
}
|
||||
this.setState({
|
||||
percent: percent,
|
||||
used: sizeToString(response.data.used),
|
||||
total: sizeToString(response.data.total),
|
||||
});
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, t } = this.props;
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={() => this.setState({ showExpand: true })}
|
||||
onMouseLeave={() => this.setState({ showExpand: false })}
|
||||
className={classes.stickFooter}
|
||||
>
|
||||
<Divider />
|
||||
<ButtonBase onClick={() => this.props.history.push("/quota")}>
|
||||
<div className={classes.storageContainer}>
|
||||
<StorageIcon className={classes.iconFix} />
|
||||
<div className={classes.detail}>
|
||||
<Typography variant={"subtitle2"}>
|
||||
{t("navbar.storage") + " "}
|
||||
{this.state.showExpand && (
|
||||
<Link
|
||||
component={RouterLink}
|
||||
color={"secondary"}
|
||||
to={"/buy"}
|
||||
>
|
||||
{t("vas.extendStorage")}
|
||||
</Link>
|
||||
)}
|
||||
</Typography>
|
||||
|
||||
<LinearProgress
|
||||
className={classes.bar}
|
||||
color="secondary"
|
||||
variant="determinate"
|
||||
value={this.state.percent}
|
||||
/>
|
||||
<div className={classes.info}>
|
||||
<Tooltip
|
||||
title={t("navbar.storageDetail", {
|
||||
used:
|
||||
this.state.used === null
|
||||
? " -- "
|
||||
: this.state.used,
|
||||
total:
|
||||
this.state.total === null
|
||||
? " -- "
|
||||
: this.state.total,
|
||||
})}
|
||||
placement="top"
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
noWrap
|
||||
color="textSecondary"
|
||||
>
|
||||
{this.state.used === null
|
||||
? " -- "
|
||||
: this.state.used}
|
||||
{" / "}
|
||||
{this.state.total === null
|
||||
? " -- "
|
||||
: this.state.total}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StorageBarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const StorageBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(withRouter(withTranslation()(StorageBarCompoment))));
|
||||
|
||||
export default StorageBar;
|
178
src/component/Navbar/UserAvatar.js
Normal file
178
src/component/Navbar/UserAvatar.js
Normal file
@@ -0,0 +1,178 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import SettingIcon from "@material-ui/icons/Settings";
|
||||
import UserAvatarPopover from "./UserAvatarPopover";
|
||||
import { AccountCircle } from "mdi-material-ui";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import {
|
||||
Avatar,
|
||||
Grow,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
withStyles,
|
||||
} from "@material-ui/core";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import pathHelper from "../../utils/page";
|
||||
import DarkModeSwitcher from "./DarkModeSwitcher";
|
||||
import PolicySwitcher from "./PolicySwitcher";
|
||||
import { Home } from "@material-ui/icons";
|
||||
import { setUserPopover } from "../../redux/explorer";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
selected: state.explorer.selected,
|
||||
isMultiple: state.explorer.selectProps.isMultiple,
|
||||
withFolder: state.explorer.selectProps.withFolder,
|
||||
withFile: state.explorer.selectProps.withFile,
|
||||
isLogin: state.viewUpdate.isLogin,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setUserPopover: (anchor) => {
|
||||
dispatch(setUserPopover(anchor));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const styles = (theme) => ({
|
||||
mobileHidden: {
|
||||
[theme.breakpoints.down("xs")]: {
|
||||
display: "none",
|
||||
},
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
avatar: {
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
},
|
||||
header: {
|
||||
display: "flex",
|
||||
padding: "20px 20px 20px 20px",
|
||||
},
|
||||
largeAvatar: {
|
||||
height: "90px",
|
||||
width: "90px",
|
||||
},
|
||||
info: {
|
||||
marginLeft: "10px",
|
||||
width: "139px",
|
||||
},
|
||||
badge: {
|
||||
marginTop: "10px",
|
||||
},
|
||||
visitorMenu: {
|
||||
width: 200,
|
||||
},
|
||||
});
|
||||
|
||||
class UserAvatarCompoment extends Component {
|
||||
state = {
|
||||
anchorEl: null,
|
||||
};
|
||||
|
||||
showUserInfo = (e) => {
|
||||
this.props.setUserPopover(e.currentTarget);
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({
|
||||
anchorEl: null,
|
||||
});
|
||||
};
|
||||
|
||||
openURL = (url) => {
|
||||
window.location.href = url;
|
||||
};
|
||||
|
||||
returnHome = () => {
|
||||
window.location.href = "/home";
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, t } = this.props;
|
||||
const loginCheck = Auth.Check(this.props.isLogin);
|
||||
const user = Auth.GetUser(this.props.isLogin);
|
||||
const isAdminPage = pathHelper.isAdminPage(
|
||||
this.props.location.pathname
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classes.mobileHidden}>
|
||||
<Grow
|
||||
in={
|
||||
this.props.selected.length <= 1 &&
|
||||
!(!this.props.isMultiple && this.props.withFile)
|
||||
}
|
||||
>
|
||||
<div>
|
||||
{!isAdminPage && (
|
||||
<>
|
||||
<DarkModeSwitcher position="top" />
|
||||
{loginCheck && (
|
||||
<>
|
||||
<PolicySwitcher />
|
||||
<Tooltip
|
||||
title={t("navbar.setting")}
|
||||
placement="bottom"
|
||||
>
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
this.props.history.push(
|
||||
"/setting?"
|
||||
)
|
||||
}
|
||||
color="inherit"
|
||||
>
|
||||
<SettingIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{isAdminPage && (
|
||||
<Tooltip
|
||||
title={t("navbar.backToHomepage")}
|
||||
placement="bottom"
|
||||
>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={this.returnHome}
|
||||
>
|
||||
<Home />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<IconButton color="inherit" onClick={this.showUserInfo}>
|
||||
{!loginCheck && <AccountCircle />}
|
||||
{loginCheck && (
|
||||
<Avatar
|
||||
src={
|
||||
"/api/v3/user/avatar/" + user.id + "/s"
|
||||
}
|
||||
className={classes.avatar}
|
||||
/>
|
||||
)}
|
||||
</IconButton>{" "}
|
||||
</div>
|
||||
</Grow>
|
||||
<UserAvatarPopover />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserAvatarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const UserAvatar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(withRouter(withTranslation()(UserAvatarCompoment))));
|
||||
|
||||
export default UserAvatar;
|
260
src/component/Navbar/UserAvatarPopover.js
Normal file
260
src/component/Navbar/UserAvatarPopover.js
Normal file
@@ -0,0 +1,260 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
AccountArrowRight,
|
||||
AccountPlus,
|
||||
DesktopMacDashboard,
|
||||
HomeAccount,
|
||||
LogoutVariant,
|
||||
} from "mdi-material-ui";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import {
|
||||
Avatar,
|
||||
Chip,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
MenuItem,
|
||||
Popover,
|
||||
Typography,
|
||||
withStyles,
|
||||
} from "@material-ui/core";
|
||||
import API from "../../middleware/Api";
|
||||
import pathHelper from "../../utils/page";
|
||||
import {
|
||||
setSessionStatus,
|
||||
setUserPopover,
|
||||
toggleSnackbar,
|
||||
} from "../../redux/explorer";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
anchorEl: state.viewUpdate.userPopoverAnchorEl,
|
||||
registerEnabled: state.siteConfig.registerEnabled,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setUserPopover: (anchor) => {
|
||||
dispatch(setUserPopover(anchor));
|
||||
},
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
},
|
||||
setSessionStatus: (status) => {
|
||||
dispatch(setSessionStatus(status));
|
||||
},
|
||||
};
|
||||
};
|
||||
const styles = () => ({
|
||||
avatar: {
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
},
|
||||
header: {
|
||||
display: "flex",
|
||||
padding: "20px 20px 20px 20px",
|
||||
},
|
||||
largeAvatar: {
|
||||
height: "90px",
|
||||
width: "90px",
|
||||
},
|
||||
info: {
|
||||
marginLeft: "10px",
|
||||
width: "139px",
|
||||
},
|
||||
badge: {
|
||||
marginTop: "10px",
|
||||
},
|
||||
visitorMenu: {
|
||||
width: 200,
|
||||
},
|
||||
});
|
||||
|
||||
class UserAvatarPopoverCompoment extends Component {
|
||||
handleClose = () => {
|
||||
this.props.setUserPopover(null);
|
||||
};
|
||||
|
||||
openURL = (url) => {
|
||||
window.location.href = url;
|
||||
};
|
||||
|
||||
sigOut = () => {
|
||||
API.delete("/user/session/")
|
||||
.then(() => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
this.props.t("login.loggedOut"),
|
||||
"success"
|
||||
);
|
||||
Auth.signout();
|
||||
window.location.reload();
|
||||
this.props.setSessionStatus(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"warning"
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
this.handleClose();
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, t } = this.props;
|
||||
const user = Auth.GetUser();
|
||||
const isAdminPage = pathHelper.isAdminPage(
|
||||
this.props.location.pathname
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
open={this.props.anchorEl !== null}
|
||||
onClose={this.handleClose}
|
||||
anchorEl={this.props.anchorEl}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
>
|
||||
{!Auth.Check() && (
|
||||
<div className={classes.visitorMenu}>
|
||||
<Divider />
|
||||
<MenuItem
|
||||
onClick={() => this.props.history.push("/login")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccountArrowRight />
|
||||
</ListItemIcon>
|
||||
{t("login.signIn")}
|
||||
</MenuItem>
|
||||
{this.props.registerEnabled && (
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.props.history.push("/signup")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccountPlus />
|
||||
</ListItemIcon>
|
||||
{t("login.signUp")}
|
||||
</MenuItem>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{Auth.Check() && (
|
||||
<div>
|
||||
<div className={classes.header}>
|
||||
<div className={classes.largeAvatarContainer}>
|
||||
<Avatar
|
||||
className={classes.largeAvatar}
|
||||
src={
|
||||
"/api/v3/user/avatar/" + user.id + "/l"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.info}>
|
||||
<Typography noWrap>{user.nickname}</Typography>
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
style={{
|
||||
fontSize: "0.875rem",
|
||||
}}
|
||||
noWrap
|
||||
>
|
||||
{user.user_name}
|
||||
</Typography>
|
||||
<Chip
|
||||
className={classes.badge}
|
||||
color={
|
||||
user.group.id === 1
|
||||
? "secondary"
|
||||
: "default"
|
||||
}
|
||||
label={user.group.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Divider />
|
||||
{!isAdminPage && (
|
||||
<MenuItem
|
||||
style={{
|
||||
padding: " 11px 16px 11px 16px",
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleClose();
|
||||
this.props.history.push(
|
||||
"/profile/" + user.id
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<HomeAccount />
|
||||
</ListItemIcon>
|
||||
{t("navbar.myProfile")}
|
||||
</MenuItem>
|
||||
)}
|
||||
{user.group.id === 1 && (
|
||||
<MenuItem
|
||||
style={{
|
||||
padding: " 11px 16px 11px 16px",
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleClose();
|
||||
this.props.history.push("/admin/home");
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DesktopMacDashboard />
|
||||
</ListItemIcon>
|
||||
{t("navbar.dashboard")}
|
||||
</MenuItem>
|
||||
)}
|
||||
|
||||
<MenuItem
|
||||
style={{
|
||||
padding: " 11px 16px 11px 16px",
|
||||
}}
|
||||
onClick={this.sigOut}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<LogoutVariant />
|
||||
</ListItemIcon>
|
||||
{t("login.logout")}
|
||||
</MenuItem>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserAvatarPopoverCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const UserAvatarPopover = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
withStyles(styles)(
|
||||
withRouter(withTranslation()(UserAvatarPopoverCompoment))
|
||||
)
|
||||
);
|
||||
|
||||
export default UserAvatarPopover;
|
152
src/component/Navbar/UserInfo.js
Normal file
152
src/component/Navbar/UserInfo.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import { Typography, withStyles } from "@material-ui/core";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import DarkModeSwitcher from "./DarkModeSwitcher";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import { setUserPopover } from "../../redux/explorer";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
isLogin: state.viewUpdate.isLogin,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setUserPopover: (anchor) => {
|
||||
dispatch(setUserPopover(anchor));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const styles = (theme) => ({
|
||||
userNav: {
|
||||
height: "170px",
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: "20px 20px 2em",
|
||||
backgroundImage:
|
||||
"url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cpolygon fill='" +
|
||||
theme.palette.primary.light.replace("#", "%23") +
|
||||
"' points='957 450 539 900 1396 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.primary.dark.replace("#", "%23") +
|
||||
"' points='957 450 872.9 900 1396 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.main.replace("#", "%23") +
|
||||
"' points='-60 900 398 662 816 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.dark.replace("#", "%23") +
|
||||
"' points='337 900 398 662 816 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.light.replace("#", "%23") +
|
||||
"' points='1203 546 1552 900 876 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.main.replace("#", "%23") +
|
||||
"' points='1203 546 1552 900 1162 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.primary.dark.replace("#", "%23") +
|
||||
"' points='641 695 886 900 367 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.primary.main.replace("#", "%23") +
|
||||
"' points='587 900 641 695 886 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.light.replace("#", "%23") +
|
||||
"' points='1710 900 1401 632 1096 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.dark.replace("#", "%23") +
|
||||
"' points='1710 900 1401 632 1365 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.main.replace("#", "%23") +
|
||||
"' points='1210 900 971 687 725 900'/%3E%3Cpolygon fill='" +
|
||||
theme.palette.secondary.dark.replace("#", "%23") +
|
||||
"' points='943 900 1210 900 971 687'/%3E%3C/svg%3E\")",
|
||||
backgroundSize: "cover",
|
||||
},
|
||||
avatar: {
|
||||
display: "block",
|
||||
width: "70px",
|
||||
height: "70px",
|
||||
border: " 2px solid #fff",
|
||||
borderRadius: "50%",
|
||||
overflow: "hidden",
|
||||
boxShadow:
|
||||
"0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12)",
|
||||
},
|
||||
avatarImg: {
|
||||
width: "66px",
|
||||
height: "66px",
|
||||
},
|
||||
nickName: {
|
||||
color: "#fff",
|
||||
marginTop: "15px",
|
||||
fontSize: "17px",
|
||||
},
|
||||
flexAvatar: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
groupName: {
|
||||
color: "#ffffff",
|
||||
opacity: "0.54",
|
||||
},
|
||||
storageCircle: {
|
||||
width: "200px",
|
||||
},
|
||||
});
|
||||
|
||||
class UserInfoCompoment extends Component {
|
||||
showUserInfo = (e) => {
|
||||
this.props.setUserPopover(e.currentTarget);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, t } = this.props;
|
||||
const isLogin = Auth.Check(this.props.isLogin);
|
||||
const user = Auth.GetUser(this.props.isLogin);
|
||||
|
||||
return (
|
||||
<div className={classes.userNav}>
|
||||
<div className={classes.flexAvatar}>
|
||||
{/* eslint-disable-next-line */}
|
||||
<a onClick={this.showUserInfo} className={classes.avatar}>
|
||||
{isLogin && (
|
||||
<Avatar
|
||||
src={"/api/v3/user/avatar/" + user.id + "/l"}
|
||||
className={classes.avatarImg}
|
||||
/>
|
||||
)}
|
||||
{!isLogin && (
|
||||
<Avatar
|
||||
src={"/api/v3/user/avatar/0/l"}
|
||||
className={classes.avatarImg}
|
||||
/>
|
||||
)}
|
||||
</a>
|
||||
<DarkModeSwitcher position="left" />
|
||||
</div>
|
||||
<div className={classes.storageCircle}>
|
||||
<Typography
|
||||
className={classes.nickName}
|
||||
component="h2"
|
||||
noWrap
|
||||
>
|
||||
{isLogin ? user.nickname : t("navbar.notLoginIn")}
|
||||
</Typography>
|
||||
<Typography
|
||||
className={classes.groupName}
|
||||
component="h2"
|
||||
color="textSecondary"
|
||||
noWrap
|
||||
>
|
||||
{isLogin ? user.group.name : t("navbar.visitor")}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserInfoCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const UserInfo = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(withTranslation()(UserInfoCompoment)));
|
||||
|
||||
export default UserInfo;
|
Reference in New Issue
Block a user