mirror of
https://github.com/mickael-kerjean/filestash
synced 2026-01-03 06:17:35 +01:00
improvement (UI): hover and select effect on files and breadcrumb improvements
This commit is contained in:
parent
c964c274a8
commit
acf243bd07
4 changed files with 74 additions and 39 deletions
|
|
@ -11,7 +11,7 @@ export class BreadCrumb extends React.Component {
|
|||
this.state = {
|
||||
path: this._formatPath(props.path)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props){
|
||||
this.setState({path: this._formatPath(props.path)});
|
||||
|
|
@ -33,12 +33,12 @@ export class BreadCrumb extends React.Component {
|
|||
});
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
||||
render(Element) {
|
||||
const Path = Element? Element : PathElement;
|
||||
return (
|
||||
<div>
|
||||
<BreadCrumbContainer className={this.props.className}>
|
||||
<BreadCrumbContainer className={this.props.className+' no-select'}>
|
||||
<Logout />
|
||||
{
|
||||
this.state.path.map((path, index) => {
|
||||
|
|
@ -63,8 +63,8 @@ BreadCrumb.propTypes = {
|
|||
|
||||
|
||||
const BreadCrumbContainer = (props) => {
|
||||
let style1 = {background: 'white', margin: '0 0 0px 0', padding: '6px 0', boxShadow: '0 4px 5px 0 rgba(0,0,0,0.14), 0 1px 10px 0 rgba(0,0,0,0.12), 0 2px 4px -1px rgba(0,0,0,0.2)', zIndex: '1000', position: 'relative'};
|
||||
let style2 = {margin: '0 auto', width: '95%', maxWidth: '800px', padding: '0'};
|
||||
let style1 = {background: theme.component.breadcrumb.bg, margin: '0 0 0px 0', padding: '6px 0', boxShadow: '0 4px 5px 0 rgba(0,0,0,0.14), 0 1px 10px 0 rgba(0,0,0,0.12), 0 2px 4px -1px rgba(0,0,0,0.2)', zIndex: '1000', position: 'relative'};
|
||||
let style2 = {margin: '0 auto', width: '95%', maxWidth: '800px', padding: '0', color: theme.component.breadcrumb.color};
|
||||
return (
|
||||
<div className={props.className} style={style1}>
|
||||
<ul style={style2}>
|
||||
|
|
@ -76,9 +76,8 @@ const BreadCrumbContainer = (props) => {
|
|||
const Logout = (props) => {
|
||||
let style = {
|
||||
float: 'right',
|
||||
fontSize: '17px',
|
||||
display: 'inline-block',
|
||||
padding: '6px 0px 6px 6px',
|
||||
padding: '5px 0px 5px 5px',
|
||||
margin: '0 0px'
|
||||
}
|
||||
return (
|
||||
|
|
@ -109,8 +108,8 @@ const Saving = (props) => {
|
|||
|
||||
const Separator = (props) => {
|
||||
return (
|
||||
<NgIf cond={props.isLast === false} style={{display: 'inline', fontFamily: 'monospace', color: '#aaaaaa'}}>
|
||||
>
|
||||
<NgIf cond={props.isLast === false} style={{position: 'relative', top: '3px', display: 'inline'}}>
|
||||
<img width="16" height="16" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAA30lEQVQ4T63T7Q2CMBAG4OuVPdQNcAPdBCYwDdclCAQ3ACfRDXQDZQMHgNRcAoYApfWjv0jIPX3b3gn4wxJjI03TUAhRBkGwV0o9ffaYIEVRrJumuQHA3ReaILxzl+bCkNZ660ozi/QQIl4BoCKieAmyIlyU53lkjCld0CIyhIwxSmt9nEvkRLgoyzIuPggh4iRJqjHkhXTQAwBWUsqNUoq/38sL+TlJf7lf38ngdU5EFNme2adPFgGGrR2LiGcAqIko/LhjeXbatuVOraWUO58hnJ1iRKx8AetxXPHH/1+y62USursaSgAAAABJRU5ErkJggg=="/>
|
||||
</NgIf>
|
||||
);
|
||||
}
|
||||
|
|
@ -120,6 +119,7 @@ const Separator = (props) => {
|
|||
export class PathElementWrapper extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {hover: false};
|
||||
}
|
||||
|
||||
onClick(){
|
||||
|
|
@ -128,24 +128,38 @@ export class PathElementWrapper extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
toggleHover(shouldHover){
|
||||
if(('ontouchstart' in window) === false){
|
||||
this.setState({hover: shouldHover})
|
||||
}
|
||||
}
|
||||
|
||||
limitSize(str){
|
||||
if(str.length > 30){
|
||||
return str.substring(0,23)+'...'
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
render(){
|
||||
let style = {
|
||||
cursor: 'pointer',
|
||||
fontSize: '17px',
|
||||
cursor: this.props.isLast ? '' : 'pointer',
|
||||
background: this.state.hover && this.props.isLast !== true? theme.effects.hover : 'inherit',
|
||||
borderRadius: '1px',
|
||||
fontSize: '18px',
|
||||
display: 'inline-block',
|
||||
padding: '5px 3px',
|
||||
margin: '0 4px',
|
||||
padding: '4px 5px',
|
||||
fontWeight: this.props.isLast ? '100': ''
|
||||
};
|
||||
if(this.props.highlight === true){
|
||||
style.background = to_rgba(theme.colors.primary, 0.5);
|
||||
style.background = theme.effects.selected;
|
||||
style.border = '2px solid '+theme.colors.primary;
|
||||
style.borderRadius = '2px';
|
||||
style.padding = '3px 20px';
|
||||
style.padding = '2px 20px';
|
||||
}
|
||||
return (
|
||||
<li onClick={this.onClick.bind(this)} style={style}>
|
||||
{this.props.path.label}
|
||||
<li onClick={this.onClick.bind(this)} style={style} onMouseEnter={this.toggleHover.bind(this, true)} onMouseLeave={this.toggleHover.bind(this, false)}>
|
||||
{this.limitSize(this.props.path.label)}
|
||||
<Saving isLast={this.props.isLast} needSaving={this.props.needSaving} isSaving={false} />
|
||||
</li>
|
||||
);
|
||||
|
|
@ -161,7 +175,7 @@ export class PathElement extends PathElementWrapper {
|
|||
|
||||
render(highlight = false){
|
||||
return (
|
||||
<div style={{display: 'inline-block'}}>
|
||||
<div style={{display: 'inline-block', color: this.props.isLast? theme.component.breadcrumb.last : 'inherit'}}>
|
||||
<PathElementWrapper highlight={highlight} {...this.props} />
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card, NgIf, Icon, pathBuilder, theme, to_rgba } from '../../utilities';
|
||||
import { Card, NgIf, Icon, pathBuilder, theme } from '../../utilities';
|
||||
import { EventEmitter } from '../../data';
|
||||
import { DragSource, DropTarget } from 'react-dnd';
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ export class ExistingThing extends React.Component {
|
|||
message: props.file.message || null,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
onSelect(){
|
||||
if(this.state.icon !== 'loading'){
|
||||
|
|
@ -127,7 +127,7 @@ export class ExistingThing extends React.Component {
|
|||
this.setState({icon: 'error', message: err.message, filename: oldFilename});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onDelete(filename){
|
||||
let toConfirm = this.props.file.name.length > 16? this.props.file.name.substring(0, 10).toLowerCase() : this.props.file.name;
|
||||
let answer = prompt('Confirm by tapping "'+toConfirm+'"');
|
||||
|
|
@ -151,20 +151,24 @@ export class ExistingThing extends React.Component {
|
|||
const { connectDragSource, connectDropFile, connectDropNativeFile } = this.props;
|
||||
let dragStyle = {whiteSpace: 'nowrap'};
|
||||
if(this.props.isDragging) { dragStyle.opacity = 0.15; }
|
||||
|
||||
if(this.state.hover === true){
|
||||
dragStyle.background = theme.effects.hover;
|
||||
}
|
||||
if((this.props.fileIsOver && this.props.canDropFile) || (this.props.nativeFileIsOver && this.props.canDropNativeFile)) {
|
||||
dragStyle.background = to_rgba(theme.colors.primary, 0.5);
|
||||
dragStyle.border = '2px solid '+theme.colors.primary;
|
||||
dragStyle.background = theme.effects.selected;
|
||||
}
|
||||
|
||||
return connectDragSource(connectDropNativeFile(connectDropFile(
|
||||
<div>
|
||||
<NgIf cond={this.state.appear}>
|
||||
<Card onClick={this.onSelect.bind(this)} onMouseEnter={() => this.setState({hover: true})} onMouseLeave={() => this.setState({hover: false})} style={dragStyle}>
|
||||
<DateTime show={this.state.hover !== true || this.state.icon === 'loading'} timestamp={this.props.file.time}/>
|
||||
<DateTime show={this.state.hover !== true || this.state.icon === 'loading'} timestamp={this.props.file.time} background={dragStyle.background}/>
|
||||
<Updater filename={this.state.filename}
|
||||
icon={this.props.file.virtual? this.props.file.icon : this.state.icon}
|
||||
can_move={this.props.file.can_move !== false}
|
||||
can_delete={this.props.file.can_delete !== false}
|
||||
background={dragStyle.background}
|
||||
show={this.state.hover === true && this.state.icon !== 'loading' && !('ontouchstart' in window)}
|
||||
onRename={this.onRename.bind(this)}
|
||||
onDelete={this.onDelete.bind(this)} />
|
||||
|
|
@ -215,7 +219,7 @@ class Updater extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
preventSelect(e){
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
|
@ -223,7 +227,7 @@ class Updater extends React.Component {
|
|||
render(){
|
||||
const style = {
|
||||
inline: {display: 'inline'},
|
||||
el: {float: 'right', color: '#6f6f6f', height: '22px', background: 'white', margin: '0 -10px', padding: '0 10px', position: 'relative'},
|
||||
el: {float: 'right', color: '#6f6f6f', height: '22px', background: this.props.background || 'white', margin: '0 -10px', padding: '0 10px', position: 'relative'},
|
||||
margin: {marginRight: '10px'}
|
||||
}
|
||||
return (
|
||||
|
|
@ -265,7 +269,7 @@ const DateTime = (props) => {
|
|||
}
|
||||
}
|
||||
|
||||
const style = {float: 'right', color: '#6f6f6f', lineHeight: '25px', background: 'white', margin: '0 -10px', padding: '0 10px', position: 'relative'};
|
||||
const style = {float: 'right', color: '#6f6f6f', lineHeight: '25px', background: props.background || 'white', margin: '0 -10px', padding: '0 10px', position: 'relative'};
|
||||
|
||||
return (
|
||||
<NgIf cond={props.show} style={style}>
|
||||
|
|
@ -289,7 +293,7 @@ const FileSize = (props) => {
|
|||
}
|
||||
}
|
||||
const style = {color: '#6f6f6f', fontSize: '0.85em'};
|
||||
|
||||
|
||||
return (
|
||||
<NgIf cond={props.type === 'file'} style={{display: 'inline-block'}}>
|
||||
<span style={style}>({displaySize(props.size)})</span>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,33 @@
|
|||
export const theme = {
|
||||
colors: {
|
||||
primary: '#9AD1ED',
|
||||
secondary: '#466372',
|
||||
emphasis: '#375160',
|
||||
error: '#ff0000',
|
||||
text: '#6f6f6f'
|
||||
},
|
||||
spacing: {
|
||||
const palette = {
|
||||
primary: '#9AD1ED',
|
||||
secondary: '#466372',
|
||||
emphasis: '#375160',
|
||||
error: '#ff0000',
|
||||
text: '#6f6f6f'
|
||||
}
|
||||
|
||||
|
||||
let _theme = {
|
||||
colors: palette,
|
||||
space: {
|
||||
normal: '10px',
|
||||
big: '20px'
|
||||
},
|
||||
effects: {
|
||||
hover: '#f5f5f5',
|
||||
selected: '#c5e2f1',
|
||||
shadow_small: 'rgba(0, 0, 0, 0.14) 2px 2px 2px 0px',
|
||||
shadow: 'rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px',
|
||||
shadow_large: 'rgba(158, 163, 172, 0.3) 0px 19px 60px, rgba(158, 163, 172, 0.22) 0px 15px 20px'
|
||||
},
|
||||
component: {
|
||||
breadcrumb: {bg: 'white', color: rgba(palette.text, 0.8), last: palette.text}
|
||||
}
|
||||
}
|
||||
|
||||
export const theme = _theme;
|
||||
|
||||
|
||||
export const to_rgba = function(color, alpha){
|
||||
function rgba(color, alpha){
|
||||
const bigint = parseInt(color.replace(/^\#/, ''), 16);
|
||||
const r = (bigint >> 16) & 255;
|
||||
const g = (bigint >> 8) & 255;
|
||||
|
|
@ -27,3 +35,4 @@ export const to_rgba = function(color, alpha){
|
|||
|
||||
return "rgba("+r+","+g+","+b+","+alpha+")";
|
||||
}
|
||||
export const to_rgba = rgba;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,14 @@ select::-ms-expand {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.no-select {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
.drag-drop{
|
||||
|
|
|
|||
Loading…
Reference in a new issue