@terrafirmagreg-team/ui 0.0.0-stage → 1.2.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 +93 -3
- package/src/components/blocks/button/icon-button.tsx +49 -0
- package/src/components/blocks/canvas/chevron-edge.tsx +242 -0
- package/src/components/blocks/canvas/flow-canvas.tsx +181 -0
- package/src/components/blocks/canvas/flow-toolbar.tsx +33 -0
- package/src/components/blocks/canvas/flow-viewport.tsx +244 -0
- package/src/components/blocks/fit-box.tsx +26 -0
- package/src/components/blocks/git/github-info.tsx +78 -0
- package/src/components/blocks/lang/content.tsx +52 -0
- package/src/components/blocks/lang/flag.tsx +25 -0
- package/src/components/blocks/lang/link.tsx +23 -0
- package/src/components/blocks/lang/redirect.tsx +48 -0
- package/src/components/blocks/lang/switcher.tsx +54 -0
- package/src/components/blocks/lang/untranslated-callout.tsx +29 -0
- package/src/components/blocks/lang/untranslated-chip.tsx +53 -0
- package/src/components/blocks/link/link-preview.tsx +257 -0
- package/src/components/blocks/list/row.tsx +92 -0
- package/src/components/blocks/media/glb/model.tsx +244 -0
- package/src/components/blocks/media/glb/scene.tsx +373 -0
- package/src/components/blocks/media/glb/viewer.tsx +52 -0
- package/src/components/blocks/media/image.tsx +136 -0
- package/src/components/blocks/media/slideshow.tsx +178 -0
- package/src/components/blocks/nav/breadcrumb.tsx +51 -0
- package/src/components/blocks/nav/copy-menu.tsx +37 -0
- package/src/components/blocks/nav/link.tsx +86 -0
- package/src/components/blocks/nav/site-menu.tsx +78 -0
- package/src/components/blocks/nav/site-title.tsx +61 -0
- package/src/components/blocks/nav/switcher.tsx +206 -0
- package/src/components/blocks/page/empty-state.tsx +32 -0
- package/src/components/blocks/page/heading.tsx +54 -0
- package/src/components/blocks/page/pager.tsx +220 -0
- package/src/components/blocks/readability/fields.tsx +250 -0
- package/src/components/blocks/readability/menu.tsx +247 -0
- package/src/components/blocks/readability/track.tsx +165 -0
- package/src/components/blocks/search/command.tsx +80 -0
- package/src/components/blocks/search/dialog.tsx +724 -0
- package/src/components/blocks/search/provider.tsx +118 -0
- package/src/components/blocks/sidebar.tsx +406 -0
- package/src/components/blocks/sprite.tsx +231 -0
- package/src/components/blocks/text/format-text.tsx +110 -0
- package/src/components/blocks/theme/toggle.tsx +75 -0
- package/src/components/blocks/tooltip/hint.tsx +28 -0
- package/src/components/blocks/tooltip/lazy.tsx +41 -0
- package/src/components/blocks/viewer/controls.tsx +284 -0
- package/src/components/blocks/viewer/float-bar.tsx +51 -0
- package/src/components/layouts/layout.tsx +94 -0
- package/src/components/layouts/left-sidebar/content.tsx +63 -0
- package/src/components/layouts/left-sidebar/context.tsx +55 -0
- package/src/components/layouts/left-sidebar/expand.tsx +23 -0
- package/src/components/layouts/left-sidebar/footer.tsx +111 -0
- package/src/components/layouts/left-sidebar/index.ts +29 -0
- package/src/components/layouts/left-sidebar/items.tsx +103 -0
- package/src/components/layouts/left-sidebar/search.tsx +75 -0
- package/src/components/layouts/left-sidebar/sidebar.tsx +189 -0
- package/src/components/layouts/left-sidebar/tree.tsx +157 -0
- package/src/components/layouts/right-sidebar.tsx +96 -0
- package/src/components/layouts/tree-context.tsx +42 -0
- package/src/components/mdx/accordion.tsx +185 -0
- package/src/components/mdx/banner.tsx +157 -0
- package/src/components/mdx/callout.tsx +97 -0
- package/src/components/mdx/card.tsx +56 -0
- package/src/components/mdx/codeblock.tsx +250 -0
- package/src/components/mdx/collapsible.tsx +33 -0
- package/src/components/mdx/files.tsx +63 -0
- package/src/components/mdx/glow-header.tsx +54 -0
- package/src/components/mdx/gradient-text.tsx +28 -0
- package/src/components/mdx/icon.tsx +35 -0
- package/src/components/mdx/image-zoom.tsx +315 -0
- package/src/components/mdx/math.tsx +30 -0
- package/src/components/mdx/mermaid.tsx +23 -0
- package/src/components/mdx/multiblock.tsx +19 -0
- package/src/components/mdx/preview.tsx +101 -0
- package/src/components/mdx/steps.tsx +10 -0
- package/src/components/mdx/table.tsx +14 -0
- package/src/components/mdx/tabs.tsx +354 -0
- package/src/components/mdx/type-table.tsx +171 -0
- package/src/components/provider.tsx +139 -0
- package/src/components/ui/accordion.tsx +71 -0
- package/src/components/ui/alert-dialog.tsx +187 -0
- package/src/components/ui/alert.tsx +75 -0
- package/src/components/ui/aspect-ratio.tsx +22 -0
- package/src/components/ui/attachment.tsx +207 -0
- package/src/components/ui/avatar.tsx +108 -0
- package/src/components/ui/badge.tsx +51 -0
- package/src/components/ui/breadcrumb.tsx +124 -0
- package/src/components/ui/bubble.tsx +127 -0
- package/src/components/ui/button-group.tsx +87 -0
- package/src/components/ui/button.tsx +57 -0
- package/src/components/ui/calendar.tsx +221 -0
- package/src/components/ui/card.tsx +102 -0
- package/src/components/ui/carousel.tsx +242 -0
- package/src/components/ui/chart.tsx +371 -0
- package/src/components/ui/checkbox.tsx +28 -0
- package/src/components/ui/collapsible.tsx +21 -0
- package/src/components/ui/combobox.tsx +297 -0
- package/src/components/ui/command.tsx +198 -0
- package/src/components/ui/context-menu.tsx +270 -0
- package/src/components/ui/dialog.tsx +160 -0
- package/src/components/ui/direction.tsx +6 -0
- package/src/components/ui/drawer.tsx +227 -0
- package/src/components/ui/dropdown-menu.tsx +269 -0
- package/src/components/ui/empty.tsx +103 -0
- package/src/components/ui/field.tsx +238 -0
- package/src/components/ui/hover-card.tsx +50 -0
- package/src/components/ui/input-group.tsx +158 -0
- package/src/components/ui/input-otp.tsx +86 -0
- package/src/components/ui/input.tsx +19 -0
- package/src/components/ui/item.tsx +201 -0
- package/src/components/ui/kbd.tsx +26 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/marker.tsx +70 -0
- package/src/components/ui/menubar.tsx +280 -0
- package/src/components/ui/message-scroller.tsx +131 -0
- package/src/components/ui/message.tsx +91 -0
- package/src/components/ui/native-select.tsx +60 -0
- package/src/components/ui/navigation-menu.tsx +167 -0
- package/src/components/ui/pagination.tsx +130 -0
- package/src/components/ui/popover.tsx +91 -0
- package/src/components/ui/progress.tsx +82 -0
- package/src/components/ui/questionnaire.tsx +324 -0
- package/src/components/ui/radio-group.tsx +37 -0
- package/src/components/ui/resizable.tsx +49 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/select.tsx +200 -0
- package/src/components/ui/separator.tsx +24 -0
- package/src/components/ui/sheet.tsx +138 -0
- package/src/components/ui/sidebar.tsx +730 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/slider.tsx +51 -0
- package/src/components/ui/spinner.tsx +10 -0
- package/src/components/ui/switch.tsx +31 -0
- package/src/components/ui/table.tsx +115 -0
- package/src/components/ui/tabs.tsx +81 -0
- package/src/components/ui/textarea.tsx +17 -0
- package/src/components/ui/toast.tsx +234 -0
- package/src/components/ui/toggle-group.tsx +89 -0
- package/src/components/ui/toggle.tsx +44 -0
- package/src/components/ui/tooltip.tsx +65 -0
- package/src/hooks/canvas/use-flow-hover.ts +19 -0
- package/src/hooks/canvas/use-flow-viewport-persist.ts +34 -0
- package/src/hooks/page/use-fit-pages.ts +92 -0
- package/src/hooks/page/use-location-search.ts +31 -0
- package/src/hooks/page/use-page-preview.ts +41 -0
- package/src/hooks/page/use-paged-list.ts +21 -0
- package/src/hooks/readability/use-readability.ts +87 -0
- package/src/hooks/search/use-dialog.ts +42 -0
- package/src/hooks/search/use-highlight-query.ts +58 -0
- package/src/hooks/search/use-provider.ts +26 -0
- package/src/hooks/use-async-value.ts +60 -0
- package/src/hooks/use-close-on-scroll.ts +24 -0
- package/src/hooks/use-copy-button.ts +47 -0
- package/src/hooks/use-cycle-index.ts +76 -0
- package/src/hooks/use-document-title.ts +10 -0
- package/src/hooks/use-element-size.ts +36 -0
- package/src/hooks/use-external-meta.ts +133 -0
- package/src/hooks/use-hot-key.ts +34 -0
- package/src/hooks/use-hover-follow.ts +55 -0
- package/src/hooks/use-in-view.ts +31 -0
- package/src/hooks/use-lang.ts +9 -0
- package/src/hooks/use-last-value.ts +16 -0
- package/src/hooks/use-layout.ts +19 -0
- package/src/hooks/use-marquee.ts +52 -0
- package/src/hooks/use-media-query.ts +15 -0
- package/src/hooks/use-mobile.ts +20 -0
- package/src/hooks/use-modifier-keys.ts +32 -0
- package/src/hooks/use-on-change.ts +36 -0
- package/src/hooks/use-pane-keys.ts +29 -0
- package/src/hooks/use-sidebar.ts +64 -0
- package/src/hooks/use-swipe.ts +27 -0
- package/src/hooks/use-tree.ts +100 -0
- package/src/hooks/viewer/use-in-float-bar.ts +7 -0
- package/src/hooks/viewer/use-viewer-prefs.ts +78 -0
- package/src/lib/canvas/edge.ts +202 -0
- package/src/lib/canvas/geometry.ts +54 -0
- package/src/lib/canvas/state.ts +48 -0
- package/src/lib/canvas/viewport.ts +38 -0
- package/src/lib/canvas/xyflow.ts +2 -0
- package/src/lib/config.ts +106 -0
- package/src/lib/mdx/callout.ts +21 -0
- package/src/lib/mdx/gradient.ts +16 -0
- package/src/lib/mdx/mermaid.ts +15 -0
- package/src/lib/media/crop-opaque.ts +77 -0
- package/src/lib/media/nearby-indexes.ts +7 -0
- package/src/lib/media/trim-transparent.ts +118 -0
- package/src/lib/readability/config.ts +11 -0
- package/src/lib/readability/spotlight.ts +187 -0
- package/src/lib/readability/store.ts +147 -0
- package/src/lib/tree.ts +90 -0
- package/src/lib/utils/cn.ts +2 -0
- package/src/lib/utils/format.ts +22 -0
- package/src/lib/utils/highlight-style.ts +10 -0
- package/src/lib/utils/history.ts +10 -0
- package/src/lib/utils/merge-refs.ts +14 -0
- package/src/lib/utils/nav-active.ts +59 -0
- package/src/lib/utils/stored-value.ts +137 -0
- package/src/lib/utils/urls.ts +18 -0
- package/src/locales/en_us.json +110 -0
- package/src/locales/pl_pl.json +33 -0
- package/src/locales/ru_ru.json +110 -0
- package/src/locales/uk_ua.json +33 -0
- package/src/locales/zh_cn.json +15 -0
- package/src/locales/zh_tw.json +15 -0
- package/src/locales.ts +6 -0
- package/src/types/canvas.ts +54 -0
- package/src/types/glb.ts +26 -0
- package/src/types/mdx-directives.ts +106 -0
- package/src/types/nav.ts +96 -0
- package/src/types/preview.ts +15 -0
- package/src/types/readability.ts +29 -0
- package/src/types/search.ts +57 -0
- package/src/types/tree.ts +19 -0
- package/src/types/viewer.ts +54 -0
- package/styles/content/base.css +198 -0
- package/styles/content/default-colors.css +51 -0
- package/styles/content/shiki.css +107 -0
- package/styles/content/typography.mjs +3637 -0
- package/styles/content.css +5 -0
- package/styles/image-zoom.css +83 -0
- package/styles/layout.css +28 -0
- package/styles/left-sidebar.css +140 -0
- package/styles/readability.css +50 -0
- package/styles/right-sidebar.css +6 -0
- package/styles/workspace.css +26 -0
- package/styles.css +430 -0
- package/README.md +0 -3
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Check, LinkIcon } from 'lucide-react';
|
|
4
|
+
import { type ComponentProps, type ReactNode, useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
6
|
+
import { Accordion as Primitive } from '@base-ui/react/accordion';
|
|
7
|
+
import { ChevronRight } from 'lucide-react';
|
|
8
|
+
import { useCopyButton } from '@terrafirmagreg-team/ui/hooks/use-copy-button';
|
|
9
|
+
import { buttonVariants } from '@terrafirmagreg-team/ui/components/ui/button';
|
|
10
|
+
import { mergeRefs } from '@terrafirmagreg-team/ui/lib/utils/merge-refs';
|
|
11
|
+
import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
|
|
12
|
+
|
|
13
|
+
export function AccordionRoot({ className, ...props }: ComponentProps<typeof Primitive.Root>) {
|
|
14
|
+
return (
|
|
15
|
+
<Primitive.Root
|
|
16
|
+
className={(s) =>
|
|
17
|
+
cn(
|
|
18
|
+
'divide-y divide-border overflow-hidden rounded-lg border bg-card',
|
|
19
|
+
typeof className === 'function' ? className(s) : className,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function AccordionItem({ children, ...props }: ComponentProps<typeof Primitive.Item>) {
|
|
28
|
+
return <Primitive.Item {...props}>{children}</Primitive.Item>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function AccordionHeader({
|
|
32
|
+
className,
|
|
33
|
+
children,
|
|
34
|
+
...props
|
|
35
|
+
}: ComponentProps<typeof Primitive.Header>) {
|
|
36
|
+
return (
|
|
37
|
+
<Primitive.Header
|
|
38
|
+
className={(s) =>
|
|
39
|
+
cn(
|
|
40
|
+
'scroll-m-24 not-prose flex flex-row items-center text-card-foreground font-medium has-focus-visible:bg-accent',
|
|
41
|
+
typeof className === 'function' ? className(s) : className,
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
</Primitive.Header>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function AccordionTrigger({
|
|
52
|
+
className,
|
|
53
|
+
children,
|
|
54
|
+
...props
|
|
55
|
+
}: ComponentProps<typeof Primitive.Trigger>) {
|
|
56
|
+
return (
|
|
57
|
+
<Primitive.Trigger
|
|
58
|
+
className={(s) =>
|
|
59
|
+
cn(
|
|
60
|
+
'group flex flex-1 items-center gap-2 px-3 py-2.5 text-start focus-visible:outline-none',
|
|
61
|
+
typeof className === 'function' ? className(s) : className,
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
{...props}
|
|
65
|
+
>
|
|
66
|
+
<ChevronRight className="size-4 shrink-0 text-muted-foreground transition-transform duration-200 group-data-panel-open:rotate-90" />
|
|
67
|
+
{children}
|
|
68
|
+
</Primitive.Trigger>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function AccordionContent({
|
|
73
|
+
className,
|
|
74
|
+
children,
|
|
75
|
+
...props
|
|
76
|
+
}: ComponentProps<typeof Primitive.Panel>) {
|
|
77
|
+
return (
|
|
78
|
+
<Primitive.Panel
|
|
79
|
+
className={(s) =>
|
|
80
|
+
cn(
|
|
81
|
+
'h-(--accordion-panel-height) overflow-hidden transition-[height] ease-out data-ending-style:h-0 data-starting-style:h-0',
|
|
82
|
+
typeof className === 'function' ? className(s) : className,
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
{...props}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</Primitive.Panel>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function Accordions({
|
|
93
|
+
ref,
|
|
94
|
+
className,
|
|
95
|
+
defaultValue,
|
|
96
|
+
...props
|
|
97
|
+
}: ComponentProps<typeof AccordionRoot>) {
|
|
98
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
99
|
+
const composedRef = mergeRefs(ref, rootRef);
|
|
100
|
+
const [value, setValue] = useState<unknown[]>(defaultValue ?? []);
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const id = window.location.hash.substring(1);
|
|
104
|
+
const element = rootRef.current;
|
|
105
|
+
if (!element || id.length === 0) return;
|
|
106
|
+
|
|
107
|
+
const selected = document.getElementById(id);
|
|
108
|
+
if (!selected || !element.contains(selected)) return;
|
|
109
|
+
const value = selected.getAttribute('data-accordion-value');
|
|
110
|
+
|
|
111
|
+
if (value) setValue((prev) => [value, ...prev]);
|
|
112
|
+
}, []);
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<AccordionRoot
|
|
116
|
+
ref={composedRef}
|
|
117
|
+
value={value}
|
|
118
|
+
onValueChange={setValue}
|
|
119
|
+
className={(s) =>
|
|
120
|
+
cn(
|
|
121
|
+
'divide-y divide-border overflow-hidden rounded-lg border bg-card',
|
|
122
|
+
typeof className === 'function' ? className(s) : className,
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
{...props}
|
|
126
|
+
/>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function Accordion({
|
|
131
|
+
title,
|
|
132
|
+
id,
|
|
133
|
+
value = String(title),
|
|
134
|
+
children,
|
|
135
|
+
...props
|
|
136
|
+
}: Omit<ComponentProps<typeof AccordionItem>, 'value' | 'title'> & {
|
|
137
|
+
title: string | ReactNode;
|
|
138
|
+
value?: string;
|
|
139
|
+
}) {
|
|
140
|
+
return (
|
|
141
|
+
<AccordionItem value={value} {...props}>
|
|
142
|
+
<AccordionHeader id={id} data-accordion-value={value}>
|
|
143
|
+
<AccordionTrigger>{title}</AccordionTrigger>
|
|
144
|
+
{id ? <CopyButton id={id} /> : null}
|
|
145
|
+
</AccordionHeader>
|
|
146
|
+
<AccordionContent hiddenUntilFound>
|
|
147
|
+
<div className="px-4 pb-2 text-[0.9375rem] prose-no-margin [&[hidden]:not([hidden='until-found'])]:hidden">
|
|
148
|
+
{children}
|
|
149
|
+
</div>
|
|
150
|
+
</AccordionContent>
|
|
151
|
+
</AccordionItem>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function CopyButton({ id }: { id: string }) {
|
|
156
|
+
const t = useTranslations();
|
|
157
|
+
const { checked, onClick } = useCopyButton(() => {
|
|
158
|
+
const url = new URL(window.location.href);
|
|
159
|
+
url.hash = id;
|
|
160
|
+
|
|
161
|
+
return navigator.clipboard.writeText(url.toString());
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<button
|
|
166
|
+
type="button"
|
|
167
|
+
aria-live="polite"
|
|
168
|
+
className={cn(
|
|
169
|
+
buttonVariants({
|
|
170
|
+
variant: 'ghost',
|
|
171
|
+
className: 'text-muted-foreground me-2',
|
|
172
|
+
}),
|
|
173
|
+
)}
|
|
174
|
+
onClick={onClick}
|
|
175
|
+
>
|
|
176
|
+
{checked ? <Check className="size-3.5" /> : <LinkIcon className="size-3.5" />}
|
|
177
|
+
<span className="sr-only">
|
|
178
|
+
{checked
|
|
179
|
+
? t('Copied Link', { note: 'ui.copied_link' })
|
|
180
|
+
: t('Copy Link', { note: 'ui.copy_link' })}
|
|
181
|
+
</span>
|
|
182
|
+
</button>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { type HTMLAttributes, useEffect, useState } from 'react';
|
|
4
|
+
import { X } from 'lucide-react';
|
|
5
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
6
|
+
import { buttonVariants } from '@terrafirmagreg-team/ui/components/ui/button';
|
|
7
|
+
import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
|
|
8
|
+
|
|
9
|
+
type BannerVariant = 'rainbow' | 'normal';
|
|
10
|
+
|
|
11
|
+
export type BannerProps = HTMLAttributes<HTMLDivElement> & {
|
|
12
|
+
|
|
13
|
+
height?: string;
|
|
14
|
+
|
|
15
|
+
variant?: BannerVariant;
|
|
16
|
+
|
|
17
|
+
rainbowColors?: string[];
|
|
18
|
+
|
|
19
|
+
changeLayout?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function Banner({
|
|
23
|
+
id,
|
|
24
|
+
variant = 'normal',
|
|
25
|
+
changeLayout = true,
|
|
26
|
+
height = '3rem',
|
|
27
|
+
rainbowColors = [
|
|
28
|
+
'rgba(0,149,255,0.56)',
|
|
29
|
+
'rgba(231,77,255,0.77)',
|
|
30
|
+
'rgba(255,0,0,0.73)',
|
|
31
|
+
'rgba(131,255,166,0.66)',
|
|
32
|
+
],
|
|
33
|
+
...props
|
|
34
|
+
}: BannerProps) {
|
|
35
|
+
const t = useTranslations();
|
|
36
|
+
const [open, setOpen] = useState(true);
|
|
37
|
+
const globalKey = id ? `banner-${encodeBase32(id)}` : null;
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (globalKey && localStorage.getItem(globalKey) === 'true') setOpen(false);
|
|
41
|
+
}, [globalKey]);
|
|
42
|
+
|
|
43
|
+
function onClose() {
|
|
44
|
+
setOpen(false);
|
|
45
|
+
if (globalKey) localStorage.setItem(globalKey, 'true');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!open) return null;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
id={id}
|
|
53
|
+
{...props}
|
|
54
|
+
className={cn(
|
|
55
|
+
'sticky top-0 z-40 flex flex-row items-center justify-center rounded-xl px-4 text-center text-sm font-medium',
|
|
56
|
+
variant === 'normal' && 'bg-secondary',
|
|
57
|
+
variant === 'rainbow' && 'bg-background',
|
|
58
|
+
!open && 'hidden',
|
|
59
|
+
props.className,
|
|
60
|
+
)}
|
|
61
|
+
style={{
|
|
62
|
+
height,
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
{changeLayout && open ? (
|
|
66
|
+
<style>
|
|
67
|
+
{globalKey
|
|
68
|
+
? `:root:not(.${globalKey}) { --banner-height: ${height}; }`
|
|
69
|
+
: `:root { --banner-height: ${height}; }`}
|
|
70
|
+
</style>
|
|
71
|
+
) : null}
|
|
72
|
+
{globalKey ? <style>{`.${globalKey} #${id} { display: none; }`}</style> : null}
|
|
73
|
+
{globalKey ? (
|
|
74
|
+
<script
|
|
75
|
+
dangerouslySetInnerHTML={{
|
|
76
|
+
__html: `if (localStorage.getItem('${globalKey}') === 'true') document.documentElement.classList.add('${globalKey}');`,
|
|
77
|
+
}}
|
|
78
|
+
/>
|
|
79
|
+
) : null}
|
|
80
|
+
|
|
81
|
+
{variant === 'rainbow'
|
|
82
|
+
? flow({
|
|
83
|
+
colors: rainbowColors,
|
|
84
|
+
})
|
|
85
|
+
: null}
|
|
86
|
+
{props.children}
|
|
87
|
+
{id ? (
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
aria-label={t('Close Banner', { note: 'ui.banner_close' })}
|
|
91
|
+
onClick={onClose}
|
|
92
|
+
className={cn(
|
|
93
|
+
buttonVariants({
|
|
94
|
+
variant: 'ghost',
|
|
95
|
+
className: 'absolute inset-e-2 top-1/2 -translate-y-1/2 text-muted-foreground/50',
|
|
96
|
+
size: 'icon-sm',
|
|
97
|
+
}),
|
|
98
|
+
)}
|
|
99
|
+
>
|
|
100
|
+
<X />
|
|
101
|
+
</button>
|
|
102
|
+
) : null}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const maskImage =
|
|
108
|
+
'linear-gradient(to bottom,white,transparent), radial-gradient(circle at top center, white, transparent)';
|
|
109
|
+
|
|
110
|
+
function flow({ colors }: { colors: string[] }) {
|
|
111
|
+
return (
|
|
112
|
+
<>
|
|
113
|
+
<div
|
|
114
|
+
className="absolute inset-0 -z-1"
|
|
115
|
+
style={{
|
|
116
|
+
maskImage,
|
|
117
|
+
maskComposite: 'intersect',
|
|
118
|
+
animation: 'moving-banner 20s linear infinite',
|
|
119
|
+
backgroundImage: `repeating-linear-gradient(70deg, ${[...colors, colors[0]].map((color, i) => `${color} ${(i * 50) / colors.length}%`).join(', ')})`,
|
|
120
|
+
backgroundSize: '200% 100%',
|
|
121
|
+
filter: 'saturate(2)',
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
<style>
|
|
125
|
+
{`@keyframes moving-banner {
|
|
126
|
+
from { background-position: 0% 0; }
|
|
127
|
+
to { background-position: 100% 0; }
|
|
128
|
+
}`}
|
|
129
|
+
</style>
|
|
130
|
+
</>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function encodeBase32(str: string) {
|
|
135
|
+
const alphabet = 'abcdefghijklmnopqrstuvwxyz234567';
|
|
136
|
+
let encoded = '';
|
|
137
|
+
|
|
138
|
+
let buffer = 0;
|
|
139
|
+
let bitsLeft = 0;
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < str.length; i++) {
|
|
142
|
+
buffer = (buffer << 8) | str.charCodeAt(i);
|
|
143
|
+
bitsLeft += 8;
|
|
144
|
+
|
|
145
|
+
while (bitsLeft >= 5) {
|
|
146
|
+
bitsLeft -= 5;
|
|
147
|
+
encoded += alphabet[(buffer >> bitsLeft) & 31];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (bitsLeft > 0) {
|
|
152
|
+
encoded += alphabet[(buffer << (5 - bitsLeft)) & 31];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return encoded;
|
|
156
|
+
}
|
|
157
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { CircleCheck, CircleX, Info, Lightbulb, StickyNote, TriangleAlert } from 'lucide-react';
|
|
2
|
+
import type { ComponentProps, CSSProperties, ReactNode } from 'react';
|
|
3
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
4
|
+
import { calloutStyle } from '@terrafirmagreg-team/ui/lib/mdx/callout';
|
|
5
|
+
|
|
6
|
+
export type CalloutType =
|
|
7
|
+
| 'info'
|
|
8
|
+
| 'note'
|
|
9
|
+
| 'tip'
|
|
10
|
+
| 'warn'
|
|
11
|
+
| 'warning'
|
|
12
|
+
| 'error'
|
|
13
|
+
| 'danger'
|
|
14
|
+
| 'success'
|
|
15
|
+
| 'idea';
|
|
16
|
+
|
|
17
|
+
const iconClass = 'size-5 -me-0.5 fill-(--callout-color) text-card';
|
|
18
|
+
|
|
19
|
+
const ICONS: Record<string, ReactNode> = {
|
|
20
|
+
info: <Info className={iconClass} />,
|
|
21
|
+
note: <StickyNote className={iconClass} />,
|
|
22
|
+
tip: (
|
|
23
|
+
<Lightbulb className="size-5 -me-0.5 fill-(--callout-color) text-(--callout-color)" />
|
|
24
|
+
),
|
|
25
|
+
warn: <TriangleAlert className={iconClass} />,
|
|
26
|
+
warning: <TriangleAlert className={iconClass} />,
|
|
27
|
+
error: <CircleX className={iconClass} />,
|
|
28
|
+
danger: <CircleX className={iconClass} />,
|
|
29
|
+
success: <CircleCheck className={iconClass} />,
|
|
30
|
+
idea: (
|
|
31
|
+
<Lightbulb className="size-5 -me-0.5 fill-(--callout-color) text-(--callout-color)" />
|
|
32
|
+
),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export function Callout({
|
|
36
|
+
children,
|
|
37
|
+
title,
|
|
38
|
+
...props
|
|
39
|
+
}: { title?: ReactNode } & Omit<CalloutContainerProps, 'title'>) {
|
|
40
|
+
return (
|
|
41
|
+
<CalloutContainer {...props}>
|
|
42
|
+
{title && <CalloutTitle>{title}</CalloutTitle>}
|
|
43
|
+
<CalloutDescription>{children}</CalloutDescription>
|
|
44
|
+
</CalloutContainer>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface CalloutContainerProps extends ComponentProps<'div'> {
|
|
49
|
+
|
|
50
|
+
type?: CalloutType;
|
|
51
|
+
|
|
52
|
+
icon?: ReactNode;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function CalloutContainer({
|
|
56
|
+
type = 'info',
|
|
57
|
+
icon,
|
|
58
|
+
children,
|
|
59
|
+
className,
|
|
60
|
+
style,
|
|
61
|
+
...props
|
|
62
|
+
}: CalloutContainerProps) {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
className={cn(
|
|
66
|
+
'flex gap-2 my-4 rounded-xl border bg-card p-3 ps-1 text-sm text-card-foreground',
|
|
67
|
+
className,
|
|
68
|
+
)}
|
|
69
|
+
style={calloutStyle(type, style)}
|
|
70
|
+
{...props}
|
|
71
|
+
>
|
|
72
|
+
<div role="none" className="w-0.5 bg-(--callout-color)/50 rounded-sm" />
|
|
73
|
+
{icon ?? ICONS[type]}
|
|
74
|
+
<div className="flex flex-col gap-2 min-w-0 flex-1">{children}</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function CalloutTitle({ children, className, ...props }: ComponentProps<'p'>) {
|
|
80
|
+
return (
|
|
81
|
+
<p className={cn('font-medium my-0!', className)} {...props}>
|
|
82
|
+
{children}
|
|
83
|
+
</p>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function CalloutDescription({ children, className, ...props }: ComponentProps<'p'>) {
|
|
88
|
+
return (
|
|
89
|
+
<div
|
|
90
|
+
className={cn('text-muted-foreground prose-no-margin empty:hidden', className)}
|
|
91
|
+
{...props}
|
|
92
|
+
>
|
|
93
|
+
{children}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useUiComponents } from '@terrafirmagreg-team/ui/provider';
|
|
3
|
+
import type { ComponentProps, ComponentType, HTMLAttributes, ReactNode } from 'react';
|
|
4
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
5
|
+
import { Icon } from '@terrafirmagreg-team/ui/components/mdx/icon';
|
|
6
|
+
|
|
7
|
+
export function Cards(props: HTMLAttributes<HTMLDivElement>) {
|
|
8
|
+
return (
|
|
9
|
+
<div {...props} className={cn('grid grid-cols-2 gap-3 @container', props.className)}>
|
|
10
|
+
{props.children}
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type CardProps = Omit<HTMLAttributes<HTMLElement>, 'title'> & {
|
|
16
|
+
icon?: ReactNode | string;
|
|
17
|
+
title: ReactNode;
|
|
18
|
+
description?: ReactNode;
|
|
19
|
+
|
|
20
|
+
href?: string;
|
|
21
|
+
external?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function Card({ icon, title, description, ...props }: CardProps) {
|
|
25
|
+
const { Link } = useUiComponents();
|
|
26
|
+
const { external, href, ...rest } = props;
|
|
27
|
+
const E = (href ? Link : 'div') as ComponentType<ComponentProps<'a'>>;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<E
|
|
31
|
+
{...rest}
|
|
32
|
+
href={href}
|
|
33
|
+
{...(external
|
|
34
|
+
? { target: '_blank', rel: 'noopener noreferrer' }
|
|
35
|
+
: {})}
|
|
36
|
+
data-card
|
|
37
|
+
className={cn(
|
|
38
|
+
'block rounded-xl border bg-card p-4 text-card-foreground transition-colors @max-lg:col-span-full',
|
|
39
|
+
props.href && 'hover:bg-accent/80',
|
|
40
|
+
props.className,
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
{icon ? (
|
|
44
|
+
<div className="not-prose mb-2 inline-flex h-7 min-w-8 items-center justify-center rounded-lg border bg-muted px-2 text-muted-foreground shadow-md [&_svg]:size-4">
|
|
45
|
+
{typeof icon === 'string' ? <Icon name={icon} /> : icon}
|
|
46
|
+
</div>
|
|
47
|
+
) : null}
|
|
48
|
+
<h3 className="not-prose mb-1 text-sm font-medium">{title}</h3>
|
|
49
|
+
{description ? <p className="my-0! text-sm text-muted-foreground">{description}</p> : null}
|
|
50
|
+
<div className="text-sm text-muted-foreground prose-no-margin empty:hidden">
|
|
51
|
+
{props.children}
|
|
52
|
+
</div>
|
|
53
|
+
</E>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|