diff --git a/src/components/EditableText.tsx b/src/components/EditableText.tsx new file mode 100644 index 000000000..7fc825896 --- /dev/null +++ b/src/components/EditableText.tsx @@ -0,0 +1,74 @@ +import React, { createRef, Fragment, Component } from "react"; + +type InputState = { + initialValue: string; + value: string; + edit: boolean; +}; + +type Props = { + value: string; + updateName: (name: string) => void; +}; + +export default class EditableInput extends Component { + constructor(props: Props) { + super(props); + const { value } = props; + + this.state = { + initialValue: value, + value, + edit: false + }; + } + + private inputRef = createRef(); + + private handleEdit(e: React.ChangeEvent) { + this.setState({ value: e.target.value }); + } + + private handleBlur() { + const { value, initialValue } = this.state; + + if (!value) { + this.setState({ value: initialValue, edit: false }); + return; + } + this.props.updateName(value); + this.setState({ edit: false, initialValue: value }); + } + + private focusInput() { + const input = this.inputRef.current; + if (input) { + input.focus(); + } + this.setState({ edit: true }); + } + + public render() { + const { value, edit } = this.state; + + return ( + + {edit ? ( + this.handleEdit(e)} + onBlur={() => this.handleBlur()} + ref={this.inputRef} + /> + ) : ( + this.focusInput()} className="project-name"> + {value} + + )} + + ); + } +} diff --git a/src/index.tsx b/src/index.tsx index ff6dbacc8..39814854a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,6 +6,8 @@ import { SketchPicker } from "react-color"; import { moveOneLeft, moveAllLeft, moveOneRight, moveAllRight } from "./zindex"; import { roundRect } from "./roundRect"; +import EditableText from "./components/EditableText"; +import { getDateTime } from "./utils"; import "./styles.scss"; @@ -573,17 +575,17 @@ function loadFromJSON() { function exportAsPNG({ exportBackground, exportPadding = 10, - viewBackgroundColor + viewBackgroundColor, + name }: { exportBackground: boolean; exportPadding?: number; viewBackgroundColor: string; scrollX: number; scrollY: number; + name: string; }) { if (!elements.length) return window.alert("Cannot export empty canvas."); - - const fileName = prompt("Enter name of project"); // calculate smallest area to fit the contents in let subCanvasX1 = Infinity; @@ -873,6 +875,7 @@ type AppState = { viewBackgroundColor: string; scrollX: number; scrollY: number; + name: string; }; const KEYS = { @@ -988,6 +991,11 @@ class App extends React.Component<{}, AppState> { if (savedState) { this.setState(savedState); } + + if (!(savedState && savedState.name)) { + const name = `excalidraw-${getDateTime()}`; + this.setState({ name }); + } } public componentWillUnmount() { @@ -1005,7 +1013,8 @@ class App extends React.Component<{}, AppState> { currentItemBackgroundColor: "#ffffff", viewBackgroundColor: "#ffffff", scrollX: 0, - scrollY: 0 + scrollY: 0, + name: "" }; private onResize = () => { @@ -1130,10 +1139,16 @@ class App extends React.Component<{}, AppState> { private removeWheelEventListener: (() => void) | undefined; + private updateProjectName(name: string): void { + this.setState({ name }); + } + public render() { const canvasWidth = window.innerWidth - CANVAS_WINDOW_OFFSET_LEFT; const canvasHeight = window.innerHeight - CANVAS_WINDOW_OFFSET_TOP; + const { name } = this.state; + return (
{ }} >
+

Project name

+ {name && ( + this.updateProjectName(name)} + /> + )} +

Shapes

{SHAPES.map(({ value, icon }) => ( diff --git a/src/styles.scss b/src/styles.scss index 70d215e9f..eb1e721bb 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -173,3 +173,12 @@ button { padding: 2px 4px; border: 1px solid #ddd; } +.project-name { + font-size: 14px; + cursor: pointer; +} + +.project-name-input { + width: 200px; + font: inherit; +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 000000000..9441c7e0b --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,11 @@ +export const getDateTime = (): string => { + const date = new Date(); + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + const hr = date.getHours(); + const min = date.getMinutes(); + const secs = date.getSeconds(); + + return `${year}${month}${day}${hr}${min}${secs}`; +};