thibaud frere commited on
Commit
efb32fc
·
1 Parent(s): a4b9560

update responsiveness

Browse files
app/package-lock.json CHANGED
Binary files a/app/package-lock.json and b/app/package-lock.json differ
 
app/package.json CHANGED
Binary files a/app/package.json and b/app/package.json differ
 
app/postcss.config.mjs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // PostCSS config enabling Custom Media Queries
2
+ // Allows usage of: @media (--bp-content-collapse) { ... }
3
+
4
+ import postcssCustomMedia from 'postcss-custom-media';
5
+ import postcssPresetEnv from 'postcss-preset-env';
6
+
7
+ export default {
8
+ plugins: [
9
+ postcssCustomMedia(),
10
+ postcssPresetEnv({
11
+ stage: 0
12
+ })
13
+ ]
14
+ };
app/src/components/Footer.astro CHANGED
@@ -151,17 +151,6 @@ const { citationText, bibtex, licence, doi } = Astro.props as Props;
151
  grid-column: 2;
152
  }
153
 
154
- @media (max-width: var(--bp-content-collapse)) {
155
- .footer-inner {
156
- grid-template-columns: 1fr;
157
- gap: 16px;
158
- }
159
-
160
- .footer-inner > h3 {
161
- grid-column: auto;
162
- margin-top: 16px;
163
- }
164
- }
165
 
166
  .citation-block h3 {
167
  margin: 0 0 8px;
@@ -239,13 +228,6 @@ const { citationText, bibtex, licence, doi } = Astro.props as Props;
239
  [data-theme="dark"] .citation a { color: rgba(255,255,255,0.75); }
240
 
241
 
242
- @media (max-width: var(--bp-content-collapse)) {
243
- .footer-inner {
244
- display: block;
245
- padding: 40px 16px;
246
- }
247
- }
248
-
249
  /* Footer links: use primary color consistently */
250
  .footer a {
251
  color: var(--primary-color);
 
151
  grid-column: 2;
152
  }
153
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
  .citation-block h3 {
156
  margin: 0 0 8px;
 
228
  [data-theme="dark"] .citation a { color: rgba(255,255,255,0.75); }
229
 
230
 
 
 
 
 
 
 
 
231
  /* Footer links: use primary color consistently */
232
  .footer a {
233
  color: var(--primary-color);
app/src/components/Hero.astro CHANGED
@@ -93,7 +93,7 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
93
  </div>
94
  )}
95
  {published && (
96
- <div class="meta-container-cell">
97
  <h3>Published</h3>
98
  <p>{published}</p>
99
  </div>
@@ -201,6 +201,12 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
201
  .affiliations li {
202
  margin: 0;
203
  }
 
 
 
 
 
 
204
  @media print {
205
  .meta-container-cell--pdf {
206
  display: none !important;
 
93
  </div>
94
  )}
95
  {published && (
96
+ <div class="meta-container-cell meta-container-cell--published">
97
  <h3>Published</h3>
98
  <p>{published}</p>
99
  </div>
 
201
  .affiliations li {
202
  margin: 0;
203
  }
204
+
205
+ header.meta .meta-container {
206
+ flex-wrap: wrap;
207
+ row-gap: 12px;
208
+ }
209
+
210
  @media print {
211
  .meta-container-cell--pdf {
212
  display: none !important;
app/src/components/Sidenote.astro CHANGED
@@ -27,7 +27,7 @@
27
  color: var(--muted-color);
28
  }
29
 
30
- @media (max-width: var(--bp-content-collapse)) {
31
  .aside__aside {
32
  position: static;
33
  width: auto;
 
27
  color: var(--muted-color);
28
  }
29
 
30
+ @media (--bp-content-collapse) {
31
  .aside__aside {
32
  position: static;
33
  width: auto;
app/src/components/TableOfContents.astro CHANGED
@@ -2,10 +2,10 @@
2
  export interface Props { tableOfContentAutoCollapse?: boolean }
3
  const { tableOfContentAutoCollapse = false } = Astro.props as Props;
4
  ---
5
- <aside class="table-of-contents" data-auto-collapse={tableOfContentAutoCollapse ? '1' : '0'}>
6
  <div class="title">Table of Contents</div>
7
  <div id="article-toc-placeholder"></div>
8
- </aside>
9
  <details class="table-of-contents-mobile">
10
  <summary>Table of Contents</summary>
11
  <div id="article-toc-mobile-placeholder"></div>
@@ -97,7 +97,15 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
97
  ...(holder ? holder.querySelectorAll('a') : []),
98
  ...(holderMobile ? holderMobile.querySelectorAll('a') : [])
99
  ];
100
- const autoCollapse = (document.querySelector('aside.table-of-contents')?.getAttribute('data-auto-collapse') === '1');
 
 
 
 
 
 
 
 
101
 
102
  // Inject styles for collapsible & animation
103
  const ensureStyles = () => {
@@ -105,9 +113,9 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
105
  const style = document.createElement('style');
106
  style.id = 'toc-collapse-style';
107
  style.textContent = `
108
- aside.table-of-contents nav.table-of-contents-collapsible > ul > li > ul,
109
  details.table-of-contents-mobile nav.table-of-contents-collapsible > ul > li > ul { overflow: hidden; transition: height 200ms ease; }
110
- aside.table-of-contents nav.table-of-contents-collapsible > ul > li.collapsed > ul,
111
  details.table-of-contents-mobile nav.table-of-contents-collapsible > ul > li.collapsed > ul { display: block; }
112
  `;
113
  document.head.appendChild(style);
@@ -181,6 +189,29 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
181
  prevActiveIdx = activeIdx;
182
  };
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  const onScroll = () => {
185
  // active link highlight
186
  let activeIdx = -1;
@@ -288,11 +319,12 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
288
  .table-of-contents-mobile > summary {
289
  cursor: pointer;
290
  list-style: none;
291
- padding: 8px 12px;
292
  border: 1px solid var(--border-color);
293
  border-radius: 8px;
294
  color: var(--text-color);
295
  font-weight: 600;
 
296
  }
297
 
298
  .table-of-contents-mobile[open] > summary {
@@ -300,6 +332,25 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
300
  border-bottom-right-radius: 0;
301
  }
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  .table-of-contents-mobile nav {
304
  border-left: none;
305
  padding: 10px 12px;
@@ -340,17 +391,6 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
340
  text-decoration: underline;
341
  }
342
 
343
- [data-theme="dark"] .table-of-contents nav { border-left-color: rgba(255,255,255,.15); }
344
 
345
- /* Responsive: hide sticky TOC, show mobile */
346
- @media (max-width: var(--bp-content-collapse)) {
347
- .table-of-contents {
348
- position: static;
349
- display: none;
350
- }
351
 
352
- .table-of-contents-mobile {
353
- display: block;
354
- }
355
- }
356
  </style>
 
2
  export interface Props { tableOfContentAutoCollapse?: boolean }
3
  const { tableOfContentAutoCollapse = false } = Astro.props as Props;
4
  ---
5
+ <nav class="table-of-contents" aria-label="Table of Contents" data-auto-collapse={tableOfContentAutoCollapse ? '1' : '0'}>
6
  <div class="title">Table of Contents</div>
7
  <div id="article-toc-placeholder"></div>
8
+ </nav>
9
  <details class="table-of-contents-mobile">
10
  <summary>Table of Contents</summary>
11
  <div id="article-toc-mobile-placeholder"></div>
 
97
  ...(holder ? holder.querySelectorAll('a') : []),
98
  ...(holderMobile ? holderMobile.querySelectorAll('a') : [])
99
  ];
100
+ // Read breakpoint from CSS var and set autoCollapse only on desktop (disabled on mobile)
101
+ const getCollapsePx = () => {
102
+ const root = document.documentElement;
103
+ const raw = getComputedStyle(root).getPropertyValue('--bp-content-collapse').trim();
104
+ return raw || '1100px';
105
+ };
106
+ const mq = window.matchMedia(`(max-width: ${getCollapsePx()})`);
107
+ const attrEnabled = (document.querySelector('.table-of-contents')?.getAttribute('data-auto-collapse') === '1');
108
+ let autoCollapse = attrEnabled && !mq.matches;
109
 
110
  // Inject styles for collapsible & animation
111
  const ensureStyles = () => {
 
113
  const style = document.createElement('style');
114
  style.id = 'toc-collapse-style';
115
  style.textContent = `
116
+ .table-of-contents nav.table-of-contents-collapsible > ul > li > ul,
117
  details.table-of-contents-mobile nav.table-of-contents-collapsible > ul > li > ul { overflow: hidden; transition: height 200ms ease; }
118
+ .table-of-contents nav.table-of-contents-collapsible > ul > li.collapsed > ul,
119
  details.table-of-contents-mobile nav.table-of-contents-collapsible > ul > li.collapsed > ul { display: block; }
120
  `;
121
  document.head.appendChild(style);
 
189
  prevActiveIdx = activeIdx;
190
  };
191
 
192
+ // When switching between desktop/mobile, refresh autoCollapse and expand all on mobile
193
+ const expandAll = () => {
194
+ const { sideTop, mobileTop } = getTopLevelItems();
195
+ const expand = (items) => items.forEach((li) => {
196
+ li.classList.remove('collapsed');
197
+ const sub = li.querySelector(':scope > ul');
198
+ if (sub) sub.style.height = 'auto';
199
+ });
200
+ expand(sideTop);
201
+ expand(mobileTop);
202
+ };
203
+
204
+ const onMqChange = () => {
205
+ autoCollapse = attrEnabled && !mq.matches;
206
+ if (!autoCollapse) {
207
+ expandAll();
208
+ } else {
209
+ setCollapsedState(prevActiveIdx);
210
+ }
211
+ };
212
+ if (mq.addEventListener) mq.addEventListener('change', onMqChange);
213
+ else if (mq.addListener) mq.addListener(onMqChange);
214
+
215
  const onScroll = () => {
216
  // active link highlight
217
  let activeIdx = -1;
 
319
  .table-of-contents-mobile > summary {
320
  cursor: pointer;
321
  list-style: none;
322
+ padding: var(--spacing-3) var(--spacing-4);
323
  border: 1px solid var(--border-color);
324
  border-radius: 8px;
325
  color: var(--text-color);
326
  font-weight: 600;
327
+ position: relative;
328
  }
329
 
330
  .table-of-contents-mobile[open] > summary {
 
332
  border-bottom-right-radius: 0;
333
  }
334
 
335
+ /* Disclosure arrow for mobile summary */
336
+ .table-of-contents-mobile > summary::after {
337
+ content: '';
338
+ position: absolute;
339
+ right: var(--spacing-4);
340
+ top: 50%;
341
+ width: 8px;
342
+ height: 8px;
343
+ border-right: 2px solid currentColor;
344
+ border-bottom: 2px solid currentColor;
345
+ transform: translateY(-70%) rotate(45deg);
346
+ transition: transform 150ms ease;
347
+ opacity: .7;
348
+ }
349
+
350
+ .table-of-contents-mobile[open] > summary::after {
351
+ transform: translateY(-30%) rotate(-135deg);
352
+ }
353
+
354
  .table-of-contents-mobile nav {
355
  border-left: none;
356
  padding: 10px 12px;
 
391
  text-decoration: underline;
392
  }
393
 
 
394
 
 
 
 
 
 
 
395
 
 
 
 
 
396
  </style>
app/src/pages/index.astro CHANGED
@@ -157,10 +157,6 @@ const licence = (articleFM as any)?.licence ?? (articleFM as any)?.license ?? (a
157
  <TableOfContents tableOfContentAutoCollapse={tableOfContentAutoCollapse} />
158
  <main>
159
  <Article />
160
- <style is:inline>
161
- /* Inline tweak for details blocks used in MDX */
162
- details { background: var(--code-bg) !important; border: 1px solid var(--border-color) !important; border-radius: 6px; margin: 1em 0; padding: .5em .75em; }
163
- </style>
164
  </main>
165
  </section>
166
 
 
157
  <TableOfContents tableOfContentAutoCollapse={tableOfContentAutoCollapse} />
158
  <main>
159
  <Article />
 
 
 
 
160
  </main>
161
  </section>
162
 
app/src/styles/_base.css CHANGED
@@ -1,8 +1,6 @@
1
  @import "https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,200..900;1,200..900&display=swap";
2
 
3
- html { font-size: 14px; line-height: 1.6; }
4
- @media (min-width: 768px) { html { font-size: 16px; } }
5
- @media (min-width: 1024px) { html { font-size: 17px; } }
6
 
7
  .content-grid main { color: var(--text-color); }
8
  .content-grid main p { margin: 0 0 var(--spacing-3); }
 
1
  @import "https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,200..900;1,200..900&display=swap";
2
 
3
+ html { font-size: 16px; line-height: 1.6; }
 
 
4
 
5
  .content-grid main { color: var(--text-color); }
6
  .content-grid main p { margin: 0 0 var(--spacing-3); }
app/src/styles/_layout.css CHANGED
@@ -19,25 +19,44 @@
19
  padding: 0;
20
  }
21
 
22
- @media (max-width: var(--bp-content-collapse)) {
23
  .content-grid {
24
  overflow: hidden;
 
 
25
  }
26
- }
27
-
28
 
29
- /* Responsive – collapse to single column */
30
- @media (max-width: var(--bp-content-collapse)) {
31
  .content-grid {
32
  grid-template-columns: 1fr;
33
  }
34
 
35
- main > nav:first-of-type {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  display: block;
 
37
  }
38
  }
39
 
40
 
 
41
  /* ============================================================================ */
42
  /* Width helpers – slightly wider than main column, and full-width to viewport */
43
  /* ---------------------------------------------------------------------------- */
@@ -63,7 +82,7 @@
63
  margin-right: calc(50% - 50vw);
64
  }
65
 
66
- @media (max-width: var(--bp-content-collapse)) {
67
  .wide,
68
  .full-width {
69
  width: 100%;
@@ -73,5 +92,40 @@
73
  }
74
  }
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
 
 
19
  padding: 0;
20
  }
21
 
22
+ @media (--bp-content-collapse) {
23
  .content-grid {
24
  overflow: hidden;
25
+ display: block;
26
+ margin-top: var(--spacing-2);
27
  }
 
 
28
 
 
 
29
  .content-grid {
30
  grid-template-columns: 1fr;
31
  }
32
 
33
+ .table-of-contents {
34
+ position: static;
35
+ display: none;
36
+ }
37
+
38
+ .table-of-contents-mobile {
39
+ display: block;
40
+ }
41
+
42
+ .footer-inner {
43
+ grid-template-columns: 1fr;
44
+ gap: 16px;
45
+ }
46
+
47
+ .footer-inner > h3 {
48
+ grid-column: auto;
49
+ margin-top: 16px;
50
+ }
51
+
52
+ .footer-inner {
53
  display: block;
54
+ padding: 40px 16px;
55
  }
56
  }
57
 
58
 
59
+
60
  /* ============================================================================ */
61
  /* Width helpers – slightly wider than main column, and full-width to viewport */
62
  /* ---------------------------------------------------------------------------- */
 
82
  margin-right: calc(50% - 50vw);
83
  }
84
 
85
+ @media (--bp-content-collapse) {
86
  .wide,
87
  .full-width {
88
  width: 100%;
 
92
  }
93
  }
94
 
95
+ /* ------------------------------------------------------------------------- */
96
+ /* Hero meta bar responsiveness */
97
+ /* Two columns at collapse breakpoint, then one column below small screens */
98
+ /* ------------------------------------------------------------------------- */
99
+ @media (--bp-sm) {
100
+ header.meta .meta-container {
101
+ display: flex;
102
+ flex-wrap: wrap;
103
+ row-gap: 12px;
104
+ column-gap: 8px;
105
+ max-width: 100%;
106
+ padding: 0 var(--spacing-4);
107
+ }
108
+ header.meta .meta-container .meta-container-cell {
109
+ flex: 1 1 calc(50% - 8px);
110
+ min-width: 0;
111
+ }
112
+ }
113
+
114
+ @media (--bp-xxs) {
115
+ header.meta .meta-container .meta-container-cell {
116
+ flex-basis: 100%;
117
+ text-align: center;
118
+ }
119
+ /* Center ordered list numbers within meta (e.g., affiliations) */
120
+ header.meta .affiliations {
121
+ list-style-position: inside;
122
+ padding-left: 0;
123
+ margin-left: 0;
124
+ }
125
+ header.meta .affiliations li {
126
+ text-align: center;
127
+ }
128
+ }
129
+
130
 
131
 
app/src/styles/_print.css CHANGED
@@ -57,10 +57,12 @@
57
  /* Prefer keeping header+lead together */
58
  .hero { page-break-after: avoid; }
59
  }
60
-
61
- .muted {
62
- color: var(--muted-color);
 
 
 
63
  }
64
 
65
-
66
 
 
57
  /* Prefer keeping header+lead together */
58
  .hero { page-break-after: avoid; }
59
  }
60
+
61
+
62
+ @media print {
63
+ .meta-container-cell--pdf {
64
+ display: none !important;
65
+ }
66
  }
67
 
 
68
 
app/src/styles/_variables.css CHANGED
@@ -40,13 +40,14 @@
40
  --spacing-9: 64px;
41
  --spacing-10: 72px;
42
 
43
- /* Breakpoints */
44
- --bp-xs: 480px;
45
- --bp-sm: 640px;
46
- --bp-md: 768px;
47
- --bp-lg: 1024px;
48
- --bp-content-collapse: 1100px; /* layout single-column */
49
- --bp-xl: 1280px;
 
50
 
51
  /* Layout */
52
  --content-padding-x: 16px; /* default page gutter */
 
40
  --spacing-9: 64px;
41
  --spacing-10: 72px;
42
 
43
+ /* Custom Media aliases compiled by PostCSS */
44
+ @custom-media --bp-xxs (max-width: 320px);
45
+ @custom-media --bp-xs (max-width: 480px);
46
+ @custom-media --bp-sm (max-width: 640px);
47
+ @custom-media --bp-md (max-width: 768px);
48
+ @custom-media --bp-lg (max-width: 1024px);
49
+ @custom-media --bp-xl (max-width: 1280px);
50
+ @custom-media --bp-content-collapse (max-width: 1100px);
51
 
52
  /* Layout */
53
  --content-padding-x: 16px; /* default page gutter */
app/src/styles/components/_code.css CHANGED
@@ -49,7 +49,7 @@ section.content-grid pre code {
49
  }
50
 
51
  /* Wrap long lines only on small screens to prevent layout overflow */
52
- @media (max-width: var(--bp-content-collapse)) {
53
  .astro-code,
54
  section.content-grid pre {
55
  white-space: pre-wrap;
 
49
  }
50
 
51
  /* Wrap long lines only on small screens to prevent layout overflow */
52
+ @media (--bp-content-collapse) {
53
  .astro-code,
54
  section.content-grid pre {
55
  white-space: pre-wrap;