mirror of
https://github.com/maputnik/editor.git
synced 2026-08-25 06:27:25 +00:00
Compare commits
3 Commits
a322afdcee
...
5312d61598
| Author | SHA1 | Date | |
|---|---|---|---|
| 5312d61598 | |||
| 56cdfd23df | |||
| 69143ea5d6 |
@@ -5,6 +5,9 @@
|
||||
- Add support for hillshade's color arrays and relief-color elevation expression
|
||||
- Change layers icons to make them a bit more distinct
|
||||
- Remove `@mdi` packages in favor of `react-icons`
|
||||
- Add ability to control the projection of the map - either globe or mercator
|
||||
- Add markdown support for doc related to the style-spec fields
|
||||
- Added global state modal to allow editing the global state
|
||||
- _...Add new stuff here..._
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
@@ -491,6 +491,20 @@ describe("layers", () => {
|
||||
when.click("field-doc-button-Offset", 0);
|
||||
then(get.elementByTestId("spec-field-doc")).shouldContainText("Offset distance");
|
||||
});
|
||||
|
||||
it.only("should hide spec info when clicking a second time", () => {
|
||||
when.modal.fillLayers({
|
||||
type: "symbol",
|
||||
layer: "example",
|
||||
});
|
||||
|
||||
when.hover("spec-field-container:text-rotate");
|
||||
then(get.elementByTestId("field-doc-button-Rotate")).shouldBeVisible();
|
||||
when.click("field-doc-button-Rotate", 0);
|
||||
when.wait(200);
|
||||
when.click("field-doc-button-Rotate", 0);
|
||||
then(get.elementByTestId("spec-field-doc")).shouldNotBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
describe("raster", () => {
|
||||
|
||||
@@ -236,6 +236,29 @@ describe("modals", () => {
|
||||
).shouldInclude({ "maputnik:locationiq_access_token": apiKey });
|
||||
});
|
||||
|
||||
it("style projection mercator", () => {
|
||||
when.select("modal:settings.projection", "mercator");
|
||||
then(
|
||||
get.styleFromLocalStorage().then((style) => style.projection)
|
||||
).shouldInclude({ type: "mercator" });
|
||||
});
|
||||
|
||||
it("style projection globe", () => {
|
||||
when.select("modal:settings.projection", "globe");
|
||||
then(
|
||||
get.styleFromLocalStorage().then((style) => style.projection)
|
||||
).shouldInclude({ type: "globe" });
|
||||
});
|
||||
|
||||
|
||||
it("style projection vertical-perspective", () => {
|
||||
when.select("modal:settings.projection", "vertical-perspective");
|
||||
then(
|
||||
get.styleFromLocalStorage().then((style) => style.projection)
|
||||
).shouldInclude({ type: "vertical-perspective" });
|
||||
|
||||
});
|
||||
|
||||
it("style renderer", () => {
|
||||
cy.on("uncaught:exception", () => false); // this is due to the fact that this is an invalid style for openlayers
|
||||
when.select("modal:settings.maputnik:renderer", "ol");
|
||||
@@ -304,6 +327,57 @@ describe("modals", () => {
|
||||
it("toggle");
|
||||
});
|
||||
|
||||
describe("global state", () => {
|
||||
beforeEach(() => {
|
||||
when.click("nav:global-state");
|
||||
});
|
||||
|
||||
it("add variable", () => {
|
||||
when.click("global-state-add-variable");
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
state: { key1: { default: "value" } },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("add multiple variables", () => {
|
||||
when.click("global-state-add-variable");
|
||||
when.click("global-state-add-variable");
|
||||
when.click("global-state-add-variable");
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
state: { key1: { default: "value" }, key2: { default: "value" }, key3: { default: "value" } },
|
||||
});
|
||||
});
|
||||
|
||||
it("remove variable", () => {
|
||||
when.click("global-state-add-variable");
|
||||
when.click("global-state-add-variable");
|
||||
when.click("global-state-add-variable");
|
||||
when.click("global-state-remove-variable", 0);
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
state: { key2: { default: "value" }, key3: { default: "value" } },
|
||||
});
|
||||
});
|
||||
|
||||
it("edit variable key", () => {
|
||||
when.click("global-state-add-variable");
|
||||
when.setValue("global-state-variable-key:0", "mykey");
|
||||
when.typeKeys("{enter}");
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
state: { mykey: { default: "value" } },
|
||||
});
|
||||
});
|
||||
|
||||
it("edit variable value", () => {
|
||||
when.click("global-state-add-variable");
|
||||
when.setValue("global-state-variable-value:0", "myvalue");
|
||||
when.typeKeys("{enter}");
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
state: { key1: { default: "myvalue" } },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Handle localStorage QuotaExceededError", () => {
|
||||
it("handles quota exceeded error when opening style from URL", () => {
|
||||
// Clear localStorage to start fresh
|
||||
|
||||
Generated
+1169
-16
File diff suppressed because it is too large
Load Diff
@@ -69,6 +69,7 @@
|
||||
"react-file-reader-input": "^2.0.0",
|
||||
"react-i18next": "^15.7.3",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"slugify": "^1.6.6",
|
||||
"string-hash": "^1.1.3",
|
||||
|
||||
+21
-6
@@ -25,6 +25,7 @@ import ModalSources from "./modals/ModalSources";
|
||||
import ModalOpen from "./modals/ModalOpen";
|
||||
import ModalShortcuts from "./modals/ModalShortcuts";
|
||||
import ModalDebug from "./modals/ModalDebug";
|
||||
import ModalGlobalState from "./modals/ModalGlobalState";
|
||||
|
||||
import {downloadGlyphsMetadata, downloadSpriteMetadata} from "../libs/metadata";
|
||||
import style from "../libs/style";
|
||||
@@ -126,6 +127,7 @@ type AppState = {
|
||||
shortcuts: boolean
|
||||
export: boolean
|
||||
debug: boolean
|
||||
globalState: boolean
|
||||
}
|
||||
fileHandle: FileSystemFileHandle | null
|
||||
};
|
||||
@@ -164,6 +166,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
shortcuts: false,
|
||||
export: false,
|
||||
debug: false,
|
||||
globalState: false,
|
||||
},
|
||||
maplibreGlDebugOptions: {
|
||||
showTileBoundaries: false,
|
||||
@@ -213,6 +216,12 @@ export default class App extends React.Component<any, AppState> {
|
||||
this.toggleModal("settings");
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "g",
|
||||
handler: () => {
|
||||
this.toggleModal("globalState");
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "i",
|
||||
handler: () => {
|
||||
@@ -911,39 +920,45 @@ export default class App extends React.Component<any, AppState> {
|
||||
onChangeMaplibreGlDebug={this.onChangeMaplibreGlDebug}
|
||||
onChangeOpenlayersDebug={this.onChangeOpenlayersDebug}
|
||||
isOpen={this.state.isOpen.debug}
|
||||
onOpenToggle={this.toggleModal.bind(this, "debug")}
|
||||
onOpenToggle={() => this.toggleModal("debug")}
|
||||
mapView={this.state.mapView}
|
||||
/>
|
||||
<ModalShortcuts
|
||||
isOpen={this.state.isOpen.shortcuts}
|
||||
onOpenToggle={this.toggleModal.bind(this, "shortcuts")}
|
||||
onOpenToggle={() => this.toggleModal("shortcuts")}
|
||||
/>
|
||||
<ModalSettings
|
||||
mapStyle={this.state.mapStyle}
|
||||
onStyleChanged={this.onStyleChanged}
|
||||
onChangeMetadataProperty={this.onChangeMetadataProperty}
|
||||
isOpen={this.state.isOpen.settings}
|
||||
onOpenToggle={this.toggleModal.bind(this, "settings")}
|
||||
onOpenToggle={() => this.toggleModal("settings")}
|
||||
/>
|
||||
<ModalExport
|
||||
mapStyle={this.state.mapStyle}
|
||||
onStyleChanged={this.onStyleChanged}
|
||||
isOpen={this.state.isOpen.export}
|
||||
onOpenToggle={this.toggleModal.bind(this, "export")}
|
||||
onOpenToggle={() => this.toggleModal("export")}
|
||||
fileHandle={this.state.fileHandle}
|
||||
onSetFileHandle={this.onSetFileHandle}
|
||||
/>
|
||||
<ModalOpen
|
||||
isOpen={this.state.isOpen.open}
|
||||
onStyleOpen={this.openStyle}
|
||||
onOpenToggle={this.toggleModal.bind(this, "open")}
|
||||
onOpenToggle={() => this.toggleModal("open")}
|
||||
fileHandle={this.state.fileHandle}
|
||||
/>
|
||||
<ModalSources
|
||||
mapStyle={this.state.mapStyle}
|
||||
onStyleChanged={this.onStyleChanged}
|
||||
isOpen={this.state.isOpen.sources}
|
||||
onOpenToggle={this.toggleModal.bind(this, "sources")}
|
||||
onOpenToggle={() => this.toggleModal("sources")}
|
||||
/>
|
||||
<ModalGlobalState
|
||||
mapStyle={this.state.mapStyle}
|
||||
onStyleChanged={this.onStyleChanged}
|
||||
isOpen={this.state.isOpen.globalState}
|
||||
onOpenToggle={() => this.toggleModal("globalState")}
|
||||
/>
|
||||
</div>;
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
MdHelpOutline,
|
||||
MdFindInPage,
|
||||
MdLanguage,
|
||||
MdSave
|
||||
MdSave,
|
||||
MdPublic
|
||||
} from "react-icons/md";
|
||||
import pkgJson from "../../package.json";
|
||||
//@ts-ignore
|
||||
@@ -236,6 +237,10 @@ class AppToolbarInternal extends React.Component<AppToolbarInternalProps> {
|
||||
<MdSettings />
|
||||
<IconText>{t("Style Settings")}</IconText>
|
||||
</ToolbarAction>
|
||||
<ToolbarAction wdKey="nav:global-state" onClick={this.props.onToggleModal.bind(this, "globalState")}>
|
||||
<MdPublic />
|
||||
<IconText>{t("Global State")}</IconText>
|
||||
</ToolbarAction>
|
||||
|
||||
<ToolbarSelect wdKey="nav:inspect">
|
||||
<MdFindInPage />
|
||||
|
||||
+16
-4
@@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import Markdown from "react-markdown";
|
||||
|
||||
const headers = {
|
||||
js: "JS",
|
||||
android: "Android",
|
||||
ios: "iOS",
|
||||
macos: "macOS",
|
||||
ios: "iOS"
|
||||
};
|
||||
|
||||
type DocProps = {
|
||||
@@ -37,11 +37,23 @@ export default class Doc extends React.Component<DocProps> {
|
||||
!Array.isArray(values)
|
||||
);
|
||||
|
||||
const sdkSupportToJsx = (value: string) => {
|
||||
const supportValue = value.toLowerCase();
|
||||
if (supportValue.startsWith("https://")) {
|
||||
return <a href={supportValue} target="_blank" rel="noreferrer">{"#" + supportValue.split("/").pop()}</a>;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{doc &&
|
||||
<div className="SpecDoc">
|
||||
<div className="SpecDoc__doc" data-wd-key='spec-field-doc'>{doc}</div>
|
||||
<div className="SpecDoc__doc" data-wd-key='spec-field-doc'>
|
||||
<Markdown components={{
|
||||
a: ({node: _node, href, children, ...props}) => <a href={href} target="_blank" {...props}>{children}</a>,
|
||||
}}>{doc}</Markdown>
|
||||
</div>
|
||||
{renderValues &&
|
||||
<ul className="SpecDoc__values">
|
||||
{Object.entries(values).map(([key, value]) => {
|
||||
@@ -74,7 +86,7 @@ export default class Doc extends React.Component<DocProps> {
|
||||
<td>{key}</td>
|
||||
{Object.keys(headers).map((k) => {
|
||||
if (Object.prototype.hasOwnProperty.call(supportObj, k)) {
|
||||
return <td key={k}>{supportObj[k as keyof typeof headers]}</td>;
|
||||
return <td key={k}>{sdkSupportToJsx(supportObj[k as keyof typeof headers])}</td>;
|
||||
}
|
||||
else {
|
||||
return <td key={k}>no</td>;
|
||||
|
||||
@@ -8,7 +8,7 @@ type ModalInternalProps = PropsWithChildren & {
|
||||
"data-wd-key"?: string
|
||||
isOpen: boolean
|
||||
title: string
|
||||
onOpenToggle(value: boolean): unknown
|
||||
onOpenToggle(): void
|
||||
underlayClickExits?: boolean
|
||||
className?: string
|
||||
} & WithTranslation;
|
||||
@@ -26,7 +26,7 @@ class ModalInternal extends React.Component<ModalInternalProps> {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.props.onOpenToggle(false);
|
||||
this.props.onOpenToggle();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ type ModalAddInternalProps = {
|
||||
layers: LayerSpecification[]
|
||||
onLayersChange(layers: LayerSpecification[]): unknown
|
||||
isOpen: boolean
|
||||
onOpenToggle(open: boolean): unknown
|
||||
onOpenToggle(): void
|
||||
// A dict of source id's and the available source layers
|
||||
sources: Record<string, SourceSpecification & {layers: string[]}>;
|
||||
} & WithTranslation;
|
||||
@@ -50,7 +50,7 @@ class ModalAddInternal extends React.Component<ModalAddInternalProps, ModalAddSt
|
||||
changedLayers.push(layer as LayerSpecification);
|
||||
this.setState({ error: null }, () => {
|
||||
this.props.onLayersChange(changedLayers);
|
||||
this.props.onOpenToggle(false);
|
||||
this.props.onOpenToggle();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ type ModalDebugInternalProps = {
|
||||
renderer: string
|
||||
onChangeMaplibreGlDebug(key: string, checked: boolean): unknown
|
||||
onChangeOpenlayersDebug(key: string, checked: boolean): unknown
|
||||
onOpenToggle(value: boolean): unknown
|
||||
onOpenToggle(): void
|
||||
maplibreGlDebugOptions?: object
|
||||
openlayersDebugOptions?: object
|
||||
mapView: {
|
||||
|
||||
@@ -22,7 +22,7 @@ type ModalExportInternalProps = {
|
||||
mapStyle: StyleSpecificationWithId
|
||||
onStyleChanged: OnStyleChangedCallback
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onOpenToggle(): void
|
||||
onSetFileHandle(fileHandle: FileSystemFileHandle | null): unknown
|
||||
fileHandle: FileSystemFileHandle | null
|
||||
} & WithTranslation;
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import React from "react";
|
||||
import { withTranslation, type WithTranslation } from "react-i18next";
|
||||
import { MdDelete } from "react-icons/md";
|
||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||
|
||||
import Modal from "./Modal";
|
||||
import FieldString from "../FieldString";
|
||||
import InputButton from "../InputButton";
|
||||
import { PiListPlusBold } from "react-icons/pi";
|
||||
import { type StyleSpecificationWithId } from "../../libs/definitions";
|
||||
import { type SchemaSpecification } from "maplibre-gl";
|
||||
import Doc from "../Doc";
|
||||
|
||||
type ModalGlobalStateInternalProps = {
|
||||
mapStyle: StyleSpecificationWithId;
|
||||
isOpen: boolean;
|
||||
onStyleChanged(style: StyleSpecificationWithId): void;
|
||||
onOpenToggle(): void
|
||||
} & WithTranslation;
|
||||
|
||||
type GlobalStateVariable = {
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
|
||||
const ModalGlobalStateInternal: React.FC<ModalGlobalStateInternalProps> = (props) => {
|
||||
const getGlobalStateVariables = (): GlobalStateVariable[] => {
|
||||
const style = props.mapStyle;
|
||||
const globalState = style.state || {};
|
||||
|
||||
return Object.entries(globalState).map(([key, value]) => ({
|
||||
key,
|
||||
value: value.default
|
||||
}));
|
||||
};
|
||||
|
||||
const setGlobalStateVariables = (variables: GlobalStateVariable[]) => {
|
||||
const style = { ...props.mapStyle };
|
||||
|
||||
// Create the globalState object from the variables array
|
||||
const globalState: Record<string, SchemaSpecification> = {};
|
||||
for (const variable of variables) {
|
||||
if (variable.key.trim() !== "") {
|
||||
globalState[variable.key] = {
|
||||
default: variable.value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
style.state = Object.keys(globalState).length > 0 ? globalState : undefined;
|
||||
|
||||
props.onStyleChanged(style);
|
||||
};
|
||||
|
||||
const onAddVariable = () => {
|
||||
const variables = getGlobalStateVariables();
|
||||
let index = 1;
|
||||
while (variables.find(v => v.key === `key${index}`)) {
|
||||
index++;
|
||||
}
|
||||
variables.push({ key: `key${index}`, value: "value" });
|
||||
setGlobalStateVariables(variables);
|
||||
};
|
||||
|
||||
const onRemoveVariable = (index: number) => {
|
||||
const variables = getGlobalStateVariables();
|
||||
variables.splice(index, 1);
|
||||
setGlobalStateVariables(variables);
|
||||
};
|
||||
|
||||
const onChangeVariableKey = (index: number, newKey: string) => {
|
||||
const variables = getGlobalStateVariables();
|
||||
variables[index].key = newKey || "";
|
||||
setGlobalStateVariables(variables);
|
||||
};
|
||||
|
||||
const onChangeVariableValue = (index: number, newValue: string) => {
|
||||
const variables = getGlobalStateVariables();
|
||||
|
||||
variables[index].value = newValue || "";
|
||||
setGlobalStateVariables(variables);
|
||||
};
|
||||
|
||||
const variables = getGlobalStateVariables();
|
||||
|
||||
const variableFields = variables.map((variable, index) => (
|
||||
<tr key={index}>
|
||||
<td>
|
||||
<FieldString
|
||||
label={props.t("Key")}
|
||||
value={variable.key}
|
||||
onChange={(value) => onChangeVariableKey(index, value || "")}
|
||||
data-wd-key={"global-state-variable-key:" + index}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<FieldString
|
||||
label={props.t("Value")}
|
||||
value={variable.value}
|
||||
onChange={(value) => onChangeVariableValue(index, value || "")}
|
||||
data-wd-key={"global-state-variable-value:" + index}
|
||||
/>
|
||||
</td>
|
||||
<td style={{ verticalAlign: "middle"}}>
|
||||
<InputButton
|
||||
onClick={() => onRemoveVariable(index)}
|
||||
title={props.t("Remove variable")}
|
||||
data-wd-key="global-state-remove-variable"
|
||||
>
|
||||
<MdDelete />
|
||||
</InputButton>
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
|
||||
return (
|
||||
<Modal
|
||||
data-wd-key="modal:global-state"
|
||||
isOpen={props.isOpen}
|
||||
onOpenToggle={props.onOpenToggle}
|
||||
title={props.t("Global State Variables")}
|
||||
>
|
||||
|
||||
{variables.length === 0 &&
|
||||
<div>
|
||||
<p>{props.t("No global state variables defined. Add variables to create reusable values in your style.")}</p>
|
||||
<div key="doc" className="maputnik-doc-inline">
|
||||
<Doc fieldSpec={latest.$root.state} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{variables.length > 0 &&
|
||||
<table>
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
{variableFields}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
<div>
|
||||
<InputButton
|
||||
onClick={onAddVariable}
|
||||
data-wd-key="global-state-add-variable"
|
||||
>
|
||||
<PiListPlusBold />
|
||||
{props.t("Add Variable")}
|
||||
</InputButton>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const ModalGlobalState = withTranslation()(ModalGlobalStateInternal);
|
||||
export default ModalGlobalState;
|
||||
@@ -45,7 +45,7 @@ class PublicStyle extends React.Component<PublicStyleProps> {
|
||||
|
||||
type ModalOpenInternalProps = {
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onOpenToggle(): void
|
||||
onStyleOpen(...args: unknown[]): unknown
|
||||
fileHandle: FileSystemFileHandle | null
|
||||
} & WithTranslation;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||
import type {LightSpecification, StyleSpecification, TerrainSpecification, TransitionSpecification} from "maplibre-gl";
|
||||
import type {LightSpecification, ProjectionSpecification, StyleSpecification, TerrainSpecification, TransitionSpecification} from "maplibre-gl";
|
||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||
|
||||
import FieldArray from "../FieldArray";
|
||||
@@ -19,7 +19,7 @@ type ModalSettingsInternalProps = {
|
||||
onStyleChanged: OnStyleChangedCallback
|
||||
onChangeMetadataProperty(...args: unknown[]): unknown
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onOpenToggle(): void
|
||||
} & WithTranslation;
|
||||
|
||||
class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps> {
|
||||
@@ -79,6 +79,24 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
});
|
||||
}
|
||||
|
||||
changeProjectionType(value: any) {
|
||||
const projection = {
|
||||
...this.props.mapStyle.projection,
|
||||
} as ProjectionSpecification;
|
||||
|
||||
if (value === undefined) {
|
||||
delete projection.type;
|
||||
}
|
||||
else {
|
||||
projection.type = value;
|
||||
}
|
||||
|
||||
this.props.onStyleChanged({
|
||||
...this.props.mapStyle,
|
||||
projection,
|
||||
});
|
||||
}
|
||||
|
||||
changeStyleProperty(property: keyof StyleSpecification | "owner", value: any) {
|
||||
const changedStyle = {
|
||||
...this.props.mapStyle,
|
||||
@@ -103,6 +121,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
const light = this.props.mapStyle.light || {};
|
||||
const transition = this.props.mapStyle.transition || {};
|
||||
const terrain = this.props.mapStyle.terrain || {} as TerrainSpecification;
|
||||
const projection = this.props.mapStyle.projection || {} as ProjectionSpecification;
|
||||
|
||||
return <Modal
|
||||
data-wd-key="modal:settings"
|
||||
@@ -116,21 +135,21 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.$root.name}
|
||||
data-wd-key="modal:settings.name"
|
||||
value={this.props.mapStyle.name}
|
||||
onChange={this.changeStyleProperty.bind(this, "name")}
|
||||
onChange={(value) => this.changeStyleProperty("name", value)}
|
||||
/>
|
||||
<FieldString
|
||||
label={t("Owner")}
|
||||
fieldSpec={{doc: t("Owner ID of the style. Used by Mapbox or future style APIs.")}}
|
||||
data-wd-key="modal:settings.owner"
|
||||
value={(this.props.mapStyle as any).owner}
|
||||
onChange={this.changeStyleProperty.bind(this, "owner")}
|
||||
onChange={(value) => this.changeStyleProperty("owner", value)}
|
||||
/>
|
||||
<FieldUrl
|
||||
fieldSpec={latest.$root.sprite}
|
||||
label={t("Sprite URL")}
|
||||
data-wd-key="modal:settings.sprite"
|
||||
value={this.props.mapStyle.sprite as string}
|
||||
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
||||
onChange={(value) => this.changeStyleProperty("sprite", value)}
|
||||
/>
|
||||
|
||||
<FieldUrl
|
||||
@@ -138,7 +157,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.$root.glyphs}
|
||||
data-wd-key="modal:settings.glyphs"
|
||||
value={this.props.mapStyle.glyphs as string}
|
||||
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
||||
onChange={(value) => this.changeStyleProperty("glyphs", value)}
|
||||
/>
|
||||
|
||||
<FieldString
|
||||
@@ -146,7 +165,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={fsa.maputnik.maptiler_access_token}
|
||||
data-wd-key="modal:settings.maputnik:openmaptiles_access_token"
|
||||
value={metadata["maputnik:openmaptiles_access_token"]}
|
||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
||||
onChange={(value) => onChangeMetadataProperty("maputnik:openmaptiles_access_token", value)}
|
||||
/>
|
||||
|
||||
<FieldString
|
||||
@@ -154,7 +173,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={fsa.maputnik.thunderforest_access_token}
|
||||
data-wd-key="modal:settings.maputnik:thunderforest_access_token"
|
||||
value={metadata["maputnik:thunderforest_access_token"]}
|
||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
|
||||
onChange={(value) => onChangeMetadataProperty("maputnik:thunderforest_access_token", value)}
|
||||
/>
|
||||
|
||||
<FieldString
|
||||
@@ -162,7 +181,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={fsa.maputnik.stadia_access_token}
|
||||
data-wd-key="modal:settings.maputnik:stadia_access_token"
|
||||
value={metadata["maputnik:stadia_access_token"]}
|
||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:stadia_access_token")}
|
||||
onChange={(value) => onChangeMetadataProperty("maputnik:stadia_access_token", value)}
|
||||
/>
|
||||
|
||||
<FieldString
|
||||
@@ -170,7 +189,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={fsa.maputnik.locationiq_access_token}
|
||||
data-wd-key="modal:settings.maputnik:locationiq_access_token"
|
||||
value={metadata["maputnik:locationiq_access_token"]}
|
||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:locationiq_access_token")}
|
||||
onChange={(value) => onChangeMetadataProperty("maputnik:locationiq_access_token", value)}
|
||||
/>
|
||||
|
||||
<FieldArray
|
||||
@@ -180,7 +199,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
type="number"
|
||||
value={mapStyle.center || []}
|
||||
default={[0, 0]}
|
||||
onChange={this.changeStyleProperty.bind(this, "center")}
|
||||
onChange={(value) => this.changeStyleProperty("center", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -188,7 +207,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.$root.zoom}
|
||||
value={mapStyle.zoom}
|
||||
default={0}
|
||||
onChange={this.changeStyleProperty.bind(this, "zoom")}
|
||||
onChange={(value) => this.changeStyleProperty("zoom", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -196,7 +215,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.$root.bearing}
|
||||
value={mapStyle.bearing}
|
||||
default={latest.$root.bearing.default}
|
||||
onChange={this.changeStyleProperty.bind(this, "bearing")}
|
||||
onChange={(value) => this.changeStyleProperty("bearing", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -204,7 +223,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.$root.pitch}
|
||||
value={mapStyle.pitch}
|
||||
default={latest.$root.pitch.default}
|
||||
onChange={this.changeStyleProperty.bind(this, "pitch")}
|
||||
onChange={(value) => this.changeStyleProperty("pitch", value)}
|
||||
/>
|
||||
|
||||
<FieldEnum
|
||||
@@ -214,7 +233,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
value={light.anchor as string}
|
||||
options={Object.keys(latest.light.anchor.values)}
|
||||
default={latest.light.anchor.default}
|
||||
onChange={this.changeLightProperty.bind(this, "anchor")}
|
||||
onChange={(value) => this.changeLightProperty("anchor", value)}
|
||||
/>
|
||||
|
||||
<FieldColor
|
||||
@@ -222,7 +241,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.light.color}
|
||||
value={light.color as string}
|
||||
default={latest.light.color.default}
|
||||
onChange={this.changeLightProperty.bind(this, "color")}
|
||||
onChange={(value) => this.changeLightProperty("color", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -230,7 +249,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.light.intensity}
|
||||
value={light.intensity as number}
|
||||
default={latest.light.intensity.default}
|
||||
onChange={this.changeLightProperty.bind(this, "intensity")}
|
||||
onChange={(value) => this.changeLightProperty("intensity", value)}
|
||||
/>
|
||||
|
||||
<FieldArray
|
||||
@@ -240,7 +259,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
length={latest.light.position.length}
|
||||
value={light.position as number[]}
|
||||
default={latest.light.position.default}
|
||||
onChange={this.changeLightProperty.bind(this, "position")}
|
||||
onChange={(value) => this.changeLightProperty("position", value)}
|
||||
/>
|
||||
|
||||
<FieldString
|
||||
@@ -248,7 +267,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.terrain.source}
|
||||
data-wd-key="modal:settings.maputnik:terrain_source"
|
||||
value={terrain.source}
|
||||
onChange={this.changeTerrainProperty.bind(this, "source")}
|
||||
onChange={(value) => this.changeTerrainProperty("source", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -256,7 +275,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.terrain.exaggeration}
|
||||
value={terrain.exaggeration}
|
||||
default={latest.terrain.exaggeration.default}
|
||||
onChange={this.changeTerrainProperty.bind(this, "exaggeration")}
|
||||
onChange={(value) => this.changeTerrainProperty("exaggeration", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -264,7 +283,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.transition.delay}
|
||||
value={transition.delay}
|
||||
default={latest.transition.delay.default}
|
||||
onChange={this.changeTransitionProperty.bind(this, "delay")}
|
||||
onChange={(value) => this.changeTransitionProperty("delay", value)}
|
||||
/>
|
||||
|
||||
<FieldNumber
|
||||
@@ -272,7 +291,20 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
fieldSpec={latest.transition.duration}
|
||||
value={transition.duration}
|
||||
default={latest.transition.duration.default}
|
||||
onChange={this.changeTransitionProperty.bind(this, "duration")}
|
||||
onChange={(value) => this.changeTransitionProperty("duration", value)}
|
||||
/>
|
||||
|
||||
<FieldSelect
|
||||
label={t("Projection")}
|
||||
data-wd-key="modal:settings.projection"
|
||||
options={[
|
||||
["", "Undefined"],
|
||||
["mercator", "Mercator"],
|
||||
["globe", "Globe"],
|
||||
["vertical-perspective", "Vertical Perspective"]
|
||||
]}
|
||||
value={projection?.type?.toString() || ""}
|
||||
onChange={(value) => this.changeProjectionType(value)}
|
||||
/>
|
||||
|
||||
<FieldSelect
|
||||
@@ -284,7 +316,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
||||
["ol", t("Open Layers (experimental)")],
|
||||
]}
|
||||
value={metadata["maputnik:renderer"] || "mlgljs"}
|
||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:renderer")}
|
||||
onChange={(value) => onChangeMetadataProperty("maputnik:renderer", value)}
|
||||
/>
|
||||
</div>
|
||||
</Modal>;
|
||||
|
||||
@@ -6,7 +6,7 @@ import Modal from "./Modal";
|
||||
|
||||
type ModalShortcutsInternalProps = {
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onOpenToggle(): void
|
||||
} & WithTranslation;
|
||||
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class AddSource extends React.Component<AddSourceProps, AddSourceState> {
|
||||
type ModalSourcesInternalProps = {
|
||||
mapStyle: StyleSpecificationWithId
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onOpenToggle(): void
|
||||
onStyleChanged: OnStyleChangedCallback
|
||||
} & WithTranslation;
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
margin-top: vars.$margin-3;
|
||||
}
|
||||
|
||||
.SpecDoc__values code {
|
||||
.SpecDoc__values code, .SpecDoc__doc code {
|
||||
background: vars.$color-midgray;
|
||||
padding: 0.1em 0.3em;
|
||||
border-radius: 2px;
|
||||
|
||||
Reference in New Issue
Block a user