[CORE-1701] Phase 3.1: NavBar and Footer Migration to Plain CSS#2917
[CORE-1701] Phase 3.1: NavBar and Footer Migration to Plain CSS#2917RoyEJohnson merged 15 commits intomainfrom
Conversation
967ad4c to
b189207
Compare
This comment was marked as resolved.
This comment was marked as resolved.
1a8cc0c to
f920030
Compare
f920030 to
25173ec
Compare
25173ec to
d9b517b
Compare
d9b517b to
24196db
Compare
This comment was marked as resolved.
This comment was marked as resolved.
343b761 to
aacc5c6
Compare
This comment was marked as resolved.
This comment was marked as resolved.
Summary: All Review Comments Addressed ✅I've successfully addressed all code review feedback from Roy and Copilot. Latest Change (Review #21)Issue: Fix: Removed the CSS variable and used plain CSS value
Complete List of Addressed Review Comments
Migration ComplianceAll changes follow the established patterns from:
CSS Variable Usage Now ConsistentThe PR now correctly applies CSS variables only when:
And uses plain CSS when:
Ready for final review and merge! 🚀 |
- Create NavBar.css with all styled-components converted to plain CSS - Includes fadeIn animation, responsive breakpoints, z-index management - Uses CSS variables for theme values (colors, spacing, z-indices) - Follows PLAIN_CSS_MIGRATION_GUIDE patterns Related to CORE-1701 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Complete the NavBar migration by updating index.tsx to use plain CSS classes and CSS variables instead of styled-components. Changes: - Create constants.ts to export navDesktopHeight, navMobileHeight, and maxNavWidth - Replace all Styled.* components with plain HTML elements + className - Import and use react-aria-components ModalOverlay and Modal directly - Add CSS variable bindings from theme for colors, z-indices, and dimensions - Migrate Redux connect() HOCs to useSelector hooks for: - ConnectedNavigationBar (default export) - ConnectedLoginButton - Import theme and Color for CSS variable values - Import Times component directly instead of through styled wrapper - Import NavBar.css for styles The component now follows the plain CSS migration pattern: - CSS classes defined in NavBar.css - Theme values bound as CSS variables via style prop - Redux hooks instead of connect() HOC - All functionality preserved with improved performance 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changes: - Created Footer.css with all styled-components converted to plain CSS classes - Updated Footer/index.tsx to use plain CSS with className instead of Styled.* components - Migrated social media icons (Facebook, Twitter, Instagram, LinkedIn) to inline SVG - Wrapped icon components with styled() for component selector compatibility - Bound CSS variables from theme for dynamic values (colors, backgrounds) - Preserved complex CSS grid layouts for responsive behavior - Maintained vertical nav toolbar styling with clamp() calculation - Used classNames package for className composition - Preserved all functionality including: - Normal footer with mission, columns, social links - Portal footer variant - Contact dialog integration - Manage cookies links - Responsive breakpoints (37.5em, 37.6em, 60.1em) Migration follows the patterns established in PLAIN_CSS_MIGRATION_GUIDE.md and PLAIN_CSS_MIGRATION_LEARNINGS.md. All CSS variables are set before spreading style props to allow overrides. Note: Tests will be updated in a separate commit per task requirements. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Reordered CSS selectors to ensure proper specificity ordering: - Moved all base link selectors (a) before pseudo-class selectors (:hover, :active, :focus) - Grouped .footer-copyrights and .footer-mission link selectors properly - This fixes the stylelint error where .footer-copyrights a appeared after .footer-mission a:hover/active/focus The rule requires less specific selectors to appear before more specific ones to avoid unexpected CSS cascade behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Restore yarn.lock Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Updated Footer.spec.tsx to work with plain CSS migration:
- Changed test to find button by className='footer-button' instead of styled component
- The test uses findAll() to locate button with matching className and message ID
- This fixes the "Cannot read property 'props' of undefined" error
- The existing test already covers the onClick in PortalColumn2
The test "calls captureOpeningElement when 'Contact Us' is clicked in portal footer"
exercises the Contact Us button in PortalColumn2, which calls:
- captureOpeningElement('contactdialog')
- open() from useContactDialog hook
This provides the coverage that was previously missing when the test was failing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Following the hybrid CSS pattern from PLAIN_CSS_MIGRATION_GUIDE.md, removed CSS variables that were: - Set to hardcoded static values in JSX - Had identical fallback values in CSS - Not derived from theme.ts - Never changed at runtime Removed redundant variables: - --navbar-logo-height-desktop / --navbar-logo-height-mobile - --navbar-overlay-logo-top - --navbar-height-desktop / --navbar-height-mobile - --navbar-max-width Kept theme-derived variables (correct usage): - --navbar-z-index (from theme.zIndex.navbar) - --navbar-bg (from theme.color.neutral.base) - --navbar-padding-desktop/mobile (from theme.padding.page) - --nav-text-color (from theme.color.primary.gray.base) - --mobile-overlay-bg (computed with Color library) - --mobile-overlay-z-index (computed from theme) This makes the code cleaner and follows the migration guide's principle: "CSS variables should be used when values need to be looked up from theme.ts at runtime or require JavaScript computation" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Following the same pattern as NavBar, removed CSS variables that were: - Set to hardcoded static color values in JSX - Had identical fallback values in CSS - Not derived from theme.ts - Never changed at runtime (hardcoded in original styled-components) Removed redundant variables: - --footer-top-bg (was '#424242', now plain CSS) - --footer-bottom-bg (was '#3b3b3b', now plain CSS) These colors were hardcoded in the original styled-components (not from theme), so they should be plain CSS values, not CSS variables. Kept theme-derived variables (correct usage): - --footer-text-color (from theme.color.text.label) - --footer-social-icon-bg (from theme.color.primary.gray.light) - --footer-social-icon-color (computed hex value) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1. Footer.spec.tsx: Use data-testid for test selector robustness - Added data-testid="portal-footer-contact-button" to Contact Us button - Updated test to use findByProps with data-testid instead of fragile .find() logic - Prevents test failures when FormattedMessage structure changes 2. NavBar: Bind layout constants as CSS variables - Import maxNavWidth, navDesktopHeight, navMobileHeight from constants.ts - Bind as CSS variables in navbar-bar-wrapper to prevent drift - Update NavBar.css to reference CSS variables with fallbacks - Ensures single source of truth for layout dimensions used across codebase These changes improve test reliability and maintainability by: - Making tests resilient to DOM structure changes - Preventing CSS/JS constant drift for shared layout values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Update index.tsx Apply Copilot suggestions from code review More Copilot notes Remove window undefined test and revert to optional chaining The test for window being undefined was causing failures because: 1. The original code did NOT handle window being undefined 2. The component legitimately requires window (for addEventListener) 3. The test was breaking other tests by deleting global.window Changes: - Removed "handles portal footer when window is not defined" test - Reverted typeof window check to original window?.location.href pattern - This matches the behavior of the code before migration The Footer component is browser-only and requires window to function. SSR scenarios are not supported by this component's design. Fixes test failures reported in Review 15. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Add test coverage for PortalColumn2 when window is undefined Added test case "handles portal footer when window is not defined" to verify that the Footer component renders correctly in SSR/test environments where window is not defined. This test covers the typeof window !== 'undefined' check on line 491 in Footer/index.tsx, ensuring that the component gracefully handles the absence of the window object without crashing. Addresses Review 13 from RoyEJohnson. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Update Footer.spec.tsx Address Copilot review comments - final round This commit addresses all remaining review comments from Copilot and reviewers: 1. Footer.css: Fixed media query breakpoint from 60.1em to 75.0625em - The original styled-components used theme.breakpoints.desktopBreak (75.0625em) - Using 60.1em would apply the toolbar offset earlier than intended - Updated comment to document both breakpoint sources (theme.ts and constants.ts) 2. Footer/index.tsx: Fixed window reference in PortalColumn2 - Added typeof guard to prevent ReferenceError in SSR/test environments - Changed from window?.location.href to typeof window !== 'undefined' ? window.location.href : undefined - Prevents crashes when window is completely undeclared (not just undefined) 3. NavBar/styled.tsx: Fixed constants duplication - Made styled.tsx re-export constants from constants.ts - Maintains backward compatibility for existing imports - Creates single source of truth in constants.ts 4. NavBar/index.tsx: Removed encodeURIComponent from login link - Reverted to original behavior (raw currentPath without encoding) - Prevents breaking snapshots (/accounts/login?r=/ vs ?r=%2F) - Maintains consistency with other auth links in codebase 5. Footer/index.tsx: Added comprehensive comment for icon wrappers - Explains why icons are wrapped with styled() for component selector compatibility - References PLAIN_CSS_MIGRATION_LEARNINGS.md for pattern documentation All changes verified with syntax checks. Tests cannot run due to missing @openstax/highlighter dependency (environment issue, not related to changes). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Revert lock files Address Copilot and reviewer feedback Fixed the following issues from code review: 1. **Footer.css**: Removed `flex-flow` property from grid layouts - Removed from .footer-top-boxed, .footer-bottom-boxed, .footer-portal-bottom-boxed - flex-flow has no effect on grid layouts and caused confusion 2. **Footer.spec.tsx**: Changed .findAll()[0] to .find() - More deterministic error handling if button is not found - Test will throw clear error instead of undefined access 3. **FooterLinkMessage**: Auto-add noreferrer for external links - When target="_blank", automatically includes "noopener noreferrer" - Prevents reverse-tabnabbing and referrer leakage security issues 4. **OpenKeyboardShortcutsLink**: Removed unnecessary preventDefault() - Button with type="button" has no default action to prevent - Makes handler intent clearer 5. **NavBar**: Consolidated redundant CSS variable assignments - Moved --nav-text-color, --link-hover, --focus-outline-color to parent container - Set once on .navbar-dropdown-overlay instead of multiple children - Reduces duplication and prevents drift during future edits All changes improve code quality, security, and maintainability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Address all code review comments from Copilot and reviewers 1. **Added unit tests for getSafeRelAttribute function** - Exported function for testability - Added comprehensive test coverage for all edge cases - Tests ensure proper rel token normalization and security 2. **Optimized Color computation in MobileDropdown** - Added useMemo to cache Color().alpha().string() result - Reduces render cost by avoiding repeated object allocation - Empty dependency array since theme.color.neutral.base is constant 3. **Replaced hardcoded hex colors with theme constants** - Added linkFocusOutline constant to Links.constants.ts - Imported linkHover and linkFocusOutline in NavBar - Replaced '#0064a0' with linkHover - Replaced '#007297' with linkFocusOutline - Maintains consistency with design system 4. **Fixed URL encoding security issue** - Added encodeURIComponent to currentPath in login URL - Prevents query parameter injection attacks - Properly handles special characters (?, #, &, etc.) 5. **Prevented layout shift in navbar links** - Added transparent border-bottom to default .navbar-link state - Adjusted padding to maintain same total height - On hover/focus, only border color changes (not layout) - Mobile version properly resets to transparent - Improves keyboard navigation experience All changes improve code quality, security, performance, and accessibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Address all remaining code review comments This commit addresses feedback from both Copilot and human reviewers: 1. Footer.css: Added doubled selector specificity to .footer-manage-cookies-flex-link - Matches the pattern used for .footer-manage-cookies-link - Ensures ui-components default styles don't override our styling - Applied to base selector and all pseudo-class variants 2. Footer/index.tsx: Fixed className merging in MissionDiv and CopyrightsDiv - Now properly destructures className prop - Uses classNames() to merge base class with any passed className - Prevents className override from htmlMessage callers 3. Footer/index.tsx: Improved rel attribute normalization - Created getSafeRelAttribute() helper function - Normalizes rel tokens using Set to prevent duplicates - Ensures both 'noopener' and 'noreferrer' are present for target="_blank" - Prevents duplicate tokens like "noopener noreferrer noreferrer" - Extracted as reusable helper per reviewer suggestion 4. NavBar/index.tsx: Optimized useSelector usage - Combined 5 separate useSelector calls into single selector - Added shallowEqual comparison to prevent unnecessary re-renders - Reduces subscription overhead and render churn - Improves performance by only re-rendering when values actually change All changes improve code quality, security, and performance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Remove redundant --footer-text-color CSS variable The --footer-text-color variable was set to a hardcoded constant '#d5d5d5' that never changes and is not derived from theme. Per the CSS migration principles established in this PR, CSS variables should only be used for: 1. Values from theme.ts 2. Computed values 3. Runtime-variable values Since textColor is a static hardcoded value, it belongs in plain CSS. Changes: - Removed textColor constant from Footer/index.tsx - Replaced var(--footer-text-color, #d5d5d5) with #d5d5d5 in Footer.css - Removed all style={{--footer-text-color: textColor}} bindings This makes the code cleaner and follows the hybrid pattern correctly, consistent with earlier cleanup commits (2500e7d, bb3abd5). Addresses review comment from RoyEJohnson in Review #21. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Copilot <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
RoyEJohnson
left a comment
There was a problem hiding this comment.
Look at Footer/index.tsx. It's a pretty big file and handles several disparate tasks. Can you break it up into a few smaller, more focused modules? The social directory/icons seem like a good candidate, and maybe the dialog(s)?
Refactored Footer into Smaller, Focused Modules ✅I've addressed Review #26 by breaking up the large Footer/index.tsx file into smaller, more focused modules. Changes Made (Commit: cbe0ab1)Created Two New Modules:
Refactored
Benefits✅ Improved Organization: Each module has a single, focused responsibility Module Responsibilities
The refactoring maintains all existing functionality while significantly improving code organization. Ready for re-review! 🚀 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Extracted social icons and contact dialog into separate modules as requested in code review to improve maintainability and reduce the size of the main Footer component file. **Changes:** - Created `Footer/SocialIcons.tsx` (194 lines): Social media icons, constants, and SocialDirectory component - Created `Footer/ContactDialog.tsx` (68 lines): ContactDialog component and useContactDialog hook - Refactored `Footer/index.tsx` from 561 to 315 lines (44% reduction) - Maintained backward compatibility by re-exporting ContactDialog and useContactDialog from index.tsx - All existing imports continue to work (no breaking changes) **Benefits:** - Improved code organization and separation of concerns - Each module now has a single, focused responsibility - Easier to navigate and understand the Footer component - Facilitates future maintenance and testing Addresses Review #26 🤖 Generated with [Claude Code](https://claude.com/claude-code) Cleanup Don't export icons Footer is browser-only Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Summary
This PR migrates the NavBar and Footer components from styled-components to plain CSS following the hybrid approach documented in PLAIN_CSS_MIGRATION_GUIDE.md.
Related Jira Ticket: CORE-1701
Migration Approach
Using plain CSS (not CSS Modules) with the hybrid pattern:
✅ Completed Work
NavBar Migration (Commit: cfa4203)
Footer Migration (Commit: 3995ea4)
Components Migrated
NavBar (src/app/components/NavBar/)
Footer (src/app/components/Footer/)
Key Implementation Details
NavBar
Footer
Migration Compliance
Following all patterns from:
Testing
Tests should be run in CI environment. The migration preserves all existing functionality:
See the Testing Guide in CORE-1701 comments for comprehensive manual testing checklist.
Files Changed
Created
src/app/components/NavBar/NavBar.css- NavBar plain CSS (231 lines)src/app/components/NavBar/constants.ts- Extracted constantssrc/app/components/Footer/Footer.css- Footer plain CSS (475 lines)Modified
src/app/components/NavBar/index.tsx- Migrated to plain CSS + hookssrc/app/components/Footer/index.tsx- Migrated to plain CSS + inline SVG iconsRemoved
src/app/components/NavBar/styled.tsx- Replaced with plain CSSsrc/app/components/Footer/styled.tsx- Replaced with plain CSSNotes
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com