@agent-native/core-corpus 0.213.1 → 0.214.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/community/qr/package.json +1 -1
  3. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +15 -1
  4. package/corpus/templates/content/CHANGELOG.md +5 -0
  5. package/corpus/templates/content/actions/_database-view-setup.ts +305 -11
  6. package/corpus/templates/content/actions/_property-utils.ts +3 -0
  7. package/corpus/templates/content/actions/update-content-database-view.ts +18 -2
  8. package/corpus/templates/content/actions/view-screen.ts +12 -0
  9. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +91 -16
  10. package/corpus/templates/content/app/components/editor/database/ListItemLayout.tsx +410 -0
  11. package/corpus/templates/content/app/components/editor/database/ListItemRow.tsx +426 -0
  12. package/corpus/templates/content/app/components/editor/database/ListView.tsx +136 -18
  13. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +3 -0
  14. package/corpus/templates/content/app/components/editor/database/settings.tsx +3 -3
  15. package/corpus/templates/content/app/components/editor/database/view-config.ts +4 -0
  16. package/corpus/templates/content/app/global.css +13 -0
  17. package/corpus/templates/content/app/i18n-data.ts +32 -0
  18. package/corpus/templates/content/changelog/2026-10-19-list-rows-can-be-customized.md +6 -0
  19. package/corpus/templates/content/changelog/2026-10-19-list-views-fit-phone-screens.md +6 -0
  20. package/corpus/templates/content/shared/api.ts +18 -0
  21. package/corpus/templates/content/shared/database-item-layout.ts +591 -0
  22. package/package.json +1 -1
@@ -32,6 +32,7 @@ import {
32
32
  type ContentDatabaseFilterMode,
33
33
  type ContentDatabaseFilterOperator,
34
34
  type ContentDatabaseFormQuestion,
35
+ type ContentDatabaseItemLayout,
35
36
  type ContentDatabaseOpenPagesIn,
36
37
  type ContentDatabaseRowDensity,
37
38
  type ContentDatabaseSort,
@@ -46,6 +47,7 @@ import {
46
47
  } from "@shared/api";
47
48
  import { contentRecentHref } from "@shared/content-personal-navigation";
48
49
  import { contentDatabaseFormQuestions } from "@shared/database-form";
50
+ import { contentDatabaseItemLayoutField } from "@shared/database-item-layout";
49
51
  import {
50
52
  applyContentDatabaseTableQuery,
51
53
  contentDatabaseFilterDateRangeValues,
@@ -332,6 +334,7 @@ import { DatabaseGalleryView } from "./GalleryView";
332
334
  import type { GitHubCollectionPlace } from "./github-availability";
333
335
  import { GitHubSourcePanel, useGitHubSourcesRow } from "./GitHubSourcePanel";
334
336
  import { GitHubSourceStatusLine } from "./GitHubSourceStatusLine";
337
+ import { DatabaseListRowsSetting } from "./ListItemLayout";
335
338
  import { DatabaseListView } from "./ListView";
336
339
  import {
337
340
  DATABASE_NAVIGATION_VISIBLE_ITEM_LIMIT,
@@ -1125,6 +1128,9 @@ function DatabaseTable({
1125
1128
  >(null);
1126
1129
  const [searchOpen, setSearchOpen] = useState(false);
1127
1130
  const [settingsOpen, setSettingsOpen] = useState(false);
1131
+ const [editingListRowsViewId, setEditingListRowsViewId] = useState<
1132
+ string | null
1133
+ >(null);
1128
1134
  const settingsTriggerRef = useRef<HTMLButtonElement | null>(null);
1129
1135
  const [preserveSourceNavigationOnClose, setPreserveSourceNavigationOnClose] =
1130
1136
  useState(false);
@@ -2549,6 +2555,10 @@ function DatabaseTable({
2549
2555
  updateActiveView((view) => ({ ...view, formQuestions }));
2550
2556
  }
2551
2557
 
2558
+ function setItemLayout(itemLayout: ContentDatabaseItemLayout | null) {
2559
+ updateActiveView((view) => ({ ...view, itemLayout }));
2560
+ }
2561
+
2552
2562
  function setGroupCollapsed(groupId: string, collapsed: boolean) {
2553
2563
  updateActiveView((view) =>
2554
2564
  setDatabaseViewCollapsedGroup(view, groupId, collapsed),
@@ -3591,8 +3601,15 @@ function DatabaseTable({
3591
3601
  <DatabaseListView
3592
3602
  properties={tableProperties}
3593
3603
  groupableProperties={orderedProperties}
3604
+ layoutProperties={databaseListLayoutProperties(
3605
+ orderedProperties,
3606
+ activeView,
3607
+ )}
3594
3608
  items={visibleItems}
3609
+ databaseId={databaseId}
3595
3610
  databaseDocumentId={document.id}
3611
+ itemLayout={activeView.itemLayout ?? null}
3612
+ editingRows={editingListRowsViewId === activeView.id}
3596
3613
  canEdit={effectiveCanEdit}
3597
3614
  canCreateItems={canCreateItems}
3598
3615
  isLoading={isDatabaseViewLoading}
@@ -3610,6 +3627,10 @@ function DatabaseTable({
3610
3627
  onPreview={previewItemPage}
3611
3628
  onDeletedPreviewItem={handleDeletedPreviewItem}
3612
3629
  onOpenPage={openItemPage}
3630
+ onItemLayoutChange={setItemLayout}
3631
+ onEditingRowsChange={(editing) =>
3632
+ setEditingListRowsViewId(editing ? activeView.id : null)
3633
+ }
3613
3634
  />
3614
3635
  ) : activeView.type === "gallery" ? (
3615
3636
  <DatabaseGalleryView
@@ -4053,6 +4074,12 @@ function DatabaseTable({
4053
4074
  onWrapCellsChange={setWrapCells}
4054
4075
  onOpenPagesInChange={setOpenPagesIn}
4055
4076
  onFormQuestionsChange={setFormQuestions}
4077
+ editingListRows={editingListRowsViewId === activeView.id}
4078
+ onItemLayoutChange={setItemLayout}
4079
+ onEditListRows={() => {
4080
+ setEditingListRowsViewId(activeView.id);
4081
+ closeDatabaseSettings();
4082
+ }}
4056
4083
  onPropertyHiddenChange={setPropertyHiddenInActiveView}
4057
4084
  onPropertiesHiddenChange={setPropertiesHiddenInActiveView}
4058
4085
  onGroupByChange={(propertyId) =>
@@ -4180,6 +4207,7 @@ export function databaseNavigationState({
4180
4207
  | "tableColumnOrderIds"
4181
4208
  | "rowDensity"
4182
4209
  | "openPagesIn"
4210
+ | "itemLayout"
4183
4211
  >;
4184
4212
  effectiveFrozenColumnIds?: string[];
4185
4213
  searchQuery?: string;
@@ -4294,6 +4322,8 @@ export function databaseNavigationState({
4294
4322
  activeView.openPagesIn === "full_page"
4295
4323
  ? activeView.openPagesIn
4296
4324
  : undefined,
4325
+ databaseItemLayout:
4326
+ activeView.type === "list" ? (activeView.itemLayout ?? null) : undefined,
4297
4327
  databaseVisibleItemCount: visibleItemCount,
4298
4328
  databaseTotalItemCount: totalItemCount,
4299
4329
  databaseVisibleItems: databaseVisibleItemSummaries(
@@ -6821,8 +6851,8 @@ function DatabaseInlineSortControl({
6821
6851
  size="sm"
6822
6852
  variant="ghost"
6823
6853
  className={cn(
6824
- "relative h-7 max-w-[16rem] rounded border border-[#2383e2]/30 bg-[#2383e2]/10 px-2 text-xs font-normal text-[#0f5ea8] shadow-none hover:bg-[#2383e2]/15 focus-visible:border-[#2383e2]/40 focus-visible:ring-[#2383e2]/25 dark:border-[#529cca]/35 dark:bg-[#529cca]/15 dark:text-[#8ec7ff] dark:hover:bg-[#529cca]/20",
6825
- open && "border-[#2383e2]/40 bg-[#2383e2]/15",
6854
+ "relative h-7 max-w-[16rem] rounded border border-database-chip/30 bg-database-chip/10 px-2 text-xs font-normal text-database-chip-foreground shadow-none hover:bg-database-chip/15 focus-visible:border-database-blue/40 focus-visible:ring-database-blue/25 dark:border-database-chip/35 dark:bg-database-chip/15 dark:hover:bg-database-chip/20",
6855
+ open && "border-database-blue/40 bg-database-blue/15",
6826
6856
  )}
6827
6857
  >
6828
6858
  {sort.direction === "asc" ? (
@@ -7139,8 +7169,8 @@ function DatabaseAdvancedFilterGroupControl({
7139
7169
  size="sm"
7140
7170
  variant="ghost"
7141
7171
  className={cn(
7142
- "relative h-7 rounded border border-[#2383e2]/30 bg-[#2383e2]/10 px-2 text-xs font-normal text-[#0f5ea8] shadow-none hover:bg-[#2383e2]/15 focus-visible:border-[#2383e2]/40 focus-visible:ring-[#2383e2]/25 dark:border-[#529cca]/35 dark:bg-[#529cca]/15 dark:text-[#8ec7ff] dark:hover:bg-[#529cca]/20",
7143
- open && "border-[#2383e2]/40 bg-[#2383e2]/15",
7172
+ "relative h-7 rounded border border-database-chip/30 bg-database-chip/10 px-2 text-xs font-normal text-database-chip-foreground shadow-none hover:bg-database-chip/15 focus-visible:border-database-blue/40 focus-visible:ring-database-blue/25 dark:border-database-chip/35 dark:bg-database-chip/15 dark:hover:bg-database-chip/20",
7173
+ open && "border-database-blue/40 bg-database-blue/15",
7144
7174
  )}
7145
7175
  >
7146
7176
  <IconFilter className="size-3.5 shrink-0" />
@@ -7640,10 +7670,10 @@ function DatabaseInlineFilterControl({
7640
7670
  size="sm"
7641
7671
  variant="ghost"
7642
7672
  className={cn(
7643
- "relative h-7 max-w-[16rem] rounded border border-border/70 bg-background px-2 text-xs font-normal text-foreground shadow-none hover:bg-muted focus-visible:border-[#2383e2]/40 focus-visible:ring-[#2383e2]/25",
7673
+ "relative h-7 max-w-[16rem] rounded border border-border/70 bg-background px-2 text-xs font-normal text-foreground shadow-none hover:bg-muted focus-visible:border-database-blue/40 focus-visible:ring-database-blue/25",
7644
7674
  filterIsComplete &&
7645
- "border-[#2383e2]/30 bg-[#2383e2]/10 text-[#0f5ea8] hover:bg-[#2383e2]/15 dark:border-[#529cca]/35 dark:bg-[#529cca]/15 dark:text-[#8ec7ff] dark:hover:bg-[#529cca]/20",
7646
- open && "border-[#2383e2]/40 bg-[#2383e2]/15",
7675
+ "border-database-chip/30 bg-database-chip/10 text-database-chip-foreground hover:bg-database-chip/15 dark:border-database-chip/35 dark:bg-database-chip/15 dark:hover:bg-database-chip/20",
7676
+ open && "border-database-blue/40 bg-database-blue/15",
7647
7677
  !filterIsComplete && "text-muted-foreground",
7648
7678
  )}
7649
7679
  >
@@ -7922,6 +7952,9 @@ function DatabaseSettingsPanelSheet({
7922
7952
  onWrapCellsChange,
7923
7953
  onOpenPagesInChange,
7924
7954
  onFormQuestionsChange,
7955
+ editingListRows,
7956
+ onItemLayoutChange,
7957
+ onEditListRows,
7925
7958
  onPropertyHiddenChange,
7926
7959
  onPropertiesHiddenChange,
7927
7960
  onGroupByChange,
@@ -7972,6 +8005,9 @@ function DatabaseSettingsPanelSheet({
7972
8005
  onWrapCellsChange: (wrapCells: boolean) => void;
7973
8006
  onOpenPagesInChange: (openPagesIn: ContentDatabaseOpenPagesIn) => void;
7974
8007
  onFormQuestionsChange: (formQuestions: ContentDatabaseFormQuestion[]) => void;
8008
+ editingListRows: boolean;
8009
+ onItemLayoutChange: (itemLayout: ContentDatabaseItemLayout | null) => void;
8010
+ onEditListRows: () => void;
7975
8011
  onPropertyHiddenChange: (propertyId: string, hidden: boolean) => void;
7976
8012
  onPropertiesHiddenChange: (propertyIds: string[], hidden: boolean) => void;
7977
8013
  onGroupByChange: (propertyId: string | null) => void;
@@ -8134,10 +8170,14 @@ function DatabaseSettingsPanelSheet({
8134
8170
  <DatabaseSettingsLayoutPanel
8135
8171
  activeView={activeView}
8136
8172
  properties={properties}
8173
+ items={items}
8174
+ editingListRows={editingListRows}
8137
8175
  onViewTypeChange={onViewTypeChange}
8138
8176
  onWrapCellsChange={onWrapCellsChange}
8139
8177
  onOpenPagesInChange={onOpenPagesInChange}
8140
8178
  onFormQuestionsChange={onFormQuestionsChange}
8179
+ onItemLayoutChange={onItemLayoutChange}
8180
+ onEditListRows={onEditListRows}
8141
8181
  />
8142
8182
  ) : panel === "property_visibility" ? (
8143
8183
  <DatabaseSettingsPropertyVisibilityPanel
@@ -9081,7 +9121,7 @@ function DatabaseSettingsSourcePanel({
9081
9121
  className={cn(
9082
9122
  "min-w-0 rounded px-2 py-1.5 text-[11px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default disabled:opacity-60",
9083
9123
  selected
9084
- ? "bg-[#2383e2] text-white shadow-sm"
9124
+ ? "bg-database-blue text-database-blue-foreground shadow-sm"
9085
9125
  : "text-muted-foreground hover:bg-background hover:text-foreground",
9086
9126
  )}
9087
9127
  onClick={() =>
@@ -9122,7 +9162,7 @@ function DatabaseSettingsSourcePanel({
9122
9162
  className={cn(
9123
9163
  "mt-0.5 inline-flex size-4 shrink-0 items-center justify-center rounded border",
9124
9164
  liveWriteControl.allowPublicationTransitions
9125
- ? "border-[#2383e2] bg-[#2383e2] text-white"
9165
+ ? "border-database-blue bg-database-blue text-database-blue-foreground"
9126
9166
  : "border-muted-foreground/40 bg-background text-transparent",
9127
9167
  )}
9128
9168
  >
@@ -10536,7 +10576,7 @@ function SourceDetailsFieldPicker({
10536
10576
  className={cn(
10537
10577
  "flex size-4 shrink-0 items-center justify-center rounded border",
10538
10578
  selected.has(field.id)
10539
- ? "border-[#2383e2] bg-[#2383e2] text-white"
10579
+ ? "border-database-blue bg-database-blue text-database-blue-foreground"
10540
10580
  : "border-muted-foreground/40 text-transparent",
10541
10581
  )}
10542
10582
  >
@@ -11229,7 +11269,7 @@ function DatabaseSettingsSwitch({
11229
11269
  <span
11230
11270
  className={cn(
11231
11271
  "relative h-5 w-9 rounded-full transition-colors",
11232
- checked ? "bg-[#2383e2]" : "bg-muted-foreground/25",
11272
+ checked ? "bg-database-blue" : "bg-muted-foreground/25",
11233
11273
  )}
11234
11274
  >
11235
11275
  <span
@@ -11246,17 +11286,25 @@ function DatabaseSettingsSwitch({
11246
11286
  function DatabaseSettingsLayoutPanel({
11247
11287
  activeView,
11248
11288
  properties,
11289
+ items,
11290
+ editingListRows,
11249
11291
  onViewTypeChange,
11250
11292
  onWrapCellsChange,
11251
11293
  onOpenPagesInChange,
11252
11294
  onFormQuestionsChange,
11295
+ onItemLayoutChange,
11296
+ onEditListRows,
11253
11297
  }: {
11254
11298
  activeView: ContentDatabaseView;
11255
11299
  properties: DocumentProperty[];
11300
+ items: ContentDatabaseItem[];
11301
+ editingListRows: boolean;
11256
11302
  onViewTypeChange: (type: ContentDatabaseViewType) => void;
11257
11303
  onWrapCellsChange: (wrapCells: boolean) => void;
11258
11304
  onOpenPagesInChange: (openPagesIn: ContentDatabaseOpenPagesIn) => void;
11259
11305
  onFormQuestionsChange: (formQuestions: ContentDatabaseFormQuestion[]) => void;
11306
+ onItemLayoutChange: (itemLayout: ContentDatabaseItemLayout | null) => void;
11307
+ onEditListRows: () => void;
11260
11308
  }) {
11261
11309
  const wrapCells = activeView.wrapCells === true;
11262
11310
  const openPagesIn = activeView.openPagesIn ?? "preview";
@@ -11272,7 +11320,7 @@ function DatabaseSettingsLayoutPanel({
11272
11320
  className={cn(
11273
11321
  "flex h-16 flex-col items-center justify-center gap-1 rounded-md border text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
11274
11322
  activeView.type === type
11275
- ? "border-[#2383e2] bg-[#2383e2]/5 text-[#2383e2]"
11323
+ ? "border-database-blue bg-database-blue/5 text-database-blue"
11276
11324
  : "border-border text-muted-foreground hover:bg-muted hover:text-foreground",
11277
11325
  )}
11278
11326
  onClick={() => onViewTypeChange(type)}
@@ -11301,6 +11349,18 @@ function DatabaseSettingsLayoutPanel({
11301
11349
  onChange={onFormQuestionsChange}
11302
11350
  />
11303
11351
  ) : null}
11352
+ {activeView.type === "list" ? (
11353
+ <DatabaseListRowsSetting
11354
+ itemLayout={activeView.itemLayout ?? null}
11355
+ properties={databaseListLayoutProperties(properties, activeView)}
11356
+ visibleProperties={properties.filter((property) =>
11357
+ isDatabasePropertyVisibleInView(property, items, activeView),
11358
+ )}
11359
+ editingOnList={editingListRows}
11360
+ onChange={onItemLayoutChange}
11361
+ onEditOnList={onEditListRows}
11362
+ />
11363
+ ) : null}
11304
11364
  </div>
11305
11365
  );
11306
11366
  }
@@ -13868,6 +13928,7 @@ export function createDatabaseView(
13868
13928
  rowDensity: normalizeClientDatabaseRowDensity(values.rowDensity),
13869
13929
  openPagesIn: normalizeClientDatabaseOpenPagesIn(values.openPagesIn),
13870
13930
  formQuestions: normalizeClientDatabaseFormQuestions(values.formQuestions),
13931
+ ...contentDatabaseItemLayoutField(values.itemLayout),
13871
13932
  };
13872
13933
  }
13873
13934
 
@@ -14137,6 +14198,7 @@ export function duplicateDatabaseView(
14137
14198
  rowDensity: view.rowDensity,
14138
14199
  openPagesIn: view.openPagesIn,
14139
14200
  formQuestions: view.formQuestions,
14201
+ itemLayout: view.itemLayout,
14140
14202
  },
14141
14203
  view.type,
14142
14204
  );
@@ -14279,6 +14341,7 @@ function normalizeClientDatabaseView(
14279
14341
  rowDensity: normalizeClientDatabaseRowDensity(value.rowDensity),
14280
14342
  openPagesIn: normalizeClientDatabaseOpenPagesIn(value.openPagesIn),
14281
14343
  formQuestions: normalizeClientDatabaseFormQuestions(value.formQuestions),
14344
+ itemLayout: value.itemLayout,
14282
14345
  },
14283
14346
  type,
14284
14347
  );
@@ -14636,6 +14699,18 @@ export function isDatabasePropertyVisibleInView(
14636
14699
  );
14637
14700
  }
14638
14701
 
14702
+ /**
14703
+ * The properties a list's custom rows can show: all but those hidden in this
14704
+ * view. Always-hidden properties are left out by the row layout itself.
14705
+ */
14706
+ function databaseListLayoutProperties(
14707
+ properties: DocumentProperty[],
14708
+ view: Pick<ContentDatabaseView, "hiddenPropertyIds">,
14709
+ ) {
14710
+ const hidden = new Set(view.hiddenPropertyIds ?? []);
14711
+ return properties.filter((property) => !hidden.has(property.definition.id));
14712
+ }
14713
+
14639
14714
  export function setDatabaseViewHiddenPropertyIds(
14640
14715
  view: ContentDatabaseView,
14641
14716
  propertyIds: string[],
@@ -17992,7 +18067,7 @@ function DatabaseFilterValueControl({
17992
18067
  return (
17993
18068
  <div className="overflow-hidden rounded-sm">
17994
18069
  <div className="px-1 pb-1">
17995
- <div className="flex min-h-9 flex-wrap items-center gap-1 rounded border border-input bg-background px-2 py-1 focus-within:border-[#2383e2] focus-within:ring-2 focus-within:ring-[#2383e2]/25">
18070
+ <div className="flex min-h-9 flex-wrap items-center gap-1 rounded border border-input bg-background px-2 py-1 focus-within:border-database-blue focus-within:ring-2 focus-within:ring-database-blue/25">
17996
18071
  {showCompactOptionValueInput ? null : (
17997
18072
  <IconSearch className="size-3.5 shrink-0 text-muted-foreground" />
17998
18073
  )}
@@ -18114,7 +18189,7 @@ function DatabaseFilterValueControl({
18114
18189
  value={filter.value}
18115
18190
  placeholder={filterValuePlaceholder(filter.key, properties)}
18116
18191
  onChange={(event) => onValueChange(event.target.value)}
18117
- className="h-9 text-sm focus-visible:border-[#2383e2] focus-visible:ring-[#2383e2]/25"
18192
+ className="h-9 text-sm focus-visible:border-database-blue focus-visible:ring-database-blue/25"
18118
18193
  />
18119
18194
  );
18120
18195
  }
@@ -18255,7 +18330,7 @@ function DatabaseBetweenDateFilterValueControl({
18255
18330
  value={start}
18256
18331
  aria-label={`Start ${filter.label} filter date`}
18257
18332
  onChange={(event) => updateRange(event.target.value, end)}
18258
- className="h-9 text-sm focus-visible:border-[#2383e2] focus-visible:ring-[#2383e2]/25"
18333
+ className="h-9 text-sm focus-visible:border-database-blue focus-visible:ring-database-blue/25"
18259
18334
  />
18260
18335
  <span className="text-xs text-muted-foreground">to</span>
18261
18336
  <Input
@@ -18263,7 +18338,7 @@ function DatabaseBetweenDateFilterValueControl({
18263
18338
  value={end}
18264
18339
  aria-label={`End ${filter.label} filter date`}
18265
18340
  onChange={(event) => updateRange(start, event.target.value)}
18266
- className="h-9 text-sm focus-visible:border-[#2383e2] focus-visible:ring-[#2383e2]/25"
18341
+ className="h-9 text-sm focus-visible:border-database-blue focus-visible:ring-database-blue/25"
18267
18342
  />
18268
18343
  </div>
18269
18344
  );