Redesign idea (#343)

* Redisign idea

* Code cleanup

* Fixed to right container

* Reoredered layout

* Reordering panels

* Export dialog

* Removed redunant code

* Fixed not removing temp canvas

* Fixed preview not using only selected elements

* Returned file name on export

* Toggle export selected/all elements

* Hide copy to clipboard button if no support of clipboard

* Added border to swatches

* Fixed modal flickering
This commit is contained in:
Timur Khazamov 2020-01-15 20:42:02 +05:00 committed by Christopher Chedeau
parent 8104c8525d
commit 79aee53ff6
37 changed files with 1043 additions and 746 deletions

View file

@ -21,17 +21,21 @@ import {
saveToLocalStorage,
getElementAtPosition,
createScene,
getElementContainingPosition
getElementContainingPosition,
hasBackground,
hasStroke,
hasText,
exportCanvas
} from "./scene";
import { renderScene } from "./renderer";
import { AppState } from "./types";
import { ExcalidrawElement, ExcalidrawTextElement } from "./element/types";
import { isInputLike, measureText, debounce } from "./utils";
import { isInputLike, measureText, debounce, capitalizeString } from "./utils";
import { KEYS, META_KEY, isArrowKey } from "./keys";
import { findShapeByKey, shapesShortcutKeys } from "./shapes";
import { findShapeByKey, shapesShortcutKeys, SHAPES } from "./shapes";
import { createHistory } from "./history";
import ContextMenu from "./components/ContextMenu";
@ -63,14 +67,18 @@ import {
actionCopyStyles,
actionPasteStyles
} from "./actions";
import { SidePanel } from "./components/SidePanel";
import { Action, ActionResult } from "./actions/types";
import { getDefaultAppState } from "./appState";
import { Island } from "./components/Island";
import Stack from "./components/Stack";
import { FixedSideContainer } from "./components/FixedSideContainer";
import { ToolIcon } from "./components/ToolIcon";
import { ExportDialog } from "./components/ExportDialog";
let { elements } = createScene();
const { history } = createHistory();
const CANVAS_WINDOW_OFFSET_LEFT = 250;
const CANVAS_WINDOW_OFFSET_LEFT = 0;
const CANVAS_WINDOW_OFFSET_TOP = 0;
function resetCursor() {
@ -331,26 +339,197 @@ export class App extends React.Component<{}, AppState> {
}
};
private renderSelectedShapeActions(elements: readonly ExcalidrawElement[]) {
const selectedElements = elements.filter(el => el.isSelected);
if (selectedElements.length === 0) {
return null;
}
return (
<Island padding={4}>
<div className="panelColumn">
{this.actionManager.renderAction(
"changeStrokeColor",
elements,
this.state,
this.syncActionResult
)}
{hasBackground(elements) && (
<>
{this.actionManager.renderAction(
"changeBackgroundColor",
elements,
this.state,
this.syncActionResult
)}
{this.actionManager.renderAction(
"changeFillStyle",
elements,
this.state,
this.syncActionResult
)}
<hr />
</>
)}
{hasStroke(elements) && (
<>
{this.actionManager.renderAction(
"changeStrokeWidth",
elements,
this.state,
this.syncActionResult
)}
{this.actionManager.renderAction(
"changeSloppiness",
elements,
this.state,
this.syncActionResult
)}
<hr />
</>
)}
{hasText(elements) && (
<>
{this.actionManager.renderAction(
"changeFontSize",
elements,
this.state,
this.syncActionResult
)}
{this.actionManager.renderAction(
"changeFontFamily",
elements,
this.state,
this.syncActionResult
)}
<hr />
</>
)}
{this.actionManager.renderAction(
"changeOpacity",
elements,
this.state,
this.syncActionResult
)}
{this.actionManager.renderAction(
"deleteSelectedElements",
elements,
this.state,
this.syncActionResult
)}
</div>
</Island>
);
}
private renderShapesSwitcher() {
return (
<>
{SHAPES.map(({ value, icon }) => (
<ToolIcon
key={value}
type="radio"
icon={icon}
checked={this.state.elementType === value}
name="editor-current-shape"
title={`${capitalizeString(value)}${capitalizeString(value)[0]}`}
onChange={() => {
this.setState({ elementType: value });
elements = clearSelection(elements);
document.documentElement.style.cursor =
value === "text" ? "text" : "crosshair";
this.forceUpdate();
}}
></ToolIcon>
))}
</>
);
}
private renderCanvasActions() {
return (
<Stack.Col gap={4}>
<Stack.Row gap={1}>
{this.actionManager.renderAction(
"loadScene",
elements,
this.state,
this.syncActionResult
)}
{this.actionManager.renderAction(
"saveScene",
elements,
this.state,
this.syncActionResult
)}
<ExportDialog
elements={elements}
appState={this.state}
actionManager={this.actionManager}
syncActionResult={this.syncActionResult}
onExportToPng={exportedElements => {
if (this.canvas)
exportCanvas("png", exportedElements, this.canvas, this.state);
}}
onExportToClipboard={exportedElements => {
if (this.canvas)
exportCanvas(
"clipboard",
exportedElements,
this.canvas,
this.state
);
}}
/>
{this.actionManager.renderAction(
"clearCanvas",
elements,
this.state,
this.syncActionResult
)}
</Stack.Row>
{this.actionManager.renderAction(
"changeViewBackgroundColor",
elements,
this.state,
this.syncActionResult
)}
</Stack.Col>
);
}
public render() {
const canvasWidth = window.innerWidth - CANVAS_WINDOW_OFFSET_LEFT;
const canvasHeight = window.innerHeight - CANVAS_WINDOW_OFFSET_TOP;
return (
<div className="container">
<SidePanel
actionManager={this.actionManager}
syncActionResult={this.syncActionResult}
appState={{ ...this.state }}
elements={elements}
onToolChange={value => {
this.setState({ elementType: value });
elements = clearSelection(elements);
document.documentElement.style.cursor =
value === "text" ? "text" : "crosshair";
this.forceUpdate();
}}
canvas={this.canvas!}
/>
<FixedSideContainer side="top">
<div className="App-menu App-menu_top">
<Stack.Col gap={4} align="end">
<div className="App-right-menu">
<Island padding={4}>{this.renderCanvasActions()}</Island>
</div>
<div className="App-right-menu">
{this.renderSelectedShapeActions(elements)}
</div>
</Stack.Col>
<Stack.Col gap={4} align="start">
<Island padding={1}>
<Stack.Row gap={1}>{this.renderShapesSwitcher()}</Stack.Row>
</Island>
</Stack.Col>
<div />
</div>
</FixedSideContainer>
<canvas
id="canvas"
style={{
@ -374,7 +553,6 @@ export class App extends React.Component<{}, AppState> {
});
this.removeWheelEventListener = () =>
canvas.removeEventListener("wheel", this.handleWheel);
// Whenever React sets the width/height of the canvas element,
// the context loses the scale transform. We need to re-apply it
if (