diff --git a/app/actions/index.js b/app/actions/index.js
index c1fa83dc..44bef703 100644
--- a/app/actions/index.js
+++ b/app/actions/index.js
@@ -172,3 +172,15 @@ export const dropFolder = folder => async dispatch => {
if (!isDirectory) return
addDat({ path: folder.path })(dispatch)
}
+
+export const updateTitle = (key, path, editValue) => ({
+ type: 'UPDATE_TITLE',
+ key,
+ editValue
+})
+
+export const makeEditable = title => ({ type: 'MAKE_EDITABLE', title })
+
+export const editTitle = title => ({ type: 'EDIT_TITLE', title })
+
+export const deactivate = () => ({ type: 'DEACTIVATE_EDITING' })
diff --git a/app/components/table-row.js b/app/components/table-row.js
index b53c0a3f..8f21940b 100644
--- a/app/components/table-row.js
+++ b/app/components/table-row.js
@@ -7,6 +7,7 @@ import Icon from './icon'
import Status from './status'
import bytes from 'prettier-bytes'
import FinderButton from './finder-button'
+import TitleField from './title-field'
const Tr = styled.tr`
transition: background-color 0.025s ease-out;
@@ -161,15 +162,17 @@ const DeleteButton = ({ ...props }) => (
/>
)
-const TitleField = ({ dat }) => (
-
inspectDat(dat.key)}>
@@ -178,7 +181,14 @@ const Row = ({ dat, shareDat, onDeleteDat, inspectDat }) => (
|
-
+
{dat.metadata.author || 'Anonymous'} •{' '}
diff --git a/app/components/table.js b/app/components/table.js
index 31643965..bd7375cc 100644
--- a/app/components/table.js
+++ b/app/components/table.js
@@ -40,7 +40,18 @@ const StyledTable = styled.table`
}
`
-const Table = ({ dats, show, shareDat, onDeleteDat, inspectDat }) => {
+const Table = ({
+ dats,
+ show,
+ editing,
+ shareDat,
+ onDeleteDat,
+ inspectDat,
+ updateTitle,
+ makeEditable,
+ editTitle,
+ deactivate
+}) => {
if (!show) {
return (
@@ -68,10 +79,15 @@ const Table = ({ dats, show, shareDat, onDeleteDat, inspectDat }) => {
{Object.keys(dats).map(key => (
))}
diff --git a/app/components/title-field.js b/app/components/title-field.js
new file mode 100644
index 00000000..fa07de98
--- /dev/null
+++ b/app/components/title-field.js
@@ -0,0 +1,141 @@
+import React, { Component } from 'react'
+import styled from 'styled-components'
+import Icon from './icon'
+import { Plain as PlainButton, Green as GreenButton } from './button'
+
+const Overlay = styled.div`
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(0, 0, 0, 0.2);
+`
+
+const EditableField = styled.div`
+ position: relative;
+ h2 {
+ position: relative;
+ }
+ .indicator {
+ position: absolute;
+ display: none;
+ top: 0.25rem;
+ right: 0;
+ width: 0.75rem;
+ }
+ &:hover,
+ &:focus {
+ h2 {
+ color: var(--color-blue);
+ }
+ .indicator {
+ display: block;
+ }
+ }
+`
+
+class TitleField extends Component {
+ constructor (props) {
+ super(props)
+ this.onclick = this.onclick.bind(this)
+ this.deactivate = this.deactivate.bind(this)
+ }
+
+ onclick (ev) {
+ ev.stopPropagation()
+ ev.preventDefault()
+ this.props.makeEditable()
+ setTimeout(() => {
+ this.titleInput.focus()
+ this.titleInput.select()
+ }, 0)
+ }
+
+ deactivate () {
+ this.props.deactivate()
+ }
+
+ handleSave () {
+ const { key, path } = this.props.dat
+ const editValue = this.props.editing.editValue
+ this.props.updateTitle(key, path, editValue)
+ this.props.deactivate()
+ }
+
+ handleKeypress (ev) {
+ const oldValue = this.props.editing.editValue
+ const newValue = ev.target.value
+ const editValue = newValue
+ ev.stopPropagation()
+
+ if (ev.code === 'Escape') {
+ ev.preventDefault()
+ this.props.deactivate()
+ } else if (ev.code === 'Enter') {
+ ev.preventDefault()
+ const { key, path } = this.props.dat
+ this.props.updateTitle(key, path, editValue)
+ } else if (oldValue !== newValue) {
+ this.props.editTitle(newValue)
+ }
+ }
+
+ render () {
+ const { writable, metadata } = this.props.dat
+ const { title } = metadata
+ const { isEditing, placeholderTitle, editValue } = this.props.editing
+
+ if (isEditing && writable) {
+ return (
+
+ )
+ }
+
+ if (writable) {
+ return (
+
+ this.onclick(ev)}
+ >
+ {title || placeholderTitle}
+
+
+
+ )
+ }
+
+ return (
+
+
+ {title || placeholderTitle}
+
+
+ )
+ }
+}
+
+export default TitleField
diff --git a/app/containers/table.js b/app/containers/table.js
index b600a95f..38c4c27e 100644
--- a/app/containers/table.js
+++ b/app/containers/table.js
@@ -1,18 +1,32 @@
'use strict'
import Table from '../components/table'
-import { shareDat, deleteDat, inspectDat } from '../actions'
+import {
+ shareDat,
+ deleteDat,
+ inspectDat,
+ updateTitle,
+ makeEditable,
+ editTitle,
+ deactivate
+} from '../actions'
import { connect } from 'react-redux'
const mapStateToProps = state => ({
dats: state.dats,
- show: !state.inspect.key
+ show: !state.inspect.key,
+ editing: state.editing
})
const mapDispatchToProps = dispatch => ({
shareDat: link => dispatch(shareDat(link)),
onDeleteDat: key => dispatch(deleteDat(key)),
- inspectDat: key => dispatch(inspectDat(key))
+ inspectDat: key => dispatch(inspectDat(key)),
+ updateTitle: (key, path, editValue) =>
+ dispatch(updateTitle(key, path, editValue)),
+ makeEditable: (title, editable) => dispatch(makeEditable(title)),
+ editTitle: title => dispatch(editTitle(title)),
+ deactivate: () => dispatch(deactivate())
})
const TableContainer = connect(mapStateToProps, mapDispatchToProps)(Table)
diff --git a/app/reducers/index.js b/app/reducers/index.js
index 70aea678..0d31bb50 100644
--- a/app/reducers/index.js
+++ b/app/reducers/index.js
@@ -15,7 +15,8 @@ const defaultState = {
up: 0,
down: 0
},
- inspect: { key: null }
+ inspect: { key: null },
+ editing: {}
}
const redatApp = (state = defaultState, action) => {
@@ -179,6 +180,41 @@ const redatApp = (state = defaultState, action) => {
}
}
}
+ case 'UPDATE_TITLE':
+ return {
+ ...state,
+ dats: {
+ ...state.dats,
+ [action.key]: {
+ ...state.dats[action.key],
+ metadata: {
+ ...state.dats[action.key].metadata,
+ title: action.editValue
+ }
+ }
+ }
+ }
+ case 'MAKE_EDITABLE':
+ return {
+ ...state,
+ editing: {
+ ...state.editing,
+ isEditing: true
+ }
+ }
+ case 'EDIT_TITLE':
+ return {
+ ...state,
+ editing: {
+ ...state.editing,
+ editValue: action.title
+ }
+ }
+ case 'DEACTIVATE_EDITING':
+ return {
+ ...state,
+ editing: {}
+ }
case 'DIALOGS_LINK_OPEN':
return {
...state,
|