@raystack/chronicle 0.6.0 → 0.7.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/dist/cli/index.js +174 -3
- package/package.json +2 -2
- package/src/components/mdx/mermaid.tsx +21 -24
- package/src/lib/config.ts +5 -0
- package/src/lib/source.ts +12 -3
- package/src/pages/LandingPage.module.css +137 -24
- package/src/pages/LandingPage.tsx +23 -7
- package/src/server/entry-server.tsx +4 -1
- package/src/server/vite-config.ts +3 -0
- package/src/themes/paper/ChapterNav.module.css +23 -12
- package/src/themes/paper/ChapterNav.tsx +1 -17
- package/src/themes/paper/Layout.module.css +57 -16
- package/src/themes/paper/Layout.tsx +71 -17
- package/src/themes/paper/Page.module.css +89 -37
- package/src/themes/paper/Page.tsx +89 -53
- package/src/themes/paper/ReaderModeContext.tsx +28 -0
- package/src/themes/paper/ReadingProgress.tsx +1 -0
- package/src/themes/paper/fonts/DepartureMono-Regular.woff2 +0 -0
- package/src/themes/registry.ts +1 -1
- package/src/types/config.ts +1 -0
- package/src/types/content.ts +1 -0
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
ArrowLeftIcon,
|
|
3
|
+
ArrowRightIcon,
|
|
4
|
+
ChevronRightIcon,
|
|
5
|
+
AdjustmentsHorizontalIcon,
|
|
6
|
+
EyeIcon,
|
|
7
|
+
SunIcon,
|
|
8
|
+
MoonIcon,
|
|
9
|
+
XMarkIcon,
|
|
10
|
+
} from '@heroicons/react/24/outline';
|
|
11
|
+
import { IconButton, useTheme } from '@raystack/apsara';
|
|
12
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
13
|
import { Link as RouterLink, useLocation } from 'react-router';
|
|
5
14
|
import { getBreadcrumbItems } from 'fumadocs-core/breadcrumb';
|
|
6
15
|
import { flattenTree } from 'fumadocs-core/page-tree';
|
|
7
|
-
import { Search } from '@/components/ui/search';
|
|
8
16
|
import type { ThemePageProps } from '@/types';
|
|
9
17
|
import styles from './Page.module.css';
|
|
18
|
+
import { useReaderMode } from './ReaderModeContext';
|
|
10
19
|
import { ReadingProgress } from './ReadingProgress';
|
|
11
20
|
|
|
12
|
-
export function Page({ page,
|
|
21
|
+
export function Page({ page, tree }: ThemePageProps) {
|
|
13
22
|
const { pathname } = useLocation();
|
|
23
|
+
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
24
|
+
const [isClient, setIsClient] = useState(false);
|
|
25
|
+
const { resolvedTheme, setTheme } = useTheme();
|
|
26
|
+
const { readerMode, toggleReaderMode } = useReaderMode();
|
|
27
|
+
|
|
28
|
+
useEffect(() => { setIsClient(true); }, []);
|
|
14
29
|
|
|
15
30
|
const { prev, next, crumbs } = useMemo(() => {
|
|
16
31
|
const pages = flattenTree(tree.children);
|
|
@@ -32,47 +47,33 @@ export function Page({ page, config, tree }: ThemePageProps) {
|
|
|
32
47
|
|
|
33
48
|
return (
|
|
34
49
|
<>
|
|
35
|
-
<main className={styles.main}>
|
|
36
|
-
<
|
|
37
|
-
<
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
to={prev.url}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
className={styles.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
className={styles.arrow}
|
|
59
|
-
aria-label='Next page'
|
|
60
|
-
>
|
|
61
|
-
<ChevronRightIcon width={14} height={14} />
|
|
62
|
-
</RouterLink>
|
|
63
|
-
) : (
|
|
64
|
-
<button
|
|
65
|
-
disabled
|
|
66
|
-
className={styles.arrowDisabled}
|
|
67
|
-
aria-label='Next page'
|
|
68
|
-
>
|
|
69
|
-
<ChevronRightIcon width={14} height={14} />
|
|
70
|
-
</button>
|
|
71
|
-
)}
|
|
50
|
+
<main className={`${styles.main} ${readerMode ? styles.readerMode : ''}`}>
|
|
51
|
+
<div className={styles.navbar}>
|
|
52
|
+
<div className={styles.navLeft}>
|
|
53
|
+
<div className={styles.arrows}>
|
|
54
|
+
{prev ? (
|
|
55
|
+
<RouterLink to={prev.url} className={styles.arrowLink} aria-label='Previous page'>
|
|
56
|
+
<ArrowLeftIcon width={14} height={14} />
|
|
57
|
+
</RouterLink>
|
|
58
|
+
) : (
|
|
59
|
+
<span className={styles.arrowDisabled} aria-hidden='true'>
|
|
60
|
+
<ArrowLeftIcon width={14} height={14} />
|
|
61
|
+
</span>
|
|
62
|
+
)}
|
|
63
|
+
{next ? (
|
|
64
|
+
<RouterLink to={next.url} className={styles.arrowLink} aria-label='Next page'>
|
|
65
|
+
<ArrowRightIcon width={14} height={14} />
|
|
66
|
+
</RouterLink>
|
|
67
|
+
) : (
|
|
68
|
+
<span className={styles.arrowDisabled} aria-hidden='true'>
|
|
69
|
+
<ArrowRightIcon width={14} height={14} />
|
|
70
|
+
</span>
|
|
71
|
+
)}
|
|
72
|
+
</div>
|
|
72
73
|
<nav className={styles.breadcrumb}>
|
|
73
74
|
{crumbs.map((crumb, i) => (
|
|
74
75
|
<span key={crumb.href}>
|
|
75
|
-
{i > 0 && <
|
|
76
|
+
{i > 0 && <ChevronRightIcon width={12} height={12} className={styles.separator} />}
|
|
76
77
|
{i === crumbs.length - 1 ? (
|
|
77
78
|
<span className={styles.crumbActive}>{crumb.label}</span>
|
|
78
79
|
) : (
|
|
@@ -83,18 +84,53 @@ export function Page({ page, config, tree }: ThemePageProps) {
|
|
|
83
84
|
</span>
|
|
84
85
|
))}
|
|
85
86
|
</nav>
|
|
86
|
-
</
|
|
87
|
-
<
|
|
88
|
-
{
|
|
89
|
-
|
|
87
|
+
</div>
|
|
88
|
+
<div className={styles.navRight}>
|
|
89
|
+
{settingsOpen ? (
|
|
90
|
+
<>
|
|
91
|
+
<IconButton size={2} onClick={toggleReaderMode} aria-label='Toggle reader mode'>
|
|
92
|
+
<EyeIcon width={14} height={14} />
|
|
93
|
+
</IconButton>
|
|
94
|
+
{isClient && (
|
|
95
|
+
<IconButton
|
|
96
|
+
size={2}
|
|
97
|
+
onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
|
|
98
|
+
aria-label={resolvedTheme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme'}
|
|
99
|
+
>
|
|
100
|
+
{resolvedTheme === 'dark'
|
|
101
|
+
? <SunIcon width={14} height={14} />
|
|
102
|
+
: <MoonIcon width={14} height={14} />
|
|
103
|
+
}
|
|
104
|
+
</IconButton>
|
|
105
|
+
)}
|
|
106
|
+
<IconButton size={2} onClick={() => setSettingsOpen(false)} aria-label='Close settings'>
|
|
107
|
+
<XMarkIcon width={14} height={14} />
|
|
108
|
+
</IconButton>
|
|
109
|
+
</>
|
|
110
|
+
) : (
|
|
111
|
+
<IconButton size={2} onClick={() => setSettingsOpen(true)} aria-label='Open settings'>
|
|
112
|
+
<AdjustmentsHorizontalIcon width={14} height={14} />
|
|
113
|
+
</IconButton>
|
|
114
|
+
)}
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<div className={styles.content}>
|
|
118
|
+
<header className={styles.articleHeader}>
|
|
119
|
+
{page.frontmatter._readingTime && (
|
|
120
|
+
<span className={styles.readingTime}>{page.frontmatter._readingTime}min Read</span>
|
|
121
|
+
)}
|
|
122
|
+
<h1 className={styles.articleTitle}>{page.frontmatter.title}</h1>
|
|
123
|
+
{page.frontmatter.description && (
|
|
124
|
+
<p className={styles.articleDescription}>{page.frontmatter.description}</p>
|
|
90
125
|
)}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
126
|
+
<hr className={styles.articleSeparator} />
|
|
127
|
+
</header>
|
|
128
|
+
<article className={styles.article} data-article-content>
|
|
129
|
+
{page.content}
|
|
130
|
+
</article>
|
|
131
|
+
</div>
|
|
96
132
|
</main>
|
|
97
|
-
<ReadingProgress items={page.toc} />
|
|
133
|
+
{!readerMode && <ReadingProgress items={page.toc} />}
|
|
98
134
|
</>
|
|
99
135
|
);
|
|
100
136
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, useState, type ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
interface ReaderModeContextValue {
|
|
6
|
+
readerMode: boolean;
|
|
7
|
+
toggleReaderMode: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ReaderModeContext = createContext<ReaderModeContextValue>({
|
|
11
|
+
readerMode: false,
|
|
12
|
+
toggleReaderMode: () => {},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export function ReaderModeProvider({ children }: { children: ReactNode }) {
|
|
16
|
+
const [readerMode, setReaderMode] = useState(false);
|
|
17
|
+
return (
|
|
18
|
+
<ReaderModeContext.Provider
|
|
19
|
+
value={{ readerMode, toggleReaderMode: () => setReaderMode(v => !v) }}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</ReaderModeContext.Provider>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useReaderMode() {
|
|
27
|
+
return useContext(ReaderModeContext);
|
|
28
|
+
}
|
|
@@ -220,6 +220,7 @@ export function ReadingProgress({ items }: ReadingProgressProps) {
|
|
|
220
220
|
const element = document.getElementById(id);
|
|
221
221
|
if (!element) return;
|
|
222
222
|
|
|
223
|
+
history.pushState(null, '', `#${id}`);
|
|
223
224
|
const elementTop = element.getBoundingClientRect().top + window.scrollY;
|
|
224
225
|
window.scrollTo({
|
|
225
226
|
top: Math.max(0, elementTop - NAV_HEIGHT),
|
|
Binary file
|
package/src/themes/registry.ts
CHANGED
|
@@ -15,7 +15,7 @@ export function getTheme(name?: string): Theme {
|
|
|
15
15
|
|
|
16
16
|
export function getThemeConfig(name?: string) {
|
|
17
17
|
if (name === 'paper') {
|
|
18
|
-
return { enableSystem:
|
|
18
|
+
return { enableSystem: true };
|
|
19
19
|
}
|
|
20
20
|
return { enableSystem: true };
|
|
21
21
|
}
|
package/src/types/config.ts
CHANGED