@jupytergis/base 0.10.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/BaseCommandIDs.d.ts +2 -0
- package/lib/commands/BaseCommandIDs.js +3 -0
- package/lib/commands/index.js +66 -0
- package/lib/constants.js +4 -0
- package/lib/dialogs/symbology/hooks/useGetBandInfo.d.ts +0 -6
- package/lib/dialogs/symbology/hooks/useGetBandInfo.js +2 -2
- package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.js +4 -4
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +1 -5
- package/lib/formbuilder/formselectors.js +5 -1
- package/lib/formbuilder/objectform/StoryEditorForm.d.ts +9 -0
- package/lib/formbuilder/objectform/StoryEditorForm.js +16 -0
- package/lib/formbuilder/objectform/components/StorySegmentReset.d.ts +8 -0
- package/lib/formbuilder/objectform/components/StorySegmentReset.js +24 -0
- package/lib/formbuilder/objectform/layer/index.d.ts +1 -0
- package/lib/formbuilder/objectform/layer/index.js +1 -0
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +5 -0
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +32 -0
- package/lib/mainview/mainView.d.ts +18 -0
- package/lib/mainview/mainView.js +293 -14
- package/lib/panelview/components/layers.d.ts +2 -1
- package/lib/panelview/components/layers.js +31 -23
- package/lib/panelview/{components/filter-panel → filter-panel}/Filter.js +1 -1
- package/lib/panelview/leftpanel.js +89 -7
- package/lib/panelview/rightpanel.d.ts +2 -0
- package/lib/panelview/rightpanel.js +41 -4
- package/lib/panelview/story-maps/PreviewModeSwitch.d.ts +7 -0
- package/lib/panelview/story-maps/PreviewModeSwitch.js +13 -0
- package/lib/panelview/story-maps/StoryEditorPanel.d.ts +9 -0
- package/lib/panelview/story-maps/StoryEditorPanel.js +34 -0
- package/lib/panelview/story-maps/StoryNavBar.d.ts +10 -0
- package/lib/panelview/story-maps/StoryNavBar.js +11 -0
- package/lib/panelview/story-maps/StoryViewerPanel.d.ts +13 -0
- package/lib/panelview/story-maps/StoryViewerPanel.js +179 -0
- package/lib/panelview/story-maps/components/StoryContentSection.d.ts +6 -0
- package/lib/panelview/story-maps/components/StoryContentSection.js +10 -0
- package/lib/panelview/story-maps/components/StoryImageSection.d.ts +15 -0
- package/lib/panelview/story-maps/components/StoryImageSection.js +13 -0
- package/lib/panelview/story-maps/components/StorySubtitleSection.d.ts +11 -0
- package/lib/panelview/story-maps/components/StorySubtitleSection.js +9 -0
- package/lib/panelview/story-maps/components/StoryTitleSection.d.ts +12 -0
- package/lib/panelview/story-maps/components/StoryTitleSection.js +8 -0
- package/lib/shared/components/Calendar.d.ts +1 -1
- package/lib/shared/components/Combobox.d.ts +21 -0
- package/lib/shared/components/Combobox.js +32 -0
- package/lib/shared/components/Command.d.ts +18 -0
- package/lib/shared/components/Command.js +60 -0
- package/lib/shared/components/Dialog.d.ts +15 -0
- package/lib/shared/components/Dialog.js +62 -0
- package/lib/shared/components/Input.d.ts +3 -0
- package/lib/shared/components/Input.js +18 -0
- package/lib/shared/components/Pagination.js +3 -2
- package/lib/shared/components/RadioGroup.d.ts +5 -0
- package/lib/shared/components/RadioGroup.js +26 -0
- package/lib/shared/components/Select.d.ts +19 -0
- package/lib/shared/components/Select.js +28 -0
- package/lib/shared/components/SingleDatePicker.d.ts +11 -0
- package/lib/shared/components/SingleDatePicker.js +16 -0
- package/lib/shared/components/Switch.d.ts +4 -0
- package/lib/shared/components/Switch.js +20 -0
- package/lib/stacBrowser/components/StacPanel.d.ts +9 -1
- package/lib/stacBrowser/components/StacPanel.js +53 -9
- package/lib/stacBrowser/components/filter-extension/QueryableComboBox.d.ts +9 -0
- package/lib/stacBrowser/components/filter-extension/QueryableComboBox.js +179 -0
- package/lib/stacBrowser/components/filter-extension/QueryableRow.d.ts +16 -0
- package/lib/stacBrowser/components/filter-extension/QueryableRow.js +16 -0
- package/lib/stacBrowser/components/filter-extension/StacFilterExtensionPanel.d.ts +7 -0
- package/lib/stacBrowser/components/filter-extension/StacFilterExtensionPanel.js +49 -0
- package/lib/stacBrowser/components/filter-extension/StacQueryableFilters.d.ts +11 -0
- package/lib/stacBrowser/components/filter-extension/StacQueryableFilters.js +19 -0
- package/lib/stacBrowser/components/{StacFilterSection.d.ts → geodes/StacFilterSection.d.ts} +1 -1
- package/lib/stacBrowser/components/{StacFilterSection.js → geodes/StacFilterSection.js} +3 -3
- package/lib/stacBrowser/components/geodes/StacGeodesFilterPanel.d.ts +7 -0
- package/lib/stacBrowser/components/geodes/StacGeodesFilterPanel.js +69 -0
- package/lib/stacBrowser/components/shared/StacPanelResults.d.ts +3 -0
- package/lib/stacBrowser/components/shared/StacPanelResults.js +68 -0
- package/lib/stacBrowser/components/shared/StacSpatialExtent.d.ts +8 -0
- package/lib/stacBrowser/components/shared/StacSpatialExtent.js +10 -0
- package/lib/stacBrowser/components/shared/StacTemporalExtent.d.ts +9 -0
- package/lib/stacBrowser/components/shared/StacTemporalExtent.js +9 -0
- package/lib/stacBrowser/context/StacResultsContext.d.ts +33 -0
- package/lib/stacBrowser/context/StacResultsContext.js +269 -0
- package/lib/stacBrowser/hooks/useGeodesSearch.d.ts +24 -0
- package/lib/stacBrowser/hooks/useGeodesSearch.js +178 -0
- package/lib/stacBrowser/hooks/useStacFilterExtension.d.ts +30 -0
- package/lib/stacBrowser/hooks/useStacFilterExtension.js +262 -0
- package/lib/stacBrowser/hooks/useStacSearch.d.ts +5 -16
- package/lib/stacBrowser/hooks/useStacSearch.js +30 -184
- package/lib/stacBrowser/types/types.d.ts +86 -3
- package/lib/toolbar/widget.d.ts +15 -0
- package/lib/toolbar/widget.js +70 -0
- package/lib/tools.d.ts +0 -7
- package/lib/tools.js +56 -15
- package/package.json +8 -3
- package/style/base.css +42 -3
- package/style/leftPanel.css +18 -0
- package/style/shared/button.css +6 -5
- package/style/shared/calendar.css +7 -1
- package/style/shared/combobox.css +75 -0
- package/style/shared/command.css +178 -0
- package/style/shared/dialog.css +177 -0
- package/style/shared/input.css +59 -0
- package/style/shared/pagination.css +1 -1
- package/style/shared/popover.css +1 -0
- package/style/shared/radioGroup.css +55 -0
- package/style/shared/switch.css +63 -0
- package/style/shared/tabs.css +4 -3
- package/style/shared/toggle.css +1 -1
- package/style/stacBrowser.css +169 -16
- package/style/statusBar.css +1 -0
- package/style/storyPanel.css +185 -0
- package/style/tabPanel.css +1 -88
- package/lib/stacBrowser/components/StacPanelFilters.d.ts +0 -14
- package/lib/stacBrowser/components/StacPanelFilters.js +0 -81
- package/lib/stacBrowser/components/StacPanelResults.d.ts +0 -13
- package/lib/stacBrowser/components/StacPanelResults.js +0 -48
- /package/lib/panelview/{components/filter-panel → filter-panel}/Filter.d.ts +0 -0
- /package/lib/panelview/{components/filter-panel → filter-panel}/FilterRow.d.ts +0 -0
- /package/lib/panelview/{components/filter-panel → filter-panel}/FilterRow.js +0 -0
- /package/lib/panelview/{components/identify-panel → identify-panel}/IdentifyPanel.d.ts +0 -0
- /package/lib/panelview/{components/identify-panel → identify-panel}/IdentifyPanel.js +0 -0
|
@@ -1,29 +1,109 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { LayersBodyComponent } from './components/layers';
|
|
3
|
+
import FilterComponent from './filter-panel/Filter';
|
|
3
4
|
import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
|
|
4
5
|
import StacPanel from '../stacBrowser/components/StacPanel';
|
|
5
|
-
import FilterComponent from './components/filter-panel/Filter';
|
|
6
6
|
export const LeftPanel = (props) => {
|
|
7
|
+
var _a;
|
|
7
8
|
const [settings, setSettings] = React.useState(props.model.jgisSettings);
|
|
9
|
+
const [options, setOptions] = React.useState(props.model.getOptions());
|
|
10
|
+
const storyMapPresentationMode = (_a = options.storyMapPresentationMode) !== null && _a !== void 0 ? _a : false;
|
|
11
|
+
const [layerTree, setLayerTree] = React.useState(props.model.getLayerTree());
|
|
8
12
|
React.useEffect(() => {
|
|
9
13
|
const onSettingsChanged = () => {
|
|
10
14
|
setSettings(Object.assign({}, props.model.jgisSettings));
|
|
11
15
|
};
|
|
16
|
+
const onOptionsChanged = () => {
|
|
17
|
+
setOptions(Object.assign({}, props.model.getOptions()));
|
|
18
|
+
};
|
|
19
|
+
const updateLayerTree = () => {
|
|
20
|
+
setLayerTree(props.model.getLayerTree() || []);
|
|
21
|
+
};
|
|
12
22
|
props.model.settingsChanged.connect(onSettingsChanged);
|
|
23
|
+
props.model.sharedOptionsChanged.connect(onOptionsChanged);
|
|
24
|
+
props.model.sharedModel.layersChanged.connect(updateLayerTree);
|
|
25
|
+
props.model.sharedModel.layerTreeChanged.connect(updateLayerTree);
|
|
26
|
+
updateLayerTree();
|
|
13
27
|
return () => {
|
|
14
28
|
props.model.settingsChanged.disconnect(onSettingsChanged);
|
|
29
|
+
props.model.sharedOptionsChanged.disconnect(onOptionsChanged);
|
|
30
|
+
props.model.sharedModel.layersChanged.disconnect(updateLayerTree);
|
|
31
|
+
props.model.sharedModel.layerTreeChanged.disconnect(updateLayerTree);
|
|
15
32
|
};
|
|
16
33
|
}, [props.model]);
|
|
34
|
+
// Since story segments are technically layers they are stored in the layer tree, so we separate them
|
|
35
|
+
// from regular layers. Process the tree once to build both filtered and story segment trees.
|
|
36
|
+
const { filteredLayerTree, storySegmentLayerTree } = React.useMemo(() => {
|
|
37
|
+
const filtered = [];
|
|
38
|
+
const storySegments = [];
|
|
39
|
+
const processLayer = (layer) => {
|
|
40
|
+
if (typeof layer === 'string') {
|
|
41
|
+
const layerData = props.model.getLayer(layer);
|
|
42
|
+
const isStorySegment = (layerData === null || layerData === void 0 ? void 0 : layerData.type) === 'StorySegmentLayer';
|
|
43
|
+
return {
|
|
44
|
+
filtered: isStorySegment ? null : layer,
|
|
45
|
+
storySegment: isStorySegment ? layer : null,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// For layer groups, recursively process their layers
|
|
49
|
+
const filteredGroupLayers = [];
|
|
50
|
+
const storySegmentGroupLayers = [];
|
|
51
|
+
for (const groupLayer of layer.layers) {
|
|
52
|
+
const result = processLayer(groupLayer);
|
|
53
|
+
if (result.filtered !== null) {
|
|
54
|
+
filteredGroupLayers.push(result.filtered);
|
|
55
|
+
}
|
|
56
|
+
if (result.storySegment !== null) {
|
|
57
|
+
storySegmentGroupLayers.push(result.storySegment);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
filtered: filteredGroupLayers.length > 0
|
|
62
|
+
? Object.assign(Object.assign({}, layer), { layers: filteredGroupLayers }) : null,
|
|
63
|
+
storySegment: storySegmentGroupLayers.length > 0
|
|
64
|
+
? Object.assign(Object.assign({}, layer), { layers: storySegmentGroupLayers }) : null,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
for (const layer of layerTree) {
|
|
68
|
+
const result = processLayer(layer);
|
|
69
|
+
if (result.filtered !== null) {
|
|
70
|
+
filtered.push(result.filtered);
|
|
71
|
+
}
|
|
72
|
+
if (result.storySegment !== null) {
|
|
73
|
+
storySegments.push(result.storySegment);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Reverse filteredLayerTree before returning
|
|
77
|
+
filtered.reverse();
|
|
78
|
+
return {
|
|
79
|
+
filteredLayerTree: filtered,
|
|
80
|
+
storySegmentLayerTree: storySegments,
|
|
81
|
+
};
|
|
82
|
+
}, [layerTree]);
|
|
83
|
+
// Updates story segments array based on layer tree array
|
|
84
|
+
React.useEffect(() => {
|
|
85
|
+
const { storyId, story } = props.model.getSelectedStory();
|
|
86
|
+
if (!story) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
props.model.sharedModel.updateStoryMap(storyId, Object.assign(Object.assign({}, story), { storySegments: storySegmentLayerTree }));
|
|
90
|
+
}, [storySegmentLayerTree]);
|
|
17
91
|
const allLeftTabsDisabled = settings.layersDisabled &&
|
|
18
92
|
settings.stacBrowserDisabled &&
|
|
19
|
-
settings.filtersDisabled
|
|
93
|
+
settings.filtersDisabled &&
|
|
94
|
+
settings.storyMapsDisabled;
|
|
20
95
|
const leftPanelVisible = !settings.leftPanelDisabled && !allLeftTabsDisabled;
|
|
21
96
|
const tabInfo = [
|
|
22
97
|
!settings.layersDisabled ? { name: 'layers', title: 'Layers' } : false,
|
|
23
|
-
!settings.stacBrowserDisabled
|
|
98
|
+
!settings.stacBrowserDisabled && !storyMapPresentationMode
|
|
24
99
|
? { name: 'stac', title: 'Stac Browser' }
|
|
25
100
|
: false,
|
|
26
|
-
!settings.filtersDisabled
|
|
101
|
+
!settings.filtersDisabled && !storyMapPresentationMode
|
|
102
|
+
? { name: 'filters', title: 'Filters' }
|
|
103
|
+
: false,
|
|
104
|
+
!settings.storyMapsDisabled
|
|
105
|
+
? { name: 'segments', title: 'Segments' }
|
|
106
|
+
: false,
|
|
27
107
|
].filter(Boolean);
|
|
28
108
|
const [curTab, setCurTab] = React.useState(tabInfo.length > 0 ? tabInfo[0].name : undefined);
|
|
29
109
|
return (React.createElement("div", { className: "jgis-left-panel-container", style: { display: leftPanelVisible ? 'block' : 'none' } },
|
|
@@ -37,9 +117,11 @@ export const LeftPanel = (props) => {
|
|
|
37
117
|
}
|
|
38
118
|
} }, tab.title)))),
|
|
39
119
|
!settings.layersDisabled && (React.createElement(TabsContent, { value: "layers", className: "jgis-panel-tab-content jp-gis-layerPanel" },
|
|
40
|
-
React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state }))),
|
|
41
|
-
!settings.stacBrowserDisabled && (React.createElement(TabsContent, { value: "stac", className: "jgis-panel-tab-content" },
|
|
120
|
+
React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state, layerTree: filteredLayerTree }))),
|
|
121
|
+
!settings.stacBrowserDisabled && (React.createElement(TabsContent, { value: "stac", className: "jgis-panel-tab-content jgis-panel-tab-content-stac-panel" },
|
|
42
122
|
React.createElement(StacPanel, { model: props.model }))),
|
|
43
123
|
!settings.filtersDisabled && (React.createElement(TabsContent, { value: "filters", className: "jgis-panel-tab-content" },
|
|
44
|
-
React.createElement(FilterComponent, { model: props.model })))
|
|
124
|
+
React.createElement(FilterComponent, { model: props.model }))),
|
|
125
|
+
!settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "segments", className: "jgis-panel-tab-content" },
|
|
126
|
+
React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state, layerTree: storySegmentLayerTree }))))));
|
|
45
127
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { IAnnotationModel, IJGISFormSchemaRegistry, IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
interface IRightPanelProps {
|
|
4
5
|
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
5
6
|
annotationModel: IAnnotationModel;
|
|
6
7
|
model: IJupyterGISModel;
|
|
8
|
+
commands: CommandRegistry;
|
|
7
9
|
}
|
|
8
10
|
export declare const RightPanel: React.FC<IRightPanelProps>;
|
|
9
11
|
export {};
|
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { AnnotationsPanel } from './annotationPanel';
|
|
3
|
-
import { IdentifyPanelComponent } from './
|
|
3
|
+
import { IdentifyPanelComponent } from './identify-panel/IdentifyPanel';
|
|
4
4
|
import { ObjectPropertiesReact } from './objectproperties';
|
|
5
|
+
import { PreviewModeSwitch } from './story-maps/PreviewModeSwitch';
|
|
6
|
+
import StoryEditorPanel from './story-maps/StoryEditorPanel';
|
|
7
|
+
import StoryViewerPanel from './story-maps/StoryViewerPanel';
|
|
5
8
|
import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
|
|
6
9
|
export const RightPanel = props => {
|
|
10
|
+
var _a;
|
|
11
|
+
const [editorMode, setEditorMode] = React.useState(true);
|
|
7
12
|
const [settings, setSettings] = React.useState(props.model.jgisSettings);
|
|
13
|
+
const [storyMapPresentationMode, setStoryMapPresentationMode] = React.useState((_a = props.model.getOptions().storyMapPresentationMode) !== null && _a !== void 0 ? _a : false);
|
|
14
|
+
// Only show editor when not in presentation mode and editorMode is true
|
|
15
|
+
const showEditor = !storyMapPresentationMode && editorMode;
|
|
16
|
+
// Tab title: "Story Map" in presentation mode, otherwise based on editorMode
|
|
17
|
+
const storyPanelTitle = storyMapPresentationMode
|
|
18
|
+
? 'Story Map'
|
|
19
|
+
: editorMode
|
|
20
|
+
? 'Story Editor'
|
|
21
|
+
: 'Story Map';
|
|
8
22
|
const tabInfo = [
|
|
9
|
-
!settings.objectPropertiesDisabled
|
|
23
|
+
!settings.objectPropertiesDisabled && !storyMapPresentationMode
|
|
10
24
|
? { name: 'objectProperties', title: 'Object Properties' }
|
|
11
25
|
: false,
|
|
26
|
+
!settings.storyMapsDisabled
|
|
27
|
+
? {
|
|
28
|
+
name: 'storyPanel',
|
|
29
|
+
title: storyPanelTitle,
|
|
30
|
+
}
|
|
31
|
+
: false,
|
|
12
32
|
!settings.annotationsDisabled
|
|
13
33
|
? { name: 'annotations', title: 'Annotations' }
|
|
14
34
|
: false,
|
|
@@ -16,11 +36,20 @@ export const RightPanel = props => {
|
|
|
16
36
|
? { name: 'identifyPanel', title: 'Identified Features' }
|
|
17
37
|
: false,
|
|
18
38
|
].filter(Boolean);
|
|
19
|
-
const [curTab, setCurTab] = React.useState(
|
|
39
|
+
const [curTab, setCurTab] = React.useState(() => {
|
|
40
|
+
if (storyMapPresentationMode) {
|
|
41
|
+
return 'storyPanel';
|
|
42
|
+
}
|
|
43
|
+
return tabInfo.length > 0 ? tabInfo[0].name : '';
|
|
44
|
+
});
|
|
20
45
|
React.useEffect(() => {
|
|
21
46
|
const onSettingsChanged = () => {
|
|
22
47
|
setSettings(Object.assign({}, props.model.jgisSettings));
|
|
23
48
|
};
|
|
49
|
+
const onOptionsChanged = () => {
|
|
50
|
+
const { storyMapPresentationMode } = props.model.getOptions();
|
|
51
|
+
setStoryMapPresentationMode(storyMapPresentationMode !== null && storyMapPresentationMode !== void 0 ? storyMapPresentationMode : false);
|
|
52
|
+
};
|
|
24
53
|
let currentlyIdentifiedFeatures = undefined;
|
|
25
54
|
const onAwerenessChanged = (_, clients) => {
|
|
26
55
|
var _a;
|
|
@@ -34,9 +63,11 @@ export const RightPanel = props => {
|
|
|
34
63
|
}
|
|
35
64
|
};
|
|
36
65
|
props.model.settingsChanged.connect(onSettingsChanged);
|
|
66
|
+
props.model.sharedOptionsChanged.connect(onOptionsChanged);
|
|
37
67
|
props.model.clientStateChanged.connect(onAwerenessChanged);
|
|
38
68
|
return () => {
|
|
39
69
|
props.model.settingsChanged.disconnect(onSettingsChanged);
|
|
70
|
+
props.model.sharedOptionsChanged.disconnect(onOptionsChanged);
|
|
40
71
|
props.model.clientStateChanged.disconnect(onAwerenessChanged);
|
|
41
72
|
};
|
|
42
73
|
}, [props.model]);
|
|
@@ -45,9 +76,12 @@ export const RightPanel = props => {
|
|
|
45
76
|
settings.identifyDisabled;
|
|
46
77
|
const rightPanelVisible = !settings.rightPanelDisabled && !allRightTabsDisabled;
|
|
47
78
|
const [selectedObjectProperties, setSelectedObjectProperties] = React.useState(undefined);
|
|
79
|
+
const toggleEditor = () => {
|
|
80
|
+
setEditorMode(!editorMode);
|
|
81
|
+
};
|
|
48
82
|
return (React.createElement("div", { className: "jgis-right-panel-container", style: { display: rightPanelVisible ? 'block' : 'none' } },
|
|
49
83
|
React.createElement(PanelTabs, { className: "jgis-panel-tabs", curTab: curTab },
|
|
50
|
-
React.createElement(TabsList, null, tabInfo.map(tab => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", key: tab.name
|
|
84
|
+
React.createElement(TabsList, null, tabInfo.map(tab => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", key: `${tab.name}-${tab.title}`, value: tab.name, onClick: () => {
|
|
51
85
|
if (curTab !== tab.name) {
|
|
52
86
|
setCurTab(tab.name);
|
|
53
87
|
}
|
|
@@ -57,6 +91,9 @@ export const RightPanel = props => {
|
|
|
57
91
|
} }, tab.title)))),
|
|
58
92
|
!settings.objectPropertiesDisabled && (React.createElement(TabsContent, { value: "objectProperties", className: "jgis-panel-tab-content" },
|
|
59
93
|
React.createElement(ObjectPropertiesReact, { setSelectedObject: setSelectedObjectProperties, selectedObject: selectedObjectProperties, formSchemaRegistry: props.formSchemaRegistry, model: props.model }))),
|
|
94
|
+
!settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "storyPanel", className: "jgis-panel-tab-content", style: { paddingTop: 0 } },
|
|
95
|
+
!storyMapPresentationMode && (React.createElement(PreviewModeSwitch, { checked: !editorMode, onCheckedChange: toggleEditor })),
|
|
96
|
+
showEditor ? (React.createElement(StoryEditorPanel, { model: props.model, commands: props.commands })) : (React.createElement(StoryViewerPanel, { model: props.model, isSpecta: false })))),
|
|
60
97
|
!settings.annotationsDisabled && (React.createElement(TabsContent, { value: "annotations", className: "jgis-panel-tab-content" },
|
|
61
98
|
React.createElement(AnnotationsPanel, { annotationModel: props.annotationModel, jgisModel: props.model }))),
|
|
62
99
|
!settings.identifyDisabled && (React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Switch } from "../../shared/components/Switch";
|
|
3
|
+
export function PreviewModeSwitch({ checked, onCheckedChange, }) {
|
|
4
|
+
return (React.createElement("div", { style: {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
alignItems: 'center',
|
|
7
|
+
gap: '0.5rem',
|
|
8
|
+
padding: '1rem',
|
|
9
|
+
paddingBottom: '0',
|
|
10
|
+
} },
|
|
11
|
+
React.createElement("label", { htmlFor: "preview-mode-switch", style: { fontSize: '0.875rem' } }, "Preview Mode"),
|
|
12
|
+
React.createElement(Switch, { id: "preview-mode-switch", checked: checked, onCheckedChange: onCheckedChange })));
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
interface IStoryPanelProps {
|
|
5
|
+
model: IJupyterGISModel;
|
|
6
|
+
commands: CommandRegistry;
|
|
7
|
+
}
|
|
8
|
+
export declare function StoryEditorPanel({ model, commands }: IStoryPanelProps): React.JSX.Element;
|
|
9
|
+
export default StoryEditorPanel;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { faLink } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
+
import jgisSchema from '@jupytergis/schema/lib/schema/project/jgis.json';
|
|
4
|
+
import React, { useMemo } from 'react';
|
|
5
|
+
import { CommandIDs } from "../../constants";
|
|
6
|
+
import { StoryEditorPropertiesForm } from "../../formbuilder/objectform/StoryEditorForm";
|
|
7
|
+
import { Button } from "../../shared/components/Button";
|
|
8
|
+
import { deepCopy } from "../../tools";
|
|
9
|
+
const storyMapSchema = deepCopy(jgisSchema.definitions.jGISStoryMap);
|
|
10
|
+
const AddStorySegmentButton = ({ model, commands }) => (React.createElement("div", { style: { display: 'flex', justifyContent: 'center' } },
|
|
11
|
+
React.createElement(Button, { onClick: () => commands.execute(CommandIDs.addStorySegment) },
|
|
12
|
+
React.createElement(FontAwesomeIcon, { icon: faLink }),
|
|
13
|
+
" Add Story Segment")));
|
|
14
|
+
export function StoryEditorPanel({ model, commands }) {
|
|
15
|
+
const { storyId, story } = useMemo(() => {
|
|
16
|
+
return model.getSelectedStory();
|
|
17
|
+
}, [model, model.sharedModel.stories]);
|
|
18
|
+
const syncStoryData = (properties) => {
|
|
19
|
+
var _a;
|
|
20
|
+
// Preserve storySegments when updating, since the form removes it from the UI
|
|
21
|
+
const updatedStory = Object.assign(Object.assign(Object.assign({}, story), properties), { storySegments: (_a = story === null || story === void 0 ? void 0 : story.storySegments) !== null && _a !== void 0 ? _a : [] });
|
|
22
|
+
model.sharedModel.updateStoryMap(storyId, updatedStory);
|
|
23
|
+
};
|
|
24
|
+
if (!story) {
|
|
25
|
+
return (React.createElement("div", { style: { padding: '1rem' } },
|
|
26
|
+
React.createElement("p", null, "No Story Map available."),
|
|
27
|
+
React.createElement("p", null, "Add a Story Segment from the Add Layer menu. A segment captures the current map view. You can add markdown text and an image to each segment to tell your story."),
|
|
28
|
+
React.createElement(AddStorySegmentButton, { model: model, commands: commands })));
|
|
29
|
+
}
|
|
30
|
+
return (React.createElement("div", { className: "jgis-story-editor-panel" },
|
|
31
|
+
React.createElement(StoryEditorPropertiesForm, { formContext: "update", sourceData: story, model: model, schema: storyMapSchema, syncData: syncStoryData, filePath: model.filePath }),
|
|
32
|
+
React.createElement(AddStorySegmentButton, { model: model, commands: commands })));
|
|
33
|
+
}
|
|
34
|
+
export default StoryEditorPanel;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IStoryNavBarProps {
|
|
3
|
+
onPrev: () => void;
|
|
4
|
+
onNext: () => void;
|
|
5
|
+
hasPrev: boolean;
|
|
6
|
+
hasNext: boolean;
|
|
7
|
+
isSpecta: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function StoryNavBar({ onPrev, onNext, hasPrev, hasNext, isSpecta, }: IStoryNavBarProps): React.JSX.Element;
|
|
10
|
+
export default StoryNavBar;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Button } from "../../shared/components/Button";
|
|
4
|
+
function StoryNavBar({ onPrev, onNext, hasPrev, hasNext, isSpecta, }) {
|
|
5
|
+
return (React.createElement("div", { className: `jgis-story-navbar ${isSpecta ? 'jgis-story-navbar-specta-mod' : ''}` },
|
|
6
|
+
React.createElement(Button, { onClick: onPrev, disabled: !hasPrev, "aria-label": "Previous slide" },
|
|
7
|
+
React.createElement(ChevronLeft, null)),
|
|
8
|
+
React.createElement(Button, { onClick: onNext, disabled: !hasNext, "aria-label": "Next slide" },
|
|
9
|
+
React.createElement(ChevronRight, null))));
|
|
10
|
+
}
|
|
11
|
+
export default StoryNavBar;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
interface IStoryViewerPanelProps {
|
|
4
|
+
model: IJupyterGISModel;
|
|
5
|
+
isSpecta: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface IStoryViewerPanelHandle {
|
|
8
|
+
handlePrev: () => void;
|
|
9
|
+
handleNext: () => void;
|
|
10
|
+
canNavigate: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const StoryViewerPanel: React.ForwardRefExoticComponent<IStoryViewerPanelProps & React.RefAttributes<IStoryViewerPanelHandle>>;
|
|
13
|
+
export default StoryViewerPanel;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
|
|
2
|
+
import StoryContentSection from './components/StoryContentSection';
|
|
3
|
+
import StoryImageSection from './components/StoryImageSection';
|
|
4
|
+
import StorySubtitleSection from './components/StorySubtitleSection';
|
|
5
|
+
import StoryTitleSection from './components/StoryTitleSection';
|
|
6
|
+
const StoryViewerPanel = forwardRef(({ model, isSpecta }, ref) => {
|
|
7
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
8
|
+
const [currentIndexDisplayed, setCurrentIndexDisplayed] = useState(0);
|
|
9
|
+
const [storyData, setStoryData] = useState((_a = model.getSelectedStory().story) !== null && _a !== void 0 ? _a : null);
|
|
10
|
+
const [imageLoaded, setImageLoaded] = useState(false);
|
|
11
|
+
const panelRef = useRef(null);
|
|
12
|
+
// Derive story segments from story data
|
|
13
|
+
const storySegments = useMemo(() => {
|
|
14
|
+
if (!(storyData === null || storyData === void 0 ? void 0 : storyData.storySegments)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
return storyData.storySegments
|
|
18
|
+
.map(storySegmentId => model.getLayer(storySegmentId))
|
|
19
|
+
.filter((layer) => layer !== undefined);
|
|
20
|
+
}, [storyData, model]);
|
|
21
|
+
// Derive current story segment from story segments and currentIndexDisplayed
|
|
22
|
+
const currentStorySegment = useMemo(() => {
|
|
23
|
+
return storySegments[currentIndexDisplayed];
|
|
24
|
+
}, [storySegments, currentIndexDisplayed]);
|
|
25
|
+
// Derive active slide and layer name from current story segment
|
|
26
|
+
const activeSlide = useMemo(() => {
|
|
27
|
+
return currentStorySegment === null || currentStorySegment === void 0 ? void 0 : currentStorySegment.parameters;
|
|
28
|
+
}, [currentStorySegment]);
|
|
29
|
+
const layerName = useMemo(() => {
|
|
30
|
+
var _a;
|
|
31
|
+
return (_a = currentStorySegment === null || currentStorySegment === void 0 ? void 0 : currentStorySegment.name) !== null && _a !== void 0 ? _a : '';
|
|
32
|
+
}, [currentStorySegment]);
|
|
33
|
+
// Derive story segment ID for zooming
|
|
34
|
+
const currentStorySegmentId = useMemo(() => {
|
|
35
|
+
var _a;
|
|
36
|
+
return (_a = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) === null || _a === void 0 ? void 0 : _a[currentIndexDisplayed];
|
|
37
|
+
}, [storyData, currentIndexDisplayed]);
|
|
38
|
+
const zoomToCurrentLayer = () => {
|
|
39
|
+
if (currentStorySegmentId) {
|
|
40
|
+
model.centerOnPosition(currentStorySegmentId);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const setSelectedLayerByIndex = useCallback((index) => {
|
|
44
|
+
var _a;
|
|
45
|
+
const storySegmentId = (_a = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) === null || _a === void 0 ? void 0 : _a[index];
|
|
46
|
+
if (storySegmentId) {
|
|
47
|
+
model.selected = {
|
|
48
|
+
[storySegmentId]: {
|
|
49
|
+
type: 'layer',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}, [storyData, model]);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const updateStory = () => {
|
|
56
|
+
const { story } = model.getSelectedStory();
|
|
57
|
+
setStoryData(story !== null && story !== void 0 ? story : null);
|
|
58
|
+
// Reset to first slide when story changes
|
|
59
|
+
setCurrentIndexDisplayed(0);
|
|
60
|
+
};
|
|
61
|
+
updateStory();
|
|
62
|
+
model.sharedModel.storyMapsChanged.connect(updateStory);
|
|
63
|
+
return () => {
|
|
64
|
+
model.sharedModel.storyMapsChanged.disconnect(updateStory);
|
|
65
|
+
};
|
|
66
|
+
}, [model]);
|
|
67
|
+
// Prefetch image when slide changes
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
var _a;
|
|
70
|
+
const imageUrl = (_a = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _a === void 0 ? void 0 : _a.image;
|
|
71
|
+
if (!imageUrl) {
|
|
72
|
+
setImageLoaded(false);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Reset state
|
|
76
|
+
setImageLoaded(false);
|
|
77
|
+
// Preload the image
|
|
78
|
+
const img = new Image();
|
|
79
|
+
img.onload = () => {
|
|
80
|
+
setImageLoaded(true);
|
|
81
|
+
};
|
|
82
|
+
img.onerror = () => {
|
|
83
|
+
setImageLoaded(false);
|
|
84
|
+
};
|
|
85
|
+
img.src = imageUrl;
|
|
86
|
+
// Cleanup: abort loading if component unmounts or slide changes
|
|
87
|
+
return () => {
|
|
88
|
+
img.onload = null;
|
|
89
|
+
img.onerror = null;
|
|
90
|
+
};
|
|
91
|
+
}, [(_b = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _b === void 0 ? void 0 : _b.image]);
|
|
92
|
+
// Auto-zoom when slide changes
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (currentStorySegmentId) {
|
|
95
|
+
zoomToCurrentLayer();
|
|
96
|
+
}
|
|
97
|
+
}, [currentStorySegmentId, model]);
|
|
98
|
+
// Set selected layer on initial render and when story data changes
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if ((storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) && currentIndexDisplayed >= 0) {
|
|
101
|
+
setSelectedLayerByIndex(currentIndexDisplayed);
|
|
102
|
+
}
|
|
103
|
+
}, [storyData, currentIndexDisplayed, setSelectedLayerByIndex]);
|
|
104
|
+
// Listen for layer selection changes in unguided mode
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
// ! TODO this logic (getting a single selected layer) is also in the processing index.ts, move to tools
|
|
107
|
+
const handleSelectedStorySegmentChange = () => {
|
|
108
|
+
var _a, _b;
|
|
109
|
+
// This is just to update the displayed content
|
|
110
|
+
// So bail early if we don't need to do that
|
|
111
|
+
if (!storyData || storyData.storyType !== 'unguided') {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const localState = model.sharedModel.awareness.getLocalState();
|
|
115
|
+
if (!localState || !((_a = localState['selected']) === null || _a === void 0 ? void 0 : _a.value)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const selectedLayers = Object.keys(localState['selected'].value);
|
|
119
|
+
// Ensure only one layer is selected
|
|
120
|
+
if (selectedLayers.length !== 1) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const selectedLayerId = selectedLayers[0];
|
|
124
|
+
const selectedLayer = model.getLayer(selectedLayerId);
|
|
125
|
+
if (!selectedLayer || selectedLayer.type !== 'StorySegmentLayer') {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const index = (_b = storyData.storySegments) === null || _b === void 0 ? void 0 : _b.indexOf(selectedLayerId);
|
|
129
|
+
if (index === undefined || index === -1) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
setCurrentIndexDisplayed(index);
|
|
133
|
+
};
|
|
134
|
+
model.sharedModel.awareness.on('change', handleSelectedStorySegmentChange);
|
|
135
|
+
return () => {
|
|
136
|
+
model.sharedModel.awareness.off('change', handleSelectedStorySegmentChange);
|
|
137
|
+
};
|
|
138
|
+
}, [model, storyData]);
|
|
139
|
+
const handlePrev = useCallback(() => {
|
|
140
|
+
if (currentIndexDisplayed > 0) {
|
|
141
|
+
const newIndex = currentIndexDisplayed - 1;
|
|
142
|
+
setCurrentIndexDisplayed(newIndex);
|
|
143
|
+
}
|
|
144
|
+
}, [currentIndexDisplayed]);
|
|
145
|
+
const handleNext = useCallback(() => {
|
|
146
|
+
if (currentIndexDisplayed < storySegments.length - 1) {
|
|
147
|
+
const newIndex = currentIndexDisplayed + 1;
|
|
148
|
+
setCurrentIndexDisplayed(newIndex);
|
|
149
|
+
}
|
|
150
|
+
}, [currentIndexDisplayed, storySegments.length]);
|
|
151
|
+
// Expose methods via ref for parent component to use
|
|
152
|
+
useImperativeHandle(ref, () => ({
|
|
153
|
+
handlePrev,
|
|
154
|
+
handleNext,
|
|
155
|
+
canNavigate: isSpecta,
|
|
156
|
+
}), [handlePrev, handleNext, storyData, isSpecta]);
|
|
157
|
+
if (!storyData || ((_c = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) === null || _c === void 0 ? void 0 : _c.length) === 0) {
|
|
158
|
+
return (React.createElement("div", { style: { padding: '1rem' } },
|
|
159
|
+
React.createElement("p", null, "No Segments available. Add one using the Add Layer menu.")));
|
|
160
|
+
}
|
|
161
|
+
const navProps = {
|
|
162
|
+
onPrev: handlePrev,
|
|
163
|
+
onNext: handleNext,
|
|
164
|
+
hasPrev: currentIndexDisplayed > 0,
|
|
165
|
+
hasNext: currentIndexDisplayed < storySegments.length - 1,
|
|
166
|
+
};
|
|
167
|
+
// Get transition time from current segment, default to 0.3s
|
|
168
|
+
const transitionTime = (_e = (_d = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.transition) === null || _d === void 0 ? void 0 : _d.time) !== null && _e !== void 0 ? _e : 0.3;
|
|
169
|
+
return (React.createElement("div", { ref: panelRef, className: `jgis-story-viewer-panel ${isSpecta ? 'jgis-story-viewer-panel-specta-mod' : ''}` },
|
|
170
|
+
React.createElement("div", { key: currentIndexDisplayed, className: "jgis-story-segment-container", style: {
|
|
171
|
+
animationDuration: `${transitionTime}s`,
|
|
172
|
+
} },
|
|
173
|
+
React.createElement("h1", { className: "jgis-story-viewer-title" }, layerName !== null && layerName !== void 0 ? layerName : `Slide ${currentIndexDisplayed + 1}`),
|
|
174
|
+
((_f = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _f === void 0 ? void 0 : _f.image) && imageLoaded ? (React.createElement(StoryImageSection, Object.assign({ imageUrl: activeSlide.content.image, imageLoaded: imageLoaded, layerName: layerName !== null && layerName !== void 0 ? layerName : '', slideNumber: currentIndexDisplayed, isSpecta: isSpecta, storyType: (_g = storyData.storyType) !== null && _g !== void 0 ? _g : 'guided' }, navProps))) : (React.createElement(StoryTitleSection, Object.assign({ title: (_h = storyData.title) !== null && _h !== void 0 ? _h : '', isSpecta: isSpecta, storyType: (_j = storyData.storyType) !== null && _j !== void 0 ? _j : 'guided' }, navProps))),
|
|
175
|
+
React.createElement(StorySubtitleSection, Object.assign({ title: (_l = (_k = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _k === void 0 ? void 0 : _k.title) !== null && _l !== void 0 ? _l : '', isSpecta: isSpecta }, navProps)),
|
|
176
|
+
React.createElement(StoryContentSection, { markdown: (_o = (_m = activeSlide === null || activeSlide === void 0 ? void 0 : activeSlide.content) === null || _m === void 0 ? void 0 : _m.markdown) !== null && _o !== void 0 ? _o : '' }))));
|
|
177
|
+
});
|
|
178
|
+
StoryViewerPanel.displayName = 'StoryViewerPanel';
|
|
179
|
+
export default StoryViewerPanel;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Markdown from 'react-markdown';
|
|
3
|
+
function StoryContentSection({ markdown }) {
|
|
4
|
+
if (!markdown) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return (React.createElement("div", { className: "jgis-story-viewer-content" },
|
|
8
|
+
React.createElement(Markdown, null, markdown)));
|
|
9
|
+
}
|
|
10
|
+
export default StoryContentSection;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IStoryImageSectionProps {
|
|
3
|
+
imageUrl: string;
|
|
4
|
+
imageLoaded: boolean;
|
|
5
|
+
layerName: string;
|
|
6
|
+
slideNumber: number;
|
|
7
|
+
isSpecta: boolean;
|
|
8
|
+
storyType: string;
|
|
9
|
+
onPrev: () => void;
|
|
10
|
+
onNext: () => void;
|
|
11
|
+
hasPrev: boolean;
|
|
12
|
+
hasNext: boolean;
|
|
13
|
+
}
|
|
14
|
+
declare function StoryImageSection({ imageUrl, imageLoaded, layerName, slideNumber, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }: IStoryImageSectionProps): React.JSX.Element | null;
|
|
15
|
+
export default StoryImageSection;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import StoryNavBar from '../StoryNavBar';
|
|
3
|
+
function StoryImageSection({ imageUrl, imageLoaded, layerName, slideNumber, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }) {
|
|
4
|
+
if (!imageLoaded) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return (React.createElement("div", { className: "jgis-story-viewer-image-section" },
|
|
8
|
+
React.createElement("div", { className: "jgis-story-viewer-image-container" },
|
|
9
|
+
React.createElement("img", { src: imageUrl, alt: "Story map image", className: "jgis-story-viewer-image" }),
|
|
10
|
+
!isSpecta && storyType === 'guided' && (React.createElement("div", { className: "jgis-story-viewer-nav-container" },
|
|
11
|
+
React.createElement(StoryNavBar, { onPrev: onPrev, onNext: onNext, hasPrev: hasPrev, hasNext: hasNext, isSpecta: isSpecta }))))));
|
|
12
|
+
}
|
|
13
|
+
export default StoryImageSection;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IStorySubtitleSectionProps {
|
|
3
|
+
title: string;
|
|
4
|
+
isSpecta: boolean;
|
|
5
|
+
onPrev: () => void;
|
|
6
|
+
onNext: () => void;
|
|
7
|
+
hasPrev: boolean;
|
|
8
|
+
hasNext: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function StorySubtitleSection({ title, isSpecta, onPrev, onNext, hasPrev, hasNext, }: IStorySubtitleSectionProps): React.JSX.Element;
|
|
11
|
+
export default StorySubtitleSection;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import StoryNavBar from '../StoryNavBar';
|
|
3
|
+
function StorySubtitleSection({ title, isSpecta, onPrev, onNext, hasPrev, hasNext, }) {
|
|
4
|
+
return (React.createElement("div", { className: "jgis-story-viewer-subtitle-container" },
|
|
5
|
+
React.createElement("h2", { className: "jgis-story-viewer-subtitle" }, title || 'Slide Title'),
|
|
6
|
+
isSpecta && (React.createElement("div", { className: "jgis-story-viewer-nav-container-specta-mod" },
|
|
7
|
+
React.createElement(StoryNavBar, { onPrev: onPrev, onNext: onNext, hasPrev: hasPrev, hasNext: hasNext, isSpecta: isSpecta })))));
|
|
8
|
+
}
|
|
9
|
+
export default StorySubtitleSection;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IStoryTitleSectionProps {
|
|
3
|
+
title: string;
|
|
4
|
+
isSpecta: boolean;
|
|
5
|
+
storyType: string;
|
|
6
|
+
onPrev: () => void;
|
|
7
|
+
onNext: () => void;
|
|
8
|
+
hasPrev: boolean;
|
|
9
|
+
hasNext: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare function StoryTitleSection({ title, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }: IStoryTitleSectionProps): React.JSX.Element;
|
|
12
|
+
export default StoryTitleSection;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import StoryNavBar from '../StoryNavBar';
|
|
3
|
+
function StoryTitleSection({ title, isSpecta, storyType, onPrev, onNext, hasPrev, hasNext, }) {
|
|
4
|
+
return (React.createElement(React.Fragment, null,
|
|
5
|
+
React.createElement("h1", { className: "jgis-story-viewer-title" }, title),
|
|
6
|
+
!isSpecta && storyType === 'guided' && (React.createElement(StoryNavBar, { onPrev: onPrev, onNext: onNext, hasPrev: hasPrev, hasNext: hasNext, isSpecta: isSpecta }))));
|
|
7
|
+
}
|
|
8
|
+
export default StoryTitleSection;
|