Skip to content

Commit c8ef5ad

Browse files
authored
fix: reduce duplication in CSS and HTML (#33)
1 parent 04cf676 commit c8ef5ad

15 files changed

+289
-226
lines changed

package-lock.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@carbon/styles": "^1.72.0",
2626
"@ibm/plex": "^6.4.1",
2727
"@lhci/cli": "^0.15.0",
28+
"classnames": "^2.5.1",
2829
"compression": "^1.7.5",
2930
"express": "^5.0.1",
3031
"react": "^19.0.0",
@@ -33,18 +34,18 @@
3334
"sirv": "^3.0.0"
3435
},
3536
"devDependencies": {
37+
"@double-great/stylelint-a11y": "^3.0.4",
38+
"@eslint/js": "^9.21.0",
3639
"@testing-library/jest-dom": "^6.6.3",
3740
"@testing-library/react": "^16.2.0",
3841
"@testing-library/user-event": "^14.6.1",
39-
"@vitest/coverage-v8": "^3.1.2",
40-
"cross-env": "^7.0.3",
41-
"eslint": "^9.23.0",
42-
"@double-great/stylelint-a11y": "^3.0.4",
43-
"@eslint/js": "^9.21.0",
4442
"@types/react": "^19.0.10",
4543
"@types/react-dom": "^19.0.4",
4644
"@vitejs/plugin-react-swc": "^3.8.0",
45+
"@vitest/coverage-v8": "^3.1.2",
46+
"cross-env": "^7.0.3",
4747
"cspell": "^8.18.1",
48+
"eslint": "^9.23.0",
4849
"eslint-config-prettier": "^10.1.2",
4950
"eslint-plugin-import": "^2.31.0",
5051
"eslint-plugin-jsx-a11y": "^6.10.2",
@@ -57,8 +58,8 @@
5758
"jsdom": "^26.0.0",
5859
"lint-staged": "^15.4.3",
5960
"msw": "^2.7.3",
60-
"sass-embedded": "^1.85.1",
6161
"prettier": "^3.5.3",
62+
"sass-embedded": "^1.85.1",
6263
"stylelint": "^16.18.0",
6364
"stylelint-config-standard-scss": "^14.0.0",
6465
"stylelint-plugin-carbon-tokens": "^3.2.3",

src/entry-client.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
import { StrictMode } from 'react';
1010
import { hydrateRoot } from 'react-dom/client';
1111
import { BrowserRouter } from 'react-router';
12+
import { Router } from './routes';
1213

1314
// App level imports
14-
import { PageWrapper } from './components/wrapper/PageWrapper.jsx';
1515

1616
hydrateRoot(
1717
document.getElementById('root'),
1818
<StrictMode>
1919
<BrowserRouter>
20-
<PageWrapper />
20+
<Router />
2121
</BrowserRouter>
2222
</StrictMode>,
2323
);

src/entry-server.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { renderToPipeableStream } from 'react-dom/server';
1111
import { StaticRouter } from 'react-router';
1212

1313
// App level imports
14-
import { PageWrapper } from './components/wrapper/PageWrapper.jsx';
14+
import { Router } from './routes/index.jsx';
1515

1616
/**
1717
* @param {string} url
@@ -23,7 +23,7 @@ export function render(_url, options) {
2323
const { pipe, abort } = renderToPipeableStream(
2424
<StrictMode>
2525
<StaticRouter location={url}>
26-
<PageWrapper />
26+
<Router />
2727
</StaticRouter>
2828
</StrictMode>,
2929
options,

src/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
not "flashing style" - everything will be at the right
1919
place from the start. In most case, avoid loading styles
2020
from the JavaScript. */
21+
@use 'layouts/page-layout';
2122
@use 'pages/welcome/welcome';
2223
@use 'pages/dashboard/dashboard';
2324
@use 'components/welcomeHeader/welcomeHeader';

src/layouts/page-layout.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright IBM Corp. 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { Content } from '@carbon/react';
9+
import { Suspense } from 'react';
10+
import { Nav } from '../components/nav/Nav';
11+
import classNames from 'classnames';
12+
13+
export const PageLayout = ({ children, className, fallback }) => {
14+
return (
15+
<Suspense fallback={fallback}>
16+
<div className={classNames('cs--page-layout', className)}>
17+
<Nav />
18+
<Content className="cs--page-layout-content">{children}</Content>
19+
</div>
20+
</Suspense>
21+
);
22+
};

src/layouts/page-layout.scss

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Copyright IBM Corp. 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
@use '@carbon/react/scss/spacing' as *;
9+
@use '@carbon/react/scss/type' as *;
10+
@use '@carbon/react/scss/breakpoint' as *;
11+
@use '@carbon/react/scss/theme' as *;
12+
13+
@mixin carbon-content-overrides() {
14+
// These Carbon overrides are pending outcome of issue #19877
15+
// https://github.com/carbon-design-system/carbon/issues/19877
16+
17+
:where(.cds--side-nav ~ .cds--content) {
18+
// Where used to allow padding to be overridden later
19+
padding: 0;
20+
}
21+
22+
.cds--side-nav ~ .cds--content {
23+
/* stylelint-disable-next-line carbon/layout-use -- temporary fix pending Content component updates */
24+
margin-inline-start: 16rem;
25+
26+
@include breakpoint-down('lg') {
27+
margin-inline-start: 0;
28+
}
29+
}
30+
31+
.cds--side-nav--hidden ~ .cds--content {
32+
margin-inline-start: 0;
33+
}
34+
35+
.cds--side-nav--rail ~ .cds--content {
36+
margin-inline: $spacing-09;
37+
}
38+
}
39+
40+
.cs--page-layout {
41+
@include carbon-content-overrides;
42+
}
43+
44+
.cs--page-layout-content {
45+
@include default-type;
46+
47+
// These following styles size the content area and move the scroll
48+
// from the body to this content area
49+
block-size: calc(100vh - $spacing-09);
50+
max-block-size: calc(100vh - $spacing-08);
51+
padding-block-start: $spacing-05;
52+
overflow-y: auto;
53+
scrollbar-color: $background-active $layer-01;
54+
}

src/components/wrapper/PageWrapper.jsx renamed to src/layouts/theme-layout.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@
77

88
import { GlobalTheme, Theme } from '@carbon/react';
99

10-
import { useThemes } from '../../hooks/useThemes';
11-
import { Router } from '../../routes/index';
10+
import { useThemes } from '../hooks/useThemes';
11+
import { Outlet } from 'react-router';
1212

13-
export const PageWrapper = () => {
13+
export const ThemeLayout = () => {
1414
const { primaryTheme, themeReady } = useThemes();
1515

1616
return themeReady ? (
1717
<GlobalTheme theme={primaryTheme}>
1818
<Theme theme={primaryTheme}>
19-
<Router />
19+
<Outlet />
2020
</Theme>
2121
</GlobalTheme>
2222
) : (
23-
<Router />
23+
<Outlet />
2424
);
2525
};

src/pages/_page-common.scss

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright IBM Corp. 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
@use '@carbon/react/scss/spacing' as *;
9+
@use '@carbon/react/scss/type' as *;
10+
@use '@carbon/react/scss/breakpoint' as *;
11+
12+
@mixin page-common() {
13+
h1,
14+
dd {
15+
@include type-style('heading-07');
16+
17+
margin-block-end: $spacing-08;
18+
}
19+
20+
h3 {
21+
margin-block-end: $spacing-05;
22+
}
23+
24+
p,
25+
dt {
26+
margin-block-end: $spacing-05;
27+
margin-inline-end: $spacing-08;
28+
}
29+
30+
dt {
31+
@include type-style('label-02');
32+
}
33+
}

src/pages/dashboard/Dashboard.jsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import { Suspense } from 'react';
98
import { Column, Grid, Tile } from '@carbon/react';
109

11-
import { Nav } from '../../components/nav/Nav';
1210
import { Footer } from '../../components/footer/Footer';
11+
import { PageLayout } from '../../layouts/page-layout';
1312

1413
// The styles are imported into index.scss by default.
1514
// Do the same unless you have a good reason not to.
@@ -29,31 +28,29 @@ const NumberTile = () => {
2928

3029
const Dashboard = () => {
3130
return (
32-
<Suspense fallback={<p>Loading welcome page...</p>}>
33-
<Nav />
34-
35-
{/* Main Content */}
36-
<main className="cs--dashboard">
37-
<Grid>
38-
<NumberTile />
39-
<NumberTile />
40-
<NumberTile />
41-
<NumberTile />
42-
43-
<Column sm={4} md={4} lg={8} xlg={8}>
44-
<Tile className="cs--dashboard__tile cs--dashboard__tile--data">
45-
<strong>Visualization</strong>
46-
</Tile>
47-
</Column>
48-
<Column sm={4} md={4} lg={8} xlg={8}>
49-
<Tile className="cs--dashboard__tile cs--dashboard__tile--data">
50-
<strong>Cool table</strong>
51-
</Tile>
52-
</Column>
53-
<Footer />
54-
</Grid>
55-
</main>
56-
</Suspense>
31+
<PageLayout
32+
className="cs--dashboard"
33+
fallback={<p>Loading dashboard page...</p>}
34+
>
35+
<Grid>
36+
<NumberTile />
37+
<NumberTile />
38+
<NumberTile />
39+
<NumberTile />
40+
41+
<Column sm={4} md={4} lg={8} xlg={8}>
42+
<Tile className="cs--dashboard__tile cs--dashboard__tile--data">
43+
<strong>Visualization</strong>
44+
</Tile>
45+
</Column>
46+
<Column sm={4} md={4} lg={8} xlg={8}>
47+
<Tile className="cs--dashboard__tile cs--dashboard__tile--data">
48+
<strong>Cool table</strong>
49+
</Tile>
50+
</Column>
51+
<Footer />
52+
</Grid>
53+
</PageLayout>
5754
);
5855
};
5956

0 commit comments

Comments
 (0)