Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AG-9300 Prompt to avoid loss of saved work in Theme Builder
- Loading branch information
1 parent
c58bc5f
commit ee5e5d3
Showing
5 changed files
with
186 additions
and
128 deletions.
There are no files selected for viewing
44 changes: 34 additions & 10 deletions
44
documentation/ag-grid-docs/src/components/theme-builder/ThemeBuilder.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,42 @@ | ||
import { Provider, createStore } from 'jotai'; | ||
import { useMemo } from 'react'; | ||
import { useLayoutEffect, useMemo, useState } from 'react'; | ||
|
||
import { RootContainer } from './components/general/RootContainer'; | ||
import { applyPreset, darkModePreset, lightModePreset } from './components/presets/presets'; | ||
import { allParamModels } from './model/ParamModel'; | ||
import { allPartModels } from './model/PartModel'; | ||
import { addChangedModelItem, getChangedModelItemCount } from './model/changed-model-items'; | ||
import { rerenderTheme } from './model/rendered-theme'; | ||
|
||
export const ThemeBuilder = () => { | ||
const store = useMemo(createStore, []); | ||
const store = useMemo(createStore, []); | ||
|
||
(window as any).handlePartsCssChange = () => { | ||
rerenderTheme(store); | ||
}; | ||
|
||
const [initialised, setInitialised] = useState(false); | ||
|
||
useLayoutEffect(() => { | ||
const hasChanges = getChangedModelItemCount(store) !== 0; | ||
if (!hasChanges) { | ||
const isDarkMode = document.documentElement.dataset.darkMode === 'true'; | ||
applyPreset(store, isDarkMode ? darkModePreset : lightModePreset); | ||
} | ||
|
||
const detectChange = (name: string) => { | ||
addChangedModelItem(store, name); | ||
}; | ||
const listeners = [ | ||
...allParamModels().map((param) => store.sub(param.valueAtom, () => detectChange(param.property))), | ||
...allPartModels().map((part) => store.sub(part.variantAtom, () => detectChange(part.partId))), | ||
]; | ||
|
||
(window as any).handlePartsCssChange = () => { | ||
rerenderTheme(store); | ||
}; | ||
if (!initialised) { | ||
setInitialised(true); | ||
} | ||
return () => listeners.forEach((listener) => listener()); | ||
}, []); | ||
|
||
return ( | ||
<Provider store={store}> | ||
<RootContainer /> | ||
</Provider> | ||
); | ||
return <Provider store={store}>{initialised && <RootContainer />}</Provider>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
documentation/ag-grid-docs/src/components/theme-builder/components/presets/presets.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { type CoreParam, type PartId, opaqueForeground, ref } from '@ag-grid-community/theming'; | ||
import { allParamModels } from '@components/theme-builder/model/ParamModel'; | ||
import { allPartModels } from '@components/theme-builder/model/PartModel'; | ||
import { getApplicationConfigAtom } from '@components/theme-builder/model/application-config'; | ||
import { resetChangedModelItems } from '@components/theme-builder/model/changed-model-items'; | ||
|
||
import type { Store } from '../../model/store'; | ||
|
||
export type Preset = { | ||
pageBackgroundColor: string; | ||
params?: Partial<Record<CoreParam, string>>; | ||
parts?: Partial<Record<PartId, string>>; | ||
}; | ||
|
||
export const lightModePreset: Preset = { | ||
pageBackgroundColor: '#FAFAFA', | ||
}; | ||
export const darkModePreset: Preset = { | ||
pageBackgroundColor: '#1D2634', | ||
params: { | ||
backgroundColor: '#1f2836', | ||
foregroundColor: '#FFF', | ||
chromeBackgroundColor: opaqueForeground(0.07), | ||
}, | ||
}; | ||
|
||
export const allPresets: Preset[] = [ | ||
lightModePreset, | ||
darkModePreset, | ||
{ | ||
pageBackgroundColor: 'rgb(75, 153, 154)', | ||
params: { | ||
backgroundColor: 'rgb(241, 237, 225)', | ||
foregroundColor: 'rgb(46, 55, 66)', | ||
chromeBackgroundColor: ref('backgroundColor'), | ||
fontFamily: 'google:Press Start 2P', | ||
gridSize: '4px', | ||
}, | ||
}, | ||
{ | ||
pageBackgroundColor: '#948B8E', | ||
params: { | ||
backgroundColor: '#E4E0E2', | ||
headerBackgroundColor: '#807078', | ||
headerTextColor: '#EEECED', | ||
// headerBackgroundColor: '#807078', | ||
foregroundColor: 'rgb(46, 55, 66)', | ||
chromeBackgroundColor: ref('backgroundColor'), | ||
fontFamily: 'google:Jacquard 24', | ||
gridSize: '8px', | ||
wrapperBorderRadius: '0px', | ||
headerFontWeight: '600', | ||
}, | ||
}, | ||
{ | ||
pageBackgroundColor: '#212124', | ||
params: { | ||
backgroundColor: '#252A33', | ||
headerBackgroundColor: '#8AB4F9', | ||
headerTextColor: '#252A33', | ||
// headerBackgroundColor: '#807078', | ||
foregroundColor: '#BDC2C7', | ||
chromeBackgroundColor: ref('backgroundColor'), | ||
fontFamily: 'google:Plus Jakarta Sans', | ||
gridSize: '8px', | ||
wrapperBorderRadius: '12px', | ||
headerFontWeight: '600', | ||
accentColor: '#8AB4F9', | ||
rowVerticalPaddingScale: '0.6', | ||
}, | ||
}, | ||
{ | ||
pageBackgroundColor: '#ffffff', | ||
params: { | ||
backgroundColor: '#ffffff', | ||
headerBackgroundColor: '#F9FAFB', | ||
headerTextColor: '#919191', | ||
foregroundColor: 'rgb(46, 55, 66)', | ||
fontFamily: 'Arial', | ||
gridSize: '8px', | ||
wrapperBorderRadius: '0px', | ||
headerFontWeight: '600', | ||
oddRowBackgroundColor: '#F9FAFB', | ||
rowBorder: 'none', | ||
wrapperBorder: 'none', | ||
}, | ||
}, | ||
]; | ||
|
||
export const applyPreset = (store: Store, preset: Preset) => { | ||
const presetParams: any = preset.params || {}; | ||
for (const { property, valueAtom } of allParamModels()) { | ||
if (store.get(valueAtom) != null || presetParams[property] != null) { | ||
store.set(valueAtom, presetParams[property] || null); | ||
} | ||
} | ||
|
||
const presetParts = preset.parts || {}; | ||
for (const part of allPartModels()) { | ||
const newVariantId = presetParts[part.partId]; | ||
if (store.get(part.variantAtom) != null || newVariantId != null) { | ||
const newVariant = | ||
newVariantId == null ? part.defaultVariant : part.variants.find((v) => v.variantId === newVariantId); | ||
if (!newVariant) { | ||
throw new Error( | ||
`Invalid variant ${newVariantId} for part ${part.partId}, use one of: ${part.variants.map((v) => v.variantId).join(', ')}` | ||
); | ||
} | ||
store.set(part.variantAtom, newVariant); | ||
} | ||
} | ||
store.set(getApplicationConfigAtom('previewPaneBackgroundColor'), preset.pageBackgroundColor || null); | ||
resetChangedModelItems(store); | ||
}; |
23 changes: 23 additions & 0 deletions
23
documentation/ag-grid-docs/src/components/theme-builder/model/changed-model-items.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { atomWithJSONStorage } from './JSONStorage'; | ||
import type { Store } from './store'; | ||
|
||
const changedParamsAtom = atomWithJSONStorage<string[] | null>('changedParams', null); | ||
|
||
export const addChangedModelItem = (store: Store, name: string) => { | ||
let existing = store.get(changedParamsAtom); | ||
if (!Array.isArray(existing)) { | ||
existing = []; | ||
} | ||
if (!existing.includes(name)) { | ||
store.set(changedParamsAtom, [...existing, name]); | ||
} | ||
}; | ||
|
||
export const resetChangedModelItems = (store: Store) => { | ||
store.set(changedParamsAtom, null); | ||
}; | ||
|
||
export const getChangedModelItemCount = (store: Store) => { | ||
const changes = store.get(changedParamsAtom); | ||
return Array.isArray(changes) ? changes.length : 0; | ||
}; |