Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Commit

Permalink
feat: page overview (#399)
Browse files Browse the repository at this point in the history
❤️ @Palmaswell 

* feat: add page overview

* chore: update lock file

* fix: update usage of arrow icons

* fix: be consistent about event listener names

* fix: consistently indicate texts can be edited

* fix: truncate too long page titles

* fix: adjust project title styling and page inset

* fix: visually align chrome title

* fix: adapt styling of view-switch

* fix: ensure page list title clicks enable edit mode

* feat: show view button only page detail view

* fix: visually align chrome title

* feat: wrap the page list for narrow viewports

* fix: manage preview resizing lifecycle correctly
  • Loading branch information
Palmaswell authored and marionebl committed May 4, 2018
1 parent ebc9a43 commit 75f3c40
Show file tree
Hide file tree
Showing 52 changed files with 1,346 additions and 997 deletions.
765 changes: 386 additions & 379 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"@commitlint/config-conventional": "6.1.3",
"@commitlint/prompt-cli": "6.1.3",
"@commitlint/travis-cli": "6.1.3",
"@patternplate/cli": "2.3.1",
"@patternplate/cli": "2.5.2",
"@patternplate/render-styled-components": "2.1.6",
"@types/chokidar": "1.7.5",
"@types/deep-assign": "0.1.1",
Expand Down
58 changes: 46 additions & 12 deletions src/component/chrome/chrome-container.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
import Chrome from '../../lsg/patterns/chrome';
import { CopySize as FontSize } from '../../lsg/patterns/copy';
import { observer } from 'mobx-react';
import { OverviewSwitchContainer } from './overview-switch-container';
import { Page } from '../../store/page/page';
import { PageRef } from '../../store/page/page-ref';
import * as React from 'react';
import { Store } from '../../store/store';
import { AlvaView, Store } from '../../store/store';
import { ViewSwitch, ViewTitle } from '../../lsg/patterns/view-switch';

@observer
export class ChromeContainer extends React.Component {
protected store = Store.getInstance();

protected getCurrentPage(): Page | undefined {
return this.store.getCurrentPage();
}

protected openPage(page: PageRef | undefined): void {
if (page) {
this.store.openPage(page.getId());
}
return;
}

public render(): JSX.Element {
let nextPage: PageRef | undefined;
let previousPage: PageRef | undefined;

const store = Store.getInstance();
const page = store.getCurrentPage();
const pages: PageRef[] = page ? page.getProject().getPages() : [];
const currentIndex = page ? pages.indexOf(page.getPageRef()) : 0;
const currentPage = this.getCurrentPage();
const project = currentPage ? currentPage.getProject() : undefined;
const pages = project ? project.getPages() : [];
const currentIndex = currentPage ? pages.indexOf(currentPage.getPageRef()) : 0;

if (currentIndex > 0) {
previousPage = pages[currentIndex - 1];
Expand All @@ -24,13 +41,30 @@ export class ChromeContainer extends React.Component {
}

return (
<Chrome
leftVisible={!!previousPage}
rightVisible={!!nextPage}
onLeftClick={() => (previousPage ? store.openPage(previousPage.getId()) : undefined)}
onRightClick={() => (nextPage ? store.openPage(nextPage.getId()) : undefined)}
title={page ? page.getName() : undefined}
>
<Chrome>
{this.store.getActiveView() === AlvaView.PageDetail ? (
<OverviewSwitchContainer />
) : (
<div />
)}
{this.store.getActiveView() === AlvaView.PageDetail && (
<ViewSwitch
fontSize={FontSize.M}
justify="center"
leftVisible={Boolean(previousPage)}
rightVisible={Boolean(nextPage)}
onLeftClick={() => this.openPage(previousPage)}
onRightClick={() => this.openPage(nextPage)}
title={currentPage ? currentPage.getName() : ''}
/>
)}
{this.store.getActiveView() === AlvaView.Pages && (
<ViewTitle
fontSize={FontSize.M}
justify="center"
title={project ? project.getName() : 'Alva'}
/>
)}
{this.props.children}
</Chrome>
);
Expand Down
23 changes: 23 additions & 0 deletions src/component/chrome/overview-switch-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { observer } from 'mobx-react';
import { Project } from '../../store/project';
import * as React from 'react';
import { AlvaView, Store } from '../../store/store';
import { ViewButton } from '../../lsg/patterns/view-switch';

@observer
export class OverviewSwitchContainer extends React.Component {
public render(): JSX.Element | null {
const store = Store.getInstance();
const project: Project | undefined = store.getCurrentProject();
const page = store.getCurrentPage();

if (!project || !page) {
return null;
}

const title = store.getActiveView() === AlvaView.Pages ? `Show "${page.getName()}"` : 'Pages';
const next = store.getActiveView() === AlvaView.Pages ? AlvaView.PageDetail : AlvaView.Pages;

return <ViewButton onClick={() => store.setActiveView(next)} title={title} />;
}
}
117 changes: 64 additions & 53 deletions src/component/container/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ import ElementPane from '../../lsg/patterns/panes/element-pane';
import * as FsExtra from 'fs-extra';
import globalStyles from '../../lsg/patterns/global-styles';
import { IconName, IconRegistry } from '../../lsg/patterns/icons';
import Layout, { MainArea, SideBar } from '../../lsg/patterns/layout';
import Layout, {
LayoutBorder,
LayoutDirection,
LayoutSide,
MainArea,
SideBar
} from '../../lsg/patterns/layout';
import { createMenu } from '../../electron/menu';
import * as MobX from 'mobx';
import { observer } from 'mobx-react';
import { PageListContainer } from '../page-list/page-list-container';
import { PageListPreview } from '../page-list/page-list-preview';
import * as Path from 'path';
import { PatternListContainer } from './pattern-list';
import PatternsPane from '../../lsg/patterns/panes/patterns-pane';
Expand All @@ -19,7 +27,7 @@ import { PropertyList } from './property-list';
import PropertyPane from '../../lsg/patterns/panes/property-pane';
import * as React from 'react';
import { SplashScreen } from './splash-screen';
import { RightPane, Store } from '../../store/store';
import { AlvaView, RightPane, Store } from '../../store/store';

globalStyles();

Expand All @@ -29,16 +37,11 @@ const store = Store.getInstance();
export class App extends React.Component {
private static PATTERN_LIST_ID = 'patternlist';
private static PROPERTIES_LIST_ID = 'propertieslist';

@MobX.observable protected activeTab: string = App.PATTERN_LIST_ID;

private ctrlDown: boolean = false;
private shiftDown: boolean = false;

public constructor(props: {}) {
super(props);
this.handleTabNaviagtionClick = this.handleTabNaviagtionClick.bind(this);
}
private shiftDown: boolean = false;

public componentDidMount(): void {
createMenu();
Expand Down Expand Up @@ -81,10 +84,6 @@ export class App extends React.Component {
createMenu();
}

protected handleTabNaviagtionClick(evt: React.MouseEvent<HTMLElement>, id: string): void {
this.activeTab = id;
}

protected get isPatternListVisible(): boolean {
return this.activeTab === App.PATTERN_LIST_ID;
}
Expand Down Expand Up @@ -135,54 +134,66 @@ export class App extends React.Component {
const DevTools = this.getDevTools();

return (
<Layout directionVertical onClick={this.handleMainWindowClick}>
<Layout direction={LayoutDirection.Column} onClick={() => this.handleMainWindowClick()}>
<ChromeContainer />
<MainArea>
{project ? (
<React.Fragment>
<SideBar
side="left"
directionVertical
onClick={() => store.setSelectedElement()}
hasBorder
>
<ElementPane>
<ElementList />
</ElementPane>
<AddButton
active={store.getRightPane() === RightPane.Patterns}
label="Add Elements"
onClick={e => {
e.stopPropagation();
store.setRightPane(RightPane.Patterns);
store.setSelectedElement();
}}
/>
</SideBar>
<PreviewPaneWrapper
key="center"
id="preview"
previewFrame={`http://localhost:${store.getServerPort()}/preview.html`}
/>
<SideBar side="right" directionVertical hasBorder>
{store.getRightPane() === RightPane.Properties && (
<PropertyPane>
<PropertyList />
</PropertyPane>
)}
{store.getRightPane() === RightPane.Patterns && (
<PatternsPane>
<PatternListContainer />
</PatternsPane>
)}
</SideBar>
</React.Fragment>
) : (
{!project && (
<SplashScreen
onPrimaryButtonClick={() => this.createNewSpace()}
onSecondaryButtonClick={() => this.openSpace()}
/>
)}
{project &&
store.getActiveView() === AlvaView.Pages && (
<PageListPreview>
<PageListContainer />
</PageListPreview>
)}
{project &&
store.getActiveView() === AlvaView.PageDetail && (
<React.Fragment>
<SideBar
side={LayoutSide.Left}
direction={LayoutDirection.Column}
onClick={() => store.setSelectedElement()}
border={LayoutBorder.Side}
>
<ElementPane>
<ElementList />
</ElementPane>
<AddButton
active={store.getRightPane() === RightPane.Patterns}
label="Add Elements"
onClick={e => {
e.stopPropagation();
store.setRightPane(RightPane.Patterns);
store.setSelectedElement();
}}
/>
</SideBar>
<PreviewPaneWrapper
key="center"
id="preview"
previewFrame={`http://localhost:${store.getServerPort()}/preview.html`}
/>
<SideBar
side={LayoutSide.Right}
direction={LayoutDirection.Column}
border={LayoutBorder.Side}
>
{store.getRightPane() === RightPane.Properties && (
<PropertyPane>
<PropertyList />
</PropertyPane>
)}
{store.getRightPane() === RightPane.Patterns && (
<PatternsPane>
<PatternListContainer />
</PatternsPane>
)}
</SideBar>
</React.Fragment>
)}
</MainArea>
<IconRegistry names={IconName} />
{DevTools ? <DevTools /> : null}
Expand Down
23 changes: 9 additions & 14 deletions src/component/container/pattern-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import PatternList, {
PatternListItemProps
} from '../../lsg/patterns/pattern-list';
import * as React from 'react';
import Space, { Size } from '../../lsg/patterns/space';
import Space, { SpaceSize } from '../../lsg/patterns/space';
import { Store } from '../../store/store';

export interface PatternListContainerItemProps {
Expand All @@ -26,14 +26,6 @@ export interface NamedPatternListItemProps extends PatternListItemProps {
export class PatternListContainer extends React.Component {
public items: PatternListContainerItemProps[] = [];

public constructor(props: {}) {
super(props);

this.handleSearchInputChange = this.handleSearchInputChange.bind(this);
this.handlePatternClick = this.handlePatternClick.bind(this);
this.handleDragStart = this.handleDragStart.bind(this);
}

public createItemsFromFolder(parent: PatternFolder): PatternListContainerItemProps[] {
const result: PatternListContainerItemProps[] = [];

Expand All @@ -48,7 +40,7 @@ export class PatternListContainer extends React.Component {
name: pattern.getName(),
draggable: true,
icon: pattern.getIconPath(),
handleDragStart: (e: React.DragEvent<HTMLElement>) => {
onDragStart: (e: React.DragEvent<HTMLElement>) => {
this.handleDragStart(e, pattern);
},
onClick: () => {
Expand All @@ -74,7 +66,7 @@ export class PatternListContainer extends React.Component {
{container.items.map((item, itemIndex) => (
<PatternListItem
draggable={item.draggable}
handleDragStart={item.handleDragStart}
onDragStart={item.onDragStart}
key={itemIndex}
icon={item.icon}
onClick={item.onClick}
Expand Down Expand Up @@ -136,10 +128,13 @@ export class PatternListContainer extends React.Component {
const list = this.createList(this.items);
return (
<div>
<Space sizeBottom={Size.XXS}>
<Input handleChange={this.handleSearchInputChange} placeholder="Search patterns" />
<Space sizeBottom={SpaceSize.XXS}>
<Input
onChange={e => this.handleSearchInputChange(e)}
placeholder="Search patterns"
/>
</Space>
<Space size={[0, Size.L]}>{list}</Space>
<Space size={[0, SpaceSize.L]}>{list}</Space>
</div>
);
}
Expand Down
21 changes: 7 additions & 14 deletions src/component/container/property-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ class PropertyTree extends React.Component<PropertyTreeProps> {
@MobX.observable protected isOpen = false;
protected lastCommand: PropertyValueCommand;

public constructor(props: PropertyTreeProps) {
super(props);

this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}

protected convertOptionsToValues(options: Option[]): Values[] {
return options.map(option => ({
id: option.getId(),
Expand Down Expand Up @@ -136,7 +129,7 @@ class PropertyTree extends React.Component<PropertyTreeProps> {
key={id}
label={name}
checked={value as boolean}
handleChange={event => this.handleChange(id, !value, context)}
onChange={event => this.handleChange(id, !value, context)}
/>
);

Expand All @@ -146,10 +139,10 @@ class PropertyTree extends React.Component<PropertyTreeProps> {
key={id}
label={name}
value={value as string}
handleChange={event =>
onChange={event =>
this.handleChange(id, event.currentTarget.value, context)
}
handleBlur={event => this.handleBlur()}
onBlur={event => this.handleBlur()}
/>
);

Expand All @@ -165,7 +158,7 @@ class PropertyTree extends React.Component<PropertyTreeProps> {
label={name}
selectedValue={option && option.getId()}
values={this.convertOptionsToValues(options)}
handleChange={event =>
onChange={event =>
this.handleChange(id, event.currentTarget.value, context)
}
/>
Expand All @@ -179,11 +172,11 @@ class PropertyTree extends React.Component<PropertyTreeProps> {
label={name}
inputValue={src && !src.startsWith('data:') ? src : ''}
imageSrc={src}
handleInputChange={event =>
onInputChange={event =>
this.handleChange(id, event.currentTarget.value, context)
}
handleChooseClick={event => this.handleChooseAsset(id, context)}
handleClearClick={event => this.handleChange(id, undefined, context)}
onChooseClick={event => this.handleChooseAsset(id, context)}
onClearClick={event => this.handleChange(id, undefined, context)}
/>
);

Expand Down
Loading

0 comments on commit 75f3c40

Please sign in to comment.