CMS / foldkit-cms

Kinds, and how they are drawn

Two controls and two displays, made with Input.kind and Display.kind exactly as you make your own. There is no CMS view package: a kind and its renderer are all a view needs.

ts
const PostForm = Form.make('PostForm', Entity.input(Post, PostInput), {
  inputs: {
    slug: Cms.slug('title', { prefix: '/blog/' }), // follows the title until the author writes it
    goesLiveAt: Cms.dateTime(), // a datetime-local input, submitted as an ISO string
  },
})

FormView.define(PostForm, { renderers: Cms.controlRenderers() })
EntryTable({ page, renderers: Cms.displayRenderers() }, h)
KindWhat it is
Cms.Input.SlugText shown after the address it completes. Cms.slug(from, { prefix?, through? }) makes one that follows from through Cms.slugify. A form filled with a published slug does not follow: an address must not move because its title did. Drawn as the prefix in FieldSlots.affix and the input in text, together in group.
Cms.Input.DateTimeA moment. Text that is none is Invalid, not submitted.
Cms.Display.StateAn entry's state as words: Changed, scheduled, New, overdue. of({ words }) takes yours, text with blanks as every words object is: each state, scheduled, overdue, and withSchedule ('{state}, {schedule}'). Its renderer is a span with data-cms-state and data-cms-schedule to style.
Cms.Display.MomentA time. of({ now }) reads relative to that clock (3 days ago), and you decide how often it moves; without one it is the date and time. Its renderer is a time.

Cms.Entities already say how they are shown: an entry's state is a State, and its times are Moments, so a Crud.list over Cms.Entries needs only the renderers.

Entry-level views live beside the kinds: Cms.stateBadge for the state (written in Cms.stateAttribute, data-cms-state, as a list's state cell is, so one tone rule styles both), Cms.revisionsOf for the open entry's published revisions, Cms.historyCard for the timeline, Cms.moreCard for the rest of what can happen to it. They draw on your own slot builders, so you keep your slots and styles; who published and the archive button's icon are yours to name:

ts
Cms.historyCard(slots, h, Cms.revisionsOf(model, history), {
  state,
  restore: revision => Message.RestoreAsked({ revision }),
  authorName: name => directoryName(name),
})