@raystack/chronicle 0.11.3 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raystack/chronicle",
3
- "version": "0.11.3",
3
+ "version": "0.12.0",
4
4
  "description": "Config-driven documentation framework",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -3,6 +3,7 @@
3
3
  border-radius: var(--rs-radius-2);
4
4
  overflow: hidden;
5
5
  width: 100%;
6
+ max-width: 100%;
6
7
  }
7
8
 
8
9
  .header {
@@ -20,4 +21,5 @@
20
21
 
21
22
  .body {
22
23
  background: var(--rs-color-background-base-primary);
24
+ overflow-x: auto;
23
25
  }
@@ -60,6 +60,16 @@
60
60
 
61
61
  .left,
62
62
  .right {
63
+ min-width: 0;
64
+ max-width: 100%;
63
65
  width: 100%;
64
66
  }
65
67
  }
68
+
69
+ @media (max-width: 768px) {
70
+ .layout {
71
+ gap: var(--rs-space-5);
72
+ padding-left: var(--rs-space-5);
73
+ padding-right: var(--rs-space-5);
74
+ }
75
+ }
@@ -283,3 +283,121 @@
283
283
  line-height: var(--rs-line-height-mini);
284
284
  flex-shrink: 0;
285
285
  }
286
+
287
+ .mobileMenuBtn {
288
+ display: none;
289
+ align-items: center;
290
+ justify-content: center;
291
+ background: none;
292
+ border: none;
293
+ cursor: pointer;
294
+ padding: var(--rs-space-1);
295
+ color: var(--rs-color-foreground-base-primary);
296
+ }
297
+
298
+ .mobileHeader {
299
+ display: none;
300
+ align-items: center;
301
+ justify-content: space-between;
302
+ height: var(--navbar-height);
303
+ padding: 0 var(--rs-space-5);
304
+ background: var(--rs-color-background-base-primary);
305
+ border-bottom: 0.5px solid var(--rs-color-border-base-primary);
306
+ backdrop-filter: blur(1px);
307
+ }
308
+
309
+ .mobileMenu {
310
+ display: none;
311
+ position: fixed;
312
+ top: var(--navbar-height);
313
+ left: 0;
314
+ right: 0;
315
+ bottom: 0;
316
+ z-index: 100;
317
+ background: var(--rs-color-background-base-primary);
318
+ overflow-y: auto;
319
+ padding: var(--rs-space-7) var(--rs-space-5);
320
+ }
321
+
322
+ .mobileMenuFooter {
323
+ margin-top: var(--rs-space-7);
324
+ padding-top: var(--rs-space-5);
325
+ border-top: 0.5px solid var(--rs-color-border-base-primary);
326
+ }
327
+
328
+ .mobileNav {
329
+ display: none;
330
+ }
331
+
332
+ @media (max-width: 768px) {
333
+ .sidebar {
334
+ display: none;
335
+ }
336
+
337
+ .mobileHeader {
338
+ display: flex;
339
+ }
340
+
341
+ .mobileMenuBtn {
342
+ display: flex;
343
+ }
344
+
345
+ .mobileMenu[data-open='true'] {
346
+ display: block;
347
+ }
348
+
349
+ .subNav {
350
+ display: none;
351
+ }
352
+
353
+ .content {
354
+ padding: var(--rs-space-10) var(--rs-space-5);
355
+ }
356
+
357
+ .card {
358
+ width: 100%;
359
+ border-left: none;
360
+ box-shadow: none;
361
+ }
362
+
363
+ .cardWrapper {
364
+ padding: 0;
365
+ }
366
+
367
+ .mobileNav {
368
+ display: flex;
369
+ gap: var(--rs-space-10);
370
+ padding: var(--rs-space-3) var(--rs-space-5);
371
+ background: var(--rs-color-background-base-primary);
372
+ }
373
+
374
+ .mobileNavLink {
375
+ flex: 1;
376
+ display: flex;
377
+ align-items: center;
378
+ gap: var(--rs-space-3);
379
+ padding: var(--rs-space-4) var(--rs-space-3);
380
+ border: 0.5px solid var(--rs-color-border-base-primary);
381
+ border-radius: var(--rs-radius-4);
382
+ text-decoration: none;
383
+ font-family: var(--rs-font-body);
384
+ font-size: var(--rs-font-size-regular);
385
+ font-weight: var(--rs-font-weight-medium);
386
+ line-height: var(--rs-line-height-regular);
387
+ letter-spacing: var(--rs-letter-spacing-regular);
388
+ color: var(--rs-color-foreground-base-tertiary);
389
+ min-width: 0;
390
+ }
391
+
392
+ .mobileNavLink[data-direction='next'] {
393
+ justify-content: flex-end;
394
+ background: var(--rs-color-background-base-secondary);
395
+ color: var(--rs-color-foreground-base-primary);
396
+ }
397
+
398
+ .mobileNavLabel {
399
+ overflow: hidden;
400
+ text-overflow: ellipsis;
401
+ white-space: nowrap;
402
+ }
403
+ }
@@ -4,7 +4,9 @@ import {
4
4
  CodeBracketSquareIcon,
5
5
  RectangleStackIcon,
6
6
  DocumentTextIcon,
7
- Squares2X2Icon
7
+ Squares2X2Icon,
8
+ Bars3Icon,
9
+ XMarkIcon
8
10
  } from '@heroicons/react/24/outline';
9
11
  import { Flex, IconButton, Button, Sidebar } from '@raystack/apsara';
10
12
  import { PlayIcon } from '@radix-ui/react-icons';
@@ -73,6 +75,7 @@ export function Layout({
73
75
  const navigate = useNavigate();
74
76
  const { page, version } = usePageContext();
75
77
  const scrollRef = useRef<HTMLDivElement>(null);
78
+ const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
76
79
  const isApiRoute = pathname === '/apis' || pathname.startsWith('/apis/');
77
80
  const isApiBase = (basePath: string) =>
78
81
  pathname === basePath || pathname.startsWith(`${basePath}/`);
@@ -109,10 +112,82 @@ export function Layout({
109
112
  requestAnimationFrame(() => {
110
113
  el.scrollTop = savedScrollTop;
111
114
  });
115
+ setMobileSidebarOpen(false);
112
116
  }, [pathname]);
113
117
 
114
118
  return (
115
119
  <Flex direction='column' className={cx(styles.layout, classNames?.layout)}>
120
+ <div className={styles.mobileHeader}>
121
+ <SidebarLogo config={config} />
122
+ <Flex align='center' gap={3}>
123
+ {config.search?.enabled && <Search />}
124
+ <ClientThemeSwitcher size={16} />
125
+ {!hideSidebar && (
126
+ <button
127
+ type='button'
128
+ className={styles.mobileMenuBtn}
129
+ onClick={() => setMobileSidebarOpen(o => !o)}
130
+ aria-label={mobileSidebarOpen ? 'Close menu' : 'Open menu'}
131
+ aria-expanded={mobileSidebarOpen}
132
+ aria-controls='mobile-menu'
133
+ >
134
+ {mobileSidebarOpen
135
+ ? <XMarkIcon width={16} height={16} />
136
+ : <Bars3Icon width={16} height={16} />}
137
+ </button>
138
+ )}
139
+ </Flex>
140
+ </div>
141
+ <div id='mobile-menu' className={styles.mobileMenu} data-open={!hideSidebar && mobileSidebarOpen}>
142
+ {showTopLinks ? (
143
+ <div className={styles.topLinks}>
144
+ {contentEntries.map(entry => (
145
+ <Sidebar.Item
146
+ key={entry.href}
147
+ href={entry.href}
148
+ active={activeContentDir === entry.contentDir}
149
+ leadingIcon={renderConfigIcon(entry.icon, entry.label, <DocumentTextIcon width={16} height={16} />)}
150
+ classNames={{ root: styles.topLinkItem, text: styles.topLinkText }}
151
+ render={<RouterLink to={entry.href} />}
152
+ >
153
+ {entry.label}
154
+ </Sidebar.Item>
155
+ ))}
156
+ {apiEntries.map(api => (
157
+ <Sidebar.Item
158
+ key={`${api.basePath}-${api.name}`}
159
+ href={api.basePath}
160
+ active={isApiBase(api.basePath)}
161
+ leadingIcon={renderConfigIcon(api.icon, api.name, <CodeBracketSquareIcon width={16} height={16} />)}
162
+ classNames={{ root: styles.topLinkItem, text: styles.topLinkText }}
163
+ render={<RouterLink to={api.basePath} />}
164
+ >
165
+ {api.name} API
166
+ </Sidebar.Item>
167
+ ))}
168
+ </div>
169
+ ) : null}
170
+ {tree.children.map((item, i) => (
171
+ isApiRoute ? (
172
+ <ApiSidebarNode
173
+ key={item.type === 'page' ? item.url : (item.name?.toString() ?? i)}
174
+ item={item}
175
+ pathname={pathname}
176
+ />
177
+ ) : (
178
+ <SidebarNode
179
+ key={item.type === 'page' ? item.url : (item.name?.toString() ?? i)}
180
+ item={item}
181
+ pathname={pathname}
182
+ />
183
+ )
184
+ ))}
185
+ {config.versions?.length ? (
186
+ <div className={styles.mobileMenuFooter}>
187
+ <VersionSwitcher />
188
+ </div>
189
+ ) : null}
190
+ </div>
116
191
  <Flex className={cx(styles.body, classNames?.body)}>
117
192
  {hideSidebar ? null : (
118
193
  <Sidebar
@@ -221,6 +296,20 @@ export function Layout({
221
296
  <main className={cx(styles.content, classNames?.content)}>
222
297
  {children}
223
298
  </main>
299
+ <div className={styles.mobileNav}>
300
+ {prev ? (
301
+ <RouterLink to={prev.url} className={styles.mobileNavLink}>
302
+ <ArrowLeftIcon width={16} height={16} />
303
+ <span className={styles.mobileNavLabel}>{prev.title}</span>
304
+ </RouterLink>
305
+ ) : <div />}
306
+ {next ? (
307
+ <RouterLink to={next.url} className={styles.mobileNavLink} data-direction='next'>
308
+ <span className={styles.mobileNavLabel}>{next.title}</span>
309
+ <ArrowRightIcon width={16} height={16} />
310
+ </RouterLink>
311
+ ) : <div />}
312
+ </div>
224
313
  </div>
225
314
  </div>
226
315
  </Flex>
@@ -184,3 +184,17 @@
184
184
  .headerLoader {
185
185
  margin-bottom: var(--rs-space-5);
186
186
  }
187
+
188
+ @media (max-width: 768px) {
189
+ .page {
190
+ gap: var(--rs-space-5);
191
+ }
192
+
193
+ .article {
194
+ max-width: 100%;
195
+ }
196
+
197
+ .title {
198
+ margin-bottom: var(--rs-space-5);
199
+ }
200
+ }