Skip to content

[772] fix: prevent content flash when using case studies filtering#213

Merged
VitalyyP merged 17 commits intomainfrom
772-feature/prevent-content-flash
Aug 17, 2025
Merged

[772] fix: prevent content flash when using case studies filtering#213
VitalyyP merged 17 commits intomainfrom
772-feature/prevent-content-flash

Conversation

@VitalyyP
Copy link
Contributor

@VitalyyP VitalyyP commented Aug 12, 2025

  • added loading and loaded CSS classes;
  • apply loading class while case studies are being fetched;
  • switch to loaded class once case studies are fully loaded;

@VitalyyP VitalyyP self-assigned this Aug 12, 2025
@VitalyyP VitalyyP requested a review from killev as a code owner August 12, 2025 12:27
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 12, 2025

Walkthrough

Adds a loading/reveal system across templates, styles, and frontend logic. HTML: add "loading" class and aria-busy to breadcrumb, sf-container, and the case-studies main content, make Barba container namespace dynamic, and add noscript CSS fallbacks for visibility when JS is disabled. SCSS: introduce .loading/.loaded rules with specialized breadcrumb and container variants and remove gap from .cs_content. JS: add revealLoaded(), call it on DOMContentLoaded and in Barba's after hook, consolidate initFilterModal() into that flow, and simplify case-studies detection. Also updates a .cursor submodule pointer. No public API/signature changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • yuramax
  • IhorMasechko
  • Anton-88
  • killev

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 34b4648 and 1a59ad3.

📒 Files selected for processing (1)
  • website/modules/asset/ui/src/index.js (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/modules/asset/ui/src/index.js
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 772-feature/prevent-content-flash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@github-actions
Copy link

github-actions bot commented Aug 12, 2025

🔍 Vulnerabilities of apostrophe-cms:test

📦 Image Reference apostrophe-cms:test
digestsha256:a56c04b7a020726791ca23314a98f742eff043614f411164d6c3365aa6a42b64
vulnerabilitiescritical: 1 high: 4 medium: 0 low: 0
platformlinux/amd64
size291 MB
packages984
📦 Base Image node:23-alpine
also known as
  • 23-alpine3.22
  • 23.11-alpine
  • 23.11-alpine3.22
  • 23.11.1-alpine
  • 23.11.1-alpine3.22
digestsha256:b9d38d589853406ff0d4364f21969840c3e0397087643aef8eede40edbb6c7cd
vulnerabilitiescritical: 0 high: 0 medium: 1 low: 1
critical: 1 high: 0 medium: 0 low: 0 form-data 4.0.2 (npm)

pkg:npm/form-data@4.0.2

critical 9.4: CVE--2025--7783 Use of Insufficiently Random Values

Affected range>=4.0.0
<4.0.4
Fixed version4.0.4
CVSS Score9.4
CVSS VectorCVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
EPSS Score0.022%
EPSS Percentile4th percentile
Description

Summary

form-data uses Math.random() to select a boundary value for multipart form-encoded data. This can lead to a security issue if an attacker:

  1. can observe other values produced by Math.random in the target application, and
  2. can control one field of a request made using form-data

Because the values of Math.random() are pseudo-random and predictable (see: https://blog.securityevaluators.com/hacking-the-javascript-lottery-80cc437e3b7f), an attacker who can observe a few sequential values can determine the state of the PRNG and predict future values, includes those used to generate form-data's boundary value. The allows the attacker to craft a value that contains a boundary value, allowing them to inject additional parameters into the request.

This is largely the same vulnerability as was recently found in undici by parrot409 -- I'm not affiliated with that researcher but want to give credit where credit is due! My PoC is largely based on their work.

Details

The culprit is this line here: https://github.com/form-data/form-data/blob/426ba9ac440f95d1998dac9a5cd8d738043b048f/lib/form_data.js#L347

An attacker who is able to predict the output of Math.random() can predict this boundary value, and craft a payload that contains the boundary value, followed by another, fully attacker-controlled field. This is roughly equivalent to any sort of improper escaping vulnerability, with the caveat that the attacker must find a way to observe other Math.random() values generated by the application to solve for the state of the PRNG. However, Math.random() is used in all sorts of places that might be visible to an attacker (including by form-data itself, if the attacker can arrange for the vulnerable application to make a request to an attacker-controlled server using form-data, such as a user-controlled webhook -- the attacker could observe the boundary values from those requests to observe the Math.random() outputs). A common example would be a x-request-id header added by the server. These sorts of headers are often used for distributed tracing, to correlate errors across the frontend and backend. Math.random() is a fine place to get these sorts of IDs (in fact, opentelemetry uses Math.random for this purpose)

PoC

PoC here: https://github.com/benweissmann/CVE-2025-7783-poc

Instructions are in that repo. It's based on the PoC from https://hackerone.com/reports/2913312 but simplified somewhat; the vulnerable application has a more direct side-channel from which to observe Math.random() values (a separate endpoint that happens to include a randomly-generated request ID).

Impact

For an application to be vulnerable, it must:

  • Use form-data to send data including user-controlled data to some other system. The attacker must be able to do something malicious by adding extra parameters (that were not intended to be user-controlled) to this request. Depending on the target system's handling of repeated parameters, the attacker might be able to overwrite values in addition to appending values (some multipart form handlers deal with repeats by overwriting values instead of representing them as an array)
  • Reveal values of Math.random(). It's easiest if the attacker can observe multiple sequential values, but more complex math could recover the PRNG state to some degree of confidence with non-sequential values.

If an application is vulnerable, this allows an attacker to make arbitrary requests to internal systems.

critical: 0 high: 1 medium: 0 low: 0 linkifyjs 4.2.0 (npm)

pkg:npm/linkifyjs@4.2.0

high 8.8: CVE--2025--8101 Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')

Affected range<4.3.2
Fixed version4.3.2
CVSS Score8.8
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N
EPSS Score0.060%
EPSS Percentile19th percentile
Description

Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') vulnerability in Linkify (linkifyjs) allows XSS Targeting HTML Attributes and Manipulating User-Controlled Variables.This issue affects Linkify: from 4.3.1 before 4.3.2.

critical: 0 high: 1 medium: 0 low: 0 async 0.9.2 (npm)

pkg:npm/async@0.9.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.907%
EPSS Percentile75th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 async 1.5.2 (npm)

pkg:npm/async@1.5.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.907%
EPSS Percentile75th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 connect-multiparty 2.2.0 (npm)

pkg:npm/connect-multiparty@2.2.0

high 7.8: CVE--2022--29623 Unrestricted Upload of File with Dangerous Type

Affected range<=2.2.0
Fixed versionNot Fixed
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.320%
EPSS Percentile54th percentile
Description

An arbitrary file upload vulnerability in the file upload module of Express Connect-Multiparty 2.2.0 allows attackers to execute arbitrary code via a crafted PDF file. NOTE: the Supplier has not verified this vulnerability report.

Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 336cb19 and 9cca755.

📒 Files selected for processing (2)
  • website/modules/asset/ui/src/scss/_base.scss (1 hunks)
  • website/modules/case-studies-page/views/index.html (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
🔇 Additional comments (1)
website/modules/case-studies-page/views/index.html (1)

300-310: ID Uniqueness Verified – No Duplicates Found

A repository-wide ripgrep search for page-main_content returned only the instance in
website/modules/case-studies-page/views/index.html, confirming the ID is unique.
No further changes are needed.

- Add breadcrumbs functionality with hidden/visible classes
- Implement DOM content loading script for breadcrumbs
- Update layout.html to handle breadcrumbs visibility
- Modify case-studies-page to control breadcrumbs display
- Update CSS for better content visibility control
Copy link
Contributor

@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

🧹 Nitpick comments (2)
website/views/layout.html (1)

47-47: Remove empty script tag

This empty tag is noise and may trigger CSP linters. Remove it.

-    <script type="text/javascript"></script>
website/views/fragments/fragments.html (1)

36-61: Add a no-JS fallback to prevent permanently hidden breadcrumbs when scripts don’t run

With CSS-based hiding and inline scripts, users with JS disabled or strict CSP will never see breadcrumbs. Provide a graceful fallback.

Option A (preferred): Use a no-js/js class on and CSS like:

  • HTML: and JS switches it to js on DOMContentLoaded.
  • CSS: .js .breadcrumb.loading { visibility: hidden; opacity: 0; } so in no-js, breadcrumbs remain visible.

Option B (local fallback): Add a noscript override near the breadcrumbs:

<noscript><style>.breadcrumb{visibility: visible !important; opacity: 1 !important;}</style></noscript>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9cca755 and 33a5ae4.

📒 Files selected for processing (5)
  • website/modules/asset/ui/src/scss/_base.scss (1 hunks)
  • website/modules/asset/ui/src/scss/_cases.scss (0 hunks)
  • website/modules/case-studies-page/views/index.html (2 hunks)
  • website/views/fragments/fragments.html (1 hunks)
  • website/views/layout.html (2 hunks)
💤 Files with no reviewable changes (1)
  • website/modules/asset/ui/src/scss/_cases.scss
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/modules/asset/ui/src/scss/_base.scss
  • website/modules/case-studies-page/views/index.html
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: security-scan

Copy link
Contributor

@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

♻️ Duplicate comments (1)
website/views/layout.html (1)

36-36: Align with PR objective: use loading/loaded semantics (not hidden/visible) and set aria-busy

Per PR goals, this should start as a loading state and later switch to loaded. Also add aria-busy to signal assistive tech while content is being prepared.

-      <div class="sf-container hidden">
+      <div class="sf-container loading" aria-busy="true">

Follow-up:

  • Ensure corresponding CSS for .loading/.loaded exists and matches the intended visibility behavior.
  • If this layout applies to all pages, confirm that globally hiding the container until JS runs won’t cause a blank page flash site-wide; you may want to scope this to the case studies pages only.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 38fc583 and 64f7423.

📒 Files selected for processing (1)
  • website/views/layout.html (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: security-scan
  • GitHub Check: unit-tests

Copy link
Contributor

@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

♻️ Duplicate comments (1)
website/views/layout.html (1)

50-65: Refactor reveal logic: target all matches and avoid duplication; clear aria-busy conditionally

Use querySelectorAll to handle multiple breadcrumbs/containers, and centralize this logic in a shared asset (and call it after Barba transitions). This was flagged previously and remains applicable.

Apply this minimal diff here:

-      document.addEventListener('DOMContentLoaded', function () {
-        const breadcrumbs = document.querySelector('.breadcrumb');
-        const container = document.querySelector('.sf-container');
-        if (breadcrumbs) {
-          breadcrumbs.classList.remove('loading');
-          breadcrumbs.classList.add('loaded');
-          breadcrumbs.setAttribute('aria-busy', 'false');
-        }
-        if (container) {
-          container.classList.remove('loading');
-          container.classList.add('loaded');
-          container.setAttribute('aria-busy', 'false');
-        }
-      });
+      document.addEventListener('DOMContentLoaded', function () {
+        document.querySelectorAll('.breadcrumb.loading, .sf-container.loading')
+          .forEach(function (el) {
+            el.classList.remove('loading');
+            el.classList.add('loaded');
+            if (el.hasAttribute('aria-busy')) {
+              el.setAttribute('aria-busy', 'false');
+            }
+          });
+      });

Follow-up (recommended):

  • Extract into a shared JS module and invoke on DOMContentLoaded and Barba hooks (e.g., barba.hooks.after()), so transitions don’t leave elements in the loading state.
🧹 Nitpick comments (2)
website/views/layout.html (2)

40-45: Add a no-JS fallback so content isn’t stuck in “loading” if JS is disabled

If .loading styles hide content, users without JS will never see it. Consider the common no-js/js pattern (default no-js on , then flip to js early), and scope the hiding rule to .js .loading so non-JS environments still show content.

Happy to add:

  • a tiny inline head script to set class="js" on <html>; and
  • a CSS tweak: .js .loading { visibility: hidden; } while leaving .loading visible by default.

48-48: Remove empty script tag

This empty <script type="text/javascript"></script> is unnecessary and can confuse linters or readers.

Apply this diff:

-    <script type="text/javascript"></script>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4fbb879 and b9ad348.

📒 Files selected for processing (5)
  • .cursor/rules/common (1 hunks)
  • website/modules/asset/ui/src/scss/_base.scss (1 hunks)
  • website/modules/case-studies-page/views/index.html (2 hunks)
  • website/views/fragments/fragments.html (1 hunks)
  • website/views/layout.html (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .cursor/rules/common
🚧 Files skipped from review as they are similar to previous changes (3)
  • website/modules/asset/ui/src/scss/_base.scss
  • website/views/fragments/fragments.html
  • website/modules/case-studies-page/views/index.html
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: unit-tests
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: security-scan
🔇 Additional comments (2)
website/views/layout.html (2)

29-37: Confirm intent: disable Barba container when user is authenticated

data-barba="container" is conditionally applied only when not data.user. If authenticated pages should also participate in transitions, this condition will disable them and could lead to inconsistent behavior. If disabling Barba for logged-in users is deliberate (e.g., for editing UI), ignore; otherwise, consider always rendering the container.

Would you like me to propose a guarded pattern (e.g., a site-level flag) instead of coupling it to data.user?


40-45: Good adoption of loading state and aria-busy on the main content container

This aligns with the PR objective and improves a11y during async fetches. Looks solid.

Copy link
Contributor

@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

♻️ Duplicate comments (2)
website/views/layout.html (2)

8-8: Remove literal and tags from this block (invalid HTML structure)

This template extends an outer layout; adding a wrapper inside a block injects invalid markup (body content within head) and breaks the document structure. This was flagged earlier and still applies.

Apply this diff:

-<head>
...
-</head>

Also applies to: 73-73


48-60: Switch reveal logic to loading→loaded (current hidden→visible is inconsistent and breaks the UX)

The template initializes the container with class="loading" (Line 40), but this script targets ".hidden" and toggles to ".visible". As a result, elements remain in the loading state and never become visible as "loaded". Toggle loading→loaded and keep aria-busy in sync.

Apply this diff:

-      document.addEventListener('DOMContentLoaded', function () {
-        document
-          .querySelectorAll('.breadcrumb.hidden, .sf-container.hidden')
-          .forEach(function (el) {
-            el.classList.remove('hidden');
-            el.classList.add('visible');
-            if (el.hasAttribute('aria-busy')) {
-              el.setAttribute('aria-busy', 'false');
-            }
-          });
-      });
+      document.addEventListener('DOMContentLoaded', function () {
+        document
+          .querySelectorAll('.breadcrumb.loading, .sf-container.loading')
+          .forEach(function (el) {
+            el.classList.remove('loading');
+            el.classList.add('loaded');
+            if (el.hasAttribute('aria-busy')) {
+              el.setAttribute('aria-busy', 'false');
+            }
+          });
+      });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b9ad348 and 690b970.

📒 Files selected for processing (3)
  • website/modules/asset/ui/src/scss/_base.scss (1 hunks)
  • website/modules/case-studies-page/views/index.html (2 hunks)
  • website/views/layout.html (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/modules/asset/ui/src/scss/_base.scss
  • website/modules/case-studies-page/views/index.html
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
🔇 Additional comments (2)
website/views/layout.html (2)

20-23: Barba attribute placement: move namespace to the container and avoid hardcoding

Barba expects data-barba="wrapper" on the wrapper and data-barba="container" + data-barba-namespace on the page container. Here, namespace is on the wrapper and hardcoded as "home". Suggest moving namespace to the main element when it acts as the container, and avoid a hardcoded value.

Apply this minimal, consistent change:

-  <div
-    class="bp-wrapper relative"
-    data-barba="wrapper"
-    data-barba-namespace="home"
-  >
+  <div
+    class="bp-wrapper relative"
+    data-barba="wrapper"
+  >

And add the namespace alongside the conditional container attribute:

       id="main"
       {%
       if
       not
       data.user
       %}
-      data-barba="container"
+      data-barba="container"
+      data-barba-namespace="home"
       {%
       endif
       %}

Follow-up:

  • If you have a per-page namespace (preferred), bind it dynamically (e.g., based on data.page or similar) instead of "home".
  • Verify Barba transitions still work as expected after the move.

Also applies to: 29-37


40-45: Confirm global CSS for .loading/.loaded exists

The container starts with class="loading" and relies on .loaded for reveal. Ensure the global stylesheet defines .loading/.loaded behavior (and that legacy .hidden/.visible isn’t relied upon here).

If needed, I can scan the repo and generate a minimal SCSS snippet to define .loading/.loaded to prevent flashes or stuck states. Would you like me to proceed?

Copy link
Contributor

@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

♻️ Duplicate comments (1)
website/views/layout.html (1)

50-62: Centralize and reuse reveal logic; also run after Barba transitions

Inline duplication makes it easy to miss routes or transitions. Move this to a shared UI script and call it on DOMContentLoaded and Barba hooks (e.g., barba.hooks.after).

Example (outside this file, in your UI bundle):

export function revealLoaded() {
  document.querySelectorAll('.breadcrumb.loading, [data-reveal="dom"].loading')
    .forEach(el => {
      el.classList.remove('loading');
      el.classList.add('loaded');
      if (el.hasAttribute('aria-busy')) el.setAttribute('aria-busy', 'false');
    });
}
document.addEventListener('DOMContentLoaded', revealLoaded);
if (window.barba && window.barba.hooks) {
  window.barba.hooks.after(() => revealLoaded());
}
🧹 Nitpick comments (2)
website/views/layout.html (2)

50-50: Nit: drop redundant type="text/javascript" in HTML5

HTML5 defaults to JavaScript. Removing this reduces noise.

Apply this diff:

-  <script type="text/javascript">
+  <script>

64-71: Noscript fallback should force display in case .loading uses display:none

If .loading sets display: none, the current rules won’t make content visible. Add display: block to guarantee visibility without JS.

Apply this diff:

       .breadcrumb.loading,
       .sf-container.loading {
+        display: block !important;
         opacity: 1 !important;
         overflow: visible !important;
         visibility: visible !important;
       }

Optional: If .loading/.loaded are defined differently (e.g., opacity/visibility only), confirm whether display is needed. I can scan SCSS and adjust accordingly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a39528d and 139ec5e.

📒 Files selected for processing (1)
  • website/views/layout.html (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: security-scan
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
🔇 Additional comments (1)
website/views/layout.html (1)

37-39: Breadcrumbs initial "loading" + aria-busy confirmed — no change required

Confirmed:

  • website/views/fragments/fragments.html — renders:
  • website/views/layout.html — renders a wrapper
    and includes the DOMContentLoaded script that queries '.breadcrumb.loading, .sf-container.loading', swaps loading → loaded and sets aria-busy="false".
  • website/modules/asset/ui/src/scss/_base.scss — contains .loading and .loaded styles.

No fixes needed.

@VitalyyP VitalyyP requested a review from Anton-88 August 14, 2025 22:03
Copy link
Contributor

@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

🧹 Nitpick comments (6)
website/modules/asset/ui/src/scss/_animation.scss (2)

59-76: Good pattern for reveal states; consider reduced-motion support

The base .loading/.loaded pattern looks solid and will prevent FOUC. To respect users who prefer reduced motion, disable the transform/transition when prefers-reduced-motion: reduce is set.

Add this (outside the changed block) to honor OS a11y settings:

@media (prefers-reduced-motion: reduce) {
  .loading,
  .breadcrumb.loading,
  .sf-container.loading {
    transform: none;
    transition: none;
  }
  .loaded,
  .breadcrumb.loaded,
  .sf-container.loaded {
    transition: none;
  }
}

77-87: Visibility doesn’t transition; remove from transition list

visibility is a discrete property and doesn’t animate. Keeping it in the transition list is misleading and can confuse future maintainers. Rely on opacity + transform only.

 .breadcrumb.loading,
 .sf-container.loading {
   opacity: 0 !important;
   visibility: hidden !important;
   transform: translateY(15px);
   transition:
-    opacity 0.5s ease-out,
-    visibility 0.5s ease-out,
-    transform 0.5s ease-out;
+    opacity 0.5s ease-out,
+    transform 0.5s ease-out;
 }
website/modules/asset/ui/src/index.js (3)

100-103: Avoid multiple initializations of initCaseStudiesFilterHandler

This handler is invoked in three places: inside initializeAllComponents(), inside initBarbaPageTransitions’ onReady, and again in export default’s onReady. Unless it’s strictly idempotent, this risks duplicate event listeners/state.

Suggested consolidation:

  • Keep the call within initializeAllComponents() (already run on initial load and in Barba enter).
  • Remove the two extra calls below.
 apos.util.onReady(() => {
-  initCaseStudiesFilterHandler();
   …
 });
-apos.util.onReady(() => {
-  initCaseStudiesFilterHandler();
-});

Please confirm the handler is idempotent or guarded internally; otherwise duplicate listeners may accumulate.

Also applies to: 109-110, 276-278


251-265: FilterModal re-instantiation across navigations — verify teardown

You instantiate a new FilterModal on DOMContentLoaded and again in Barba after. If FilterModal binds any document/window-level listeners, these can stack unless the previous instance is destroyed.

If the class exposes a destroy/teardown, clear it before re-instantiating:

 window.caseStudiesFilterModal = new FilterModal({

Becomes:

+ if (window.caseStudiesFilterModal?.destroy) {
+   window.caseStudiesFilterModal.destroy();
+ }
 window.caseStudiesFilterModal = new FilterModal({

If there’s no destroy, consider adding one to the class or using delegated event listeners to avoid per-instance globals.

Also applies to: 267-267, 199-202


287-293: Condition reads clearer; consider URLSearchParams for robustness

The simplified condition is readable. For robustness (e.g., encoded params, reordering), using URLSearchParams is a bit safer and intent-revealing.

Example:

const params = new URLSearchParams(search);
const hasFilter =
  params.has('industry') ||
  params.has('stack') ||
  params.has('caseStudyType') ||
  hash.includes('filter');

if (pathname.includes('/cases') && hasFilter) {
  
}
website/modules/case-studies-page/views/index.html (1)

305-313: noscript fallback should also reset transform

.loading applies transform: translateY(20px), so without JS the content will remain offset. Add a reset for transform to ensure proper layout for no-JS users.

 <noscript>
   <style>
     #page-main_content {
       opacity: 1 !important;
       overflow: visible !important;
       visibility: visible !important;
+      transform: none !important;
     }
   </style>
 </noscript>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e8bc450 and 7bb6d8a.

📒 Files selected for processing (4)
  • website/modules/asset/ui/src/index.js (4 hunks)
  • website/modules/asset/ui/src/scss/_animation.scss (1 hunks)
  • website/modules/case-studies-page/views/index.html (2 hunks)
  • website/views/layout.html (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/views/layout.html
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-14T09:44:56.398Z
Learnt from: yuramax
PR: speedandfunction/website#84
File: website/modules/case-studies-page/views/index.html:87-90
Timestamp: 2025-05-14T09:44:56.398Z
Learning: For the Case Study cards in website/modules/case-studies-page/views/index.html, the "type" and "industry" fields are temporarily hard-coded with values "Mobile Development" and "Manufacturing" as placeholders. These will be replaced with dynamic data ({{ article.type }} and {{ article.industry }}) in a future task.

Applied to files:

  • website/modules/case-studies-page/views/index.html
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
🔇 Additional comments (4)
website/modules/asset/ui/src/scss/_animation.scss (1)

89-94: LGTM: loaded state overrides are clear and scoped

Using specific selectors with !important here makes sense given existing breadcrumb/container styles. No issues.

website/modules/asset/ui/src/index.js (2)

15-27: Simple, idempotent reveal — good implementation

The selector targets are precise, and flipping aria-busy to false is a good a11y touch. Idempotent by design since it only selects .loading.


198-202: Hooking revealLoaded into Barba after is the right place

This ensures the newly replaced containers become visible promptly after navigation. Nicely done.

website/modules/case-studies-page/views/index.html (1)

9-15: A11y-friendly loading wrapper — good alignment with revealLoaded

Adding loading + aria-busy="true" on #page-main_content aligns with the new reveal flow and communicates state to AT. Looks good.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (2)
website/modules/asset/ui/src/index.js (2)

274-279: Addresses DOMContentLoaded race for revealLoaded

This readyState guard ensures revealLoaded runs even if the script loads after DOMContentLoaded. Nice follow-through.


267-267: Ensure initFilterModal runs even if DOMContentLoaded already fired

If this script loads after DOMContentLoaded, the listener won’t fire and the modal won’t initialize on first load (before any Barba transitions). Guard with readyState.

-document.addEventListener('DOMContentLoaded', initFilterModal);
+if (document.readyState === 'loading') {
+  document.addEventListener('DOMContentLoaded', initFilterModal);
+} else {
+  initFilterModal();
+}
🧹 Nitpick comments (1)
website/modules/asset/ui/src/index.js (1)

291-297: Use URLSearchParams and stricter path check to avoid false positives

includes('/cases') can match “/showcases”, and scanning raw search can mis-detect. Prefer URLSearchParams and a stricter pathname check.

-    const { pathname, search, hash } = window.location;
-    if (
-      pathname.includes('/cases') &&
-      (search.includes('industry') ||
-        search.includes('stack') ||
-        search.includes('caseStudyType') ||
-        hash.includes('filter'))
-    ) {
+    const { pathname, search, hash } = window.location;
+    const params = new URLSearchParams(search);
+    if (
+      (pathname === '/cases' || pathname.startsWith('/cases/')) &&
+      (params.has('industry') ||
+        params.has('stack') ||
+        params.has('caseStudyType') ||
+        hash === '#filter' ||
+        hash.startsWith('#filter='))
+    ) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7bb6d8a and e8cc54c.

📒 Files selected for processing (1)
  • website/modules/asset/ui/src/index.js (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: unit-tests
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: security-scan
🔇 Additional comments (2)
website/modules/asset/ui/src/index.js (2)

15-27: Solid, idempotent revealLoaded implementation

Toggles loading→loaded states cleanly and resets aria-busy to false. This should prevent flashes while remaining a11y-friendly.


198-201: Good placement: reveal before initializing the modal

Calling revealLoaded() in Barba’s after hook (before initFilterModal) ensures the UI is visible when the modal is bound, minimizing flash.

coderabbitai[bot]
coderabbitai bot previously approved these changes Aug 16, 2025
Copy link
Contributor

@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

♻️ Duplicate comments (1)
website/modules/asset/ui/src/index.js (1)

270-275: Good fix: revealLoaded now runs even if the script loads after DOMContentLoaded

This addresses the race noted earlier so content doesn’t remain hidden.

🧹 Nitpick comments (2)
website/modules/asset/ui/src/index.js (2)

15-27: Nit: use classList.replace for clarity and fewer DOM mutations

Slightly cleaner and avoids two separate classList ops.

-      el.classList.remove('loading');
-      el.classList.add('loaded');
+      el.classList.replace('loading', 'loaded');

286-292: Prefer URLSearchParams over substring checks to avoid false positives

Substring checks (e.g., search.includes('industry')) can misfire on similarly named params. Using URLSearchParams keeps it precise.

-    if (
-      pathname.includes('/cases') &&
-      (search.includes('industry') ||
-        search.includes('stack') ||
-        search.includes('caseStudyType') ||
-        hash.includes('filter'))
-    ) {
+    if (
+      pathname.includes('/cases') &&
+      (new URLSearchParams(search).has('industry') ||
+        new URLSearchParams(search).has('stack') ||
+        new URLSearchParams(search).has('caseStudyType') ||
+        hash.includes('filter'))
+    ) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e8cc54c and 34b4648.

📒 Files selected for processing (1)
  • website/modules/asset/ui/src/index.js (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: security-scan

@VitalyyP VitalyyP enabled auto-merge (squash) August 16, 2025 13:38
Copy link
Contributor

@Anton-88 Anton-88 left a comment

Choose a reason for hiding this comment

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

LGTM

@sonarqubecloud
Copy link

@VitalyyP VitalyyP merged commit f907408 into main Aug 17, 2025
12 checks passed
@VitalyyP VitalyyP deleted the 772-feature/prevent-content-flash branch August 17, 2025 11:28
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.

3 participants