diff --git a/src/BloomBrowserUI/bookEdit/bookSettings/BookSettingsDialog.tsx b/src/BloomBrowserUI/bookEdit/bookSettings/BookSettingsDialog.tsx index dd7baacf5ddc..c9975a998edd 100644 --- a/src/BloomBrowserUI/bookEdit/bookSettings/BookSettingsDialog.tsx +++ b/src/BloomBrowserUI/bookEdit/bookSettings/BookSettingsDialog.tsx @@ -1,16 +1,18 @@ import { css } from "@emotion/react"; -import { ListItem, Slider, Typography } from "@mui/material"; +import { Slider, Typography } from "@mui/material"; import { ConfigrPane, + ConfigrPage, ConfigrGroup, - ConfigrSubgroup, + ConfigrStatic, ConfigrCustomStringInput, ConfigrCustomObjectInput, ConfigrBoolean, ConfigrSelect, } from "@sillsdev/config-r"; import * as React from "react"; -import { kBloomBlue } from "../../bloomMaterialUITheme"; +import { kBloomBlue, lightTheme } from "../../bloomMaterialUITheme"; +import { ThemeProvider } from "@mui/material/styles"; import { BloomDialog, DialogMiddle, @@ -28,7 +30,6 @@ import { DialogResult, } from "../../react_components/color-picking/colorPickerDialog"; import { - get, post, postJson, useApiBoolean, @@ -65,7 +66,7 @@ export interface IAppearanceSettings { // Stuff we get from the book/settings api. // Not yet complete export interface IBookSettings { - appearance: IAppearanceSettings; + appearance?: IAppearanceSettings; firstPossiblyLegacyCss?: string; } @@ -92,11 +93,10 @@ enum PageNumberPosition { export const BookSettingsDialog: React.FunctionComponent<{ initiallySelectedGroupIndex?: number; }> = (props) => { - const { showDialog, closeDialog, propsForBloomDialog } = - useSetupBloomDialog({ - initiallyOpen: true, - dialogFrameProvidedExternally: false, - }); + const { closeDialog, propsForBloomDialog } = useSetupBloomDialog({ + initiallyOpen: true, + dialogFrameProvidedExternally: false, + }); const appearanceUIOptions: IAppearanceUIOptions = useApiObject( @@ -191,7 +191,7 @@ export const BookSettingsDialog: React.FunctionComponent<{ "Show Credits", "BookSettings.ShowCredits", ); - const frontAndBackMatterLabel = useL10n( + const _frontAndBackMatterLabel = useL10n( "Front & Back Matter", "BookSettings.FrontAndBackMatter", ); @@ -224,7 +224,7 @@ export const BookSettingsDialog: React.FunctionComponent<{ "BookSettings.PageNumbers.Hidden", ); - const frontAndBackMatterDescription = useL10n( + const _frontAndBackMatterDescription = useL10n( "Normally, books use the front & back matter pack that is chosen for the entire collection. Using this setting, you can cause this individual book to use a different one.", "BookSettings.FrontAndBackMatter.Description", ); @@ -314,12 +314,25 @@ export const BookSettingsDialog: React.FunctionComponent<{ () => propsForBloomDialog.open, ); - const [settings, setSettings] = React.useState( + const [settings, setSettings] = React.useState( undefined, ); - const [settingsToReturnLater, setSettingsToReturnLater] = - React.useState(""); + const [settingsToReturnLater, setSettingsToReturnLater] = React.useState< + string | IBookSettings | undefined + >(undefined); + + const normalizeConfigrSettings = ( + settingsValue: string | IBookSettings | undefined, + ): IBookSettings | undefined => { + if (!settingsValue) { + return undefined; + } + if (typeof settingsValue === "string") { + return JSON.parse(settingsValue) as IBookSettings; + } + return settingsValue; + }; const [appearanceDisabled, setAppearanceDisabled] = React.useState(false); @@ -356,14 +369,14 @@ export const BookSettingsDialog: React.FunctionComponent<{ const bookSettingsTitle = useL10n("Book Settings", "BookSettings.Title"); React.useEffect(() => { - if (settings && (settings as any).appearance) { - const liveSettings = settingsToReturnLater || settings; + if (settings?.appearance) { + const liveSettings = + normalizeConfigrSettings(settingsToReturnLater) ?? settings; // when we're in legacy, we're just going to disable all the appearance controls setAppearanceDisabled( - (liveSettings as any)?.appearance?.cssThemeName === - "legacy-5-6", + liveSettings?.appearance?.cssThemeName === "legacy-5-6", ); - setTheme((liveSettings as IBookSettings)?.appearance?.cssThemeName); + setTheme(liveSettings?.appearance?.cssThemeName ?? ""); } }, [settings, settingsToReturnLater]); @@ -381,9 +394,10 @@ export const BookSettingsDialog: React.FunctionComponent<{ const tierAllowsFullBleed = useGetFeatureStatus("PrintshopReady")?.enabled; function saveSettingsAndCloseDialog() { - if (settingsToReturnLater) { + const settingsToPost = normalizeConfigrSettings(settingsToReturnLater); + if (settingsToPost) { // If nothing changed, we don't get any...and don't need to make this call. - postJson("book/settings", settingsToReturnLater); + postJson("book/settings", settingsToPost); } isOpenAlready = false; closeDialog(); @@ -443,8 +457,6 @@ export const BookSettingsDialog: React.FunctionComponent<{ - + {appearanceDisabled && ( - -
- The selected page theme does not support - the following settings. -
-
+ + +
+ The selected page theme does not + support the following settings. +
+
+
)} - +
- - + + - + {/* - - */} - - + */} + + { // This group of four possible messages...sometimes none of them shows, so there are five options... // is very similar to the one in BookInfoIndicator.tsx. If you change one, you may need to change the other. @@ -577,80 +594,90 @@ export const BookSettingsDialog: React.FunctionComponent<{ // I'm not seeing a clean way to reuse the logic. Some sort of higher-order component might work, // but I don't think the logic is complex enough to be worth it, when only used in two places. } - {firstPossiblyLegacyCss && + {firstPossiblyLegacyCss.length > 0 && theme === "legacy-5-6" && ( - - - + + + + + )} {firstPossiblyLegacyCss === "customBookStyles.css" && theme !== "legacy-5-6" && ( - -
- {migratedTheme ? ( - - ) : ( - - )} -
- deleteCustomBookStyles() - } - > - -
+ +
+ {migratedTheme ? ( + + ) : ( + + )} +
+ deleteCustomBookStyles() + } > - Delete{" "} - {firstPossiblyLegacyCss} -
+ +
+ Delete{" "} + {firstPossiblyLegacyCss} +
+
-
- + + )} - {firstPossiblyLegacyCss && + {firstPossiblyLegacyCss.length > 0 && firstPossiblyLegacyCss !== "customBookStyles.css" && theme !== "legacy-5-6" && ( - - - + + + + + )} - + {/* Wrapping these two in a div prevents Config-R from sticking a divider between them */}
- - + - - + + - - - - + + + +
-
- - + + + {/* note that this is used for bloomPUB and ePUB, but we don't have separate settings so we're putting them in bloomPUB and leaving it to c# code to use it for ePUB as well. */} - - - - -
-

- When you publish a book to the web or as - an ebook, Bloom will flag any - problematic fonts. For example, we - cannot legally host most Microsoft fonts - on BloomLibrary.org. -

-

- The following table shows where fonts - have been used. -

-
-
- -
+ + + +
+ + + + +
+

+ When you publish a book to the + web or as an ebook, Bloom will + flag any problematic fonts. For + example, we cannot legally host + most Microsoft fonts on + BloomLibrary.org. +

+

+ The following table shows where + fonts have been used. +

+
+
+ +
+
+
)} @@ -901,40 +943,42 @@ const BloomResolutionSliderInner: React.FunctionComponent<{ ); return ( -
- +
{`${currentLabel}`} - { - return `${current.w}x${current.h}`; - }} - onChange={(e, value) => { - props.onChange({ - maxWidth: sizes[value as number].w, - maxHeight: sizes[value as number].h, - }); - }} - valueLabelDisplay="auto" - > -
+ > + {`${currentLabel}`} + { + return `${current.w}x${current.h}`; + }} + onChange={(e, value) => { + props.onChange({ + maxWidth: sizes[value as number].w, + maxHeight: sizes[value as number].h, + }); + }} + valueLabelDisplay="auto" + > +
+ ); }; @@ -1051,19 +1095,3 @@ const ColorPickerForConfigr: React.FunctionComponent<{ /> ); }; - -// TODO: move this to config-r -const ConfigrCustomRow: React.FunctionComponent< - React.PropsWithChildren -> = (props) => { - return ( - - {props.children} - - ); -}; diff --git a/src/BloomBrowserUI/bookEdit/bookSettings/FieldVisibilityGroup.tsx b/src/BloomBrowserUI/bookEdit/bookSettings/FieldVisibilityGroup.tsx index 6123fc94e4ab..3dcffdce8ed1 100644 --- a/src/BloomBrowserUI/bookEdit/bookSettings/FieldVisibilityGroup.tsx +++ b/src/BloomBrowserUI/bookEdit/bookSettings/FieldVisibilityGroup.tsx @@ -20,7 +20,7 @@ export const FieldVisibilityGroup: React.FunctionComponent<{ labelFrame: string; labelFrameL10nKey: string; settings: object | undefined; - settingsToReturnLater: string; + settingsToReturnLater: string | object | undefined; disabled: boolean; L1MustBeTurnedOn?: boolean; @@ -83,8 +83,13 @@ export const FieldVisibilityGroup: React.FunctionComponent<{ const [showL1, showL2, showL3, numberShowing] = useMemo(() => { let appearance = props.settings?.["appearance"]; if (props.settingsToReturnLater) { - // although we declared it a string, it appears the Config-R callback always gives us an object - appearance = props.settingsToReturnLater["appearance"]; + // although we originally declared it a string, Config-R may return a JSON string or an object + if (typeof props.settingsToReturnLater === "string") { + const parsedSettings = JSON.parse(props.settingsToReturnLater); + appearance = parsedSettings["appearance"]; + } else { + appearance = props.settingsToReturnLater["appearance"]; + } } if (!appearance) { // This is a bit arbitrary. It should only apply during early renders. diff --git a/src/BloomBrowserUI/collection/CollectionSettingsDialog.tsx b/src/BloomBrowserUI/collection/CollectionSettingsDialog.tsx index 8cf882633128..9a313beca1c8 100644 --- a/src/BloomBrowserUI/collection/CollectionSettingsDialog.tsx +++ b/src/BloomBrowserUI/collection/CollectionSettingsDialog.tsx @@ -1,6 +1,11 @@ import { css } from "@emotion/react"; import * as React from "react"; -import { ConfigrGroup, ConfigrPane } from "@sillsdev/config-r"; +import { + ConfigrGroup, + ConfigrPage, + ConfigrPane, + ConfigrStatic, +} from "@sillsdev/config-r"; import { BloomDialog, DialogBottomButtons, @@ -27,6 +32,7 @@ export const CollectionSettingsDialog: React.FunctionComponent = () => { ); const [settingsString, setSettingsString] = React.useState("{}"); + // Fetch collection settings when the dialog opens so we sync with host state. React.useEffect(() => { if (propsForBloomDialog.open) get("collection/settings", (result) => { @@ -34,8 +40,22 @@ export const CollectionSettingsDialog: React.FunctionComponent = () => { }); }, [propsForBloomDialog.open]); - const [settingsToReturnLater, setSettingsToReturnLater] = - React.useState(""); + const [settingsToReturnLater, setSettingsToReturnLater] = React.useState< + string | object | undefined + >(undefined); + + const normalizeConfigrSettings = ( + settingsValue: string | object | undefined, + ): object | undefined => { + if (!settingsValue) { + return undefined; + } + if (typeof settingsValue === "string") { + return JSON.parse(settingsValue) as object; + } + return settingsValue; + }; + // Parse the settings JSON for Configr's initial values once it arrives. React.useEffect(() => { if (settingsString === "{}") { return; // leave settings as undefined @@ -66,33 +86,76 @@ export const CollectionSettingsDialog: React.FunctionComponent = () => { height: 100%; `} > - { - setSettingsToReturnLater(s); - }} - > - - - + {settings && ( + { + setSettingsToReturnLater(s); + }} + > + + + +
+ Settings for this section are not + available yet. +
+
+
+
+ + + +
+ Settings for this section are not + available yet. +
+
+
+
+
+ )} { - postJson("collection/settings", settingsToReturnLater); + const settingsToPost = normalizeConfigrSettings( + settingsToReturnLater, + ); + if (settingsToPost) { + postJson("collection/settings", settingsToPost); + } closeDialog(); }} /> diff --git a/src/BloomBrowserUI/package.json b/src/BloomBrowserUI/package.json index b52b787ecde6..0340b65f75f7 100644 --- a/src/BloomBrowserUI/package.json +++ b/src/BloomBrowserUI/package.json @@ -128,7 +128,7 @@ "@nivo/core": "^0.80.0", "@nivo/scatterplot": "^0.80.0", "@nivo/tooltip": "^0.80.0", - "@sillsdev/config-r": "1.0.0-alpha.15", + "@sillsdev/config-r": "1.0.0-alpha.18", "@types/filesize": "^5.0.0", "@types/react-transition-group": "^4.4.1", "@use-it/event-listener": "^0.1.7", diff --git a/src/BloomBrowserUI/patches/@sillsdev+config-r+1.0.0-alpha.15.patch b/src/BloomBrowserUI/patches/@sillsdev+config-r+1.0.0-alpha.15.patch deleted file mode 100644 index 240038e629e8..000000000000 --- a/src/BloomBrowserUI/patches/@sillsdev+config-r+1.0.0-alpha.15.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/node_modules/@sillsdev/config-r/package.json b/node_modules/@sillsdev/config-r/package.json -index 1234567..abcdefg 100644 ---- a/node_modules/@sillsdev/config-r/package.json -+++ b/node_modules/@sillsdev/config-r/package.json -@@ -92,7 +92,9 @@ - "types": "./dist/index.d.ts", - "exports": { - ".": { -- "require": "./dist/configr.es.js" -+ "import": "./dist/configr.es.js", -+ "require": "./dist/configr.es.js", -+ "default": "./dist/configr.es.js" - } - }, - "publishConfig": { diff --git a/src/BloomBrowserUI/yarn.lock b/src/BloomBrowserUI/yarn.lock index 421e5b9ed009..d7cbabbfff85 100644 --- a/src/BloomBrowserUI/yarn.lock +++ b/src/BloomBrowserUI/yarn.lock @@ -2930,10 +2930,10 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz#1657f56326bbe0ac80eedc9f9c18fc1ddd24e107" integrity sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg== -"@sillsdev/config-r@1.0.0-alpha.15": - version "1.0.0-alpha.15" - resolved "https://registry.yarnpkg.com/@sillsdev/config-r/-/config-r-1.0.0-alpha.15.tgz#0979c316e50e6d7edbe699e30235c3160cbf18b0" - integrity sha512-blKYURgkxTr7kdjR13+7JDwnyqolMtfKaTKAVRuEiyLxbNNUiHDIXazc7A9k/tNBPNpItAT21tu4E+3RZB9gXQ== +"@sillsdev/config-r@1.0.0-alpha.18": + version "1.0.0-alpha.18" + resolved "https://registry.npmjs.org/@sillsdev/config-r/-/config-r-1.0.0-alpha.18.tgz#177178ec2bba9e2843a3edab949c6b6489f0286d" + integrity sha512-EFiyAwUTMJ4jlvXRMBsO4+Zm8Gkaur+idUB3czXADqE0zG8ZnrMug951dWv67uFLH6hZT9jhGasEsHU1G/2/qA== dependencies: "@textea/json-viewer" "^2.13.1" formik "^2.2.9"