@knitli/docs-components 1.0.3 → 1.1.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,231 +1,8 @@
1
1
  ---
2
- // Custom header with actual Knitli logo
3
- const { pathname } = Astro.url;
4
-
5
- // Environment-aware URL configuration
6
- const isDev = import.meta.env.DEV;
7
-
8
- const getSiteUrls = () => {
9
- if (isDev) {
10
- return {
11
- marketing: import.meta.env.PUBLIC_MARKETING_URL || 'http://localhost:4321',
12
- blog: import.meta.env.PUBLIC_BLOG_URL || 'http://localhost:4322',
13
- docs: import.meta.env.PUBLIC_DOCS_URL || 'http://localhost:4323',
14
- };
15
- }
16
-
17
- return {
18
- marketing: 'https://knitli.com',
19
- blog: 'https://blog.knitli.com',
20
- docs: 'https://docs.knitli.com',
21
- };
22
- };
23
-
24
- const urls = getSiteUrls();
25
- const isDocsHome = pathname === '/' || pathname === '';
26
- const shouldShowBreadcrumb = !isDocsHome;
27
-
2
+ // DEPRECATED This component has been removed.
3
+ // Use PageFrame.astro instead:
4
+ // starlight({ components: { PageFrame: '@knitli/docs-components/PageFrame.astro' } })
5
+ throw new Error(
6
+ '@knitli/docs-components: DocsHeader has been removed. Use PageFrame.astro instead.'
7
+ );
28
8
  ---
29
-
30
- <header class="docs-header">
31
- <div class="docs-header-content">
32
- <!-- Knitli Logo + Docs Section -->
33
- <a href={urls.marketing} class="docs-logo" aria-label="Knitli home">
34
- <img src={`${import.meta.env.BASE_URL}/knitli-logo.svg`} alt="Knitli" class="logo-icon" />
35
- <span class="logo-text">
36
- <span class="logo-separator">/</span>
37
- <span class="logo-section">docs</span>
38
- </span>
39
- </a>
40
-
41
- <!-- Breadcrumb -->
42
- {shouldShowBreadcrumb && (
43
- <nav class="docs-breadcrumb" aria-label="Breadcrumb">
44
- <a href="/">Documentation</a>
45
- <span class="breadcrumb-separator" aria-hidden="true">→</span>
46
- <a href="/ReCoco" class="breadcrumb-product">
47
- ReCoco
48
- </a>
49
- </nav>
50
- )}
51
-
52
- <div class="spacer"></div>
53
-
54
- <!-- Cross-site Navigation -->
55
- <nav class="docs-nav" aria-label="Site navigation">
56
- <a
57
- href="/"
58
- class:list={[{ active: isDocsHome }]}
59
- aria-current={isDocsHome ? 'page' : undefined}
60
- >
61
- Docs Home
62
- </a>
63
- <a href={urls.marketing}>
64
- Main Site
65
- </a>
66
- <a href={urls.blog}>
67
- Blog
68
- </a>
69
- <a
70
- href="https://github.com/knitli"
71
- class="external"
72
- target="_blank"
73
- rel="noopener noreferrer"
74
- aria-label="Knitli on GitHub (opens in new tab)"
75
- >
76
- GitHub
77
- <span class="external-icon" aria-hidden="true">↗</span>
78
- </a>
79
- </nav>
80
- </div>
81
- </header>
82
-
83
- <style>
84
- .docs-header {
85
- background: white;
86
- border-bottom: 1px solid #e5e7eb;
87
- border-radius: 0 0 6px 2px; /* Chamfered bottom corners only */
88
- position: sticky;
89
- top: 0;
90
- z-index: 100;
91
- }
92
-
93
- .docs-header-content {
94
- max-width: 1400px;
95
- margin: 0 auto;
96
- padding: 1rem 2rem;
97
- display: flex;
98
- align-items: center;
99
- gap: 2rem;
100
- }
101
-
102
- .docs-logo {
103
- display: flex;
104
- align-items: center;
105
- gap: 0.5rem;
106
- text-decoration: none;
107
- transition: opacity 0.2s ease;
108
- }
109
-
110
- .docs-logo:hover {
111
- opacity: 0.8;
112
- }
113
-
114
- .logo-icon {
115
- height: 32px;
116
- width: auto;
117
- flex-shrink: 0;
118
- }
119
-
120
- .logo-text {
121
- font-family: system-ui, -apple-system, sans-serif;
122
- font-size: 1.125rem;
123
- font-weight: 600;
124
- line-height: 1;
125
- color: #374151;
126
- }
127
-
128
- .logo-separator {
129
- color: #9ca3af;
130
- margin: 0 0.5rem;
131
- }
132
-
133
- .logo-section {
134
- color: #6b7280;
135
- }
136
-
137
- .docs-breadcrumb {
138
- display: flex;
139
- align-items: center;
140
- align-self: flex-end;
141
- gap: 0.5rem;
142
- font-size: 0.875rem;
143
- color: #6b7280;
144
- }
145
-
146
- .docs-breadcrumb a {
147
- color: inherit;
148
- text-decoration: none;
149
- transition: color 0.2s ease;
150
- }
151
-
152
- .docs-breadcrumb a:hover {
153
- color: #111827;
154
- text-decoration: underline;
155
- }
156
-
157
- .breadcrumb-separator {
158
- opacity: 0.5;
159
- }
160
-
161
- .breadcrumb-product {
162
- font-weight: 500;
163
- color: #111827;
164
- }
165
-
166
- .spacer {
167
- flex: 1;
168
- }
169
-
170
- .docs-nav {
171
- display: flex;
172
- gap: 2rem;
173
- align-items: center;
174
- }
175
-
176
- .docs-nav a {
177
- font-size: 0.9375rem;
178
- color: #374151;
179
- text-decoration: none;
180
- position: relative;
181
- padding: 0.25rem 0;
182
- transition: color 0.2s ease;
183
- }
184
-
185
- .docs-nav a:hover {
186
- color: #111827;
187
- }
188
-
189
- .docs-nav a.active {
190
- color: #111827;
191
- font-weight: 500;
192
- }
193
-
194
- .docs-nav a.external {
195
- display: inline-flex;
196
- align-items: center;
197
- gap: 0.25rem;
198
- }
199
-
200
- .external-icon {
201
- font-size: 0.75em;
202
- opacity: 0.6;
203
- }
204
-
205
- /* Mobile Responsive */
206
- @media (max-width: 768px) {
207
- .docs-header-content {
208
- flex-wrap: wrap;
209
- padding: 1rem;
210
- gap: 1rem;
211
- }
212
-
213
- .docs-breadcrumb {
214
- order: 3;
215
- width: 100%;
216
- }
217
-
218
- .spacer {
219
- display: none;
220
- }
221
-
222
- .docs-nav {
223
- gap: 1rem;
224
- font-size: 0.875rem;
225
- }
226
-
227
- .logo-icon {
228
- height: 28px;
229
- }
230
- }
231
- </style>
@@ -0,0 +1,244 @@
1
+ ---
2
+ // SPDX-FileCopyrightText: 2025 Knitli Inc.
3
+ // SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
4
+ //
5
+ // SPDX-License-Identifier: MIT OR Apache-2.0
6
+ //
7
+ // Starlight Footer override for Knitli product documentation sites.
8
+ // Renders Starlight's native page-level footer (edit link, last updated,
9
+ // pagination, optional credits) followed by the Knitli site footer.
10
+ //
11
+ // Usage in astro.config.mjs:
12
+ // starlight({ components: { Footer: '@knitli/docs-components/Footer.astro' } })
13
+
14
+ // @ts-expect-error: virtual modules are typed in virtual-internal.d.ts (not in Starlight's public exports map)
15
+ import EditLink from 'virtual:starlight/components/EditLink';
16
+ // @ts-expect-error
17
+ import LastUpdated from 'virtual:starlight/components/LastUpdated';
18
+ // @ts-expect-error
19
+ import Pagination from 'virtual:starlight/components/Pagination';
20
+ // @ts-expect-error
21
+ import config from 'virtual:starlight/user-config';
22
+ import { Icon } from '@astrojs/starlight/components';
23
+
24
+ const currentYear = new Date().getFullYear();
25
+ ---
26
+
27
+ <footer class="sl-flex knitli-page-footer">
28
+
29
+ <!-- Starlight's native page-level footer: edit link, last updated, pagination, optional credits -->
30
+ <div class="sl-flex page-actions">
31
+ <div class="meta sl-flex">
32
+ <EditLink />
33
+ <LastUpdated />
34
+ </div>
35
+ <Pagination />
36
+ {config.credits && (
37
+ <a class="kudos sl-flex" href="https://starlight.astro.build">
38
+ <Icon name="starlight" /> {Astro.locals.t('builtWithStarlight.label')}
39
+ </a>
40
+ )}
41
+ </div>
42
+
43
+ <!-- Knitli site footer -->
44
+ <div class="site-footer sl-flex">
45
+ <div class="footer-content sl-flex">
46
+
47
+ <div class="footer-brand">
48
+ <p class="copyright">© {currentYear} Knitli, Inc. All rights reserved.</p>
49
+ <div class="social-links sl-flex">
50
+ <a href="https://github.com/knitli" aria-label="GitHub" class="social-link" target="_blank" rel="noopener noreferrer">
51
+ <Icon name="github" size="1.1rem" />
52
+ </a>
53
+ <a href="https://x.com/knitli_inc" aria-label="X" class="social-link" target="_blank" rel="noopener noreferrer">
54
+ <Icon name="x.com" size="1.1rem" />
55
+ </a>
56
+ <a href="https://bsky.app/profile/knitli.com" aria-label="Bluesky" class="social-link" target="_blank" rel="noopener noreferrer">
57
+ <Icon name="blueSky" size="1.1rem" />
58
+ </a>
59
+ <a href="https://linkedin.com/company/knitli" aria-label="LinkedIn" class="social-link" target="_blank" rel="noopener noreferrer">
60
+ <Icon name="linkedin" size="1.1rem" />
61
+ </a>
62
+ </div>
63
+ </div>
64
+
65
+ <nav class="footer-nav" aria-label="Knitli">
66
+ <p class="nav-heading">Knitli</p>
67
+ <ul>
68
+ <li><a href="https://knitli.com">knitli.com</a></li>
69
+ <li><a href="https://blog.knitli.com">Blog</a></li>
70
+ </ul>
71
+ </nav>
72
+
73
+ <nav class="footer-nav" aria-label="Documentation">
74
+ <p class="nav-heading">Docs</p>
75
+ <ul>
76
+ <li><a href="https://docs.knitli.com">Developer Docs</a></li>
77
+ <li><a href="https://docs.knitli.com/ReCoco">ReCoco</a></li>
78
+ <li>
79
+ <span class="link-disabled">
80
+ CodeWeaver
81
+ <span class="soon-badge">soon</span>
82
+ </span>
83
+ </li>
84
+ <li>
85
+ <a href="https://docs.rs/thread" target="_blank" rel="noopener noreferrer">
86
+ Thread ↗
87
+ </a>
88
+ </li>
89
+ </ul>
90
+ </nav>
91
+
92
+ </div>
93
+ </div>
94
+
95
+ </footer>
96
+
97
+ <style>
98
+ @layer starlight.core {
99
+ /* ---- Outer wrapper ---- */
100
+ .knitli-page-footer {
101
+ flex-direction: column;
102
+ gap: 0;
103
+ }
104
+
105
+ /* ---- Starlight native page actions (replicated from Starlight's Footer) ---- */
106
+ .page-actions {
107
+ flex-direction: column;
108
+ gap: 1.5rem;
109
+ }
110
+
111
+ .meta {
112
+ gap: 0.75rem 3rem;
113
+ justify-content: space-between;
114
+ flex-wrap: wrap;
115
+ margin-top: 3rem;
116
+ font-size: var(--sl-text-sm);
117
+ color: var(--sl-color-gray-3);
118
+ }
119
+
120
+ .meta > :global(p:only-child) {
121
+ margin-inline-start: auto;
122
+ }
123
+
124
+ .kudos {
125
+ align-items: center;
126
+ gap: 0.5em;
127
+ margin: 1.5rem auto;
128
+ font-size: var(--sl-text-xs);
129
+ text-decoration: none;
130
+ color: var(--sl-color-gray-3);
131
+ }
132
+
133
+ .kudos:hover {
134
+ color: var(--sl-color-white);
135
+ }
136
+
137
+ /* ---- Knitli site footer ---- */
138
+ .site-footer {
139
+ flex-direction: column;
140
+ border-top: 1px solid var(--sl-color-gray-5);
141
+ padding-top: 2rem;
142
+ margin-top: 2rem;
143
+ gap: 1.5rem;
144
+ }
145
+
146
+ .footer-content {
147
+ flex-wrap: wrap;
148
+ gap: 2rem 4rem;
149
+ align-items: flex-start;
150
+ }
151
+
152
+ .footer-brand {
153
+ flex: 1;
154
+ min-width: 200px;
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 0.75rem;
158
+ }
159
+
160
+ .copyright {
161
+ margin: 0;
162
+ font-size: var(--sl-text-sm);
163
+ color: var(--sl-color-gray-3);
164
+ }
165
+
166
+ .social-links {
167
+ gap: 0.75rem;
168
+ align-items: center;
169
+ }
170
+
171
+ .social-link {
172
+ display: flex;
173
+ align-items: center;
174
+ color: var(--sl-color-gray-3);
175
+ text-decoration: none;
176
+ transition: color 0.2s ease;
177
+ }
178
+
179
+ .social-link:hover {
180
+ color: var(--sl-color-accent-high);
181
+ }
182
+
183
+ .footer-nav {
184
+ display: flex;
185
+ flex-direction: column;
186
+ gap: 0.5rem;
187
+ }
188
+
189
+ .nav-heading {
190
+ margin: 0 0 0.5rem;
191
+ font-size: var(--sl-text-xs);
192
+ font-weight: 600;
193
+ text-transform: uppercase;
194
+ letter-spacing: 0.08em;
195
+ color: var(--sl-color-accent);
196
+ }
197
+
198
+ .footer-nav ul {
199
+ list-style: none;
200
+ padding: 0;
201
+ margin: 0;
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: 0.4rem;
205
+ }
206
+
207
+ .footer-nav a {
208
+ font-size: var(--sl-text-sm);
209
+ color: var(--sl-color-gray-2);
210
+ text-decoration: none;
211
+ transition: color 0.2s ease;
212
+ }
213
+
214
+ .footer-nav a:hover {
215
+ color: var(--sl-color-accent-high);
216
+ }
217
+
218
+ .link-disabled {
219
+ font-size: var(--sl-text-sm);
220
+ color: var(--sl-color-gray-4);
221
+ display: flex;
222
+ align-items: center;
223
+ gap: 0.4rem;
224
+ }
225
+
226
+ .soon-badge {
227
+ font-size: var(--sl-text-xs);
228
+ padding: 0.1em 0.4em;
229
+ border-radius: 3px;
230
+ background: var(--sl-color-accent-low);
231
+ color: var(--sl-color-accent-high);
232
+ font-weight: 600;
233
+ letter-spacing: 0.05em;
234
+ text-transform: uppercase;
235
+ }
236
+ }
237
+
238
+ @layer starlight.components {
239
+ /* Starlight icon color in the kudos link */
240
+ .kudos :global(svg) {
241
+ color: var(--sl-color-orange);
242
+ }
243
+ }
244
+ </style>
@@ -0,0 +1,189 @@
1
+ ---
2
+ // SPDX-FileCopyrightText: 2025 Knitli Inc.
3
+ // SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
4
+ //
5
+ // SPDX-License-Identifier: MIT OR Apache-2.0
6
+ //
7
+ // Starlight PageFrame override for Knitli product documentation sites.
8
+ // Adds the cross-site subnav bar (with breadcrumb) above the Starlight header.
9
+ //
10
+ // Usage in astro.config.mjs:
11
+ // starlight({ components: { PageFrame: '@knitli/docs-components/PageFrame.astro' } })
12
+ //
13
+ // Required env variable: PUBLIC_DOCS_PRODUCT = 'ReCoco' | 'CodeWeaver' | 'Thread'
14
+ // The --sl-subnav-height CSS variable defaults to 2rem if not set in customCss.
15
+
16
+ // @ts-expect-error: virtual:starlight/components/* are typed in virtual-internal.d.ts,
17
+ // which is not in Starlight's public exports map
18
+ import MobileMenuToggle from 'virtual:starlight/components/MobileMenuToggle';
19
+ import DocsBreadcrumb from './DocsBreadcrumb.astro';
20
+
21
+ const { hasSidebar } = Astro.locals.starlightRoute;
22
+
23
+ const product = import.meta.env.PUBLIC_DOCS_PRODUCT as
24
+ | 'ReCoco'
25
+ | 'CodeWeaver'
26
+ | 'Thread'
27
+ | undefined;
28
+
29
+ // Strip the configured base URL to get the within-product path for the breadcrumb.
30
+ // e.g. for base='/ReCoco/' and pathname='/ReCoco/guide/start', path = 'guide/start'
31
+ const basePath = (import.meta.env.BASE_URL ?? '/').replace(/\/?$/, '/');
32
+ const currentPath = Astro.url.pathname
33
+ .slice(basePath.length)
34
+ .replace(/^\//, '');
35
+ ---
36
+
37
+ <div class="page sl-flex">
38
+
39
+ <nav class="knitli-subnav sl-flex" aria-label="Knitli">
40
+ {product && (
41
+ <div class="subnav-breadcrumb">
42
+ <DocsBreadcrumb
43
+ product={product}
44
+ productUrl={basePath}
45
+ path={currentPath}
46
+ variant="inline"
47
+ />
48
+ </div>
49
+ )}
50
+ <div class="subnav-links sl-flex">
51
+ <a href="https://knitli.com" class="subnav-link">Knitli Home</a>
52
+ <a href="https://blog.knitli.com" class="subnav-link">Blog</a>
53
+ </div>
54
+ </nav>
55
+
56
+ <header class="header"><slot name="header" /></header>
57
+
58
+ {
59
+ hasSidebar && (
60
+ <nav class="sidebar print:hidden" aria-label={Astro.locals.t('sidebarNav.accessibleLabel')}>
61
+ <MobileMenuToggle />
62
+ <div id="starlight__sidebar" class="sidebar-pane">
63
+ <div class="sidebar-content sl-flex">
64
+ <slot name="sidebar" />
65
+ </div>
66
+ </div>
67
+ </nav>
68
+ )
69
+ }
70
+
71
+ <div class="main-frame"><slot /></div>
72
+ </div>
73
+
74
+ <style>
75
+ @layer starlight.core {
76
+ /* Replicated from Starlight's PageFrame — only positional values modified */
77
+ .page {
78
+ flex-direction: column;
79
+ min-height: 100vh;
80
+ }
81
+
82
+ .header {
83
+ z-index: var(--sl-z-index-navbar);
84
+ position: fixed;
85
+ inset-inline-start: 0;
86
+ inset-block-start: var(--sl-subnav-height, 2rem); /* offset below subnav */
87
+ width: 100%;
88
+ height: var(--sl-nav-height);
89
+ border-bottom: 1px solid var(--sl-color-hairline-shade);
90
+ padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
91
+ padding-inline-end: var(--sl-nav-pad-x);
92
+ background-color: var(--sl-color-bg-nav);
93
+ }
94
+
95
+ :global([data-has-sidebar]) .header {
96
+ padding-inline-end: calc(
97
+ var(--sl-nav-gap) + var(--sl-nav-pad-x) + var(--sl-menu-button-size)
98
+ );
99
+ }
100
+
101
+ .sidebar-pane {
102
+ visibility: var(--sl-sidebar-visibility, hidden);
103
+ position: fixed;
104
+ z-index: var(--sl-z-index-menu);
105
+ inset-block: calc(var(--sl-nav-height) + var(--sl-subnav-height, 2rem)) 0;
106
+ inset-inline-start: 0;
107
+ width: 100%;
108
+ background-color: var(--sl-color-black);
109
+ overflow-y: auto;
110
+ }
111
+
112
+ :global([aria-expanded='true']) ~ .sidebar-pane {
113
+ --sl-sidebar-visibility: visible;
114
+ }
115
+
116
+ .sidebar-content {
117
+ height: 100%;
118
+ min-height: max-content;
119
+ padding: 1rem var(--sl-sidebar-pad-x) 0;
120
+ flex-direction: column;
121
+ gap: 1rem;
122
+ }
123
+
124
+ @media (min-width: 50rem) {
125
+ .sidebar-content::after {
126
+ content: '';
127
+ padding-bottom: 1px;
128
+ }
129
+ }
130
+
131
+ .main-frame {
132
+ padding-top: calc(
133
+ var(--sl-nav-height) + var(--sl-subnav-height, 2rem) + var(--sl-mobile-toc-height)
134
+ );
135
+ padding-inline-start: var(--sl-content-inline-start);
136
+ }
137
+
138
+ @media (min-width: 50rem) {
139
+ :global([data-has-sidebar]) .header {
140
+ padding-inline-end: var(--sl-nav-pad-x);
141
+ }
142
+ .sidebar-pane {
143
+ --sl-sidebar-visibility: visible;
144
+ width: var(--sl-sidebar-width);
145
+ background-color: var(--sl-color-bg-sidebar);
146
+ border-inline-end: 1px solid var(--sl-color-hairline-shade);
147
+ }
148
+ }
149
+
150
+ /* Knitli cross-site subnav */
151
+ .knitli-subnav {
152
+ position: fixed;
153
+ inset-block-start: 0;
154
+ inset-inline-start: 0;
155
+ width: 100%;
156
+ height: var(--sl-subnav-height, 2rem);
157
+ z-index: var(--sl-z-index-navbar);
158
+ background-color: var(--sl-color-bg-nav);
159
+ padding-inline: var(--sl-nav-pad-x);
160
+ justify-content: space-between;
161
+ align-items: center;
162
+ gap: 1rem;
163
+ }
164
+
165
+ .subnav-breadcrumb {
166
+ flex: 1;
167
+ min-width: 0; /* allows breadcrumb to shrink and truncate */
168
+ overflow: hidden;
169
+ }
170
+
171
+ .subnav-links {
172
+ gap: 1.25rem;
173
+ align-items: center;
174
+ flex-shrink: 0;
175
+ }
176
+
177
+ .subnav-link {
178
+ font-size: var(--sl-text-xs);
179
+ color: var(--sl-color-gray-3);
180
+ text-decoration: none;
181
+ transition: color 0.2s ease;
182
+ white-space: nowrap;
183
+ }
184
+
185
+ .subnav-link:hover {
186
+ color: var(--sl-color-white);
187
+ }
188
+ }
189
+ </style>
@@ -5,7 +5,8 @@
5
5
  */
6
6
 
7
7
  /* Import color palette and variables */
8
- @import "./variables.css";
8
+ @import "@knitli/layouts/styles/variables.css";
9
+ @import "@knitli/layouts/styles/textures.css";
9
10
 
10
11
  /* ========================================
11
12
  GOOGLE FONTS
@@ -24,7 +25,7 @@
24
25
  }
25
26
 
26
27
  html {
27
- font-size: 16px;
28
+ font-size: var(--font-sm);
28
29
  -webkit-font-smoothing: antialiased;
29
30
  -moz-osx-font-smoothing: grayscale;
30
31
  }
@@ -32,8 +33,8 @@ html {
32
33
  body {
33
34
  margin: 0;
34
35
  padding: 0;
35
- font-family: var(--font-docs-body);
36
- font-size: var(--text-base);
36
+ font-family: var(--font-cw-body);
37
+ font-size: var(--font-base);
37
38
  line-height: var(--leading-normal);
38
39
  color: var(--docs-text-primary);
39
40
  background: var(--docs-parchment);