@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,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CollectionFieldData } from '@byline/core'
|
|
10
|
+
import { defineCollection, defineWorkflow } from '@byline/core'
|
|
11
|
+
|
|
12
|
+
import { availableLanguagesField } from '~/fields/available-languages-field.js'
|
|
13
|
+
|
|
14
|
+
// ---- Schema (server-safe, no UI concerns) ----
|
|
15
|
+
|
|
16
|
+
export const Pages = defineCollection({
|
|
17
|
+
path: 'pages',
|
|
18
|
+
labels: {
|
|
19
|
+
singular: 'Page',
|
|
20
|
+
plural: 'Pages',
|
|
21
|
+
},
|
|
22
|
+
// Workflow: defineWorkflow() guarantees draft, published, and archived are
|
|
23
|
+
// always present and correctly ordered. No custom statuses here — the
|
|
24
|
+
// standard three-step lifecycle is used.
|
|
25
|
+
//
|
|
26
|
+
// Resulting order: [draft, published, archived]
|
|
27
|
+
workflow: defineWorkflow({
|
|
28
|
+
draft: { label: 'Draft', verb: 'Revert to Draft' },
|
|
29
|
+
published: { label: 'Published', verb: 'Publish' },
|
|
30
|
+
archived: { label: 'Archived', verb: 'Archive' },
|
|
31
|
+
}),
|
|
32
|
+
showStats: true,
|
|
33
|
+
search: { fields: ['title'] },
|
|
34
|
+
useAsTitle: 'title',
|
|
35
|
+
useAsPath: 'title',
|
|
36
|
+
fields: [
|
|
37
|
+
{ name: 'title', label: 'Title', type: 'text', localized: true },
|
|
38
|
+
{
|
|
39
|
+
name: 'summary',
|
|
40
|
+
label: 'Summary',
|
|
41
|
+
type: 'textArea',
|
|
42
|
+
localized: true,
|
|
43
|
+
helpText:
|
|
44
|
+
'Enter a short summary. The first 150 characters are used for social media meta descriptions. Aim for 100–300 characters.',
|
|
45
|
+
},
|
|
46
|
+
// Relation field demo. Points at the Media upload collection
|
|
47
|
+
// so editors can choose a feature image via the relation picker widget.
|
|
48
|
+
// Set `displayField: 'title'` so the picker's row label reads from the
|
|
49
|
+
// uploaded item's `title` field rather than falling back to its path.
|
|
50
|
+
// Will display the picker defined columns if present in the admin.tsx
|
|
51
|
+
// configuration.
|
|
52
|
+
{
|
|
53
|
+
name: 'featureImage',
|
|
54
|
+
label: 'Feature Image',
|
|
55
|
+
type: 'relation',
|
|
56
|
+
targetCollection: 'media',
|
|
57
|
+
displayField: 'title',
|
|
58
|
+
optional: true,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'category',
|
|
62
|
+
label: 'Category',
|
|
63
|
+
type: 'select',
|
|
64
|
+
optional: true,
|
|
65
|
+
helpText: 'Select a category for this page',
|
|
66
|
+
options: [
|
|
67
|
+
{ label: 'Foo', value: 'foo' },
|
|
68
|
+
{ label: 'Bar', value: 'bar' },
|
|
69
|
+
{ label: 'Baz', value: 'baz' },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'content',
|
|
74
|
+
label: 'Content',
|
|
75
|
+
type: 'richText',
|
|
76
|
+
helpText: 'Enter the main content for this page.',
|
|
77
|
+
localized: true,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'publishedOn',
|
|
81
|
+
label: 'Published On',
|
|
82
|
+
type: 'datetime',
|
|
83
|
+
mode: 'datetime',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'featured',
|
|
87
|
+
label: 'Featured',
|
|
88
|
+
type: 'checkbox',
|
|
89
|
+
optional: true,
|
|
90
|
+
helpText: 'Feature this page.',
|
|
91
|
+
},
|
|
92
|
+
availableLanguagesField(),
|
|
93
|
+
],
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
export type PageFields = CollectionFieldData<typeof Pages>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Portions Copyright (c) Payload CMS, LLC info@payloadcms.com
|
|
5
|
+
* Copyright notices appear at the top of source files where applicable
|
|
6
|
+
* and are licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree
|
|
8
|
+
*
|
|
9
|
+
* https://github.com/payloadcms/payload/
|
|
10
|
+
* From the Payload SEO plugin
|
|
11
|
+
* https://github.com/payloadcms/payload/tree/main/packages/plugin-seo
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type React from 'react'
|
|
15
|
+
import { Fragment, useEffect, useState } from 'react'
|
|
16
|
+
|
|
17
|
+
import { Pill } from './pill'
|
|
18
|
+
|
|
19
|
+
export const LengthIndicator: React.FC<{
|
|
20
|
+
maxLength?: number
|
|
21
|
+
minLength?: number
|
|
22
|
+
text?: string
|
|
23
|
+
}> = (props) => {
|
|
24
|
+
const { maxLength = 0, minLength = 0, text } = props
|
|
25
|
+
|
|
26
|
+
const [labelStyle, setLabelStyle] = useState({
|
|
27
|
+
backgroundColor: '',
|
|
28
|
+
color: '',
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const [label, setLabel] = useState('')
|
|
32
|
+
const [barWidth, setBarWidth] = useState<number>(0)
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const textLength = text?.length ?? 0
|
|
36
|
+
|
|
37
|
+
if (textLength === 0) {
|
|
38
|
+
setLabel('Missing')
|
|
39
|
+
setLabelStyle({
|
|
40
|
+
backgroundColor: 'red',
|
|
41
|
+
color: 'white',
|
|
42
|
+
})
|
|
43
|
+
setBarWidth(0)
|
|
44
|
+
} else {
|
|
45
|
+
const progress = (textLength - minLength) / (maxLength - minLength)
|
|
46
|
+
|
|
47
|
+
if (progress < 0) {
|
|
48
|
+
const ratioUntilMin = textLength / minLength
|
|
49
|
+
|
|
50
|
+
if (ratioUntilMin > 0.9) {
|
|
51
|
+
setLabel('Almost there')
|
|
52
|
+
setLabelStyle({
|
|
53
|
+
backgroundColor: 'orange',
|
|
54
|
+
color: 'white',
|
|
55
|
+
})
|
|
56
|
+
} else {
|
|
57
|
+
setLabel('Too short')
|
|
58
|
+
setLabelStyle({
|
|
59
|
+
backgroundColor: 'orangered',
|
|
60
|
+
color: 'white',
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setBarWidth(ratioUntilMin)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (progress >= 0 && progress <= 1) {
|
|
68
|
+
setLabel('Good')
|
|
69
|
+
setLabelStyle({
|
|
70
|
+
backgroundColor: 'green',
|
|
71
|
+
color: 'white',
|
|
72
|
+
})
|
|
73
|
+
setBarWidth(progress)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (progress > 1) {
|
|
77
|
+
setLabel('Too long')
|
|
78
|
+
setLabelStyle({
|
|
79
|
+
backgroundColor: 'red',
|
|
80
|
+
color: 'white',
|
|
81
|
+
})
|
|
82
|
+
setBarWidth(1)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}, [minLength, maxLength, text])
|
|
86
|
+
|
|
87
|
+
const textLength = text?.length ?? 0
|
|
88
|
+
|
|
89
|
+
const charsUntilMax = maxLength - textLength
|
|
90
|
+
const charsUntilMin = minLength - textLength
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
style={{
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
display: 'flex',
|
|
97
|
+
width: '100%',
|
|
98
|
+
}}
|
|
99
|
+
>
|
|
100
|
+
<Pill backgroundColor={labelStyle.backgroundColor} color={labelStyle.color} label={label} />
|
|
101
|
+
<div
|
|
102
|
+
style={{
|
|
103
|
+
flexShrink: 0,
|
|
104
|
+
lineHeight: 1,
|
|
105
|
+
marginRight: '10px',
|
|
106
|
+
whiteSpace: 'nowrap',
|
|
107
|
+
fontVariantNumeric: 'tabular-nums',
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
<small>
|
|
111
|
+
{`${text?.length ?? 0}/${minLength}-${maxLength} chars, `}
|
|
112
|
+
{(textLength === 0 || charsUntilMin > 0) && `${charsUntilMin} to go`}
|
|
113
|
+
{charsUntilMin <= 0 && charsUntilMax >= 0 && `${charsUntilMax} left over`}
|
|
114
|
+
{charsUntilMax < 0 && <Fragment>{`${charsUntilMax * -1} too many`}</Fragment>}
|
|
115
|
+
</small>
|
|
116
|
+
</div>
|
|
117
|
+
<div
|
|
118
|
+
style={{
|
|
119
|
+
backgroundColor: '#F3F3F3',
|
|
120
|
+
height: '2px',
|
|
121
|
+
position: 'relative',
|
|
122
|
+
width: '100%',
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
<div
|
|
126
|
+
style={{
|
|
127
|
+
backgroundColor: labelStyle.backgroundColor,
|
|
128
|
+
height: '100%',
|
|
129
|
+
left: 0,
|
|
130
|
+
position: 'absolute',
|
|
131
|
+
top: 0,
|
|
132
|
+
width: `${barWidth * 100}%`,
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Portions Copyright (c) Payload CMS, LLC info@payloadcms.com
|
|
5
|
+
* Copyright notices appear at the top of source files where applicable
|
|
6
|
+
* and are licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree
|
|
8
|
+
*
|
|
9
|
+
* https://github.com/payloadcms/payload/
|
|
10
|
+
* From the Payload SEO plugin
|
|
11
|
+
* https://github.com/payloadcms/payload/tree/main/packages/plugin-seo
|
|
12
|
+
*/
|
|
13
|
+
import type React from 'react'
|
|
14
|
+
|
|
15
|
+
export const Pill: React.FC<{
|
|
16
|
+
backgroundColor: string
|
|
17
|
+
color: string
|
|
18
|
+
label: string
|
|
19
|
+
}> = (props) => {
|
|
20
|
+
const { backgroundColor, color, label } = props
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
style={{
|
|
25
|
+
backgroundColor,
|
|
26
|
+
borderRadius: '2px',
|
|
27
|
+
color,
|
|
28
|
+
flexShrink: 0,
|
|
29
|
+
lineHeight: 1,
|
|
30
|
+
marginRight: '10px',
|
|
31
|
+
padding: '4px 6px',
|
|
32
|
+
whiteSpace: 'nowrap',
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
<small>{label}</small>
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FieldHelpTextSlotProps, SlotComponent } from '@byline/core'
|
|
10
|
+
import { useFieldValue } from '@byline/ui/react/forms'
|
|
11
|
+
|
|
12
|
+
import { LengthIndicator } from './length-indicator'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Custom HelpText slot component for summary-style textArea fields.
|
|
16
|
+
*
|
|
17
|
+
* Renders the field's `helpText` description alongside a live character-count
|
|
18
|
+
* indicator that updates reactively as the user types. Wire it up via the
|
|
19
|
+
* `components.HelpText` slot in the collection's `CollectionAdminConfig.fields`
|
|
20
|
+
* or directly on the field definition's `components` property.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // In CollectionAdminConfig
|
|
25
|
+
* fields: { summary: { components: { HelpText: SummaryLength } } }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const SummaryLength: SlotComponent<FieldHelpTextSlotProps> = ({ path, helpText }) => {
|
|
29
|
+
const value = useFieldValue<string>(path)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className="mt-2 flex flex-col gap-1">
|
|
33
|
+
<LengthIndicator minLength={100} maxLength={300} text={value} />
|
|
34
|
+
{helpText && (
|
|
35
|
+
<p className="text-sm text-gray-500 dark:text-gray-400 leading-tight mb-1">{helpText}</p>
|
|
36
|
+
)}
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { GroupField } from '@byline/core'
|
|
10
|
+
|
|
11
|
+
import { contentLocales, type LocaleDefinition } from '../i18n.js'
|
|
12
|
+
|
|
13
|
+
type Options = Partial<Omit<GroupField, 'type' | 'fields'>> & {
|
|
14
|
+
locales?: readonly LocaleDefinition[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type LocaleFields<T extends readonly LocaleDefinition[]> = {
|
|
18
|
+
[K in keyof T]: {
|
|
19
|
+
name: T[K]['code']
|
|
20
|
+
label: T[K]['label']
|
|
21
|
+
type: 'checkbox'
|
|
22
|
+
optional: true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type WithOverride<O, K extends string, V, D> = O extends { [P in K]: V } ? O[K] : D
|
|
27
|
+
|
|
28
|
+
type AvailableLanguagesField<Opts extends Options> = Omit<GroupField, 'name' | 'fields'> & {
|
|
29
|
+
name: WithOverride<Opts, 'name', string, 'availableLanguages'>
|
|
30
|
+
fields: LocaleFields<
|
|
31
|
+
WithOverride<Opts, 'locales', readonly LocaleDefinition[], typeof contentLocales>
|
|
32
|
+
>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const builtInValidate = (value: Record<string, boolean> | undefined): string | undefined => {
|
|
36
|
+
const hasSelection =
|
|
37
|
+
value != null &&
|
|
38
|
+
typeof value === 'object' &&
|
|
39
|
+
!Array.isArray(value) &&
|
|
40
|
+
Object.values(value).some(Boolean)
|
|
41
|
+
if (!hasSelection) {
|
|
42
|
+
return 'At least one language must be selected.'
|
|
43
|
+
}
|
|
44
|
+
return undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns a `GroupField` that renders one checkbox per locale entry.
|
|
49
|
+
* Validation requires at least one language to be selected; if the caller
|
|
50
|
+
* supplies its own `validate`, the built-in rule runs first and the caller's
|
|
51
|
+
* validator only runs when the built-in passes.
|
|
52
|
+
*
|
|
53
|
+
* @description This field is intended for use in a document's "Edit" view
|
|
54
|
+
* to allow editors to specify which languages a document is available in.
|
|
55
|
+
* It is orthogonal to the defined workflow system and is here as a 'signal'
|
|
56
|
+
* to frontend websites / consumers - allowing them to implement their own
|
|
57
|
+
* logic around content availability per language.
|
|
58
|
+
*
|
|
59
|
+
* @param options - Optional overrides. Accepts any `GroupField` property
|
|
60
|
+
* except `type` and `fields` (which are computed), plus a `locales` array
|
|
61
|
+
* that drives the generated checkbox set.
|
|
62
|
+
*/
|
|
63
|
+
export function availableLanguagesField<const Opts extends Options>(
|
|
64
|
+
options: Opts = {} as Opts
|
|
65
|
+
): AvailableLanguagesField<Opts> {
|
|
66
|
+
const { name, label, helpText, locales, validate: userValidate, ...rest } = options
|
|
67
|
+
|
|
68
|
+
const validate = userValidate
|
|
69
|
+
? (value: any, data: Record<string, any>) => {
|
|
70
|
+
const builtInError = builtInValidate(value)
|
|
71
|
+
if (builtInError) return builtInError
|
|
72
|
+
return userValidate(value, data)
|
|
73
|
+
}
|
|
74
|
+
: builtInValidate
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
...rest,
|
|
78
|
+
name: (name ?? 'availableLanguages') as any,
|
|
79
|
+
label: label ?? 'Published Languages',
|
|
80
|
+
helpText: helpText ?? 'Select the languages this document is available in.',
|
|
81
|
+
type: 'group',
|
|
82
|
+
fields: (locales ?? contentLocales).map(({ code, label }) => ({
|
|
83
|
+
name: code,
|
|
84
|
+
label,
|
|
85
|
+
type: 'checkbox' as const,
|
|
86
|
+
optional: true,
|
|
87
|
+
})) as any,
|
|
88
|
+
validate,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { RichTextField } from '@byline/core'
|
|
10
|
+
import { defaultEditorConfig, type EditorConfig } from '@byline/richtext-lexical'
|
|
11
|
+
import { cloneDeep } from 'lodash-es'
|
|
12
|
+
|
|
13
|
+
type Options = Partial<Omit<RichTextField, 'type' | 'editorConfig'>> & {
|
|
14
|
+
/**
|
|
15
|
+
* Optional callback to further customise the compact defaults. Receives a
|
|
16
|
+
* mutable copy of the compact config; mutate and return, or return a new
|
|
17
|
+
* object. Runs after the compact preset is applied, so callers can re-enable
|
|
18
|
+
* specific options for a particular field without re-listing the full set.
|
|
19
|
+
*/
|
|
20
|
+
configure?: (config: EditorConfig) => EditorConfig
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Compact preset — disables block-level features (tables, layouts,
|
|
25
|
+
* admonitions, code highlight, lists, embeds, inline images, alignment) and
|
|
26
|
+
* keeps a slim toolbar suitable for inline body copy like image captions,
|
|
27
|
+
* byline strap-lines, or compact form fields.
|
|
28
|
+
*/
|
|
29
|
+
function applyCompactPreset(config: EditorConfig): EditorConfig {
|
|
30
|
+
const o = config.settings.options
|
|
31
|
+
o.textAlignment = false
|
|
32
|
+
o.tablePlugin = false
|
|
33
|
+
o.tableActionMenuPlugin = false
|
|
34
|
+
o.tableCellBackgroundColor = false
|
|
35
|
+
o.tableCellMerge = false
|
|
36
|
+
o.layoutPlugin = false
|
|
37
|
+
o.admonitionPlugin = false
|
|
38
|
+
o.codeHighlightPlugin = false
|
|
39
|
+
o.horizontalRulePlugin = false
|
|
40
|
+
o.listPlugin = false
|
|
41
|
+
o.checkListPlugin = false
|
|
42
|
+
o.inlineImagePlugin = false
|
|
43
|
+
o.autoEmbedPlugin = false
|
|
44
|
+
o.floatingTextFormatToolbarPlugin = false
|
|
45
|
+
o.textStyle = false
|
|
46
|
+
o.inlineCode = false
|
|
47
|
+
o.undoRedo = false
|
|
48
|
+
return config
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Returns a `RichTextField` with a reduced Lexical feature set baked into
|
|
53
|
+
* `editorConfig`. Use this for caption-style or otherwise constrained rich-text
|
|
54
|
+
* fields where the full editor surface would be inappropriate.
|
|
55
|
+
*
|
|
56
|
+
* The compact preset disables tables, layouts, lists, code highlight, inline
|
|
57
|
+
* images, embeds, and most secondary toolbar features while keeping bold /
|
|
58
|
+
* italic / link editing and the floating link editor.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* fields: [
|
|
63
|
+
* lexicalRichTextCompact({ name: 'caption', label: 'Caption' }),
|
|
64
|
+
* // Compact + re-enable lists for a specific field:
|
|
65
|
+
* lexicalRichTextCompact({
|
|
66
|
+
* name: 'summary',
|
|
67
|
+
* label: 'Summary',
|
|
68
|
+
* configure: (c) => {
|
|
69
|
+
* c.settings.options.listPlugin = true
|
|
70
|
+
* return c
|
|
71
|
+
* },
|
|
72
|
+
* }),
|
|
73
|
+
* ]
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function lexicalRichTextCompact(options: Options = {}): RichTextField {
|
|
77
|
+
const { configure, ...rest } = options
|
|
78
|
+
const base = applyCompactPreset(cloneDeep(defaultEditorConfig))
|
|
79
|
+
const editorConfig = configure ? configure(base) : base
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
name: 'richText',
|
|
83
|
+
label: 'RichText',
|
|
84
|
+
...rest,
|
|
85
|
+
type: 'richText',
|
|
86
|
+
editorConfig,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared i18n locale configuration — no upstream dependencies, safe to import
|
|
11
|
+
* from both config entry-points and collection schema files without circular
|
|
12
|
+
* references.
|
|
13
|
+
*
|
|
14
|
+
* `interface` locales govern the CMS admin UI language.
|
|
15
|
+
* `content` locales govern the languages a document can be published in.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export interface LocaleDefinition {
|
|
19
|
+
code: string
|
|
20
|
+
label: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Locales available in the CMS admin interface. */
|
|
24
|
+
export const interfaceLocales: LocaleDefinition[] = [
|
|
25
|
+
{ code: 'en', label: 'English' },
|
|
26
|
+
{ code: 'fr', label: 'Français' },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
/** Locales a document can be published in. */
|
|
30
|
+
export const contentLocales = [
|
|
31
|
+
{ code: 'en', label: 'English' },
|
|
32
|
+
{ code: 'fr', label: 'Français' },
|
|
33
|
+
{ code: 'es', label: 'Español' },
|
|
34
|
+
{ code: 'de', label: 'Deutsch' },
|
|
35
|
+
] as const
|
|
36
|
+
|
|
37
|
+
/** Derived config object — passed directly to defineServerConfig / defineClientConfig. */
|
|
38
|
+
export const i18n = {
|
|
39
|
+
interface: {
|
|
40
|
+
defaultLocale: 'en',
|
|
41
|
+
locales: interfaceLocales.map((l) => l.code),
|
|
42
|
+
},
|
|
43
|
+
content: {
|
|
44
|
+
defaultLocale: 'en',
|
|
45
|
+
locales: contentLocales.map((l) => l.code),
|
|
46
|
+
},
|
|
47
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* URL segments for admin and (future) public API routes. Defaults of
|
|
11
|
+
* `/admin` and `/api` are applied automatically by `resolveRoutes()` —
|
|
12
|
+
* keys only need to be set here when overriding either default.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { RoutesConfig } from '@byline/core'
|
|
16
|
+
|
|
17
|
+
export const routes: Partial<RoutesConfig> = {
|
|
18
|
+
admin: '/admin',
|
|
19
|
+
api: '/api',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fallback used by both server and admin entry points when no
|
|
24
|
+
* `VITE_SERVER_URL` env var is set. Each entry resolves the env var
|
|
25
|
+
* itself (Vite's `import.meta.env` on the client, Node's `process.env`
|
|
26
|
+
* on the server) and falls back to this literal.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_SERVER_URL = 'http://localhost:5173/'
|