Skip to content
This repository has been archived by the owner on Jan 6, 2022. It is now read-only.

Make table title field editable #501

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' })
30 changes: 20 additions & 10 deletions app/components/table-row.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -161,15 +162,17 @@ const DeleteButton = ({ ...props }) => (
/>
)

const TitleField = ({ dat }) => (
<div>
<h2 className='f6 f5-l normal truncate pr3'>
{dat.metadata.title || `#${dat.key}`}
</h2>
</div>
)

const Row = ({ dat, shareDat, onDeleteDat, inspectDat }) => (
const Row = ({
dat,
editing,
shareDat,
onDeleteDat,
inspectDat,
updateTitle,
makeEditable,
editTitle,
deactivate
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like adding above props, any suggestions on how to refactor this?

}) => (
<Tr onClick={() => inspectDat(dat.key)}>
<td className='cell-1'>
<div className='w2 center'>
Expand All @@ -178,7 +181,14 @@ const Row = ({ dat, shareDat, onDeleteDat, inspectDat }) => (
</td>
<td className='cell-2'>
<div className='cell-truncate'>
<TitleField dat={dat} />
<TitleField
dat={dat}
editing={editing}
updateTitle={updateTitle}
makeEditable={makeEditable}
editTitle={editTitle}
deactivate={deactivate}
/>
<p className='f7 f6-l color-neutral-60 truncate'>
<span className='author'>
{dat.metadata.author || 'Anonymous'} •{' '}
Expand Down
18 changes: 17 additions & 1 deletion app/components/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Fragment>
Expand Down Expand Up @@ -68,10 +79,15 @@ const Table = ({ dats, show, shareDat, onDeleteDat, inspectDat }) => {
{Object.keys(dats).map(key => (
<TableRow
dat={dats[key]}
editing={editing}
key={key}
shareDat={shareDat}
onDeleteDat={onDeleteDat}
inspectDat={inspectDat}
updateTitle={updateTitle}
makeEditable={makeEditable}
editTitle={editTitle}
deactivate={deactivate}
/>
))}
</tbody>
Expand Down
141 changes: 141 additions & 0 deletions app/components/title-field.js
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<Overlay onClick={() => this.deactivate()} />
<EditableField className='bg-white nt1 nb1 nl1 pl1 shadow-1 flex justify-between'>
<input
className='bn f6 normal w-100'
defaultValue={editValue || title}
onKeyUp={ev => this.handleKeypress(ev)}
ref={input => {
this.titleInput = input
}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can i do it without having to use ref?

/>
{editValue === title ? (
<PlainButton onClick={ev => this.deactivate(ev)}>
Save
</PlainButton>
) : (
<GreenButton onClick={() => this.handleSave()}>Save</GreenButton>
)}
</EditableField>
</div>
)
}

if (writable) {
return (
<EditableField>
<h2
className='f6 f5-l normal truncate pr3'
onClick={ev => this.onclick(ev)}
>
{title || placeholderTitle}
<Icon
name='edit'
className='absolute top-0 bottom-0 right-0 color-neutral-30 indicator'
/>
</h2>
</EditableField>
)
}

return (
<div>
<h2 className='f6 f5-l normal truncate pr3'>
{title || placeholderTitle}
</h2>
</div>
)
}
}

export default TitleField
20 changes: 17 additions & 3 deletions app/containers/table.js
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
38 changes: 37 additions & 1 deletion app/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const defaultState = {
up: 0,
down: 0
},
inspect: { key: null }
inspect: { key: null },
editing: {}
}

const redatApp = (state = defaultState, action) => {
Expand Down Expand Up @@ -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,
Expand Down