Skip to content

Commit 6c3e967

Browse files
committed
feat: enhance responsive design and accessibility in documentation layout and styles
1 parent 9d7e205 commit 6c3e967

5 files changed

Lines changed: 119 additions & 129 deletions

File tree

packages/reca-docs/app/globals.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ html,
88
body {
99
max-width: 100vw;
1010
overflow-x: hidden;
11+
/* Prevent content overflow from breaking sticky AppBar on mobile */
12+
-webkit-text-size-adjust: 100%;
1113
}
1214

1315
a {

packages/reca-docs/app/layout.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
import type {Metadata} from "next";
1+
import type {Metadata, Viewport} from "next";
22
import "./globals.css";
33
import {type JSX} from "react";
44
import {ThemeRegistry} from "../src/components/theme-registry/theme-registry.js";
55

6+
export const viewport: Viewport = {
7+
width: "device-width",
8+
initialScale: 1
9+
};
10+
611
export const metadata: Metadata = {
712
title: "ReCA Documentation",
813
description: "Documentation for ReCA — React Clean Architecture state manager"

packages/reca-docs/src/components/doc-content/doc-content.styles.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export const DocArticle = styled("article")`
44
line-height: 1.8;
55
color: #333;
66
max-width: 820px;
7+
width: 100%;
78
89
h1 {
910
font-size: 2rem;
@@ -30,8 +31,25 @@ export const DocArticle = styled("article")`
3031
color: #333;
3132
}
3233
34+
/* Tablet: 600px – 899px */
35+
@media (max-width: 899px) {
36+
h1 { font-size: 1.65rem; }
37+
h2 { font-size: 1.25rem; margin-top: 32px; }
38+
h3 { font-size: 1.05rem; margin-top: 22px; }
39+
}
40+
41+
/* Mobile: < 600px */
42+
@media (max-width: 599px) {
43+
line-height: 1.7;
44+
h1 { font-size: 1.4rem; }
45+
h2 { font-size: 1.15rem; margin-top: 24px; }
46+
h3 { font-size: 1rem; margin-top: 18px; }
47+
}
48+
3349
p {
3450
margin-bottom: 16px;
51+
overflow-wrap: break-word;
52+
word-break: break-word;
3553
}
3654
3755
code {
@@ -40,6 +58,8 @@ export const DocArticle = styled("article")`
4058
border-radius: 4px;
4159
font-size: 0.88em;
4260
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
61+
overflow-wrap: break-word;
62+
word-break: break-all;
4363
}
4464
4565
pre {
@@ -48,10 +68,17 @@ export const DocArticle = styled("article")`
4868
padding: 20px 24px;
4969
border-radius: 8px;
5070
overflow-x: auto;
71+
max-width: 100%;
5172
margin-bottom: 24px;
5273
font-size: 0.88rem;
5374
line-height: 1.6;
5475
76+
@media (max-width: 599px) {
77+
padding: 14px 16px;
78+
font-size: 0.82rem;
79+
border-radius: 6px;
80+
}
81+
5582
code {
5683
background: none;
5784
padding: 0;
@@ -148,8 +175,17 @@ export const DocArticle = styled("article")`
148175
}
149176
}
150177
178+
/* Wrap tables for horizontal scroll on small screens */
179+
.table-wrapper,
180+
table {
181+
display: block;
182+
overflow-x: auto;
183+
-webkit-overflow-scrolling: touch;
184+
}
185+
151186
table {
152187
width: 100%;
188+
min-width: 480px;
153189
border-collapse: collapse;
154190
margin-bottom: 24px;
155191
font-size: 0.9rem;
@@ -166,7 +202,25 @@ export const DocArticle = styled("article")`
166202
font-weight: 600;
167203
}
168204
205+
@media (max-width: 599px) {
206+
th, td {
207+
padding: 8px 10px;
208+
font-size: 0.82rem;
209+
}
210+
}
211+
169212
strong {
170213
font-weight: 600;
171214
}
215+
216+
img {
217+
max-width: 100%;
218+
height: auto;
219+
}
220+
221+
/* Long URLs and identifiers in paragraphs should wrap */
222+
a {
223+
overflow-wrap: break-word;
224+
word-break: break-word;
225+
}
172226
`;

packages/reca-docs/src/components/shell/shell.styles.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,38 @@ import styled from "@emotion/styled";
22

33
export const DRAWER_WIDTH = 280;
44

5+
/* AppBar (Toolbar) height: 56px on xs, 64px on sm+ */
6+
export const TOOLBAR_HEIGHT_MOBILE = 56;
7+
export const TOOLBAR_HEIGHT_DESKTOP = 64;
8+
59
export const MainContent = styled("main", {
610
shouldForwardProp: (prop) => prop !== "drawerWidth"
711
})<{drawerWidth: number}>`
812
flex-grow: 1;
13+
/* min-width: 0 prevents flex child from overflowing its container */
14+
min-width: 0;
15+
max-width: 100%;
16+
overflow-x: hidden;
917
padding: 40px 48px;
10-
margin-top: 64px;
11-
min-height: calc(100vh - 64px);
18+
margin-top: ${TOOLBAR_HEIGHT_DESKTOP}px;
19+
min-height: calc(100vh - ${TOOLBAR_HEIGHT_DESKTOP}px);
1220
1321
@media (min-width: 900px) {
1422
margin-left: ${({drawerWidth}) => drawerWidth}px;
1523
}
1624
17-
@media (max-width: 600px) {
18-
padding: 24px 16px;
25+
/* Tablet: 600px – 899px */
26+
@media (min-width: 600px) and (max-width: 899px) {
27+
padding: 28px 32px;
28+
margin-top: ${TOOLBAR_HEIGHT_DESKTOP}px;
29+
min-height: calc(100vh - ${TOOLBAR_HEIGHT_DESKTOP}px);
30+
}
31+
32+
/* Mobile: < 600px */
33+
@media (max-width: 599px) {
34+
padding: 20px 16px;
35+
margin-top: ${TOOLBAR_HEIGHT_MOBILE}px;
36+
min-height: calc(100vh - ${TOOLBAR_HEIGHT_MOBILE}px);
1937
}
2038
`;
2139

packages/reca-docs/src/components/shell/shell.tsx

Lines changed: 35 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
ListItemText,
1313
Toolbar,
1414
Typography,
15-
useMediaQuery,
1615
useTheme
1716
} from "@mui/material";
1817
import MenuIcon from "@mui/icons-material/Menu";
@@ -22,7 +21,7 @@ import GitHubIcon from "@mui/icons-material/GitHub";
2221
import Link from "next/link";
2322
import {usePathname} from "next/navigation";
2423
import {type INavGroup, navigation} from "../../navigation.js";
25-
import {DRAWER_WIDTH, LogoWrapper, MainContent} from "./shell.styles.js";
24+
import {DRAWER_WIDTH, TOOLBAR_HEIGHT_DESKTOP, TOOLBAR_HEIGHT_MOBILE, LogoWrapper, MainContent} from "./shell.styles.js";
2625

2726
interface IShellProps {
2827
readonly children: ReactNode;
@@ -31,14 +30,12 @@ interface IShellProps {
3130
export const Shell = ({children}: IShellProps): JSX.Element => {
3231
const muiTheme = useTheme();
3332
const pathname = usePathname();
34-
const isMobile = useMediaQuery(muiTheme.breakpoints.down("md"));
3533
const [mobileOpen, setMobileOpen] = useState(false);
3634
const [openSections, setOpenSections] = useState<Record<string, boolean>>(() => {
3735
const initial: Record<string, boolean> = {};
3836
for (const group of navigation) {
3937
initial[group.label] = true;
4038
}
41-
4239
return initial;
4340
});
4441

@@ -50,69 +47,30 @@ export const Shell = ({children}: IShellProps): JSX.Element => {
5047
setOpenSections((prev) => ({...prev, [label]: !prev[label]}));
5148
};
5249

53-
const handleMobileClose = (): void => {
54-
if (isMobile) {
55-
setMobileOpen(false);
56-
}
57-
};
58-
5950
const isActive = (path: string): boolean => pathname === path || pathname === `${path}/`;
6051

6152
const drawerContent = (
62-
<Box sx={{mt: "64px", overflowY: "auto", py: 1}}>
53+
<Box sx={{mt: {xs: `${TOOLBAR_HEIGHT_MOBILE}px`, sm: `${TOOLBAR_HEIGHT_DESKTOP}px`}, overflowY: "auto", py: 1}}>
6354
<List component="nav" disablePadding>
6455
{navigation.map((group: INavGroup) => (
6556
<Box key={group.label}>
66-
<ListItemButton
67-
onClick={() => handleSectionToggle(group.label)}
68-
sx={{py: 0.8, px: 2.5}}
69-
>
57+
<ListItemButton onClick={() => handleSectionToggle(group.label)} sx={{py: 0.8, px: 2.5}}>
7058
<ListItemText
7159
primary={group.label}
72-
slotProps={{
73-
primary: {
74-
sx: {
75-
fontWeight: 700,
76-
fontSize: "0.75rem",
77-
textTransform: "uppercase",
78-
letterSpacing: "0.08em",
79-
color: "text.secondary"
80-
}
81-
}
82-
}}
60+
slotProps={{primary: {sx: {fontWeight: 700, fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "0.08em", color: "text.secondary"}}}}
8361
/>
84-
{openSections[group.label]
85-
? <ExpandLess fontSize="small" />
86-
: <ExpandMore fontSize="small" />}
62+
{openSections[group.label] ? <ExpandLess fontSize="small" /> : <ExpandMore fontSize="small" />}
8763
</ListItemButton>
8864
<Collapse in={openSections[group.label]} timeout="auto" unmountOnExit>
8965
<List component="div" disablePadding>
9066
{group.items.map((item) => (
9167
<Link key={item.path} href={item.path} style={{textDecoration: "none", color: "inherit"}}>
9268
<ListItemButton
93-
onClick={handleMobileClose}
69+
onClick={() => setMobileOpen(false)}
9470
selected={isActive(item.path)}
95-
sx={{
96-
pl: 4,
97-
py: 0.5,
98-
"&.Mui-selected": {
99-
backgroundColor: "rgba(25, 118, 210, 0.08)",
100-
borderRight: "3px solid #1976d2",
101-
"& .MuiListItemText-primary": {
102-
color: "#1976d2",
103-
fontWeight: 600
104-
}
105-
}
106-
}}
71+
sx={{pl: 4, py: 0.5, "&.Mui-selected": {backgroundColor: "rgba(25, 118, 210, 0.08)", borderRight: "3px solid #1976d2", "& .MuiListItemText-primary": {color: "#1976d2", fontWeight: 600}}}}
10772
>
108-
<ListItemText
109-
primary={item.label}
110-
slotProps={{
111-
primary: {
112-
sx: {fontSize: "0.9rem"}
113-
}
114-
}}
115-
/>
73+
<ListItemText primary={item.label} slotProps={{primary: {sx: {fontSize: "0.9rem"}}}} />
11674
</ListItemButton>
11775
</Link>
11876
))}
@@ -125,91 +83,44 @@ export const Shell = ({children}: IShellProps): JSX.Element => {
12583
);
12684

12785
return (
128-
<Box sx={{display: "flex"}}>
129-
<AppBar
130-
position="fixed"
131-
sx={{
132-
zIndex: muiTheme.zIndex.drawer + 1,
133-
backgroundColor: "#fff",
134-
color: "#333",
135-
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.08)"
136-
}}
137-
>
86+
<Box sx={{display: "flex", overflow: "hidden"}}>
87+
<AppBar position="fixed" sx={{zIndex: muiTheme.zIndex.drawer + 1, backgroundColor: "#fff", color: "#333", boxShadow: "0 1px 3px rgba(0, 0, 0, 0.08)"}}>
13888
<Toolbar>
139-
{isMobile && (
140-
<IconButton
141-
edge="start"
142-
onClick={handleDrawerToggle}
143-
sx={{mr: 1}}
144-
>
145-
<MenuIcon />
146-
</IconButton>
147-
)}
89+
<IconButton edge="start" onClick={handleDrawerToggle} sx={{mr: 1, display: {md: "none"}}}>
90+
<MenuIcon />
91+
</IconButton>
14892
<LogoWrapper>
14993
<Link href="/" style={{display: "flex", alignItems: "center", gap: 10, textDecoration: "none"}}>
150-
<Typography
151-
variant="h6"
152-
noWrap
153-
sx={{fontWeight: 800, color: "#1976d2"}}
154-
>
155-
ReCA
156-
</Typography>
157-
<Typography
158-
variant="body2"
159-
noWrap
160-
sx={{color: "#999", fontWeight: 400}}
161-
>
162-
Documentation
163-
</Typography>
94+
<Typography variant="h6" noWrap sx={{fontWeight: 800, color: "#1976d2"}}>ReCA</Typography>
95+
<Typography variant="body2" noWrap sx={{color: "#999", fontWeight: 400}}>Documentation</Typography>
16496
</Link>
16597
</LogoWrapper>
16698
<Box sx={{flexGrow: 1}} />
167-
<IconButton
168-
component="a"
169-
href="https://github.com/LabEG/reca"
170-
target="_blank"
171-
rel="noopener noreferrer"
172-
sx={{color: "#555"}}
173-
>
99+
<IconButton component="a" href="https://github.com/LabEG/reca" target="_blank" rel="noopener noreferrer" sx={{color: "#555"}}>
174100
<GitHubIcon />
175101
</IconButton>
176102
</Toolbar>
177103
</AppBar>
178104

179-
{isMobile
180-
? (
181-
<Drawer
182-
variant="temporary"
183-
open={mobileOpen}
184-
onClose={handleDrawerToggle}
185-
ModalProps={{keepMounted: true}}
186-
sx={{
187-
"& .MuiDrawer-paper": {
188-
width: DRAWER_WIDTH,
189-
boxSizing: "border-box"
190-
}
191-
}}
192-
>
193-
{drawerContent}
194-
</Drawer>
195-
)
196-
: (
197-
<Drawer
198-
variant="permanent"
199-
sx={{
200-
width: DRAWER_WIDTH,
201-
flexShrink: 0,
202-
"& .MuiDrawer-paper": {
203-
width: DRAWER_WIDTH,
204-
boxSizing: "border-box",
205-
borderRight: "1px solid #f0f0f0"
206-
}
207-
}}
208-
open
209-
>
210-
{drawerContent}
211-
</Drawer>
212-
)}
105+
<Box component="nav" sx={{display: {md: "none"}}}>
106+
<Drawer
107+
variant="temporary"
108+
open={mobileOpen}
109+
onClose={handleDrawerToggle}
110+
ModalProps={{keepMounted: true}}
111+
sx={{"& .MuiDrawer-paper": {width: DRAWER_WIDTH, boxSizing: "border-box"}}}
112+
>
113+
{drawerContent}
114+
</Drawer>
115+
</Box>
116+
117+
<Drawer
118+
variant="permanent"
119+
sx={{display: {xs: "none", md: "block"}, width: DRAWER_WIDTH, flexShrink: 0, "& .MuiDrawer-paper": {width: DRAWER_WIDTH, boxSizing: "border-box", borderRight: "1px solid #f0f0f0"}}}
120+
open
121+
>
122+
{drawerContent}
123+
</Drawer>
213124

214125
<MainContent drawerWidth={DRAWER_WIDTH}>
215126
{children}

0 commit comments

Comments
 (0)