summaryrefslogtreecommitdiff
path: root/frontend/views
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/views')
-rw-r--r--frontend/views/graph/graph.css62
-rw-r--r--frontend/views/page/components/tile.form.js255
-rw-r--r--frontend/views/page/components/tile.new.js2
-rw-r--r--frontend/views/page/page.container.js8
4 files changed, 276 insertions, 51 deletions
diff --git a/frontend/views/graph/graph.css b/frontend/views/graph/graph.css
index 73ac103..6facb9b 100644
--- a/frontend/views/graph/graph.css
+++ b/frontend/views/graph/graph.css
@@ -15,11 +15,14 @@
/* Sidebar boxes */
-.box {
- width: 15rem;
+.sidebar {
position: absolute;
top: 1rem;
right: 1rem;
+ z-index: 2000;
+}
+.box {
+ width: 15rem;
padding: 0.5rem;
background: rgba(64,12,64,0.9);
border: 2px solid #000;
@@ -36,6 +39,30 @@
align-items: flex-start;
margin-bottom: 0.25rem;
}
+.box form label.checkbox {
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+}
+.box form input[type="checkbox"] {
+ margin-left: 0rem;
+}
+.box form input[type=checkbox] + span {
+ color: #ddd;
+}
+.box form input[type=checkbox]:hover + span {
+ color: #fff;
+}
+.box form input[type="checkbox"]:after {
+ border-color: #84f;
+}
+.box form input[type="checkbox"]:checked:after {
+ border-color: #84f;
+ background-color: #84f;
+}
+.box form input[type=checkbox]:hover + span {
+ color: #84f;
+}
.box input[type=text],
.box input[type=number],
.box input[type=password] {
@@ -48,10 +75,37 @@
height: 5rem;
border-color: #888;
}
-.box .text.description span:first-child {
- display: none;
+.box .select {
+ padding: 0.25rem;
+ margin-right: 0;
+}
+.box .selects label {
+ flex-direction: row;
+ width: 6.5rem;
+ margin-right: 0.5rem;
+ min-width: auto;
+}
+.box form textarea {
+ padding: 0.25rem;
}
+.box form .pair label span {
+ min-width: 3rem;
+ padding: 0.25rem 0;
+}
+.box .pair label {
+ flex-direction: row;
+ width: 6rem;
+ margin-right: 1rem;
+ min-width: auto;
+}
+.box .pair input[type=text] {
+ width: 3rem;
+}
+.box .position {
+ font-size: smaller;
+ margin-bottom: 0.25rem;
+}
/* Graph handles */
.handle {
diff --git a/frontend/views/page/components/tile.form.js b/frontend/views/page/components/tile.form.js
index 6b9d0a7..9bd8f14 100644
--- a/frontend/views/page/components/tile.form.js
+++ b/frontend/views/page/components/tile.form.js
@@ -3,38 +3,79 @@ import { Link } from 'react-router-dom'
import { session } from '../../../session'
-import { TextInput, LabelDescription, TextArea, Checkbox, SubmitButton, Loader } from '../../../common'
+import { TextInput, NumberInput, Select, LabelDescription, TextArea, Checkbox, SubmitButton, Loader } from '../../../common'
-const newTile = (data) => ({
- path: '',
- title: '',
- username: session('username'),
- description: '',
+const SELECT_TYPES = [
+ "image", "text"
+].map(s => ({ name: s, label: s }))
+
+const ALIGNMENTS = [
+ "top_left", "top center", "top_right",
+ "center_left", "center_center", "center_right",
+ "bottom_left", "bottom_center", "bottom_right",
+].map(align => ({
+ name: align,
+ label: align === 'center_center'
+ ? 'center'
+ : align.replace('_', ' ')
+ }))
+
+const REQUIRED_KEYS = {
+ image: ['url'],
+ text: ['content', 'width', 'height'],
+}
+
+// target_page_id = Column(Integer, ForeignKey('page.id'), nullable=True)
+
+const newImage = (data) => ({
settings: {
- x: 0.05, y: 0.05,
+ ...newPosition(),
+ tile: false,
+ url: "",
},
+ type: 'image',
...data,
})
+const newText = (data) => ({
+ settings: {
+ ...newPosition(),
+ tile: false,
+ url: "",
+ width: 200,
+ height: 200,
+ },
+ type: 'text',
+ ...data,
+})
+
+const newPosition = () => ({
+ x: 0, y: 0,
+ width: 0, height: 0,
+ rotation: 0, scale: 1,
+ align: "center_center",
+})
+
export default class TileForm extends Component {
state = {
title: "",
submitTitle: "",
- data: { ...newTile() },
+ data: { ...newText() },
errorFields: new Set([]),
}
componentDidMount() {
- const { graph, page, data, isNew } = this.props
- const title = isNew ? 'new tile' : 'editing ' + data.title
+ const { graph, page, isNew } = this.props
+ const title = isNew ? 'new tile' : 'editing tile'
const submitTitle = isNew ? "Create Tile" : "Save Changes"
this.setState({
title,
submitTitle,
errorFields: new Set([]),
data: {
- ...newTile({ graph_id: graph.id, page_id: page.id }),
- ...data,
+ ...(this.props.data || this.state.data),
+ graph_id: graph.id,
+ page_id: page.id,
},
})
}
@@ -45,15 +86,45 @@ export default class TileForm extends Component {
if (errorFields.has(name)) {
errorFields.delete(name)
}
- let sanitizedValue = value
- if (name === 'path') {
- sanitizedValue = sanitizedValue.toLowerCase().replace(/ /, '-').replace(/[!@#$%^&*()[\]{}]/, '-').replace(/-+/, '-')
+ if (name === 'type') {
+ const { graph, page } = this.props
+ let newData;
+ switch(type) {
+ case 'image':
+ newData = newImage({ graph_id: graph.id, page_id: page.id })
+ break
+ case 'text':
+ newData = newText({ graph_id: graph.id, page_id: page.id })
+ break
+ }
+ this.setState({
+ errorFields,
+ data: newData,
+ })
+ }
+ this.setState({
+ errorFields,
+ data: {
+ ...this.state.data,
+ [name]: value,
+ }
+ })
+ }
+
+ handleSettingsChange(e) {
+ const { errorFields } = this.state
+ const { name, value } = e.target
+ if (errorFields.has(name)) {
+ errorFields.delete(name)
}
this.setState({
errorFields,
data: {
...this.state.data,
- [name]: sanitizedValue,
+ settings: {
+ ...this.state.settings,
+ [name]: value,
+ }
}
})
}
@@ -72,12 +143,29 @@ export default class TileForm extends Component {
})
}
+ handleSettingsSelect(name, value) {
+ const { errorFields } = this.state
+ if (errorFields.has(name)) {
+ errorFields.delete(name)
+ }
+ this.setState({
+ errorFields,
+ data: {
+ ...this.state.data,
+ settings: {
+ ...this.state.data.settings,
+ [name]: value,
+ }
+ }
+ })
+ }
+
handleSubmit(e) {
e.preventDefault()
const { isNew, onSubmit } = this.props
const { data } = this.state
- const requiredKeys = "path title".split(" ")
- const validKeys = "graph_id path title username description settings".split(" ")
+ const requiredKeys = REQUIRED_KEYS[data.type]
+ const validKeys = "graph_id username settings".split(" ")
const validData = validKeys.reduce((a,b) => { a[b] = data[b]; return a }, {})
const errorFields = requiredKeys.filter(key => !validData[key])
if (errorFields.length) {
@@ -96,36 +184,38 @@ export default class TileForm extends Component {
}
render() {
- const { graph, isNew } = this.props
+ const { isNew } = this.props
const { title, submitTitle, errorFields, data } = this.state
+ if (!data) return
return (
<div className='box'>
<h1>{title}</h1>
<form onSubmit={this.handleSubmit.bind(this)}>
- <TextInput
- title="Path"
- name="path"
- required
- data={data}
- error={errorFields.has('path')}
- onChange={this.handleChange.bind(this)}
- autoComplete="off"
- />
- <TextInput
- title="Title"
- name="title"
- required
- data={data}
- error={errorFields.has('title')}
- onChange={this.handleChange.bind(this)}
- autoComplete="off"
- />
- <TextArea
- title="Description"
- name="description"
- data={data}
- onChange={this.handleChange.bind(this)}
- />
+ <div className="row selects">
+ <Select
+ name='type'
+ selected={data.type}
+ options={SELECT_TYPES}
+ title=''
+ onChange={this.handleSelect.bind(this)}
+ />
+ <Select
+ name='align'
+ selected={data.settings.align}
+ options={ALIGNMENTS}
+ title=''
+ onChange={this.handleSettingsSelect.bind(this)}
+ />
+ </div>
+
+ {this.renderPositionInfo()}
+
+ {data.type === 'image'
+ ? this.renderImageForm()
+ : data.type === 'text'
+ ? this.renderTextForm()
+ : ""}
+
<SubmitButton
title={submitTitle}
onClick={this.handleSubmit.bind(this)}
@@ -140,4 +230,83 @@ export default class TileForm extends Component {
</div>
)
}
+
+ renderPositionInfo() {
+ const { x, y, width, height, rotation, scale } = this.state.data.settings
+ return (
+ <div className='position'>
+ {''}{parseInt(x)}{', '}
+ {''}{parseInt(y)}{' '}
+ {parseInt(width)}{'x'}{parseInt(height)}{' '}
+ {parseInt(rotation * 180 / Math.PI)}{'\u00B0 '}
+ {'x'}{scale.toFixed(0.2)}
+ </div>
+ )
+ }
+
+ renderImageForm() {
+ // const { isNew } = this.props
+ const { data } = this.state
+ return (
+ <div>
+ <TextInput
+ title=""
+ placeholder='http://'
+ name="url"
+ required
+ data={data.settings}
+ error={errorFields.has('url')}
+ onChange={this.handleSettingsChange.bind(this)}
+ autoComplete="off"
+ />
+ <Checkbox
+ label="Tiled"
+ name="tile"
+ data={data.settings}
+ onChange={this.handleSettingsSelect.bind(this)}
+ autoComplete="off"
+ />
+ </div>
+ )
+
+ }
+
+ renderTextForm() {
+ const { data } = this.state
+ return (
+ <div>
+ <TextArea
+ title=""
+ name="content"
+ required
+ data={data.settings}
+ error={errorFields.has('content')}
+ onChange={this.handleChange.bind(this)}
+ autoComplete="off"
+ />
+ <div className='row pair'>
+ <NumberInput
+ title="Width"
+ name="width"
+ data={data.settings}
+ min={10}
+ max={1200}
+ error={errorFields.has('width')}
+ onChange={this.handleSettingsChange.bind(this)}
+ autoComplete="off"
+ />
+ <NumberInput
+ title="Height"
+ name="height"
+ data={data.settings}
+ min={10}
+ max={1200}
+ error={errorFields.has('height')}
+ onChange={this.handleSettingsChange.bind(this)}
+ autoComplete="off"
+ />
+ </div>
+ </div>
+ )
+ }
}
diff --git a/frontend/views/page/components/tile.new.js b/frontend/views/page/components/tile.new.js
index cb5eaa8..4e88729 100644
--- a/frontend/views/page/components/tile.new.js
+++ b/frontend/views/page/components/tile.new.js
@@ -29,7 +29,7 @@ class TileNew extends Component {
isNew
graph={this.props.graph.show.res}
page={this.props.page.show.res}
- data={{}}
+ data={null}
onSubmit={this.handleSubmit.bind(this)}
/>
)
diff --git a/frontend/views/page/page.container.js b/frontend/views/page/page.container.js
index bbb1f3a..6993632 100644
--- a/frontend/views/page/page.container.js
+++ b/frontend/views/page/page.container.js
@@ -66,9 +66,11 @@ class PageContainer extends Component {
<PageHeader />
<div className='body'>
<PageEditor />
- {this.props.graph.editor.editingPage && <PageEdit />}
- {this.props.page.editor.addingTile && <TileNew />}
- {this.props.page.editor.editingTile && <TileEdit />}
+ <div className='sidebar'>
+ {this.props.graph.editor.editingPage && <PageEdit />}
+ {this.props.page.editor.addingTile && <TileNew />}
+ {this.props.page.editor.editingTile && <TileEdit />}
+ </div>
</div>
</div>
)