@byline/cli 0.1.1
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/LICENSE +373 -0
- package/README.md +23 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +36 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +76 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/context.d.ts +38 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +37 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/pg-url.d.ts +11 -0
- package/dist/lib/pg-url.d.ts.map +1 -0
- package/dist/lib/pg-url.js +22 -0
- package/dist/lib/pg-url.js.map +1 -0
- package/dist/manifest/deps.d.ts +29 -0
- package/dist/manifest/deps.d.ts.map +1 -0
- package/dist/manifest/deps.js +97 -0
- package/dist/manifest/deps.js.map +1 -0
- package/dist/manifest/env.d.ts +18 -0
- package/dist/manifest/env.d.ts.map +1 -0
- package/dist/manifest/env.js +38 -0
- package/dist/manifest/env.js.map +1 -0
- package/dist/phases/db-init.d.ts +3 -0
- package/dist/phases/db-init.d.ts.map +1 -0
- package/dist/phases/db-init.js +163 -0
- package/dist/phases/db-init.js.map +1 -0
- package/dist/phases/db.d.ts +11 -0
- package/dist/phases/db.d.ts.map +1 -0
- package/dist/phases/db.js +93 -0
- package/dist/phases/db.js.map +1 -0
- package/dist/phases/deps.d.ts +3 -0
- package/dist/phases/deps.d.ts.map +1 -0
- package/dist/phases/deps.js +115 -0
- package/dist/phases/deps.js.map +1 -0
- package/dist/phases/env.d.ts +3 -0
- package/dist/phases/env.d.ts.map +1 -0
- package/dist/phases/env.js +172 -0
- package/dist/phases/env.js.map +1 -0
- package/dist/phases/host.d.ts +3 -0
- package/dist/phases/host.d.ts.map +1 -0
- package/dist/phases/host.js +99 -0
- package/dist/phases/host.js.map +1 -0
- package/dist/phases/index.d.ts +7 -0
- package/dist/phases/index.d.ts.map +1 -0
- package/dist/phases/index.js +40 -0
- package/dist/phases/index.js.map +1 -0
- package/dist/phases/preflight.d.ts +4 -0
- package/dist/phases/preflight.d.ts.map +1 -0
- package/dist/phases/preflight.js +81 -0
- package/dist/phases/preflight.js.map +1 -0
- package/dist/phases/routes.d.ts +3 -0
- package/dist/phases/routes.d.ts.map +1 -0
- package/dist/phases/routes.js +145 -0
- package/dist/phases/routes.js.map +1 -0
- package/dist/phases/scaffold.d.ts +3 -0
- package/dist/phases/scaffold.d.ts.map +1 -0
- package/dist/phases/scaffold.js +113 -0
- package/dist/phases/scaffold.js.map +1 -0
- package/dist/phases/stub.d.ts +3 -0
- package/dist/phases/stub.d.ts.map +1 -0
- package/dist/phases/stub.js +25 -0
- package/dist/phases/stub.js.map +1 -0
- package/dist/phases/ui.d.ts +3 -0
- package/dist/phases/ui.d.ts.map +1 -0
- package/dist/phases/ui.js +93 -0
- package/dist/phases/ui.js.map +1 -0
- package/dist/phases/wire/index.d.ts +3 -0
- package/dist/phases/wire/index.d.ts.map +1 -0
- package/dist/phases/wire/index.js +67 -0
- package/dist/phases/wire/index.js.map +1 -0
- package/dist/phases/wire/root-tsx.d.ts +3 -0
- package/dist/phases/wire/root-tsx.d.ts.map +1 -0
- package/dist/phases/wire/root-tsx.js +57 -0
- package/dist/phases/wire/root-tsx.js.map +1 -0
- package/dist/phases/wire/server-ts.d.ts +3 -0
- package/dist/phases/wire/server-ts.d.ts.map +1 -0
- package/dist/phases/wire/server-ts.js +54 -0
- package/dist/phases/wire/server-ts.js.map +1 -0
- package/dist/phases/wire/shared.d.ts +34 -0
- package/dist/phases/wire/shared.d.ts.map +1 -0
- package/dist/phases/wire/shared.js +2 -0
- package/dist/phases/wire/shared.js.map +1 -0
- package/dist/phases/wire/start-ts.d.ts +3 -0
- package/dist/phases/wire/start-ts.d.ts.map +1 -0
- package/dist/phases/wire/start-ts.js +149 -0
- package/dist/phases/wire/start-ts.js.map +1 -0
- package/dist/phases/wire/tsconfig.d.ts +3 -0
- package/dist/phases/wire/tsconfig.d.ts.map +1 -0
- package/dist/phases/wire/tsconfig.js +105 -0
- package/dist/phases/wire/tsconfig.js.map +1 -0
- package/dist/phases/wire/vite-config.d.ts +3 -0
- package/dist/phases/wire/vite-config.d.ts.map +1 -0
- package/dist/phases/wire/vite-config.js +46 -0
- package/dist/phases/wire/vite-config.js.map +1 -0
- package/dist/prompts.d.ts +34 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +49 -0
- package/dist/prompts.js.map +1 -0
- package/dist/runner.d.ts +5 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +91 -0
- package/dist/runner.js.map +1 -0
- package/dist/state.d.ts +18 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +68 -0
- package/dist/state.js.map +1 -0
- package/dist/templates/byline/admin.config.ts +41 -0
- package/dist/templates/byline/i18n.ts +47 -0
- package/dist/templates/byline/routes.ts +28 -0
- package/dist/templates/byline/seed.ts +19 -0
- package/dist/templates/byline/seeds/admin.ts +62 -0
- package/dist/templates/byline/server.config.ts +92 -0
- package/dist/templates/byline-examples/admin.config.ts +74 -0
- package/dist/templates/byline-examples/blocks/photo-block.ts +59 -0
- package/dist/templates/byline-examples/blocks/richtext-block.ts +35 -0
- package/dist/templates/byline-examples/collections/doc-example-flat-locale-all.ts +373 -0
- package/dist/templates/byline-examples/collections/doc-example-flat-locale-en.ts +283 -0
- package/dist/templates/byline-examples/collections/doc-example-tree-locale-all.ts +278 -0
- package/dist/templates/byline-examples/collections/doc-example-tree-locale-en.ts +205 -0
- package/dist/templates/byline-examples/collections/docs/admin.tsx +204 -0
- package/dist/templates/byline-examples/collections/docs/components/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/docs/components/feature-formatter.tsx +10 -0
- package/dist/templates/byline-examples/collections/docs/hooks/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/docs/index.ts +10 -0
- package/dist/templates/byline-examples/collections/docs/schema.ts +209 -0
- package/dist/templates/byline-examples/collections/docs-categories/admin.tsx +78 -0
- package/dist/templates/byline-examples/collections/docs-categories/components/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/docs-categories/hooks/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/docs-categories/index.ts +10 -0
- package/dist/templates/byline-examples/collections/docs-categories/schema.ts +33 -0
- package/dist/templates/byline-examples/collections/media/admin.tsx +188 -0
- package/dist/templates/byline-examples/collections/media/components/media-list-view.tsx +330 -0
- package/dist/templates/byline-examples/collections/media/components/media-thumbnail.tsx +63 -0
- package/dist/templates/byline-examples/collections/media/hooks/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/media/index.ts +10 -0
- package/dist/templates/byline-examples/collections/media/schema.ts +157 -0
- package/dist/templates/byline-examples/collections/news/admin.tsx +192 -0
- package/dist/templates/byline-examples/collections/news/components/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/news/hooks/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/news/index.ts +10 -0
- package/dist/templates/byline-examples/collections/news/schema.ts +91 -0
- package/dist/templates/byline-examples/collections/news-categories/admin.tsx +78 -0
- package/dist/templates/byline-examples/collections/news-categories/components/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/news-categories/hooks/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/news-categories/index.ts +10 -0
- package/dist/templates/byline-examples/collections/news-categories/schema.ts +33 -0
- package/dist/templates/byline-examples/collections/pages/admin.tsx +183 -0
- package/dist/templates/byline-examples/collections/pages/components/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/pages/hooks/.gitkeep +0 -0
- package/dist/templates/byline-examples/collections/pages/index.ts +10 -0
- package/dist/templates/byline-examples/collections/pages/schema.ts +96 -0
- package/dist/templates/byline-examples/components/length-indicator.tsx +138 -0
- package/dist/templates/byline-examples/components/pill.tsx +38 -0
- package/dist/templates/byline-examples/components/summary-length.tsx +39 -0
- package/dist/templates/byline-examples/fields/available-languages-field.ts +90 -0
- package/dist/templates/byline-examples/fields/lexical-richtext-compact.ts +88 -0
- package/dist/templates/byline-examples/i18n.ts +47 -0
- package/dist/templates/byline-examples/routes.ts +28 -0
- package/dist/templates/byline-examples/scripts/regenerate-media.ts +275 -0
- package/dist/templates/byline-examples/seed.ts +25 -0
- package/dist/templates/byline-examples/seeds/admin.ts +62 -0
- package/dist/templates/byline-examples/seeds/doc-categories.ts +71 -0
- package/dist/templates/byline-examples/seeds/docs.ts +293 -0
- package/dist/templates/byline-examples/seeds/news-categories.ts +71 -0
- package/dist/templates/byline-examples/server.config.ts +179 -0
- package/dist/templates/host/vite.config.ts +41 -0
- package/dist/templates/migrations/0000_condemned_kronos.sql +324 -0
- package/dist/templates/migrations/0001_sudden_phantom_reporter.sql +1 -0
- package/dist/templates/migrations/meta/0000_snapshot.json +2793 -0
- package/dist/templates/migrations/meta/0001_snapshot.json +2799 -0
- package/dist/templates/migrations/meta/_journal.json +20 -0
- package/dist/templates/routes/(byline)/admin/account/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/collections/$collection/$id/api.tsx +16 -0
- package/dist/templates/routes/(byline)/admin/collections/$collection/$id/history.tsx +19 -0
- package/dist/templates/routes/(byline)/admin/collections/$collection/$id/index.tsx +16 -0
- package/dist/templates/routes/(byline)/admin/collections/$collection/create.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/collections/$collection/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/permissions/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/roles/$id/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/roles/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/route.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/users/$id/index.tsx +11 -0
- package/dist/templates/routes/(byline)/admin/users/index.tsx +11 -0
- package/dist/templates/routes/(byline)/sign-in.tsx +11 -0
- package/dist/templates/ui-byline/blocks/photo-block/index.tsx +80 -0
- package/dist/templates/ui-byline/blocks/richtext-block/index.tsx +46 -0
- package/dist/templates/ui-byline/components/admonition/index.tsx +40 -0
- package/dist/templates/ui-byline/components/code/code-serializer.tsx +20 -0
- package/dist/templates/ui-byline/components/code/code.tsx +50 -0
- package/dist/templates/ui-byline/components/code/index.module.scss +137 -0
- package/dist/templates/ui-byline/components/code/index.ts +2 -0
- package/dist/templates/ui-byline/components/code/types.ts +5 -0
- package/dist/templates/ui-byline/components/code/utils.ts +20 -0
- package/dist/templates/ui-byline/components/heading-anchor/heading-anchor.tsx +69 -0
- package/dist/templates/ui-byline/components/heading-anchor/index.ts +1 -0
- package/dist/templates/ui-byline/components/heading-anchor/utils.ts +15 -0
- package/dist/templates/ui-byline/components/inline-image/index.tsx +109 -0
- package/dist/templates/ui-byline/components/layout/index.tsx +63 -0
- package/dist/templates/ui-byline/components/link/lang-link.tsx +70 -0
- package/dist/templates/ui-byline/components/link/link-field.tsx +298 -0
- package/dist/templates/ui-byline/components/link/link-lexical.tsx +191 -0
- package/dist/templates/ui-byline/components/list/index.ts +2 -0
- package/dist/templates/ui-byline/components/list/list-item.tsx +32 -0
- package/dist/templates/ui-byline/components/list/list.tsx +17 -0
- package/dist/templates/ui-byline/components/responsive-image/index.tsx +205 -0
- package/dist/templates/ui-byline/components/richtext-lexical/index.tsx +31 -0
- package/dist/templates/ui-byline/components/richtext-lexical/serialize/index.tsx +249 -0
- package/dist/templates/ui-byline/components/richtext-lexical/serialize/richtext-node-formats.ts +66 -0
- package/dist/templates/ui-byline/components/richtext-lexical/serialize/types.ts +48 -0
- package/dist/templates/ui-byline/components/richtext-lexical/serialize/utils.ts +15 -0
- package/dist/templates/ui-byline/components/table-cell/index.tsx +36 -0
- package/dist/templates/ui-byline/components/vimeo/index.tsx +21 -0
- package/dist/templates/ui-byline/components/youtube/index.tsx +22 -0
- package/dist/templates/ui-byline/render-blocks.tsx +71 -0
- package/dist/templates/ui-byline/types/i18n.ts +14 -0
- package/dist/templates/ui-byline/utils/image-sources.ts +102 -0
- package/dist/templates/ui-byline/utils/to-kebab-case.ts +5 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/diff.d.ts +4 -0
- package/dist/ui/diff.d.ts.map +1 -0
- package/dist/ui/diff.js +23 -0
- package/dist/ui/diff.js.map +1 -0
- package/dist/ui/grid.d.ts +7 -0
- package/dist/ui/grid.d.ts.map +1 -0
- package/dist/ui/grid.js +24 -0
- package/dist/ui/grid.js.map +1 -0
- package/dist/ui/logger.d.ts +14 -0
- package/dist/ui/logger.d.ts.map +1 -0
- package/dist/ui/logger.js +30 -0
- package/dist/ui/logger.js.map +1 -0
- package/dist/ui/snippet.d.ts +2 -0
- package/dist/ui/snippet.d.ts.map +1 -0
- package/dist/ui/snippet.js +7 -0
- package/dist/ui/snippet.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type * as React from 'react'
|
|
4
|
+
|
|
5
|
+
import { formatTextValue } from '@byline/core'
|
|
6
|
+
import cx from 'classnames'
|
|
7
|
+
|
|
8
|
+
import { extractHeadingText } from './utils.ts'
|
|
9
|
+
import type { SerializedLexicalNode } from '../richtext-lexical/serialize/types.ts'
|
|
10
|
+
|
|
11
|
+
type Heading = Extract<keyof React.JSX.IntrinsicElements, 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'>
|
|
12
|
+
|
|
13
|
+
export function HeadingWithAnchorSerializer({
|
|
14
|
+
node,
|
|
15
|
+
}: {
|
|
16
|
+
node: SerializedLexicalNode
|
|
17
|
+
}): React.JSX.Element {
|
|
18
|
+
const tag = node?.tag
|
|
19
|
+
const text = extractHeadingText(node?.children)
|
|
20
|
+
const headingId = formatTextValue(text)
|
|
21
|
+
const Element = tag as Heading
|
|
22
|
+
if (tag != null && (tag === 'h4' || tag === 'h5' || tag === 'h6')) {
|
|
23
|
+
return (
|
|
24
|
+
<Element
|
|
25
|
+
id={headingId}
|
|
26
|
+
className="clear-both relative font-normal text-gray-800 dark:text-gray-300"
|
|
27
|
+
>
|
|
28
|
+
{text}
|
|
29
|
+
</Element>
|
|
30
|
+
)
|
|
31
|
+
} else {
|
|
32
|
+
return (
|
|
33
|
+
<Element id={headingId} className="relative clear-both ">
|
|
34
|
+
<a href={`#${headingId}`} className="component--heading-anchor not-prose no-underline">
|
|
35
|
+
<span className="component--heading-anchor-text font-bold text-theme-900 dark:text-white">
|
|
36
|
+
{text}
|
|
37
|
+
</span>
|
|
38
|
+
<span
|
|
39
|
+
className={cx(
|
|
40
|
+
'component--heading-anchor-icon absolute p-0 leading-4 sm:inline-block',
|
|
41
|
+
'right-[-0.125em] top-[-0.4em] m-0 -translate-y-1 translate-x-1 sm:right-auto sm:top-auto',
|
|
42
|
+
'transition-all duration-200 ease-in-out',
|
|
43
|
+
'text-gray-300 hover:text-gray-400 dark:text-gray-700 dark:hover:text-gray-600',
|
|
44
|
+
'aria-hidden="true"'
|
|
45
|
+
)}
|
|
46
|
+
>
|
|
47
|
+
<svg
|
|
48
|
+
aria-hidden="true"
|
|
49
|
+
tabIndex={-1}
|
|
50
|
+
className="inline"
|
|
51
|
+
width="0.85em"
|
|
52
|
+
height="0.85em"
|
|
53
|
+
viewBox="0 0 15 15"
|
|
54
|
+
fill="none"
|
|
55
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
56
|
+
>
|
|
57
|
+
<path
|
|
58
|
+
d="M4.62471 4.00001L4.56402 4.00001C4.04134 3.99993 3.70687 3.99988 3.4182 4.055C2.2379 4.28039 1.29846 5.17053 1.05815 6.33035C0.999538 6.61321 0.999604 6.93998 0.999703 7.43689L0.999711 7.50001L0.999703 7.56312C0.999604 8.06003 0.999538 8.3868 1.05815 8.66966C1.29846 9.82948 2.2379 10.7196 3.4182 10.945C3.70688 11.0001 4.04135 11.0001 4.56403 11L4.62471 11H5.49971C5.7759 11 5.99971 10.7762 5.99971 10.5C5.99971 10.2239 5.7759 10 5.49971 10H4.62471C4.02084 10 3.78907 9.99777 3.60577 9.96277C2.80262 9.8094 2.18169 9.21108 2.02456 8.42678C1.98838 8.24809 1.98971 8.02242 1.98971 7.50001C1.98971 6.9776 1.98838 6.75192 2.02456 6.57323C2.18169 5.78893 2.80262 5.19061 3.60577 5.03724C3.78907 5.00225 4.02084 5.00001 4.62471 5.00001H5.49971C5.7759 5.00001 5.99971 4.77615 5.99971 4.50001C5.99971 4.22387 5.7759 4.00001 5.49971 4.00001H4.62471ZM10.3747 4.00001H9.49971C9.22357 4.00001 8.99971 4.22387 8.99971 4.50001C8.99971 4.77615 9.22357 5.00001 9.49971 5.00001H10.3747C10.9786 5.00001 11.2104 5.00225 11.3937 5.03724C12.1968 5.19061 12.8177 5.78893 12.9749 6.57323C13.0111 6.75192 13.0097 6.9776 13.0097 7.50001C13.0097 8.02242 13.0111 8.24809 12.9749 8.42678C12.8177 9.21108 12.1968 9.8094 11.3937 9.96277C11.2104 9.99777 10.9786 10 10.3747 10H9.49971C9.22357 10 8.99971 10.2239 8.99971 10.5C8.99971 10.7762 9.22357 11 9.49971 11H10.3747L10.4354 11C10.9581 11.0001 11.2925 11.0001 11.5812 10.945C12.7615 10.7196 13.701 9.82948 13.9413 8.66966C13.9999 8.3868 13.9998 8.06003 13.9997 7.56312L13.9997 7.50001L13.9997 7.43689C13.9998 6.93998 13.9999 6.61321 13.9413 6.33035C13.701 5.17053 12.7615 4.28039 11.5812 4.055C11.2925 3.99988 10.9581 3.99993 10.4354 4.00001L10.3747 4.00001ZM4.99971 7.50001C4.99971 7.22387 5.22357 7.00001 5.49971 7.00001H9.49971C9.7759 7.00001 9.99971 7.22387 9.99971 7.50001C9.99971 7.77615 9.7759 8.00001 9.49971 8.00001H5.49971C5.22357 8.00001 4.99971 7.77615 4.99971 7.50001Z"
|
|
59
|
+
fill="currentColor"
|
|
60
|
+
fillRule="evenodd"
|
|
61
|
+
clipRule="evenodd"
|
|
62
|
+
/>
|
|
63
|
+
</svg>
|
|
64
|
+
</span>
|
|
65
|
+
</a>
|
|
66
|
+
</Element>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './heading-anchor.tsx'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SerializedLexicalNode } from '../richtext-lexical/serialize/types.ts'
|
|
2
|
+
|
|
3
|
+
export function extractHeadingText(nodes?: SerializedLexicalNode[], text: string = ''): string {
|
|
4
|
+
if (nodes != null) {
|
|
5
|
+
for (const node of nodes) {
|
|
6
|
+
if (node.type === 'text' && node.text != null) {
|
|
7
|
+
text = text + node.text
|
|
8
|
+
}
|
|
9
|
+
if (node.children != null) {
|
|
10
|
+
extractHeadingText(node.children, text)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return text
|
|
15
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
|
|
5
|
+
import type { StoredFileValue } from '@byline/core'
|
|
6
|
+
import type { InlineImagePosition, SerializedInlineImageNode } from '@byline/richtext-lexical'
|
|
7
|
+
import { FadeInLift } from '@byline/ui'
|
|
8
|
+
|
|
9
|
+
import { ResponsiveImage } from '../responsive-image/index.tsx'
|
|
10
|
+
import type { Locale } from '@/ui/byline/types/i18n'
|
|
11
|
+
import type { SerializeOptions, SerializeProps } from '../richtext-lexical/serialize/index.tsx'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Map the inline-image `position` (a layout choice the editor exposes
|
|
15
|
+
* via radio buttons) onto the public renderer's `<ResponsiveImage>`
|
|
16
|
+
* size cap and constrained-layout flag. Mirrors the editor-side
|
|
17
|
+
* `variantFor()` heuristic in `@byline/richtext-lexical`'s
|
|
18
|
+
* `inline-image-plugin/utils.ts` so the public render and the editor
|
|
19
|
+
* preview agree on which variants matter.
|
|
20
|
+
*
|
|
21
|
+
* - `left` / `right` — floated 50% column on desktop. Cap at the tablet
|
|
22
|
+
* variant; flag `constrainedLayout` so the `sizes` hint halves the
|
|
23
|
+
* desktop viewport portion.
|
|
24
|
+
* - `full` / `default` — main article column (~920px). Tablet cap is
|
|
25
|
+
* plenty; no extra constraint.
|
|
26
|
+
* - `wide` — bleeds beyond the article. Full variant set; no constraint.
|
|
27
|
+
*/
|
|
28
|
+
const POSITION_TO_SIZE: Record<
|
|
29
|
+
NonNullable<InlineImagePosition>,
|
|
30
|
+
{ size: 'large' | 'medium' | 'small'; constrainedLayout: boolean }
|
|
31
|
+
> = {
|
|
32
|
+
left: { size: 'medium', constrainedLayout: true },
|
|
33
|
+
right: { size: 'medium', constrainedLayout: true },
|
|
34
|
+
full: { size: 'medium', constrainedLayout: false },
|
|
35
|
+
default: { size: 'medium', constrainedLayout: false },
|
|
36
|
+
wide: { size: 'large', constrainedLayout: false },
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface Props {
|
|
40
|
+
node: SerializedInlineImageNode
|
|
41
|
+
serialize: ({ nodes, options }: SerializeProps) => React.JSX.Element
|
|
42
|
+
lng: Locale
|
|
43
|
+
options: SerializeOptions
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function InlineImageSerializer({ node, serialize, lng, options }: Props): React.JSX.Element {
|
|
47
|
+
const { showCaption, position, altText, document: pickerDoc, caption } = node
|
|
48
|
+
const image = pickerDoc?.image as StoredFileValue | undefined
|
|
49
|
+
|
|
50
|
+
const floatLeft = position === 'left'
|
|
51
|
+
const floatRight = position === 'right'
|
|
52
|
+
const isFloat = floatLeft || floatRight
|
|
53
|
+
|
|
54
|
+
const { size, constrainedLayout } = POSITION_TO_SIZE[position ?? 'default']
|
|
55
|
+
|
|
56
|
+
let classes: string
|
|
57
|
+
if (floatLeft) {
|
|
58
|
+
classes =
|
|
59
|
+
'inline-image-block w-full sm:w-[50%] float-left mt-5 mb-5 sm:mt-[0.5rem] sm:mr-[1.2rem] sm:mb-1 sm:ml-0'
|
|
60
|
+
} else if (floatRight) {
|
|
61
|
+
classes =
|
|
62
|
+
'inline-image-block w-full sm:w-[50%] float-right mt-5 mb-5 sm:mt-[0.5rem] sm:ml-[1rem] sm:mb-1 sm:mr-[1rem]'
|
|
63
|
+
} else {
|
|
64
|
+
classes = 'inline-image-block block w-full mt-5 mb-5'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// For now, if animation is disabled we must be inside a table cell
|
|
68
|
+
// (or similar non-animatable host); also disable bleed-to-edge.
|
|
69
|
+
const animationDisabled = options?.disableAnimation === true
|
|
70
|
+
|
|
71
|
+
const Img = (
|
|
72
|
+
<ResponsiveImage
|
|
73
|
+
image={image}
|
|
74
|
+
size={size}
|
|
75
|
+
constrainedLayout={constrainedLayout}
|
|
76
|
+
bleedOnMobile={!animationDisabled && !isFloat}
|
|
77
|
+
alt={altText}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
const ImgSlot = animationDisabled ? (
|
|
82
|
+
Img
|
|
83
|
+
) : (
|
|
84
|
+
<FadeInLift as="span" delay={0.1} className="block">
|
|
85
|
+
{Img}
|
|
86
|
+
</FadeInLift>
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if (showCaption) {
|
|
90
|
+
return (
|
|
91
|
+
<span className={classes}>
|
|
92
|
+
{ImgSlot}
|
|
93
|
+
<span className="block inline-image-block--caption">
|
|
94
|
+
{caption?.editorState?.root?.children != null ? (
|
|
95
|
+
serialize({
|
|
96
|
+
nodes: caption.editorState.root.children,
|
|
97
|
+
lng,
|
|
98
|
+
options: { renderParagraphInline: true },
|
|
99
|
+
})
|
|
100
|
+
) : (
|
|
101
|
+
<span>Caption not found for inline image.</span>
|
|
102
|
+
)}
|
|
103
|
+
</span>
|
|
104
|
+
</span>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return <span className={classes}>{ImgSlot}</span>
|
|
109
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
|
|
5
|
+
import cx from 'classnames'
|
|
6
|
+
|
|
7
|
+
import type { Locale } from '@/ui/byline/types/i18n'
|
|
8
|
+
import type { SerializeOptions, SerializeProps } from '../richtext-lexical/serialize/index.tsx'
|
|
9
|
+
import type { SerializedLexicalNode } from '../richtext-lexical/serialize/types.ts'
|
|
10
|
+
|
|
11
|
+
const layoutMap = {
|
|
12
|
+
'1fr 1fr': 'grid-cols-[1fr_1fr]',
|
|
13
|
+
'1fr 3fr': 'grid-cols-[1fr_3fr]',
|
|
14
|
+
'3fr 1fr': 'grid-cols-[3fr_1fr]',
|
|
15
|
+
'1fr 1fr 1fr': 'grid-cols-[1fr_1fr_1fr]',
|
|
16
|
+
'1fr 2fr 1fr': 'grid-cols-[1fr_2fr_1fr]',
|
|
17
|
+
'1fr 1fr 1fr 1fr': 'grid-cols-[1fr_1fr_1fr_1fr]',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function LayoutContainerSerializer({
|
|
21
|
+
node,
|
|
22
|
+
serialize,
|
|
23
|
+
lng,
|
|
24
|
+
options,
|
|
25
|
+
}: {
|
|
26
|
+
node: SerializedLexicalNode
|
|
27
|
+
serialize: ({ nodes }: SerializeProps) => React.JSX.Element
|
|
28
|
+
lng: Locale
|
|
29
|
+
options: SerializeOptions
|
|
30
|
+
}): React.JSX.Element {
|
|
31
|
+
const gridColumns = layoutMap[node.templateColumns as keyof typeof layoutMap]
|
|
32
|
+
return (
|
|
33
|
+
<div className={cx('sm:grid gap-5 my-5', gridColumns)}>
|
|
34
|
+
{node?.children != null ? (
|
|
35
|
+
serialize({ nodes: node?.children, lng, options })
|
|
36
|
+
) : (
|
|
37
|
+
<span>Content not found for layout container.</span>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function LayoutItemSerializer({
|
|
44
|
+
node,
|
|
45
|
+
serialize,
|
|
46
|
+
lng,
|
|
47
|
+
options,
|
|
48
|
+
}: {
|
|
49
|
+
node: SerializedLexicalNode
|
|
50
|
+
serialize: ({ nodes }: SerializeProps) => React.JSX.Element
|
|
51
|
+
lng: Locale
|
|
52
|
+
options: SerializeOptions
|
|
53
|
+
}): React.JSX.Element {
|
|
54
|
+
return (
|
|
55
|
+
<div className="mb-5 sm:mb-0">
|
|
56
|
+
{node?.children != null ? (
|
|
57
|
+
serialize({ nodes: node?.children, lng, options })
|
|
58
|
+
) : (
|
|
59
|
+
<span>Content not found for layout item.</span>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale-aware Link STUB.
|
|
3
|
+
*
|
|
4
|
+
* The reference webapp ships a real `LangLink` that injects an optional
|
|
5
|
+
* `{-$lng}` path parameter onto TanStack Router's `<Link>` so that the
|
|
6
|
+
* current locale survives client-side navigation. This stub is a thin
|
|
7
|
+
* pass-through — it accepts the `lng` prop but does NOT prefix URLs.
|
|
8
|
+
*
|
|
9
|
+
* If your app is single-locale, this is fine as-is.
|
|
10
|
+
*
|
|
11
|
+
* If you have a multi-locale strategy, replace the body with your own
|
|
12
|
+
* Link wrapper. The reference implementation lives at
|
|
13
|
+
* apps/webapp/src/i18n/components/lang-link.tsx
|
|
14
|
+
* in https://github.com/Byline-CMS/bylinecms.dev.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type React from 'react'
|
|
18
|
+
import { Link } from '@tanstack/react-router'
|
|
19
|
+
|
|
20
|
+
import type { Locale } from '../../types/i18n'
|
|
21
|
+
|
|
22
|
+
export interface LangLinkProps
|
|
23
|
+
extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> {
|
|
24
|
+
to: string
|
|
25
|
+
lng?: Locale
|
|
26
|
+
params?: Record<string, string | undefined>
|
|
27
|
+
search?:
|
|
28
|
+
| true
|
|
29
|
+
| Record<string, unknown>
|
|
30
|
+
| ((current: Record<string, unknown>) => Record<string, unknown>)
|
|
31
|
+
forceReload?: boolean
|
|
32
|
+
scroll?: boolean
|
|
33
|
+
replace?: boolean
|
|
34
|
+
ref?: React.Ref<HTMLAnchorElement>
|
|
35
|
+
children?: React.ReactNode
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function LangLink({
|
|
39
|
+
to,
|
|
40
|
+
lng: _lng,
|
|
41
|
+
params,
|
|
42
|
+
search,
|
|
43
|
+
forceReload,
|
|
44
|
+
scroll,
|
|
45
|
+
replace,
|
|
46
|
+
ref,
|
|
47
|
+
children,
|
|
48
|
+
...rest
|
|
49
|
+
}: LangLinkProps): React.JSX.Element {
|
|
50
|
+
if (forceReload) {
|
|
51
|
+
return (
|
|
52
|
+
<a href={to} ref={ref} {...rest}>
|
|
53
|
+
{children}
|
|
54
|
+
</a>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
return (
|
|
58
|
+
<Link
|
|
59
|
+
to={to}
|
|
60
|
+
params={params}
|
|
61
|
+
search={search}
|
|
62
|
+
resetScroll={scroll}
|
|
63
|
+
replace={replace}
|
|
64
|
+
ref={ref}
|
|
65
|
+
{...rest}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
</Link>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
|
|
5
|
+
import { Button, type Intent } from '@byline/ui'
|
|
6
|
+
import cx from 'classnames'
|
|
7
|
+
|
|
8
|
+
import { LangLink } from '@/ui/byline/components/link/lang-link'
|
|
9
|
+
import type { Locale } from '@/ui/byline/types/i18n'
|
|
10
|
+
|
|
11
|
+
export interface LinkFieldAttributes {
|
|
12
|
+
id?: string | null
|
|
13
|
+
type?: ('reference' | 'custom') | null
|
|
14
|
+
newTab?: boolean | null
|
|
15
|
+
label: string
|
|
16
|
+
customId?: string | null
|
|
17
|
+
url?: string | null
|
|
18
|
+
appearance?: ('primary' | 'secondary') | null
|
|
19
|
+
reference?: {
|
|
20
|
+
value: string
|
|
21
|
+
relationTo: string
|
|
22
|
+
data: {
|
|
23
|
+
id: string
|
|
24
|
+
title: string
|
|
25
|
+
slug: string
|
|
26
|
+
collectionAlias: string
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface LinkFieldProps extends React.ComponentPropsWithoutRef<'a'> {
|
|
32
|
+
link: LinkFieldAttributes
|
|
33
|
+
size?: 'sm' | 'md' | 'lg'
|
|
34
|
+
lng: Locale
|
|
35
|
+
className?: string
|
|
36
|
+
onMouseEnter?: () => void
|
|
37
|
+
onMouseLeave?: () => void
|
|
38
|
+
children?: React.ReactNode
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function manageRel(input: string, action: 'add' | 'remove', value: string): string {
|
|
42
|
+
let result: string
|
|
43
|
+
let mutableInput = `${input}`
|
|
44
|
+
if (action === 'add') {
|
|
45
|
+
// if we somehow got out of sync - clean up
|
|
46
|
+
if (mutableInput.includes(value)) {
|
|
47
|
+
const re = new RegExp(value, 'g')
|
|
48
|
+
mutableInput = mutableInput.replace(re, '').trim()
|
|
49
|
+
}
|
|
50
|
+
mutableInput = mutableInput.trim()
|
|
51
|
+
result = mutableInput.length === 0 ? `${value}` : `${mutableInput} ${value}`
|
|
52
|
+
} else {
|
|
53
|
+
const re = new RegExp(value, 'g')
|
|
54
|
+
result = mutableInput.replace(re, '').trim()
|
|
55
|
+
}
|
|
56
|
+
return result
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getHref(args: LinkFieldAttributes): string {
|
|
60
|
+
let href = ''
|
|
61
|
+
const publicWebsiteUrl = '/' // getPublicWebsiteUrl()
|
|
62
|
+
const { type, url } = args
|
|
63
|
+
|
|
64
|
+
if ((type === 'custom' || type === undefined) && url != null) {
|
|
65
|
+
href = url
|
|
66
|
+
} else if (
|
|
67
|
+
type === 'reference' &&
|
|
68
|
+
args.reference?.relationTo != null &&
|
|
69
|
+
args.reference?.data?.slug != null
|
|
70
|
+
) {
|
|
71
|
+
const collection = args?.reference?.relationTo
|
|
72
|
+
// biome-ignore lint/correctness/noUnsafeOptionalChaining: To be refactored in the future
|
|
73
|
+
const { slug, collectionAlias } = args?.reference?.data
|
|
74
|
+
if (collectionAlias != null) {
|
|
75
|
+
// The alias might be for the root
|
|
76
|
+
if (collectionAlias.length === 0) {
|
|
77
|
+
href = `/${slug}`
|
|
78
|
+
} else {
|
|
79
|
+
href = `/${collectionAlias}/${slug}`
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
href = `/${collection}/${slug}`
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const hrefIsLocal = ['tel:', 'mailto:', '/'].some((prefix) => href.startsWith(prefix))
|
|
87
|
+
if (!hrefIsLocal) {
|
|
88
|
+
try {
|
|
89
|
+
const objectURL = new URL(href)
|
|
90
|
+
if (objectURL.origin === publicWebsiteUrl) {
|
|
91
|
+
href = objectURL.href.replace(publicWebsiteUrl, '')
|
|
92
|
+
}
|
|
93
|
+
} catch (e) {
|
|
94
|
+
console.error(`Failed to format url: ${href}`, e) // eslint-disable-line no-console
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return href
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getAdditionalProps(
|
|
102
|
+
args: LinkFieldAttributes,
|
|
103
|
+
href: string
|
|
104
|
+
): {
|
|
105
|
+
rel: string | undefined
|
|
106
|
+
target: string | undefined
|
|
107
|
+
} {
|
|
108
|
+
const additionalProps: {
|
|
109
|
+
rel: string | undefined
|
|
110
|
+
target: string | undefined
|
|
111
|
+
} = {
|
|
112
|
+
rel: undefined,
|
|
113
|
+
target: undefined,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let rel = ''
|
|
117
|
+
if (args.newTab === true) rel = manageRel(rel, 'add', 'noopener')
|
|
118
|
+
additionalProps.rel = rel
|
|
119
|
+
|
|
120
|
+
if (args.newTab === true) {
|
|
121
|
+
additionalProps.target = '_blank'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!href.startsWith('/')) {
|
|
125
|
+
additionalProps.target = '_blank'
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (additionalProps.rel == null || additionalProps.rel.length === 0) delete additionalProps.rel
|
|
129
|
+
if (additionalProps.target == null) delete additionalProps.target
|
|
130
|
+
|
|
131
|
+
return additionalProps
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* DefaultLink
|
|
136
|
+
* @param param0
|
|
137
|
+
* @returns
|
|
138
|
+
*/
|
|
139
|
+
export function DefaultLink({
|
|
140
|
+
link,
|
|
141
|
+
lng,
|
|
142
|
+
className,
|
|
143
|
+
onMouseEnter,
|
|
144
|
+
onMouseLeave,
|
|
145
|
+
...rest
|
|
146
|
+
}: LinkFieldProps): React.JSX.Element {
|
|
147
|
+
const href = getHref(link)
|
|
148
|
+
const additionalProps = getAdditionalProps(link, href)
|
|
149
|
+
|
|
150
|
+
if (href.startsWith('/')) {
|
|
151
|
+
return (
|
|
152
|
+
<LangLink
|
|
153
|
+
lng={lng}
|
|
154
|
+
to={href}
|
|
155
|
+
{...additionalProps}
|
|
156
|
+
className={className}
|
|
157
|
+
onMouseEnter={onMouseEnter}
|
|
158
|
+
onMouseLeave={onMouseLeave}
|
|
159
|
+
{...rest}
|
|
160
|
+
>
|
|
161
|
+
{link.label}
|
|
162
|
+
</LangLink>
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
return (
|
|
166
|
+
<a
|
|
167
|
+
href={href}
|
|
168
|
+
{...additionalProps}
|
|
169
|
+
className={cx(className, '!no-underline')}
|
|
170
|
+
onMouseEnter={onMouseEnter}
|
|
171
|
+
onMouseLeave={onMouseLeave}
|
|
172
|
+
{...rest}
|
|
173
|
+
>
|
|
174
|
+
<span className="underline">{link.label}</span>
|
|
175
|
+
<span style={{ display: 'inline', whiteSpace: 'nowrap' }}>
|
|
176
|
+
 
|
|
177
|
+
<svg
|
|
178
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
179
|
+
className="fill-[#001827] dark:fill-gray-50"
|
|
180
|
+
style={{ display: 'inline' }}
|
|
181
|
+
focusable="false"
|
|
182
|
+
aria-hidden="true"
|
|
183
|
+
height="14px"
|
|
184
|
+
width="14px"
|
|
185
|
+
viewBox="0 0 24 24"
|
|
186
|
+
>
|
|
187
|
+
<path d="M0 0h24v24H0V0z" fill="none" />
|
|
188
|
+
<path d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" />
|
|
189
|
+
</svg>
|
|
190
|
+
</span>
|
|
191
|
+
</a>
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* ButtonLink
|
|
197
|
+
* @param param0
|
|
198
|
+
* @returns
|
|
199
|
+
*/
|
|
200
|
+
export function ButtonLink({
|
|
201
|
+
link,
|
|
202
|
+
size = 'md',
|
|
203
|
+
lng,
|
|
204
|
+
className,
|
|
205
|
+
onMouseEnter,
|
|
206
|
+
onMouseLeave,
|
|
207
|
+
...rest
|
|
208
|
+
}: LinkFieldProps): React.JSX.Element {
|
|
209
|
+
const href = getHref(link)
|
|
210
|
+
const additionalProps = getAdditionalProps(link, href)
|
|
211
|
+
|
|
212
|
+
if (href.startsWith('/')) {
|
|
213
|
+
return (
|
|
214
|
+
<Button
|
|
215
|
+
intent={link?.appearance as Intent}
|
|
216
|
+
size={size}
|
|
217
|
+
render={
|
|
218
|
+
<LangLink
|
|
219
|
+
lng={lng}
|
|
220
|
+
to={href}
|
|
221
|
+
{...additionalProps}
|
|
222
|
+
className={cx(className, '!no-underline')}
|
|
223
|
+
onMouseEnter={onMouseEnter}
|
|
224
|
+
onMouseLeave={onMouseLeave}
|
|
225
|
+
{...rest}
|
|
226
|
+
/>
|
|
227
|
+
}
|
|
228
|
+
>
|
|
229
|
+
{link.label}
|
|
230
|
+
</Button>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
return (
|
|
234
|
+
<Button
|
|
235
|
+
intent={link?.appearance as Intent}
|
|
236
|
+
size={size}
|
|
237
|
+
render={
|
|
238
|
+
<a
|
|
239
|
+
href={href}
|
|
240
|
+
{...additionalProps}
|
|
241
|
+
className={cx(className, '!no-underline')}
|
|
242
|
+
onMouseEnter={onMouseEnter}
|
|
243
|
+
onMouseLeave={onMouseLeave}
|
|
244
|
+
{...rest}
|
|
245
|
+
/>
|
|
246
|
+
}
|
|
247
|
+
>
|
|
248
|
+
{link.label}
|
|
249
|
+
</Button>
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* We export LinkField which will attempt to automatically switch
|
|
255
|
+
* between ButtonLink and DefaultLink based on the appearance of the link.
|
|
256
|
+
*
|
|
257
|
+
* For more control including className and style overrides, a block may
|
|
258
|
+
* choose to use the above ButtonLink or DefaultLink directly.
|
|
259
|
+
*
|
|
260
|
+
* @param param0
|
|
261
|
+
* @returns
|
|
262
|
+
*/
|
|
263
|
+
export function LinkField({
|
|
264
|
+
link,
|
|
265
|
+
lng,
|
|
266
|
+
size = 'md',
|
|
267
|
+
className,
|
|
268
|
+
onMouseEnter,
|
|
269
|
+
onMouseLeave,
|
|
270
|
+
...rest
|
|
271
|
+
}: LinkFieldProps): React.JSX.Element {
|
|
272
|
+
if (
|
|
273
|
+
link.appearance != null &&
|
|
274
|
+
(link.appearance === 'primary' || link.appearance === 'secondary')
|
|
275
|
+
) {
|
|
276
|
+
return (
|
|
277
|
+
<ButtonLink
|
|
278
|
+
size={size}
|
|
279
|
+
link={link}
|
|
280
|
+
lng={lng}
|
|
281
|
+
className={className}
|
|
282
|
+
onMouseEnter={onMouseEnter}
|
|
283
|
+
onMouseLeave={onMouseLeave}
|
|
284
|
+
{...rest}
|
|
285
|
+
/>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
return (
|
|
289
|
+
<DefaultLink
|
|
290
|
+
link={link}
|
|
291
|
+
lng={lng}
|
|
292
|
+
className={className}
|
|
293
|
+
onMouseEnter={onMouseEnter}
|
|
294
|
+
onMouseLeave={onMouseLeave}
|
|
295
|
+
{...rest}
|
|
296
|
+
/>
|
|
297
|
+
)
|
|
298
|
+
}
|