@byline/cli 1.6.0 → 1.6.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.
@@ -119,11 +119,25 @@ export const DocsAdmin: CollectionAdminConfig = defineAdmin(Docs, {
119
119
  },
120
120
 
121
121
  /**
122
- * Preview URL builder for live preview links. Receives the document and an
123
- * optional locale and should return a fully-qualified URL string.
122
+ * Preview URL builder for live preview links. Returns a URL string (relative
123
+ * or absolute), or `null` to hide the preview affordance.
124
+ *
125
+ * `doc.path` is the top-level slug (derived from `useAsPath`), not a field.
126
+ * Direct relations are auto-populated by the edit view (depth 1, picker
127
+ * projection) and appear under `doc.fields.<name>?.document`.
124
128
  *
125
129
  * @example
126
- * preview: (doc, { locale }) => `https://example.com/${locale}/docs/${doc.fields.path}`
130
+ * preview: {
131
+ * url: (doc, { locale }) => {
132
+ * if (!doc.path) return null
133
+ * // `category` is a direct relation — auto-populated to depth 1.
134
+ * const category = doc.fields.category?.document?.path
135
+ * const prefix = locale && locale !== 'en' ? `/${locale}` : ''
136
+ * return category
137
+ * ? `${prefix}/docs/${category}/${doc.path}`
138
+ * : `${prefix}/docs/${doc.path}`
139
+ * },
140
+ * }
127
141
  */
128
142
  // preview: undefined,
129
143
 
@@ -147,7 +161,7 @@ export const DocsAdmin: CollectionAdminConfig = defineAdmin(Docs, {
147
161
  */
148
162
  tabSets: [
149
163
  {
150
- name: 'main',
164
+ name: 'tabs',
151
165
  tabs: [
152
166
  {
153
167
  name: 'details',
@@ -198,7 +212,7 @@ export const DocsAdmin: CollectionAdminConfig = defineAdmin(Docs, {
198
212
  * schema field in `main` in declaration order.
199
213
  */
200
214
  layout: {
201
- main: ['main'],
215
+ main: ['tabs'],
202
216
  sidebar: ['publishedOn', 'availableLanguages'],
203
217
  },
204
218
  })
@@ -12,6 +12,7 @@ import { defineCollection, defineWorkflow } from '@byline/core'
12
12
  import { PhotoBlock } from '../../blocks/photo-block.js'
13
13
  import { RichTextBlock } from '../../blocks/richtext-block.js'
14
14
  import { availableLanguagesField } from '../../fields/available-languages-field.js'
15
+ import { publishedOnField } from '../../fields/published-on-field.js'
15
16
 
16
17
  // ---- Schema (server-safe, no UI concerns) ----
17
18
 
@@ -146,12 +147,7 @@ export const Docs = defineCollection({
146
147
  displayField: 'title',
147
148
  optional: true,
148
149
  },
149
- {
150
- name: 'publishedOn',
151
- label: 'Published On',
152
- type: 'datetime',
153
- mode: 'datetime',
154
- },
150
+ publishedOnField,
155
151
  {
156
152
  name: 'category',
157
153
  label: 'Category',
@@ -127,11 +127,17 @@ export const MediaAdmin: CollectionAdminConfig = defineAdmin(Media, {
127
127
  // fields: {},
128
128
 
129
129
  /**
130
- * Preview URL builder for live preview links. Receives the document and an
131
- * optional locale and should return a fully-qualified URL string.
130
+ * Preview URL builder for live preview links. Returns a URL string (relative
131
+ * or absolute), or `null` to hide the preview affordance.
132
+ *
133
+ * `doc.path` is the top-level slug (derived from `useAsPath`), not a field.
134
+ * Direct relations are auto-populated by the edit view (depth 1, picker
135
+ * projection) and appear under `doc.fields.<name>?.document`.
132
136
  *
133
137
  * @example
134
- * preview: (doc, { locale }) => `https://example.com/media/${doc.fields.path}`
138
+ * preview: {
139
+ * url: (doc) => (doc.path ? `/media/${doc.path}` : null),
140
+ * }
135
141
  */
136
142
  // preview: undefined,
137
143
 
@@ -24,8 +24,16 @@ import { Link, useNavigate, useRouterState } from '@tanstack/react-router'
24
24
  import type { ListViewComponentProps, StoredFileValue, WorkflowStatus } from '@byline/core'
25
25
  import type { AnyCollectionSchemaTypes } from '@byline/core/zod-schemas'
26
26
  import { RouterPager } from '@byline/host-tanstack-start/admin-shell/chrome/router-pager'
27
- import { Container, IconButton, LoaderRing, PlusIcon, Search, Section, Select } from '@byline/ui/react'
28
- import { LocalDateTime } from '@byline/ui/react'
27
+ import {
28
+ Container,
29
+ IconButton,
30
+ LoaderRing,
31
+ LocalDateTime,
32
+ PlusIcon,
33
+ Search,
34
+ Section,
35
+ Select,
36
+ } from '@byline/ui/react'
29
37
 
30
38
  import { FormatBadge } from './media-thumbnail'
31
39
 
@@ -111,11 +111,25 @@ export const NewsAdmin: CollectionAdminConfig = defineAdmin(News, {
111
111
  },
112
112
 
113
113
  /**
114
- * Preview URL builder for live preview links. Receives the document and an
115
- * optional locale and should return a fully-qualified URL string.
114
+ * Preview URL builder for live preview links. Returns a URL string (relative
115
+ * or absolute), or `null` to hide the preview affordance.
116
+ *
117
+ * `doc.path` is the top-level slug (derived from `useAsPath`), not a field.
118
+ * Direct relations are auto-populated by the edit view (depth 1, picker
119
+ * projection) and appear under `doc.fields.<name>?.document`.
116
120
  *
117
121
  * @example
118
- * preview: (doc, { locale }) => `https://example.com/${locale}/news/${doc.fields.path}`
122
+ * preview: {
123
+ * url: (doc, { locale }) => {
124
+ * if (!doc.path) return null
125
+ * // `category` is a direct relation — auto-populated to depth 1.
126
+ * const category = doc.fields.category?.document?.path
127
+ * const prefix = locale && locale !== 'en' ? `/${locale}` : ''
128
+ * return category
129
+ * ? `${prefix}/news/${category}/${doc.path}`
130
+ * : `${prefix}/news/${doc.path}`
131
+ * },
132
+ * }
119
133
  */
120
134
  // preview: undefined,
121
135
 
@@ -10,6 +10,7 @@ import type { CollectionFieldData } from '@byline/core'
10
10
  import { defineCollection, defineWorkflow } from '@byline/core'
11
11
 
12
12
  import { availableLanguagesField } from '~/fields/available-languages-field.js'
13
+ import { publishedOnField } from '~/fields/published-on-field.js'
13
14
 
14
15
  // ---- Schema (server-safe, no UI concerns) ----
15
16
 
@@ -73,12 +74,7 @@ export const News = defineCollection({
73
74
  localized: true,
74
75
  embedRelationsOnSave: true, // See type definition for details.
75
76
  },
76
- {
77
- name: 'publishedOn',
78
- label: 'Published On',
79
- type: 'datetime',
80
- mode: 'datetime',
81
- },
77
+ publishedOnField,
82
78
  availableLanguagesField(),
83
79
  ],
84
80
  })
@@ -10,6 +10,7 @@ import { type CollectionAdminConfig, type ColumnDefinition, defineAdmin } from '
10
10
  import { DateTimeFormatter } from '@byline/ui/react'
11
11
 
12
12
  import { SummaryLength } from '~/components/summary-length.js'
13
+ import { i18n } from '~/i18n'
13
14
 
14
15
  import { Pages } from './schema.js'
15
16
 
@@ -37,11 +38,10 @@ const listViewColumns: ColumnDefinition[] = [
37
38
  className: 'w-[30%]',
38
39
  },
39
40
  {
40
- fieldName: 'featured',
41
- label: 'Featured',
41
+ fieldName: 'area',
42
+ label: 'Area',
42
43
  align: 'center',
43
44
  className: 'w-[10%]',
44
- formatter: (value) => (value ? '★' : ''),
45
45
  },
46
46
  {
47
47
  fieldName: 'status',
@@ -119,13 +119,30 @@ export const PagesAdmin: CollectionAdminConfig = defineAdmin(Pages, {
119
119
  },
120
120
 
121
121
  /**
122
- * Preview URL builder for live preview links. Receives the document and an
123
- * optional locale and should return a fully-qualified URL string.
122
+ * Preview URL builder for live preview links. Returns a URL string (relative
123
+ * or absolute), or `null` to hide the preview affordance.
124
+ *
125
+ * `doc.path` is the top-level slug (derived from `useAsPath`), not a field.
126
+ * Direct relations are auto-populated by the edit view (depth 1, picker
127
+ * projection) and appear under `doc.fields.<name>?.document`.
124
128
  *
125
129
  * @example
126
- * preview: (doc, { locale }) => `https://example.com/${locale}/pages/${doc.fields.path}`
130
+ * preview: {
131
+ * url: (doc, { locale }) => {
132
+ * if (!doc.path) return null
133
+ * const prefix = locale && locale !== 'en' ? `/${locale}` : ''
134
+ * return `${prefix}/${doc.path}`
135
+ * },
136
+ * }
127
137
  */
128
- // preview: undefined,
138
+ preview: {
139
+ url: (doc, { locale }) => {
140
+ if (!doc.path) return null
141
+ const prefix = locale && locale !== i18n.interface.defaultLocale ? `/${locale}` : ''
142
+ const pathWithArea = doc.fields?.area && doc.fields.area !== 'root' ? `${doc.fields.area}/${doc.path}` : doc.path
143
+ return `${prefix}/${pathWithArea}`
144
+ },
145
+ },
129
146
 
130
147
  // ---------------------------------------------------------------------------
131
148
  // UI Layout
@@ -145,7 +162,23 @@ export const PagesAdmin: CollectionAdminConfig = defineAdmin(Pages, {
145
162
  * Each tab's `fields` array accepts schema field names, row names, and group names.
146
163
  * An optional `condition` function can show/hide a tab based on live form data.
147
164
  */
148
- // tabSets: [],
165
+ tabSets: [
166
+ {
167
+ name: 'tabs',
168
+ tabs: [
169
+ {
170
+ name: 'details',
171
+ label: 'Details',
172
+ fields: ['title', 'area', 'summary', 'featureImage'],
173
+ },
174
+ {
175
+ name: 'content',
176
+ label: 'Content',
177
+ fields: ['content'],
178
+ },
179
+ ],
180
+ },
181
+ ],
149
182
 
150
183
  /**
151
184
  * Named horizontal-row layouts. Fields listed inside a row are rendered
@@ -177,7 +210,7 @@ export const PagesAdmin: CollectionAdminConfig = defineAdmin(Pages, {
177
210
  * schema field in `main` in declaration order.
178
211
  */
179
212
  layout: {
180
- main: ['title', 'summary', 'featureImage', 'category', 'content'],
181
- sidebar: ['publishedOn', 'featured', 'availableLanguages'],
213
+ main: ['tabs'],
214
+ sidebar: ['publishedOn', 'availableLanguages'],
182
215
  },
183
216
  })
@@ -9,7 +9,10 @@
9
9
  import type { CollectionFieldData } from '@byline/core'
10
10
  import { defineCollection, defineWorkflow } from '@byline/core'
11
11
 
12
+ import { PhotoBlock } from '~/blocks/photo-block'
13
+ import { RichTextBlock } from '~/blocks/richtext-block'
12
14
  import { availableLanguagesField } from '~/fields/available-languages-field.js'
15
+ import { publishedOnField } from '~/fields/published-on-field'
13
16
 
14
17
  // ---- Schema (server-safe, no UI concerns) ----
15
18
 
@@ -58,37 +61,25 @@ export const Pages = defineCollection({
58
61
  optional: true,
59
62
  },
60
63
  {
61
- name: 'category',
62
- label: 'Category',
64
+ name: 'area',
65
+ label: 'Area',
63
66
  type: 'select',
64
- optional: true,
65
- helpText: 'Select a category for this page',
67
+ defaultValue: 'root',
68
+ helpText: 'Select an area for this page',
66
69
  options: [
67
- { label: 'Foo', value: 'foo' },
68
- { label: 'Bar', value: 'bar' },
69
- { label: 'Baz', value: 'baz' },
70
+ { label: 'Root', value: 'root' },
71
+ { label: 'About', value: 'about' },
72
+ { label: 'Legal', value: 'legal' },
70
73
  ],
71
74
  },
72
75
  {
73
76
  name: 'content',
74
77
  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',
78
+ type: 'blocks',
89
79
  optional: true,
90
- helpText: 'Feature this page.',
80
+ blocks: [RichTextBlock, PhotoBlock],
91
81
  },
82
+ publishedOnField,
92
83
  availableLanguagesField(),
93
84
  ],
94
85
  })
@@ -0,0 +1,25 @@
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 { defineField, type FieldData } from '@byline/core'
10
+
11
+ /**
12
+ * Common "published on" datetime field. Defined once via `defineField`
13
+ * so the literal `name: 'publishedOn'` and `type: 'datetime'` survive
14
+ * inference, and dropped into any collection that needs a publish
15
+ * timestamp.
16
+ */
17
+ export const publishedOnField = defineField({
18
+ name: 'publishedOn',
19
+ label: 'Published On',
20
+ type: 'datetime',
21
+ mode: 'datetime',
22
+ })
23
+
24
+ /** Data shape contributed by `publishedOnField` (resolves to `Date`). */
25
+ export type PublishedOnFieldData = FieldData<typeof publishedOnField>
@@ -146,14 +146,7 @@ async function run(): Promise<void> {
146
146
  extractMeta: extractImageMeta,
147
147
  isBypassMimeType,
148
148
  generateVariants: ({ buffer, mimeType, storedFile, storage, upload, logger }) =>
149
- generateImageVariants(
150
- buffer,
151
- mimeType,
152
- storedFile,
153
- storage,
154
- upload.sizes ?? [],
155
- logger
156
- ),
149
+ generateImageVariants(buffer, mimeType, storedFile, storage, upload.sizes ?? [], logger),
157
150
  },
158
151
  }
159
152
 
@@ -128,7 +128,8 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
128
128
  }),
129
129
  // S3-compatible alternative (AWS S3 / Cloudflare R2 / MinIO). Replace
130
130
  // the `localStorageProvider` block above with the call below and add
131
- // the corresponding `BYLINE_STORAGE_S3_*` entries to your `.env`.
131
+ // the corresponding `BYLINE_STORAGE_S3_*` entries to your `.env`
132
+ // (see `apps/webapp/.env.example`).
132
133
  //
133
134
  // On AWS with an IAM role / instance profile, omit `accessKeyId` and
134
135
  // `secretAccessKey` so the SDK resolves credentials via its default
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@byline/cli",
3
3
  "private": false,
4
4
  "license": "MPL-2.0",
5
- "version": "1.6.0",
5
+ "version": "1.6.1",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },