Material UI: finish Create Torrent

This commit is contained in:
DC
2016-08-31 03:35:27 -07:00
parent b6bdeab50b
commit f8cc155650
3 changed files with 107 additions and 82 deletions

View File

@@ -39,14 +39,11 @@ class ShowMore extends React.Component {
? this.props.hideLabel ? this.props.hideLabel
: this.props.showLabel : this.props.showLabel
return ( return (
<div <div style={this.props.style}>
style={this.props.style}
>
{this.state.expanded ? this.props.children : null} {this.state.expanded ? this.props.children : null}
<FlatButton <FlatButton
onClick={this.handleClick} onClick={this.handleClick}
label={label} label={label} />
/>
</div> </div>
) )
} }

View File

@@ -8,6 +8,7 @@ const {dispatch, dispatcher} = require('../lib/dispatcher')
const FlatButton = require('material-ui/FlatButton').default const FlatButton = require('material-ui/FlatButton').default
const RaisedButton = require('material-ui/RaisedButton').default const RaisedButton = require('material-ui/RaisedButton').default
const TextField = require('material-ui/TextField').default const TextField = require('material-ui/TextField').default
const Checkbox = require('material-ui/Checkbox').default
const CreateTorrentErrorPage = require('../components/create-torrent-error-page') const CreateTorrentErrorPage = require('../components/create-torrent-error-page')
const Heading = require('../components/Heading') const Heading = require('../components/Heading')
@@ -20,27 +21,20 @@ class CreateTorrentPage extends React.Component {
var state = this.props.state var state = this.props.state
var info = state.location.current() var info = state.location.current()
// Preprocess: exclude .DS_Store and other dotfiles
var files = info.files
.filter((f) => !f.name.startsWith('.'))
.map((f) => ({name: f.name, path: f.path, size: f.size}))
if (files.length === 0) return (<CreateTorrentErrorPage state={state} />)
// First, extract the base folder that the files are all in // First, extract the base folder that the files are all in
var pathPrefix = info.folderPath var pathPrefix = info.folderPath
if (!pathPrefix) { if (!pathPrefix) {
pathPrefix = files.map((x) => x.path).reduce(findCommonPrefix) pathPrefix = info.files.map((x) => x.path).reduce(findCommonPrefix)
if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) { if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) {
pathPrefix = path.dirname(pathPrefix) pathPrefix = path.dirname(pathPrefix)
} }
} }
// Sanity check: show the number of files and total size // Then, exclude .DS_Store and other dotfiles
var numFiles = files.length var files = info.files
var totalBytes = files .filter((f) => !containsDots(f.path, pathPrefix))
.map((f) => f.size) .map((f) => ({name: f.name, path: f.path, size: f.size}))
.reduce((a, b) => a + b, 0) if (files.length === 0) return (<CreateTorrentErrorPage state={state} />)
var torrentInfo = `${numFiles} files, ${prettyBytes(totalBytes)}`
// Then, use the name of the base folder (or sole file, for a single file torrent) // Then, use the name of the base folder (or sole file, for a single file torrent)
// as the default name. Show all files relative to the base folder. // as the default name. Show all files relative to the base folder.
@@ -54,34 +48,32 @@ class CreateTorrentPage extends React.Component {
defaultName = path.basename(pathPrefix) defaultName = path.basename(pathPrefix)
basePath = path.dirname(pathPrefix) basePath = path.dirname(pathPrefix)
} }
var maxFileElems = 100
var fileElems = files.slice(0, maxFileElems).map(function (file, i) { // Default trackers
var relativePath = files.length === 0
? file.name
: path.relative(pathPrefix, file.path)
return (<div key={i}>{relativePath}</div>)
})
if (files.length > maxFileElems) {
fileElems.push(<div key='more'>+ {maxFileElems - files.length} more</div>)
}
var trackers = createTorrent.announceList.join('\n') var trackers = createTorrent.announceList.join('\n')
this.state = { this.state = {
comment: '',
isPrivate: false,
pathPrefix,
basePath, basePath,
defaultName, defaultName,
fileElems, files,
torrentInfo,
trackers trackers
} }
// Create React event handlers only once
this.setIsPrivate = (_, isPrivate) => this.setState({isPrivate})
this.setComment = (_, comment) => this.setState({comment})
this.setTrackers = (_, trackers) => this.setState({trackers})
this.handleSubmit = () => this.handleSubmit
} }
handleSubmit () { handleSubmit () {
var announceList = document.querySelector('.torrent-trackers').value var announceList = this.state.trackers
.split('\n') .split('\n')
.map((s) => s.trim()) .map((s) => s.trim())
.filter((s) => s !== '') .filter((s) => s !== '')
var isPrivate = document.querySelector('.torrent-is-private').checked
var comment = document.querySelector('.torrent-comment').value.trim()
var options = { var options = {
// We can't let the user choose their own name if we want WebTorrent // We can't let the user choose their own name if we want WebTorrent
// to use the files in place rather than creating a new folder. // to use the files in place rather than creating a new folder.
@@ -89,55 +81,37 @@ class CreateTorrentPage extends React.Component {
path: this.state.basePath, path: this.state.basePath,
files: this.state.files, files: this.state.files,
announce: announceList, announce: announceList,
private: isPrivate, private: this.state.isPrivate,
comment: comment comment: this.state.comment.trim()
} }
dispatch('createTorrent', options) dispatch('createTorrent', options)
} }
render () { render () {
var files = this.state.files
// Sanity check: show the number of files and total size
var numFiles = files.length
var totalBytes = files
.map((f) => f.size)
.reduce((a, b) => a + b, 0)
var torrentInfo = `${numFiles} files, ${prettyBytes(totalBytes)}`
return ( return (
<div className='create-torrent'> <div className='create-torrent'>
<Heading level={1}> <Heading level={1}>Create torrent {this.state.defaultName}</Heading>
Create torrent "{this.state.defaultName}" <div className='torrent-info'>{torrentInfo}</div>
</Heading>
<div className='torrent-info'>
{this.state.torrentInfo}
</div>
<div className='torrent-attribute'> <div className='torrent-attribute'>
<label>Path:</label> <label>Path:</label>
<div className='torrent-attribute'>{this.state.pathPrefix}</div> <div>{this.state.pathPrefix}</div>
</div> </div>
<ShowMore <ShowMore
style={{ style={{
marginBottom: 10 marginBottom: 10
}} }}
hideLabel='Hide advanced settings...' hideLabel='Hide advanced settings...'
showLabel='Show advanced settings...' showLabel='Show advanced settings...' >
> {this.renderAdvanced()}
<div key='advanced' className='create-torrent-advanced'>
<div key='private' className='torrent-attribute'>
<label>Private:</label>
<input type='checkbox' className='torrent-is-private' value='torrent-is-private' />
</div>
<Heading level={2}>Trackers:</Heading>
<TextField
className='torrent-trackers'
hintText='Tracker'
multiLine
rows={2}
rowsMax={10}
defaultValue={this.state.trackers}
/>
<div key='comment' className='torrent-attribute'>
<label>Comment:</label>
<textarea className='torrent-attribute torrent-comment' />
</div>
<div key='files' className='torrent-attribute'>
<label>Files:</label>
<div>{this.state.fileElems}</div>
</div>
</div>
</ShowMore> </ShowMore>
<div className='float-right'> <div className='float-right'>
<FlatButton <FlatButton
@@ -156,6 +130,65 @@ class CreateTorrentPage extends React.Component {
</div> </div>
) )
} }
renderAdvanced () {
// Create file list
var maxFileElems = 100
var files = this.state.files
var fileElems = files.slice(0, maxFileElems).map((file, i) => {
var relativePath = path.relative(this.state.pathPrefix, file.path)
return (<div key={i}>{relativePath}</div>)
})
if (files.length > maxFileElems) {
fileElems.push(<div key='more'>+ {maxFileElems - files.length} more</div>)
}
// Align the text fields
var textFieldStyle = { width: '' }
var textareaStyle = { margin: 0 }
return (
<div key='advanced' className='create-torrent-advanced'>
<div key='private' className='torrent-attribute'>
<label>Private:</label>
<Checkbox
className='torrent-is-private'
style={{display: ''}}
value={this.state.isPrivate}
onChange={this.setIsPrivate} />
</div>
<div key='trackers' className='torrent-attribute'>
<label>Trackers:</label>
<TextField
className='torrent-trackers'
style={textFieldStyle}
textareaStyle={textareaStyle}
multiLine
rows={2}
rowsMax={10}
value={this.state.trackers}
onChange={this.setTrackers} />
</div>
<div key='comment' className='torrent-attribute'>
<label>Comment:</label>
<TextField
className='torrent-comment'
style={textFieldStyle}
textareaStyle={textareaStyle}
hintText='Optionally describe your torrent...'
multiLine
rows={2}
rowsMax={10}
value={this.state.comment}
onChange={this.setComment} />
</div>
<div key='files' className='torrent-attribute'>
<label>Files:</label>
<div>{fileElems}</div>
</div>
</div>
)
}
} }
// Finds the longest common prefix // Finds the longest common prefix
@@ -168,4 +201,10 @@ function findCommonPrefix (a, b) {
return a.substring(0, i) return a.substring(0, i)
} }
function containsDots (path, pathPrefix) {
var suffix = path.substring(pathPrefix.length).replace(/\\/g, '/')
console.log('SUFFIX ' + suffix)
return ('/' + suffix).includes('/.')
}
module.exports = CreateTorrentPage module.exports = CreateTorrentPage

View File

@@ -272,10 +272,12 @@ table {
.create-torrent { .create-torrent {
padding: 10px 25px; padding: 10px 25px;
overflow: hidden; overflow: hidden;
font: 16px/24px BlinkMacSystemFont, "Helvetica Neue", Helvetica, sans-serif;
} }
.create-torrent .torrent-attribute { .create-torrent .torrent-attribute {
white-space: nowrap; white-space: nowrap;
margin: 8px 0;
} }
.create-torrent .torrent-attribute>* { .create-torrent .torrent-attribute>* {
@@ -283,13 +285,12 @@ table {
} }
.create-torrent .torrent-attribute label { .create-torrent .torrent-attribute label {
width: 60px; width: 100px;
margin-right: 10px;
vertical-align: top; vertical-align: top;
} }
.create-torrent .torrent-attribute>div { .create-torrent .torrent-attribute>div {
width: calc(100% - 90px); width: calc(100% - 100px);
} }
.create-torrent .torrent-attribute div { .create-torrent .torrent-attribute div {
@@ -298,18 +299,6 @@ table {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.create-torrent .torrent-attribute textarea {
width: calc(100% - 80px);
height: 80px;
color: #eee;
background-color: transparent;
line-height: 1.5;
font-size: 14px;
font-family: inherit;
border-radius: 2px;
padding: 4px 6px;
}
/* /*
* BUTTONS * BUTTONS
*/ */