@mwater/visualization 5.2.0 → 5.3.1
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/ColorComponent.d.ts +10 -11
- package/lib/ColorComponent.js +78 -29
- package/lib/ColorSchemeFactory.d.ts +13 -2
- package/lib/ColorSchemeFactory.js +7 -5
- package/lib/CustomColorsContext.d.ts +6 -0
- package/lib/CustomColorsContext.js +6 -0
- package/lib/FiltersDesignerComponent.d.ts +1 -4
- package/lib/FiltersDesignerComponent.js +2 -3
- package/lib/LocaleContextInjector.d.ts +5 -11
- package/lib/LocaleContextInjector.js +4 -12
- package/lib/MWaterAddRelatedFormComponent.js +3 -3
- package/lib/MWaterAddRelatedIndicatorComponent.d.ts +1 -4
- package/lib/MWaterAddRelatedIndicatorComponent.js +6 -6
- package/lib/MWaterCompleteTableSelectComponent.d.ts +5 -16
- package/lib/MWaterCompleteTableSelectComponent.js +36 -36
- package/lib/MWaterContextComponent.d.ts +4 -6
- package/lib/MWaterContextComponent.js +4 -13
- package/lib/MWaterLoaderComponent.d.ts +5 -3
- package/lib/MWaterLoaderComponent.js +2 -1
- package/lib/MWaterTableSelectComponent.d.ts +1 -4
- package/lib/MWaterTableSelectComponent.js +10 -12
- package/lib/UIComponents.d.ts +2 -2
- package/lib/UIComponents.js +4 -12
- package/lib/axes/AxisBuilder.d.ts +7 -4
- package/lib/axes/AxisBuilder.js +3 -1
- package/lib/axes/AxisComponent.d.ts +2 -5
- package/lib/axes/AxisComponent.js +1 -2
- package/lib/axes/ColorPaletteCollectionComponent.d.ts +5 -12
- package/lib/axes/ColorPaletteCollectionComponent.js +67 -36
- package/lib/dashboards/DashboardComponent.d.ts +4 -12
- package/lib/dashboards/DashboardComponent.js +18 -38
- package/lib/dashboards/DashboardDesign.d.ts +3 -3
- package/lib/dashboards/DashboardUpgrader.js +36 -1
- package/lib/dashboards/DashboardViewComponent.d.ts +5 -34
- package/lib/dashboards/DashboardViewComponent.js +109 -132
- package/lib/dashboards/FontStyleEditor.d.ts +8 -0
- package/lib/dashboards/FontStyleEditor.js +130 -0
- package/lib/dashboards/LayoutOptionsComponent.d.ts +0 -1
- package/lib/dashboards/LayoutOptionsComponent.js +211 -42
- package/lib/dashboards/ServerDashboardDataSource.d.ts +1 -2
- package/lib/dashboards/ServerDashboardDataSource.js +52 -33
- package/lib/dashboards/WidgetComponent.d.ts +3 -3
- package/lib/dashboards/WidgetComponent.js +3 -6
- package/lib/dashboards/WidgetDataSourcePrioritizer.d.ts +20 -0
- package/lib/dashboards/WidgetDataSourcePrioritizer.js +72 -0
- package/lib/dashboards/layoutOptions.d.ts +83 -0
- package/lib/dashboards/layoutOptions.js +436 -10
- package/lib/datagrids/DatagridDesign.d.ts +7 -6
- package/lib/datagrids/ServerDatagridDataSource.d.ts +7 -6
- package/lib/datagrids/ServerDatagridDataSource.js +87 -33
- package/lib/demo.js +3 -3
- package/lib/index.css +5 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +0 -1
- package/lib/layouts/LayoutManager.d.ts +33 -29
- package/lib/layouts/LayoutManager.js +2 -8
- package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +26 -57
- package/lib/layouts/blocks/BlocksDisplayComponent.js +122 -205
- package/lib/layouts/blocks/BlocksLayoutManager.d.ts +6 -22
- package/lib/layouts/blocks/BlocksLayoutManager.js +5 -14
- package/lib/layouts/blocks/HorizontalBlockComponent.d.ts +5 -4
- package/lib/layouts/blocks/HorizontalBlockComponent.js +5 -5
- package/lib/mWaterLoader.d.ts +2 -0
- package/lib/mWaterLoader.js +2 -1
- package/lib/maps/AddLayerComponent.d.ts +6 -8
- package/lib/maps/AddLayerComponent.js +6 -6
- package/lib/maps/BingLayer.js +10 -20
- package/lib/maps/BufferLayer.js +2 -1
- package/lib/maps/ChoroplethLayer.js +2 -1
- package/lib/maps/DirectMapDataSource.d.ts +5 -2
- package/lib/maps/DirectMapDataSource.js +2 -1
- package/lib/maps/EditPopupComponent.js +2 -1
- package/lib/maps/MapComponent.d.ts +1 -4
- package/lib/maps/MapComponent.js +3 -3
- package/lib/maps/MarkersLayer.js +30 -25
- package/lib/maps/RasterMapViewComponent.d.ts +1 -4
- package/lib/maps/RasterMapViewComponent.js +3 -3
- package/lib/maps/ServerMapDataSource.d.ts +2 -3
- package/lib/maps/ServerMapDataSource.js +5 -5
- package/lib/maps/VectorMapViewComponent.js +2 -1
- package/lib/maps/mapSymbols.js +2 -0
- package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
- package/lib/maps/vectorMaps.js +61 -55
- package/lib/quickfilter/QuickfiltersComponent.d.ts +1 -4
- package/lib/quickfilter/QuickfiltersComponent.js +3 -3
- package/lib/richtext/DropdownPaletteItem.d.ts +32 -0
- package/lib/richtext/DropdownPaletteItem.js +82 -0
- package/lib/richtext/FontColorPaletteItem.d.ts +1 -5
- package/lib/richtext/FontColorPaletteItem.js +32 -27
- package/lib/richtext/ItemsHtmlConverter.js +12 -3
- package/lib/richtext/RichTextComponent.d.ts +26 -52
- package/lib/richtext/RichTextComponent.js +166 -128
- package/lib/valueFormatter.js +6 -1
- package/lib/wellknown.d.ts +5 -0
- package/lib/wellknown.js +288 -0
- package/lib/widgets/DropdownWidgetComponent.d.ts +8 -25
- package/lib/widgets/DropdownWidgetComponent.js +48 -25
- package/lib/widgets/IFrameWidgetComponent.d.ts +1 -2
- package/lib/widgets/ImageWidgetComponent.d.ts +2 -3
- package/lib/widgets/MapWidget.d.ts +2 -0
- package/lib/widgets/MapWidget.js +2 -1
- package/lib/widgets/TOCWidget.js +2 -1
- package/lib/widgets/Widget.d.ts +2 -0
- package/lib/widgets/WidgetDataSource.d.ts +3 -1
- package/lib/widgets/charts/Chart.d.ts +0 -1
- package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
- package/lib/widgets/charts/ChartViewComponent.js +11 -3
- package/lib/widgets/charts/ChartWidget.d.ts +1 -62
- package/lib/widgets/charts/ChartWidget.js +4 -183
- package/lib/widgets/charts/ChartWidgetComponent.d.ts +51 -0
- package/lib/widgets/charts/ChartWidgetComponent.js +167 -0
- package/lib/widgets/charts/calendar/CalendarChartViewComponent.d.ts +1 -4
- package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +4 -4
- package/lib/widgets/charts/layered/LayeredChart.d.ts +5 -10
- package/lib/widgets/charts/layered/LayeredChart.js +6 -7
- package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +4 -2
- package/lib/widgets/charts/layered/LayeredChartCompiler.js +46 -32
- package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +4 -0
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +3 -0
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +21 -3
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +1 -2
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +2 -1
- package/lib/widgets/charts/layered/LayeredChartViewComponent.d.ts +1 -4
- package/lib/widgets/charts/layered/LayeredChartViewComponent.js +89 -38
- package/lib/widgets/charts/pivot/IntersectionDesignerComponent.d.ts +5 -112
- package/lib/widgets/charts/pivot/IntersectionDesignerComponent.js +122 -166
- package/lib/widgets/charts/pivot/PivotChart.d.ts +6 -0
- package/lib/widgets/charts/pivot/PivotChart.js +47 -17
- package/lib/widgets/charts/pivot/PivotChartDesign.d.ts +11 -0
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +1 -1
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +1 -1
- package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +2 -2
- package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +20 -36
- package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +0 -1
- package/lib/widgets/charts/pivot/PivotChartQueryBuilder.d.ts +23 -2
- package/lib/widgets/charts/pivot/PivotChartQueryBuilder.js +215 -181
- package/lib/widgets/charts/pivot/PivotChartUtils.d.ts +2 -2
- package/lib/widgets/charts/pivot/PivotChartViewComponent.d.ts +9 -28
- package/lib/widgets/charts/pivot/PivotChartViewComponent.js +20 -60
- package/lib/widgets/charts/table/TableChart.js +8 -4
- package/lib/widgets/charts/table/TableChartDesignerComponent.js +3 -3
- package/lib/widgets/charts/table/TableChartViewComponent.js +11 -11
- package/lib/widgets/text/TextComponent.d.ts +5 -12
- package/lib/widgets/text/TextComponent.js +19 -39
- package/lib/widgets/text/TextWidget.d.ts +2 -1
- package/lib/widgets/text/TextWidget.js +5 -1
- package/lib/widgets/text/TextWidgetComponent.d.ts +15 -3
- package/lib/widgets/text/TextWidgetComponent.js +76 -19
- package/lib/widgets/text/TextWidgetDesign.d.ts +13 -1
- package/lib/widgets/text/TextWidgetDesign.js +6 -0
- package/package.json +4 -4
- package/src/ColorComponent.tsx +177 -0
- package/src/ColorSchemeFactory.ts +12 -6
- package/src/CustomColorsContext.tsx +9 -0
- package/src/FiltersDesignerComponent.ts +3 -4
- package/src/LocaleContextInjector.tsx +14 -13
- package/src/MWaterAddRelatedFormComponent.ts +3 -3
- package/src/MWaterAddRelatedIndicatorComponent.ts +6 -6
- package/src/MWaterCompleteTableSelectComponent.tsx +36 -36
- package/src/MWaterContextComponent.tsx +8 -17
- package/src/MWaterLoaderComponent.ts +6 -3
- package/src/MWaterTableSelectComponent.tsx +11 -12
- package/src/{UIComponents.ts → UIComponents.tsx} +7 -15
- package/src/axes/AxisBuilder.ts +7 -5
- package/src/axes/AxisComponent.ts +3 -4
- package/src/axes/{ColorPaletteCollectionComponent.ts → ColorPaletteCollectionComponent.tsx} +87 -61
- package/src/dashboards/DashboardComponent.tsx +71 -107
- package/src/dashboards/DashboardDesign.ts +3 -3
- package/src/dashboards/DashboardUpgrader.ts +41 -1
- package/src/dashboards/DashboardViewComponent.tsx +313 -0
- package/src/dashboards/FontStyleEditor.tsx +166 -0
- package/src/dashboards/LayoutOptionsComponent.tsx +380 -75
- package/src/dashboards/ServerDashboardDataSource.ts +52 -33
- package/src/dashboards/WidgetComponent.tsx +6 -12
- package/src/dashboards/WidgetDataSourcePrioritizer.ts +82 -0
- package/src/dashboards/layoutOptions.tsx +581 -0
- package/src/datagrids/DatagridDesign.ts +8 -3
- package/src/datagrids/ServerDatagridDataSource.ts +106 -43
- package/src/demo.ts +3 -3
- package/src/index.css +5 -0
- package/src/index.ts +1 -1
- package/src/layouts/LayoutManager.ts +44 -42
- package/src/layouts/blocks/BlocksDisplayComponent.tsx +498 -0
- package/src/layouts/blocks/BlocksLayoutManager.ts +6 -15
- package/src/layouts/blocks/HorizontalBlockComponent.ts +9 -8
- package/src/mWaterLoader.ts +4 -1
- package/src/maps/AddLayerComponent.ts +9 -9
- package/src/maps/BingLayer.ts +16 -26
- package/src/maps/BufferLayer.ts +2 -1
- package/src/maps/ChoroplethLayer.ts +2 -1
- package/src/maps/DirectMapDataSource.ts +12 -3
- package/src/maps/EditPopupComponent.ts +2 -1
- package/src/maps/MapComponent.ts +3 -3
- package/src/maps/MarkersLayer.ts +38 -41
- package/src/maps/RasterMapViewComponent.ts +3 -3
- package/src/maps/ServerMapDataSource.ts +7 -7
- package/src/maps/VectorMapViewComponent.tsx +2 -1
- package/src/maps/mapSymbols.ts +2 -0
- package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
- package/src/maps/vectorMaps.tsx +79 -74
- package/src/quickfilter/QuickfiltersComponent.ts +3 -3
- package/src/richtext/DropdownPaletteItem.tsx +144 -0
- package/src/richtext/FontColorPaletteItem.tsx +160 -0
- package/src/richtext/ItemsHtmlConverter.ts +15 -5
- package/src/richtext/RichTextComponent.tsx +274 -232
- package/src/valueFormatter.ts +5 -1
- package/src/wellknown.ts +286 -0
- package/src/widgets/DropdownWidgetComponent.tsx +75 -0
- package/src/widgets/MapWidget.ts +5 -2
- package/src/widgets/TOCWidget.ts +2 -1
- package/src/widgets/Widget.ts +3 -0
- package/src/widgets/WidgetDataSource.ts +3 -1
- package/src/widgets/charts/Chart.ts +1 -1
- package/src/widgets/charts/ChartViewComponent.ts +16 -3
- package/src/widgets/charts/ChartWidget.ts +3 -275
- package/src/widgets/charts/ChartWidgetComponent.tsx +281 -0
- package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +4 -4
- package/src/widgets/charts/layered/LayeredChart.ts +4 -6
- package/src/widgets/charts/layered/LayeredChartCompiler.ts +80 -63
- package/src/widgets/charts/layered/LayeredChartDesign.ts +7 -1
- package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +43 -10
- package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +6 -6
- package/src/widgets/charts/layered/LayeredChartViewComponent.ts +140 -88
- package/src/widgets/charts/pivot/IntersectionDesignerComponent.tsx +305 -221
- package/src/widgets/charts/pivot/PivotChart.ts +56 -18
- package/src/widgets/charts/pivot/PivotChartDesign.ts +12 -0
- package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +4 -3
- package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +39 -76
- package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +0 -1
- package/src/widgets/charts/pivot/PivotChartQueryBuilder.ts +230 -189
- package/src/widgets/charts/pivot/PivotChartUtils.ts +4 -4
- package/src/widgets/charts/pivot/{PivotChartViewComponent.ts → PivotChartViewComponent.tsx} +86 -89
- package/src/widgets/charts/table/TableChart.ts +8 -4
- package/src/widgets/charts/table/TableChartDesignerComponent.ts +4 -4
- package/src/widgets/charts/table/TableChartViewComponent.ts +13 -14
- package/src/widgets/text/TextComponent.tsx +47 -49
- package/src/widgets/text/TextWidget.ts +8 -3
- package/src/widgets/text/TextWidgetComponent.tsx +249 -0
- package/src/widgets/text/TextWidgetDesign.ts +22 -1
- package/src/ColorComponent.ts +0 -117
- package/src/dashboards/DashboardViewComponent.ts +0 -303
- package/src/dashboards/layoutOptions.ts +0 -40
- package/src/layout-styles.css +0 -263
- package/src/layouts/blocks/BlocksDisplayComponent.ts +0 -461
- package/src/layouts/grid/GridLayoutComponent.ts +0 -67
- package/src/layouts/grid/GridLayoutManager.ts +0 -185
- package/src/layouts/grid/LegoLayoutEngine.ts +0 -142
- package/src/layouts/grid/PaletteItemComponent.ts +0 -28
- package/src/layouts/grid/README.md +0 -14
- package/src/layouts/grid/WidgetContainerComponent.ts +0 -420
- package/src/richtext/FontColorPaletteItem.ts +0 -172
- package/src/richtext/FontSizePaletteItem.ts +0 -110
- package/src/widgets/DropdownWidgetComponent.ts +0 -78
- package/src/widgets/text/TextWidgetComponent.ts +0 -120
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import React, { useState } from "react"
|
|
2
|
+
import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent"
|
|
3
|
+
import { expandFontFamily, FontStyle } from "./layoutOptions"
|
|
4
|
+
import { default as ReactSelect } from "react-select"
|
|
5
|
+
import { Select, FormGroup } from "@mwater/react-library/lib/bootstrap"
|
|
6
|
+
import ColorComponent from "../ColorComponent"
|
|
7
|
+
|
|
8
|
+
interface FontStyleEditorProps {
|
|
9
|
+
value: FontStyle
|
|
10
|
+
onChange: (value: FontStyle) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const FontStyleEditor = ({ value, onChange }: FontStyleEditorProps) => {
|
|
14
|
+
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
15
|
+
|
|
16
|
+
const handleOpenModal = () => setIsModalOpen(true)
|
|
17
|
+
const handleCloseModal = () => setIsModalOpen(false)
|
|
18
|
+
|
|
19
|
+
const handleSave = (newValue: FontStyle) => {
|
|
20
|
+
onChange(newValue)
|
|
21
|
+
handleCloseModal()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <>
|
|
25
|
+
<div style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', border: 'solid 1px #DDD', padding: '4px', borderRadius: '6px', justifyContent: 'space-between' }} onClick={handleOpenModal}>
|
|
26
|
+
<div style={{
|
|
27
|
+
fontFamily: expandFontFamily(value.family),
|
|
28
|
+
fontSize: `${value.size}px`,
|
|
29
|
+
fontWeight: value.weight,
|
|
30
|
+
color: value.color
|
|
31
|
+
}}>
|
|
32
|
+
Sample
|
|
33
|
+
</div>
|
|
34
|
+
<div style={{ fontSize: '10px', color: '#888', marginTop: '2px' }}>
|
|
35
|
+
{value.family}, {value.size}px
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
{isModalOpen && (
|
|
39
|
+
<FontEditorModal
|
|
40
|
+
initialValue={value}
|
|
41
|
+
onSave={handleSave}
|
|
42
|
+
onCancel={handleCloseModal}
|
|
43
|
+
/>
|
|
44
|
+
)}
|
|
45
|
+
</>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface FontEditorModalProps {
|
|
49
|
+
initialValue: FontStyle
|
|
50
|
+
onSave: (value: FontStyle) => void
|
|
51
|
+
onCancel: () => void
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const FontEditorModal: React.FC<FontEditorModalProps> = ({ initialValue, onSave, onCancel }) => {
|
|
55
|
+
const [currentValue, setCurrentValue] = useState<FontStyle>(initialValue)
|
|
56
|
+
|
|
57
|
+
const handleChange = (field: keyof FontStyle, value: string | number) => {
|
|
58
|
+
if (field == "family") {
|
|
59
|
+
setCurrentValue(prev => ({ ...prev, [field]: value as string, weight: "400" }))
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
setCurrentValue(prev => ({ ...prev, [field]: value }))
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Generate font size options from 5 to 48
|
|
67
|
+
const fontSizeOptions = Array.from({ length: 44 }, (_, i) => i + 5).map(size => ({
|
|
68
|
+
value: size,
|
|
69
|
+
label: `${size}px`
|
|
70
|
+
}))
|
|
71
|
+
|
|
72
|
+
// If the font is variable, then the font weight options are much wider
|
|
73
|
+
const fontWeightOptions: string[] = []
|
|
74
|
+
if (currentValue.family === "Roboto") {
|
|
75
|
+
fontWeightOptions.push("100", "300", "400", "500", "700", "900")
|
|
76
|
+
}
|
|
77
|
+
else if (currentValue.family === "Lora") {
|
|
78
|
+
fontWeightOptions.push("400", "500", "600", "700")
|
|
79
|
+
}
|
|
80
|
+
else if (currentValue.family === "Inter") {
|
|
81
|
+
fontWeightOptions.push("100", "200", "300", "400", "500", "600", "700", "800", "900")
|
|
82
|
+
}
|
|
83
|
+
else if (currentValue.family === "Merriweather") {
|
|
84
|
+
fontWeightOptions.push("300", "400", "700", "900")
|
|
85
|
+
}
|
|
86
|
+
else if (currentValue.family === "Lato") {
|
|
87
|
+
fontWeightOptions.push("100", "300", "400", "700", "900")
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
fontWeightOptions.push("400", "700")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<ActionCancelModalComponent
|
|
95
|
+
title="Edit Font"
|
|
96
|
+
onAction={() => onSave(currentValue)}
|
|
97
|
+
onCancel={onCancel}
|
|
98
|
+
>
|
|
99
|
+
<div style={{
|
|
100
|
+
border: '1px solid #ccc',
|
|
101
|
+
padding: '10px',
|
|
102
|
+
marginBottom: '15px',
|
|
103
|
+
borderRadius: '4px'
|
|
104
|
+
}}>
|
|
105
|
+
<div style={{
|
|
106
|
+
marginBottom: '10px',
|
|
107
|
+
fontSize: '14px',
|
|
108
|
+
fontWeight: 'bold'
|
|
109
|
+
}}>
|
|
110
|
+
Sample Text:
|
|
111
|
+
</div>
|
|
112
|
+
<div style={{
|
|
113
|
+
fontFamily: expandFontFamily(currentValue.family),
|
|
114
|
+
fontSize: `${currentValue.size}px`,
|
|
115
|
+
fontWeight: currentValue.weight,
|
|
116
|
+
color: currentValue.color
|
|
117
|
+
}}>
|
|
118
|
+
The quick brown fox jumps over the lazy dog.
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
<FormGroup label="Font Family">
|
|
122
|
+
<ReactSelect
|
|
123
|
+
value={{ value: currentValue.family, label: currentValue.family }}
|
|
124
|
+
onChange={(option) => handleChange('family', option?.value || '')}
|
|
125
|
+
options={[
|
|
126
|
+
{ value: 'Helvetica Neue', label: 'Helvetica Neue' },
|
|
127
|
+
{ value: 'Georgia', label: 'Georgia' },
|
|
128
|
+
{ value: 'Inter', label: 'Inter' },
|
|
129
|
+
{ value: 'Lato', label: 'Lato' },
|
|
130
|
+
{ value: 'Lora', label: 'Lora' },
|
|
131
|
+
{ value: 'Lucida Grande', label: 'Lucida Grande' },
|
|
132
|
+
{ value: 'Merriweather', label: 'Merriweather' },
|
|
133
|
+
{ value: 'Roboto', label: 'Roboto' },
|
|
134
|
+
]}
|
|
135
|
+
formatOptionLabel={(option) => (
|
|
136
|
+
<span style={{ fontFamily: expandFontFamily(option.value) }}>{option.label}</span>
|
|
137
|
+
)}
|
|
138
|
+
isClearable={false}
|
|
139
|
+
menuPortalTarget={document.body}
|
|
140
|
+
styles={{ menuPortal: (style) => ({ ...style, zIndex: 2000 }) }}
|
|
141
|
+
/>
|
|
142
|
+
</FormGroup>
|
|
143
|
+
<FormGroup label="Font Size:" horizontal>
|
|
144
|
+
<Select
|
|
145
|
+
value={currentValue.size}
|
|
146
|
+
onChange={(value) => handleChange('size', value || 12)}
|
|
147
|
+
options={fontSizeOptions}
|
|
148
|
+
/>
|
|
149
|
+
</FormGroup>
|
|
150
|
+
<FormGroup label="Font Weight:" horizontal>
|
|
151
|
+
<Select
|
|
152
|
+
value={currentValue.weight}
|
|
153
|
+
onChange={(value) => handleChange('weight', value as string)}
|
|
154
|
+
options={fontWeightOptions.map(weight => ({ value: weight, label: weight }))}
|
|
155
|
+
/>
|
|
156
|
+
</FormGroup>
|
|
157
|
+
<FormGroup label="Font Color:" horizontal>
|
|
158
|
+
<ColorComponent
|
|
159
|
+
color={currentValue.color}
|
|
160
|
+
onChange={(value) => handleChange('color', value!)}
|
|
161
|
+
disableReset
|
|
162
|
+
/>
|
|
163
|
+
</FormGroup>
|
|
164
|
+
</ActionCancelModalComponent>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import _ from "lodash"
|
|
1
2
|
import React, { ReactNode } from "react"
|
|
2
3
|
import { useState } from "react"
|
|
3
|
-
import { FormGroup, Select,
|
|
4
|
+
import { FormGroup, Toggle, Select, CollapsibleSection, Checkbox, CollapsiblePanel } from "@mwater/react-library/lib/bootstrap"
|
|
4
5
|
import { DashboardDesign } from "./DashboardDesign"
|
|
5
6
|
import {
|
|
6
7
|
BlocksLayoutOptions,
|
|
7
8
|
DashboardTheme,
|
|
8
9
|
getDefaultLayoutOptions,
|
|
9
10
|
getLayoutOptions,
|
|
10
|
-
|
|
11
|
+
Spacing,
|
|
11
12
|
} from "./layoutOptions"
|
|
13
|
+
import ColorComponent from "../ColorComponent"
|
|
14
|
+
import { FontStyleEditor } from "./FontStyleEditor"
|
|
15
|
+
import produce from "immer"
|
|
16
|
+
import FileSaver from "file-saver"
|
|
12
17
|
|
|
13
18
|
interface Size {
|
|
14
19
|
width: number
|
|
@@ -25,7 +30,6 @@ const sizeOptions: { value: Size; label: string }[] = [
|
|
|
25
30
|
export function LayoutOptionsComponent(props: {
|
|
26
31
|
design: DashboardDesign
|
|
27
32
|
onDesignChange: (design: DashboardDesign) => void
|
|
28
|
-
onClose: () => void
|
|
29
33
|
|
|
30
34
|
/** Dashboard view to preview*/
|
|
31
35
|
dashboardView: ReactNode
|
|
@@ -40,78 +44,29 @@ export function LayoutOptionsComponent(props: {
|
|
|
40
44
|
props.onDesignChange({ ...props.design, layoutOptions })
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
props.onDesignChange({ ...props.design, layoutOptions: getDefaultLayoutOptions(props.design.style) })
|
|
45
|
-
}
|
|
47
|
+
const isCustomized = !_.isEqual(layoutOptions, getDefaultLayoutOptions(props.design.style))
|
|
46
48
|
|
|
47
49
|
return (
|
|
48
|
-
<div style={{ display: "grid", gridTemplateRows: "auto 1fr", gridTemplateColumns: "
|
|
49
|
-
<div style={{ padding:
|
|
50
|
-
<
|
|
51
|
-
<button className="btn btn-sm btn-link" onClick={props.onClose}>
|
|
52
|
-
<i className="fa fa-arrow-left" /> Close
|
|
53
|
-
</button>
|
|
54
|
-
</div>
|
|
55
|
-
<br />
|
|
50
|
+
<div style={{ display: "grid", gridTemplateRows: "auto 1fr", gridTemplateColumns: "360px 1fr", height: "100%" }}>
|
|
51
|
+
<div style={{ padding: "5px 10px 5px 0px", gridRow: "1 / 3", overflowY: "auto" }}>
|
|
52
|
+
<h5>Theme</h5>
|
|
56
53
|
<ThemeToggle
|
|
57
54
|
theme={props.design.style}
|
|
58
55
|
onChange={(theme) => {
|
|
56
|
+
if (isCustomized) {
|
|
57
|
+
if (!confirm("Are you sure you want to change the theme? Your customizations will be lost.")) return
|
|
58
|
+
}
|
|
59
59
|
props.onDesignChange({ ...props.design, style: theme, layoutOptions: getDefaultLayoutOptions(theme) })
|
|
60
60
|
}}
|
|
61
|
+
isCustomized={isCustomized}
|
|
61
62
|
/>
|
|
62
63
|
<br />
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<FormGroup label="Collapse to Single Column">
|
|
68
|
-
<WidthSelector
|
|
69
|
-
value={layoutOptions.collapseColumnsWidth}
|
|
70
|
-
onChange={(collapseColumnsWidth) => {
|
|
71
|
-
setLayoutOptions({ ...layoutOptions, collapseColumnsWidth })
|
|
72
|
-
}}
|
|
73
|
-
sign="< "
|
|
74
|
-
/>
|
|
75
|
-
</FormGroup>
|
|
76
|
-
<FormGroup label="Hide Quickfilters">
|
|
77
|
-
<WidthSelector
|
|
78
|
-
value={layoutOptions.hideQuickfiltersWidth}
|
|
79
|
-
onChange={(hideQuickfiltersWidth) => {
|
|
80
|
-
setLayoutOptions({ ...layoutOptions, hideQuickfiltersWidth })
|
|
81
|
-
}}
|
|
82
|
-
sign="< "
|
|
83
|
-
/>
|
|
84
|
-
</FormGroup>
|
|
85
|
-
<FormGroup label="Minimum Width (before scrolling or scaling)">
|
|
86
|
-
<WidthSelector
|
|
87
|
-
value={layoutOptions.minimumWidth}
|
|
88
|
-
onChange={(minimumWidth) => {
|
|
89
|
-
setLayoutOptions({ ...layoutOptions, minimumWidth })
|
|
90
|
-
}}
|
|
91
|
-
sign="< "
|
|
64
|
+
<CollapsibleSection label={<h5 style={{ display: "inline-block" }}>Customize Layout</h5>} initiallyOpen={isCustomized}>
|
|
65
|
+
<CustomizeLayout
|
|
66
|
+
layoutOptions={layoutOptions}
|
|
67
|
+
onLayoutOptionsChange={setLayoutOptions}
|
|
92
68
|
/>
|
|
93
|
-
|
|
94
|
-
<Toggle
|
|
95
|
-
value={layoutOptions.belowMinimumWidth}
|
|
96
|
-
onChange={(belowMinimumWidth) => {
|
|
97
|
-
setLayoutOptions({ ...layoutOptions, belowMinimumWidth: belowMinimumWidth as "scale" | "scroll" })
|
|
98
|
-
}}
|
|
99
|
-
options={[
|
|
100
|
-
{ value: "scroll", label: "Scroll" },
|
|
101
|
-
{ value: "scale", label: "Scale" }
|
|
102
|
-
]}
|
|
103
|
-
/>
|
|
104
|
-
</FormGroup>
|
|
105
|
-
</FormGroup>
|
|
106
|
-
<FormGroup label="Maximum Width (before padding)">
|
|
107
|
-
<WidthSelector
|
|
108
|
-
value={layoutOptions.maximumWidth}
|
|
109
|
-
onChange={(maximumWidth) => {
|
|
110
|
-
setLayoutOptions({ ...layoutOptions, maximumWidth })
|
|
111
|
-
}}
|
|
112
|
-
sign="> "
|
|
113
|
-
/>
|
|
114
|
-
</FormGroup>
|
|
69
|
+
</CollapsibleSection>
|
|
115
70
|
</div>
|
|
116
71
|
<div style={{ textAlign: "center", padding: 3 }}>
|
|
117
72
|
<span className="text-muted">Preview As: </span>
|
|
@@ -151,9 +106,13 @@ export function LayoutOptionsComponent(props: {
|
|
|
151
106
|
)
|
|
152
107
|
}
|
|
153
108
|
|
|
154
|
-
function ThemeToggle(props: {
|
|
109
|
+
function ThemeToggle(props: {
|
|
110
|
+
theme?: DashboardTheme;
|
|
111
|
+
onChange: (theme: DashboardTheme) => void
|
|
112
|
+
isCustomized: boolean
|
|
113
|
+
}) {
|
|
155
114
|
function renderStyleItem(theme: string) {
|
|
156
|
-
const isActive = (props.theme || "default") == theme
|
|
115
|
+
const isActive = props.isCustomized ? theme == "custom" : (props.theme || "default") == theme
|
|
157
116
|
|
|
158
117
|
if (theme == "default") {
|
|
159
118
|
return (
|
|
@@ -191,17 +150,363 @@ function ThemeToggle(props: { theme?: DashboardTheme; onChange: (theme: Dashboar
|
|
|
191
150
|
</a>
|
|
192
151
|
)
|
|
193
152
|
}
|
|
153
|
+
if (theme == "custom") {
|
|
154
|
+
return (
|
|
155
|
+
<a
|
|
156
|
+
key={theme}
|
|
157
|
+
className={isActive ? "list-group-item active" : "list-group-item"}
|
|
158
|
+
>
|
|
159
|
+
<div>Custom</div>
|
|
160
|
+
<div style={{ opacity: 0.6 }}>Customized theme</div>
|
|
161
|
+
</a>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
194
164
|
return null
|
|
195
165
|
}
|
|
196
166
|
|
|
197
167
|
return (
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
168
|
+
<div className="list-group">
|
|
169
|
+
{renderStyleItem("default")}
|
|
170
|
+
{renderStyleItem("greybg")}
|
|
171
|
+
{renderStyleItem("story")}
|
|
172
|
+
{props.isCustomized && renderStyleItem("custom")}
|
|
173
|
+
</div>
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function CustomizeLayout(props: { layoutOptions: BlocksLayoutOptions; onLayoutOptionsChange: (layoutOptions: BlocksLayoutOptions) => void }) {
|
|
178
|
+
const { layoutOptions, onLayoutOptionsChange } = props
|
|
179
|
+
|
|
180
|
+
const handleDownloadTheme = () => {
|
|
181
|
+
const blob = new Blob([JSON.stringify(layoutOptions, null, 2)], { type: "application/json" })
|
|
182
|
+
FileSaver.saveAs(blob, "custom_theme.theme")
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const handleUploadTheme = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
186
|
+
const file = event.target.files?.[0]
|
|
187
|
+
if (file) {
|
|
188
|
+
const reader = new FileReader()
|
|
189
|
+
reader.onload = (e) => {
|
|
190
|
+
try {
|
|
191
|
+
const uploadedTheme = JSON.parse(e.target?.result as string)
|
|
192
|
+
onLayoutOptionsChange(uploadedTheme)
|
|
193
|
+
} catch (error) {
|
|
194
|
+
alert("Invalid theme file")
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
reader.readAsText(file)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<div>
|
|
203
|
+
<CollapsiblePanel title="Text">
|
|
204
|
+
<FormGroup label="Title">
|
|
205
|
+
<FontStyleEditor value={layoutOptions.titleWidgetFont} onChange={(titleWidgetFont) => {
|
|
206
|
+
onLayoutOptionsChange({ ...layoutOptions, titleWidgetFont })
|
|
207
|
+
}} />
|
|
208
|
+
</FormGroup>
|
|
209
|
+
<FormGroup label="Heading H1">
|
|
210
|
+
<FontStyleEditor value={layoutOptions.textWidgetH1Font} onChange={(textWidgetH1Font) => {
|
|
211
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetH1Font })
|
|
212
|
+
}} />
|
|
213
|
+
<div className="mt-1">
|
|
214
|
+
<FormGroup label="Top Margin:" horizontal labelMuted>
|
|
215
|
+
<PixelsInput
|
|
216
|
+
value={layoutOptions.textWidgetH1MarginTop}
|
|
217
|
+
onChange={(textWidgetH1MarginTop) => {
|
|
218
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetH1MarginTop: textWidgetH1MarginTop! })
|
|
219
|
+
}}
|
|
220
|
+
/>
|
|
221
|
+
</FormGroup>
|
|
222
|
+
</div>
|
|
223
|
+
</FormGroup>
|
|
224
|
+
<FormGroup label="Heading H2">
|
|
225
|
+
<FontStyleEditor value={layoutOptions.textWidgetH2Font} onChange={(textWidgetH2Font) => {
|
|
226
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetH2Font })
|
|
227
|
+
}} />
|
|
228
|
+
<div className="mt-1">
|
|
229
|
+
<FormGroup label="Top Margin:" horizontal labelMuted>
|
|
230
|
+
<PixelsInput
|
|
231
|
+
value={layoutOptions.textWidgetH2MarginTop}
|
|
232
|
+
onChange={(textWidgetH2MarginTop) => {
|
|
233
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetH2MarginTop: textWidgetH2MarginTop! })
|
|
234
|
+
}}
|
|
235
|
+
/>
|
|
236
|
+
</FormGroup>
|
|
237
|
+
</div>
|
|
238
|
+
</FormGroup>
|
|
239
|
+
<FormGroup label="Text">
|
|
240
|
+
<FontStyleEditor value={layoutOptions.textWidgetFont} onChange={(textWidgetFont) => {
|
|
241
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetFont })
|
|
242
|
+
}} />
|
|
243
|
+
<div className="mt-1">
|
|
244
|
+
<FormGroup label="Line Height:" horizontal labelMuted>
|
|
245
|
+
<PixelsInput
|
|
246
|
+
value={layoutOptions.textWidgetLineHeight}
|
|
247
|
+
onChange={(textWidgetLineHeight) => {
|
|
248
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetLineHeight: textWidgetLineHeight })
|
|
249
|
+
}}
|
|
250
|
+
allowDefault
|
|
251
|
+
defaultLabel="Default"
|
|
252
|
+
/>
|
|
253
|
+
</FormGroup>
|
|
254
|
+
<FormGroup label="Paragraph Spacing:" horizontal labelMuted>
|
|
255
|
+
<PixelsInput
|
|
256
|
+
value={layoutOptions.textWidgetParagraphSpacing}
|
|
257
|
+
onChange={(textWidgetParagraphSpacing) => {
|
|
258
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetParagraphSpacing: textWidgetParagraphSpacing! })
|
|
259
|
+
}}
|
|
260
|
+
/>
|
|
261
|
+
</FormGroup>
|
|
262
|
+
</div>
|
|
263
|
+
</FormGroup>
|
|
264
|
+
<FormGroup label="List Line Height:" horizontal>
|
|
265
|
+
<PixelsInput
|
|
266
|
+
value={layoutOptions.textWidgetListLineHeight}
|
|
267
|
+
onChange={(textWidgetListLineHeight) => {
|
|
268
|
+
onLayoutOptionsChange({ ...layoutOptions, textWidgetListLineHeight: textWidgetListLineHeight })
|
|
269
|
+
}}
|
|
270
|
+
allowDefault
|
|
271
|
+
defaultLabel="Default"
|
|
272
|
+
/>
|
|
273
|
+
</FormGroup>
|
|
274
|
+
<FormGroup label="Chart Header Font">
|
|
275
|
+
<FontStyleEditor value={layoutOptions.widgetHeaderFont} onChange={(widgetHeaderFont) => {
|
|
276
|
+
onLayoutOptionsChange({ ...layoutOptions, widgetHeaderFont })
|
|
277
|
+
}} />
|
|
278
|
+
</FormGroup>
|
|
279
|
+
<FormGroup label="Chart Footer Font">
|
|
280
|
+
<FontStyleEditor value={layoutOptions.widgetFooterFont} onChange={(widgetFooterFont) => {
|
|
281
|
+
onLayoutOptionsChange({ ...layoutOptions, widgetFooterFont })
|
|
282
|
+
}} />
|
|
283
|
+
</FormGroup>
|
|
284
|
+
<FormGroup label="Chart Font">
|
|
285
|
+
<FontStyleEditor value={layoutOptions.chartFont} onChange={(chartFont) => {
|
|
286
|
+
onLayoutOptionsChange({ ...layoutOptions, chartFont })
|
|
287
|
+
}} />
|
|
288
|
+
</FormGroup>
|
|
289
|
+
<FormGroup label="Table Font">
|
|
290
|
+
<FontStyleEditor value={layoutOptions.tableFont} onChange={(tableFont) => {
|
|
291
|
+
onLayoutOptionsChange({ ...layoutOptions, tableFont })
|
|
292
|
+
}} />
|
|
293
|
+
</FormGroup>
|
|
294
|
+
<FormGroup label="Pivot Table Font">
|
|
295
|
+
<FontStyleEditor value={layoutOptions.pivotTableFont} onChange={(pivotTableFont) => {
|
|
296
|
+
onLayoutOptionsChange({ ...layoutOptions, pivotTableFont })
|
|
297
|
+
}} />
|
|
298
|
+
</FormGroup>
|
|
299
|
+
</CollapsiblePanel>
|
|
300
|
+
<CollapsiblePanel title="Spacing">
|
|
301
|
+
<FormGroup label="Outer Padding:" horizontal>
|
|
302
|
+
<PixelsInput
|
|
303
|
+
value={layoutOptions.outerPadding}
|
|
304
|
+
onChange={(outerPadding) => {
|
|
305
|
+
onLayoutOptionsChange({ ...layoutOptions, outerPadding: outerPadding! })
|
|
306
|
+
}}
|
|
307
|
+
/>
|
|
308
|
+
</FormGroup>
|
|
309
|
+
<FormGroup label="Block Margins">
|
|
310
|
+
<SpacingInput value={layoutOptions.blockMargin} onChange={(blockMargin) => {
|
|
311
|
+
onLayoutOptionsChange({ ...layoutOptions, blockMargin })
|
|
312
|
+
}} />
|
|
313
|
+
</FormGroup>
|
|
314
|
+
<FormGroup label="Block Padding">
|
|
315
|
+
<SpacingInput value={layoutOptions.blockPadding} onChange={(blockPadding) => {
|
|
316
|
+
onLayoutOptionsChange({ ...layoutOptions, blockPadding })
|
|
317
|
+
}} />
|
|
318
|
+
</FormGroup>
|
|
319
|
+
<FormGroup label="Block Border Radius:" horizontal>
|
|
320
|
+
<PixelsInput
|
|
321
|
+
value={layoutOptions.blockBorderRadius}
|
|
322
|
+
onChange={(blockBorderRadius) => {
|
|
323
|
+
onLayoutOptionsChange({ ...layoutOptions, blockBorderRadius: blockBorderRadius! })
|
|
324
|
+
}}
|
|
325
|
+
/>
|
|
326
|
+
</FormGroup>
|
|
327
|
+
</CollapsiblePanel>
|
|
328
|
+
<CollapsiblePanel title="Colors">
|
|
329
|
+
<FormGroup label="Background Color:" horizontal>
|
|
330
|
+
<ColorComponent
|
|
331
|
+
color={layoutOptions.backgroundColor}
|
|
332
|
+
onChange={(backgroundColor) => {
|
|
333
|
+
onLayoutOptionsChange({ ...layoutOptions, backgroundColor: backgroundColor ?? "white" })
|
|
334
|
+
}}
|
|
335
|
+
/>
|
|
336
|
+
</FormGroup>
|
|
337
|
+
<FormGroup label="Block Background Color:" horizontal>
|
|
338
|
+
<ColorComponent
|
|
339
|
+
color={layoutOptions.blockBackgroundColor}
|
|
340
|
+
onChange={(blockBackgroundColor) => {
|
|
341
|
+
onLayoutOptionsChange({ ...layoutOptions, blockBackgroundColor: blockBackgroundColor ?? "white" })
|
|
342
|
+
}}
|
|
343
|
+
/>
|
|
344
|
+
</FormGroup>
|
|
345
|
+
<FormGroup label="Custom Colors">
|
|
346
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: '5px' }}>
|
|
347
|
+
{/* 18 colors, 3 rows of 6 */}
|
|
348
|
+
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17].map((colorIndex) => (
|
|
349
|
+
<ColorComponent
|
|
350
|
+
key={colorIndex}
|
|
351
|
+
color={layoutOptions.customColors[colorIndex]}
|
|
352
|
+
onChange={(color) => {
|
|
353
|
+
onLayoutOptionsChange(produce(layoutOptions, (draft) => {
|
|
354
|
+
draft.customColors[colorIndex] = color
|
|
355
|
+
}))
|
|
356
|
+
}}
|
|
357
|
+
/>
|
|
358
|
+
))}
|
|
359
|
+
</div>
|
|
360
|
+
</FormGroup>
|
|
361
|
+
</CollapsiblePanel>
|
|
362
|
+
<CollapsiblePanel title="Responsive Layout">
|
|
363
|
+
<FormGroup label="Collapse to Single Column">
|
|
364
|
+
<WidthSelector
|
|
365
|
+
value={layoutOptions.collapseColumnsWidth}
|
|
366
|
+
onChange={(collapseColumnsWidth) => {
|
|
367
|
+
onLayoutOptionsChange({ ...layoutOptions, collapseColumnsWidth })
|
|
368
|
+
}}
|
|
369
|
+
sign="< "
|
|
370
|
+
/>
|
|
371
|
+
</FormGroup>
|
|
372
|
+
<FormGroup label="Hide Quickfilters">
|
|
373
|
+
<WidthSelector
|
|
374
|
+
value={layoutOptions.hideQuickfiltersWidth}
|
|
375
|
+
onChange={(hideQuickfiltersWidth) => {
|
|
376
|
+
onLayoutOptionsChange({ ...layoutOptions, hideQuickfiltersWidth })
|
|
377
|
+
}}
|
|
378
|
+
sign="< "
|
|
379
|
+
/>
|
|
380
|
+
</FormGroup>
|
|
381
|
+
<FormGroup label="Minimum Width (before scrolling or scaling)">
|
|
382
|
+
<WidthSelector
|
|
383
|
+
value={layoutOptions.minimumWidth}
|
|
384
|
+
onChange={(minimumWidth) => {
|
|
385
|
+
onLayoutOptionsChange({ ...layoutOptions, minimumWidth })
|
|
386
|
+
}}
|
|
387
|
+
sign="< "
|
|
388
|
+
/>
|
|
389
|
+
<FormGroup label="When Below Minimum Width">
|
|
390
|
+
<Toggle
|
|
391
|
+
value={layoutOptions.belowMinimumWidth}
|
|
392
|
+
onChange={(belowMinimumWidth) => {
|
|
393
|
+
onLayoutOptionsChange({ ...layoutOptions, belowMinimumWidth: belowMinimumWidth as "scale" | "scroll" })
|
|
394
|
+
}}
|
|
395
|
+
size="sm"
|
|
396
|
+
options={[
|
|
397
|
+
{ value: "scroll", label: "Scroll" },
|
|
398
|
+
{ value: "scale", label: "Scale" }
|
|
399
|
+
]}
|
|
400
|
+
/>
|
|
401
|
+
</FormGroup>
|
|
402
|
+
</FormGroup>
|
|
403
|
+
<FormGroup label="Maximum Width (before padding)">
|
|
404
|
+
<WidthSelector
|
|
405
|
+
value={layoutOptions.maximumWidth}
|
|
406
|
+
onChange={(maximumWidth) => {
|
|
407
|
+
onLayoutOptionsChange({ ...layoutOptions, maximumWidth })
|
|
408
|
+
}}
|
|
409
|
+
sign="> "
|
|
410
|
+
/>
|
|
411
|
+
</FormGroup>
|
|
412
|
+
<Checkbox value={layoutOptions.collapseSpacers} onChange={(collapseSpacers) => {
|
|
413
|
+
onLayoutOptionsChange({ ...layoutOptions, collapseSpacers })
|
|
414
|
+
}}>
|
|
415
|
+
Collapse Spacers on Mobile
|
|
416
|
+
</Checkbox>
|
|
417
|
+
</CollapsiblePanel>
|
|
418
|
+
|
|
419
|
+
<CollapsiblePanel title="Download/Upload Theme" initiallyClosed>
|
|
420
|
+
<div className="mb-2 text-muted">
|
|
421
|
+
Download or upload a custom theme to use for this dashboard.
|
|
422
|
+
This saves the current theme as a theme file that you can then use on other dashboards by uploading it there.
|
|
423
|
+
</div>
|
|
424
|
+
<div style={{ display: "flex", flexDirection: "column", marginTop: "10px", gap: "10px" }}>
|
|
425
|
+
<button className="btn btn-sm btn-secondary" onClick={handleDownloadTheme}>
|
|
426
|
+
<i className="fas fa-download" /> Download Custom Theme
|
|
427
|
+
</button>
|
|
428
|
+
<label className="btn btn-sm btn-secondary">
|
|
429
|
+
<i className="fas fa-upload" /> Upload Custom Theme
|
|
430
|
+
<input
|
|
431
|
+
type="file"
|
|
432
|
+
accept=".theme"
|
|
433
|
+
style={{ display: "none" }}
|
|
434
|
+
onChange={handleUploadTheme}
|
|
435
|
+
/>
|
|
436
|
+
</label>
|
|
437
|
+
</div>
|
|
438
|
+
</CollapsiblePanel>
|
|
439
|
+
</div>
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function SpacingInput(props: { value: Spacing; onChange: (value: Spacing) => void }) {
|
|
444
|
+
return (
|
|
445
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', width: '100%' }}>
|
|
446
|
+
<div>Top</div>
|
|
447
|
+
<div>Bottom</div>
|
|
448
|
+
<div>Left</div>
|
|
449
|
+
<div>Right</div>
|
|
450
|
+
<PixelsInput value={props.value.top} onChange={(top) => props.onChange({ ...props.value, top: top! })} />
|
|
451
|
+
<PixelsInput value={props.value.bottom} onChange={(bottom) => props.onChange({ ...props.value, bottom: bottom! })} />
|
|
452
|
+
<PixelsInput value={props.value.left} onChange={(left) => props.onChange({ ...props.value, left: left! })} />
|
|
453
|
+
<PixelsInput value={props.value.right} onChange={(right) => props.onChange({ ...props.value, right: right! })} />
|
|
454
|
+
</div>
|
|
455
|
+
)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function PixelsInput(props: {
|
|
459
|
+
value: number | null
|
|
460
|
+
onChange: (value: number | null) => void
|
|
461
|
+
allowDefault?: boolean
|
|
462
|
+
defaultLabel?: string
|
|
463
|
+
}) {
|
|
464
|
+
const options = [
|
|
465
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40
|
|
466
|
+
]
|
|
467
|
+
|
|
468
|
+
return (
|
|
469
|
+
<div className="dropdown">
|
|
470
|
+
<a
|
|
471
|
+
className="dropdown-toggle"
|
|
472
|
+
type="button"
|
|
473
|
+
id="pixelsInputDropdown"
|
|
474
|
+
data-bs-toggle="dropdown"
|
|
475
|
+
aria-expanded="false"
|
|
476
|
+
>
|
|
477
|
+
{props.value === null ? (props.defaultLabel || "Default") : `${props.value}px`}
|
|
478
|
+
</a>
|
|
479
|
+
<ul className="dropdown-menu" aria-labelledby="pixelsInputDropdown">
|
|
480
|
+
{props.allowDefault && (
|
|
481
|
+
<li key="default">
|
|
482
|
+
<a
|
|
483
|
+
className="dropdown-item"
|
|
484
|
+
href="#"
|
|
485
|
+
onClick={(e) => {
|
|
486
|
+
e.preventDefault()
|
|
487
|
+
props.onChange(null)
|
|
488
|
+
}}
|
|
489
|
+
>
|
|
490
|
+
{props.defaultLabel || "Default"}
|
|
491
|
+
</a>
|
|
492
|
+
</li>
|
|
493
|
+
)}
|
|
494
|
+
{options.map(option => (
|
|
495
|
+
<li key={option}>
|
|
496
|
+
<a
|
|
497
|
+
className="dropdown-item"
|
|
498
|
+
href="#"
|
|
499
|
+
onClick={(e) => {
|
|
500
|
+
e.preventDefault()
|
|
501
|
+
props.onChange(option)
|
|
502
|
+
}}
|
|
503
|
+
>
|
|
504
|
+
{option}px
|
|
505
|
+
</a>
|
|
506
|
+
</li>
|
|
507
|
+
))}
|
|
508
|
+
</ul>
|
|
509
|
+
</div>
|
|
205
510
|
)
|
|
206
511
|
}
|
|
207
512
|
|
|
@@ -226,4 +531,4 @@ function WidthSelector(props: {
|
|
|
226
531
|
]}
|
|
227
532
|
/>
|
|
228
533
|
)
|
|
229
|
-
}
|
|
534
|
+
}
|