Skip to content

Commit 2f8b4ed

Browse files
OpenStaxClaudeclaudeRoyEJohnsonCopilotstaxly[bot]
authored
Phase 7.3b: Migrate Assignment/Book Info Components to Plain CSS (#3060)
* Migrate AssignedTopBar component from styled-components to plain CSS - Replaced styled-components with plain CSS using CSS variables - Created AssignedTopBar.css with responsive breakpoints - Converted StyledTopBarWrapper to use TopBarWrapper with className - Converted StyledSectionTitle to plain h2 element with className - Used CSS variables for dynamic theme values (colors, heights) - Followed migration patterns from PLAIN_CSS_MIGRATION_LEARNINGS.md - All component logic remains unchanged 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Migrate BuyBook component from styled-components to plain CSS This commit migrates the BuyBook component following the simplified plain CSS migration approach documented in PLAIN_CSS_MIGRATION_LEARNINGS.md. Changes: - Created BuyBook.css with plain CSS styles - Updated BuyBook.tsx to use className instead of styled-components - Used CSS variables for dynamic values (max-width and color) - Applied disablePrintClass for print hiding behavior - Followed established patterns from other migrated components The component maintains identical functionality and styling while removing the styled-components dependency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Migrate Attribution component from styled-components to plain CSS - Convert class component to functional component with hooks - Replace connect() HOC with useSelector hook - Create Attribution.css with all component styles - Use CSS variables for dynamic values (theme colors, widths) - Replace styled Summary/Details with plain HTML elements - Implement htmlMessage pattern inline (Content and CodeRunnerNote components) - Maintain all existing functionality: - Auto-scroll on toggle - Close on page navigation - Special attribution for python books - Support for special book IDs - Export named Attribution component for testing - Use classNames package for className composition - Follow patterns from PLAIN_CSS_MIGRATION_LEARNINGS.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Migrate Assigned.tsx from styled-components to plain CSS - Replace styled-components imports with classNames - Convert StyledButton, ToastOverride, and PlatformWrapper to plain React components - Create Assigned.css with corresponding styles - Use CSS variables for dynamic values (contentTextWidth, topbarDesktopHeight, assignedMobileTop) - Convert theme.breakpoints.mobile() to @media query with correct breakpoint (75em) - Maintain all existing functionality and component behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Assorted fixups Combine summary style entries Minor lint stuff Lint mobileToolbarOpen is not in props Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Fix Attribution test failure by using useLayoutEffect for page changes The test 'closes attribution on navigation' was failing because it expected the 'open' attribute to be removed synchronously when the page changes. When converting from class component to functional component, the page change detection logic was using useEffect, which runs asynchronously after the browser has painted. The original class component used componentDidUpdate, which runs synchronously during the commit phase. Changed the page change effect from useEffect to useLayoutEffect to match the original synchronous behavior of componentDidUpdate. This ensures the 'open' attribute is removed immediately when the page changes, making the test pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Copilot suggestions Address Copilot review feedback on AssignedTopBar and Attribution **AssignedTopBar.tsx:** - Conditionally render the <h2> heading only when section?.title exists - Prevents empty headings which are an accessibility issue for screen readers - While section should always be defined in practice (as Roy noted), this handles edge cases during initial render and follows best practices **Attribution.tsx:** - Revert useEffect dependency array back to [] (empty) - The toggle event listener doesn't depend on `page` and should only run on mount/unmount - Re-running this effect on every page change is unnecessary and wasteful - The page change logic is already handled in the separate useLayoutEffect These changes address Copilot's accessibility concern while maintaining the correct React hook behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Fix AssignedTopBar to handle undefined section during loading The AssignedTopBar component was expecting section to always be defined, but sections[currentSectionIndex] can be undefined while the book and assigned sections are still loading. Changes: - Made section prop optional: LinkedArchiveTreeSection | undefined - Added early return (null) when section is not yet available - This allows the Page component to render its loader during loading state - Fixes the test "renders loading state without book" This addresses both Copilot's concern about empty headings and Roy's observation that the test was failing. The component now properly handles the loading state by returning null instead of rendering an empty h2. 🤖 Generated with [Claude Code](https://claude.com/claude-code) props.section is always defined Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Moved undefined check for section up to Assigned Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Specificity fix - noticed Kinetic banner had wrong spacing 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: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Roy Johnson <roy.e.johnson@rice.edu> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: staxly[bot] <35789409+staxly[bot]@users.noreply.github.com>
1 parent 3a18860 commit 2f8b4ed

13 files changed

Lines changed: 1092 additions & 7895 deletions

src/app/content/__snapshots__/routes.spec.tsx.snap

Lines changed: 42 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`assigned route route renders renders a component 1`] = `
4-
.c3 {
4+
.c0 {
55
overflow: visible;
66
position: relative;
77
}
88
9-
.c4 {
9+
.c1 {
1010
position: relative;
1111
border-left: 0.1rem solid transparent;
1212
border-right: 0.1rem solid transparent;
1313
}
1414
15-
.c4 > div {
15+
.c1 > div {
1616
padding: 2rem 2.4rem;
1717
outline: none;
1818
color: #424242;
@@ -35,222 +35,15 @@ exports[`assigned route route renders renders a component 1`] = `
3535
justify-content: flex-end;
3636
}
3737
38-
.c1 {
39-
box-shadow: 0 0.2rem 0.2rem 0 rgba(0,0,0,0.14);
40-
background-color: #fff;
41-
color: #424242;
42-
display: -webkit-box;
43-
display: -webkit-flex;
44-
display: -ms-flexbox;
45-
display: flex;
46-
height: 5rem;
47-
}
48-
49-
.c1.c1 {
50-
top: 0;
51-
}
52-
53-
.c12 {
54-
height: 1.7rem;
55-
width: 1.7rem;
56-
}
57-
58-
.c15 {
59-
height: 1.7rem;
60-
width: 1.7rem;
61-
}
62-
63-
.c8 {
64-
list-style: none;
65-
cursor: pointer;
66-
}
67-
68-
.c8::before {
69-
display: none;
70-
}
71-
72-
.c8::-moz-list-bullet {
73-
list-style-type: none;
74-
}
75-
76-
.c8::-webkit-details-marker {
77-
display: none;
78-
}
79-
80-
.c2 {
81-
font-size: 1.8rem;
82-
line-height: 2.1rem;
83-
-webkit-letter-spacing: 0.03px;
84-
-moz-letter-spacing: 0.03px;
85-
-ms-letter-spacing: 0.03px;
86-
letter-spacing: 0.03px;
87-
margin-left: 1.6rem;
88-
}
89-
90-
.c13 {
91-
margin-left: -0.3rem;
92-
}
93-
94-
.c16 {
95-
margin-left: -0.3rem;
96-
}
97-
98-
.c10 {
99-
font-weight: 500;
100-
list-style: none;
101-
}
102-
103-
.c10,
104-
.c10 span {
105-
color: #424242;
106-
font-size: 1.6rem;
107-
line-height: 2.5rem;
108-
color: #027EB5;
109-
cursor: pointer;
110-
-webkit-text-decoration: none;
111-
text-decoration: none;
112-
}
113-
114-
.c10 a,
115-
.c10 span a {
116-
color: #027EB5;
117-
cursor: pointer;
118-
-webkit-text-decoration: underline;
119-
text-decoration: underline;
120-
}
121-
122-
.c10 a:hover,
123-
.c10 span a:hover {
124-
color: #0064A0;
125-
}
126-
127-
.c10:hover,
128-
.c10 span:hover,
129-
.c10:focus,
130-
.c10 span:focus {
131-
-webkit-text-decoration: underline;
132-
text-decoration: underline;
133-
color: #0064A0;
134-
}
135-
136-
.c17 blockquote {
137-
margin-left: 0;
138-
}
139-
140-
.c6 {
141-
color: #424242;
142-
font-size: 1.6rem;
143-
line-height: 2.5rem;
144-
box-shadow: 0 -1rem 1rem -1rem rgba(0,0,0,0.1);
145-
margin: 3rem 0 0 0;
146-
min-height: 6rem;
147-
padding: 0 3.2rem;
148-
padding-top: 1.8rem;
149-
}
150-
151-
.c6[open] > summary .c11 {
152-
display: none;
153-
}
154-
155-
.c6:not([open]) > summary .c14 {
156-
display: none;
157-
}
158-
159-
.c6 a {
160-
color: #027EB5;
161-
cursor: pointer;
162-
-webkit-text-decoration: underline;
163-
text-decoration: underline;
164-
}
165-
166-
.c6 a:hover {
167-
color: #0064A0;
168-
}
169-
170-
.c6 > .c9 {
171-
margin-bottom: 1.8rem;
172-
}
173-
174-
.c6 li {
175-
margin-bottom: 1rem;
176-
overflow: visible;
177-
}
178-
179-
.c5 {
180-
top: 5rem;
181-
left: 0;
182-
max-width: 100%;
183-
}
184-
185-
.c0 [data-platform-hidden="assignable"] {
186-
display: none;
187-
}
188-
18938
@media screen and (max-width:75em) {
190-
.c4 > div {
39+
.c1 > div {
19140
padding: 1rem 1.6rem;
19241
}
19342
}
19443
195-
@media screen and (max-width:50em) {
196-
.c1 {
197-
height: 5.3rem;
198-
}
199-
}
200-
201-
@media screen and (max-width:75em) {
202-
.c2 {
203-
white-space: nowrap;
204-
overflow: hidden;
205-
text-overflow: ellipsis;
206-
}
207-
}
208-
209-
@media screen {
210-
.c10 {
211-
max-width: 82.5rem;
212-
margin: 0 auto;
213-
}
214-
}
215-
216-
@media screen {
217-
.c17 {
218-
max-width: 82.5rem;
219-
margin: 0 auto;
220-
}
221-
}
222-
223-
@media screen and (max-width:75em) {
224-
.c6 {
225-
padding: 0 1.6rem;
226-
}
227-
}
228-
229-
@media screen and (max-width:75em) {
230-
.c6 {
231-
min-height: 4rem;
232-
padding-top: 0.8rem;
233-
}
234-
235-
.c6 > .c7 {
236-
margin-bottom: 0.8rem;
237-
}
238-
}
239-
240-
@media print {
241-
.c6 {
242-
display: none;
243-
}
244-
}
245-
246-
@media screen and (max-width:75em) {
247-
.c5 {
248-
top: 5.300000000000001rem;
249-
}
250-
}
251-
25244
<div
253-
className="c0"
45+
className="platform-wrapper"
46+
data-platform="assignable"
25447
>
25548
<a
25649
className="hidden-but-accessible hidden-link"
@@ -291,9 +84,13 @@ exports[`assigned route route renders renders a component 1`] = `
29184
Keyboard shortcuts menu
29285
</button>
29386
<div
294-
className="topbar-wrapper c1"
87+
className="topbar-wrapper assigned-topbar-wrapper"
29588
style={
29689
Object {
90+
"--assigned-topbar-bg-color": "#fff",
91+
"--assigned-topbar-height-desktop": "5rem",
92+
"--assigned-topbar-height-mobile": "5.3rem",
93+
"--assigned-topbar-text-color": "#424242",
29794
"--topbar-sticky-top-desktop": "7rem",
29895
"--topbar-sticky-top-mobile": "6rem",
29996
"--topbar-z-index": 30,
@@ -302,22 +99,22 @@ exports[`assigned route route renders renders a component 1`] = `
30299
}
303100
>
304101
<h2
305-
className="c2"
102+
className="assigned-topbar-section-title"
306103
dangerouslySetInnerHTML={
307104
Object {
308105
"__html": "<span class=\\"os-text\\">Test Page 1</span>",
309106
}
310107
}
311108
/>
312109
<div
313-
className="c3 topbar-text-resizer-dropdown"
110+
className="c0 topbar-text-resizer-dropdown"
314111
data-testid="text-resizer"
315112
>
316113
<button
317114
aria-controls="text-resizer-menu"
318115
aria-expanded={false}
319116
aria-label="Change text size"
320-
className="plain-button c4 dropdown-toggle "
117+
className="plain-button c1 dropdown-toggle "
321118
data-analytics-label="Change text size"
322119
onClick={[Function]}
323120
>
@@ -344,14 +141,16 @@ exports[`assigned route route renders renders a component 1`] = `
344141
>
345142
<div
346143
aria-live="polite"
347-
className="page-toast-container c5"
144+
className="page-toast-container assigned-toast-override"
348145
style={
349146
Object {
147+
"--assigned-mobile-top": "5.300000000000001rem",
350148
"--content-wrapper-max-width": "128rem",
351149
"--desktop-search-failure-top": "12rem",
352150
"--mobile-search-failure-top": "11.3rem",
353151
"--toast-z-index-desktop": 19,
354152
"--toast-z-index-mobile": 21,
153+
"--topbar-desktop-height": "5rem",
355154
"--vertical-navbar-max-width": "8rem",
356155
}
357156
}
@@ -398,17 +197,32 @@ exports[`assigned route route renders renders a component 1`] = `
398197
</div>
399198
</div>
400199
<details
401-
className="c6"
200+
className="attribution-details"
402201
data-analytics-region="attribution"
403202
data-testid="attribution-details"
203+
style={
204+
Object {
205+
"--attribution-text-color": "#424242",
206+
"--content-text-width": "82.5rem",
207+
"--link-color": "#027EB5",
208+
"--link-hover": "#0064A0",
209+
}
210+
}
404211
>
405212
<summary
406213
aria-label="Citation/Attribution"
407-
className="c7 c8 c9 c10"
214+
className="attribution-summary"
215+
style={
216+
Object {
217+
"--attribution-text-color": "#424242",
218+
"--link-color": "#027EB5",
219+
"--link-hover": "#0064A0",
220+
}
221+
}
408222
>
409223
<svg
410224
aria-hidden="true"
411-
className="details-expand-icon c11 c12 c13"
225+
className="details-expand-icon attribution-summary-icon attribution-expand-icon"
412226
viewBox="0 0 192 512"
413227
>
414228
<path
@@ -418,7 +232,7 @@ exports[`assigned route route renders renders a component 1`] = `
418232
</svg>
419233
<svg
420234
aria-hidden="true"
421-
className="details-collapse-icon c14 c15 c16"
235+
className="details-collapse-icon attribution-summary-icon attribution-collapse-icon"
422236
viewBox="0 0 320 512"
423237
>
424238
<path
@@ -434,7 +248,7 @@ exports[`assigned route route renders renders a component 1`] = `
434248
</span>
435249
</summary>
436250
<div
437-
className="c17"
251+
className="attribution-content"
438252
dangerouslySetInnerHTML={
439253
Object {
440254
"__html": "
@@ -504,6 +318,11 @@ exports[`assigned route route renders renders a component 1`] = `
504318
",
505319
}
506320
}
321+
style={
322+
Object {
323+
"--content-text-width": "82.5rem",
324+
}
325+
}
507326
/>
508327
</details>
509328
</div>

0 commit comments

Comments
 (0)