Modify layout

This commit is contained in:
Lukas Martinelli 2016-12-04 17:03:36 +01:00
parent b5cfecec81
commit 02a7ccf831
6 changed files with 305 additions and 293 deletions

View file

@ -8,7 +8,7 @@
"build": "webpack --config webpack.production.config.js --progress --profile --colors",
"test": "karma start --single-run",
"test-watch": "karma start",
"start": "webpack-dev-server --progress --profile --colors",
"start": "webpack-dev-server --progress --profile --colors --watch-poll",
"lint": "eslint --ext js --ext jsx {src,test}"
},
"repository": {

View file

@ -12,55 +12,48 @@ import PureRenderMixin from 'react-addons-pure-render-mixin';
// List of collapsible layer editors
export class LayerList extends React.Component {
static propTypes = {
layers: React.PropTypes.instanceOf(Immutable.OrderedMap),
onLayersChanged: React.PropTypes.func.isRequired
}
static propTypes = {
layers: React.PropTypes.instanceOf(Immutable.OrderedMap),
onLayersChanged: React.PropTypes.func.isRequired
}
constructor(props) {
super(props)
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
}
constructor(props) {
super(props)
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
}
onLayerDestroyed(deletedLayer) {
const remainingLayers = this.props.layers.delete(deletedLayer.get('id'))
this.props.onLayersChanged(remainingLayers)
}
onLayerDestroyed(deletedLayer) {
const remainingLayers = this.props.layers.delete(deletedLayer.get('id'))
this.props.onLayersChanged(remainingLayers)
}
onLayerChanged(layer) {
const changedLayers = this.props.layers.set(layer.get('id'), layer)
this.props.onLayersChanged(changedLayers)
}
onLayerChanged(layer) {
const changedLayers = this.props.layers.set(layer.get('id'), layer)
this.props.onLayersChanged(changedLayers)
}
render() {
var layerPanels = []
layerPanels = this.props.layers.map(layer => {
return <LayerEditor
key={layer.get('id')}
layer={layer}
onLayerDestroyed={this.onLayerDestroyed.bind(this)}
onLayerChanged={this.onLayerChanged.bind(this)}
/>
}).toIndexedSeq()
render() {
var layerPanels = []
layerPanels = this.props.layers.map(layer => {
return <LayerEditor
key={layer.get('id')}
layer={layer}
onLayerDestroyed={this.onLayerDestroyed.bind(this)}
onLayerChanged={this.onLayerChanged.bind(this)}
/>
}).toIndexedSeq()
return <div>
<Toolbar style={{marginRight: 20}}>
<NavItem>
<Heading>Layers</Heading>
</NavItem>
<Space auto x={1} />
</Toolbar>
<div className={scrollbars.darkScrollbar} style={{
overflowY: "scroll",
bottom:0,
left:0,
right:0,
top:40,
position: "absolute",
}}>
{layerPanels}
</div>
</div>
}
return <div>
<div className={scrollbars.darkScrollbar} style={{
overflowY: "scroll",
bottom:0,
left:0,
right:0,
top:1,
position: "absolute",
}}>
{layerPanels}
</div>
</div>
}
}

View file

@ -1,12 +1,12 @@
.darkScrollbar::-webkit-scrollbar {
background-color: #313131;
width: 10px;
background-color: #26282e;
width: 10px;
}
.darkScrollbar::-webkit-scrollbar-thumb {
border-radius: 6px;
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
padding-left: 2px;
padding-right: 2px;
border-radius: 6px;
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #40444e;
padding-left: 2px;
padding-right: 2px;
}

View file

@ -1,112 +1,112 @@
const caps = {
textTransform: 'uppercase',
letterSpacing: '.2em'
textTransform: 'uppercase',
letterSpacing: '.2em'
}
export const fullHeight = {
position: "fixed",
top: 0,
bottom: 0,
height: "100%",
position: "fixed",
top: 0,
bottom: 0,
height: "100%",
}
const baseColors = {
black: '#242424',
gray: '#313131',
midgray: '#778',
lowgray: '#dcdcdc',
white: '#fff',
blue: '#00d9f7',
green: '#B4C7AD',
orange: '#fb3',
red: '#f04',
black: '#1c1f24',
gray: '#26282e',
midgray: '#36383e',
lowgray: '#8e8e8e',
white: '#fff',
blue: '#00d9f7',
green: '#B4C7AD',
orange: '#fb3',
red: '#f04',
}
const themeColors = {
primary: baseColors.gray,
secondary: baseColors.midgray,
default: baseColors.gray,
info: baseColors.blue,
success: baseColors.green,
warning: baseColors.orange,
error: baseColors.red
primary: baseColors.gray,
secondary: baseColors.midgray,
default: baseColors.gray,
info: baseColors.blue,
success: baseColors.green,
warning: baseColors.orange,
error: baseColors.red
}
export const colors = {
...baseColors,
...themeColors
...baseColors,
...themeColors
}
export const inputBase = {
display: 'block',
border: '1px solid rgb(36, 36, 36)',
height: 30,
width: '100%',
paddingLeft: 5,
paddingRight: 5,
backgroundColor: colors.gray,
display: 'block',
border: '1px solid rgb(36, 36, 36)',
height: 30,
width: '100%',
paddingLeft: 5,
paddingRight: 5,
backgroundColor: colors.gray,
}
const scale = [3, 5, 10, 30, 40]
const fontSizes = [28, 24, 20, 16, 14, 12, 10]
const border = {
borderColor: colors.black,
borderRadius: 0,
borderColor: colors.black,
borderRadius: 0,
}
const dark = {
name: 'Dark',
color: colors.white,
fontFamily: 'Roboto, sans-serif',
scale,
fontSizes,
colors,
inverted: colors.midGray,
...border,
name: 'Dark',
color: colors.white,
fontFamily: 'Roboto, sans-serif',
scale,
fontSizes,
colors,
inverted: colors.midGray,
...border,
Block: {
backgroundColor: colors.gray,
...border,
borderLeft: 0,
borderRight: 0,
marginBottom: 0,
paddingBottom: 0,
},
PanelHeader: {
marginRight: -10,
marginBottom: 0,
fontSize: fontSizes[5],
fontWeight: 400,
color: colors.white,
},
Button: {
color: '#00d9f7',
},
Menu: {
color: '#00d9f7',
backgroundColor: '#000'
},
Message: {
color: '#111',
opacity: 15/16
},
Header: {
fontWeight: 400,
},
ButtonCircle : {
},
Toolbar: {
fontWeight: 400,
minHeight: scale[3]
},
Label: {
fontWeight: 300,
},
Input: {
fontWeight: 300,
fontSize: fontSizes[5],
},
Block: {
backgroundColor: colors.gray,
...border,
borderLeft: 0,
borderRight: 0,
marginBottom: 0,
paddingBottom: 0,
},
PanelHeader: {
marginRight: -10,
marginBottom: 0,
fontSize: fontSizes[5],
fontWeight: 400,
color: colors.white,
},
Button: {
color: '#00d9f7',
},
Menu: {
color: '#00d9f7',
backgroundColor: '#000'
},
Message: {
color: '#111',
opacity: 15/16
},
Header: {
fontWeight: 400,
},
ButtonCircle : {
},
Toolbar: {
fontWeight: 400,
minHeight: scale[3]
},
Label: {
fontWeight: 300,
},
Input: {
fontWeight: 300,
fontSize: fontSizes[5],
},
}
export default dark

View file

@ -12,122 +12,140 @@ import Fixed from 'rebass/dist/Fixed'
import MdFileDownload from 'react-icons/lib/md/file-download'
import MdFileUpload from 'react-icons/lib/md/file-upload'
import MdOpenInBrowser from 'react-icons/lib/md/open-in-browser'
import MdSettings from 'react-icons/lib/md/settings'
import MdInfo from 'react-icons/lib/md/info'
import MdLayers from 'react-icons/lib/md/layers'
import MdSave from 'react-icons/lib/md/save'
import MdStyle from 'react-icons/lib/md/style'
import MdMap from 'react-icons/lib/md/map'
import MdInsertEmoticon from 'react-icons/lib/md/insert-emoticon'
import MdFontDownload from 'react-icons/lib/md/font-download'
import MdHelpOutline from 'react-icons/lib/md/help-outline'
import MdFindInPage from 'react-icons/lib/md/find-in-page'
import style from './style.js'
import { fullHeight } from './theme.js'
import theme from './theme.js';
const InlineBlock = props => <div style={{display: "inline-block", ...props.style}}>
{props.children}
</div>
export class Toolbar extends React.Component {
static propTypes = {
// A new style has been uploaded
onStyleUpload: React.PropTypes.func.isRequired,
// Current style is requested for download
onStyleDownload: React.PropTypes.func.isRequired,
// Style is explicitely saved to local cache
onStyleSave: React.PropTypes.func,
// Open settings drawer
onOpenSettings: React.PropTypes.func,
// Open about page
onOpenAbout: React.PropTypes.func,
// Open sources drawer
onOpenSources: React.PropTypes.func,
// Open layers drawer
onOpenLayers: React.PropTypes.func,
// Whether a style is available for download or saving
// A style with no layers should not be available
styleAvailable: React.PropTypes.bool,
}
static propTypes = {
// A new style has been uploaded
onStyleUpload: React.PropTypes.func.isRequired,
// Current style is requested for download
onStyleDownload: React.PropTypes.func.isRequired,
// Style is explicitely saved to local cache
onStyleSave: React.PropTypes.func,
// Open settings drawer
onOpenSettings: React.PropTypes.func,
// Open about page
onOpenAbout: React.PropTypes.func,
// Open sources drawer
onOpenSources: React.PropTypes.func,
// Open layers drawer
onOpenLayers: React.PropTypes.func,
// Whether a style is available for download or saving
// A style with no layers should not be available
styleAvailable: React.PropTypes.bool,
}
onUpload(_, files) {
const [e, file] = files[0];
const reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = e => {
let mapStyle = style.fromJSON(JSON.parse(e.target.result))
mapStyle = style.ensureMetadataExists(mapStyle)
this.props.onStyleUpload(mapStyle);
}
reader.onerror = e => console.log(e.target);
}
onUpload(_, files) {
const [e, file] = files[0];
const reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = e => {
let mapStyle = style.fromJSON(JSON.parse(e.target.result))
mapStyle = style.ensureMetadataExists(mapStyle)
this.props.onStyleUpload(mapStyle);
}
reader.onerror = e => console.log(e.target);
}
saveButton() {
if(this.props.styleAvailable) {
return <Block>
<Button onClick={this.props.onStyleSave} big={true}>
<Tooltip inverted rounded title="Save style">
<MdSave />
</Tooltip>
</Button>
</Block>
}
return null
}
saveButton() {
if(this.props.styleAvailable) {
return <InlineBlock>
<Button onClick={this.props.onStyleSave} big={true}>
<MdSave />
Save
</Button>
</InlineBlock>
}
return null
}
downloadButton() {
if(this.props.styleAvailable) {
return <Block>
<Button onClick={this.props.onStyleDownload} big={true}>
<Tooltip inverted rounded title="Download style">
<MdFileDownload />
</Tooltip>
</Button>
</Block>
}
return null
}
downloadButton() {
if(this.props.styleAvailable) {
return <InlineBlock>
<Button onClick={this.props.onStyleDownload} big={true}>
<MdFileDownload />
Download
</Button>
</InlineBlock>
}
return null
}
render() {
return <Container style={{
...fullHeight,
zIndex: 100,
left: 0,
top: 0,
backgroundColor: theme.colors.black }
}>
<Block>
<FileReaderInput onChange={this.onUpload.bind(this)}>
<Button big={true} theme={this.props.styleAvailable ? "default" : "success"}>
<Tooltip inverted rounded title="Upload style">
<MdFileUpload />
</Tooltip>
</Button>
</FileReaderInput>
</Block>
{this.downloadButton()}
{this.saveButton()}
<Block>
<Button big={true} onClick={this.props.onOpenLayers}>
<Tooltip inverted rounded title="Layers">
<MdLayers />
</Tooltip>
</Button>
</Block>
<Block>
<Button big={true} onClick={this.props.onOpenSources}>
<Tooltip inverted rounded title="Sources">
<MdMap />
</Tooltip>
</Button>
</Block>
<Block>
<Button big={true} onClick={this.props.onOpenSettings}>
<Tooltip inverted rounded title="Settings">
<MdSettings />
</Tooltip>
</Button>
</Block>
<Block>
<Button big={true} onClick={this.props.onOpenAbout}>
<Tooltip inverted rounded title="About">
<MdInfo />
</Tooltip>
</Button>
</Block>
</Container>
}
render() {
return <div style={{
position: "fixed",
height: 50,
width: '100%',
zIndex: 100,
left: 0,
top: 0,
backgroundColor: theme.colors.black
}}>
<InlineBlock>
<Button style={{width: 300, textAlign: 'left'}}>
<img src="https://github.com/maputnik/editor/raw/master/media/maputnik.png" alt="Maputnik" style={{width: 40, height: 40, paddingRight: 5, verticalAlign: 'middle'}}/>
<span style={{fontSize: 20 }}>Maputnik</span>
</Button>
</InlineBlock>
<InlineBlock>
<FileReaderInput onChange={this.onUpload.bind(this)}>
<Button big={true} theme={this.props.styleAvailable ? "default" : "success"}>
<MdOpenInBrowser />
Open
</Button>
</FileReaderInput>
</InlineBlock>
{this.downloadButton()}
{this.saveButton()}
<InlineBlock>
<Button big={true} onClick={this.props.onOpenSettings}>
<MdLayers />
Tilesets
</Button>
</InlineBlock>
<InlineBlock>
<Button big={true} onClick={this.props.onOpenSettings}>
<MdFontDownload />
Fonts
</Button>
</InlineBlock>
<InlineBlock>
<Button big={true} onClick={this.props.onOpenSettings}>
<MdInsertEmoticon/>
Icons
</Button>
</InlineBlock>
<InlineBlock>
<Button big={true} onClick={this.props.onOpenSettings}>
<MdFindInPage />
Inspect
</Button>
</InlineBlock>
<InlineBlock>
<Button big={true} onClick={this.props.onOpenAbout}>
<MdHelpOutline />
Help
</Button>
</InlineBlock>
</div>
}
}

View file

@ -8,65 +8,66 @@ import { colors, fullHeight } from './theme.js'
/** The workspace drawer contains the editor components depending on the edit
* context chosen in the toolbar. It holds the state of the layers.*/
export class WorkspaceDrawer extends React.Component {
static propTypes = {
mapStyle: React.PropTypes.object.isRequired,
onStyleChanged: React.PropTypes.func.isRequired,
workContext: React.PropTypes.oneOf(['layers', 'settings', 'sources']).isRequired,
accessToken: React.PropTypes.string,
onAccessTokenChanged: React.PropTypes.func,
onReset: React.PropTypes.func,
}
static propTypes = {
mapStyle: React.PropTypes.object.isRequired,
onStyleChanged: React.PropTypes.func.isRequired,
workContext: React.PropTypes.oneOf(['layers', 'settings', 'sources']).isRequired,
accessToken: React.PropTypes.string,
onAccessTokenChanged: React.PropTypes.func,
onReset: React.PropTypes.func,
}
onLayersChanged(changedLayers) {
const changedStyle = this.props.mapStyle.set('layers', changedLayers)
this.props.onStyleChanged(changedStyle)
}
onLayersChanged(changedLayers) {
const changedStyle = this.props.mapStyle.set('layers', changedLayers)
this.props.onStyleChanged(changedStyle)
}
onSourcesChanged(changedSources) {
const changedStyle = this.props.mapStyle.set('sources', changedSources)
this.props.onStyleChanged(changedStyle)
}
onSourcesChanged(changedSources) {
const changedStyle = this.props.mapStyle.set('sources', changedSources)
this.props.onStyleChanged(changedStyle)
}
render() {
let workspaceContent = null
render() {
let workspaceContent = null
if(this.props.workContext === "sources") {
workspaceContent = <SourceList
onSourcesChanged={this.onSourcesChanged.bind(this)}
sources={this.props.mapStyle.get('sources')}
/>
}
if(this.props.workContext === "sources") {
workspaceContent = <SourceList
onSourcesChanged={this.onSourcesChanged.bind(this)}
sources={this.props.mapStyle.get('sources')}
/>
}
if(this.props.workContext === "layers") {
workspaceContent = <LayerList
onLayersChanged={this.onLayersChanged.bind(this)}
layers={this.props.mapStyle.get('layers')}
/>
}
if(this.props.workContext === "layers") {
workspaceContent = <LayerList
onLayersChanged={this.onLayersChanged.bind(this)}
layers={this.props.mapStyle.get('layers')}
/>
}
if(this.props.workContext === "settings") {
workspaceContent = <SettingsEditor
onReset={this.props.onReset}
onStyleChanged={this.props.onStyleChanged}
mapStyle={this.props.mapStyle}
accessToken={this.props.accessToken}
onAccessTokenChanged={this.props.onAccessTokenChanged}
/>
}
if(this.props.workContext === "settings") {
workspaceContent = <SettingsEditor
onReset={this.props.onReset}
onStyleChanged={this.props.onStyleChanged}
mapStyle={this.props.mapStyle}
accessToken={this.props.accessToken}
onAccessTokenChanged={this.props.onAccessTokenChanged}
/>
}
if(this.props.workContext === "about") {
workspaceContent = <About />
}
if(this.props.workContext === "about") {
workspaceContent = <About />
}
return <div style={{
...fullHeight,
zIndex: 100,
left: 60,
width: 300,
overflow: "hidden",
backgroundColor: colors.gray}
}>
{workspaceContent}
</div>
}
return <div style={{
...fullHeight,
top: 50,
left: 0,
zIndex: 100,
width: 300,
overflow: "hidden",
backgroundColor: colors.gray}
}>
{workspaceContent}
</div>
}
}