@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.
@@ -1,21 +1,25 @@
1
1
  .nav {
2
2
  display: flex;
3
3
  flex-direction: column;
4
- gap: var(--rs-space-5);
4
+ gap: var(--rs-space-8);
5
5
  }
6
6
 
7
7
  .chapter {
8
8
  display: flex;
9
9
  flex-direction: column;
10
10
  gap: var(--rs-space-2);
11
+ margin-top: var(--rs-space-8);
11
12
  }
12
13
 
13
14
  .chapterLabel {
15
+ font-family: var(--paper-font-mono);
14
16
  font-size: var(--rs-font-size-small);
15
- font-weight: 600;
17
+ font-weight: var(--rs-font-weight-medium);
18
+ line-height: var(--rs-line-height-small);
19
+ letter-spacing: var(--rs-letter-spacing-small);
16
20
  text-transform: uppercase;
17
- letter-spacing: 0.05em;
18
- color: var(--rs-color-foreground-base-primary);
21
+ color: var(--rs-color-foreground-base-secondary);
22
+ padding: 0 var(--rs-space-3);
19
23
  white-space: nowrap;
20
24
  overflow: hidden;
21
25
  text-overflow: ellipsis;
@@ -27,30 +31,32 @@
27
31
  margin: 0;
28
32
  display: flex;
29
33
  flex-direction: column;
30
- gap: var(--rs-space-1);
31
- padding-left: var(--rs-space-4);
32
34
  }
33
35
 
34
36
  .link {
35
37
  display: flex;
36
38
  align-items: center;
37
- gap: var(--rs-space-2);
39
+ gap: var(--rs-space-3);
40
+ font-family: var(--paper-font-body);
38
41
  font-size: var(--rs-font-size-small);
39
- color: var(--rs-color-foreground-base-tertiary);
42
+ font-weight: var(--rs-font-weight-regular);
43
+ line-height: var(--rs-line-height-small);
44
+ letter-spacing: var(--rs-letter-spacing-small);
45
+ color: var(--rs-color-foreground-base-primary);
40
46
  text-decoration: none;
41
- padding: var(--rs-space-1) 0;
47
+ padding: var(--rs-space-3);
48
+ border-radius: var(--rs-radius-2);
42
49
  white-space: nowrap;
43
50
  overflow: hidden;
44
51
  text-overflow: ellipsis;
45
52
  }
46
53
 
47
54
  .link:hover {
48
- color: var(--rs-color-foreground-base-primary);
55
+ color: var(--rs-color-foreground-accent-primary);
49
56
  }
50
57
 
51
58
  .active {
52
59
  color: var(--rs-color-foreground-accent-primary);
53
- font-weight: 500;
54
60
  }
55
61
 
56
62
  .icon {
@@ -60,9 +66,14 @@
60
66
  }
61
67
 
62
68
  .subLabel {
69
+ font-family: var(--paper-font-mono);
63
70
  font-size: var(--rs-font-size-small);
64
- font-weight: 500;
71
+ font-weight: var(--rs-font-weight-medium);
72
+ line-height: var(--rs-line-height-small);
73
+ letter-spacing: var(--rs-letter-spacing-small);
74
+ text-transform: uppercase;
65
75
  color: var(--rs-color-foreground-base-secondary);
76
+ padding: 0 var(--rs-space-3);
66
77
  margin-top: var(--rs-space-3);
67
78
  display: block;
68
79
  white-space: nowrap;
@@ -15,23 +15,8 @@ interface ChapterNavProps {
15
15
  tree: Root;
16
16
  }
17
17
 
18
- function buildChapterIndices(
19
- children: Node[]
20
- ): Map<Node, number> {
21
- const indices = new Map<Node, number>();
22
- let index = 0;
23
- for (const item of children) {
24
- if (item.type === 'folder') {
25
- index++;
26
- indices.set(item, index);
27
- }
28
- }
29
- return indices;
30
- }
31
-
32
18
  export function ChapterNav({ tree }: ChapterNavProps) {
33
19
  const { pathname } = useLocation();
34
- const chapterIndices = buildChapterIndices(tree.children);
35
20
 
36
21
  return (
37
22
  <nav className={styles.nav}>
@@ -40,11 +25,10 @@ export function ChapterNav({ tree }: ChapterNavProps) {
40
25
  if (item.type === 'separator') return null;
41
26
 
42
27
  if (item.type === 'folder') {
43
- const chapterIndex = chapterIndices.get(item) ?? 0;
44
28
  return (
45
29
  <li key={item.name?.toString()} className={styles.chapter}>
46
30
  <span className={styles.chapterLabel}>
47
- {String(chapterIndex).padStart(2, '0')}. {item.name}
31
+ {item.name}
48
32
  </span>
49
33
  <ul className={styles.chapterItems}>
50
34
  {item.children.map(child => (
@@ -1,5 +1,17 @@
1
+ @import url("https://fonts.googleapis.com/css2?family=Hanuman:wght@400;700&display=swap");
2
+
3
+ @font-face {
4
+ font-family: "Departure Mono";
5
+ src: url("./fonts/DepartureMono-Regular.woff2") format("woff2");
6
+ font-weight: 400;
7
+ font-style: normal;
8
+ font-display: swap;
9
+ }
10
+
1
11
  .layout {
2
- --paper-sidebar-width: 260px;
12
+ --paper-sidebar-width: 262px;
13
+ --paper-font-mono: "Departure Mono", "SF Mono", "Fira Code", monospace;
14
+ --paper-font-body: "Hanuman", sans-serif;
3
15
 
4
16
  min-height: 100vh;
5
17
  }
@@ -8,33 +20,62 @@
8
20
  flex: 1;
9
21
  }
10
22
 
23
+ :global(body) {
24
+ background: var(--rs-color-background-neutral-primary);
25
+ }
26
+
11
27
  .sidebar {
12
28
  width: var(--paper-sidebar-width);
13
- padding: var(--rs-space-7) var(--rs-space-5);
29
+ display: flex;
30
+ flex-direction: column;
31
+ height: 100vh;
32
+ position: sticky;
33
+ top: 0;
14
34
  background: var(--rs-color-background-neutral-primary);
15
- overflow-y: auto;
16
- font-family: "SF Mono", "Fira Code", "Fira Mono", "Roboto Mono", monospace;
17
35
  }
18
36
 
19
- .title {
37
+ .header {
38
+ display: flex;
39
+ align-items: center;
40
+ height: 48px;
41
+ padding: 0 var(--rs-space-5);
42
+ flex-shrink: 0;
43
+ }
44
+
45
+ .contentDirTrigger {
46
+ border: none;
47
+ outline: none;
48
+ background: var(--rs-color-background-neutral-primary);
49
+ color: var(--rs-color-foreground-accent-primary);
50
+ font-family: var(--paper-font-mono);
51
+ font-size: var(--rs-font-size-regular);
52
+ font-weight: var(--rs-font-weight-medium);
53
+ line-height: var(--rs-line-height-mini);
54
+ letter-spacing: var(--rs-letter-spacing-mini);
20
55
  text-transform: uppercase;
21
- letter-spacing: 0.08em;
56
+ }
57
+
58
+ .title {
59
+ font-size: var(--rs-font-size-regular);
60
+ letter-spacing: var(--rs-letter-spacing-mini);
22
61
  color: var(--rs-color-foreground-accent-primary);
23
- font-family: inherit;
24
- font-size: var(--rs-font-size-mono-large);
25
- margin-bottom: var(--rs-space-7);
62
+ font-family: var(--paper-font-mono);
63
+ text-transform: uppercase;
26
64
  }
27
65
 
28
- .nav {
29
- display: flex;
30
- flex-direction: column;
31
- gap: var(--rs-space-3);
32
- margin-bottom: var(--rs-space-7);
66
+ .navScroll {
67
+ flex: 1;
68
+ overflow-y: auto;
69
+ padding: var(--rs-space-5) var(--rs-space-5);
70
+ }
71
+
72
+ .footer {
73
+ flex-shrink: 0;
74
+ padding: var(--rs-space-4) var(--rs-space-5);
75
+ border-top: 1px solid var(--rs-color-border-base-primary);
33
76
  }
34
77
 
35
78
  .content {
36
79
  flex: 1;
37
- overflow-y: auto;
38
80
  background: var(--rs-color-background-neutral-primary);
39
- padding-right: var(--paper-sidebar-width);
40
81
  }
@@ -1,40 +1,86 @@
1
1
  'use client';
2
2
 
3
- import { Flex, Headline } from '@raystack/apsara';
3
+ import { Flex, Select, Text } from '@raystack/apsara';
4
4
  import { cx } from 'class-variance-authority';
5
+ import { useLocation, useNavigate } from 'react-router';
6
+ import { getLandingEntries } from '@/lib/config';
7
+ import { getActiveContentDir } from '@/lib/navigation';
8
+ import { usePageContext } from '@/lib/page-context';
5
9
  import type { ThemeLayoutProps } from '@/types';
6
10
  import { ChapterNav } from './ChapterNav';
7
- import { ContentDirDropdown } from './ContentDirDropdown';
8
11
  import styles from './Layout.module.css';
12
+ import { ReaderModeProvider, useReaderMode } from './ReaderModeContext';
9
13
  import { VersionSwitcher } from './VersionSwitcher';
10
14
 
11
- export function Layout({
15
+ function SidebarHeader({ config }: { config: ThemeLayoutProps['config'] }) {
16
+ const { version } = usePageContext();
17
+ const { pathname } = useLocation();
18
+ const navigate = useNavigate();
19
+
20
+ const entries = getLandingEntries(config, version.dir);
21
+
22
+ if (entries.length <= 1) {
23
+ return (
24
+ <Text size={2} weight={500} className={styles.title}>
25
+ {config.site.title}
26
+ </Text>
27
+ );
28
+ }
29
+
30
+ const activeDir = getActiveContentDir(pathname, config);
31
+ const activeEntry =
32
+ entries.find(e => e.contentDir === activeDir) ?? entries[0];
33
+
34
+ return (
35
+ <Select
36
+ value={activeEntry.contentDir}
37
+ onValueChange={(val: string) => {
38
+ const entry = entries.find(e => e.contentDir === val);
39
+ if (entry) navigate(entry.href);
40
+ }}
41
+ >
42
+ <Select.Trigger size='small' className={styles.contentDirTrigger}>
43
+ <Select.Value placeholder={activeEntry.label} className={styles.title} />
44
+ </Select.Trigger>
45
+ <Select.Content>
46
+ {entries.map(entry => (
47
+ <Select.Item key={entry.href} value={entry.contentDir}>
48
+ {entry.label}
49
+ </Select.Item>
50
+ ))}
51
+ </Select.Content>
52
+ </Select>
53
+ );
54
+ }
55
+
56
+ function LayoutInner({
12
57
  children,
13
58
  config,
14
59
  tree,
15
60
  hideSidebar,
16
61
  classNames
17
62
  }: ThemeLayoutProps) {
63
+ const { readerMode } = useReaderMode();
64
+ const showSidebar = !hideSidebar && !readerMode;
65
+
18
66
  return (
19
67
  <Flex direction='column' className={cx(styles.layout, classNames?.layout)}>
20
68
  <Flex className={cx(styles.body, classNames?.body)}>
21
- {hideSidebar ? null : (
69
+ {showSidebar ? (
22
70
  <aside className={cx(styles.sidebar, classNames?.sidebar)}>
23
- <Headline
24
- size='small'
25
- weight='medium'
26
- as='h1'
27
- className={styles.title}
28
- >
29
- {config.site.title}
30
- </Headline>
31
- <div className={styles.nav}>
32
- <VersionSwitcher />
33
- <ContentDirDropdown />
71
+ <div className={styles.header}>
72
+ <SidebarHeader config={config} />
34
73
  </div>
35
- <ChapterNav tree={tree} />
74
+ <div className={styles.navScroll}>
75
+ <ChapterNav tree={tree} />
76
+ </div>
77
+ {config.versions?.length ? (
78
+ <div className={styles.footer}>
79
+ <VersionSwitcher />
80
+ </div>
81
+ ) : null}
36
82
  </aside>
37
- )}
83
+ ) : null}
38
84
  <div className={cx(styles.content, classNames?.content)}>
39
85
  {children}
40
86
  </div>
@@ -42,3 +88,11 @@ export function Layout({
42
88
  </Flex>
43
89
  );
44
90
  }
91
+
92
+ export function Layout(props: ThemeLayoutProps) {
93
+ return (
94
+ <ReaderModeProvider>
95
+ <LayoutInner {...props} />
96
+ </ReaderModeProvider>
97
+ );
98
+ }
@@ -1,76 +1,89 @@
1
1
  .main {
2
- --paper-navbar-height: 40px;
3
- --paper-navbar-padding: var(--rs-space-3);
4
- --paper-navbar-total: calc(
5
- var(--paper-navbar-height) +
6
- var(--paper-navbar-padding) *
7
- 2 +
8
- 1px
9
- );
10
-
11
2
  flex: 1;
12
- max-width: 1024px;
3
+ width: 90%;
4
+ max-width: calc(1024px + var(--rs-space-17));
5
+ margin: 0 auto;
6
+ padding-top: var(--rs-space-12);
7
+ padding-right: var(--rs-space-17);
8
+ }
9
+
10
+ .readerMode {
11
+ padding-right: 0;
13
12
  margin: 0 auto;
14
13
  }
15
14
 
16
15
  .navbar {
17
- height: var(--paper-navbar-height);
18
- padding: var(--paper-navbar-padding) 0;
19
- border-bottom: 1px solid var(--rs-color-border-base-primary);
16
+ display: flex;
17
+ align-items: center;
20
18
  justify-content: space-between;
21
- width: 100%;
22
- position: fixed;
23
- top: 0;
19
+ height: 48px;
20
+ padding: var(--rs-space-2) var(--rs-space-7);
24
21
  background: var(--rs-color-background-neutral-primary);
22
+ backdrop-filter: blur(8px);
23
+ border-bottom: 0.5px solid var(--rs-color-border-base-primary);
24
+ position: sticky;
25
+ top: 0;
25
26
  z-index: 10;
26
- max-width: 1024px;
27
27
  }
28
28
 
29
29
  .navLeft {
30
+ display: flex;
30
31
  align-items: center;
32
+ gap: var(--rs-space-3);
31
33
  }
32
34
 
33
35
  .navRight {
36
+ display: flex;
34
37
  align-items: center;
38
+ gap: var(--rs-space-3);
35
39
  }
36
40
 
37
- .arrow {
41
+ .arrows {
38
42
  display: flex;
39
43
  align-items: center;
40
- color: var(--rs-color-foreground-base-primary);
44
+ gap: var(--rs-space-2);
45
+ }
46
+
47
+ .arrowLink {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
41
51
  text-decoration: none;
52
+ color: var(--rs-color-foreground-base-primary);
53
+ padding: var(--rs-space-1);
54
+ border-radius: var(--rs-radius-2);
42
55
  }
43
56
 
44
- .arrow:hover {
57
+ .arrowLink:hover {
45
58
  color: var(--rs-color-foreground-accent-primary);
46
59
  }
47
60
 
48
61
  .arrowDisabled {
49
62
  display: flex;
50
63
  align-items: center;
64
+ justify-content: center;
51
65
  color: var(--rs-color-foreground-base-tertiary);
52
66
  opacity: 0.4;
53
- cursor: default;
54
- border: none;
55
- background: none;
56
- padding: 0;
67
+ padding: var(--rs-space-1);
57
68
  }
58
69
 
59
70
  .breadcrumb {
60
- font-family: "SF Mono", "Fira Code", monospace;
71
+ display: flex;
72
+ align-items: center;
73
+ font-family: var(--paper-font-mono);
61
74
  font-size: var(--rs-font-size-small);
62
- text-transform: uppercase;
63
- letter-spacing: 0.05em;
64
- margin-left: var(--rs-space-3);
75
+ line-height: var(--rs-line-height-small);
76
+ letter-spacing: var(--rs-letter-spacing-small);
65
77
  }
66
78
 
67
79
  .separator {
68
- margin: 0 var(--rs-space-2);
80
+ margin: 0 var(--rs-space-1);
69
81
  color: var(--rs-color-foreground-base-tertiary);
70
82
  }
71
83
 
72
84
  .crumbLink {
73
85
  color: var(--rs-color-foreground-base-tertiary);
86
+ font-weight: var(--rs-font-weight-medium);
74
87
  text-decoration: none;
75
88
  }
76
89
 
@@ -80,29 +93,67 @@
80
93
 
81
94
  .crumbActive {
82
95
  color: var(--rs-color-foreground-base-primary);
83
- font-weight: 600;
96
+ font-weight: var(--rs-font-weight-medium);
84
97
  }
85
98
 
86
99
  .article {
87
100
  flex: 1;
88
101
  min-width: 0;
89
- margin-top: var(--paper-navbar-total);
102
+ width: 100%;
90
103
  padding: 0 var(--rs-space-7);
91
104
  }
92
105
 
93
- .searchButton {
94
- height: 28px;
95
- padding: 0 var(--rs-space-3);
106
+ .articleHeader {
107
+ text-align: center;
108
+ max-width: 656px;
109
+ margin: 0 auto;
110
+ }
111
+
112
+ .readingTime {
113
+ display: block;
114
+ font-family: var(--paper-font-mono);
96
115
  font-size: var(--rs-font-size-small);
116
+ font-weight: var(--rs-font-weight-regular);
117
+ line-height: 1.67;
118
+ letter-spacing: var(--rs-letter-spacing-t1);
119
+ color: var(--rs-color-foreground-base-tertiary);
120
+ margin-bottom: var(--rs-space-5);
121
+ }
122
+
123
+ .articleTitle {
124
+ font-family: var(--paper-font-body);
125
+ font-size: var(--rs-space-8);
126
+ font-weight: var(--rs-font-weight-medium);
127
+ line-height: var(--rs-space-10);
128
+ letter-spacing: var(--rs-letter-spacing-t1);
129
+ text-align: center;
130
+ color: var(--rs-color-foreground-base-primary);
131
+ margin: 0;
132
+ }
133
+
134
+ .articleSeparator {
135
+ width: 55px;
97
136
  border: none;
98
- box-shadow: none;
137
+ border-top: 1px solid var(--rs-color-border-base-primary);
138
+ margin: var(--rs-space-10) auto;
139
+ }
140
+
141
+ .articleDescription {
142
+ font-family: var(--paper-font-body);
143
+ font-size: var(--rs-space-4);
144
+ font-weight: var(--rs-font-weight-medium);
145
+ line-height: var(--rs-space-7);
146
+ letter-spacing: var(--rs-letter-spacing-t1);
147
+ text-align: center;
148
+ color: var(--rs-color-foreground-base-secondary);
149
+ margin: var(--rs-space-4) 0 0;
99
150
  }
100
151
 
101
152
  .content {
102
- font-family: Georgia, "Times New Roman", serif;
153
+ font-family: var(--paper-font-body);
103
154
  line-height: 1.8;
104
155
  background: var(--rs-color-background-base-primary);
105
- padding: var(--rs-space-9);
156
+ padding: var(--rs-space-15) var(--rs-space-9) var(--rs-space-9);
106
157
  border-left: 1px solid var(--rs-color-border-base-primary);
107
158
  border-right: 1px solid var(--rs-color-border-base-primary);
108
159
  box-shadow:
@@ -152,6 +203,7 @@
152
203
 
153
204
  .content p {
154
205
  margin: 0.75rem 0;
206
+ line-height: 2;
155
207
  }
156
208
 
157
209
  .content ul,