@terrafirmagreg-team/ui 1.2.1 → 1.2.3
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 +3 -4
- package/src/components/blocks/canvas/flow-viewport.tsx +6 -2
- package/src/components/blocks/page/heading.tsx +9 -4
- package/src/components/layouts/workspace/content.tsx +53 -0
- package/src/components/layouts/workspace/index.ts +12 -0
- package/src/components/layouts/workspace/pagination.tsx +73 -0
- package/src/components/layouts/workspace/workspace.tsx +101 -0
- package/styles/content/base.css +198 -198
- package/styles/content/shiki.css +107 -107
- package/styles/content/typography.mjs +3637 -3637
- package/styles/content.css +5 -5
- package/styles/workspace.css +1 -0
- package/styles.css +430 -430
- package/src/locales/en_us.json +0 -110
- package/src/locales/pl_pl.json +0 -33
- package/src/locales/ru_ru.json +0 -110
- package/src/locales/uk_ua.json +0 -33
- package/src/locales/zh_cn.json +0 -15
- package/src/locales/zh_tw.json +0 -15
- package/src/locales.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terrafirmagreg-team/ui",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared UI kit",
|
|
6
6
|
"license": "LGPL-3.0-only",
|
|
@@ -36,8 +36,7 @@
|
|
|
36
36
|
"./components/mdx/*": [
|
|
37
37
|
"./src/components/mdx/*.tsx",
|
|
38
38
|
"./src/components/mdx/*/index.tsx"
|
|
39
|
-
]
|
|
40
|
-
"./locales": "./src/locales.ts"
|
|
39
|
+
]
|
|
41
40
|
},
|
|
42
41
|
"dependencies": {
|
|
43
42
|
"@base-ui/react": "^1.9.0",
|
|
@@ -45,7 +44,7 @@
|
|
|
45
44
|
"@react-three/drei": "10.7.9",
|
|
46
45
|
"@react-three/fiber": "9.8.2",
|
|
47
46
|
"@shadcn/react": "^0.3.1",
|
|
48
|
-
"@terrafirmagreg-team/translate": "1.2.
|
|
47
|
+
"@terrafirmagreg-team/translate": "1.2.3",
|
|
49
48
|
"@xyflow/react": "12.12.0",
|
|
50
49
|
"beautiful-mermaid": "^1.1.3",
|
|
51
50
|
"class-variance-authority": "^0.7.1",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useEffect, useRef } from 'react';
|
|
4
4
|
import {
|
|
5
5
|
useReactFlow,
|
|
6
|
+
useStore,
|
|
6
7
|
useStoreApi,
|
|
7
8
|
} from '@terrafirmagreg-team/ui/lib/canvas/xyflow';
|
|
8
9
|
import { readStoredViewport } from '@terrafirmagreg-team/ui/lib/canvas/viewport';
|
|
@@ -46,6 +47,7 @@ export function FlowViewport({
|
|
|
46
47
|
}) {
|
|
47
48
|
const { setCenter, setViewport, getZoom } = useReactFlow();
|
|
48
49
|
const storeApi = useStoreApi();
|
|
50
|
+
const paneReady = useStore((s) => s.width > 0 && s.height > 0);
|
|
49
51
|
const initRef = useRef<string | null>(null);
|
|
50
52
|
const preInitRef = useRef<string | null>(null);
|
|
51
53
|
const nodesRef = useRef(nodes);
|
|
@@ -66,6 +68,7 @@ export function FlowViewport({
|
|
|
66
68
|
|
|
67
69
|
useEffect(() => {
|
|
68
70
|
if (viewSize.w < 1 || viewSize.h < 1) return;
|
|
71
|
+
if (!paneReady) return;
|
|
69
72
|
if (!ready) {
|
|
70
73
|
|
|
71
74
|
initRef.current = null;
|
|
@@ -170,6 +173,7 @@ export function FlowViewport({
|
|
|
170
173
|
initFocusId,
|
|
171
174
|
nodes,
|
|
172
175
|
onReady,
|
|
176
|
+
paneReady,
|
|
173
177
|
ready,
|
|
174
178
|
resetKey,
|
|
175
179
|
restoreViewport,
|
|
@@ -229,7 +233,7 @@ export function FlowViewport({
|
|
|
229
233
|
useEffect(() => {
|
|
230
234
|
if (selectedId === lastSelectedRef.current) return;
|
|
231
235
|
lastSelectedRef.current = selectedId ?? null;
|
|
232
|
-
if (initRef.current !==
|
|
236
|
+
if (initRef.current !== initKey || !selectedId) return;
|
|
233
237
|
if (selectedId === suppressPanRef?.current) return;
|
|
234
238
|
const node = nodesRef.current.find((entry) => entry.id === selectedId);
|
|
235
239
|
if (!node) return;
|
|
@@ -237,7 +241,7 @@ export function FlowViewport({
|
|
|
237
241
|
zoom: getZoom() || focusZoom,
|
|
238
242
|
duration: 300,
|
|
239
243
|
});
|
|
240
|
-
}, [focusZoom, getZoom,
|
|
244
|
+
}, [focusZoom, getZoom, initKey, selectedId, suppressPanRef, setCenter]);
|
|
241
245
|
|
|
242
246
|
return null;
|
|
243
247
|
}
|
|
@@ -25,14 +25,19 @@ export function Heading({
|
|
|
25
25
|
return (
|
|
26
26
|
<As
|
|
27
27
|
{...props}
|
|
28
|
+
onClick={(event) => {
|
|
29
|
+
props.onClick?.(event);
|
|
30
|
+
if (event.defaultPrevented) return;
|
|
31
|
+
if ((event.target as HTMLElement).closest('a,button,input,select,textarea,[role="button"],[role="link"]'))
|
|
32
|
+
return;
|
|
33
|
+
window.location.hash = props.id!;
|
|
34
|
+
}}
|
|
28
35
|
className={cn(
|
|
29
|
-
'group/heading flex scroll-m-28 flex-row items-center gap-1',
|
|
36
|
+
'group/heading flex cursor-pointer scroll-m-28 flex-row items-center gap-1',
|
|
30
37
|
props.className,
|
|
31
38
|
)}
|
|
32
39
|
>
|
|
33
|
-
|
|
34
|
-
{props.children}
|
|
35
|
-
</a>
|
|
40
|
+
{props.children}
|
|
36
41
|
<button
|
|
37
42
|
aria-live="polite"
|
|
38
43
|
className={cn(
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
3
|
+
import type { ComponentProps } from 'react';
|
|
4
|
+
|
|
5
|
+
export function WorkspaceBody({ className, ...props }: ComponentProps<'div'>) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
data-slot="workspace-body"
|
|
9
|
+
{...props}
|
|
10
|
+
className={cn('prose flex-1', className)}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function WorkspaceDescription({
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
...props
|
|
19
|
+
}: ComponentProps<'p'>) {
|
|
20
|
+
if (children === undefined) return null;
|
|
21
|
+
return (
|
|
22
|
+
<p
|
|
23
|
+
data-slot="workspace-description"
|
|
24
|
+
{...props}
|
|
25
|
+
className={cn('mb-8 text-lg text-muted-foreground', className)}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</p>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function WorkspaceTitle({ className, ...props }: ComponentProps<'h1'>) {
|
|
33
|
+
return (
|
|
34
|
+
<h1
|
|
35
|
+
data-slot="workspace-title"
|
|
36
|
+
{...props}
|
|
37
|
+
className={cn('text-[1.75em] font-semibold', className)}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function WorkspaceFooter({
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}: ComponentProps<'div'>) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
data-slot="workspace-footer"
|
|
49
|
+
className={cn('mt-auto empty:hidden', className)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
WorkspacePaginationItems,
|
|
3
|
+
WorkspaceProps,
|
|
4
|
+
} from './workspace';
|
|
5
|
+
export { Workspace } from './workspace';
|
|
6
|
+
export {
|
|
7
|
+
WorkspaceBody,
|
|
8
|
+
WorkspaceDescription,
|
|
9
|
+
WorkspaceTitle,
|
|
10
|
+
WorkspaceFooter,
|
|
11
|
+
} from './content';
|
|
12
|
+
export { WorkspacePagination } from './pagination';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { type ComponentProps, useMemo } from 'react';
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
import Link from '@terrafirmagreg-team/ui/components/blocks/nav/link';
|
|
5
|
+
import { ArrowLeftIcon, ArrowRightIcon } from 'lucide-react';
|
|
6
|
+
import { useFooterItems } from '@terrafirmagreg-team/ui/hooks/use-tree';
|
|
7
|
+
import { useLocationSearch } from '@terrafirmagreg-team/ui/hooks/page/use-location-search';
|
|
8
|
+
import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
|
|
9
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
10
|
+
import { isNavItemActive } from '@terrafirmagreg-team/ui/lib/utils/nav-active';
|
|
11
|
+
import type { WorkspacePaginationItems } from './workspace';
|
|
12
|
+
|
|
13
|
+
export function WorkspacePagination({
|
|
14
|
+
items,
|
|
15
|
+
className,
|
|
16
|
+
...props
|
|
17
|
+
}: ComponentProps<'nav'> & { items?: WorkspacePaginationItems }) {
|
|
18
|
+
const footerList = useFooterItems();
|
|
19
|
+
const pathname = usePathname();
|
|
20
|
+
const search = useLocationSearch();
|
|
21
|
+
const { previous, next } = useMemo(() => {
|
|
22
|
+
if (items && (items.previous || items.next)) return items;
|
|
23
|
+
const idx = footerList.findIndex((item) =>
|
|
24
|
+
isNavItemActive(item.url, pathname, search),
|
|
25
|
+
);
|
|
26
|
+
if (idx === -1) return {};
|
|
27
|
+
return { previous: footerList[idx - 1], next: footerList[idx + 1] };
|
|
28
|
+
}, [footerList, items, pathname, search]);
|
|
29
|
+
|
|
30
|
+
if (!previous && !next) return null;
|
|
31
|
+
return (
|
|
32
|
+
<nav
|
|
33
|
+
data-slot="workspace-pagination"
|
|
34
|
+
className={cn('@container grid grid-cols-2 gap-3 mt-8', className)}
|
|
35
|
+
{...props}
|
|
36
|
+
>
|
|
37
|
+
{previous && <WorkspacePaginationItem item={previous} next={false} />}
|
|
38
|
+
{next && <WorkspacePaginationItem item={next} next />}
|
|
39
|
+
</nav>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function WorkspacePaginationItem({
|
|
44
|
+
item,
|
|
45
|
+
next,
|
|
46
|
+
}: {
|
|
47
|
+
item: NonNullable<WorkspacePaginationItems['previous']>;
|
|
48
|
+
next: boolean;
|
|
49
|
+
}) {
|
|
50
|
+
const t = useTranslations();
|
|
51
|
+
const Icon = next ? ArrowRightIcon : ArrowLeftIcon;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Link
|
|
55
|
+
href={item.url}
|
|
56
|
+
className={cn(
|
|
57
|
+
'group flex flex-col gap-1 rounded-2xl border p-4 text-sm transition-colors hover:bg-accent/40 @max-md:col-span-full',
|
|
58
|
+
next && 'col-start-2 items-end text-end',
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
61
|
+
<span className="inline-flex items-center gap-1.5 text-muted-foreground">
|
|
62
|
+
{!next && (
|
|
63
|
+
<Icon className="size-3.5 transition-transform group-hover:-translate-x-0.5 rtl:rotate-180" />
|
|
64
|
+
)}
|
|
65
|
+
{next ? t('Next Page', { note: 'ui.next_page' }) : t('Previous Page', { note: 'ui.prev_page' })}
|
|
66
|
+
{next && (
|
|
67
|
+
<Icon className="size-3.5 transition-transform group-hover:translate-x-0.5 rtl:rotate-180" />
|
|
68
|
+
)}
|
|
69
|
+
</span>
|
|
70
|
+
<span className="font-medium">{item.name}</span>
|
|
71
|
+
</Link>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
import type * as PageTree from '@terrafirmagreg-team/translate/types/tree';
|
|
5
|
+
import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
|
|
6
|
+
import type { PagePreviewData } from '@terrafirmagreg-team/ui/types/preview';
|
|
7
|
+
import { LeftSidebarExpand } from '@terrafirmagreg-team/ui/components/layouts/left-sidebar';
|
|
8
|
+
import { Breadcrumb } from '@terrafirmagreg-team/ui/components/blocks/nav/breadcrumb';
|
|
9
|
+
import { WorkspaceFooter } from './content';
|
|
10
|
+
import { WorkspacePagination } from './pagination';
|
|
11
|
+
|
|
12
|
+
export type WorkspacePaginationItems = {
|
|
13
|
+
previous?: Pick<PageTree.Item, 'name' | 'description' | 'url'>;
|
|
14
|
+
next?: Pick<PageTree.Item, 'name' | 'description' | 'url'>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type WorkspaceProps = ComponentProps<'article'> & {
|
|
18
|
+
full?: boolean;
|
|
19
|
+
outlineDropdown?: ReactNode;
|
|
20
|
+
breadcrumb?: {
|
|
21
|
+
items?: { name: string; url?: string }[];
|
|
22
|
+
previews?: Record<string, PagePreviewData>;
|
|
23
|
+
};
|
|
24
|
+
pagination?: { items?: WorkspacePaginationItems } | false;
|
|
25
|
+
actions?: ReactNode;
|
|
26
|
+
footer?: ReactNode;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function Workspace({
|
|
30
|
+
full = false,
|
|
31
|
+
outlineDropdown,
|
|
32
|
+
breadcrumb,
|
|
33
|
+
pagination = {},
|
|
34
|
+
actions,
|
|
35
|
+
footer,
|
|
36
|
+
className,
|
|
37
|
+
children,
|
|
38
|
+
...props
|
|
39
|
+
}: WorkspaceProps) {
|
|
40
|
+
const crumbs = breadcrumb?.items ?? [];
|
|
41
|
+
const hasCrumbs = crumbs.length > 0;
|
|
42
|
+
const pathname = usePathname();
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
key={pathname}
|
|
47
|
+
id="page-panel"
|
|
48
|
+
data-slot="workspace-panel"
|
|
49
|
+
className="@container relative flex flex-col min-w-0 min-h-0 [grid-area:main] mx-2 bg-background md:ms-0 md:my-2 md:overflow-clip md:rounded-2xl md:border md:shadow-sm print:overflow-visible"
|
|
50
|
+
>
|
|
51
|
+
<header
|
|
52
|
+
data-slot="workspace-header"
|
|
53
|
+
className={cn(
|
|
54
|
+
'absolute inset-x-0 top-0 z-10 flex items-center gap-1.5 h-(--header-height) ps-6 pe-4 bg-linear-to-b from-background to-transparent pointer-events-none *:pointer-events-auto max-md:hidden',
|
|
55
|
+
hasCrumbs || outlineDropdown ? 'from-50%' : 'to-40%',
|
|
56
|
+
)}
|
|
57
|
+
>
|
|
58
|
+
<LeftSidebarExpand />
|
|
59
|
+
{hasCrumbs && (
|
|
60
|
+
<Breadcrumb items={crumbs} previews={breadcrumb?.previews} />
|
|
61
|
+
)}
|
|
62
|
+
{outlineDropdown}
|
|
63
|
+
<div data-slot="workspace-actions" className="ms-auto">
|
|
64
|
+
{actions}
|
|
65
|
+
</div>
|
|
66
|
+
</header>
|
|
67
|
+
<div
|
|
68
|
+
data-slot="workspace-scroll"
|
|
69
|
+
className="flex flex-1 items-start px-4 md:min-h-0 md:pt-(--header-height) md:px-[max(--spacing(6),calc((100%_-_var(--page-width)_-_var(--toc-width))/2))] md:overflow-y-auto md:overscroll-y-contain md:scrollbar-thin md:scrollbar-gutter-stable md:[--docs-height:calc(var(--layout-height)_-_var(--spacing)*4_-_2px_-_var(--header-height))]"
|
|
70
|
+
>
|
|
71
|
+
<article
|
|
72
|
+
id="page"
|
|
73
|
+
data-slot="workspace"
|
|
74
|
+
data-full={full}
|
|
75
|
+
className={cn(
|
|
76
|
+
'flex flex-col gap-4 w-full min-w-0 max-w-(--page-width) pt-6 pb-8 md:min-h-(--docs-height)',
|
|
77
|
+
className,
|
|
78
|
+
)}
|
|
79
|
+
{...props}
|
|
80
|
+
>
|
|
81
|
+
{hasCrumbs && (
|
|
82
|
+
<Breadcrumb
|
|
83
|
+
items={crumbs}
|
|
84
|
+
previews={breadcrumb?.previews}
|
|
85
|
+
className="md:hidden"
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
{children}
|
|
89
|
+
{pagination !== false || footer ? (
|
|
90
|
+
<WorkspaceFooter>
|
|
91
|
+
{pagination !== false && (
|
|
92
|
+
<WorkspacePagination items={pagination.items} />
|
|
93
|
+
)}
|
|
94
|
+
{footer}
|
|
95
|
+
</WorkspaceFooter>
|
|
96
|
+
) : null}
|
|
97
|
+
</article>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|