Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation between pages and books with history #347

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

hatton
Copy link
Member

@hatton hatton commented Dec 4, 2024

This change is Reviewable

Summary by CodeRabbit

  • New Features

    • Enhanced Storybook configuration for improved static file handling and story sorting.
    • Introduced new styles for multilingual book layouts and branding elements.
    • Added new JSON configuration files for appearance settings and user preferences.
    • New BloomPlayerIframe component and useBuildIsReady hook for iframe integration.
  • Bug Fixes

    • Improved back button functionality and visibility management in the Bloom Player.
  • Documentation

    • Updated README files for clarity on usage and integration of the bloom-player package.
  • Tests

    • Comprehensive unit tests added for navigation functions and interaction within the iframe.
  • Style

    • New CSS files and classes added for better layout and presentation across various book formats.

@hatton hatton marked this pull request as ready for review December 4, 2024 22:12
Copy link

coderabbitai bot commented Dec 4, 2024

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

.storybook/main.ts

Oops! Something went wrong! :(

ESLint: 9.13.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

Walkthrough

The changes in this pull request encompass updates to configuration files, CSS styles, and components related to the Bloom Player project. Key modifications include enhancements to Storybook configuration, the introduction of new CSS files for styling multilingual books, and updates to the BloomPlayerControls and BloomPlayerCore components to improve navigation functionality. Additionally, new JSON files for appearance settings and metadata have been added, along with a comprehensive suite of tests for navigation functions. Overall, these changes aim to refine the user experience and improve the functionality of the Bloom Player interface.

Changes

File Change Summary
.storybook/main.ts Added staticDirs property and modified viteFinal function for proxy handling. Introduced idToBookName mapping.
.storybook/preview.ts Added options and storySort properties for custom story sorting.
README-advanced.md Updated installation instructions and file paths for bloom-player.
README.md Enhanced clarity on usage, parameters, and development instructions for bloom-player.
package.json Added buildForStorybook script and updated Storybook-related dependencies.
public/testBooks/multibook-index/Basic Book.css Introduced new CSS classes for multilingual book layouts.
public/testBooks/multibook-index/Traditional-XMatter.css Added styles for front matter and title pages.
public/testBooks/multibook-index/appearance.css Established default theme styles for books.
public/testBooks/multibook-index/appearance.json Created JSON file for multi-book appearance settings.
public/testBooks/multibook-index/basePage.css Updated styles for multi-book interface elements.
public/testBooks/multibook-index/book.userPrefs Added JSON object for user preferences.
public/testBooks/multibook-index/branding.css Defined styles for branding elements.
public/testBooks/multibook-index/customCollectionStyles.css Added comments for customizing styles.
public/testBooks/multibook-index/defaultLangStyles.css Introduced font-face declarations for various fonts.
public/testBooks/multibook-index/index.htm Created new HTML file for multi-book index structure.
public/testBooks/multibook-index/meta.json Added metadata for the multi-book project.
public/testBooks/multibook-index/origami.css Established styles for split-pane layout components.
public/testBooks/multibook-index/previewMode.css Defined styles for preview mode of books.
public/testBooks/multibook-target1/Basic Book.css Added CSS rules for multilingual book layouts.
public/testBooks/multibook-target1/Traditional-XMatter.css Defined styles for traditional book layouts.
public/testBooks/multibook-target1/appearance.css Established default styling rules for book elements.
public/testBooks/multibook-target1/appearance.json Created JSON configuration for appearance settings.
public/testBooks/multibook-target1/basePage.css Enhanced styling framework for book elements.
public/testBooks/multibook-target1/book.userPrefs Added JSON object for user preferences.
public/testBooks/multibook-target1/branding.css Defined styles for branding elements.
public/testBooks/multibook-target1/customCollectionStyles.css Added comments for managing custom styles.
public/testBooks/multibook-target1/defaultLangStyles.css Introduced font-face declarations for various fonts.
public/testBooks/multibook-target1/index.htm Created new HTML file for multi-book target structure.
public/testBooks/multibook-target1/meta.json Added metadata for the multi-book target project.
public/testBooks/multibook-target1/origami.css Established styles for split-pane layout components.
public/testBooks/multibook-target1/previewMode.css Defined styles for preview mode of books.
public/testBooks/multibook-target1/publish-settings.json Created JSON configuration for publishing settings.
src/bloom-player-controls.tsx Renamed onBackClicked to sendBackToHost and added getBackButtonState method.
src/bloom-player-core.tsx Updated state management and navigation methods.
src/bloomPlayerAnalytics.tsx Commented out debug log statement in track function.
src/bookInfo.ts Changed bookInstanceId access modifier from private to public.
src/controlBar.tsx Introduced BackButtonState enum and updated props interface.
src/externalContext.ts Renamed onBackClicked to sendBackToHost.
src/navigation.test.ts Added unit tests for navigation functions.
src/navigation.ts Implemented navigation history management and URL parsing functions.
src/stories/BloomPlayerIframe.tsx Introduced BloomPlayerIframe component and useBuildIsReady hook.
src/stories/BloomPlayerTester.ts Added BloomPlayerTester class for iframe interaction testing.
src/stories/multiBook.stories.tsx Created Storybook stories for BloomPlayerIframe in multi-book scenarios.
src/stories/navigation.stories.tsx Added Storybook story for navigation functionality within the iframe.
public/testBooks/multibook-index/publish-settings.json Created JSON configuration for publishing settings.

Poem

In the garden where stories bloom,
New styles and scripts dispel the gloom.
With buttons and pages, we hop with delight,
A multi-book journey, oh what a sight!
From CSS to JSON, each change a cheer,
Hopping along, we spread joy and cheer! 🐇📚


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 27

🧹 Outside diff range and nitpick comments (51)
public/testBooks/multibook-target1/Traditional-XMatter.css (3)

1-9: LGTM! Consider documenting the hidden "Traditional" text usage.

The pseudo-element implementation is clean and follows best practices. The hidden "Traditional" text might be used in specific contexts - consider adding a comment explaining its purpose.


218-226: Consider using modern CSS gap property

The flex gaps could be simplified using the modern gap property instead of dedicated gap elements.

Instead of using elements for gaps:

- .titlePage .smallFlexGap {
-   flex: 0 1 0.5em;
- }
- .titlePage .largeFlexGap {
-   flex: 0 4 3em;
- }
- .titlePage .fillPageFlexGap {
-   flex: 1 4 3em;
- }

Consider using:

.titlePage .marginBox {
  display: flex;
  flex-direction: column;
  gap: var(--title-page-gap, 1em);
}

1-262: Consider adopting CSS custom properties for better maintainability

The stylesheet implements a comprehensive layout system, but could benefit from better variable usage:

  1. Define a set of CSS custom properties for commonly used values (margins, paddings, colors)
  2. Create a consistent naming convention for variables
  3. Consider breaking the file into logical sections with comments

This would improve maintainability and make the styling system more flexible for different book formats.

public/testBooks/multibook-index/branding.css (2)

1-9: Update documentation to reflect CSS instead of LESS

The comments reference .less files (bloom-xmatter-commons.less and branding-base.less), but this is a CSS file. This might cause confusion for developers.

Consider updating the documentation to reference the correct file types or clarify if there's a LESS to CSS compilation step in the build process.


10-24: Consider adding fallbacks for better browser compatibility

The styles use modern CSS features like flexbox and object-fit. While these are well-supported, consider adding fallbacks for older browsers.

[data-book*="branding"] {
  display: flex;
+ display: -webkit-flex; /* Safari */
  flex-direction: column;
+ -webkit-flex-direction: column; /* Safari */
}
[data-book*="branding"] img {
  margin-left: auto;
  margin-right: auto;
  width: auto;
  max-width: 100%;
  align-self: center;
+ -webkit-align-self: center; /* Safari */
  object-fit: contain;
+ font-family: "object-fit: contain"; /* object-fit polyfill */
}
public/testBooks/multibook-target1/appearance.css (3)

1-118: Consider improving variable naming and fixing comment formatting.

While the implementation is thorough and well-documented, there are a few suggestions for improvement:

  1. Consider shortening --page-and-marginBox-are-same-color-multiplicand to something more concise like --page-marginBox-color-match.
  2. The comment at line 103 is missing a closing parenthesis.
  3. The comment at lines 115-116 is incorrectly split across lines.
- --page-and-marginBox-are-same-color-multiplicand: 1;
+ --page-marginBox-color-match: 1;

- /* it is not transparent because at edit time we set the parent (the translationGroup) color to show padding
+ /* it is not transparent because at edit time we set the parent (the translationGroup) color to show padding) */

- /* In some themes, at edit-
-    time, the format button lands under the page number. See BL-13206. The name is is intentionally vague about direction and what we do with it. */
+ /* In some themes, at edit-time, the format button lands under the page number.
+    See BL-13206. The name is intentionally vague about direction and what we do with it. */

173-178: Document the necessity of !important usage.

While the use of !important might be necessary here, it's good practice to document why it's required to prevent future maintainers from trying to remove it.

- --pageNumber-extra-height: 8mm !important;
+ /* !important needed to override theme-specific values that might be applied later */
+ --pageNumber-extra-height: 8mm !important;

220-229: Consider using a semantic color variable.

For better maintainability and theme consistency, consider using a semantic color variable for the cover background.

+ /* At the top of the file */
+ :root {
+   --color-cover-background: #7bdcb5;
+ }

- --cover-background-color: #7bdcb5;
+ --cover-background-color: var(--color-cover-background);
public/testBooks/multibook-target1/previewMode.css (3)

16-24: Consider using a more maintainable selector pattern

The hard-coded ID #ddd9b811-63d6-4d51-baf8-0a5fe88cd73d makes the styles brittle and difficult to maintain. Consider using a more semantic class name or data attribute to target device-specific layouts.

-.preview:not([data-l1]) .bloom-frontMatter.Device16x9Landscape#ddd9b811-63d6-4d51-baf8-0a5fe88cd73d .bookTitle {
+.preview:not([data-l1]) .bloom-frontMatter.Device16x9Landscape[data-layout="cover"] .bookTitle {
   min-height: 10%;
 }

51-54: Decouple styling from JavaScript functionality

The comment indicates a tight coupling between CSS and JavaScript for readonly state management. Consider using a dedicated class or attribute for this purpose instead.

-textarea {
-  /*we have javascript function which notices this border and makes it read-only
-  (which isn't a style, so we can't set it ourselves*/
-  border: 1px solid transparent;
-}
+textarea {
+  border: 1px solid transparent;
+}
+textarea[data-readonly="true"] {
+  pointer-events: none;
+  background-color: #f5f5f5;
+}

105-113: Review z-index stacking context

The z-index: 10000 seems arbitrarily high and could cause issues with other overlapping elements. Consider using a lower value and documenting the stacking context hierarchy.

 .preview.template .numberedPage .pageLabel,
 .bloomPlayer-page.template .numberedPage .pageLabel {
   position: absolute;
-  z-index: 10000;
+  z-index: 100; /* Ensure this is higher than other page elements but not arbitrarily high */
   background-color: #d65649;
   color: white;
   padding: 5px;
   display: block;
 }
public/testBooks/multibook-index/index.htm (1)

16-32: Modernize CSS implementation

  1. The CDATA section is unnecessary in HTML5
  2. Consider moving styles to an external stylesheet for better maintainability
-    <style type="text/css" title="userModifiedStyles">
-        /*<![CDATA[*/
+    <style title="userModifiedStyles">
         .BigWords-style {
             font-size: 45pt !important;
             text-align: center !important;
         }
-        /*]]>*/
     </style>
public/testBooks/multibook-target1/index.htm (2)

6-13: Remove unnecessary closing tags for meta elements.

Meta tags are self-closing in HTML5 and don't need separate closing tags.

-    <meta charset="UTF-8">
-    </meta>
-    <meta name="Generator" content="Bloom Version 6.2.0 (apparent build date: 27-Nov-2024)">
-    </meta>
-    <meta name="BloomFormatVersion" content="2.1">
-    </meta>
-    <meta name="pageTemplateSource" content="Basic Book">
-    </meta>
+    <meta charset="UTF-8">
+    <meta name="Generator" content="Bloom Version 6.2.0 (apparent build date: 27-Nov-2024)">
+    <meta name="BloomFormatVersion" content="2.1">
+    <meta name="pageTemplateSource" content="Basic Book">

39-56: Enhance security for external resources.

Consider the following security improvements:

  1. Add integrity hashes for CSS files to prevent tampering
  2. Implement Content Security Policy (CSP) headers
  3. Validate user input in contenteditable elements

Example of adding integrity hash:

-    <link rel="stylesheet" href="basePage.css" type="text/css">
+    <link rel="stylesheet" href="basePage.css" type="text/css" integrity="sha384-[hash]" crossorigin="anonymous">
public/testBooks/multibook-target1/branding.css (4)

1-9: Consider enhancing the documentation clarity

While the documentation effectively explains the separation of concerns, consider:

  1. Using more specific version number format (e.g., 6.0.0)
  2. Adding absolute paths to referenced files (bloom-xmatter-commons.less, branding-base.less)
-    compatibleWithAppearanceVersion: 6.0;
+    compatibleWithAppearanceVersion: "6.0.0";

10-21: Consider adding vendor prefixes for better browser compatibility

The flexbox and object-fit properties might need vendor prefixes for older browsers.

 [data-book*="branding"] {
   display: flex;
+  display: -webkit-flex;
+  display: -ms-flexbox;
   flex-direction: column;
+  -webkit-flex-direction: column;
+  -ms-flex-direction: column;
 }
 [data-book*="branding"] img {
   margin-left: auto;
   margin-right: auto;
   width: auto;
   max-width: 100%;
   align-self: center;
+  -webkit-align-self: center;
+  -ms-flex-item-align: center;
   object-fit: contain;
+  -o-object-fit: contain;
 }

22-24: Add documentation for the outside back cover rule

Consider adding a comment explaining why this element needs 100% width.

+/* Ensures the back cover branding spans the full width of its container */
 [data-book="outside-back-cover-branding-bottom-html"] {
   width: 100%;
 }

25-54: Consider optimizing orientation-specific rules

The current implementation has a lot of repetition. Consider using CSS custom properties or a more maintainable approach.

+/* Define reusable classes for orientations */
+.Portrait {
+  &[class*="Size6x9"], &[class*="USComic"],
+  &[class*="Device16x9"], &[class*="QuarterLetter"],
+  &[class*="HalfLetter"], &[class*="Letter"],
+  &[class*="Legal"], &[class*="A3"],
+  &[class*="A4"], &[class*="A5"],
+  &[class*="B5"], &[class*="A6"] {
+    .portraitOnly {
+      display: unset;
+    }
+  }
+}
.storybook/main.ts (1)

23-25: Consider externalizing the book ID to name mapping

Hardcoding the idToBookName mapping within the code may reduce maintainability as the list grows or changes. Consider externalizing this mapping to a configuration file or environment variable to improve flexibility and ease of updates.

public/testBooks/multibook-target1/basePage.css (2)

1-1304: Consider modularizing the CSS for better maintainability

The CSS file contains over 1300 lines of code. To improve maintainability and readability, consider splitting the CSS into modular components or using a CSS preprocessor like Sass or Less to organize styles logically.


689-694: Remove unnecessary comment /*+init {*/

At line 689, there is an incomplete comment /*+init {*/. Please remove or correct this comment to improve code clarity.

src/bloom-player-core.tsx (2)

1898-1898: Simplify null checks using optional chaining

You can use optional chaining to simplify the condition:

if (result?.data) {
    combinedStyle += result.data;
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 1898-1898: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


1698-1700: Handle rejected promises to prevent unhandled rejections

The axios.get(href) call does not have a catch clause. If the request fails, it may lead to an unhandled promise rejection. Consider adding a catch clause to handle errors gracefully.

Apply this diff to handle errors:

 axios.get(href).then((result) => {
     // Existing code
 })
+ .catch((error) => {
+     // Handle error or log it if necessary
+     console.error(`Failed to load fonts.css from ${href}:`, error);
+ });
src/stories/BloomPlayerIframe.tsx (1)

16-19: Consider adding error boundaries and loading states

The iframe implementation could benefit from error handling and loading states:

  1. Add error boundary for iframe loading failures
  2. Add loading indicator while iframe is initializing

Consider adding:

 return (
+    <ErrorBoundary fallback={<div>Failed to load Bloom Player</div>}>
         <iframe
             src={`/bloomplayer.htm?url=${encodeURIComponent(bookUrl)}&start-page=${bookPageIndex}${backButtonParam}`}
             style={{ width: "100%", height: "500px" }}
+            onLoad={() => setLoading(false)}
+            onError={(e) => console.error("Failed to load Bloom Player:", e)}
         />
+    </ErrorBoundary>
 );
src/stories/multiBook.stories.tsx (1)

34-35: Clean up commented code and standardize story names

  1. Remove the commented out storyName
  2. Use consistent quote style in story names

Apply this change:

-    // doesn't work storyName: "Use `bookPageIndex` to specify the starting page",
 };
-UsePageIndex.storyName =
-    "Use `bookPageIndex` to specify the starting page of the first book";
+UsePageIndex.storyName = "Use bookPageIndex to specify the starting page of the first book";

Also applies to: 36-37

README-advanced.md (1)

28-28: Improve documentation clarity and grammar

Consider these style improvements:

  1. Replace "so as to" with "to"
  2. Replace "a variety of" with "many" or "various"
  3. Fix "both ... as well as" construction

Apply these changes:

-`Bloom-player` is designed to be published using `npm` so as to be readily available to a variety of clients. The published version includes both `dist/bloomPlayer-HASH.js`, as well as some mp3 files used by activities.
+`Bloom-player` is designed to be published using `npm` to be readily available to various clients. The published version includes both `dist/bloomPlayer-HASH.js` and mp3 files used by activities.
🧰 Tools
🪛 LanguageTool

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)

src/navigation.ts (1)

1-7: Consider using a more robust data structure for history

The current implementation uses a simple array for history management. Consider using a class or more structured approach that could:

  • Enforce maximum history size to prevent memory issues
  • Add methods for history manipulation
  • Include timestamps for potential time-based features
-const jumpHistory: { bookId: string; pageId: string }[] = [];
+class NavigationHistory {
+    private readonly maxSize = 100;
+    private history: Array<{
+        bookId: string;
+        pageId: string;
+        timestamp: number;
+    }> = [];
+
+    push(bookId: string, pageId: string): void {
+        if (this.history.length >= this.maxSize) {
+            this.history.shift();
+        }
+        this.history.push({ bookId, pageId, timestamp: Date.now() });
+    }
+
+    pop() {
+        return this.history.pop();
+    }
+
+    canGoBack(): boolean {
+        return this.history.length > 0;
+    }
+}
src/stories/navigation.stories.tsx (1)

12-23: Consider adding more configuration options

The story configuration could benefit from additional controls:

  • Initial history state
  • Network delay simulation
  • Error injection
 const meta: Meta<typeof BloomPlayerIframe> = {
     title: "Automated/Navigation",
     component: BloomPlayerIframe,
     argTypes: {
         showBackButton: {
             control: "boolean",
             description:
                 "Show back button in the player that will send a message to the host when the local history is empty and the user clicks it.",
             defaultValue: false,
         },
+        initialHistory: {
+            control: "object",
+            description: "Initial navigation history state",
+            defaultValue: [],
+        },
+        networkDelay: {
+            control: "number",
+            description: "Simulate network delay in milliseconds",
+            defaultValue: 0,
+        },
     },
 };
src/navigation.test.ts (2)

16-26: Consider adding edge cases for canGoBack tests.

While the basic cases are covered, consider adding tests for:

  • Multiple navigation steps
  • Edge cases with rapid back navigation

138-152: Consider enhancing the createClickEvent helper.

The helper function could be more robust by:

  • Adding TypeScript types for the event object
  • Supporting additional event properties that might be needed in future tests
-function createClickEvent(href: string) {
+interface MockClickEvent {
+    target: {
+        attributes: {
+            href: { nodeValue: string }
+        },
+        closest: () => any
+    },
+    preventDefault: () => void,
+    stopPropagation: () => void
+}
+
+function createClickEvent(href: string): MockClickEvent {
README.md (1)

57-67: Fix grammatical issues in the showBackButton section.

There are a few grammatical issues to address:

-If true, displays a button in the upper left corner of the app bar. When clicked, bloom-player will post a message "backButtonClicked" that the your host can catch and respond to.
+If true, displays a button in the upper-left corner of the app bar. When clicked, bloom-player will post a message "backButtonClicked" that your host can catch and respond to.

-However if bloom-player is the top level window
+However, if bloom-player is the top-level window
🧰 Tools
🪛 LanguageTool

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[grammar] ~57-~57: A determiner cannot be combined with a possessive pronoun. Did you mean simply “the” or “your”?
Context: ...post a message "backButtonClicked" that the your host can catch and respond to. Example...

(A_MY)


[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

public/testBooks/multibook-target1/origami.css (4)

46-48: Remove or update the commented-out code.

The comment about JohnT's modification should either be removed or updated to follow a standard documentation format.

-    /* JohnT mod: this extra padding makes it impossible to grab the crop control right above the split.
-    padding-bottom: 5px; /* this actually enlarges the target area for the user trying to find the splitter, without changing the layout of the page (because the position is absolute)*/
+    /* Removed padding-bottom to prevent interference with crop control above the split */

205-209: Remove commented-out transition code.

Either implement the transition or remove the commented code block.

-/* I wasn't convinced this was helpful... may return to it
-.adders{
-        transition-property: width, height;
-        transition-duration: 0.5s;
-}*/

271-277: Improve documentation of z-index behavior.

The comment about z-index behavior should be more clearly documented, possibly with a specific example.

 .origami-layout-mode {
-  /*the commented line below would also add it to an empty bloom-content1 for re-entry to layout mode*/
-  /*but that would be problematic/confusing in a multilingual context*/
-  /*.origami-layout-mode .split-pane-component-inner .bloom-editable.bloom-content1:empty:before,*/
-  /* not setting z-index in the upper layer allows the adder buttons to be visible and active when the */
-  /* cursor is over the "Text Box" text, but not when it is over the .formatButton gearbox icon. (BL-9176) */
+  /* Z-index hierarchy:
+   * - Adder buttons: visible when cursor is over "Text Box"
+   * - Format button (gearbox): takes precedence over adder buttons
+   * Note: Intentionally not applying to empty bloom-content1 to avoid multilingual confusion
+   * Reference: BL-9176
+   */
 }

304-304: Remove source map comment if not used.

The source map comment should be removed if source maps are not being generated.

-/*# sourceMappingURL=../../../../output/browser/bookEdit/css/origami.css.map */
public/testBooks/multibook-index/Basic Book.css (3)

1-348: Consider consolidating duplicate CSS files

The same CSS file exists in both multibook-index and multibook-target1 directories. This duplication could lead to maintenance issues.

Consider:

  1. Moving the shared CSS to a common location
  2. Using CSS imports or a build process to include the styles where needed
  3. Creating a shared component library for these styles

59-59: Simplify the calculation for top positioning

The calculation calc(1.3% + 24% + 24%) could be simplified to calc(49.3%) for better readability and performance.

-  top: calc(1.3% + 24% +  24%);
+  top: calc(49.3%);

14-14: Avoid using !important declarations

The use of !important in border declarations suggests potential specificity issues in the CSS cascade.

Consider:

  1. Restructuring the selectors to be more specific
  2. Using more specific combinators instead of !important
  3. Document why !important is necessary if it cannot be avoided

Also applies to: 138-138

src/externalContext.ts (1)

Line range hint 193-203: Consider enhancing error logging

The JSON parse error handling could be more informative for debugging purposes.

    } catch (e) {
        console.log(
-            "receiveMessage failed to parse json: " +
-                data +
-                " with error " +
-                e.message,
+            `receiveMessage failed to parse json: ${JSON.stringify(data)} with error: ${e.message}`,
         );
        return;
    }
src/bookInfo.ts (1)

24-24: Consider using a getter method instead of making bookInstanceId public.

Making the property public breaks encapsulation. Consider using a getter method to maintain better control over the property access:

-public bookInstanceId = "";
+private bookInstanceId = "";
+
+public getBookInstanceId(): string {
+    return this.bookInstanceId;
+}
public/testBooks/multibook-index/appearance.css (2)

115-116: Fix incomplete comment.

The comment appears to be cut off mid-sentence: "In some themes, at edit-". Please complete the comment to improve code documentation.


177-177: Document the magic number for page number extra height.

The value 8mm appears to be a magic number. Consider adding a comment explaining why this specific value was chosen for the extra height of page numbers on device pages.

src/controlBar.tsx (3)

39-39: Remove unused import.

The Button import from @material-ui/core is not used in the code.

-import { Button } from "@material-ui/core";

Line range hint 254-296: Simplify back button rendering logic.

The nested conditional rendering with multiple checks against BackButtonState could be simplified using a separate function or switch statement for better readability.

Consider refactoring to:

const renderBackButton = (state: BackButtonState): JSX.Element | null => {
    switch (state) {
        case BackButtonState.showArrow:
            return (
                <ArrowBack
                    aria-label="Go Back"
                    titleAccess={LocalizationManager.getTranslation(
                        "Button.Back",
                        props.preferredLanguages,
                        "Back"
                    )}
                />
            );
        case BackButtonState.showEllipsis:
            return (
                <MoreHoriz
                    aria-label="More Menu"
                    titleAccess={LocalizationManager.getTranslation(
                        "Button.More",
                        props.preferredLanguages,
                        "More"
                    )}
                />
            );
        default:
            return null;
    }
};

Then use it in the JSX:

{!props.videoPreviewMode && (
    <IconButton
        color="secondary"
        onClick={() => props.backClicked?.()}
        data-testid="history-back-button"
        disabled={props.getBackButtonState() === BackButtonState.showNothing}
    >
        {renderBackButton(props.getBackButtonState())}
    </IconButton>
)}

258-262: Add type for onClick event handler.

The onClick event handler should have proper type annotations for better type safety.

-onClick={() => {
-    if (props.backClicked) {
-        props.backClicked();
-    }
-}}
+onClick={(e: React.MouseEvent<HTMLButtonElement>) => props.backClicked?.()}
src/bloom-player-controls.tsx (2)

913-928: Consider adding documentation for the back button states.

The getBackButtonState method implements a clear logic flow, but would benefit from JSDoc comments explaining:

  • The purpose and use case for each state (showArrow, showEllipsis, showNothing)
  • The conditions that trigger each state
  • The difference between showing an arrow vs ellipsis
+/**
+ * Determines the visibility state of the back button based on navigation history and container context.
+ * @returns {BackButtonState}
+ * - showArrow: When there's internal history or the container wants a direct "back" action
+ * - showEllipsis: When in an iframe and the parent page handles navigation
+ * - showNothing: When no back navigation is available
+ */
 getBackButtonState={() => {

934-938: Add error handling to the back button click handler.

The back button click handler should include error handling to gracefully handle potential failures when sending messages to the host.

 backClicked={() => {
+    try {
         if (!coreRef.current?.HandleBackButtonClicked()) {
             sendBackToHost();
         }
+    } catch (error) {
+        console.error("Failed to handle back button click:", error);
+        // Fallback behavior or error notification
+    }
 }}
public/testBooks/multibook-index/basePage.css (1)

1-1304: Consider performance optimizations for the CSS.

The CSS file is comprehensive but could benefit from the following optimizations:

  1. Reduce specificity of selectors to improve rendering performance
  2. Consider splitting into smaller files for better caching
  3. Evaluate if all transform operations are necessary
  4. Group media queries to reduce CSS size

Consider implementing CSS modules or a CSS-in-JS solution for better code organization and performance. This would also help with:

  • Dead code elimination
  • Scoped styles
  • Dynamic theming
  • Better build-time optimizations
public/testBooks/multibook-target1/Basic Book.css (3)

3-7: Consider using relative units for better responsiveness

The fixed height of 1.6cm for .translators might not accommodate varying content lengths across different languages and screen sizes.

Consider using relative units or min-height:

.translators {
  text-align: center;
-  height: 1.6cm;
+  min-height: 1.6cm;
  position: relative;
}

8-153: Consider using CSS Grid or Flexbox for more maintainable layouts

The current implementation heavily relies on absolute positioning, which can be brittle and harder to maintain. Modern CSS layout systems like Grid or Flexbox could provide more flexible and maintainable solutions.

Example approach using CSS Grid:

.imageOnTop {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: var(--multilingual-editable-vertical-gap);
}

.imageOnTop .bloom-imageContainer {
  grid-row: 1;
}

.imageOnTop .bloom-translationGroup {
  grid-row: 2;
}

154-163: Consider using CSS for vertical centering

The comment indicates that vertical centering is handled in JavaScript. Modern CSS can handle this more efficiently.

Consider using CSS for vertical centering:

.textWholePage {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
}

.textWholePage .bloom-editable {
  min-height: 2em;
}

.textWholePage .bloom-translationGroup {
  width: 100%;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fdc257b and d74b943.

⛔ Files ignored due to path filters (16)
  • public/testBooks/multibook-index/BloomLocal.svg is excluded by !**/*.svg
  • public/testBooks/multibook-index/back-cover-local.svg is excluded by !**/*.svg
  • public/testBooks/multibook-index/happy-pirate.png is excluded by !**/*.png
  • public/testBooks/multibook-index/history.db is excluded by !**/*.db
  • public/testBooks/multibook-index/image.jpg is excluded by !**/*.jpg
  • public/testBooks/multibook-index/license.png is excluded by !**/*.png
  • public/testBooks/multibook-index/placeHolder.png is excluded by !**/*.png
  • public/testBooks/multibook-index/thumbnail.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/BloomLocal.svg is excluded by !**/*.svg
  • public/testBooks/multibook-target1/back-cover-local.svg is excluded by !**/*.svg
  • public/testBooks/multibook-target1/history.db is excluded by !**/*.db
  • public/testBooks/multibook-target1/image.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/license.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/placeHolder.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/thumbnail.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (45)
  • .storybook/main.ts (2 hunks)
  • .storybook/preview.ts (1 hunks)
  • README-advanced.md (2 hunks)
  • README.md (4 hunks)
  • package.json (2 hunks)
  • public/testBooks/multibook-index/Basic Book.css (1 hunks)
  • public/testBooks/multibook-index/Traditional-XMatter.css (1 hunks)
  • public/testBooks/multibook-index/appearance.css (1 hunks)
  • public/testBooks/multibook-index/appearance.json (1 hunks)
  • public/testBooks/multibook-index/basePage.css (1 hunks)
  • public/testBooks/multibook-index/book.userPrefs (1 hunks)
  • public/testBooks/multibook-index/branding.css (1 hunks)
  • public/testBooks/multibook-index/customCollectionStyles.css (1 hunks)
  • public/testBooks/multibook-index/defaultLangStyles.css (1 hunks)
  • public/testBooks/multibook-index/index.htm (1 hunks)
  • public/testBooks/multibook-index/meta.json (1 hunks)
  • public/testBooks/multibook-index/origami.css (1 hunks)
  • public/testBooks/multibook-index/previewMode.css (1 hunks)
  • public/testBooks/multibook-index/publish-settings.json (1 hunks)
  • public/testBooks/multibook-target1/Basic Book.css (1 hunks)
  • public/testBooks/multibook-target1/Traditional-XMatter.css (1 hunks)
  • public/testBooks/multibook-target1/appearance.css (1 hunks)
  • public/testBooks/multibook-target1/appearance.json (1 hunks)
  • public/testBooks/multibook-target1/basePage.css (1 hunks)
  • public/testBooks/multibook-target1/book.userPrefs (1 hunks)
  • public/testBooks/multibook-target1/branding.css (1 hunks)
  • public/testBooks/multibook-target1/customCollectionStyles.css (1 hunks)
  • public/testBooks/multibook-target1/defaultLangStyles.css (1 hunks)
  • public/testBooks/multibook-target1/index.htm (1 hunks)
  • public/testBooks/multibook-target1/meta.json (1 hunks)
  • public/testBooks/multibook-target1/origami.css (1 hunks)
  • public/testBooks/multibook-target1/previewMode.css (1 hunks)
  • public/testBooks/multibook-target1/publish-settings.json (1 hunks)
  • src/bloom-player-controls.tsx (4 hunks)
  • src/bloom-player-core.tsx (25 hunks)
  • src/bloomPlayerAnalytics.tsx (1 hunks)
  • src/bookInfo.ts (1 hunks)
  • src/controlBar.tsx (5 hunks)
  • src/externalContext.ts (1 hunks)
  • src/navigation.test.ts (1 hunks)
  • src/navigation.ts (1 hunks)
  • src/stories/BloomPlayerIframe.tsx (1 hunks)
  • src/stories/BloomPlayerTester.ts (1 hunks)
  • src/stories/multiBook.stories.tsx (1 hunks)
  • src/stories/navigation.stories.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (16)
  • public/testBooks/multibook-target1/customCollectionStyles.css
  • public/testBooks/multibook-index/customCollectionStyles.css
  • public/testBooks/multibook-target1/appearance.json
  • public/testBooks/multibook-index/appearance.json
  • public/testBooks/multibook-index/defaultLangStyles.css
  • public/testBooks/multibook-target1/defaultLangStyles.css
  • public/testBooks/multibook-index/book.userPrefs
  • public/testBooks/multibook-index/previewMode.css
  • public/testBooks/multibook-target1/book.userPrefs
  • public/testBooks/multibook-index/Traditional-XMatter.css
  • src/bloomPlayerAnalytics.tsx
  • public/testBooks/multibook-index/publish-settings.json
  • public/testBooks/multibook-index/meta.json
  • public/testBooks/multibook-index/origami.css
  • public/testBooks/multibook-target1/publish-settings.json
  • public/testBooks/multibook-target1/meta.json
🧰 Additional context used
🪛 LanguageTool
README-advanced.md

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)

README.md

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[grammar] ~57-~57: A determiner cannot be combined with a possessive pronoun. Did you mean simply “the” or “your”?
Context: ...post a message "backButtonClicked" that the your host can catch and respond to. Example...

(A_MY)


[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)


[uncategorized] ~158-~158: Possible missing comma found.
Context: ...y. ### Running unit tests To run unit tests use yarn test. This will run all `*.t...

(AI_HYDRA_LEO_MISSING_COMMA)

🪛 Markdownlint (0.35.0)
README.md

109-109: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)

🪛 Biome (1.9.4)
src/bloom-player-core.tsx

[error] 1898-1898: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (19)
public/testBooks/multibook-target1/Traditional-XMatter.css (1)

227-243: LGTM! Consistent implementation.

The back cover layout follows the same patterns as the front cover, maintaining consistency throughout the codebase.

public/testBooks/multibook-target1/appearance.css (3)

122-124: LGTM! Clear and purposeful override for interactive pages.

The transparent marginBox for interactive pages is well-implemented and properly documented.


195-204: LGTM! Well-implemented specificity handling.

The doubled class names are a clever solution for specificity management and are well-documented.


209-217: LGTM! Clear and well-documented XMatter styles.

The variables are logically named and the font size inheritance is well explained.

public/testBooks/multibook-target1/previewMode.css (2)

115-115: Review source map path resolution

The source map uses a relative path with multiple parent directory references (../../../../). This could be fragile across different environments. Consider using a more robust path resolution strategy.


60-65: Document and review wkhtmltopdf version dependency

The CSS contains a hack specific to wkhtmltopdf 0.10.0. This version-specific dependency should be documented and periodically reviewed as it might not be necessary with newer versions of the tool.

✅ Verification successful

Version-specific CSS hack is documented and appears to be a common requirement

The CSS hack for wkhtmltopdf 0.10.0 is actually well documented across multiple files in the codebase. The comments explain that this invisible border is necessary for proper page layout with wkhtmltopdf 0.10.0, as without it "pages would not come out properly at all." This appears to be an intentional and understood workaround rather than an undocumented dependency.

  • Found consistent documentation in multiple basePage.css files explaining the necessity of the border for proper PDF generation
  • The hack appears to be a core layout requirement across different book templates
  • The version dependency is explicitly documented in the comments
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any comments or documentation about wkhtmltopdf version requirements
rg -i "wkhtmltopdf" --type md

Length of output: 29


Script:

#!/bin/bash
# Let's search for wkhtmltopdf mentions across all file types to understand its usage
rg -i "wkhtmltopdf" -A 2 -B 2

# Also search for any build or dependency configuration files that might specify the version
fd -e json -e config -e yml -e yaml | xargs rg -i "wkhtmltopdf"

Length of output: 8741

public/testBooks/multibook-target1/index.htm (1)

417-421: Review navigation implementation for maintainability.

The current navigation implementation has several concerns:

  1. Hardcoded book IDs in URLs could break if books are reorganized
  2. Multiple ways to navigate to the same page could lead to inconsistent behavior
  3. Back navigation mentioned in content implies UI elements that should be verified
public/testBooks/multibook-target1/branding.css (1)

14-21: Verify accessibility requirements for branding images

Ensure that branding images have appropriate alt text requirements defined in the HTML.

✅ Verification successful

Empty alt attributes are appropriate for decorative branding images

The branding images in the codebase are consistently implemented with empty alt attributes (alt=""), which is the correct accessibility practice for decorative images that don't convey meaningful content. These images appear to be logos and branding elements that are purely presentational, and empty alt text ensures screen readers will correctly skip them.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if branding images have alt attributes
rg -l 'img.*class="branding"' | xargs rg -l 'alt="'

Length of output: 902


Script:

#!/bin/bash
# Let's check for branding-related images and their alt attributes in the HTML files
rg -U --multiline 'data-book.*branding.*?<img.*?>' -g '*.htm' -g '*.html'

Length of output: 2166

.storybook/main.ts (3)

10-12: Approved: Added static directory configuration for Storybook

The addition of staticDirs: ["../dist"], properly configures Storybook to serve static files from the dist directory. This is necessary for stories that include an iframe and need access to bloomplayer.htm and its bundles.


28-30: Verify the proxy configuration for /book/ route

The comment indicates that the proxy setup for /book/ is not working. Please verify the proxy configuration to ensure it correctly handles requests and resolves any CORS issues.


53-59: Verify the proxy target file:/// for /bloom/ route

Setting the proxy target to file:/// may not function as intended, as proxying to the file protocol is uncommon and might not be supported. Please verify if this configuration works as expected or consider alternative methods to serve static files.

.storybook/preview.ts (1)

12-16: Approved: Customized story sorting in Storybook

The addition of options.storySort.order configures Storybook to sort stories based on the specified order, improving the organization of the stories.

package.json (2)

26-27: LGTM: New script for Storybook iframe development

The new buildForStorybook script is well-documented and serves a clear purpose for stories that use an iframe and bloomplayer.htm instead of raw React components.


47-53: Verify Storybook dependency compatibility

The Storybook dependencies have been updated from 8.3.6 to 8.4.6. While this is a minor version bump, it's good practice to verify compatibility.

Also applies to: 61-61, 67-67

✅ Verification successful

Storybook 8.4.6 update is safe to proceed

Based on the release notes, version 8.4.6 contains only improvements and compatibility updates:

  • Better Windows support for Addon Test
  • Angular v19 standalone components support
  • Vite 6 support
  • Enhanced portable stories functionality
  • React-docgen-typescript upgrade for Vite 6
  • Svelte plugin v5 support

No breaking changes are mentioned, and the changes are focused on adding support for newer versions of related tools.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for breaking changes in Storybook 8.4.6 release notes
gh api graphql -f query='
{
  repository(owner: "storybookjs", name: "storybook") {
    release(tagName: "v8.4.6") {
      description
    }
  }
}'

Length of output: 1040

src/navigation.test.ts (2)

8-14: LGTM: Good test setup with proper cleanup.

The beforeEach hook ensures a clean state for each test by clearing the navigation history.


107-134: Well-structured multi-step navigation test.

Comprehensive test covering multiple navigation scenarios and verifying the correct state after each step.

README.md (1)

102-130: Well-documented multi-book support section.

Clear explanation of the Instance ID system and the required host implementation steps.

🧰 Tools
🪛 LanguageTool

[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)

🪛 Markdownlint (0.35.0)

109-109: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)

src/externalContext.ts (1)

116-116: Verify all usages of the renamed function

The function has been renamed from onBackClicked to sendBackToHost for better clarity. Ensure all call sites have been updated.

✅ Verification successful

All usages of the renamed function have been properly updated

The function rename from onBackClicked to sendBackToHost has been correctly implemented across the codebase:

  • The only remaining reference to onBackClicked is in a comment in src/externalContext.ts
  • The new function name sendBackToHost is properly used in:
    • Export declaration in src/externalContext.ts
    • Import and two usage locations in src/bloom-player-controls.tsx
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to onBackClicked
# Test: Search for old function name references
rg "onBackClicked"

# Test: Verify the new function name usage
rg "sendBackToHost"

Length of output: 317

public/testBooks/multibook-target1/Basic Book.css (1)

1-348: Document CSS custom properties and verify source map

Two concerns need attention:

  1. The CSS variable --multilingual-editable-vertical-gap is used but not defined in this file
  2. Source map is referenced but not provided

Let's check for the CSS variable definition and source map:

Comment on lines +52 to +53
order: kFrontCoverImageOrder;
flex: 1 1 auto;
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix invalid CSS value kFrontCoverImageOrder

The value kFrontCoverImageOrder appears to be intended as a CSS variable but is used directly. This will cause the order property to be invalid.

Apply this fix:

- order: kFrontCoverImageOrder;
+ order: var(--kFrontCoverImageOrder);

Also applies to: 58-59

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood. I will skip reviewing HTML and CSS files in this PR.

Comment on lines +250 to +255
.ISBNContainer .bloom-editable {
text-align: left !important;
width: 4.3cm !important;
max-height: 1.8em;
min-height: 1.8em;
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider making ISBN dimensions more flexible

The hard-coded dimensions and use of !important might cause maintainability issues:

  1. Fixed width of 4.3cm might not accommodate all ISBN formats
  2. Fixed height of 1.8em might clip text with different font sizes
  3. Use of !important suggests potential specificity issues

Consider using:

.ISBNContainer .bloom-editable {
  text-align: left;
  min-width: 4.3cm;
  max-width: fit-content;
  min-height: 1.8em;
  height: auto;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@hatton have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 22 seconds before sending another message.

Comment on lines +55 to +58
.outsideBackCover img.branding {
margin-top: 4px;
width: 10cm;
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reconsider the use of absolute units

Using centimeters (cm) for digital displays can be unpredictable across different devices and screen resolutions.

Consider using relative units:

.outsideBackCover img.branding {
  margin-top: 4px;
- width: 10cm;
+ width: min(10cm, 30%); /* Provides a relative fallback */
+ max-width: 10cm;
}

Also, consider using a more specific class name instead of combining element and class selectors for better maintainability.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.outsideBackCover img.branding {
margin-top: 4px;
width: 10cm;
}
.outsideBackCover img.branding {
margin-top: 4px;
width: min(10cm, 30%); /* Provides a relative fallback */
max-width: 10cm;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood. Let me know if you need any further assistance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@hatton have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 53 seconds before sending another message.

Comment on lines +25 to +54
/* these rules allow different branding insertions depending on orientation */
.portraitOnly,
.landscapeOnly {
display: none;
}
.Size6x9Portrait .portraitOnly,
.USComicPortrait .portraitOnly,
.Device16x9Portrait .portraitOnly,
.QuarterLetterPortrait .portraitOnly,
.HalfLetterPortrait .portraitOnly,
.LetterPortrait .portraitOnly,
.LegalPortrait .portraitOnly,
.A3Portrait .portraitOnly,
.A4Portrait .portraitOnly,
.A5Portrait .portraitOnly,
.B5Portrait .portraitOnly,
.A6Portrait .portraitOnly {
display: unset;
}
.Size6x9Landscape .landscapeOnly,
.Cm13Landscape .landscapeOnly,
.Device16x9Landscape .landscapeOnly,
.LetterLandscape .landscapeOnly,
.LegalLandscape .landscapeOnly,
.A3Landscape .landscapeOnly,
.A4Landscape .landscapeOnly,
.A5Landscape .landscapeOnly,
.A6Landscape .landscapeOnly {
display: unset;
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize orientation-specific display rules

The current implementation could be improved in several ways:

  1. display: unset is less predictable than explicit values
  2. The extensive list of selectors could be simplified using CSS custom properties

Consider this alternative approach:

- .portraitOnly,
- .landscapeOnly {
-   display: none;
- }
+ :root {
+   --portrait-display: none;
+   --landscape-display: none;
+ }

+ /* Base classes */
+ .portraitOnly {
+   display: var(--portrait-display, none);
+ }
+ .landscapeOnly {
+   display: var(--landscape-display, none);
+ }

+ /* Portrait sizes */
+ [class*="Portrait"] {
+   --portrait-display: block;
+ }

+ /* Landscape sizes */
+ [class*="Landscape"] {
+   --landscape-display: block;
+ }

This approach:

  • Uses explicit display values
  • Reduces code duplication
  • Is easier to maintain
  • Provides better browser compatibility than unset
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* these rules allow different branding insertions depending on orientation */
.portraitOnly,
.landscapeOnly {
display: none;
}
.Size6x9Portrait .portraitOnly,
.USComicPortrait .portraitOnly,
.Device16x9Portrait .portraitOnly,
.QuarterLetterPortrait .portraitOnly,
.HalfLetterPortrait .portraitOnly,
.LetterPortrait .portraitOnly,
.LegalPortrait .portraitOnly,
.A3Portrait .portraitOnly,
.A4Portrait .portraitOnly,
.A5Portrait .portraitOnly,
.B5Portrait .portraitOnly,
.A6Portrait .portraitOnly {
display: unset;
}
.Size6x9Landscape .landscapeOnly,
.Cm13Landscape .landscapeOnly,
.Device16x9Landscape .landscapeOnly,
.LetterLandscape .landscapeOnly,
.LegalLandscape .landscapeOnly,
.A3Landscape .landscapeOnly,
.A4Landscape .landscapeOnly,
.A5Landscape .landscapeOnly,
.A6Landscape .landscapeOnly {
display: unset;
}
/* these rules allow different branding insertions depending on orientation */
:root {
--portrait-display: none;
--landscape-display: none;
}
/* Base classes */
.portraitOnly {
display: var(--portrait-display, none);
}
.landscapeOnly {
display: var(--landscape-display, none);
}
/* Portrait sizes */
[class*="Portrait"] {
--portrait-display: block;
}
/* Landscape sizes */
[class*="Landscape"] {
--landscape-display: block;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood. I'll note your preference to keep the current implementation.


✏️ Learnings added
Learnt from: hatton
PR: BloomBooks/bloom-player#347
File: public/testBooks/multibook-index/branding.css:25-54
Timestamp: 2024-12-10T16:30:37.960Z
Learning: In `public/testBooks/multibook-index/branding.css`, when handling orientation-specific display rules for the `.portraitOnly` and `.landscapeOnly` classes, the preferred approach is to use extensive selectors with `display: unset` instead of refactoring to use CSS custom properties.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@hatton have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 53 seconds before sending another message.

Comment on lines +129 to +140
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove duplicate LegalLandscape class.

The class list contains a duplicate entry for LegalLandscape.

 .A4Portrait,
 .B5Portrait,
 .LetterLandscape,
 .LetterPortrait,
 .LegalLandscape,
-.LegalLandscape {
+.LegalPortrait {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalPortrait {
--page-margin: 15mm;
--page-gutter: 10mm;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood. Skipping this issue.

Comment on lines +34 to +104
play: async ({ canvasElement, step }) => {
const tester = new BloomPlayerTester(canvasElement);

await step("Jump to a certain page in another book", async () => {
await tester.clickLinkByText("Crab Page");
await tester.shouldSeeText("This is the crab page the green book");
});

await step(
"Swipe pages to the back cover and then follow a link to jump to front cover",
async () => {
await tester.goToNextPage();
await tester.goToNextPage();
await tester.shouldSeeText(
"This is the back cover of the green book",
);
await tester.clickLinkByText("Jump to front cover");
},
);
await step(
"Jump back to the back cover and click a link within this book to the crab page",
async () => {
await tester.clickBackButton();
await tester.shouldSeeText(
"This is the back cover of the green book",
);
},
);
await step(
"Use a link that has the book and page id to jump to the crab page",
async () => {
await tester.clickLinkByText("using /book/bookId#pageId");
await tester.shouldSeeText(
"This is the crab page the green book",
);
},
);
await step(
'Use a link with a special "#back" href to get back to the back cover',
async () => {
await tester.shouldSeeText(
"This is the crab page the green book",
);
await tester.clickLinkByText('this "back" link');
await tester.shouldSeeText(
"This is the back cover of the green book",
);
},
);
await step("Jump back to get back to the original book", async () => {
await tester.clickBackButton();
await tester.shouldSeeText(
"This is a page in the index book that has links to another book",
);
});

await step("Jump to this book's cover", async () => {
await tester.clickLinkByText("This book Cover");
await tester.shouldSeeText("multibook-index");
});
await step(
"Jump back and verify that the back button is gone",
async () => {
await tester.clickBackButton();
await tester.waitForHistoryBackButtonToGoAway();
},
);
await step("Show the success page", async () => {
await tester.goToNextPage();
await tester.shouldSeeText("This is the end.");
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error scenarios to navigation tests

The current test scenarios cover the happy path well, but should also include error cases:

  • Invalid URLs
  • Missing pages
  • Network errors
  • History stack overflow
 export const Default: Story = {
     args: {
         bookUrl:
             "testBooks/multibook-index/index.htm#653f29c1-665b-4d63-a061-086401abc106",
         showBackButton: false,
     },
     play: async ({ canvasElement, step }) => {
         const tester = new BloomPlayerTester(canvasElement);
+        
+        await step("Handle invalid book URL", async () => {
+            await tester.clickLinkByText("Invalid Book");
+            await tester.shouldSeeErrorMessage("Book not found");
+        });
+
+        await step("Handle missing page", async () => {
+            await tester.clickLinkByText("Missing Page");
+            await tester.shouldSeeErrorMessage("Page not found");
+        });

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +129 to +140
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove duplicate .LegalLandscape selector.

The .LegalLandscape selector appears twice in the list, which could lead to confusion.

 .A4Portrait,
 .B5Portrait,
 .LetterLandscape,
 .LetterPortrait,
-.LegalLandscape,
 .LegalLandscape {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood.


✏️ Learnings added
Learnt from: hatton
PR: BloomBooks/bloom-player#347
File: public/testBooks/multibook-index/appearance.css:129-140
Timestamp: 2024-12-10T16:27:54.160Z
Learning: In the CSS files (e.g., `appearance.css`) in this project, duplicate CSS selectors (such as multiple `.LegalLandscape` selectors) may be intentional and should not be flagged as issues.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@hatton have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 52 seconds before sending another message.

@@ -1014,7 +1038,7 @@ export const BloomPlayerControls: React.FunctionComponent<BloomPlayerProps> = (
}
}}
shouldReportSoundLog={props.shouldReportSoundLog}
startPage={props.startPage}
startPageIndex={props.startPage}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Breaking change detected: startPage prop is still in use

The codebase shows inconsistent prop naming, which needs to be addressed:

  • BloomPlayerCore uses startPageIndex
  • BloomPlayerControls still uses startPage internally and passes it as startPageIndex to core
  • Multiple files contain references to the old startPage prop name

This indicates a breaking change that's not fully implemented across the codebase. The changes needed:

  • Update BloomPlayerControls interface to use startPageIndex
  • Update all internal references in BloomPlayerControls from startPage to startPageIndex
  • Update any consuming components still using startPage
🔗 Analysis chain

Verify the impact of renaming startPage to startPageIndex.

The property rename from startPage to startPageIndex improves clarity but may be a breaking change for existing consumers.

Run the following script to check for existing usages:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usages of the old startPage prop
# Test: Search for startPage prop usage. Expect: Only occurrences of the new name.

echo "Checking for old prop name usage..."
rg "startPage[^I]" --type ts --type tsx

echo "Checking for new prop name usage..."
rg "startPageIndex" --type ts --type tsx

Length of output: 300


Script:

#!/bin/bash
# Let's try without file type filters since tsx is not recognized
echo "Checking for old prop name usage..."
rg "startPage[^I]"

echo "Checking for new prop name usage..."
rg "startPageIndex"

Length of output: 3139

Comment on lines +164 to +347
.pictureAndWordPage.QuarterLetterLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.QuarterLetterLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.LetterPortrait .bloom-translationGroup {
height: 23%;
}
.pictureAndWordPage.LetterPortrait .bloom-imageContainer {
height: 74%;
}
.pictureAndWordPage.LetterPortrait .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LetterLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.LetterLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.LetterLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LegalPortrait .bloom-translationGroup {
height: 23%;
}
.pictureAndWordPage.LegalPortrait .bloom-imageContainer {
height: 74%;
}
.pictureAndWordPage.LegalPortrait .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LegalLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.LegalLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.LegalLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.Cm13Landscape .bloom-translationGroup {
height: 37%;
}
.pictureAndWordPage.Cm13Landscape .bloom-imageContainer {
height: 60%;
}
.pictureAndWordPage.Cm13Landscape .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.USComicPortrait .bloom-translationGroup {
height: 32%;
}
.pictureAndWordPage.USComicPortrait .bloom-imageContainer {
height: 65%;
}
.pictureAndWordPage.USComicPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage .bloom-translationGroup {
width: 100%;
text-align: center;
padding-top: 10px;
}
.pictureAndWordPage .bloom-editable {
vertical-align: middle;
height: auto;
}
.pictureAndWordPage .bloom-content2,
.pictureAndWordPage .bloom-content3 {
font-size: 200%;
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reduce code duplication using CSS custom properties

The styles for different page formats contain significant repetition. This could be simplified using CSS custom properties and reducing magic numbers.

Consider refactoring to use CSS custom properties:

:root {
  --translation-group-height-portrait: 35%;
  --translation-group-height-landscape: 42%;
  --image-container-height-portrait: 62%;
  --image-container-height-landscape: 55%;
  --font-size-large: 600%;
  --font-size-medium: 400%;
}

.pictureAndWordPage[class*="Portrait"] .bloom-translationGroup {
  height: var(--translation-group-height-portrait);
}

.pictureAndWordPage[class*="Portrait"] .bloom-imageContainer {
  height: var(--image-container-height-portrait);
}

.pictureAndWordPage[class*="Landscape"] .bloom-translationGroup {
  height: var(--translation-group-height-landscape);
}

.pictureAndWordPage[class*="Landscape"] .bloom-imageContainer {
  height: var(--image-container-height-landscape);
}

This approach would:

  1. Make the code more maintainable
  2. Make it easier to adjust values globally
  3. Document the purpose of specific values
  4. Reduce the likelihood of inconsistencies

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@hatton have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 0 seconds before sending another message.

Comment on lines +65 to +87
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
Copy link

@coderabbitai coderabbitai bot Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in class name 'nospecidalmovement'

There appears to be a typo in the class name 'nospecidalmovement' (should be 'nospecialmovement').

Apply this correction throughout the file:

-.nospecidalmovement_imageOnTop
+.nospecialmovement_imageOnTop
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
.nospecialmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecialmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecialmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecialmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecialmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood. I've noted your preference to keep the class name as nospecidalmovement_imageOnTop.


✏️ Learnings added
Learnt from: hatton
PR: BloomBooks/bloom-player#347
File: public/testBooks/multibook-target1/Basic Book.css:65-87
Timestamp: 2024-12-10T16:44:02.902Z
Learning: In `public/testBooks/multibook-target1/Basic Book.css`, the CSS class `nospecidalmovement_imageOnTop` is intentionally named and should not be corrected to `nospecialmovement_imageOnTop`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@hatton hatton force-pushed the pageAndBookNavigation branch from d74b943 to 2226513 Compare December 6, 2024 22:48
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (23)
public/testBooks/multibook-target1/Traditional-XMatter.css (2)

94-96: Consider removing !important flag

The use of !important in .coverBottomLangName line-height suggests potential specificity issues. Consider restructuring the CSS selectors to achieve the desired specificity without using !important.

-.frontCover .bottomBlock .bottomTextContent .bottomRow .coverBottomLangName {
-  line-height: 1.6em !important;
-}
+/* Increase selector specificity instead */
+.frontCover .bottomBlock .bottomTextContent .bottomRow .coverBottomLangName.bloom-editable {
+  line-height: 1.6em;
+}

1-262: Consider adding CSS documentation

This is a complex stylesheet that manages various book layout components. Consider adding documentation comments that:

  1. Explain the purpose and structure of each major section
  2. Document the expected HTML structure
  3. List any required CSS variables
  4. Provide usage examples

This will help future maintainers understand the styling system more easily.

public/testBooks/multibook-target1/previewMode.css (5)

16-24: Consider using device-specific classes instead of hardcoded IDs

The selector .preview:not([data-l1]) .bloom-frontMatter.Device16x9Landscape#ddd9b811-63d6-4d51-baf8-0a5fe88cd73d uses a hardcoded ID which could make the styles less maintainable and reusable.

Consider refactoring to use device-specific classes:

-.preview:not([data-l1]) .bloom-frontMatter.Device16x9Landscape#ddd9b811-63d6-4d51-baf8-0a5fe88cd73d {
+.preview:not([data-l1]) .bloom-frontMatter.Device16x9Landscape {

36-46: Consider using CSS custom properties for consistent opacity values

Using CSS variables would make it easier to maintain consistent opacity values across different disabled states.

Consider refactoring to:

+:root {
+  --disabled-opacity: 0.4;
+}
 .disabledVisual img {
-  opacity: 0.4;
+  opacity: var(--disabled-opacity);
 }
 .disabledVisual div {
-  opacity: 0.4;
+  opacity: var(--disabled-opacity);
   cursor: not-allowed;
 }

51-54: Improve documentation of JavaScript dependency

The comment indicates a JavaScript dependency for readonly state, but it could be more explicit.

Consider enhancing the comment to:

-  /*we have javascript function which notices this border and makes it read-only
-  (which isn't a style, so we can't set it ourselves*/
+  /* IMPORTANT: The transparent border is detected by JavaScript to set readonly state.
+   * This cannot be handled via CSS alone due to readonly being a property, not a style.
+   * See: [add link to relevant JavaScript file/function] */

55-65: Document browser/tool compatibility requirements

The comments mention specific wkhtml version requirements, but this could be more comprehensive.

Consider adding a detailed comment block:

/* Browser/Tool Compatibility Requirements
 * - wkhtml v0.10.0: Requires invisible border for correct page layout
 * - Add other known browser/tool requirements here
 */

106-113: Consider implementing z-index management system

Using a high z-index value (10000) could lead to stacking context issues. Consider implementing a z-index management system using CSS variables.

Example implementation:

+:root {
+  --z-index-overlay: 100;
+  --z-index-tooltip: 200;
+  --z-index-modal: 300;
+}
 .preview.template .numberedPage .pageLabel,
 .bloomPlayer-page.template .numberedPage .pageLabel {
   position: absolute;
-  z-index: 10000;
+  z-index: var(--z-index-overlay);
   /* ... other properties ... */
 }
public/testBooks/multibook-target1/basePage.css (3)

20-37: Consider using CSS custom properties for image container styles

The image container styles could be more maintainable by using CSS custom properties for repeated values.

+:root {
+  --image-fit: contain;
+  --image-dimensions: 100%;
+}

.bloom-imageContainer img {
-  width: 100%;
-  height: 100%;
-  object-fit: contain;
+  width: var(--image-dimensions);
+  height: var(--image-dimensions);
+  object-fit: var(--image-fit);
}

261-278: Improve maintainability of transform calculations

Consider using CSS custom properties to make transform calculations more maintainable and reusable.

+:root {
+  --transform-scale-a5: 1.04054054;
+  --transform-scale-a4: 1.02857143;
+  --transform-scale-a3: 1.02020202;
+  --transform-offset: -1.25675676mm;
+}

.bloom-fullBleed .bloom-page.A5Portrait {
-  transform: translate(0, -1.25675676mm) scale(1.04054054);
+  transform: translate(0, var(--transform-offset)) scale(var(--transform-scale-a5));
}

.bloom-fullBleed .bloom-page.A5Landscape {
-  transform: translate(-1.25675676mm, 0) scale(1.04054054);
+  transform: translate(var(--transform-offset), 0) scale(var(--transform-scale-a5));
}

1219-1259: Optimize duplicate margin calculations

Consider extracting common margin calculations into reusable CSS custom properties to reduce code duplication.

+.marginBox {
+  --margin-calculation: calc(var(--page-margin-left) * var(--page-and-marginBox-are-same-color-multiplicand));
+  --page-number-margin: calc(var(--pageNumber-extra-height) * var(--pageNumber-show-multiplicand));
+}

.marginBox > .split-pane-component-inner > .bloom-translationGroup {
-  padding-left: calc(var(--topLevel-text-padding-left) - (var(--page-margin-left) * var(--page-and-marginBox-are-same-color-multiplicand)));
+  padding-left: calc(var(--topLevel-text-padding-left) - var(--margin-calculation));
   /* Apply similar changes to other padding calculations */
}
public/testBooks/multibook-index/Basic Book.css (1)

164-347: Reduce code duplication using CSS custom properties

The styles for different page formats contain significant repetition. Consider refactoring to use CSS custom properties to simplify the code and enhance maintainability.

Here's how you might refactor the code:

:root {
  --translation-group-height-portrait: 35%;
  --translation-group-height-landscape: 42%;
  --image-container-height-portrait: 62%;
  --image-container-height-landscape: 55%;
  --font-size-large: 600%;
  --font-size-medium: 400%;
}

/* Portrait orientations */
.pictureAndWordPage[class*="Portrait"] .bloom-translationGroup {
  height: var(--translation-group-height-portrait);
}
.pictureAndWordPage[class*="Portrait"] .bloom-imageContainer {
  height: var(--image-container-height-portrait);
}

/* Landscape orientations */
.pictureAndWordPage[class*="Landscape"] .bloom-translationGroup {
  height: var(--translation-group-height-landscape);
}
.pictureAndWordPage[class*="Landscape"] .bloom-imageContainer {
  height: var(--image-container-height-landscape);
}

/* Font sizes */
.pictureAndWordPage .bloom-content1 {
  font-size: var(--font-size-medium);
}
.pictureAndWordPage[class*="Landscape"] .bloom-content1 {
  font-size: var(--font-size-large);
}

This approach will:

  1. Improve maintainability by centralizing common values.
  2. Simplify adjustments to styles across multiple page formats.
  3. Reduce the potential for inconsistencies and errors.
.storybook/main.ts (1)

23-26: Consider improving the book ID mapping implementation.

The hardcoded book ID mapping could be improved in several ways:

  1. Add TypeScript interface for better type safety
  2. Consider moving this to a separate configuration file
  3. Add comments explaining what these specific books are used for

Consider applying this improvement:

+interface BookMapping {
+    [key: string]: string;
+}
+
+// Map of book IDs to their corresponding test book names
+// multibook-index: Main index book for navigation testing
+// multibook-target1: Target book for navigation testing
 const idToBookName: BookMapping = {
     "2e492eb1-bcc5-4b2b-b756-6cda33e1eee4": "multibook-index",
     "2c1b71ac-f399-446d-8398-e61a8efd4e83": "multibook-target1",
 };
src/navigation.ts (1)

45-49: Simplify attribute access using optional chaining

You can streamline the code by utilizing optional chaining, which enhances readability.

Apply this diff:

 const href: string =
-    (linkElement.attributes["href"] &&
-        linkElement.attributes["href"].nodeValue) ||
-    (linkElement.attributes["data-href"] &&
-        linkElement.attributes["data-href"].nodeValue);
+    linkElement.attributes["href"]?.nodeValue ||
+    linkElement.attributes["data-href"]?.nodeValue;
🧰 Tools
🪛 Biome (1.9.4)

[error] 46-47: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

public/testBooks/multibook-target1/origami.css (1)

118-128: Remove commented code to clean up the stylesheet

There is commented-out code within the CSS that may no longer be needed. Consider removing it to improve maintainability.

Lines to remove:

/* JohnT mod: this extra padding makes it impossible to grab the crop control right above the split.
padding-bottom: 5px; /* this actually enlarges the target area for the user trying to find the splitter, without changing the layout of the page (because the position is absolute)*/
public/testBooks/multibook-index/appearance.css (1)

136-137: Remove duplicate .LegalLandscape selector

The .LegalLandscape selector appears twice, which is redundant and could cause confusion.

Apply this diff:

 .A4Portrait,
 .B5Portrait,
 .LetterLandscape,
 .LetterPortrait,
-.LegalLandscape,
 .LegalLandscape {
README-advanced.md (2)

28-28: Simplify phrasing for clarity

Consider rephrasing the sentence to improve readability.

Change:

-`npm` so as to be readily available to a variety of clients.
+`npm` to be readily available to clients.
🧰 Tools
🪛 LanguageTool

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)


28-28: Correct usage of 'both'

When using 'both', it's standard to use 'and' rather than 'as well as'.

Apply this diff:

-The published version includes both `dist/bloomPlayer-HASH.js`, as well as some mp3 files used by activities.
+The published version includes both `dist/bloomPlayer-HASH.js` and some mp3 files used by activities.
🧰 Tools
🪛 LanguageTool

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)

src/bloom-player-core.tsx (1)

2252-2254: Remove commented code

The fixInternalHyperlinks method is commented out but the code is still present. Since it's been replaced by checkClickForBookOrPageJump, this commented code should be removed to maintain code cleanliness.

public/testBooks/multibook-target1/appearance.css (2)

29-29: Consider using standard CSS values for visibility control.

The variable --pageNumber-show uses a non-standard value doShow-css-will-ignore-this-and-use-default. Consider using standard CSS values like block/none for better maintainability.

-    --pageNumber-show: doShow-css-will-ignore-this-and-use-default; /* default is number displaying (the value is a self-documenting trick) */
+    --pageNumber-show: block; /* Use standard CSS value for better maintainability */

187-190: Remove commented-out code.

The commented-out CSS rules should be removed if they're no longer needed. If they contain important information, consider moving it to documentation.

src/controlBar.tsx (3)

39-39: Remove unused import.

The Button import from @material-ui/core is not used in the code.

-import { Button } from "@material-ui/core";

Line range hint 270-296: Improve readability of conditional rendering.

The nested ternary expressions make the code harder to read. Consider extracting this logic into a separate function that returns the appropriate component.

+    const getBackButtonIcon = (state: BackButtonState) => {
+        switch (state) {
+            case BackButtonState.showArrow:
+                return (
+                    <ArrowBack
+                        aria-label="Go Back"
+                        titleAccess={LocalizationManager.getTranslation(
+                            "Button.Back",
+                            props.preferredLanguages,
+                            "Back"
+                        )}
+                    />
+                );
+            case BackButtonState.showEllipsis:
+                return (
+                    <MoreHoriz
+                        aria-label="More Menu"
+                        titleAccess={LocalizationManager.getTranslation(
+                            "Button.More",
+                            props.preferredLanguages,
+                            "More"
+                        )}
+                    />
+                );
+            default:
+                return null;
+        }
+    };

-    {props.getBackButtonState() === BackButtonState.showArrow ? (
-        <ArrowBack
-            aria-label="Go Back"
-            titleAccess={LocalizationManager.getTranslation(
-                "Button.Back",
-                props.preferredLanguages,
-                "Back"
-            )}
-        />
-    ) : (
-        props.getBackButtonState() === BackButtonState.showEllipsis && (
-            <MoreHoriz
-                aria-label="More Menu"
-                titleAccess={LocalizationManager.getTranslation(
-                    "Button.More",
-                    props.preferredLanguages,
-                    "More"
-                )}
-            />
-        )
-    )}
+    {getBackButtonIcon(props.getBackButtonState())}

255-268: Simplify back button click handler.

The click handler check can be combined with the disabled state check for more concise code.

 <IconButton
     color="secondary"
-    onClick={() => {
-        if (props.backClicked) {
-            props.backClicked();
-        }
-    }}
+    onClick={props.backClicked}
     data-testid="history-back-button"
     disabled={
-        props.getBackButtonState() === BackButtonState.showNothing
+        !props.backClicked || props.getBackButtonState() === BackButtonState.showNothing
     }
 >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d74b943 and 2226513.

⛔ Files ignored due to path filters (16)
  • public/testBooks/multibook-index/BloomLocal.svg is excluded by !**/*.svg
  • public/testBooks/multibook-index/back-cover-local.svg is excluded by !**/*.svg
  • public/testBooks/multibook-index/happy-pirate.png is excluded by !**/*.png
  • public/testBooks/multibook-index/history.db is excluded by !**/*.db
  • public/testBooks/multibook-index/image.jpg is excluded by !**/*.jpg
  • public/testBooks/multibook-index/license.png is excluded by !**/*.png
  • public/testBooks/multibook-index/placeHolder.png is excluded by !**/*.png
  • public/testBooks/multibook-index/thumbnail.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/BloomLocal.svg is excluded by !**/*.svg
  • public/testBooks/multibook-target1/back-cover-local.svg is excluded by !**/*.svg
  • public/testBooks/multibook-target1/history.db is excluded by !**/*.db
  • public/testBooks/multibook-target1/image.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/license.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/placeHolder.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/thumbnail.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (45)
  • .storybook/main.ts (2 hunks)
  • .storybook/preview.ts (1 hunks)
  • README-advanced.md (2 hunks)
  • README.md (4 hunks)
  • package.json (2 hunks)
  • public/testBooks/multibook-index/Basic Book.css (1 hunks)
  • public/testBooks/multibook-index/Traditional-XMatter.css (1 hunks)
  • public/testBooks/multibook-index/appearance.css (1 hunks)
  • public/testBooks/multibook-index/appearance.json (1 hunks)
  • public/testBooks/multibook-index/basePage.css (1 hunks)
  • public/testBooks/multibook-index/book.userPrefs (1 hunks)
  • public/testBooks/multibook-index/branding.css (1 hunks)
  • public/testBooks/multibook-index/customCollectionStyles.css (1 hunks)
  • public/testBooks/multibook-index/defaultLangStyles.css (1 hunks)
  • public/testBooks/multibook-index/index.htm (1 hunks)
  • public/testBooks/multibook-index/meta.json (1 hunks)
  • public/testBooks/multibook-index/origami.css (1 hunks)
  • public/testBooks/multibook-index/previewMode.css (1 hunks)
  • public/testBooks/multibook-index/publish-settings.json (1 hunks)
  • public/testBooks/multibook-target1/Basic Book.css (1 hunks)
  • public/testBooks/multibook-target1/Traditional-XMatter.css (1 hunks)
  • public/testBooks/multibook-target1/appearance.css (1 hunks)
  • public/testBooks/multibook-target1/appearance.json (1 hunks)
  • public/testBooks/multibook-target1/basePage.css (1 hunks)
  • public/testBooks/multibook-target1/book.userPrefs (1 hunks)
  • public/testBooks/multibook-target1/branding.css (1 hunks)
  • public/testBooks/multibook-target1/customCollectionStyles.css (1 hunks)
  • public/testBooks/multibook-target1/defaultLangStyles.css (1 hunks)
  • public/testBooks/multibook-target1/index.htm (1 hunks)
  • public/testBooks/multibook-target1/meta.json (1 hunks)
  • public/testBooks/multibook-target1/origami.css (1 hunks)
  • public/testBooks/multibook-target1/previewMode.css (1 hunks)
  • public/testBooks/multibook-target1/publish-settings.json (1 hunks)
  • src/bloom-player-controls.tsx (4 hunks)
  • src/bloom-player-core.tsx (25 hunks)
  • src/bloomPlayerAnalytics.tsx (1 hunks)
  • src/bookInfo.ts (1 hunks)
  • src/controlBar.tsx (5 hunks)
  • src/externalContext.ts (1 hunks)
  • src/navigation.test.ts (1 hunks)
  • src/navigation.ts (1 hunks)
  • src/stories/BloomPlayerIframe.tsx (1 hunks)
  • src/stories/BloomPlayerTester.ts (1 hunks)
  • src/stories/multiBook.stories.tsx (1 hunks)
  • src/stories/navigation.stories.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (28)
  • public/testBooks/multibook-target1/customCollectionStyles.css
  • .storybook/preview.ts
  • src/bloomPlayerAnalytics.tsx
  • public/testBooks/multibook-index/customCollectionStyles.css
  • src/externalContext.ts
  • public/testBooks/multibook-index/defaultLangStyles.css
  • src/bookInfo.ts
  • public/testBooks/multibook-index/appearance.json
  • public/testBooks/multibook-index/Traditional-XMatter.css
  • public/testBooks/multibook-target1/book.userPrefs
  • public/testBooks/multibook-target1/branding.css
  • public/testBooks/multibook-target1/appearance.json
  • public/testBooks/multibook-index/publish-settings.json
  • src/stories/BloomPlayerIframe.tsx
  • public/testBooks/multibook-index/meta.json
  • public/testBooks/multibook-target1/defaultLangStyles.css
  • src/stories/navigation.stories.tsx
  • public/testBooks/multibook-index/origami.css
  • public/testBooks/multibook-index/branding.css
  • public/testBooks/multibook-index/book.userPrefs
  • public/testBooks/multibook-target1/meta.json
  • public/testBooks/multibook-index/previewMode.css
  • src/navigation.test.ts
  • src/stories/multiBook.stories.tsx
  • public/testBooks/multibook-target1/publish-settings.json
  • package.json
  • public/testBooks/multibook-target1/index.htm
  • public/testBooks/multibook-index/index.htm
🧰 Additional context used
🪛 Biome (1.9.4)
src/bloom-player-core.tsx

[error] 1894-1894: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/navigation.ts

[error] 44-45: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 46-47: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🪛 LanguageTool
README-advanced.md

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)

README.md

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[grammar] ~57-~57: A determiner cannot be combined with a possessive pronoun. Did you mean simply “the” or “your”?
Context: ...post a message "backButtonClicked" that the your host can catch and respond to. Example...

(A_MY)


[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)

🪛 Markdownlint (0.35.0)
README.md

109-109: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)

🔇 Additional comments (28)
public/testBooks/multibook-target1/Traditional-XMatter.css (5)

1-9: LGTM! Good use of pseudo-elements and accessibility considerations.

The implementation properly handles page labels using pseudo-elements while maintaining accessibility by keeping the "Traditional" text in the DOM.


52-53: Fix invalid CSS value kFrontCoverImageOrder

The value kFrontCoverImageOrder appears to be intended as a CSS variable but is used directly. This will cause the order property to be invalid.

Also applies to: 58-59


111-226: LGTM! Well-structured layout with good responsive design practices.

The title page implementation demonstrates good practices:

  • Proper use of flexbox for layout management
  • Responsive design with flexible gaps
  • CSS variables for configuration
  • Appropriate image handling with object-fit

227-243: LGTM! Clean and straightforward implementation.

The back cover styling is appropriately minimal while maintaining consistency with the overall layout approach.


250-255: Consider making ISBN dimensions more flexible

The hard-coded dimensions and use of !important might cause maintainability issues.

public/testBooks/multibook-target1/previewMode.css (1)

33-35: Reconsider global cursor restriction

Setting cursor: not-allowed globally on the html element might be too restrictive and could affect interactive elements that should remain clickable in preview mode.

public/testBooks/multibook-target1/basePage.css (2)

1-14: LGTM: Base styles are well-structured

The base typography and layout styles are well-defined with:

  • Appropriate font stack with fallbacks
  • Good contrast for audio highlights
  • Proper flex layout for text containers

907-918: Avoid using unsupported CSS pseudo-class :has()

The CSS uses the :has() pseudo-class selector, which may cause compatibility issues.

public/testBooks/multibook-target1/Basic Book.css (2)

164-347: Reduce code duplication using CSS custom properties

As mentioned in earlier reviews, the styles for different page formats contain significant repetition. Refactoring to use CSS custom properties would enhance code maintainability.

Refer to the suggested refactoring approach provided previously.


65-87: ⚠️ Potential issue

Fix typo in class name 'nospecidalmovement'

As previously noted, there is a typo in the class name 'nospecidalmovement_imageOnTop'; it should be 'nospecialmovement_imageOnTop'.

Apply this correction throughout the file:

-.nospecidalmovement_imageOnTop
+.nospecialmovement_imageOnTop
.storybook/main.ts (4)

38-50: Handle undefined bookName to prevent potential errors.

The bookName could be undefined if the bookId is not found in the mapping.


61-65: Fix potential override of addons configuration.

Setting addons: ["@storybook/addon-interactions"] overwrites the existing addons array.


10-12: LGTM! Verify the build step documentation.

The static directory configuration and documentation are clear. The comment helpfully explains the build requirement for iframe-related stories.

Let's verify if the build step is documented in the repository:

✅ Verification successful

Build step is properly documented in package.json

The buildForStorybook script is well documented in package.json with a clear comment explaining its purpose: "run this when working with stories that use an iframe and bloomplayer.htm instead of the raw react components". This aligns perfectly with the comment in .storybook/main.ts.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the build step is documented in README or package.json
echo "Checking README for build documentation..."
rg -i "buildForStorybook|build.*storybook" README.md

echo "Checking package.json for build script..."
if [ -f "package.json" ]; then
    jq '.scripts | select(. | to_entries[] | .key | contains("buildForStorybook"))' package.json
fi

Length of output: 1527


53-59: ⚠️ Potential issue

Review the security implications of using file:/// protocol.

Using the file:/// protocol in the proxy target could potentially expose local files. Consider:

  1. Adding path validation
  2. Restricting access to specific directories
  3. Using a more secure proxy method

Let's check for other file protocol usage in the codebase:

src/navigation.ts (2)

33-37: 🛠️ Refactor suggestion

Enhance type safety and null checks in event handling

The event parameter is typed as any. Consider specifying it as MouseEvent and adding null checks to improve type safety.

Apply this diff:

-export function checkClickForBookOrPageJump(
-    event: any,
+export function checkClickForBookOrPageJump(
+    event: MouseEvent,
     currentBookInstanceId: string,
     getCurentPageId: () => string,
 ): ILocation {
-    const linkElement = (event.target as HTMLElement).closest(
+    const target = event.target as HTMLElement;
+    if (!target) return {};
+    const linkElement = target.closest(
         "[href], [data-href]",
     );

106-112: ⚠️ Potential issue

Add error handling for URL parsing

The parseTargetBookUrl function may throw an exception if the URL is malformed. Consider adding error handling to manage such cases gracefully.

Apply this diff:

 function parseTargetBookUrl(url: string) {
     // the format is "/book/BOOKID#PAGEID" where the page id is optional
+    try {
     const bloomUrl = new URL(url, window.location.origin);
     const bookId = bloomUrl.pathname.replace("/book/", "");
     const pageId = bloomUrl.hash.replace("#", "");
     return { bookId, pageId };
+    } catch (error) {
+        console.error("Error parsing URL:", error);
+        return { bookId: "", pageId: "" };
+    }
 }
src/stories/BloomPlayerTester.ts (3)

115-118: Replace pause function with a parameterized sleep utility

Create a reusable sleep function that accepts a duration parameter to improve code flexibility.

Apply this diff:

-/* oh, the shame! */
-async function pause() {
-    await new Promise((resolve) => setTimeout(resolve, 300));
-}
+/**
+ * Pauses execution for the specified duration.
+ * @param ms The duration to pause in milliseconds.
+ */
+function sleep(ms: number) {
+    return new Promise((resolve) => setTimeout(resolve, ms));
+}

Update calls to pause() to use sleep(ms) with appropriate durations.


3-7: 🛠️ Refactor suggestion

Improve type safety by handling iframeDoc as Document | null

Currently, iframeDoc is initialized using null as unknown as Document, which is not type-safe. Change the type to Document | null and handle null cases appropriately.

Apply this diff:

-    private iframeDoc: Document;
+    private iframeDoc: Document | null = null;

-        this.iframeDoc = null as unknown as Document;

Update usages of iframeDoc to handle possible null values.


22-25: ⚠️ Potential issue

Fix potential race condition when attaching onload handler

There's a risk that the iframe loads before the onload handler is attached, causing the promise to hang. Adjust the code to prevent this issue.

Apply this diff:

 this.iframeDoc = await new Promise<Document>((resolve) => {
+    const onLoadHandler = () => resolve(iframe.contentDocument!);
+    iframe.addEventListener('load', onLoadHandler);
+    if (iframe.contentDocument) {
+        iframe.removeEventListener('load', onLoadHandler);
+        resolve(iframe.contentDocument);
+    }
-    iframe.onload = () => resolve(iframe.contentDocument!);
 });
README.md (3)

5-11: LGTM!

The list of Bloom project usage is clear and well-documented.


102-130: Well-documented book linking implementation!

The documentation clearly explains:

  • How books link using Instance IDs
  • Resource request handling process
  • Implementation steps for hosts
🧰 Tools
🪛 LanguageTool

[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)

🪛 Markdownlint (0.35.0)

109-109: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)


151-154: LGTM!

Testing instructions are clear and easy to follow.

src/bloom-player-controls.tsx (2)

913-928: LGTM: Back button functionality is well-implemented

The back button implementation follows a clear hierarchy:

  1. First tries internal history navigation via CanGoBack()
  2. Falls back to host navigation if internal history is empty
  3. Intelligently handles different contexts (top window vs iframe)

Also applies to: 934-938


1041-1041: 🛠️ Refactor suggestion

Update property name for consistency

The property startPage is used here but has been renamed to startPageIndex in the interface. This should be updated for consistency.

-                startPageIndex={props.startPage}
+                startPageIndex={props.startPageIndex}

Likely invalid or redundant comment.

public/testBooks/multibook-index/basePage.css (1)

1-1304: LGTM: Well-structured CSS implementation

The CSS file provides comprehensive styling with:

  • Clear organization of rules by component
  • Proper use of CSS variables for maintainability
  • Responsive design handling for different page sizes
  • Proper fallbacks and browser compatibility
src/bloom-player-core.tsx (2)

361-370: LGTM: Improved navigation handling

The new click handler with checkClickForBookOrPageJump provides a more robust navigation system:

  • Properly handles book and page jumps
  • Maintains navigation history
  • Efficiently retrieves page IDs only when needed

1732-1832: LGTM: Robust font handling implementation

The font handling implementation is well-designed with:

  • Proper fallback chain: local → host → web fonts
  • Support for all font variants (regular, bold, italic)
  • Performance optimization by trying local fonts first
  • Clear documentation of the font loading strategy
public/testBooks/multibook-target1/appearance.css (1)

129-140: ⚠️ Potential issue

Remove duplicate .LegalLandscape class.

The selector list contains a duplicate entry for .LegalLandscape.

 .A3Landscape,
 .A3Portrait,
 .A4Landscape,
 .A4Portrait,
 .B5Portrait,
 .LetterLandscape,
 .LetterPortrait,
 .LegalLandscape,
-.LegalLandscape {
+.LegalPortrait {
     --page-margin: 15mm;
     --page-gutter: 10mm;
 }

Comment on lines +65 to +87
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
Copy link

@coderabbitai coderabbitai bot Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in class name 'nospecidalmovement'

There appears to be a typo in the class name 'nospecidalmovement_imageOnTop'; it should be 'nospecialmovement_imageOnTop'.

Apply this correction throughout the file:

-.nospecidalmovement_imageOnTop
+.nospecialmovement_imageOnTop
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
.nospecialmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecialmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecialmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecialmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecialmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hatton, understood. Skipping this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@hatton have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 53 seconds before sending another message.

Copy link
Collaborator

@andrew-polk andrew-polk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 51 of 62 files at r1, all commit messages.
Reviewable status: 51 of 62 files reviewed, 30 unresolved discussions (waiting on @coderabbitai[bot] and @hatton)


public/testBooks/multibook-index/index.htm line 1 at r2 (raw file):

<!DOCTYPE html>

Note that I did not really review the files in public/testBooks/multibook-index{1} but there are certainly some we could remove such as

  • history.db
  • userprefs
  • thumbnail
  • distribution
  • publish-settings

src/externalContext.ts line 116 at r2 (raw file):

let gotCapabilities = false;

export function sendBackToHost() {

There is an ambiguity in this name between

  • send to the host the fact that the client wants to perform a back
  • send the user back to the host

Indeed, until I saw more of the changes, the first time I saw this name elsewhere, I thought it was the latter.

Ideas:

  • performBackAction
  • informHostOfBackAction

.storybook/main.ts line 11 at r2 (raw file):

    stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
    // For stories that include an iframe and thus need access to bloomplayer.htm and the bundles it loads.
    // When using those stories, use `yarn buildForStorybook` to update non-storybook code.

Should there be a reference to this in the README?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (8)
.storybook/main.ts (2)

23-26: Consider improving type safety and maintainability

The hardcoded book ID mapping could benefit from:

  1. TypeScript interface/type definition
  2. Moving to a separate configuration file for easier maintenance

Consider applying this improvement:

+interface BookMapping {
+    [key: string]: string;
+}
+
+// Consider moving this to a separate config file
+const idToBookName: BookMapping = {
-const idToBookName = {
     "2e492eb1-bcc5-4b2b-b756-6cda33e1eee4": "multibook-index",
     "2c1b71ac-f399-446d-8398-e61a8efd4e83": "multibook-target1",
 };

27-60: Consider enhancing error handling and monitoring

The proxy configuration handles critical path routing for book resources. Consider adding:

  1. Structured error logging for failed rewrites
  2. Telemetry for tracking proxy performance
  3. Health checks for the proxy endpoints

This will help with debugging and maintaining the system in production.

README.md (4)

57-57: Fix grammatical errors and improve clarity in 'showBackButton' description

There are minor grammatical errors in the description. Consider making the following changes to improve clarity.

Apply this diff to fix the issues:

-If true, displays a button in the upper left corner of the app bar. When clicked, bloom-player will post a message "backButtonClicked" that the your host can catch and respond to.
+If true, displays a button in the upper-left corner of the app bar. When clicked, bloom-player will post a message "backButtonClicked" that your host can catch and respond to.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[grammar] ~57-~57: A determiner cannot be combined with a possessive pronoun. Did you mean simply “the” or “your”?
Context: ...post a message "backButtonClicked" that the your host can catch and respond to. Example...

(A_MY)


64-64: Add missing comma and hyphenate compound adjective

Add a comma after 'However' and hyphenate 'top level' to form 'top-level' in 'top-level window'.

Apply this diff to correct the sentence:

-> Normally this button will be a left arrow. However if bloom-player is the top level window (i.e. it is not embedded in another page), it will show as an ellipsis.
+> Normally this button will be a left arrow. However, if bloom-player is the top-level window (i.e., it is not embedded in another page), it will show as an ellipsis.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


78-78: Hyphenate compound adjectives in 'hideFullScreenButton' description

To improve readability, hyphenate compound adjectives such as 'Full Screen' and 'upper right-hand corner'.

Apply this diff:

-If true, the Full Screen icon button will not appear in the upper right hand corner of the window. Otherwise, a Full Screen icon button is displayed and allows the user to toggle between full screen and window mode.
+If true, the Full-Screen icon button will not appear in the upper right-hand corner of the window. Otherwise, a Full-Screen icon button is displayed and allows the user to toggle between full-screen and window mode.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~78-~78: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...#### hideFullScreenButton If true, the Full Screen icon button will not appear in the uppe...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~78-~78: Did you mean the adjective “right-hand”?
Context: ...con button will not appear in the upper right hand corner of the window. Otherwise, a Full...

(MISSING_HYPHEN)


[uncategorized] ~78-~78: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...hand corner of the window. Otherwise, a Full Screen icon button is displayed and allows the...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


161-161: Add missing comma in 'Running unit tests' section

Add a comma after 'tests' to improve readability.

Apply this diff:

-To run unit tests use `yarn test`. This will run all `*.test.ts`, which should be collocated with the thing being tested.
+To run unit tests, use `yarn test`. This will run all `*.test.ts`, which should be collocated with the thing being tested.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~161-~161: Possible missing comma found.
Context: ...y. ### Running unit tests To run unit tests use yarn test. This will run all `*.t...

(AI_HYDRA_LEO_MISSING_COMMA)

src/bloom-player-controls.tsx (1)

76-76: Fix typo in comment

There's a typo in the comment: 'us a proxy' should be 'use a proxy'.

Apply this diff:

-// TODO can we get rid of this and us a proxy? See .storybook/main.ts
+// TODO can we get rid of this and use a proxy? See .storybook/main.ts
src/bloom-player-core.tsx (1)

1908-1909: Simplify null checks using optional chaining

You can simplify the null check by using optional chaining.

Apply this diff:

-if (result && result.data) {
+if (result?.data) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 1909-1909: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2226513 and 04a01f1.

📒 Files selected for processing (10)
  • .storybook/main.ts (2 hunks)
  • README.md (6 hunks)
  • package.json (2 hunks)
  • src/bloom-player-controls.tsx (5 hunks)
  • src/bloom-player-core.tsx (25 hunks)
  • src/navigation.test.ts (1 hunks)
  • src/navigation.ts (1 hunks)
  • src/stories/BloomPlayerIframe.tsx (1 hunks)
  • src/stories/multiBook.stories.tsx (1 hunks)
  • src/stories/navigation.stories.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/stories/navigation.stories.tsx
  • src/navigation.test.ts
  • src/stories/BloomPlayerIframe.tsx
  • src/stories/multiBook.stories.tsx
  • package.json
🧰 Additional context used
🪛 Biome (1.9.4)
src/bloom-player-core.tsx

[error] 1909-1909: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🪛 LanguageTool
README.md

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[grammar] ~57-~57: A determiner cannot be combined with a possessive pronoun. Did you mean simply “the” or “your”?
Context: ...post a message "backButtonClicked" that the your host can catch and respond to. Example...

(A_MY)


[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~78-~78: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...#### hideFullScreenButton If true, the Full Screen icon button will not appear in the uppe...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~78-~78: Did you mean the adjective “right-hand”?
Context: ...con button will not appear in the upper right hand corner of the window. Otherwise, a Full...

(MISSING_HYPHEN)


[uncategorized] ~78-~78: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...hand corner of the window. Otherwise, a Full Screen icon button is displayed and allows the...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)


[uncategorized] ~161-~161: Possible missing comma found.
Context: ...y. ### Running unit tests To run unit tests use yarn test. This will run all `*.t...

(AI_HYDRA_LEO_MISSING_COMMA)

🪛 Markdownlint (0.35.0)
README.md

110-110: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)

🔇 Additional comments (7)
.storybook/main.ts (4)

38-50: Handle undefined bookName to prevent potential errors

This is a previously identified issue that still needs addressing.


61-65: Fix potential override of addons configuration

This is a previously identified issue that still needs addressing.


10-12: LGTM! Verify the dist directory setup

The static directory configuration is correct and well-documented. The comments provide clear guidance about using yarn watchForStorybook.

✅ Verification successful

The staticDirs: ["../dist"] configuration is correct and well-supported

The setup is verified to be correct because:

  • The dist directory is a build output directory configured in vite.config.ts
  • The watchForStorybook script in package.json specifically builds and watches this directory for development
  • Multiple dist artifacts (JS, HTML, MP3, CSS, TSV) are referenced in the package.json
  • The comment's instruction to use yarn watchForStorybook aligns with the available npm script
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the existence of the dist directory and its contents
fd -t d "^dist$" -x ls -la {} \;

Length of output: 37


Script:

#!/bin/bash
# Let's check if there are any references to the dist directory in package.json or other configuration files
rg "dist" -g "package.json" -g "*.config.*" -g ".storybook/*"

# Also check for any build or watch scripts that might generate the dist directory
rg "watchForStorybook|build" package.json

Length of output: 587


28-30: Clarify CORS resolution strategy

The comment indicates that CORS issues are not resolved ("THIS IS NOT WORKING"). This needs to be addressed or documented more clearly.

src/navigation.ts (2)

107-113: Add error handling for URL parsing

The parseTargetBookUrl function should handle potential exceptions when parsing the URL to prevent the application from crashing if an invalid URL is passed.


28-32: Improve type safety and add null checks in event handling

The event parameter should be typed more specifically than any, such as MouseEvent. Additionally, ensure that null checks are in place when accessing event properties to prevent runtime errors.

src/bloom-player-controls.tsx (1)

1041-1041: ⚠️ Potential issue

Fix incorrect prop usage: use props.startPageIndex instead of props.startPage

In the BloomPlayerCore component, the startPageIndex prop is being set to props.startPage, which is outdated. It should use props.startPageIndex to match the updated prop name in BloomPlayerProps.

Apply this diff to fix the issue:

-startPageIndex={props.startPage}
+startPageIndex={props.startPageIndex}

if (!bloomPage) {
throw new Error("No bloomPage at index " + index);
}
return bloomPage.getAttribute("id")!;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential null value when accessing page ID

The id attribute may be null. Consider adding error handling to avoid potential runtime errors.

Apply this diff:

-return bloomPage.getAttribute("id")!;
+const pageId = bloomPage.getAttribute("id");
+if (!pageId) {
+    throw new Error("No page ID found for index " + index);
+}
+return pageId;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return bloomPage.getAttribute("id")!;
const pageId = bloomPage.getAttribute("id");
if (!pageId) {
throw new Error("No page ID found for index " + index);
}
return pageId;

@andrew-polk
Copy link
Collaborator

src/bloom-player-core.tsx line 1689 at r3 (raw file):

    // a corresponding woff font in a standard location. We may even be able to pay to
    // provide some fonts there for book previewing that are NOT embeddable.
    private makeFontStylesheet(href: string): void {

I think all this got readded by accident during a merge?
You had previously pulled it out to a separate file.

Comment on lines +39 to +44
const bookId = path.split("/")[2];
const bookName = idToBookName[bookId];
const rewrittenPath = path.replace(
`/book/${bookId}`,
`testBooks/${bookName}`,
);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skip

Comment on lines +61 to +65
return {
...config,
server: { ...config.server, proxy: updatedProxy },
addons: ["@storybook/addon-interactions"],
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skip

Comment on lines +129 to +140
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skip

Comment on lines +65 to +87
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Comment on lines +25 to +54
/* these rules allow different branding insertions depending on orientation */
.portraitOnly,
.landscapeOnly {
display: none;
}
.Size6x9Portrait .portraitOnly,
.USComicPortrait .portraitOnly,
.Device16x9Portrait .portraitOnly,
.QuarterLetterPortrait .portraitOnly,
.HalfLetterPortrait .portraitOnly,
.LetterPortrait .portraitOnly,
.LegalPortrait .portraitOnly,
.A3Portrait .portraitOnly,
.A4Portrait .portraitOnly,
.A5Portrait .portraitOnly,
.B5Portrait .portraitOnly,
.A6Portrait .portraitOnly {
display: unset;
}
.Size6x9Landscape .landscapeOnly,
.Cm13Landscape .landscapeOnly,
.Device16x9Landscape .landscapeOnly,
.LetterLandscape .landscapeOnly,
.LegalLandscape .landscapeOnly,
.A3Landscape .landscapeOnly,
.A4Landscape .landscapeOnly,
.A5Landscape .landscapeOnly,
.A6Landscape .landscapeOnly {
display: unset;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Comment on lines +55 to +58
.outsideBackCover img.branding {
margin-top: 4px;
width: 10cm;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link
Member Author

@hatton hatton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 48 of 62 files reviewed, 32 unresolved discussions (waiting on @andrew-polk and @coderabbitai[bot])


.storybook/main.ts line 11 at r2 (raw file):

Previously, andrew-polk wrote…

Should there be a reference to this in the README?

Personally I consider package.json to be the index to these things in itself. No value is added (but risk increased) by documenting in two places.


public/testBooks/multibook-index/index.htm line 1 at r2 (raw file):

Previously, andrew-polk wrote…

Note that I did not really review the files in public/testBooks/multibook-index{1} but there are certainly some we could remove such as

  • history.db
  • userprefs
  • thumbnail
  • distribution
  • publish-settings

done except distribution, which bloom-player reads

public/testBooks/multibook-index/index.htm Show resolved Hide resolved

<div class="bloom-editable bloom-nodefaultstylerule Title-On-Cover-style bloom-padForOverflow bloom-visibility-code-on bloom-content1 bloom-contentNational1 bloom-contentFirst"
lang="en" contenteditable="true" data-book="bookTitle" style="padding-bottom: 0px;" tabindex="0"
spellcheck="false" role="textbox" aria-label="false" data-hasqtip="true" aria-describedby="qtip-0">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

</div>

<div class="bloom-imageContainer">
<img data-book="coverImage" src="placeHolder.png" alt=""></img>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Comment on lines +363 to +371
<p><a href="#cover">This book Cover</a></p>

<p><a href="#0b22a586-3324-4a76-b95d-e49ca03105d8">This book pirate page</a></p>

<p><a href="/book/2c1b71ac-f399-446d-8398-e61a8efd4e83">Book 1</a>
</p>
<p><a href="/book/2c1b71ac-f399-446d-8398-e61a8efd4e83#b0f5224f-7a31-4944-84fb-f2cd46d56fc8">Book
1 Crab Page</a>
</p>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Comment on lines +129 to +140
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Copy link
Member Author

@hatton hatton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 48 of 62 files reviewed, 32 unresolved discussions (waiting on @andrew-polk and @coderabbitai[bot])

Comment on lines +65 to +87
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip

Comment on lines +164 to +347
.pictureAndWordPage.QuarterLetterLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.QuarterLetterLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.LetterPortrait .bloom-translationGroup {
height: 23%;
}
.pictureAndWordPage.LetterPortrait .bloom-imageContainer {
height: 74%;
}
.pictureAndWordPage.LetterPortrait .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LetterLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.LetterLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.LetterLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LegalPortrait .bloom-translationGroup {
height: 23%;
}
.pictureAndWordPage.LegalPortrait .bloom-imageContainer {
height: 74%;
}
.pictureAndWordPage.LegalPortrait .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LegalLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.LegalLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.LegalLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.Cm13Landscape .bloom-translationGroup {
height: 37%;
}
.pictureAndWordPage.Cm13Landscape .bloom-imageContainer {
height: 60%;
}
.pictureAndWordPage.Cm13Landscape .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.USComicPortrait .bloom-translationGroup {
height: 32%;
}
.pictureAndWordPage.USComicPortrait .bloom-imageContainer {
height: 65%;
}
.pictureAndWordPage.USComicPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage .bloom-translationGroup {
width: 100%;
text-align: center;
padding-top: 10px;
}
.pictureAndWordPage .bloom-editable {
vertical-align: middle;
height: auto;
}
.pictureAndWordPage .bloom-content2,
.pictureAndWordPage .bloom-content3 {
font-size: 200%;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Comment on lines +907 to +918
.bloom-vertical-align-center:not(:has(.overflow)) {
justify-content: center;
}
.bloom-vertical-align-center:not(:has(.overflow)):not(.bloom-bilingual):not(.bloom-trilingual) .bloom-editable {
justify-content: center;
}
.bloom-vertical-align-bottom:not(:has(.overflow)) {
justify-content: flex-end;
}
.bloom-vertical-align-bottom:not(:has(.overflow)):not(.bloom-bilingual):not(.bloom-trilingual) .bloom-editable {
justify-content: flex-end;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Comment on lines +55 to +58
.outsideBackCover img.branding {
margin-top: 4px;
width: 10cm;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Comment on lines +373 to +374
title=""><img src="image.png" alt="" data-copyright="" data-creator=""
data-license=""></img></div>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Comment on lines +33 to +35
html {
cursor: not-allowed;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Comment on lines +52 to +53
order: kFrontCoverImageOrder;
flex: 1 1 auto;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Comment on lines +250 to +255
.ISBNContainer .bloom-editable {
text-align: left !important;
width: 4.3cm !important;
max-height: 1.8em;
min-height: 1.8em;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to review html or css in this pr

Copy link
Member Author

@hatton hatton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 48 of 62 files reviewed, 32 unresolved discussions (waiting on @andrew-polk and @coderabbitai[bot])

Comment on lines +39 to +44
const bookId = path.split("/")[2];
const bookName = idToBookName[bookId];
const rewrittenPath = path.replace(
`/book/${bookId}`,
`testBooks/${bookName}`,
);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +61 to +65
return {
...config,
server: { ...config.server, proxy: updatedProxy },
addons: ["@storybook/addon-interactions"],
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +129 to +140
.A3Landscape,
.A3Portrait,
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +65 to +87
.nospecidalmovement_imageOnTop .bloom-imageContainer {
height: calc(45% - var(--multilingual-editable-vertical-gap));
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.nospecidalmovement_imageOnTop .bloom-translationGroup {
height: 50%;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}
.nospecidalmovement_imageOnTop .bloom-editable.bloom-monolingual {
height: 100%;
}
.bloom-bilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(50% - var(--multilingual-editable-vertical-gap));
}
.bloom-trilingual.nospecidalmovement_imageOnTop .bloom-editable {
height: calc(33% - var(--multilingual-editable-vertical-gap));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +25 to +54
/* these rules allow different branding insertions depending on orientation */
.portraitOnly,
.landscapeOnly {
display: none;
}
.Size6x9Portrait .portraitOnly,
.USComicPortrait .portraitOnly,
.Device16x9Portrait .portraitOnly,
.QuarterLetterPortrait .portraitOnly,
.HalfLetterPortrait .portraitOnly,
.LetterPortrait .portraitOnly,
.LegalPortrait .portraitOnly,
.A3Portrait .portraitOnly,
.A4Portrait .portraitOnly,
.A5Portrait .portraitOnly,
.B5Portrait .portraitOnly,
.A6Portrait .portraitOnly {
display: unset;
}
.Size6x9Landscape .landscapeOnly,
.Cm13Landscape .landscapeOnly,
.Device16x9Landscape .landscapeOnly,
.LetterLandscape .landscapeOnly,
.LegalLandscape .landscapeOnly,
.A3Landscape .landscapeOnly,
.A4Landscape .landscapeOnly,
.A5Landscape .landscapeOnly,
.A6Landscape .landscapeOnly {
display: unset;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +55 to +58
.outsideBackCover img.branding {
margin-top: 4px;
width: 10cm;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

public/testBooks/multibook-index/index.htm Show resolved Hide resolved

<div class="bloom-editable bloom-nodefaultstylerule Title-On-Cover-style bloom-padForOverflow bloom-visibility-code-on bloom-content1 bloom-contentNational1 bloom-contentFirst"
lang="en" contenteditable="true" data-book="bookTitle" style="padding-bottom: 0px;" tabindex="0"
spellcheck="false" role="textbox" aria-label="false" data-hasqtip="true" aria-describedby="qtip-0">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

</div>

<div class="bloom-imageContainer">
<img data-book="coverImage" src="placeHolder.png" alt=""></img>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@BloomBooks BloomBooks deleted a comment from coderabbitai bot Dec 10, 2024
@BloomBooks BloomBooks deleted a comment from coderabbitai bot Dec 10, 2024
@BloomBooks BloomBooks deleted a comment from coderabbitai bot Dec 10, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (7)
src/stories/BloomPlayerTester.ts (2)

76-76: Address the TODO comment about locationOfDistFolder.

The comment suggests using a proxy instead of the locationOfDistFolder parameter.

Would you like me to help create a proxy configuration in the Storybook setup to eliminate this parameter?


119-122: Replace magic number with named constant.

The pause duration of 300ms is hardcoded without explanation.

+const DEFAULT_PAUSE_DURATION_MS = 300;
 async function pause() {
-    await new Promise((resolve) => setTimeout(resolve, 300));
+    await new Promise((resolve) => setTimeout(resolve, DEFAULT_PAUSE_DURATION_MS));
 }
src/navigation.test.ts (1)

8-14: Consider using beforeAll for one-time setup.

The history clearing in beforeEach might be more appropriate in beforeAll if the history state is not modified by individual tests.

+beforeAll(() => {
+    // Clear navigation history once before all tests
+    while (canGoBack()) {
+        tryPopPlayerHistory("dummy");
+    }
+});

-beforeEach(() => {
-    // Clear navigation history before each test
-    while (canGoBack()) {
-        tryPopPlayerHistory("dummy");
-    }
-});
src/bloom-player-controls.tsx (1)

911-926: Improve readability of back button state logic.

The nested if-else conditions make the logic harder to follow.

Consider extracting the logic into a more readable structure:

-getBackButtonState={() => {
-    if (coreRef.current?.CanGoBack())
-        return BackButtonState.showArrow;
-    else if (showBackButton) {
-        if (window === window.top)
-            return BackButtonState.showArrow;
-        else return BackButtonState.showEllipsis;
-    }
-    else return BackButtonState.showNothing;
-}}
+getBackButtonState(): BackButtonState {
+    if (coreRef.current?.CanGoBack()) {
+        return BackButtonState.showArrow;
+    }
+    
+    if (!showBackButton) {
+        return BackButtonState.showNothing;
+    }
+    
+    return window === window.top
+        ? BackButtonState.showArrow
+        : BackButtonState.showEllipsis;
+}
src/bloom-player-core.tsx (3)

Line range hint 1760-1775: Consider future-proofing the RTL implementation

The current RTL implementation works but relies on swiper's internal implementation. Consider:

  • Adding a TODO to track the upgrade to newer swiper version with built-in RTL support
  • Documenting the current approach for maintainability
 if (this.metaDataObject?.isRtl && this.swiperInstance) {
+    // TODO: Replace this implementation with Swiper's built-in RTL support when upgrading to newer version
+    // Current approach uses internal Swiper properties which may change in future versions
     this.swiperInstance.el?.setAttribute("dir", "rtl");
     this.swiperInstance.rtl = true;
     this.swiperInstance.rtlTranslate = true;
 }

907-910: Consider using a more explicit map initialization

The current map initialization could be more explicit:

  • pageIdToIndex.length = 0 is an unusual way to clear a map
  • Consider using a new object instead
-// clear the pageIdToIndex map
-pageIdToIndex.length = 0;
-pageIdToIndex["cover"] = 0;
+// Initialize the pageIdToIndex map
+const pageIdToIndex: { [key: string]: number } = {
+    cover: 0
+};

1030-1039: Enhance error message for page ID lookup

Consider providing a more descriptive error message to help with debugging:

 if (pageIdToIndex[this.state.startPageId] === undefined) {
     throw new Error(
-        `Page ID ${this.state.startPageId} not found in the current pageIdToIndexMap`,
+        `Page ID ${this.state.startPageId} not found in the current pageIdToIndexMap. ` +
+        `Available page IDs: ${Object.keys(pageIdToIndex).join(", ")}`
     );
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 04a01f1 and 3193db6.

📒 Files selected for processing (6)
  • src/bloom-player-controls.tsx (5 hunks)
  • src/bloom-player-core.tsx (25 hunks)
  • src/externalContext.ts (1 hunks)
  • src/navigation.test.ts (1 hunks)
  • src/navigation.ts (1 hunks)
  • src/stories/BloomPlayerTester.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/externalContext.ts
  • src/navigation.ts
🔇 Additional comments (7)
src/stories/BloomPlayerTester.ts (1)

1-32: 🛠️ Refactor suggestion

Consider adding error handling for iframe access.

The initialization logic assumes the iframe's contentDocument will be accessible. However, cross-origin restrictions might prevent access to the iframe's content.

Add try-catch blocks around iframe access:

 if (iframe) {
+    try {
         if (iframe.contentDocument) {
             this.iframeDoc = iframe.contentDocument;
             return;
         }
         this.iframeDoc = await new Promise<Document>((resolve) => {
             iframe.onload = () => resolve(iframe.contentDocument!);
         });
         return;
+    } catch (e) {
+        throw new Error(`Cannot access iframe content: ${e.message}`);
+    }
 }
src/bloom-player-controls.tsx (1)

1041-1041: ⚠️ Potential issue

Breaking change: Rename startPage prop to startPageIndex.

The code still uses the old startPage prop name while passing it as startPageIndex to the core component.

This is a duplicate of the previous review comment. The breaking change needs to be addressed by updating the prop name consistently across the codebase.

src/bloom-player-core.tsx (5)

80-85: LGTM: Clean interface changes for navigation support

The new imports and interface changes are well-structured and properly support the navigation functionality:

  • Modular approach with navigation-specific functions
  • Clear state management for book URL and page tracking

Also applies to: 183-187, 226-228


355-369: LGTM: Clean implementation of navigation handlers

The navigation implementation is well-structured:

  • Prevents unwanted swiper behavior for links
  • Properly handles both book and page navigation
  • Clear separation of concerns between event handling and navigation logic

Also applies to: 374-383


422-445: LGTM: Well-implemented back button support

The back button implementation is clean and follows good practices:

  • Clear method names
  • Proper separation between checking and handling
  • Consistent error handling

555-561: LGTM: Improved URL handling

The URL handling improvements are well-implemented:

  • Properly handles both relative and absolute paths
  • Clear logic for handling leading slashes

2184-2191: ⚠️ Potential issue

Handle potential null value when accessing page ID

The id attribute may be null. Consider adding error handling to avoid potential runtime errors.

Apply this diff:

-return bloomPage.getAttribute("id")!;
+const pageId = bloomPage.getAttribute("id");
+if (!pageId) {
+    throw new Error("No page ID found for index " + index);
+}
+return pageId;

Comment on lines 34 to 57
async clickLinkByText(text: string) {
await pause();
const link = await waitFor(
() => {
const links = Array.from(this.iframeDoc.querySelectorAll("a"));
const link = links.find((el) => el.textContent?.includes(text));
if (!link)
throw new Error(`Link containing "${text}" not found`);
return link;
},
{ timeout: 5000 },
);
// the "pointerdown" event fails to trigger with the normal click here,
// which probably does a number of things, at least mousedown and up.
// As a workaround, we're sending the raw "click" event.
await fireEvent.click(link as HTMLElement);
//await userEvent.click(link as HTMLElement);
}

async goToNextPage() {
await new Promise((resolve) => setTimeout(resolve, 500));
const rightButton = await waitFor(() => {
return this.iframeDoc.documentElement.querySelector(
".swiper-button-right",
);
});
await userEvent.click(rightButton!);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve click event handling reliability.

The comment about pointerdown event failure suggests potential reliability issues with the click event handling.

Consider using a more robust click simulation:

-await fireEvent.click(link as HTMLElement);
+// Simulate full click sequence
+await fireEvent.pointerDown(link as HTMLElement);
+await fireEvent.pointerUp(link as HTMLElement);
+await fireEvent.click(link as HTMLElement);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async clickLinkByText(text: string) {
await pause();
const link = await waitFor(
() => {
const links = Array.from(this.iframeDoc.querySelectorAll("a"));
const link = links.find((el) => el.textContent?.includes(text));
if (!link)
throw new Error(`Link containing "${text}" not found`);
return link;
},
{ timeout: 5000 },
);
// the "pointerdown" event fails to trigger with the normal click here,
// which probably does a number of things, at least mousedown and up.
// As a workaround, we're sending the raw "click" event.
await fireEvent.click(link as HTMLElement);
//await userEvent.click(link as HTMLElement);
}
async goToNextPage() {
await new Promise((resolve) => setTimeout(resolve, 500));
const rightButton = await waitFor(() => {
return this.iframeDoc.documentElement.querySelector(
".swiper-button-right",
);
});
await userEvent.click(rightButton!);
}
async clickLinkByText(text: string) {
await pause();
const link = await waitFor(
() => {
const links = Array.from(this.iframeDoc.querySelectorAll("a"));
const link = links.find((el) => el.textContent?.includes(text));
if (!link)
throw new Error(`Link containing "${text}" not found`);
return link;
},
{ timeout: 5000 },
);
// the "pointerdown" event fails to trigger with the normal click here,
// which probably does a number of things, at least mousedown and up.
// As a workaround, we're sending the raw "click" event.
await fireEvent.pointerDown(link as HTMLElement);
await fireEvent.pointerUp(link as HTMLElement);
await fireEvent.click(link as HTMLElement);
//await userEvent.click(link as HTMLElement);
}
async goToNextPage() {
await new Promise((resolve) => setTimeout(resolve, 500));
const rightButton = await waitFor(() => {
return this.iframeDoc.documentElement.querySelector(
".swiper-button-right",
);
});
await userEvent.click(rightButton!);
}

Comment on lines +88 to +105
const windowSpy = vi
.spyOn(window, "open")
.mockImplementation(() => null);
const event = createClickEvent("https://example.com");
const result = checkClickForBookOrPageJump(
event,
"doesn't matter",
() => "doesn't matter",
);

expect(result).toEqual({});
expect(windowSpy).toHaveBeenCalledWith(
"https://example.com",
"_blank",
"noreferrer",
);
windowSpy.mockRestore();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure mock cleanup in all test paths.

The window.open mock cleanup might not occur if the test fails.

+let windowSpy: any;
+
+beforeEach(() => {
+    windowSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
+});
+
+afterEach(() => {
+    windowSpy.mockRestore();
+});

 test("handles external links", () => {
-    const windowSpy = vi
-        .spyOn(window, "open")
-        .mockImplementation(() => null);
     const event = createClickEvent("https://example.com");
     const result = checkClickForBookOrPageJump(
         event,
         "doesn't matter",
         () => "doesn't matter",
     );

     expect(result).toEqual({});
     expect(windowSpy).toHaveBeenCalledWith(
         "https://example.com",
         "_blank",
         "noreferrer",
     );
-    windowSpy.mockRestore();
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const windowSpy = vi
.spyOn(window, "open")
.mockImplementation(() => null);
const event = createClickEvent("https://example.com");
const result = checkClickForBookOrPageJump(
event,
"doesn't matter",
() => "doesn't matter",
);
expect(result).toEqual({});
expect(windowSpy).toHaveBeenCalledWith(
"https://example.com",
"_blank",
"noreferrer",
);
windowSpy.mockRestore();
});
let windowSpy: any;
beforeEach(() => {
windowSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
});
afterEach(() => {
windowSpy.mockRestore();
});
test("handles external links", () => {
const event = createClickEvent("https://example.com");
const result = checkClickForBookOrPageJump(
event,
"doesn't matter",
() => "doesn't matter",
);
expect(result).toEqual({});
expect(windowSpy).toHaveBeenCalledWith(
"https://example.com",
"_blank",
"noreferrer",
);
});

Comment on lines 932 to 938
backClicked={() => {
if (
!coreRef.current?.HandleBackButtonClickedIfHavePlayerHistory()
) {
informHostOfBackAction();
}
}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for back button click failures.

The back button click handler doesn't handle potential errors from HandleBackButtonClickedIfHavePlayerHistory.

 backClicked={() => {
+    try {
         if (
             !coreRef.current?.HandleBackButtonClickedIfHavePlayerHistory()
         ) {
             informHostOfBackAction();
         }
+    } catch (error) {
+        console.error('Failed to handle back button click:', error);
+        // Fallback to informing host
+        informHostOfBackAction();
+    }
 }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
backClicked={() => {
if (
!coreRef.current?.HandleBackButtonClickedIfHavePlayerHistory()
) {
informHostOfBackAction();
}
}}
backClicked={() => {
try {
if (
!coreRef.current?.HandleBackButtonClickedIfHavePlayerHistory()
) {
informHostOfBackAction();
}
} catch (error) {
console.error('Failed to handle back button click:', error);
// Fallback to informing host
informHostOfBackAction();
}
}}

@hatton hatton force-pushed the pageAndBookNavigation branch from 3193db6 to 514aa4f Compare December 11, 2024 21:59
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (24)
public/testBooks/multibook-index/basePage.css (3)

1-4: Enhance font stack with modern system fonts

Consider expanding the font fallback chain to include modern system UI fonts for better cross-platform consistency.

body {
  line-height: 1.5;
-  font-family: Andika, "Andika New Basic", "Andika Basic", "Gentium Basic", "Gentium Book Basic", "Doulos SIL", Sans-Serif;
+  font-family: Andika, "Andika New Basic", "Andika Basic", "Gentium Basic", "Gentium Book Basic", "Doulos SIL", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, Sans-Serif;
}

261-266: Use CSS variables for transform calculations

The transform values contain magic numbers that would be more maintainable if defined as CSS variables with clear documentation.

+:root {
+  /* Scale factors for full bleed pages */
+  --a5-scale: 1.04054054;
+  --a5-translate: 1.25675676mm;
+}

.bloom-fullBleed .bloom-page.A5Portrait {
-  transform: translate(0, -1.25675676mm) scale(1.04054054);
+  transform: translate(0, calc(-1 * var(--a5-translate))) scale(var(--a5-scale));
}

.bloom-fullBleed .bloom-page.A5Landscape {
-  transform: translate(-1.25675676mm, 0) scale(1.04054054);
+  transform: translate(calc(-1 * var(--a5-translate)), 0) scale(var(--a5-scale));
}

1213-1216: Improve readability of complex calculations

The margin and padding calculations are complex and could be more maintainable if broken down into intermediate variables with descriptive names.

.mixinBottomTgPadding {
-  --amountOfExtraMarginAddedForPageNumber: calc(var(--pageNumber-extra-height) * var(--pageNumber-show-multiplicand));
-  --totalBottomMargin: calc(var(--page-margin-bottom) + var(--amountOfExtraMarginAddedForPageNumber));
-  --amountOfVisualPaddingProvidedByBottomMargin: calc(var(--totalBottomMargin) * var(--page-and-marginBox-are-same-color-multiplicand));
-  padding-bottom: calc(var(--topLevel-text-padding-bottom) - var(--amountOfVisualPaddingProvidedByBottomMargin));
+  /* Extra margin for page numbers when they are shown */
+  --page-number-margin: calc(var(--pageNumber-extra-height) * var(--pageNumber-show-multiplicand));
+  
+  /* Total margin including page numbers */
+  --total-bottom-margin: calc(var(--page-margin-bottom) + var(--page-number-margin));
+  
+  /* Visual padding adjustment based on margin box color */
+  --margin-visual-padding: calc(var(--total-bottom-margin) * var(--page-and-marginBox-are-same-color-multiplicand));
+  
+  /* Final padding calculation */
+  padding-bottom: calc(var(--topLevel-text-padding-bottom) - var(--margin-visual-padding));
}
public/testBooks/multibook-index/Basic Book.css (2)

1-7: Consider using relative units for better responsiveness

The .translators class uses a fixed height of 1.6cm. Consider using relative units (e.g., em or rem) for better responsiveness across different screen sizes and zoom levels.

.translators {
  text-align: center;
-  height: 1.6cm;
+  height: 2.5rem;
  position: relative;
}

154-157: Enhance documentation for vertical centering implementation

The comment about vertical centering could be more helpful by providing a specific reference to the JavaScript implementation.

-/*Text Whole Page
-The current version of this is centered vertically; if you're looking for how that is done, it's not here, but rather
-in javascript. Search for 'bloom-centerContentVertically'.
-*/
+/* Text Whole Page
+ * Vertical centering is implemented in JavaScript using the 'bloom-centerContentVertically' class.
+ * @see src/bloom-player-core.tsx - handleCenterContentVertically()
+ */
.storybook/main.ts (2)

23-26: Consider making book mappings more maintainable.

The hardcoded book ID to name mapping could become difficult to maintain. Consider moving this to a separate configuration file.

-const idToBookName = {
-    "2e492eb1-bcc5-4b2b-b756-6cda33e1eee4": "multibook-index",
-    "2c1b71ac-f399-446d-8398-e61a8efd4e83": "multibook-target1",
-};
+import { bookMappings } from '../config/storybook-book-mappings';
+const idToBookName = bookMappings;

46-49: Remove commented console.log statements.

Either remove or uncomment the logging statements. Commented-out code should not be committed.

public/testBooks/multibook-index/meta.json (2)

1-1: Consider PII implications in location data

The file contains specific location information (country, province, district). Consider:

  1. Whether this level of detail is necessary
  2. Privacy implications for users
  3. GDPR compliance if deployed in EU

1-1: Standardize boolean field values

Some boolean fields use explicit false while others are null. Consider standardizing the approach:

  • a11y_NoEssentialInfoByColor: false
  • hazards: null
  • a11yFeatures: null
-"hazards":null,
-"a11yFeatures":null,
+"hazards":false,
+"a11yFeatures":false,
README-advanced.md (1)

28-28: Improve sentence clarity and grammar

Consider rephrasing the sentence for better readability. Replace "so as to" with "to", "a variety of" with "various", and use "and" after "both".

Apply this diff to enhance the sentence:

-Bloom-player is designed to be published using `npm` so as to be readily available to a variety of clients. The published version includes both `dist/bloomPlayer-HASH.js`, as well as some mp3 files used by activities.
+Bloom-player is designed to be published using `npm` to be readily available to various clients. The published version includes both `dist/bloomPlayer-HASH.js` and some mp3 files used by activities.
🧰 Tools
🪛 LanguageTool

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)

src/navigation.ts (1)

59-69: Reuse 'goBackInHistoryIfPossible' to reduce code duplication

The logic for handling 'back' navigation duplicates code from goBackInHistoryIfPossible. Consider using the existing function to promote code reuse.

Apply this diff to refactor the code:

 if (href === "back") {
-    const previousLocation = jumpHistory.pop();
-    if (previousLocation) {
-        return {
-            bookUrl:
-                currentBookInstanceId === previousLocation.bookId
-                    ? undefined // we don't want to switch books, just pages
-                    : urlFromBookId(previousLocation.bookId!),
-            pageId: previousLocation.pageId,
-        };
-    }
+    const location = goBackInHistoryIfPossible(currentBookInstanceId);
+    if (location) {
+        return location;
+    }
 } else if (href.startsWith("/book/")) {
src/navigation.test.ts (2)

9-14: Consider using a more robust cleanup approach.

The current cleanup in beforeEach relies on the functions being tested, which could mask issues if these functions have bugs.

Consider using a more direct approach to reset the history:

-    beforeEach(() => {
-        // Clear navigation history before each test
-        while (canGoBack()) {
-            goBackInHistoryIfPossible("dummy");
-        }
-    });
+    beforeEach(() => {
+        vi.resetModules();
+        // Reset the navigation history directly
+        vi.stubGlobal('navigationHistory', []);
+    });

138-152: Consider enhancing the mock event helper.

The createClickEvent helper could be more robust by including additional event properties that might be needed in future tests.

Consider enhancing the helper:

 function createClickEvent(href: string) {
     const mockElement = {
         attributes: {
             href: { nodeValue: href },
         },
         closest: () => mockElement,
+        getAttribute: (attr: string) => attr === 'href' ? href : null,
+        dataset: {},
     };
 
     return {
         target: mockElement,
         preventDefault: () => {},
         stopPropagation: () => {},
+        currentTarget: mockElement,
+        type: 'click',
+        bubbles: true,
+        cancelable: true,
     };
 }
README.md (2)

57-67: Add missing hyphen in 'upper left'.

The term should be hyphenated when used as a compound adjective.

-If true, displays a button in the upper left corner of the app bar.
+If true, displays a button in the upper-left corner of the app bar.

Also, consider adding a comma after "However" in the note section for better readability.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


151-154: Consider adding troubleshooting section.

The testing instructions could benefit from common troubleshooting scenarios.

Consider adding:

4. If the preview doesn't load:
   - Ensure Bloom Editor is running and in Preview mode
   - Check the browser console for any CORS-related errors
   - Verify the preview URL matches the expected format
public/testBooks/multibook-target1/appearance.css (2)

103-103: Fix incomplete comment.

The comment for --marginBox-background-color is incomplete and missing its closing quote.

--- marginBox-background-color: white; /* it is not transparent because at edit time we set the parent (the translationGroup) color to show padding
+-- marginBox-background-color: white; /* it is not transparent because at edit time we set the parent (the translationGroup) color to show padding */

115-117: Fix line break in comment.

The comment has an unintended line break that splits the word "edit-time".

-    /* In some themes, at edit-
-    time, the format button lands under the page number. See BL-13206. The name is is intentionally vague about direction and what we do with it. */
+    /* In some themes, at edit-time, the format button lands under the page number. See BL-13206. The name is is intentionally vague about direction and what we do with it. */
src/controlBar.tsx (2)

39-39: Remove unused import.

The Button import from @material-ui/core is not used in the code.

-import { Button } from "@material-ui/core";

Line range hint 254-296: Consider extracting back button rendering logic.

The back button rendering logic contains nested conditional expressions that could be simplified for better readability.

Consider extracting the icon rendering into a separate function:

const renderBackButtonIcon = (state: BackButtonState, preferredLanguages: string[]) => {
    switch (state) {
        case BackButtonState.showArrow:
            return (
                <ArrowBack
                    aria-label="Go Back"
                    titleAccess={LocalizationManager.getTranslation(
                        "Button.Back",
                        preferredLanguages,
                        "Back"
                    )}
                />
            );
        case BackButtonState.showEllipsis:
            return (
                <MoreHoriz
                    aria-label="More Menu"
                    titleAccess={LocalizationManager.getTranslation(
                        "Button.More",
                        preferredLanguages,
                        "More"
                    )}
                />
            );
        default:
            return null;
    }
};

Then use it in the JSX:

<IconButton
    color="secondary"
    onClick={() => props.backClicked?.()}
    data-testid="history-back-button"
    disabled={props.getBackButtonState() === BackButtonState.showNothing}
>
    {renderBackButtonIcon(props.getBackButtonState(), props.preferredLanguages)}
</IconButton>
src/bloom-player-core.tsx (1)

1698-1832: Consider caching font stylesheet content

The Andika font stylesheet is regenerated on each call to makeAndikaStylesheet. Consider caching the stylesheet content as a constant since it's static.

+const ANDIKA_FONT_STYLESHEET = `
+    @font-face {
+        font-family: "Andika New Basic";
+        // ... rest of the stylesheet content
+    }
+`.replace("\n", "").replace("\r", "");
+
 private makeAndikaStylesheet(): void {
     let stylesheet = document.getElementById(
         "andikaCssStyleSheet",
     ) as HTMLStyleElement;
     if (!stylesheet) {
         stylesheet = document.createElement("style");
         document.head.appendChild(stylesheet);
         stylesheet.setAttribute("id", "andikaCssStyleSheet");
     }
-    stylesheet.innerText = `
-        @font-face {
-            // ... current stylesheet content
-        }
-    `.replace("\n", "").replace("\r", "");
+    stylesheet.innerText = ANDIKA_FONT_STYLESHEET;
 }
public/testBooks/multibook-target1/origami.css (4)

46-48: Remove unnecessary commented-out code for cleaner maintenance.

The commented-out code and notes at lines 46-47 are unnecessary and can be removed to improve code readability and maintainability.

Apply this diff to remove the comments:

     cursor: ns-resize;
     z-index: 2;

-    /* JohnT mod: this extra padding makes it impossible to grab the crop control right above the split.
-    padding-bottom: 5px; /* this actually enlarges the target area for the user trying to find the splitter, without changing the layout of the page (because the position is absolute)*/
 }

102-102: Avoid using !important for better CSS maintainability.

Using !important can make the stylesheet harder to maintain and override. Consider restructuring the CSS to eliminate the need for !important.


273-275: Clean up commented-out code to enhance readability.

The commented lines at 273-275 seem to be leftover or unused code. Removing them will make the codebase cleaner.

Apply this diff:

-      /*the commented line below would also add it to an empty bloom-content1 for re-entry to layout mode*/
-      /*but that would be problematic/confusing in a multilingual context*/
-      /*.origami-layout-mode .split-pane-component-inner .bloom-editable.bloom-content1:empty:before,*/

215-223: Ensure font sizes are responsive for better accessibility.

The fixed font size of 12pt may not provide optimal readability on all devices. Consider using relative units like em or rem for scalability.

Apply this diff to use relative units:

 .split-pane-component-inner {
     position: relative;
     width: 100%;
     height: 100%;
     padding: 0px;
     box-sizing: border-box;
     transition-property: font-size;
     transition-duration: 0.5s;
-    font-size: 12pt;
+    font-size: 1em;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3193db6 and 514aa4f.

⛔ Files ignored due to path filters (16)
  • public/testBooks/multibook-index/BloomLocal.svg is excluded by !**/*.svg
  • public/testBooks/multibook-index/back-cover-local.svg is excluded by !**/*.svg
  • public/testBooks/multibook-index/happy-pirate.png is excluded by !**/*.png
  • public/testBooks/multibook-index/history.db is excluded by !**/*.db
  • public/testBooks/multibook-index/image.jpg is excluded by !**/*.jpg
  • public/testBooks/multibook-index/license.png is excluded by !**/*.png
  • public/testBooks/multibook-index/placeHolder.png is excluded by !**/*.png
  • public/testBooks/multibook-index/thumbnail.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/BloomLocal.svg is excluded by !**/*.svg
  • public/testBooks/multibook-target1/back-cover-local.svg is excluded by !**/*.svg
  • public/testBooks/multibook-target1/history.db is excluded by !**/*.db
  • public/testBooks/multibook-target1/image.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/license.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/placeHolder.png is excluded by !**/*.png
  • public/testBooks/multibook-target1/thumbnail.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (45)
  • .storybook/main.ts (2 hunks)
  • .storybook/preview.ts (1 hunks)
  • README-advanced.md (2 hunks)
  • README.md (4 hunks)
  • package.json (2 hunks)
  • public/testBooks/multibook-index/Basic Book.css (1 hunks)
  • public/testBooks/multibook-index/Traditional-XMatter.css (1 hunks)
  • public/testBooks/multibook-index/appearance.css (1 hunks)
  • public/testBooks/multibook-index/appearance.json (1 hunks)
  • public/testBooks/multibook-index/basePage.css (1 hunks)
  • public/testBooks/multibook-index/book.userPrefs (1 hunks)
  • public/testBooks/multibook-index/branding.css (1 hunks)
  • public/testBooks/multibook-index/customCollectionStyles.css (1 hunks)
  • public/testBooks/multibook-index/defaultLangStyles.css (1 hunks)
  • public/testBooks/multibook-index/index.htm (1 hunks)
  • public/testBooks/multibook-index/meta.json (1 hunks)
  • public/testBooks/multibook-index/origami.css (1 hunks)
  • public/testBooks/multibook-index/previewMode.css (1 hunks)
  • public/testBooks/multibook-index/publish-settings.json (1 hunks)
  • public/testBooks/multibook-target1/Basic Book.css (1 hunks)
  • public/testBooks/multibook-target1/Traditional-XMatter.css (1 hunks)
  • public/testBooks/multibook-target1/appearance.css (1 hunks)
  • public/testBooks/multibook-target1/appearance.json (1 hunks)
  • public/testBooks/multibook-target1/basePage.css (1 hunks)
  • public/testBooks/multibook-target1/book.userPrefs (1 hunks)
  • public/testBooks/multibook-target1/branding.css (1 hunks)
  • public/testBooks/multibook-target1/customCollectionStyles.css (1 hunks)
  • public/testBooks/multibook-target1/defaultLangStyles.css (1 hunks)
  • public/testBooks/multibook-target1/index.htm (1 hunks)
  • public/testBooks/multibook-target1/meta.json (1 hunks)
  • public/testBooks/multibook-target1/origami.css (1 hunks)
  • public/testBooks/multibook-target1/previewMode.css (1 hunks)
  • public/testBooks/multibook-target1/publish-settings.json (1 hunks)
  • src/bloom-player-controls.tsx (4 hunks)
  • src/bloom-player-core.tsx (25 hunks)
  • src/bloomPlayerAnalytics.tsx (1 hunks)
  • src/bookInfo.ts (1 hunks)
  • src/controlBar.tsx (5 hunks)
  • src/externalContext.ts (1 hunks)
  • src/navigation.test.ts (1 hunks)
  • src/navigation.ts (1 hunks)
  • src/stories/BloomPlayerIframe.tsx (1 hunks)
  • src/stories/BloomPlayerTester.ts (1 hunks)
  • src/stories/multiBook.stories.tsx (1 hunks)
  • src/stories/navigation.stories.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • public/testBooks/multibook-index/publish-settings.json
🚧 Files skipped from review as they are similar to previous changes (28)
  • public/testBooks/multibook-target1/customCollectionStyles.css
  • public/testBooks/multibook-index/customCollectionStyles.css
  • src/bookInfo.ts
  • public/testBooks/multibook-index/defaultLangStyles.css
  • public/testBooks/multibook-target1/appearance.json
  • public/testBooks/multibook-index/Traditional-XMatter.css
  • public/testBooks/multibook-target1/defaultLangStyles.css
  • public/testBooks/multibook-target1/Traditional-XMatter.css
  • public/testBooks/multibook-target1/book.userPrefs
  • src/stories/navigation.stories.tsx
  • public/testBooks/multibook-index/book.userPrefs
  • public/testBooks/multibook-index/origami.css
  • public/testBooks/multibook-index/appearance.json
  • src/bloomPlayerAnalytics.tsx
  • public/testBooks/multibook-target1/previewMode.css
  • src/stories/BloomPlayerIframe.tsx
  • public/testBooks/multibook-index/previewMode.css
  • .storybook/preview.ts
  • src/externalContext.ts
  • public/testBooks/multibook-index/branding.css
  • public/testBooks/multibook-target1/publish-settings.json
  • public/testBooks/multibook-target1/index.htm
  • public/testBooks/multibook-target1/meta.json
  • public/testBooks/multibook-index/index.htm
  • src/stories/BloomPlayerTester.ts
  • package.json
  • src/stories/multiBook.stories.tsx
  • src/bloom-player-controls.tsx
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~57-~57: Consider adding a hyphen.
Context: ...tton If true, displays a button in the upper left corner of the app bar. When clicked, bl...

(TOP_LEFT_CORNER)


[uncategorized] ~64-~64: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...mally this button will be a left arrow. However if bloom-player is the top level window...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~64-~64: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...t arrow. However if bloom-player is the top level window (i.e. it is not embedded in anot...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)


[uncategorized] ~158-~158: Possible missing comma found.
Context: ...y. ### Running unit tests To run unit tests use yarn test. This will run all `*.t...

(AI_HYDRA_LEO_MISSING_COMMA)

README-advanced.md

[style] ~28-~28: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...is designed to be published using npm so as to be readily available to a variety of cl...

(SO_AS_TO)


[style] ~28-~28: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ... npm so as to be readily available to a variety of clients. The published version includes...

(A_VARIETY_OF)


[grammar] ~28-~28: Probable usage error. Use “and” after ‘both’.
Context: ...cludes both dist/bloomPlayer-HASH.js, as well as some mp3 files used by activities.

W...

(BOTH_AS_WELL_AS)

🪛 Markdownlint (0.37.0)
README.md

109-109: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)

🪛 Biome (1.9.4)
src/navigation.ts

[error] 44-45: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 46-47: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/bloom-player-core.tsx

[error] 1894-1894: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (23)
public/testBooks/multibook-target1/basePage.css (1)

1-1304: Skipping CSS review as requested

As per your comment "we don't want to review html or css in this pr", I'll skip reviewing this CSS file. Consider configuring path filters in your CodeRabbit configuration to automatically exclude HTML/CSS files from future reviews.

public/testBooks/multibook-index/basePage.css (1)

1-1304: Overall assessment: Well-structured and production-ready

The CSS codebase demonstrates good practices with:

  • Effective use of modern CSS features (variables, calc, flexbox)
  • Clear organization of styles by component and functionality
  • Detailed comments explaining complex calculations
  • Consistent naming conventions

The suggested improvements are primarily for maintainability and do not impact functionality.

public/testBooks/multibook-index/Basic Book.css (1)

65-87: Fix typo in class name 'nospecidalmovement'

The class name contains a typo: 'nospecidalmovement' should be 'nospecialmovement'.

.storybook/main.ts (3)

61-65: ⚠️ Potential issue

Fix potential override of addons configuration.

Setting addons: ["@storybook/addon-interactions"] overwrites the existing addons array defined earlier.

 return {
     ...config,
     server: { ...config.server, proxy: updatedProxy },
-    addons: ["@storybook/addon-interactions"],
+    addons: [...(config.addons || []), "@storybook/addon-interactions"],
 };

38-50: ⚠️ Potential issue

Add error handling for unknown book IDs.

The rewrite function should handle cases where the book ID is not found in the mapping.

 rewrite: (path) => {
     const bookId = path.split("/")[2];
     const bookName = idToBookName[bookId];
+    if (!bookName) {
+        console.error(`Unknown book ID: ${bookId}`);
+        return path;
+    }
     const rewrittenPath = path.replace(
         `/book/${bookId}`,
         `testBooks/${bookName}`,
     );
     return rewrittenPath;
 },

Likely invalid or redundant comment.


10-12: LGTM! Note the build requirement.

The static directory configuration is well-documented. Make sure to run yarn buildForStorybook when working with iframe stories.

Let's verify if the build script exists:

✅ Verification successful

Configuration is correct and necessary for iframe-based stories

The setup is verified and appropriate:

  • The buildForStorybook script exists and runs vite build --watch --mode development
  • The dist directory is properly gitignored
  • Multiple stories and components use iframes (notably src/stories/BloomPlayerIframe.tsx and several story files)
  • The static directory configuration is necessary for these iframe-based stories to function correctly
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the buildForStorybook script exists in package.json
jq '.scripts | has("buildForStorybook")' package.json

Length of output: 60


Script:

#!/bin/bash
# Let's check what the buildForStorybook script actually does
jq -r '.scripts.buildForStorybook' package.json

# Also check if the dist directory is mentioned in .gitignore
grep -l "dist" .gitignore

# Check if there are any stories using iframes
rg -l "iframe" "stories/"

Length of output: 200


Script:

#!/bin/bash
# Let's check where the stories are located (they might be in src/)
fd -t f "stories.tsx" -t f "stories.ts"

# Also check if there are any iframe references in any tsx/ts files
rg -l "iframe" -g "*.{tsx,ts}"

Length of output: 576

public/testBooks/multibook-index/meta.json (2)

1-1: Review security implications of exposed IDs

The bookInstanceId and bookLineage contain UUIDs that might be sensitive. Consider:

  1. Whether these IDs should be exposed in public metadata
  2. If they're used in any security-critical operations

1-1: Verify required metadata fields

Several critical metadata fields are empty or null:

  • languages array is empty but language-display-names contains English
  • copyright, author, and publisher are null
  • tags and features arrays are empty

These fields might be required for proper book indexing and discovery.

src/navigation.ts (1)

44-47: Simplify attribute access using optional chaining

You can simplify the attribute access by using optional chaining, improving readability.

Apply this diff to refactor the code:

 const href: string =
-    (linkElement.attributes["href"] &&
-        linkElement.attributes["href"].nodeValue) ||
-    (linkElement.attributes["data-href"] &&
-        linkElement.attributes["data-href"].nodeValue);
+    linkElement.attributes["href"]?.nodeValue ||
+    linkElement.attributes["data-href"]?.nodeValue;
🧰 Tools
🪛 Biome (1.9.4)

[error] 44-45: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 46-47: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/navigation.test.ts (2)

87-105: Mock cleanup might not occur if test fails.

The window.open mock cleanup might not occur if the test fails before reaching the cleanup line.


107-134: LGTM! Comprehensive test coverage for multiple back navigation steps.

The test thoroughly validates the navigation stack behavior with multiple steps and different scenarios.

README.md (1)

102-130: LGTM! Clear and comprehensive multi-book support documentation.

The section effectively explains:

  • Purpose and context of book linking
  • Instance ID concept and usage
  • Step-by-step implementation guide
  • Performance considerations
🧰 Tools
🪛 LanguageTool

[formatting] ~106-~106: If the ‘because’ clause is essential to the meaning, do not use a comma before the clause.
Context: ...r. However, Bloom Player needs your help, because it does not have a way to know what the...

(COMMA_BEFORE_BECAUSE)

🪛 Markdownlint (0.37.0)

109-109: Expected: indented; Actual: fenced
Code block style

(MD046, code-block-style)

public/testBooks/multibook-target1/Basic Book.css (1)

1-348: Skipping CSS review as requested.

As per previous feedback, HTML and CSS reviews are out of scope for this PR.

public/testBooks/multibook-target1/appearance.css (2)

136-137: ⚠️ Potential issue

Remove duplicate selector.

The .LegalLandscape selector appears twice in the list.

 .LetterLandscape,
 .LetterPortrait,
-.LegalLandscape,
 .LegalLandscape {

Likely invalid or redundant comment.


201-201: Verify page number hiding approach.

The comment "review will this work to hide it?" suggests uncertainty about the approach to hide page numbers using font-size: 0px. Consider using display: none or visibility: hidden for more explicit hiding.

✅ Verification successful

Let me search for more context about how these CSS variables are used.


Using font-size: 0px is a valid approach for hiding page numbers.

Looking at the codebase, the page number visibility is controlled through multiple coordinated CSS variables:

  1. --pageNumber-font-size: 0px effectively hides the text content
  2. --pageNumber-show-multiplicand: 0 removes extra spacing
  3. --pageNumber-extra-height: 0mm eliminates additional height

This approach is already being used consistently in both multibook-target1 and multibook-index themes. While display: none could also work, the current solution is valid as it:

  • Maintains the element's positioning in the layout
  • Properly handles spacing through the multiplicand variables
  • Integrates well with the existing CSS variable system
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there are any other page number hiding approaches in the codebase.

# Search for page number hiding patterns
rg -A 2 'pageNumber.*hide|hide.*pageNumber'

Length of output: 756


Script:

#!/bin/bash
# Search for usage of pageNumber CSS variables and related styles
rg -A 3 'pageNumber|\.pagenumber' --type css

Length of output: 26357

src/controlBar.tsx (1)

50-54: LGTM: Well-defined enum for back button states.

The BackButtonState enum clearly defines the possible states for the back button, making the code more maintainable and type-safe.

src/bloom-player-core.tsx (4)

2489-2495: Handle potential null value when accessing page ID

The id attribute may be null. Consider adding error handling to avoid potential runtime errors.


409-434: LGTM: Clean navigation implementation

The navigation implementation is well-structured:

  • Clear separation of concerns with external navigation module
  • Proper state management for book URL and page tracking
  • Consistent error handling

1655-1696: LGTM: Robust font handling implementation

The font handling implementation is well-designed:

  • Proper URL transformation for font files
  • Good error handling for missing fonts.css
  • Clear documentation of security considerations

2364-2394: Verify if fixInternalHyperlinks functionality is still needed

The fixInternalHyperlinks method is commented out. If this functionality is still needed, consider:

  1. Re-implementing it using the new navigation system
  2. Removing the commented code if it's obsolete
✅ Verification successful

Let me verify if the fixInternalHyperlinks functionality is still needed by checking if there are any internal hyperlinks in the codebase and if there is any alternative implementation.


Let me try different search patterns and file types to check for internal hyperlink handling:


Let me try one more search pattern to look for internal navigation handling:


Based on the search results, I can now provide a definitive response about the commented-out fixInternalHyperlinks method:

Internal hyperlink handling has been moved to the navigation system

The commented-out fixInternalHyperlinks method is obsolete as internal navigation is now handled by a dedicated navigation system in src/navigation.ts. The new system:

  1. Properly handles internal page links through the checkClickForBookOrPageJump function
  2. Maintains navigation state and history through jumpHistory
  3. Uses pageIdToIndexMap to convert page IDs to indices for navigation
  4. Supports both in-book (#pageId) and cross-book (/book/bookId#pageId) navigation

The commented code can be safely removed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there are any internal hyperlinks in the book that need handling

# Look for anchor tags with href starting with #
rg -A 2 "href=\"#" 

# Look for any code that might be handling internal navigation
ast-grep --pattern 'href[^>]*#[^>]*'

Length of output: 131070


Script:

#!/bin/bash
# Look for internal hyperlink handling in the codebase
rg -A 2 "href=\"#" --type ts --type tsx --type js

# Look for any code that might be handling internal navigation
ast-grep --pattern 'slideTo($_, $_)'

# Look for any new implementation of internal hyperlink handling
rg -A 2 "href.*#" --type ts --type tsx --type js

Length of output: 196


Script:

#!/bin/bash
# Look for internal hyperlink handling in the codebase
rg -A 2 "href.*#" 

# Look for any code that might be handling internal navigation
rg -A 2 "slideTo|navigateTo|internalLink" 

# Look for any new implementation of internal hyperlink handling
rg -A 2 "handleLink|linkClick|anchorClick"

Length of output: 92477


Script:

#!/bin/bash
# Look for any code that handles page/slide navigation
rg -A 5 "pageIdToIndexMap|pageId|pageNum|pageIndex" src/

# Look for any code that handles anchor/link clicks
rg -A 5 "onClick|handleClick|clickHandler" src/

# Look for any code that handles navigation state
rg -A 5 "navigationState|currentPage|currentSlide" src/

Length of output: 60292

public/testBooks/multibook-target1/branding.css (3)

55-58: Consider using relative units instead of absolute units for responsiveness.

Using absolute units like cm may not adapt well to different screen sizes and resolutions. Switching to relative units like % can improve the responsiveness of the branding images across various devices.

Apply this diff:

 .outsideBackCover img.branding {
     margin-top: 4px;
-    width: 10cm;
+    width: 100%;
 }

10-13: Verify the specificity of the attribute selector to prevent unintended styling.

Using [data-book*="branding"] may match more elements than intended due to the wildcard. Ensure that this selector targets only the desired elements to avoid unintended styles being applied elsewhere.

Run the following script to check for all elements affected by this selector:

✅ Verification successful

The attribute selector [data-book*="branding"] is consistently used across test books with the same styling pattern

The search results show that this selector is used consistently across multiple test books in the repository, always applying the same flex container styles and image alignment rules. The pattern appears in:

  • branding.css files: Setting flex layout and image styles
  • basePage.css files: Resetting link styles within branding elements

The usage is uniform and intentional across test books, indicating this is a standardized styling approach rather than an overly broad selector. The wildcard selector is appropriate here as it's part of a consistent styling system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all elements with a 'data-book' attribute containing 'branding'

# Test: Search for affected elements in the codebase.

rg '\[data-book\*="branding"\]' -A 5

Length of output: 10475


28-54: 🛠️ Refactor suggestion

Simplify media queries for orientation-specific classes.

The classes for portrait and landscape orientations are listing multiple size-specific classes. Consider using media queries to handle orientation changes more efficiently.

Apply this diff to use media queries:

-.portraitOnly,
-.landscapeOnly {
-    display: none;
-}
-
-.Size6x9Portrait .portraitOnly,
-...
-.A6Portrait .portraitOnly {
-    display: unset;
-}
-
-.Size6x9Landscape .landscapeOnly,
-...
-.A6Landscape .landscapeOnly {
-    display: unset;
-}
+
+@media (orientation: portrait) {
+    .portraitOnly {
+        display: block;
+    }
+}
+
+@media (orientation: landscape) {
+    .landscapeOnly {
+        display: block;
+    }
+}

Likely invalid or redundant comment.

Comment on lines +185 to +186
border: none;
z-index: 1002;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement a z-index management system

The z-index values are hardcoded across different components without a clear system. Consider using CSS variables to manage z-index values consistently.

:root {
+  /* Z-index stack (from highest to lowest) */
+  --z-comical: 1002;
+  --z-video: 1002;
+  --z-widget: 1000;
+  --z-translation: 1002;
}

.bloom-imageContainer .bloom-textOverPicture .bloom-translationGroup {
  border: none;
-  z-index: 1002;
+  z-index: var(--z-translation);
}

.customPage .bloom-videoContainer {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
-  z-index: 1002;
+  z-index: var(--z-video);
}

.customPage .bloom-widgetContainer {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
-  z-index: 1000;
+  z-index: var(--z-widget);
}

.comical-generated {
-  z-index: 1001;
+  z-index: var(--z-comical);
  position: absolute;
  top: 0;
  left: 0;
}

Also applies to: 868-869, 884-885, 966-967

Comment on lines +164 to +334
}
.pictureAndWordPage.QuarterLetterPortrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.QuarterLetterPortrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.QuarterLetterPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.QuarterLetterLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.QuarterLetterLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.QuarterLetterLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.HalfLetterPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.LetterPortrait .bloom-translationGroup {
height: 23%;
}
.pictureAndWordPage.LetterPortrait .bloom-imageContainer {
height: 74%;
}
.pictureAndWordPage.LetterPortrait .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LetterLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.LetterLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.LetterLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LegalPortrait .bloom-translationGroup {
height: 23%;
}
.pictureAndWordPage.LegalPortrait .bloom-imageContainer {
height: 74%;
}
.pictureAndWordPage.LegalPortrait .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.LegalLandscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.LegalLandscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.LegalLandscape .bloom-content1 {
font-size: 600%;
}
.pictureAndWordPage.Cm13Landscape .bloom-translationGroup {
height: 37%;
}
.pictureAndWordPage.Cm13Landscape .bloom-imageContainer {
height: 60%;
}
.pictureAndWordPage.Cm13Landscape .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.USComicPortrait .bloom-translationGroup {
height: 32%;
}
.pictureAndWordPage.USComicPortrait .bloom-imageContainer {
height: 65%;
}
.pictureAndWordPage.USComicPortrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-translationGroup {
height: 35%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-imageContainer {
height: 62%;
}
.pictureAndWordPage.Size6x9Portrait .bloom-content1 {
font-size: 400%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-translationGroup {
height: 42%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-imageContainer {
height: 55%;
}
.pictureAndWordPage.Size6x9Landscape .bloom-content1 {
font-size: 600%;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reduce code duplication in page format styles

There's significant repetition in the styles for different page formats. Consider using CSS custom properties and creating a more maintainable structure.

+ :root {
+   --portrait-translation-height: 35%;
+   --portrait-image-height: 62%;
+   --landscape-translation-height: 42%;
+   --landscape-image-height: 55%;
+   --large-font-size: 600%;
+   --medium-font-size: 400%;
+ }

- .pictureAndWordPage.A6Portrait .bloom-translationGroup {
-   height: 35%;
- }
- .pictureAndWordPage.A6Portrait .bloom-imageContainer {
-   height: 62%;
- }
+ .pictureAndWordPage {
+   &[class*="Portrait"] {
+     .bloom-translationGroup {
+       height: var(--portrait-translation-height);
+     }
+     .bloom-imageContainer {
+       height: var(--portrait-image-height);
+     }
+   }
+   &[class*="Landscape"] {
+     .bloom-translationGroup {
+       height: var(--landscape-translation-height);
+     }
+     .bloom-imageContainer {
+       height: var(--landscape-image-height);
+     }
+   }
+ }

This refactoring would significantly reduce code duplication and make the styles more maintainable. Consider using a CSS preprocessor like SASS/SCSS to better organize these patterns.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +51 to +64
top: calc(13px + 24%);
height: 24%;
}
.bloom-trilingual.imageOnTop .bloom-editable {
height: 24%;
}
.bloom-trilingual.imageOnTop .bloom-content2 {
position: absolute;
top: calc(1.3% + 24% + 24%);
}
.bloom-trilingual.imageOnTop .bloom-content3 {
position: absolute;
bottom: 0;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace magic numbers with CSS variables

The trilingual layout calculations use hard-coded values that could be difficult to maintain. Consider using CSS variables for these values to improve maintainability and consistency.

:root {
+  --trilingual-spacing: 13px;
+  --trilingual-section-height: 24%;
}

.bloom-trilingual.imageOnTop .bloom-imageContainer {
-  top: calc(13px + 24%);
+  top: calc(var(--trilingual-spacing) + var(--trilingual-section-height));
-  height: 24%;
+  height: var(--trilingual-section-height);
}

.bloom-trilingual.imageOnTop .bloom-content2 {
  position: absolute;
-  top: calc(1.3% + 24% + 24%);
+  top: calc(var(--trilingual-spacing) + var(--trilingual-section-height) * 2);
}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +28 to +30
// setup the same proxy that we have in "vite dev" to avoid CORS issues. (THIS IS NOT WORKING)
// Note that it requires that paths to book on BloomLibrary.org start with "s3/" in place of "https://s3.amazonaws.com/"
...proxy,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

⚠️ Potential issue

I have enough context now to provide a final response about the CORS setup issue.

The proxy configuration needs to be fixed for S3 access

The current proxy setup in .storybook/main.ts spreads the proxy configuration from vite.config.ts but doesn't properly handle the S3 proxy rule. Looking at the code:

  1. The S3 proxy rule from vite.config.ts is missing, which should handle /s3 paths
  2. The comment indicates CORS issues with S3 resources aren't being resolved

To fix this, add the S3 proxy rule explicitly:

const updatedProxy = {
    "/s3": {
        target: "https://s3.amazonaws.com",
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/s3/, ""),
    },
    ...proxy,
    // rest of the proxy config
};
🔗 Analysis chain

Address the non-working CORS setup.

The comment indicates that the CORS setup is not working. This should be investigated and fixed rather than leaving it as a known issue.

Let's check for CORS-related configurations:


Let me gather more context about the proxy configuration to better understand the CORS setup.


Let me check the vite configuration function to understand how the proxy is defined.


Let me check the vite configuration in the storybook's main.ts file to understand how the proxy is being imported and used.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CORS-related configurations in the codebase
rg -i "cors" --type ts

Length of output: 136


Script:

#!/bin/bash
# Check the proxy configuration in both vite.config.ts and .storybook/main.ts
echo "=== vite.config.ts ==="
rg -A 10 "proxy.*=" vite.config.ts

echo -e "\n=== .storybook/main.ts ==="
rg -A 10 "proxy.*=" .storybook/main.ts

Length of output: 665


Script:

#!/bin/bash
# Look for viteConfigFn definition and its proxy configuration
echo "=== Searching for viteConfigFn ==="
rg -l "viteConfigFn"

echo -e "\n=== Content of files with viteConfigFn ==="
fd -t f -e ts -e js -x sh -c 'echo "=== {}" && cat {}'

Length of output: 68751


Script:

#!/bin/bash
# Look for the content of .storybook/main.ts
echo "=== Content of .storybook/main.ts ==="
cat .storybook/main.ts

Length of output: 2802

@@ -0,0 +1 @@
{"a11y_NoEssentialInfoByColor":false,"a11y_NoTextIncludedInAnyImages":false,"bookInstanceId":"2e492eb1-bcc5-4b2b-b756-6cda33e1eee4","suitableForMakingShells":false,"suitableForMakingTemplates":false,"suitableForVernacularLibrary":true,"bloomdVersion":0,"experimental":false,"brandingProjectName":"Local-Community","nameLocked":false,"folio":false,"isRtl":false,"title":"multibook-index","allTitles":"{\"en\":\"multibook-index\"}","originalTitle":"multibook-index","BaseUrl":null,"isbn":"","bookLineage":"056B6F11-4A6C-4942-B2BC-8861E62B03B3","license":null,"formatVersion":"2.1","licenseNotes":null,"copyright":null,"credits":"","tags":[],"pageCount":0,"languages":[],"languageDescriptors":null,"summary":null,"allowUploadingToBloomLibrary":true,"draft":false,"bookletMakingIsAppropriate":true,"country":"United States","province":"","district":"","tools":[],"currentTool":"talkingBookTool","toolboxIsOpen":false,"author":null,"publisher":null,"originalPublisher":null,"subjects":null,"hazards":null,"a11yFeatures":null,"a11yLevel":null,"a11yCertifier":null,"readingLevelDescription":null,"typicalAgeRange":null,"features":[],"page-number-style":"Decimal","language-display-names":{"en":"English"},"internetLimits":null,"use-original-copyright":false,"imported-book-source-url":null,"phashOfFirstContentImage":null}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Page count mismatch confirmed in meta.json

The book actually contains 8 pages as shown in index.htm, but meta.json incorrectly shows pageCount: 0. This should be updated to reflect the actual page count.

  • public/testBooks/multibook-index/meta.json: Update pageCount from 0 to 8 to match the actual number of pages found in index.htm.
🔗 Analysis chain

Verify page count accuracy

The pageCount is set to 0, which seems incorrect for a functional book. This might affect navigation functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Look for page counting logic
ast-grep --pattern 'pageCount = $_' 

Length of output: 37


Script:

#!/bin/bash
# Look for files in the same directory to understand book structure
ls -la public/testBooks/multibook-index/

# Check if there are any page files in the directory
find public/testBooks/multibook-index/ -type f -name "*.htm" -o -name "*.html"

# Search for any page-related files or content
find public/testBooks/multibook-index/ -type f

Length of output: 2896


Script:

#!/bin/bash
# Let's examine the index.htm file to count actual pages
cat public/testBooks/multibook-index/index.htm | grep -c 'class="bloom-page'

# Also check if this is a test/sample book
cat public/testBooks/multibook-index/index.htm | head -n 20

Length of output: 674

export function checkClickForBookOrPageJump(
event: any,
currentBookInstanceId: string,
getCurentPageId: () => string,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct typo in parameter name 'getCurentPageId'

There's a typo in the parameter name getCurentPageId. It should be getCurrentPageId for consistency.

Apply this diff to fix the typo:

 export function checkClickForBookOrPageJump(
     event: any,
     currentBookInstanceId: string,
-    getCurentPageId: () => string,
+    getCurrentPageId: () => string,
 ): ILocation {

And update its usage inside the function:

-    const currentPageId = getCurentPageId();
+    const currentPageId = getCurrentPageId();

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +1 to +230
.A4Landscape,
.A4Portrait,
.B5Portrait,
.LetterLandscape,
.LetterPortrait,
.LegalLandscape,
.LegalLandscape {
--page-margin: 15mm;
--page-gutter: 10mm;
}
.HalfLetterPortrait,/* SIL Mexico says use same as A5 */
.HalfLetterLandscape,
.A5Landscape,
.A5Portrait,
.Size6x9Landscape,
.Size6x9Portrait,
.USComicPortrait {
--page-margin: 12mm;
}
.QuarterLetterPortrait,
.QuarterLetterLandscape,
.A6Portrait,
.A6Landscape {
--page-margin: 10mm;
}
.Cm13Landscape {
--page-margin: 5mm;
}
.bloom-page[class*="Device"] {
--page-margin: 10px;
}

.bloom-page[class*="Device"],
.bloomPlayer-page .bloom-page {
/* Deliberately set both of these, which combines with a special device/bloom-player rule
* in basePage.less which sets both left and right margin to auto, and we get
* centered as the default for device/bloom-player pages. (To override this, you need to
* set the margin you don't want to something like "deliberately-invalid".)*/
--pageNumber-right-margin: 0px;
--pageNumber-always-left-margin: 0px;
}

.numberedPage[class*="Device"]
{
/* These page sizes have small margins, so we need extra height on numbered ones.
(Note that this disappears if page numbers are turned off, because --pageNumber-show-multiplicand is 0.) */
--pageNumber-extra-height: 8mm !important;
}


/* We need a small margin (above) for xmatter pages (e.g., Robots Mali credits page,
* especially in landscape, comment in BL-13002).
* But we need more on numbered pages, so we can fit the page number.
* This unfortunately breaks our rule about keeping the specificity at one class so that
* the settings dialog can override. But currently we don't expect to make page margins
* a book setting, so for now we're OK.*/
/*.numberedPage.Device16x9Portrait,
.numberedPage.Device16x9Landscape {
--page-margin-bottom: 45px; /* need room for page number, so not as small as others
}*/

/* classes are doubled in this rule because it needs to beat the one above that sets the
* bottom margin for numbered pages in Device page sizes. This makes it equally specific
* and thus the last one wins. */
.no-margin-page.no-margin-page,
.comic.comic {
--page-margin-top: 0px;
--page-margin-bottom: 0px;
--page-margin-right: 0px;
--page-margin-left: 0px;
--pageNumber-font-size: 0px; /* review will this work to hide it? */
--pageNumber-show-multiplicand: 0; /* no extra space for suppressed page number */
--pageNumber-extra-height: 0mm !important;
}

/*****************************************************************************
* These variables / rules are for xmatter pages.
*/
.bloom-frontMatter, .bloom-backMatter {
--MarginBetweenXMatterBlocks: 2em;
--MarginBetweenXMatterMinorItems: 5px;
--DefaultCoverTitle1FontSize: 25pt;
--DefaultCoverTitle2FontSize: 12pt;
/* Same as our ordinary default, but we have to set it explicitly because of a trick
that copies the DefaultCoverTitle1FontSize to the translationGroup. */
--DefaultCoverTitle3FontSize: 10pt;
}

/* From this book's appearance settings */
.bloom-page {
--cover-title-L1-show: doShow-css-will-ignore-this-and-use-default;
--cover-title-L2-show: doShow-css-will-ignore-this-and-use-default;
--cover-title-L3-show: none;
--cover-topic-show: doShow-css-will-ignore-this-and-use-default;
--cover-languageName-show: doShow-css-will-ignore-this-and-use-default;
--pageNumber-show: doShow-css-will-ignore-this-and-use-default;
--cover-background-color: #d34b5f;
--pageNumber-show-multiplicand: 1;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider reducing CSS duplication.

This file is identical to multibook-target1/appearance.css except for the cover background color (#d34b5f vs #7bdcb5). Consider extracting the common styles into a shared base CSS file and only override the book-specific values.

Suggested approach:

  1. Create a base appearance.css with all common styles
  2. Create book-specific CSS files that only contain overrides:
/* book-specific.css */
.bloom-page {
    --cover-background-color: #d34b5f; /* or #7bdcb5 for the other book */
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants