+ {
+ if (typeof s === "string") {
+ setSettingsToReturnLater(s);
+ applyPageSettings(
+ JSON.parse(s) as IPageSettings,
+ );
+ return;
+ }
+
+ if (typeof s === "object" && s) {
+ const settings = s as IPageSettings;
+ setSettingsToReturnLater(settings);
+ applyPageSettings(settings);
+ return;
+ }
+
+ throw new Error(
+ "PageSettingsDialog: unexpected value from config-r onChange",
+ );
+ }}
+ >
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+ );
+};
+
+export const showPageSettingsDialog = () => {
+ if (!isOpenAlready) {
+ isOpenAlready = true;
+ ShowEditViewDialog();
+ }
+};
diff --git a/src/BloomBrowserUI/react_components/color-picking/bloomPalette.ts b/src/BloomBrowserUI/react_components/color-picking/bloomPalette.ts
index 0b8e3278b01d..04b9d1e09ab4 100644
--- a/src/BloomBrowserUI/react_components/color-picking/bloomPalette.ts
+++ b/src/BloomBrowserUI/react_components/color-picking/bloomPalette.ts
@@ -8,6 +8,7 @@ export enum BloomPalette {
BloomReaderBookshelf = "bloom-reader-bookshelf",
TextBackground = "overlay-background",
HighlightBackground = "highlight-background",
+ PageColors = "page-colors",
}
// This array provides a useful default palette for the color picker dialog.
@@ -64,6 +65,25 @@ export const HighlightBackgroundPalette: string[] = [
"#C5F0FF",
];
+// Light background colors suitable for page backgrounds.
+// (Users can still pick any color, but these are the suggested defaults.)
+export const PageColorsPalette: string[] = [
+ "#FFFFFF", // white
+ "#F7F7F7", // very light gray
+ "#FFF7E6", // warm cream
+ "#FFF1F2", // very light pink
+ "#FCE7F3", // pale rose
+ "#F3E8FF", // pale lavender
+ "#EDE9FE", // pale purple
+ "#E0F2FE", // pale sky
+ "#E0F7FA", // pale cyan
+ "#E6FFFA", // pale teal
+ "#ECFDF3", // pale green
+ "#F7FEE7", // pale lime
+ "#FFFBEB", // pale amber
+ "#FEF3C7", // light beige
+];
+
const specialColors: IColorInfo[] = [
// #DFB28B is the color Comical has been using as the default for captions.
// It's fairly close to the "Calico" color defined at https://www.htmlcsscolor.com/hex/D5B185 (#D5B185)
@@ -110,6 +130,9 @@ export async function getHexColorsForPalette(
case BloomPalette.CoverBackground:
factoryColors = CoverBackgroundPalette;
break;
+ case BloomPalette.PageColors:
+ factoryColors = PageColorsPalette;
+ break;
case BloomPalette.Text:
factoryColors = TextColorPalette;
break;
@@ -156,6 +179,9 @@ export function getDefaultColorsFromPalette(
case BloomPalette.CoverBackground:
palette = CoverBackgroundPalette;
break;
+ case BloomPalette.PageColors:
+ palette = PageColorsPalette;
+ break;
case BloomPalette.Text:
palette = TextColorPalette;
break;
diff --git a/src/BloomBrowserUI/react_components/color-picking/colorPickerDialog.tsx b/src/BloomBrowserUI/react_components/color-picking/colorPickerDialog.tsx
index 6688187f6c7b..0cd7d2c30124 100644
--- a/src/BloomBrowserUI/react_components/color-picking/colorPickerDialog.tsx
+++ b/src/BloomBrowserUI/react_components/color-picking/colorPickerDialog.tsx
@@ -1,4 +1,4 @@
-import { css } from "@emotion/react";
+import { css, Global } from "@emotion/react";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { useEffect, useRef, useState } from "react";
@@ -283,9 +283,30 @@ const ColorPickerDialog: React.FC = (props) => {
props.onChange(color);
};
+ const dialogOpen = props.open === undefined ? open : props.open;
+
+ // The MUI backdrop is rendered outside the dialog tree, so we use a body class
+ // to suppress it while the color picker is open.
+ useEffect(() => {
+ if (!dialogOpen) {
+ return;
+ }
+ document.body.classList.add("bloom-hide-color-picker-backdrop");
+ return () => {
+ document.body.classList.remove("bloom-hide-color-picker-backdrop");
+ };
+ }, [dialogOpen]);
+
return (
+ = (props) => {
padding: 10px 14px 10px 10px; // maintain same spacing all around dialog content and between header/footer
}
`}
- open={props.open === undefined ? open : props.open}
+ hideBackdrop={true}
+ BackdropProps={{
+ invisible: true,
+ }}
+ slotProps={{
+ backdrop: {
+ invisible: true,
+ },
+ }}
+ open={dialogOpen}
ref={dlgRef}
onClose={(
_event,
@@ -429,6 +459,7 @@ export interface IColorDisplayButtonProps {
width?: number;
disabled?: boolean;
onClose: (result: DialogResult, newColor: string) => void;
+ onChange?: (newColor: string) => void;
palette: BloomPalette;
}
@@ -494,9 +525,13 @@ export const ColorDisplayButton: React.FC = (
props.initialColor,
)}
onInputFocus={() => {}}
- onChange={(color: IColorInfo) =>
- setCurrentButtonColor(color.colors[0])
- }
+ onChange={(color: IColorInfo) => {
+ const newColor = color.colors[0];
+ setCurrentButtonColor(newColor);
+ if (props.onChange) {
+ props.onChange(newColor);
+ }
+ }}
/>
);
diff --git a/src/BloomExe/Book/HtmlDom.cs b/src/BloomExe/Book/HtmlDom.cs
index 8386e6787a8e..a53a180cbbd7 100644
--- a/src/BloomExe/Book/HtmlDom.cs
+++ b/src/BloomExe/Book/HtmlDom.cs
@@ -1915,6 +1915,14 @@ SafeXmlElement edittedPageDiv
//html file in a browser.
destinationPageDiv.SetAttribute("lang", edittedPageDiv.GetAttribute("lang"));
+ // Allow saving per-page CSS custom properties (e.g. --page-background-color) stored on the page div.
+ // If missing, remove any previously-saved style.
+ var style = edittedPageDiv.GetAttribute("style");
+ if (string.IsNullOrEmpty(style))
+ destinationPageDiv.RemoveAttribute("style");
+ else
+ destinationPageDiv.SetAttribute("style", style);
+
// Copy the two background audio attributes which can be set using the music toolbox.
// Ensuring that volume is missing unless the main attribute is non-empty is
// currently redundant, everything should work if we just copied all attributes.
diff --git a/src/BloomExe/Edit/EditingView.cs b/src/BloomExe/Edit/EditingView.cs
index b315fe1a48e5..c7932243c420 100644
--- a/src/BloomExe/Edit/EditingView.cs
+++ b/src/BloomExe/Edit/EditingView.cs
@@ -1913,6 +1913,23 @@ public void SaveAndOpenBookSettingsDialog()
);
}
+ public void SaveAndOpenPageSettingsDialog()
+ {
+ _model.SaveThen(
+ () =>
+ {
+ RunJavascriptAsync("editTabBundle.showEditViewPageSettingsDialog();");
+ return _model.CurrentPage.Id;
+ },
+ () => { } // wrong state, do nothing
+ );
+ }
+
+ private void _pageSettingsButton_Click(object sender, EventArgs e)
+ {
+ SaveAndOpenPageSettingsDialog();
+ }
+
// This is temporary code we added in 6.0 when trying to determine why we are sometimes losing
// user data upon save. See BL-13120.
private void _topBarPanel_Click(object sender, EventArgs e)
diff --git a/src/BloomExe/web/controllers/EditingViewApi.cs b/src/BloomExe/web/controllers/EditingViewApi.cs
index 114a27348e6b..5bd7dcfa6e89 100644
--- a/src/BloomExe/web/controllers/EditingViewApi.cs
+++ b/src/BloomExe/web/controllers/EditingViewApi.cs
@@ -120,6 +120,11 @@ public void RegisterWithApiHandler(BloomApiHandler apiHandler)
HandleShowBookSettingsDialog,
true
);
+ apiHandler.RegisterEndpointHandler(
+ "editView/showPageSettingsDialog",
+ HandleShowPageSettingsDialog,
+ true
+ );
}
private void HandleJumpToPage(ApiRequest request)
@@ -135,6 +140,12 @@ private void HandleShowBookSettingsDialog(ApiRequest request)
View.SaveAndOpenBookSettingsDialog();
}
+ private void HandleShowPageSettingsDialog(ApiRequest request)
+ {
+ request.PostSucceeded();
+ View.SaveAndOpenPageSettingsDialog();
+ }
+
///
/// This one is for the snapping function on dragging origami splitters.
///
diff --git a/src/content/appearanceMigrations/efl-zeromargin1/customBookStyles.css b/src/content/appearanceMigrations/efl-zeromargin1/customBookStyles.css
index c70b168314f5..6a7f94f5558a 100644
--- a/src/content/appearanceMigrations/efl-zeromargin1/customBookStyles.css
+++ b/src/content/appearanceMigrations/efl-zeromargin1/customBookStyles.css
@@ -28,7 +28,7 @@
--pageNumber-color: black;
--pageNumber-background-width: 17px;
--pageNumber-border-radius: 50%;
- --pageNumber-background-color: #ffffff;
+ --pageNumber-background-color: transparent;
font-family: "ABeeZee";
z-index: 1000;
diff --git a/src/content/appearanceThemes/appearance-theme-default.css b/src/content/appearanceThemes/appearance-theme-default.css
index 532dbed270cb..f7d7274e5a36 100644
--- a/src/content/appearanceThemes/appearance-theme-default.css
+++ b/src/content/appearanceThemes/appearance-theme-default.css
@@ -39,6 +39,8 @@
--pageNumber-background-width: unset; /* for when we need to have a colored background, e.g. a circle */
/* background-color: value in .numberedPage:after to display the page number */
--pageNumber-background-color: transparent;
+ /* color: value in .numberedPage:after to display the page number */
+ --pageNumber-color: black;
/* border-radius: value in .numberedPage:after to display the page number */
--pageNumber-border-radius: 0px;
/* left: value in .numberedPage.side-left:after to display the page number */
diff --git a/src/content/appearanceThemes/appearance-theme-rounded-border-ebook.css b/src/content/appearanceThemes/appearance-theme-rounded-border-ebook.css
index 36d7d8f3cf4c..aa769b7c0a0d 100644
--- a/src/content/appearanceThemes/appearance-theme-rounded-border-ebook.css
+++ b/src/content/appearanceThemes/appearance-theme-rounded-border-ebook.css
@@ -26,16 +26,16 @@
.numberedPage:where([class*="Device"]:not(.bloom-interactive-page)) {
--topLevel-text-padding: 0.5em;
}
-
[class*="Device"].numberedPage:not(.bloom-interactive-page) {
--pageNumber-extra-height: 0mm !important; /* we put the page number on top of the image so we don't need a margin boost */
+ --pageNumber-background-color: #ffffff; /* I'm not clear why this is white, but all I did in this change is to move it so that it can be overridden by page settings */
}
[class*="Device"].numberedPage:not(.bloom-interactive-page)::after {
--pageNumber-bottom: var(--page-margin-bottom);
--pageNumber-top: unset;
--pageNumber-font-size: 11pt;
--pageNumber-border-radius: 50%;
- --pageNumber-background-color: #ffffff;
+
--pageNumber-background-width: 33px;
--pageNumber-always-left-margin: var(--page-margin-left);
--pageNumber-right-margin: deliberately-invalid; /* prevents right being set at all. unset does not work. Prevent centering for this layout */
diff --git a/src/content/appearanceThemes/appearance-theme-zero-margin-ebook.css b/src/content/appearanceThemes/appearance-theme-zero-margin-ebook.css
index 520bf437b01c..784d6a3db242 100644
--- a/src/content/appearanceThemes/appearance-theme-zero-margin-ebook.css
+++ b/src/content/appearanceThemes/appearance-theme-zero-margin-ebook.css
@@ -17,8 +17,8 @@ Note that hiding the page numbers is done by a setting in appearance.json, not h
--page-horizontalSplit-height: 0mm;
}
-/* The section below controls the page number and the white circle around it. */
-.Device16x9Landscape.numberedPage {
+.numberedPage {
+ --pageNumber-background-color: #ffffff; /* I'm not clear why this is white, but all I did in this change is to move it so that it can be overridden by page settings */
--pageNumber-extra-height: 0mm !important; /* we put the page number on top of the image so we don't need a margin boost */
}
.Device16x9Portrait.numberedPage {
@@ -32,7 +32,7 @@ Note that hiding the page numbers is done by a setting in appearance.json, not h
--pageNumber-font-size: 11pt;
border-radius: 50%;
- --pageNumber-background-color: #ffffff;
+
--pageNumber-background-width: 33px;
--pageNumber-always-left-margin: var(--page-margin-left);
--pageNumber-right-margin: deliberately-invalid; /* prevents right being set at all. unset does not work. Prevent centering for this layout */
diff --git a/src/content/bookLayout/pageNumbers.less b/src/content/bookLayout/pageNumbers.less
index 441e0ab35281..e845542e69ea 100644
--- a/src/content/bookLayout/pageNumbers.less
+++ b/src/content/bookLayout/pageNumbers.less
@@ -7,6 +7,7 @@
// themes can override this as needed. If you have reasonable margins, you don't need to add anything to fit in a pageNumber
--pageNumber-extra-height: 0mm; // must have units
}
+
.numberedPage {
&:after {
content: attr(data-page-number);
@@ -22,6 +23,8 @@
bottom: var(--pageNumber-bottom);
top: var(--pageNumber-top);
background-color: var(--pageNumber-background-color);
+ color: var(--pageNumber-color);
+
border-radius: var(--pageNumber-border-radius);
z-index: 1000;
// These are needed to get the number centered in a circle. They have
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 000000000000..fb57ccd13afb
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+