mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
新增: 目录列表增加相册展示功能(大概时间、大概地点) (#62)
* 新增: 目录列表增加相册展示功能(大概时间、大概地点) * fix:修复合并遗留bug * update SubActions.js
This commit is contained in:
parent
ff0e2627dc
commit
29b8684976
|
|
@ -52,7 +52,8 @@
|
|||
"material-ui-toggle-icon": "^1.1.1",
|
||||
"mdi-material-ui": "^6.9.0",
|
||||
"mini-css-extract-plugin": "0.8.0",
|
||||
"monaco-editor-webpack-plugin": "^1.9.0",
|
||||
"monaco-editor": "0.19.0",
|
||||
"monaco-editor-webpack-plugin": "1.8.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||
"pnp-webpack-plugin": "1.5.0",
|
||||
"postcss-flexbugs-fixes": "4.1.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
import React from "react";
|
||||
import {makeStyles} from "@material-ui/core";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
container: {
|
||||
padding: "7px"
|
||||
},
|
||||
fixFlex: {
|
||||
minWidth: 0
|
||||
},
|
||||
dragging: {
|
||||
opacity: 0.4
|
||||
},
|
||||
dateSubTitle: {
|
||||
fontSize:"16px",
|
||||
padding:"16px 0 16px 6px"
|
||||
},
|
||||
dateSubTitleDate: {
|
||||
color:'#000'
|
||||
},
|
||||
dateSubTitleLocation: {
|
||||
color:"#6b6b6b"
|
||||
}
|
||||
}));
|
||||
|
||||
export default function AlbumSubTitle(props) {
|
||||
const dateText = props.date;
|
||||
const locationText = props.location
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className={classes.dateSubTitle} >
|
||||
<div className={classes.dateSubTitleDate}>{dateText} <small className={classes.dateSubTitleLocation}>{locationText}</small></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -15,23 +15,18 @@ import SadIcon from "@material-ui/icons/SentimentVeryDissatisfied";
|
|||
import EmptyIcon from "@material-ui/icons/Unarchive";
|
||||
import classNames from "classnames";
|
||||
import PropTypes from "prop-types";
|
||||
import React, { Component } from "react";
|
||||
import { configure, GlobalHotKeys } from "react-hotkeys";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import {
|
||||
changeContextMenu,
|
||||
navigateTo,
|
||||
navigateUp,
|
||||
openRemoveDialog,
|
||||
setSelectedTarget
|
||||
} from "../../actions/index";
|
||||
import React, {Component} from "react";
|
||||
import {configure, GlobalHotKeys} from "react-hotkeys";
|
||||
import {connect} from "react-redux";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import {changeContextMenu, navigateTo, navigateUp, openRemoveDialog, setSelectedTarget} from "../../actions/index";
|
||||
import explorer from "../../redux/explorer";
|
||||
import { isMac } from "../../utils";
|
||||
import {isMac} from "../../utils";
|
||||
import pathHelper from "../../utils/page";
|
||||
import ContextMenu from "./ContextMenu";
|
||||
import ImgPreivew from "./ImgPreview";
|
||||
import ObjectIcon from "./ObjectIcon";
|
||||
import PhotosAlbum from "./PhotosAlbum";
|
||||
|
||||
const styles = theme => ({
|
||||
paper: {
|
||||
|
|
@ -130,6 +125,10 @@ const styles = theme => ({
|
|||
position: "absolute",
|
||||
top: 20,
|
||||
width: 1
|
||||
},
|
||||
photosGroupSection: {
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -354,6 +353,57 @@ class ExplorerCompoment extends Component {
|
|||
</Table>
|
||||
);
|
||||
|
||||
const photoAlbumView = (
|
||||
<div className={classes.flexFix}>
|
||||
{this.props.dirList.length !== 0 && (
|
||||
<>
|
||||
<Typography
|
||||
data-clickAway={"true"}
|
||||
variant="body2"
|
||||
className={classes.typeHeader}
|
||||
>
|
||||
文件夹
|
||||
</Typography>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.dirList.map((value, index) => (
|
||||
<Grid
|
||||
key={value.id}
|
||||
item
|
||||
xs={6}
|
||||
md={3}
|
||||
sm={4}
|
||||
lg={2}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
file={value}
|
||||
index={index}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
{this.props.fileList.length !== 0 && (
|
||||
<>
|
||||
<Typography
|
||||
data-clickAway={"true"}
|
||||
variant="body2"
|
||||
className={classes.typeHeader}
|
||||
>
|
||||
照片
|
||||
</Typography>
|
||||
<PhotosAlbum fileList={this.props.fileList}></PhotosAlbum>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const normalView = (
|
||||
<div className={classes.flexFix}>
|
||||
{this.props.dirList.length !== 0 && (
|
||||
|
|
@ -400,11 +450,13 @@ class ExplorerCompoment extends Component {
|
|||
文件
|
||||
</Typography>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
className={classes.photosGroupSection}
|
||||
>
|
||||
|
||||
{this.props.fileList.map((value, index) => (
|
||||
<Grid
|
||||
key={value.id}
|
||||
|
|
@ -415,9 +467,9 @@ class ExplorerCompoment extends Component {
|
|||
lg={2}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
index={index}
|
||||
file={value}
|
||||
key={value.id}
|
||||
index={index}
|
||||
file={value}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
|
|
@ -426,7 +478,7 @@ class ExplorerCompoment extends Component {
|
|||
)}
|
||||
</div>
|
||||
);
|
||||
const view = this.props.viewMethod === "list" ? listView : normalView;
|
||||
const view = this.props.viewMethod === "list" ? listView : this.props.viewMethod == "photoAlbum" ? photoAlbumView : normalView;
|
||||
return (
|
||||
<div
|
||||
onContextMenu={this.contextMenu}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ import {
|
|||
import { lighten } from "@material-ui/core/styles";
|
||||
import classNames from "classnames";
|
||||
import PropTypes from "prop-types";
|
||||
import React, { Component } from "react";
|
||||
import React, {Component} from "react";
|
||||
import ContentLoader from "react-content-loader";
|
||||
import { LazyLoadImage } from "react-lazy-load-image-component";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router";
|
||||
import { baseURL } from "../../middleware/Api";
|
||||
import {LazyLoadImage} from "react-lazy-load-image-component";
|
||||
import {connect} from "react-redux";
|
||||
import {withRouter} from "react-router";
|
||||
import {baseURL} from "../../middleware/Api";
|
||||
import pathHelper from "../../utils/page";
|
||||
import TypeIcon from "./TypeIcon";
|
||||
import CheckCircleRoundedIcon from "@material-ui/icons/CheckCircleRounded";
|
||||
|
|
@ -35,6 +35,19 @@ const styles = theme => ({
|
|||
theme.palette.type === "dark" ? 0.3 : 0.18
|
||||
)
|
||||
},
|
||||
picSelected: {
|
||||
"&:hover": {
|
||||
border: "1px solid #d0d0d0"
|
||||
},
|
||||
// backgroundColor:
|
||||
// theme.palette.type === "dark"
|
||||
// ? "#fff"
|
||||
// : lighten(theme.palette.primary.main, 0.8),
|
||||
|
||||
padding: "8px",
|
||||
border: "solid 1px #d0d0d0",
|
||||
backgroundColor: "#3f51b58f",
|
||||
},
|
||||
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
|
|
@ -114,9 +127,22 @@ const styles = theme => ({
|
|||
width: "100%"
|
||||
},
|
||||
shareFix: {
|
||||
marginLeft: "20px"
|
||||
marginLeft: "20px" },
|
||||
hiddenTitle:{
|
||||
display: "none"
|
||||
},
|
||||
checkIcon: {
|
||||
resetPicParentContainer:{
|
||||
borderRadius: 0,
|
||||
height: "auto"
|
||||
},
|
||||
resetPicStyle: {
|
||||
position: "absolute",
|
||||
top:"0px",
|
||||
left:"0px",
|
||||
width:"100%",
|
||||
verticalAlign: "bottom"
|
||||
},
|
||||
checkIcon: {
|
||||
color: theme.palette.primary.main
|
||||
}
|
||||
});
|
||||
|
|
@ -153,14 +179,26 @@ class FileIconCompoment extends Component {
|
|||
);
|
||||
const isMobile = statusHelper.isMobile();
|
||||
|
||||
const isPhotos = this.props.file.pic !== "" &&
|
||||
!this.state.showPicIcon &&
|
||||
this.props.file.pic !== " " &&
|
||||
this.props.file.pic !== "null,null";
|
||||
|
||||
const viewMethod = this.props.viewMethod;
|
||||
const picArr = this.props.file.pic.split(',')
|
||||
const picPaddingBottom = picArr.length == 2 ? parseInt(picArr[1]) / parseInt(picArr[0]) * 100 : 0;
|
||||
const showPhotoAlbum = (viewMethod == "photoAlbum" && picPaddingBottom > 0) ? true : false;
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<div
|
||||
className={classNames({[classes.container]: !showPhotoAlbum})}
|
||||
>
|
||||
<ButtonBase
|
||||
focusRipple
|
||||
className={classNames(
|
||||
{
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected
|
||||
[classes.selected]: !showPhotoAlbum && isSelected,
|
||||
[classes.notSelected]:!showPhotoAlbum && !isSelected
|
||||
},
|
||||
classes.button
|
||||
)}
|
||||
|
|
@ -169,13 +207,22 @@ class FileIconCompoment extends Component {
|
|||
!this.state.showPicIcon &&
|
||||
this.props.file.pic !== " " &&
|
||||
this.props.file.pic !== "null,null" && (
|
||||
<div className={classes.preview}>
|
||||
<div className={classNames(classes.preview,{[classes.resetPicParentContainer]: showPhotoAlbum})} >
|
||||
{showPhotoAlbum && (
|
||||
<i style={{display: "block", paddingBottom:picPaddingBottom+"%"}}></i>
|
||||
)}
|
||||
<LazyLoadImage
|
||||
className={classNames({
|
||||
[classes.hide]: this.state.loading,
|
||||
[classes.picPreview]: !this.state
|
||||
.loading
|
||||
})}
|
||||
},
|
||||
{
|
||||
[classes.picSelected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
[classes.resetPicStyle]: showPhotoAlbum
|
||||
}
|
||||
)}
|
||||
src={
|
||||
baseURL +
|
||||
(isSharePage
|
||||
|
|
@ -234,7 +281,7 @@ class FileIconCompoment extends Component {
|
|||
this.state.showPicIcon ||
|
||||
this.props.file.pic === " " ||
|
||||
this.props.file.pic === "null,null") && <Divider />}
|
||||
<div className={classes.fileInfo}>
|
||||
<div className={classNames(classes.fileInfo, {[classes.hiddenTitle]:showPhotoAlbum && isPhotos})}>
|
||||
{!this.props.share && (
|
||||
<div
|
||||
onClick={this.props.onIconClick}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ export default function SubActions({ isSmall, share, inherit }) {
|
|||
? "list"
|
||||
: viewMethod === "list"
|
||||
? "smallIcon"
|
||||
: viewMethod === "smallIcon"
|
||||
? "photoAlbum"
|
||||
: "icon";
|
||||
Auth.SetPreference("view_method", newMethod);
|
||||
OpenLoadingDialog(newMethod);
|
||||
|
|
@ -100,6 +102,15 @@ export default function SubActions({ isSmall, share, inherit }) {
|
|||
<ViewModuleIcon fontSize={isSmall ? "small" : "default"} />
|
||||
</IconButton>
|
||||
)}
|
||||
{viewMethod === "photoAlbum" && (
|
||||
<IconButton
|
||||
title="相册模式"
|
||||
className={classes.sideButton}
|
||||
onClick={toggleViewMethod}
|
||||
>
|
||||
<ViewModuleIcon fontSize={isSmall ? "small" : "default"} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
<IconButton
|
||||
title="排序方式"
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ const useStyles = makeStyles(() => ({
|
|||
},
|
||||
dragging: {
|
||||
opacity: 0.4
|
||||
},
|
||||
clearPadding:{
|
||||
padding: 0
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -220,13 +223,13 @@ export default function ObjectIcon(props) {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={drag}
|
||||
className={classNames({
|
||||
[classes.container]: viewMethod !== "list",
|
||||
[classes.dragging]: isDragging
|
||||
[classes.dragging]: isDragging,
|
||||
[classes.clearPadding]: viewMethod === "photoAlbum" && props.file.type === "file"
|
||||
})}
|
||||
>
|
||||
<div
|
||||
|
|
@ -255,6 +258,9 @@ export default function ObjectIcon(props) {
|
|||
file={props.file}
|
||||
/>
|
||||
)}
|
||||
{props.file.type === "file" && viewMethod === "photoAlbum" && (
|
||||
<FileIcon file={props.file} viewMethod={viewMethod}/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
import React from "react";
|
||||
import {Grid, makeStyles} from "@material-ui/core";
|
||||
import AlbumSubTitle from "./AlbumSubTitle";
|
||||
import ObjectIcon from "./ObjectIcon";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
container: {
|
||||
padding: "7px"
|
||||
},
|
||||
fixFlex: {
|
||||
minWidth: 0
|
||||
},
|
||||
dragging: {
|
||||
opacity: 0.4
|
||||
},
|
||||
dateSubTitle: {
|
||||
fontSize:"16px",
|
||||
padding:"16px 0 16px 6px"
|
||||
},
|
||||
dateSubTitleDate: {
|
||||
color:'#000'
|
||||
},
|
||||
dateSubTitleLocation: {
|
||||
color:"#6b6b6b"
|
||||
},
|
||||
fileContainer: {
|
||||
marginBottom: "5px",
|
||||
marginRight: "5px",
|
||||
borderRadius: 0,
|
||||
height: "auto",
|
||||
position: "relative"
|
||||
}
|
||||
}));
|
||||
|
||||
export default function PhotosAlbum(props) {
|
||||
const classes = useStyles()
|
||||
const files = props.fileList
|
||||
const fileGroups = {}
|
||||
const dateOrder = []
|
||||
let index = 0
|
||||
|
||||
files.map(file => {
|
||||
const dateObj = new Date(file.exif_date_time !== "" ? file.exif_date_time : file.date)
|
||||
const dateDay = dateObj.getFullYear() + "年" + (dateObj.getMonth() + 1) + "月" + dateObj.getDate()+"日"
|
||||
if(!Object.prototype.hasOwnProperty.call(fileGroups, dateDay)){
|
||||
let location = ""
|
||||
if(file.exit_address !== ""){
|
||||
try{
|
||||
const exifAddress = JSON.parse(file.exit_address)
|
||||
location = exifAddress.address
|
||||
}catch (e){
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
fileGroups[dateDay] = {
|
||||
date:file.date,
|
||||
location: location,
|
||||
files:[]
|
||||
}
|
||||
dateOrder.push(dateDay)
|
||||
}
|
||||
file.index = index
|
||||
file.flexWidth = 0
|
||||
file.flexGrow = 0
|
||||
file.height = 0
|
||||
const picSize = file.pic.split(',')
|
||||
if(picSize.length == 2){
|
||||
file.flexWidth = parseInt(picSize[0])*200/parseInt(picSize[1])
|
||||
file.flexGrow = parseInt(picSize[0])*200/parseInt(picSize[1])
|
||||
}
|
||||
fileGroups[dateDay].files.push(file)
|
||||
if(file.exit_address !== "" && fileGroups[dateDay].location === ""){
|
||||
try{
|
||||
const exifAddress = JSON.parse(file.exit_address)
|
||||
fileGroups[dateDay].location = exifAddress.address
|
||||
}catch (e){
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
index = index + 1
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{dateOrder.map((dateDay) => (
|
||||
<>
|
||||
<AlbumSubTitle date={dateDay} location={fileGroups[dateDay].location}></AlbumSubTitle>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
style={{display: "flex",flexWrap: "wrap"}}
|
||||
className={classes.photosGroupSection}
|
||||
>
|
||||
|
||||
{
|
||||
fileGroups[dateDay].files.map((value) => (
|
||||
<div
|
||||
key={value.id}
|
||||
className={classes.fileContainer}
|
||||
style={{ width:value.flexWidth >0 ? value.flexWidth+"px":'auto',flexGrow:value.flexGrow}}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
index={value.index}
|
||||
file={value}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<div style={{content: "",flexGrow: "999999999"}}></div>
|
||||
</Grid>
|
||||
</>
|
||||
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue