@hanzo/ui 5.3.26 → 5.3.29

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.
Files changed (100) hide show
  1. package/content/index.ts +26 -0
  2. package/dist/util/index.js +6 -0
  3. package/dist/util/index.mjs +6 -1
  4. package/docs/_registry/index.ts +426 -0
  5. package/docs/_registry/layout/docs-min.tsx +197 -0
  6. package/docs/_registry/layout/page-min.tsx +128 -0
  7. package/docs/components/accordion.tsx +118 -0
  8. package/docs/components/banner.tsx +144 -0
  9. package/docs/components/callout.tsx +112 -0
  10. package/docs/components/card.tsx +52 -0
  11. package/docs/components/codeblock.tsx +258 -0
  12. package/docs/components/dialog/search-algolia.tsx +132 -0
  13. package/docs/components/dialog/search-default.tsx +131 -0
  14. package/docs/components/dialog/search-orama.tsx +143 -0
  15. package/docs/components/dialog/search.tsx +529 -0
  16. package/docs/components/dynamic-codeblock.tsx +129 -0
  17. package/docs/components/files.tsx +81 -0
  18. package/docs/components/github-info.tsx +107 -0
  19. package/docs/components/heading.tsx +33 -0
  20. package/docs/components/image-zoom.css +77 -0
  21. package/docs/components/image-zoom.tsx +58 -0
  22. package/docs/components/index.ts +7 -0
  23. package/docs/components/inline-toc.tsx +48 -0
  24. package/docs/components/sidebar/base.tsx +451 -0
  25. package/docs/components/sidebar/link-item.tsx +65 -0
  26. package/docs/components/sidebar/page-tree.tsx +113 -0
  27. package/docs/components/sidebar/tabs/dropdown.tsx +109 -0
  28. package/docs/components/sidebar/tabs/index.tsx +89 -0
  29. package/docs/components/steps.tsx +9 -0
  30. package/docs/components/tabs.tsx +203 -0
  31. package/docs/components/toc/clerk.tsx +173 -0
  32. package/docs/components/toc/default.tsx +57 -0
  33. package/docs/components/toc/index.tsx +136 -0
  34. package/docs/components/type-table.tsx +174 -0
  35. package/docs/components/ui/accordion.tsx +88 -0
  36. package/docs/components/ui/button.tsx +28 -0
  37. package/docs/components/ui/collapsible.tsx +42 -0
  38. package/docs/components/ui/navigation-menu.tsx +83 -0
  39. package/docs/components/ui/popover.tsx +32 -0
  40. package/docs/components/ui/scroll-area.tsx +59 -0
  41. package/docs/components/ui/tabs.tsx +145 -0
  42. package/docs/contexts/i18n.tsx +56 -0
  43. package/docs/contexts/search.tsx +165 -0
  44. package/docs/contexts/tree.tsx +65 -0
  45. package/docs/css/black.css +39 -0
  46. package/docs/css/catppuccin.css +49 -0
  47. package/docs/css/colors/index.css +51 -0
  48. package/docs/css/dusk.css +47 -0
  49. package/docs/css/layouts/docs.css +1 -0
  50. package/docs/css/layouts/home.css +1 -0
  51. package/docs/css/layouts/notebook.css +1 -0
  52. package/docs/css/neutral.css +7 -0
  53. package/docs/css/ocean.css +48 -0
  54. package/docs/css/preset.css +305 -0
  55. package/docs/css/purple.css +39 -0
  56. package/docs/css/shadcn.css +36 -0
  57. package/docs/css/shiki.css +90 -0
  58. package/docs/css/solar.css +75 -0
  59. package/docs/css/style.css +9 -0
  60. package/docs/css/vitepress.css +77 -0
  61. package/docs/i18n.tsx +30 -0
  62. package/docs/icons.tsx +354 -0
  63. package/docs/layouts/docs/client.tsx +129 -0
  64. package/docs/layouts/docs/index.tsx +321 -0
  65. package/docs/layouts/docs/page/client.tsx +376 -0
  66. package/docs/layouts/docs/page/index.tsx +251 -0
  67. package/docs/layouts/docs/sidebar.tsx +265 -0
  68. package/docs/layouts/home/client.tsx +375 -0
  69. package/docs/layouts/home/index.tsx +51 -0
  70. package/docs/layouts/home/navbar.tsx +55 -0
  71. package/docs/layouts/notebook/client.tsx +281 -0
  72. package/docs/layouts/notebook/index.tsx +461 -0
  73. package/docs/layouts/notebook/page/client.tsx +375 -0
  74. package/docs/layouts/notebook/page/index.tsx +251 -0
  75. package/docs/layouts/notebook/sidebar.tsx +248 -0
  76. package/docs/layouts/shared/index.tsx +89 -0
  77. package/docs/layouts/shared/language-toggle.tsx +66 -0
  78. package/docs/layouts/shared/link-item.tsx +119 -0
  79. package/docs/layouts/shared/search-toggle.tsx +78 -0
  80. package/docs/layouts/shared/theme-toggle.tsx +86 -0
  81. package/docs/mdx.server.tsx +37 -0
  82. package/docs/mdx.tsx +97 -0
  83. package/docs/og.tsx +101 -0
  84. package/docs/page.tsx +85 -0
  85. package/docs/provider/base.tsx +173 -0
  86. package/docs/provider/next.tsx +23 -0
  87. package/docs/provider/react-router.tsx +23 -0
  88. package/docs/provider/tanstack.tsx +23 -0
  89. package/docs/provider/waku.tsx +23 -0
  90. package/docs/source.ts +3 -0
  91. package/docs/theme/typography/LICENSE +21 -0
  92. package/docs/theme/typography/index.ts +201 -0
  93. package/docs/theme/typography/styles.ts +449 -0
  94. package/docs/utils/cn.ts +1 -0
  95. package/docs/utils/is-active.ts +23 -0
  96. package/docs/utils/merge-refs.ts +15 -0
  97. package/docs/utils/use-copy-button.ts +39 -0
  98. package/docs/utils/use-footer-items.ts +27 -0
  99. package/docs/utils/use-is-scroll-top.ts +21 -0
  100. package/package.json +4 -2
@@ -0,0 +1,201 @@
1
+ import * as styles from './styles';
2
+ import plugin from 'tailwindcss/plugin';
3
+ import merge from 'lodash.merge';
4
+ import parser, { type Pseudo } from 'postcss-selector-parser';
5
+ import type { Config } from './styles';
6
+
7
+ export interface Options {
8
+ className?: string;
9
+
10
+ /**
11
+ * Disable custom table styles
12
+ */
13
+ disableRoundedTable?: boolean;
14
+ }
15
+
16
+ interface Context {
17
+ prefix: (v: string) => string;
18
+ modifier?: string;
19
+ }
20
+
21
+ function inWhere(
22
+ selector: string,
23
+ { className, prefix, modifier }: Options & Context,
24
+ ) {
25
+ const prefixedNot = prefix(`.not-${className}`).slice(1);
26
+ const selectorPrefix = selector.startsWith('>')
27
+ ? `${modifier === 'DEFAULT' ? `.${className}` : `.${className}-${modifier}`} `
28
+ : '';
29
+
30
+ // Parse the selector, if every component ends in the same pseudo element(s) then move it to the end
31
+ const [trailingPseudo, rebuiltSelector] = commonTrailingPseudos(selector);
32
+
33
+ if (trailingPseudo) {
34
+ return `:where(${selectorPrefix}${rebuiltSelector}):not(:where([class~="${prefixedNot}"],[class~="${prefixedNot}"] *))${trailingPseudo}`;
35
+ }
36
+
37
+ return `:where(${selectorPrefix}${selector}):not(:where([class~="${prefixedNot}"],[class~="${prefixedNot}"] *))`;
38
+ }
39
+
40
+ function configToCss(
41
+ config: Config = {},
42
+ { className, modifier, prefix }: Options & Context,
43
+ ) {
44
+ function updateSelector(
45
+ k: string,
46
+ v: unknown,
47
+ ): [k: string, v: unknown, object?] {
48
+ if (Array.isArray(v)) {
49
+ return [k, v];
50
+ }
51
+
52
+ if (typeof v === 'object' && v !== null) {
53
+ const nested = Object.values(v).some((prop) => typeof prop === 'object');
54
+ if (nested) {
55
+ return [
56
+ inWhere(k, { className, modifier, prefix }),
57
+ v,
58
+ Object.fromEntries(
59
+ Object.entries(v).map(([k, v]) => updateSelector(k, v)),
60
+ ),
61
+ ];
62
+ }
63
+
64
+ return [inWhere(k, { className, modifier, prefix }), v];
65
+ }
66
+
67
+ return [k, v];
68
+ }
69
+
70
+ const css = config.css ?? [];
71
+ return Object.fromEntries(
72
+ Object.entries(merge({}, ...(Array.isArray(css) ? css : [css]))).map(
73
+ ([k, v]) => updateSelector(k, v),
74
+ ),
75
+ );
76
+ }
77
+
78
+ const parseSelector = parser();
79
+
80
+ function commonTrailingPseudos(selector: string) {
81
+ const ast = parseSelector.astSync(selector);
82
+ const matrix: Pseudo[][] = [];
83
+
84
+ // Put the pseudo elements in reverse order in a sparse, column-major 2D array
85
+ for (const [i, sel] of ast.nodes.entries()) {
86
+ for (const [j, child] of [...sel.nodes].reverse().entries()) {
87
+ // We only care about pseudo elements
88
+ if (child.type !== 'pseudo' || !child.value.startsWith('::')) {
89
+ break;
90
+ }
91
+
92
+ matrix[j] = matrix[j] || [];
93
+ matrix[j][i] = child;
94
+ }
95
+ }
96
+
97
+ const trailingPseudos = parser.selector({
98
+ value: '',
99
+ });
100
+
101
+ // At this point the pseudo elements are in a column-major 2D array
102
+ // This means each row contains one "column" of pseudo elements from each selector
103
+ // We can compare all the pseudo elements in a row to see if they are the same
104
+ for (const pseudos of matrix) {
105
+ // It's a sparse 2D array so there are going to be holes in the rows
106
+ // We skip those
107
+ if (!pseudos) {
108
+ continue;
109
+ }
110
+
111
+ const values = new Set(pseudos.map((p) => p.value));
112
+
113
+ // The pseudo elements are not the same
114
+ if (values.size > 1) {
115
+ break;
116
+ }
117
+
118
+ pseudos.forEach((pseudo) => pseudo.remove());
119
+ trailingPseudos.prepend(pseudos[0]);
120
+ }
121
+
122
+ if (trailingPseudos.nodes.length) {
123
+ return [trailingPseudos.toString(), ast.toString()];
124
+ }
125
+
126
+ return [null, selector];
127
+ }
128
+
129
+ const SELECTORS = [
130
+ ['headings', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th'],
131
+ ['h1'],
132
+ ['h2'],
133
+ ['h3'],
134
+ ['h4'],
135
+ ['h5'],
136
+ ['h6'],
137
+ ['p'],
138
+ ['a'],
139
+ ['blockquote'],
140
+ ['figure'],
141
+ ['figcaption'],
142
+ ['strong'],
143
+ ['em'],
144
+ ['kbd'],
145
+ ['code'],
146
+ ['pre'],
147
+ ['ol'],
148
+ ['ul'],
149
+ ['li'],
150
+ ['table'],
151
+ ['thead'],
152
+ ['tr'],
153
+ ['th'],
154
+ ['td'],
155
+ ['img'],
156
+ ['video'],
157
+ ['hr'],
158
+ ['lead', '[class~="lead"]'],
159
+ ];
160
+
161
+ export const typography: unknown = plugin.withOptions<Options>(
162
+ ({ className = 'prose', ...styleOptions } = {}) => {
163
+ return ({ addVariant, addComponents, ...rest }) => {
164
+ const prefix = (rest as unknown as { prefix: Context['prefix'] }).prefix;
165
+
166
+ for (const [name, ...values] of SELECTORS) {
167
+ const selectors = values.length === 0 ? [name] : values;
168
+ const selector = selectors.join(', ');
169
+
170
+ addVariant(
171
+ `${className}-${name}`,
172
+ `& :is(${inWhere(selector, {
173
+ prefix,
174
+ className,
175
+ })})`,
176
+ );
177
+ }
178
+
179
+ addComponents({
180
+ [`.${className}`]: configToCss(
181
+ {
182
+ ...styles.DEFAULT,
183
+ css: [
184
+ ...(styles.DEFAULT.css ?? []),
185
+ styleOptions.disableRoundedTable
186
+ ? styles.normalTable
187
+ : styles.roundedTable,
188
+ ],
189
+ },
190
+ {
191
+ className,
192
+ modifier: 'DEFAULT',
193
+ prefix,
194
+ },
195
+ ),
196
+ });
197
+ };
198
+ },
199
+ );
200
+
201
+ export default typography;
@@ -0,0 +1,449 @@
1
+ function round(num: number) {
2
+ return num
3
+ .toFixed(7)
4
+ .replace(/(\.[0-9]+?)0+$/, '$1')
5
+ .replace(/\.0$/, '');
6
+ }
7
+
8
+ function rem(px: number) {
9
+ return `${round(px / 16)}rem`;
10
+ }
11
+
12
+ function em(px: number, base: number) {
13
+ return `${round(px / base)}em`;
14
+ }
15
+
16
+ const colors = {
17
+ '--tw-prose-body':
18
+ 'color-mix(in oklab, var(--color-fd-foreground) 90%, transparent)',
19
+ '--tw-prose-headings': 'var(--color-fd-foreground)',
20
+ '--tw-prose-lead': `var(--color-fd-foreground)`,
21
+ '--tw-prose-links': `var(--color-fd-foreground)`,
22
+ '--tw-prose-bold': `var(--color-fd-foreground)`,
23
+ '--tw-prose-counters': `var(--color-fd-muted-foreground)`,
24
+ '--tw-prose-bullets': `var(--color-fd-muted-foreground)`,
25
+ '--tw-prose-hr': `var(--color-fd-border)`,
26
+ '--tw-prose-quotes': `var(--color-fd-foreground)`,
27
+ '--tw-prose-quote-borders': `var(--color-fd-border)`,
28
+ '--tw-prose-captions': `var(--color-fd-foreground)`,
29
+ '--tw-prose-code': `var(--color-fd-foreground)`,
30
+ '--tw-prose-th-borders': `var(--color-fd-border)`,
31
+ '--tw-prose-td-borders': `var(--color-fd-border)`,
32
+ '--tw-prose-kbd': `var(--color-fd-foreground)`,
33
+ '--tw-prose-kbd-shadows': `color-mix(in oklab, var(--color-fd-primary) 50%, transparent)`,
34
+ };
35
+
36
+ export const roundedTable = {
37
+ table: {
38
+ borderCollapse: 'separate',
39
+ borderSpacing: '0',
40
+ background: 'var(--color-fd-card)',
41
+ borderRadius: 'var(--radius-lg)',
42
+ border: '1px solid var(--color-fd-border)',
43
+ overflow: 'hidden',
44
+ },
45
+ th: {
46
+ textAlign: 'start',
47
+ padding: 'calc(var(--spacing) * 2.5)',
48
+ 'border-inline-start': '1px solid var(--color-fd-border)',
49
+ background: 'var(--color-fd-muted)',
50
+ },
51
+ 'th:first-child': {
52
+ 'border-inline-start': 'none',
53
+ },
54
+ 'th:not(tr:last-child *), td:not(tr:last-child *)': {
55
+ 'border-bottom': '1px solid var(--color-fd-border)',
56
+ },
57
+ td: {
58
+ textAlign: 'start',
59
+ 'border-inline-start': '1px solid var(--color-fd-border)',
60
+ padding: 'calc(var(--spacing) * 2.5)',
61
+ },
62
+ 'td:first-child': {
63
+ 'border-inline-start': 'none',
64
+ },
65
+ 'tfoot th, tfoot td': {
66
+ borderTopWidth: '1px',
67
+ borderTopColor: 'var(--tw-prose-th-borders)',
68
+ },
69
+ 'thead th, thead td': {
70
+ borderBottomWidth: '1px',
71
+ borderBottomColor: 'var(--tw-prose-th-borders)',
72
+ },
73
+ };
74
+
75
+ export const normalTable = {
76
+ thead: {
77
+ borderBottomWidth: '1px',
78
+ borderBottomColor: 'var(--tw-prose-th-borders)',
79
+ },
80
+ 'thead th': {
81
+ verticalAlign: 'bottom',
82
+ paddingInlineEnd: em(8, 14),
83
+ paddingBottom: em(8, 14),
84
+ paddingInlineStart: em(8, 14),
85
+ },
86
+ 'thead th:first-child': {
87
+ paddingInlineStart: '0',
88
+ },
89
+ 'thead th:last-child': {
90
+ paddingInlineEnd: '0',
91
+ },
92
+ 'tbody td, tfoot td': {
93
+ paddingTop: em(8, 14),
94
+ paddingInlineEnd: em(8, 14),
95
+ paddingBottom: em(8, 14),
96
+ paddingInlineStart: em(8, 14),
97
+ },
98
+ 'tbody td:first-child, tfoot td:first-child': {
99
+ paddingInlineStart: '0',
100
+ },
101
+ 'tbody td:last-child, tfoot td:last-child': {
102
+ paddingInlineEnd: '0',
103
+ },
104
+ 'tbody tr': {
105
+ borderBottomWidth: '1px',
106
+ borderBottomColor: 'var(--tw-prose-td-borders)',
107
+ },
108
+ 'tbody tr:last-child': {
109
+ borderBottomWidth: '0',
110
+ },
111
+ 'tbody td': {
112
+ verticalAlign: 'baseline',
113
+ },
114
+ tfoot: {
115
+ borderTopWidth: '1px',
116
+ borderTopColor: 'var(--tw-prose-th-borders)',
117
+ },
118
+ 'tfoot td': {
119
+ verticalAlign: 'top',
120
+ },
121
+ 'th, td': {
122
+ textAlign: 'start',
123
+ },
124
+ };
125
+
126
+ export interface Config {
127
+ css?: Record<string, string | Record<string, string>>[];
128
+ }
129
+
130
+ export const DEFAULT: Config = {
131
+ css: [
132
+ {
133
+ color: 'var(--tw-prose-body)',
134
+ maxWidth: 'none',
135
+ fontSize: rem(16),
136
+ lineHeight: '1.75rem',
137
+
138
+ '[class~="lead"]': {
139
+ fontSize: em(20, 16),
140
+ lineHeight: round(32 / 20),
141
+ marginTop: em(24, 20),
142
+ marginBottom: em(24, 20),
143
+ color: 'var(--tw-prose-lead)',
144
+ },
145
+ ul: {
146
+ paddingInlineStart: '1rem',
147
+ listStyleType: 'disc',
148
+ marginTop: em(20, 16),
149
+ marginBottom: em(20, 16),
150
+ },
151
+ li: {
152
+ marginTop: em(8, 16),
153
+ marginBottom: em(8, 16),
154
+ },
155
+ 'ol > li': {
156
+ paddingInlineStart: em(6, 16),
157
+ },
158
+ 'ul > li': {
159
+ paddingInlineStart: '0',
160
+ },
161
+ '> ul > li p': {
162
+ marginTop: em(12, 16),
163
+ marginBottom: em(12, 16),
164
+ },
165
+ '> ul > li > p:first-child': {
166
+ marginTop: em(20, 16),
167
+ },
168
+ '> ul > li > p:last-child': {
169
+ marginBottom: em(20, 16),
170
+ },
171
+ '> ol > li > p:first-child': {
172
+ marginTop: em(20, 16),
173
+ },
174
+ '> ol > li > p:last-child': {
175
+ marginBottom: em(20, 16),
176
+ },
177
+ 'ul ul, ul ol, ol ul, ol ol': {
178
+ marginTop: em(12, 16),
179
+ marginBottom: em(12, 16),
180
+ },
181
+ dl: {
182
+ marginTop: em(20, 16),
183
+ marginBottom: em(20, 16),
184
+ },
185
+ dt: {
186
+ color: 'var(--tw-prose-headings)',
187
+ fontWeight: '600',
188
+ marginTop: em(20, 16),
189
+ },
190
+ dd: {
191
+ marginTop: em(8, 16),
192
+ paddingInlineStart: em(26, 16),
193
+ },
194
+ hr: {
195
+ borderColor: 'var(--tw-prose-hr)',
196
+ borderTopWidth: '1px',
197
+ marginTop: em(48, 16),
198
+ marginBottom: em(48, 16),
199
+ },
200
+ p: {
201
+ marginTop: em(20, 16),
202
+ marginBottom: em(20, 16),
203
+ },
204
+ strong: {
205
+ color: 'var(--tw-prose-bold)',
206
+ fontWeight: '500',
207
+ },
208
+ 'a strong': {
209
+ color: 'inherit',
210
+ },
211
+ 'blockquote strong': {
212
+ color: 'inherit',
213
+ },
214
+ 'thead th strong': {
215
+ color: 'inherit',
216
+ },
217
+ ol: {
218
+ listStyleType: 'decimal',
219
+ marginTop: em(20, 16),
220
+ marginBottom: em(20, 16),
221
+ paddingInlineStart: em(26, 16),
222
+ },
223
+ 'ol[type="A"]': {
224
+ listStyleType: 'upper-alpha',
225
+ },
226
+ 'ol[type="a"]': {
227
+ listStyleType: 'lower-alpha',
228
+ },
229
+ 'ol[type="A" s]': {
230
+ listStyleType: 'upper-alpha',
231
+ },
232
+ 'ol[type="a" s]': {
233
+ listStyleType: 'lower-alpha',
234
+ },
235
+ 'ol[type="I"]': {
236
+ listStyleType: 'upper-roman',
237
+ },
238
+ 'ol[type="i"]': {
239
+ listStyleType: 'lower-roman',
240
+ },
241
+ 'ol[type="I" s]': {
242
+ listStyleType: 'upper-roman',
243
+ },
244
+ 'ol[type="i" s]': {
245
+ listStyleType: 'lower-roman',
246
+ },
247
+ 'ol[type="1"]': {
248
+ listStyleType: 'decimal',
249
+ },
250
+ 'ol > li::marker': {
251
+ fontWeight: '400',
252
+ color: 'var(--tw-prose-counters)',
253
+ },
254
+ 'ul > li::marker': {
255
+ color: 'var(--tw-prose-bullets)',
256
+ },
257
+ blockquote: {
258
+ marginTop: em(32, 20),
259
+ marginBottom: em(32, 20),
260
+ paddingInlineStart: em(20, 20),
261
+ fontWeight: '500',
262
+ fontStyle: 'italic',
263
+ color: 'var(--tw-prose-quotes)',
264
+ borderInlineStartWidth: '0.25rem',
265
+ borderInlineStartColor: 'var(--tw-prose-quote-borders)',
266
+ quotes: '"\\201C""\\201D""\\2018""\\2019"',
267
+ },
268
+ 'blockquote p:first-of-type::before': {
269
+ content: 'open-quote',
270
+ },
271
+ 'blockquote p:last-of-type::after': {
272
+ content: 'close-quote',
273
+ },
274
+ h1: {
275
+ color: 'var(--tw-prose-headings)',
276
+ fontWeight: '800',
277
+ fontSize: 'var(--text-3xl)',
278
+ marginTop: '0',
279
+ marginBottom: em(32, 36),
280
+ lineHeight: round(40 / 36),
281
+ },
282
+ 'h1 strong': {
283
+ fontWeight: '900',
284
+ color: 'inherit',
285
+ },
286
+ h2: {
287
+ color: 'var(--tw-prose-headings)',
288
+ fontSize: em(24, 16),
289
+ marginTop: em(48, 24),
290
+ marginBottom: em(24, 24),
291
+ lineHeight: round(32 / 24),
292
+ fontWeight: '600',
293
+ },
294
+ 'h2 strong': {
295
+ fontWeight: '800',
296
+ color: 'inherit',
297
+ },
298
+ h3: {
299
+ color: 'var(--tw-prose-headings)',
300
+ fontWeight: '600',
301
+ fontSize: em(20, 16),
302
+ marginTop: em(32, 20),
303
+ marginBottom: em(12, 20),
304
+ lineHeight: round(32 / 20),
305
+ },
306
+ 'h3 strong': {
307
+ fontWeight: '700',
308
+ color: 'inherit',
309
+ },
310
+ h4: {
311
+ color: 'var(--tw-prose-headings)',
312
+ fontWeight: '600',
313
+ marginTop: em(24, 16),
314
+ marginBottom: em(8, 16),
315
+ lineHeight: round(24 / 16),
316
+ },
317
+ 'h4 strong': {
318
+ fontWeight: '700',
319
+ color: 'inherit',
320
+ },
321
+ 'hr + *': {
322
+ marginTop: '0',
323
+ },
324
+ 'h2 + *': {
325
+ marginTop: '0',
326
+ },
327
+ 'h3 + *': {
328
+ marginTop: '0',
329
+ },
330
+ 'h4 + *': {
331
+ marginTop: '0',
332
+ },
333
+ img: {
334
+ marginTop: em(32, 16),
335
+ marginBottom: em(32, 16),
336
+ },
337
+ picture: {
338
+ display: 'block',
339
+ marginTop: em(32, 16),
340
+ marginBottom: em(32, 16),
341
+ },
342
+ 'picture > img': {
343
+ marginTop: '0',
344
+ marginBottom: '0',
345
+ },
346
+ video: {
347
+ marginTop: em(32, 16),
348
+ marginBottom: em(32, 16),
349
+ },
350
+ kbd: {
351
+ fontSize: em(14, 16),
352
+ borderRadius: rem(5),
353
+ paddingTop: em(3, 16),
354
+ paddingInlineEnd: em(6, 16),
355
+ paddingBottom: em(3, 16),
356
+ paddingInlineStart: em(6, 16),
357
+ fontWeight: '500',
358
+ fontFamily: 'inherit',
359
+ color: 'var(--tw-prose-kbd)',
360
+ boxShadow:
361
+ '0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows)',
362
+ },
363
+ code: {
364
+ padding: '3px',
365
+ border: 'solid 1px',
366
+ fontSize: '13px',
367
+ borderColor: `var(--color-fd-border)`,
368
+ borderRadius: '5px',
369
+ fontWeight: '400',
370
+ background: `var(--color-fd-muted)`,
371
+ color: 'var(--tw-prose-code)',
372
+ },
373
+ 'a code': {
374
+ color: 'inherit',
375
+ },
376
+ 'h1 code': {
377
+ color: 'inherit',
378
+ fontSize: 'var(--text-2xl)',
379
+ },
380
+ 'h2 code': {
381
+ color: 'inherit',
382
+ fontSize: em(21, 24),
383
+ },
384
+ 'h3 code': {
385
+ color: 'inherit',
386
+ fontSize: em(18, 20),
387
+ },
388
+ 'h4 code': {
389
+ color: 'inherit',
390
+ },
391
+ 'blockquote code': {
392
+ color: 'inherit',
393
+ },
394
+ 'thead th code': {
395
+ color: 'inherit',
396
+ },
397
+
398
+ table: {
399
+ fontSize: em(14, 16),
400
+ lineHeight: round(24 / 14),
401
+ width: '100%',
402
+ tableLayout: 'auto',
403
+ marginTop: em(32, 16),
404
+ marginBottom: em(32, 16),
405
+ },
406
+ 'thead th': {
407
+ color: 'var(--tw-prose-headings)',
408
+ fontWeight: '600',
409
+ },
410
+
411
+ figure: {
412
+ marginTop: em(32, 16),
413
+ marginBottom: em(32, 16),
414
+ },
415
+ 'figure > *': {
416
+ marginTop: '0',
417
+ marginBottom: '0',
418
+ },
419
+ figcaption: {
420
+ color: 'var(--tw-prose-captions)',
421
+ fontSize: em(14, 16),
422
+ lineHeight: round(20 / 14),
423
+ marginTop: em(12, 14),
424
+ },
425
+
426
+ 'a:not([data-card])': {
427
+ color: 'var(--tw-prose-links)',
428
+ transition: 'opacity .2s',
429
+ fontWeight: '500',
430
+ textDecoration: 'underline',
431
+ textUnderlineOffset: '3.5px',
432
+ textDecorationColor: 'var(--color-fd-primary)',
433
+ textDecorationThickness: '1.5px',
434
+ },
435
+ 'a:not([data-card]):hover': {
436
+ opacity: '80%',
437
+ },
438
+ },
439
+ colors,
440
+ {
441
+ '> :first-child': {
442
+ marginTop: '0',
443
+ },
444
+ '> :last-child': {
445
+ marginBottom: '0',
446
+ },
447
+ },
448
+ ],
449
+ };
@@ -0,0 +1 @@
1
+ export { twMerge as cn } from 'tailwind-merge';
@@ -0,0 +1,23 @@
1
+ import type { SidebarTab } from '@/components/sidebar/tabs';
2
+
3
+ function normalize(url: string) {
4
+ if (url.length > 1 && url.endsWith('/')) return url.slice(0, -1);
5
+ return url;
6
+ }
7
+
8
+ export function isActive(
9
+ url: string,
10
+ pathname: string,
11
+ nested = true,
12
+ ): boolean {
13
+ url = normalize(url);
14
+ pathname = normalize(pathname);
15
+
16
+ return url === pathname || (nested && pathname.startsWith(`${url}/`));
17
+ }
18
+
19
+ export function isTabActive(tab: SidebarTab, pathname: string) {
20
+ if (tab.urls) return tab.urls.has(normalize(pathname));
21
+
22
+ return isActive(tab.url, pathname, true);
23
+ }
@@ -0,0 +1,15 @@
1
+ import type * as React from 'react';
2
+
3
+ export function mergeRefs<T>(
4
+ ...refs: (React.Ref<T> | undefined)[]
5
+ ): React.RefCallback<T> {
6
+ return (value) => {
7
+ refs.forEach((ref) => {
8
+ if (typeof ref === 'function') {
9
+ ref(value);
10
+ } else if (ref) {
11
+ ref.current = value;
12
+ }
13
+ });
14
+ };
15
+ }