Applied the dark redesign across homepage, blog, services and contact.#179
Applied the dark redesign across homepage, blog, services and contact.#179AlexSkrypnyk wants to merge 40 commits into
Conversation
… and paragraph theme-flip hook.
…he site-wide signup CTA.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds redesign tokens, component styles, two frontend Drupal behaviors (reveal, stats), many static content templates, deploy hooks to seed dark-themed paragraphs from HTML, theme/footer/banner wiring, and small Drupal configuration edits. ChangesWebsite Redesign Implementation
🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Actionable comments posted: 11
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/modules/custom/do_base/content/blog/demo-article.html`:
- Line 158: The anchor with visible text "parallel execution" is a placeholder
(href="#") and must be updated to a real destination or removed; locate the <a>
element around the text "parallel execution" in the paragraph and either replace
href="#" with the correct URL to the relevant docs/article (e.g., PHPUnit
parallel execution/paratest docs) or remove the <a> tag so the text is plain
content, ensuring the final markup contains no non-functional links.
In `@web/modules/custom/do_base/do_base.deploy.php`:
- Around line 183-193: The current _do_base_set_components(Node $node, string
$dir) deletes all existing field_c_n_components entities before calling
_do_base_html_paragraphs($dir); change the flow so you first call
_do_base_html_paragraphs($dir) and validate its return (non-empty, no errors)
and only then delete the referenced entities and set the field; if the function
returns empty/false, do not delete existing components and instead return/LOG a
warning or leave the node unchanged. Ensure you reference the Node object, the
field name field_c_n_components, and the helper _do_base_html_paragraphs when
implementing this check.
- Around line 48-49: Replace the fragile hard-coded Node::load(1) in
do_base_deploy_homepage() with a UUID-based lookup: retrieve the node storage
via the entity type manager and load the node by its UUID (like the Services
deploy hook does), then handle the case where the lookup returns no result
before using the node; update do_base_deploy_homepage() to use that UUID lookup
instead of Node::load(1).
- Around line 123-138: The code deletes existing paragraph components then
creates a webform and appends HTML paragraphs from
_do_base_html_paragraphs('contact') which can return an empty array; instead,
first compute and validate the new components array (call
_do_base_html_paragraphs('contact') and build $components including the new
Paragraph::create result), ensure the resulting $components contains the
required contact details (i.e. more than just the webform or at least meets
whatever non-empty/required-structure check you use), and only if validation
passes, delete existing referenced entities and set field_c_n_components on
$node and save; update references to the existing logic around
Paragraph::create, $components, _do_base_html_paragraphs, and
$node->set('field_c_n_components') accordingly.
- Around line 204-216: The function _do_base_html_paragraphs should validate
that the content directory exists and is readable before calling glob and should
log/readably handle file read failures to avoid silent data loss; update
_do_base_html_paragraphs to check is_dir($path) and is_readable($path) and if
either check fails call \Drupal::logger('do_base')->error(...) and return an
empty array (or throw a clear exception), ensure glob() is only called after
those checks, and when file_get_contents($file) returns FALSE log the filename
and error via \Drupal::logger('do_base')->warning(...) and skip that file
instead of silently continuing; reference _do_base_set_components in tests or
calling code to ensure callers handle the empty/exceptional result
appropriately.
- Around line 218-225: The paragraph creation in _do_base_html_paragraphs()
currently saves raw file_get_contents() HTML into Paragraph::create(...) with
text format 'full_html', which lacks the filter_html sanitizer; update the
deploy code to either (A) use a restricted text format that includes the
filter_html filter when setting field_c_p_content (replace 'full_html' with the
sanitizing format machine name), or (B) add a deploy-time validation step in
_do_base_html_paragraphs() that parses each do_base/content/**/*.html and
rejects or strips forbidden tags/attributes (e.g., <script>, on* attributes)
before saving; also add a short comment/docs note near
_do_base_html_paragraphs() documenting the trust boundary for these partials so
maintainers know only trusted HTML is allowed.
In `@web/themes/custom/drevops/assets/js/stats-counter.js`:
- Around line 39-41: The early return when IntersectionObserver is unavailable
causes counters to stay at their initial values; before returning from the block
that checks if (!elements.length || !('IntersectionObserver' in window)) in
stats-counter.js, iterate over the collected elements and set each element's
displayed value to its data-target (parse numeric values as needed) so the final
stats are shown when the observer isn't supported; use the same attribute name
(data-target) and the same element collection variable (elements) used elsewhere
in the file to locate and update the nodes.
In `@web/themes/custom/drevops/assets/sass/redesign/_components.scss`:
- Line 159: Several padding declarations use horizontal tokens for vertical
spacing (e.g., the padding line with calc(var(--space-y-10) * 1.25)
var(--space-y-3) var(--space-x-10)); update each affected padding shorthand so
the top and bottom values use the Y-axis tokens instead of X-axis tokens.
Specifically, locate the padding properties at the reported spots (including the
shown line and the other occurrences) and replace any top/bottom uses of
--space-x-* with the equivalent --space-y-* token (or appropriate calc using
--space-y-*) so vertical rhythm uses the Y scale.
- Around line 1671-1712: The reveal transitions and keyframe animations
(.component-reveal, .component-reveal.visible, .component-reveal-d1..d6 and
`@keyframes` heroGlow, scrollPulse, fadeUp, fadeIn) run unconditionally; add a
prefers-reduced-motion: reduce media-query override that disables or minimizes
motion by setting transitions and animations to none (or near-zero duration),
removing transform changes and using direct opacity where needed, and ensure the
delay classes (.component-reveal-d1..d6) are also neutralized inside that media
query so motion-sensitive users won't see the animated transforms or delays.
In `@web/themes/custom/drevops/assets/sass/redesign/_tokens.scss`:
- Line 19: Replace loud block comments using /* ... */ with SCSS single-line
comments starting with // throughout the file to satisfy stylelint
scss/comment-no-loud. Specifically update the comment instances like the
"primary" block comment at _tokens.scss (and the other occurrences listed: lines
corresponding to 32, 45, 58, 71, 84, 97, 110, 129, 134, 146, 155, 162, 184, 195,
206, 213, 219, 223, 229, 241, 247, 251, 258, 263, 280, 287, 291, 296) by
converting each /* comment */ into a single-line // comment while preserving the
exact comment text and spacing.
In `@web/themes/custom/drevops/components/03-organisms/footer/footer.scss`:
- Line 41: Replace the legacy max-width media query notation with the
range-context form: locate the media query line containing "`@media` (max-width:
767px)" in footer.scss and change it to the range-context syntax "`@media` (width
<= 767px)"; ensure any matching closing brace remains unchanged so the styles
inside the `@media` block are preserved.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 51f32308-233d-444c-bcbb-755c426a624b
📒 Files selected for processing (34)
config/default/block.block.drevops_signup.ymlconfig/default/core.extension.ymlconfig/default/filter.format.full_html.ymlweb/modules/custom/do_base/content/blog/demo-article.htmlweb/modules/custom/do_base/content/contact/info.htmlweb/modules/custom/do_base/content/homepage/01-services.htmlweb/modules/custom/do_base/content/homepage/02-stats.htmlweb/modules/custom/do_base/content/homepage/03-trust.htmlweb/modules/custom/do_base/content/homepage/04-why.htmlweb/modules/custom/do_base/content/homepage/05-process.htmlweb/modules/custom/do_base/content/homepage/06-contact.htmlweb/modules/custom/do_base/content/services/01-detail.htmlweb/modules/custom/do_base/content/services/02-approach.htmlweb/modules/custom/do_base/content/services/03-cta.htmlweb/modules/custom/do_base/do_base.deploy.phpweb/modules/custom/do_base/do_base.info.ymlweb/themes/custom/drevops/assets/js/reveal.jsweb/themes/custom/drevops/assets/js/stats-counter.jsweb/themes/custom/drevops/assets/sass/redesign/_buttons.scssweb/themes/custom/drevops/assets/sass/redesign/_components.scssweb/themes/custom/drevops/assets/sass/redesign/_extra.scssweb/themes/custom/drevops/assets/sass/redesign/_tokens.scssweb/themes/custom/drevops/assets/sass/theme.scssweb/themes/custom/drevops/components/03-organisms/banner/banner.scssweb/themes/custom/drevops/components/03-organisms/footer/footer.component.ymlweb/themes/custom/drevops/components/03-organisms/footer/footer.scssweb/themes/custom/drevops/components/03-organisms/footer/footer.twigweb/themes/custom/drevops/components/04-templates/page/page.twigweb/themes/custom/drevops/components/variables.base.scssweb/themes/custom/drevops/components/variables.components.scssweb/themes/custom/drevops/drevops.info.ymlweb/themes/custom/drevops/drevops.libraries.ymlweb/themes/custom/drevops/includes/banner.incweb/themes/custom/drevops/includes/page.inc
| // step 11 = near-black. The brand base colour sits near step 9. | ||
| // ══════════════════════════════════════════════════════════════ | ||
| :root { | ||
| /* primary */ |
There was a problem hiding this comment.
Replace loud block comments with SCSS single-line comments to satisfy linting.
Stylelint is flagging these /* ... */ comments (scss/comment-no-loud). Convert them to // comments to unblock lint checks (for example, Line 19 and the same pattern throughout this file).
Proposed change pattern
- /* primary */
+ // primaryAlso applies to: 32-32, 45-45, 58-58, 71-71, 84-84, 97-97, 110-110, 129-129, 134-134, 146-146, 155-155, 162-162, 184-184, 195-195, 206-206, 213-213, 219-219, 223-223, 229-229, 241-241, 247-247, 251-251, 258-258, 263-263, 280-280, 287-287, 291-291, 296-296
🧰 Tools
🪛 Stylelint (17.12.0)
[error] 19-19: Expected // for comments instead of /* (scss/comment-no-loud)
(scss/comment-no-loud)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/themes/custom/drevops/assets/sass/redesign/_tokens.scss` at line 19,
Replace loud block comments using /* ... */ with SCSS single-line comments
starting with // throughout the file to satisfy stylelint scss/comment-no-loud.
Specifically update the comment instances like the "primary" block comment at
_tokens.scss (and the other occurrences listed: lines corresponding to 32, 45,
58, 71, 84, 97, 110, 129, 134, 146, 155, 162, 184, 195, 206, 213, 219, 223, 229,
241, 247, 251, 258, 263, 280, 287, 291, 296) by converting each /* comment */
into a single-line // comment while preserving the exact comment text and
spacing.
Source: Linters/SAST tools
There was a problem hiding this comment.
These comments are ported verbatim from the design source. The partials under assets/sass/redesign are intentionally outside the theme stylelint scope, so the comment style is preserved for traceability back to the design.
There was a problem hiding this comment.
@AlexSkrypnyk, understood — makes sense to keep the verbatim comment style for design-source traceability. I'll note that for future reviews.
✏️ Learnings added
Learnt from: AlexSkrypnyk
Repo: drevops/website PR: 179
File: web/themes/custom/drevops/assets/sass/redesign/_tokens.scss:19-19
Timestamp: 2026-06-09T06:26:57.430Z
Learning: In the `drevops` theme (Drupal 11 / CivicTheme), the SCSS partials under `web/themes/custom/drevops/assets/sass/redesign/` are intentionally outside the theme's Stylelint scope. Block-style `/* */` comments in those files are preserved verbatim from the design source for traceability back to the original design variables, so `scss/comment-no-loud` violations there should not be flagged.
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.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/behat/features/contact.feature`:
- Line 13: The step `And I should see "Contact"` is too broad and may match
unrelated text; scope it to the contact webform container instead. Change the
Behat step in the feature to assert the title within the contact webform element
(e.g. use a step like `And I should see "Contact" within
"[data-webform-id='contact']"` or within the webform CSS class such as
`.webform-submission-form`), referencing the contact webform defined in
config/default/webform.webform.contact.yml and the deployment that adds the
civictheme_webform via do_base_deploy_contact() so the check is limited to the
actual webform container.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: cc6df3a2-ca14-4f77-8d4f-14bc8d7c8ec1
📒 Files selected for processing (1)
tests/behat/features/contact.feature
| When I go to "/contact" | ||
| Then I should see the heading Contact | ||
| Then I should see the heading "Let's talk about your platform." | ||
| And I should see "Contact" |
There was a problem hiding this comment.
The assertion verifies the contact webform title Contact renders on the page, which passes. The only Contact heading on the page is the webform title, so the page-level check is unambiguous and kept for simplicity.
…ont page from config, added reduced-motion and stats fallbacks.
| When I go to "/contact" | ||
| Then I should see the heading Contact | ||
| Then I should see the heading "Let's talk about your platform." | ||
| And I should see "Contact" |
There was a problem hiding this comment.
The assertion verifies the contact webform title Contact renders on the page, which passes. The only Contact heading on the page is the webform title, so the page-level check is unambiguous and kept for simplicity.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/modules/custom/do_base/do_base.deploy.php (1)
129-140:⚠️ Potential issue | 🟠 MajorPrevent contact page component data loss if replacement webform paragraph save fails.
do_base_deploy_contact()deletes existingfield_c_n_componentsentities before creating/saving the replacement$webform; if$webform->save()fails/throws, the existing components are already gone and$node->save()won’t run. Build/save the replacement first, then delete old components and set the field.Suggested fix
- foreach ($node->get('field_c_n_components')->referencedEntities() as $existing) { - $existing->delete(); - } - $webform = Paragraph::create([ 'type' => 'civictheme_webform', 'field_c_p_theme' => 'dark', 'field_c_p_webform' => 'contact', ]); $webform->save(); $components = [$webform, ...$details]; + + foreach ($node->get('field_c_n_components')->referencedEntities() as $existing) { + $existing->delete(); + } + $node->set('field_c_n_components', $components);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/modules/custom/do_base/do_base.deploy.php` around lines 129 - 140, In do_base_deploy_contact(), avoid deleting existing field_c_n_components before creating the replacement: first construct and save the new Paragraph ($webform) and verify save succeeded, then delete each existing referenced entity ($existing) from $node->get('field_c_n_components')->referencedEntities(), build the $components array (with the new $webform and $details) and assign it to the node field, and finally call $node->save(); this ensures existing components are preserved if $webform->save() fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/modules/custom/do_base/do_base.deploy.php`:
- Around line 198-203: In _do_base_set_components() avoid deleting referenced
paragraph entities before the node's new component references are persisted;
instead set the new references via $node->set('field_c_n_components',
$components) and call $node->save() to persist the node first, then iterate over
the old referenced entities and call $existing->delete(); alternatively
implement a transactional/rollback strategy around creating paragraphs, setting
the field, saving the node, and deleting old paragraphs so the operation is
atomic and cannot leave dangling references.
---
Outside diff comments:
In `@web/modules/custom/do_base/do_base.deploy.php`:
- Around line 129-140: In do_base_deploy_contact(), avoid deleting existing
field_c_n_components before creating the replacement: first construct and save
the new Paragraph ($webform) and verify save succeeded, then delete each
existing referenced entity ($existing) from
$node->get('field_c_n_components')->referencedEntities(), build the $components
array (with the new $webform and $details) and assign it to the node field, and
finally call $node->save(); this ensures existing components are preserved if
$webform->save() fails.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7778c0fd-16e9-4a79-93d1-e2f0a1074f6b
📒 Files selected for processing (4)
web/modules/custom/do_base/content/blog/demo-article.htmlweb/modules/custom/do_base/do_base.deploy.phpweb/themes/custom/drevops/assets/js/stats-counter.jsweb/themes/custom/drevops/assets/sass/redesign/_extra.scss
This comment has been minimized.
This comment has been minimized.
…on backgrounds and minimal nav styling.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/modules/custom/do_base/do_base.deploy.php (2)
141-154:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winContact component replacement is non-atomic and can lose content
Existing components are deleted before the new references are persisted on the node. If anything fails before
Line 154save completes, the node can be left with deleted references and the new paragraphs orphaned.Persist new references first, then delete old references (or wrap the whole sequence in a transaction).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/modules/custom/do_base/do_base.deploy.php` around lines 141 - 154, The current flow deletes existing paragraph entities via the $node->get('field_c_n_components')->referencedEntities() loop before persisting the new Paragraph (Paragraph::create / $webform->save()) and updating the node ($node->set / $node->save()), which risks leaving the node with missing references if something fails; change the sequence so you first create and save the new Paragraphs (e.g., using Paragraph::create and $webform->save()), update the node's field with the new references ($node->set('field_c_n_components', ...)) and save the node ($node->save()), and only after that delete the old referenced entities ($existing->delete()), or alternatively wrap the create/save/delete sequence in a transaction so the entire operation is atomic.
50-52:⚠️ Potential issue | 🟠 Major | ⚡ Quick winResolve aliased front-page paths before parsing node ID
This only works when
page.frontis already/node/{id}. If it is configured as an alias (for example/home), homepage rebuild is skipped incorrectly.Proposed fix
- $front = (string) \Drupal::config('system.site')->get('page.front'); - $node = preg_match('#^/node/(\d+)$#', $front, $matches) ? Node::load((int) $matches[1]) : NULL; + $front = (string) \Drupal::config('system.site')->get('page.front'); + $internal_path = \Drupal::service('path_alias.manager')->getPathByAlias($front); + $node = preg_match('#^/node/(\d+)$#', $internal_path, $matches) + ? Node::load((int) $matches[1]) + : NULL;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/modules/custom/do_base/do_base.deploy.php` around lines 50 - 52, The code reads the raw page.front value and only matches literal /node/{id}; update the logic to resolve aliases first using Drupal's path alias service (e.g. \Drupal::service('path_alias.manager') or \Drupal::service('path.alias_manager')->getPathByAlias) to get the internal path, then parse that resolved path for ^/node/(\d+)$ and call Node::load((int)$matches[1]) as before; replace the current direct use of \Drupal::config('system.site')->get('page.front') with alias resolution before preg_match so aliased front pages (like /home) correctly map to the node ID.
♻️ Duplicate comments (1)
web/modules/custom/do_base/do_base.deploy.php (1)
210-215:⚠️ Potential issue | 🔴 Critical | ⚡ Quick win
_do_base_set_components()still deletes old references before node saveThis is the same unresolved delete-before-persist risk previously flagged: old paragraphs are removed before the caller saves the updated node, so a failed save can leave dangling references/data loss.
Safer sequence
function _do_base_set_components(Node $node, string $dir): void { if (!$node->hasField('field_c_n_components')) { return; } $components = _do_base_html_paragraphs($dir); + $old_components = $node->get('field_c_n_components')->referencedEntities(); - foreach ($node->get('field_c_n_components')->referencedEntities() as $existing) { - $existing->delete(); - } - $node->set('field_c_n_components', $components); + $node->save(); + + foreach ($old_components as $existing) { + $existing->delete(); + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/modules/custom/do_base/do_base.deploy.php` around lines 210 - 215, The _do_base_set_components() function currently deletes existing paragraph entities via iterating referencedEntities() on $node->get('field_c_n_components') before the node is saved, which risks data loss on failed saves; change the sequence so you first record the existing referenced entity IDs, set the node's 'field_c_n_components' to $components (replacing references) and let the caller save the node, then after a successful save delete only the previously-recorded paragraph entities that are no longer referenced; in short: do not call delete() on $existing before persistence — collect IDs, replace the field on $node, and perform deletions only post-save (or return the IDs so the caller can delete them after save).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/modules/custom/do_base/do_base.deploy.php`:
- Around line 84-89: The banner cleanup in _do_base_clear_banner() currently
deletes referenced paragraph entities immediately (using
$node->get($field)->referencedEntities() and $existing->delete()) before the
node is saved, which can leave dangling references if the save fails; change the
flow to capture the old referenced entities into a temporary array, set or stage
the new value on the node (e.g. $node->set($field, []) or assign the new
references), call $node->save() to persist the pointer changes, and only after a
successful save loop over the previously captured $oldReferences to delete each
$existing; update the function to follow this "stage -> save node -> delete old
entities" pattern.
In `@web/themes/custom/drevops/assets/sass/redesign/_extra.scss`:
- Around line 33-49: The selector .ct-basic-content:has(section) is too broad
and can remove layout constraints on non-redesign pages; narrow it to target
only redesign markup by changing the selector to require the redesign section
marker (e.g., use .ct-basic-content:has(.component-section) or
.ct-basic-content.component-section:has(section)) so the contained rules for
.container, .row and [class*='col-'] only apply to redesign sections; update the
selector in _extra.scss accordingly.
---
Outside diff comments:
In `@web/modules/custom/do_base/do_base.deploy.php`:
- Around line 141-154: The current flow deletes existing paragraph entities via
the $node->get('field_c_n_components')->referencedEntities() loop before
persisting the new Paragraph (Paragraph::create / $webform->save()) and updating
the node ($node->set / $node->save()), which risks leaving the node with missing
references if something fails; change the sequence so you first create and save
the new Paragraphs (e.g., using Paragraph::create and $webform->save()), update
the node's field with the new references ($node->set('field_c_n_components',
...)) and save the node ($node->save()), and only after that delete the old
referenced entities ($existing->delete()), or alternatively wrap the
create/save/delete sequence in a transaction so the entire operation is atomic.
- Around line 50-52: The code reads the raw page.front value and only matches
literal /node/{id}; update the logic to resolve aliases first using Drupal's
path alias service (e.g. \Drupal::service('path_alias.manager') or
\Drupal::service('path.alias_manager')->getPathByAlias) to get the internal
path, then parse that resolved path for ^/node/(\d+)$ and call
Node::load((int)$matches[1]) as before; replace the current direct use of
\Drupal::config('system.site')->get('page.front') with alias resolution before
preg_match so aliased front pages (like /home) correctly map to the node ID.
---
Duplicate comments:
In `@web/modules/custom/do_base/do_base.deploy.php`:
- Around line 210-215: The _do_base_set_components() function currently deletes
existing paragraph entities via iterating referencedEntities() on
$node->get('field_c_n_components') before the node is saved, which risks data
loss on failed saves; change the sequence so you first record the existing
referenced entity IDs, set the node's 'field_c_n_components' to $components
(replacing references) and let the caller save the node, then after a successful
save delete only the previously-recorded paragraph entities that are no longer
referenced; in short: do not call delete() on $existing before persistence —
collect IDs, replace the field on $node, and perform deletions only post-save
(or return the IDs so the caller can delete them after save).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 36621c92-db3b-4157-97bf-4cfc8a9df18a
📒 Files selected for processing (9)
web/modules/custom/do_base/content/contact/00-hero.htmlweb/modules/custom/do_base/content/homepage/00-hero.htmlweb/modules/custom/do_base/content/homepage/01-services.htmlweb/modules/custom/do_base/content/homepage/05-process.htmlweb/modules/custom/do_base/content/services/00-hero.htmlweb/modules/custom/do_base/content/services/01-detail.htmlweb/modules/custom/do_base/do_base.deploy.phpweb/themes/custom/drevops/assets/sass/redesign/_extra.scssweb/themes/custom/drevops/components/variables.base.scss
This comment has been minimized.
This comment has been minimized.
…scoped the container reset to redesign sections.
This comment has been minimized.
This comment has been minimized.
The hero was washed out because the CivicTheme banner surface sits lighter than the design's deep-navy canvas. The banner inner is now transparent so the page background shows through, and the headline accent word renders in the design's coral - the banner preprocess re-reads the raw title (CivicTheme strips tags from string fields) so the accent markup survives. The services promo 'What's included' label now uses the coral accent too. The homepage 'The essentials' figures are now a dedicated do_fact_card paragraph type (a large figure above a label) rendered through a new drevops:fact-card component and referenced from the manual list, replacing the stat snippets. They lay out as a bordered grid on the subtle surface.
This comment has been minimized.
This comment has been minimized.
CivicTheme's responsive navigation rules were not reaching the compiled theme CSS, so the horizontal desktop menu and the hamburger trigger both showed at every width. Restored the design's behaviour - a horizontal menu on desktop and a hamburger on mobile - switching at the 768px desktop-menu breakpoint.
This comment has been minimized.
This comment has been minimized.
Added a 'field_do_eyebrow' field to the manual list so each section can carry the design's small coral category label (What we do, The essentials, Who we work with, How we work) above its title. The manual list template renders it, and eyebrow-only sections leave the title empty. The trust grid used CivicTheme's four-column flex layout, where the content-box snippets overflowed and overlapped. It now uses the design's clean CSS grid with border-box cells - four columns with a gap, two on mobile. The homepage CTA email rendered as a CivicTheme external button (new-window target, arrow, 'opens in a new tab' text). It is now a plain large link in the callout body, matching the design's email link.
This comment has been minimized.
This comment has been minimized.
Reworked the homepage copy for v2: a new hero eyebrow and subtitle, reworded service and process descriptions, a new 'AI-assisted delivery' section (a dotted list of three points), refreshed statistics, and the 'Track record' section label. The other pages are unchanged between v1 and v2. Added a 'field_do_suffix' field to the Fact card so a figure can carry a small trailing unit (1 'day', 10 'yrs', 40 '+'), rendered smaller beside the number. Added the hero eyebrow above the headline.
This comment has been minimized.
This comment has been minimized.
Removed the primary-navigation side menu block from the sidebar so the blog post is a single column with no left sidebar, and widened the article measure to the design's 1100px so the content fills the container.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Code coverage (threshold: 80%) Per-class coverage |
Summary
Applied a full dark design system to the DrevOps website (Drupal 11 / CivicTheme) across the homepage, blog listing, blog post, services, and contact pages by enhancing CivicTheme's existing components, not by embedding design HTML into content. The dark palette and the Plus Jakarta Sans / Outfit typefaces are ported into CivicTheme's
--ct-*custom-property system, and every component renders on the dark palette. Each page is assembled by idempotent deploy hooks that populate CivicTheme component fields (banner, manual list, snippet, promo, callout, webform, rich-text content) - no raw markup is stored as content, and thefull_htmlformat is removed. The database can be rebuilt deterministically at any time.Changes
Dark theme foundations (
web/themes/custom/drevops/)components/variables.base.scss/components/variables.components.scss- Replaced the CivicTheme brand and semantic colour maps with the dark design system (deep-navy canvas, cyan interactive accent, coral highlight) and the Plus Jakarta Sans / Outfit type scale, generated into--ct-*custom properties.assets/sass/brand/- The design layer:_tokens.scss(design tokens),_buttons.scss(the.ct-buttonoutline treatment),_content.scss(rich-text typography for the article, contact details and hero subtitle),_lists.scss(the manual-list section treatments and the service-detail promo),_animations.scss(scroll reveal) and_extra.scss(canvas, chrome and navigation), imported viaassets/sass/theme.scss.assets/js/reveal.js- A scroll-reveal behaviour that fades each section component (.ct-list,.ct-promo,.ct-callout) up as it enters the viewport. The hiding class is applied by the script, so sections stay fully visible without JavaScript, without IntersectionObserver, or under reduced-motion.Component enhancements
components/03-organisms/banner/banner.scssandincludes/banner.inc- The hero is the CivicTheme intro banner: a deep-navy canvas with an atmospheric glow (the banner inner is transparent so the page background shows through rather than CivicTheme's lighter surface).banner.incdrops the shared banner block's background image, and re-reads the raw banner title so the design's coral accent word survives (CivicTheme strips tags from string fields).components/02-molecules/fact-card/andtemplates/paragraphs/paragraph--do-fact-card.html.twig- A newdrevops:fact-cardcomponent (a large figure above a label) renders the newdo_fact_cardparagraph type used for the homepage "The essentials" figures, laid out as a bordered grid.includes/snippet.inc- Restores the full snippet summary (CivicTheme trims it to a teaser length) so the homepage service, "why" and process descriptions render in full.includes/paragraphs.incandincludes/manual_list.inc- Map afield_do_stylevalue on a manual list to a.ct-list--style-*modifier (numbered, stat, trust, dotted), so the bespoke sections are styled CSS-only with no stored markup.components/03-organisms/footer/- Minimal dark footer (copyright + contact email). The footer region slots are still rendered when populated, so the block-demo page sees every declared region while the live footer stays minimal.includes/page.inc/includes/sidebar_navigation.inc- Force page, header, footer and sidebar navigation into the dark theme.Deploy hooks (
web/modules/custom/do_base/do_base.deploy.php)Idempotent deploy hooks built on the
drupal_helpersHelperfacade, each staging new components and clearing the banner before deleting the previous paragraphs, so a failed save can never leave a node referencing deleted entities:do_base_deploy_components_dark/do_base_deploy_blocks_dark- Flip every paragraph and block (including list items, the mobile navigation drawer and its trigger) to the dark theme.do_base_deploy_homepage- Banner hero (title, rich-text subtitle, CTA) plus manual lists of snippets (numbered services, stat figures, trust grid, dotted "why", numbered process) and a closing callout.do_base_deploy_services- Banner hero plus three promos (each a rich-text service detail with tagline, description, "what's included" list and price), a dotted "approach" manual list, and a callout.do_base_deploy_contact- Banner hero, the existing contact webform, and the contact details as rich-text content.do_base_deploy_blog_demo- Seeds the demo article with acivictheme_rich_textbody (headings, striped tables, highlighted code blocks, blockquotes and a CTA button).Configuration (
config/default/)field.storage.paragraph.field_do_style.ymlandfield.field.paragraph.civictheme_manual_list.field_do_style.yml- The list-style marker field driving the bespoke manual-list treatments.paragraphs.paragraphs_type.do_fact_card.yml(plus field instances and displays) - The Fact card paragraph type, added to the manual list's allowed list-item bundles.filter.format.full_html.yml/editor.editor.full_html.yml- Removed; all editorial content usescivictheme_rich_text.core.extension.yml- Removeddo_generated_contentandgenerated_content(CI enables them; they are not committed config).block.block.drevops_footer_*- Removed the eight footer-region block placements (site branding, social links, four menus, acknowledgment of country, copyright) so the live footer is minimal by configuration.drevops.settings.yml/block.block.drevops_signup.yml- Dark skip link; disabled the site-wide signup CTA block.Tests (
tests/behat/)behat.feature- Footer-region assertions retained: the block-demo page renders every declared region.contact.feature- Heading assertions updated to the redesigned contact hero.Before / After