1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-02 03:25:53 +01:00

Allow user to set file name (#145)

* Allow user to set file name

* Add EditableText component

Added editable text component and use component for project name edit.

* rebased branch

* Updated EditableText component

* Set default project name

* Move project name field away from the top section.
This commit is contained in:
IA 2020-01-05 22:26:00 +00:00 committed by Christopher Chedeau
parent 7201198f23
commit 5f806474e3
4 changed files with 115 additions and 7 deletions

@ -0,0 +1,68 @@
import React, { Fragment, Component } from "react";
type InputState = {
value: string;
edit: boolean;
};
type Props = {
value: string;
onChange: (value: string) => void;
};
export default class EditableText extends Component<Props, InputState> {
constructor(props: Props) {
super(props);
this.state = {
value: props.value,
edit: false
};
}
componentWillReceiveProps(props: Props) {
this.setState({ value: props.value });
}
private handleEdit(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({ value: e.target.value });
}
private handleBlur() {
const { value } = this.state;
if (!value) {
this.setState({ value: this.props.value, edit: false });
return;
}
this.props.onChange(value);
this.setState({ edit: false });
}
public render() {
const { value, edit } = this.state;
return (
<Fragment>
{edit ? (
<input
className="project-name-input"
name="name"
maxLength={25}
value={value}
onChange={e => this.handleEdit(e)}
onBlur={() => this.handleBlur()}
autoFocus
/>
) : (
<span
onClick={() => this.setState({ edit: true })}
className="project-name"
>
{value}
</span>
)}
</Fragment>
);
}
}

@ -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";
@ -22,6 +24,8 @@ const LOCAL_STORAGE_KEY_STATE = "excalidraw-state";
const elements = Array.of<ExcalidrawElement>();
const DEFAULT_PROJECT_NAME = `excalidraw-${getDateTime()}`;
let skipHistory = false;
const stateHistory: string[] = [];
function generateHistoryCurrentEntry() {
@ -529,7 +533,7 @@ function renderScene(
}
}
function saveAsJSON() {
function saveAsJSON(name: string) {
const serialized = JSON.stringify({
version: 1,
source: window.location.origin,
@ -537,7 +541,7 @@ function saveAsJSON() {
});
saveFile(
"excalidraw.json",
`${name}.json`,
"data:text/plain;charset=utf-8," + encodeURIComponent(serialized)
);
}
@ -573,16 +577,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.");
// calculate smallest area to fit the contents in
let subCanvasX1 = Infinity;
@ -623,7 +628,7 @@ function exportAsPNG({
}
);
saveFile("excalidraw.png", tempCanvas.toDataURL("image/png"));
saveFile(`${name}.png`, tempCanvas.toDataURL("image/png"));
// clean up the DOM
if (tempCanvas !== canvas) tempCanvas.remove();
@ -872,6 +877,7 @@ type AppState = {
viewBackgroundColor: string;
scrollX: number;
scrollY: number;
name: string;
};
const KEYS = {
@ -1004,7 +1010,8 @@ class App extends React.Component<{}, AppState> {
currentItemBackgroundColor: "#ffffff",
viewBackgroundColor: "#ffffff",
scrollX: 0,
scrollY: 0
scrollY: 0,
name: DEFAULT_PROJECT_NAME
};
private onResize = () => {
@ -1129,6 +1136,10 @@ 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;
@ -1349,11 +1360,20 @@ class App extends React.Component<{}, AppState> {
background
</label>
</div>
<h4>Project name</h4>
<div className="panelColumn">
{this.state.name && (
<EditableText
value={this.state.name}
onChange={(name: string) => this.updateProjectName(name)}
/>
)}
</div>
<h4>Save/Load</h4>
<div className="panelColumn">
<button
onClick={() => {
saveAsJSON();
saveAsJSON(this.state.name);
}}
>
Save as...

@ -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;
}

11
src/utils/index.ts Normal file

@ -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}`;
};