From e52dcc61ed433980d760a050ff14852a05676b96 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 3 Jun 2020 19:27:29 +0200 Subject: image/text form --- frontend/views/graph/graph.css | 62 ++++++- frontend/views/page/components/tile.form.js | 255 +++++++++++++++++++++++----- frontend/views/page/components/tile.new.js | 2 +- frontend/views/page/page.container.js | 8 +- 4 files changed, 276 insertions(+), 51 deletions(-) (limited to 'frontend/views') 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 (

{title}

- - -