@contentrain/astro-kit 0.30.0 → 0.32.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 (67) hide show
  1. package/README.md +25 -2
  2. package/catalog.json +3305 -83
  3. package/components/_shared/Section.astro +18 -3
  4. package/components/_shared/measured.ts +152 -0
  5. package/components/_shared/types.ts +40 -0
  6. package/components/band/Band.astro +132 -0
  7. package/components/band/fixtures.json +8 -0
  8. package/components/band/meta.json +323 -0
  9. package/components/card-grid/CardGrid.astro +7 -3
  10. package/components/card-grid/fixtures.json +2 -1
  11. package/components/card-grid/meta.json +111 -0
  12. package/components/contact-details/ContactDetails.astro +7 -2
  13. package/components/contact-details/meta.json +113 -1
  14. package/components/contact-form/ContactForm.astro +48 -12
  15. package/components/contact-form/fixtures.json +169 -9
  16. package/components/contact-form/meta.json +283 -15
  17. package/components/cta/Cta.astro +52 -12
  18. package/components/cta/fixtures.json +5 -1
  19. package/components/cta/meta.json +11 -2
  20. package/components/faq/Faq.astro +60 -17
  21. package/components/faq/fixtures.json +75 -0
  22. package/components/faq/meta.json +8 -2
  23. package/components/feature-list/FeatureList.astro +34 -6
  24. package/components/feature-list/fixtures.json +2 -1
  25. package/components/feature-list/meta.json +125 -1
  26. package/components/gallery/Gallery.astro +47 -13
  27. package/components/gallery/fixtures.json +275 -0
  28. package/components/gallery/meta.json +266 -14
  29. package/components/hero/Hero.astro +14 -8
  30. package/components/hero/fixtures.json +2 -1
  31. package/components/hero/meta.json +111 -0
  32. package/components/logo-cloud/LogoCloud.astro +85 -21
  33. package/components/logo-cloud/fixtures.json +239 -0
  34. package/components/logo-cloud/meta.json +145 -5
  35. package/components/newsletter/Newsletter.astro +5 -1
  36. package/components/newsletter/meta.json +113 -1
  37. package/components/post-card/PostCard.astro +4 -2
  38. package/components/post-card/meta.json +2 -1
  39. package/components/post-list/PostList.astro +114 -0
  40. package/components/post-list/fixtures.json +387 -0
  41. package/components/post-list/meta.json +308 -0
  42. package/components/pricing/Pricing.astro +128 -24
  43. package/components/pricing/fixtures.json +288 -4
  44. package/components/pricing/meta.json +188 -1
  45. package/components/split/Split.astro +76 -14
  46. package/components/split/fixtures.json +8 -1
  47. package/components/split/meta.json +226 -4
  48. package/components/stats/Stats.astro +42 -10
  49. package/components/stats/fixtures.json +173 -0
  50. package/components/stats/meta.json +153 -5
  51. package/components/steps/Steps.astro +36 -8
  52. package/components/steps/fixtures.json +217 -5
  53. package/components/steps/meta.json +157 -3
  54. package/components/tabs/Tabs.astro +5 -2
  55. package/components/tabs/meta.json +2 -1
  56. package/components/team/Team.astro +52 -8
  57. package/components/team/fixtures.json +217 -4
  58. package/components/team/meta.json +168 -3
  59. package/components/team/team.ts +9 -0
  60. package/components/testimonial/Testimonial.astro +71 -21
  61. package/components/testimonial/fixtures.json +73 -0
  62. package/components/testimonial/meta.json +167 -3
  63. package/mapping/classic.json +7 -1
  64. package/mapping/divi.json +21 -4
  65. package/mapping/elementor.json +33 -8
  66. package/mapping/gutenberg.json +20 -4
  67. package/package.json +2 -2
@@ -5,25 +5,58 @@
5
5
  "category": "section",
6
6
  "uses": [],
7
7
  "shared": [
8
- "Section.astro"
8
+ "KitImage.astro",
9
+ "Section.astro",
10
+ "image.ts",
11
+ "measured.ts",
12
+ "types.ts"
9
13
  ],
10
14
  "variants": {
15
+ "layout": {
16
+ "options": [
17
+ "grid",
18
+ "inline"
19
+ ],
20
+ "default": "grid",
21
+ "description": "grid: figures in columns. inline: one line that wraps, for two to four short figures."
22
+ },
11
23
  "columns": {
12
24
  "options": [
13
25
  "2",
14
26
  "3",
15
- "4"
27
+ "4",
28
+ "5",
29
+ "6"
16
30
  ],
17
31
  "default": "3",
18
- "description": "Figures per row on wide screens; two on phones."
32
+ "description": "Figures per row on wide screens (grid layout); two on phones."
19
33
  },
20
34
  "style": {
21
35
  "options": [
22
36
  "plain",
23
- "card"
37
+ "card",
38
+ "divided"
24
39
  ],
25
40
  "default": "plain",
26
- "description": "plain: figures on the section background. card: each figure in its own box."
41
+ "description": "plain: figures on the section background. card: each figure in its own box. divided: hairlines between the figures (across on a wide screen, above each on a phone), no box; for a single row."
42
+ },
43
+ "align": {
44
+ "options": [
45
+ "start",
46
+ "center"
47
+ ],
48
+ "default": "start",
49
+ "description": "Alignment of each figure and its label."
50
+ },
51
+ "valueSize": {
52
+ "options": [
53
+ "md",
54
+ "lg",
55
+ "xl",
56
+ "display"
57
+ ],
58
+ "default": "lg",
59
+ "description": "The figure's size: md, lg, xl or a display-size number."
27
60
  },
28
61
  "tone": {
29
62
  "options": [
@@ -92,11 +125,126 @@
92
125
  "type": "string",
93
126
  "label": "Suffix",
94
127
  "description": "Printed after the figure (`+`, `%`, `k`)."
128
+ },
129
+ "icon": {
130
+ "type": "image",
131
+ "label": "Icon",
132
+ "description": "A small picture above the figure; decorative."
95
133
  }
96
134
  }
97
135
  },
98
136
  "description": "The figures, in order (Elementor counter, Divi number counter, a Gutenberg columns row of big numbers)."
99
137
  },
138
+ "measured": {
139
+ "type": "object",
140
+ "content": false,
141
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
142
+ "fields": {
143
+ "containerPx": {
144
+ "type": "integer",
145
+ "min": 0,
146
+ "max": 2560,
147
+ "description": "The frame's content width."
148
+ },
149
+ "padY": {
150
+ "type": "integer",
151
+ "min": 0,
152
+ "max": 400,
153
+ "description": "Top and bottom padding."
154
+ },
155
+ "padX": {
156
+ "type": "integer",
157
+ "min": 0,
158
+ "max": 200,
159
+ "description": "The frame's side padding (gutter)."
160
+ },
161
+ "bg": {
162
+ "type": "object",
163
+ "description": "The section's background.",
164
+ "fields": {
165
+ "color": {
166
+ "type": "string",
167
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
168
+ },
169
+ "image": {
170
+ "type": "string",
171
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
172
+ },
173
+ "overlay": {
174
+ "type": "string",
175
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
176
+ },
177
+ "size": {
178
+ "type": "string",
179
+ "description": "cover, contain or auto; anything else draws as cover."
180
+ },
181
+ "position": {
182
+ "type": "string",
183
+ "description": "One or two of center/top/bottom/left/right or percentages."
184
+ }
185
+ }
186
+ },
187
+ "columns": {
188
+ "type": "object",
189
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
190
+ "fields": {
191
+ "390": {
192
+ "type": "integer",
193
+ "min": 1,
194
+ "max": 6,
195
+ "description": "Phone."
196
+ },
197
+ "768": {
198
+ "type": "integer",
199
+ "min": 1,
200
+ "max": 6,
201
+ "description": "Tablet."
202
+ },
203
+ "1280": {
204
+ "type": "integer",
205
+ "min": 1,
206
+ "max": 6,
207
+ "description": "Desktop."
208
+ }
209
+ }
210
+ },
211
+ "gap": {
212
+ "type": "integer",
213
+ "min": 0,
214
+ "max": 200,
215
+ "description": "Gap between items."
216
+ },
217
+ "tone": {
218
+ "type": "select",
219
+ "options": [
220
+ "light",
221
+ "dark"
222
+ ],
223
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
224
+ },
225
+ "align": {
226
+ "type": "select",
227
+ "options": [
228
+ "start",
229
+ "center",
230
+ "end"
231
+ ],
232
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
233
+ },
234
+ "radius": {
235
+ "type": "integer",
236
+ "min": 0,
237
+ "max": 200,
238
+ "description": "Card and item corner radius."
239
+ },
240
+ "minHeight": {
241
+ "type": "integer",
242
+ "min": 0,
243
+ "max": 2000,
244
+ "description": "The section's minimum height."
245
+ }
246
+ }
247
+ },
100
248
  "id": {
101
249
  "type": "string",
102
250
  "content": false,
@@ -1,10 +1,13 @@
1
1
  ---
2
2
  // How it works: an ordered sequence of steps, each a title and a line of
3
3
  // text, optionally with an image — as a vertical list or a row across the
4
- // page, numbered or plain.
4
+ // page, numbered or plain. `kind="timeline"` is the dated variant: a date per
5
+ // item on a vertical rail, optionally alternating left and right of it.
5
6
  import { tv } from 'tailwind-variants'
6
7
  import KitImage from '../_shared/KitImage.astro'
7
8
  import Section from '../_shared/Section.astro'
9
+ import { measuredGrid } from '../_shared/measured'
10
+ import type { MeasuredStyle } from '../_shared/types'
8
11
  import { imageOf, type ImageSource } from '../_shared/image'
9
12
 
10
13
  const steps = tv({
@@ -14,6 +17,7 @@ const steps = tv({
14
17
  intro: 'text-lg opacity-80',
15
18
  list: 'grid gap-8 [counter-reset:kit-step]',
16
19
  step: 'flex gap-4 [counter-increment:kit-step]',
20
+ date: 'text-sm font-semibold tabular-nums text-accent-text',
17
21
  body: 'flex flex-col gap-2',
18
22
  badge: 'shrink-0',
19
23
  media: 'mb-2 overflow-hidden rounded-[var(--radius-image,var(--radius-card))]',
@@ -24,7 +28,14 @@ const steps = tv({
24
28
  layout: {
25
29
  list: { list: 'max-w-3xl' },
26
30
  row: { list: 'sm:grid-cols-2 lg:auto-cols-fr lg:grid-flow-col lg:grid-cols-none', step: 'flex-col' },
31
+ // One rail on the inline-start side (the item's own side is the rail's, mirrored in RTL by the logical `ps-`/`border-s`).
32
+ rail: { list: 'max-w-3xl gap-0', step: 'relative border-s-2 border-line pb-8 ps-6 last:pb-0' },
33
+ // Items alternate either side of a centre rail from `md`; the DOM stays chronological, one rail on the start side on phones.
34
+ alternate: { list: 'gap-0 md:grid-cols-2', step: 'relative border-s-2 border-line pb-8 ps-6 md:[&:nth-child(even)]:col-start-2 md:[&:nth-child(odd)]:col-start-1 md:[&:nth-child(odd)]:border-s-0 md:[&:nth-child(odd)]:border-e-2 md:[&:nth-child(odd)]:pe-6 md:[&:nth-child(odd)]:ps-0 md:[&:nth-child(odd)]:text-end md:[&:nth-child(odd)]:flex-row-reverse md:[&:nth-child(even)]:-ms-px md:[&:nth-child(odd)]:after:start-auto md:[&:nth-child(odd)]:after:-end-[7px]' },
27
35
  },
36
+ // What sits on the rail: the number, a plain dot, or the date (the timeline's own marker). The number marker is `style`'s.
37
+ marker: { number: {}, dot: { step: 'before:hidden after:absolute after:top-1.5 after:-start-[7px] after:size-3 after:rounded-full after:bg-accent after:content-[""]' } },
38
+ connector: { none: {}, line: {}, dashed: { step: 'border-dashed' } },
28
39
  // The number is drawn from a CSS counter, so the list stays one <ol> a screen reader counts itself. A number the
29
40
  // source wrote (`01`) is the page's text and is shown as written, hidden from the screen reader that already counts.
30
41
  style: {
@@ -35,7 +46,7 @@ const steps = tv({
35
46
  plain: { step: 'border-s-2 border-accent ps-4', badge: 'font-semibold tabular-nums' },
36
47
  },
37
48
  },
38
- defaultVariants: { layout: 'list', style: 'numbered' },
49
+ defaultVariants: { layout: 'list', marker: 'number', connector: 'line', style: 'numbered' },
39
50
  })
40
51
 
41
52
  interface Step {
@@ -43,6 +54,10 @@ interface Step {
43
54
  number?: string | undefined
44
55
  title: string
45
56
  text: string
57
+ /** A timeline's date as the source writes it (`2019`, `Mar 2021`); `datetime` only when it parses as an ISO date or year. */
58
+ date?: string | undefined
59
+ /** Marks the latest item: a visually hidden "Current" is added for readers. */
60
+ current?: boolean | undefined
46
61
  /** The image's address. */
47
62
  image?: ImageSource | undefined
48
63
  imageAlt?: string | undefined
@@ -52,30 +67,43 @@ interface Props {
52
67
  heading?: string | undefined
53
68
  intro?: string | undefined
54
69
  items: Step[]
55
- layout?: 'list' | 'row' | undefined
70
+ /** `steps` numbers a sequence; `timeline` carries a date per item (the rail layouts below). */
71
+ kind?: 'steps' | 'timeline' | undefined
72
+ layout?: 'list' | 'row' | 'rail' | 'alternate' | undefined
73
+ marker?: 'number' | 'dot' | undefined
74
+ connector?: 'none' | 'line' | 'dashed' | undefined
75
+ currentLabel?: string | undefined
56
76
  style?: 'numbered' | 'plain' | undefined
77
+ /** The source section's measured style (`MeasuredStyle`): frame, padding, fill, background image, columns per width, gap. Absent, the site's tokens; present, it wins over tone and columns. */
78
+ measured?: MeasuredStyle | undefined
57
79
  id?: string | undefined
58
80
  }
59
81
 
60
- const { heading, intro, items, layout, style, id } = Astro.props
61
- const s = steps({ layout, style })
82
+ const { heading, intro, items, kind = 'steps', layout: givenLayout, marker, connector, currentLabel = 'Current', style, measured, id } = Astro.props
83
+ // A timeline defaults to the rail layout and, without numbers, to the plain dot marker.
84
+ const layout = givenLayout ?? (kind === 'timeline' ? 'rail' : 'list')
85
+ const s = steps({ layout, marker: marker ?? (kind === 'timeline' ? 'dot' : 'number'), connector, style })
86
+ // A bare year or an ISO date is machine-readable; anything else ("Spring 2021") stays text.
87
+ const isoDate = (date: string) => /^\d{4}(-\d{2}(-\d{2})?)?$/.test(date.trim()) ? date.trim() : undefined
62
88
  const headingId = heading && id ? `${id}-title` : undefined
63
89
  // One level under the section heading, or the section's heading when there is none.
64
90
  const StepHeading = heading ? 'h3' : 'h2'
65
91
  ---
66
92
  {items.length > 0 && (
67
- <Section id={id} aria-labelledby={headingId}>
93
+ <Section measured={measured} id={id} aria-labelledby={headingId}>
68
94
  {(heading || intro) && (
69
95
  <header class={s.header()}>
70
96
  {heading && <h2 id={headingId} class={s.heading()}>{heading}</h2>}
71
97
  {intro && <p class={s.intro()} data-kit-text>{intro}</p>}
72
98
  </header>
73
99
  )}
74
- <ol class={s.list()}>
100
+ <ol class={s.list({ class: layout === 'row' ? measuredGrid(measured) : undefined })}>
75
101
  {items.map(step => (
76
- <li class={s.step({ class: step.number ? 'before:hidden' : undefined })}>
102
+ <li class={s.step({ class: step.number || kind === 'timeline' ? 'before:hidden' : undefined })} aria-current={step.current ? 'step' : undefined}>
77
103
  {step.number && <span class={s.badge()} aria-hidden="true">{step.number}</span>}
78
104
  <div class={s.body()}>
105
+ {kind === 'timeline' && step.date && (isoDate(step.date) ? <time class={s.date()} datetime={isoDate(step.date)}>{step.date}</time> : <p class={s.date()}>{step.date}</p>)}
106
+ {step.current && <span class="sr-only">{currentLabel}</span>}
79
107
  {imageOf(step.image, step.imageAlt) && <div class={s.media()}><KitImage image={imageOf(step.image, step.imageAlt)!} sizes="(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw" class="aspect-[3/2] w-full object-cover" /></div>}
80
108
  <StepHeading class={s.title()}>{step.title}</StepHeading>
81
109
  <p class={s.text()} data-kit-text>{step.text}</p>
@@ -1,7 +1,219 @@
1
1
  [
2
- {"name": "list-numbered", "props": {"id": "how", "heading": "How it works", "intro": "Three steps from WordPress to a static site.", "items": [{"title": "Connect", "text": "Point us at your site; we read everything it publishes."}, {"title": "Review", "text": "Check the plan: every page, model and redirect."}, {"title": "Launch", "text": "Deploy the new site; every old address still works."}]}},
3
- {"name": "row-plain-images", "props": {"layout": "row", "style": "plain", "heading": "Our process", "items": [{"title": "Discover", "text": "We learn the site and its readers.", "image": "/kit-fixtures/photo-1.svg"}, {"title": "Design", "text": "We draw the pages and the system.", "image": "/kit-fixtures/photo-2.svg"}, {"title": "Build", "text": "We ship it, fast and accessible.", "image": "/kit-fixtures/photo-3.svg", "imageAlt": "A laptop showing the finished site"}]}},
4
- {"name": "row-numbered", "props": {"layout": "row", "items": [{"title": "Sign up", "text": "One minute, no card."}, {"title": "Import", "text": "Bring your content."}, {"title": "Edit", "text": "Change it in Studio."}, {"title": "Publish", "text": "Push and it is live."}]}},
5
- {"name": "source-numbers", "props": {"heading": "Getting started", "items": [{"number": "01", "title": "Connect", "text": "Point Calm Status at the services you already monitor."}, {"number": "02", "title": "Write", "text": "Pick the words customers see for each kind of problem."}, {"number": "03", "title": "Publish", "text": "Put the page live on your own domain."}]}},
6
- {"name": "row-plain-source-numbers", "props": {"layout": "row", "style": "plain", "items": [{"number": "Step 1", "title": "Call", "text": "We learn what you make and who buys it."}, {"number": "Step 2", "title": "Design and build", "text": "Four weeks of weekly previews."}, {"number": "Step 3", "title": "Launch", "text": "We switch it on together."}]}}
2
+ {
3
+ "name": "list-numbered",
4
+ "props": {
5
+ "id": "how",
6
+ "heading": "How it works",
7
+ "intro": "Three steps from WordPress to a static site.",
8
+ "items": [
9
+ {
10
+ "title": "Connect",
11
+ "text": "Point us at your site; we read everything it publishes."
12
+ },
13
+ {
14
+ "title": "Review",
15
+ "text": "Check the plan: every page, model and redirect."
16
+ },
17
+ {
18
+ "title": "Launch",
19
+ "text": "Deploy the new site; every old address still works."
20
+ }
21
+ ]
22
+ }
23
+ },
24
+ {
25
+ "name": "row-plain-images",
26
+ "props": {
27
+ "layout": "row",
28
+ "style": "plain",
29
+ "heading": "Our process",
30
+ "items": [
31
+ {
32
+ "title": "Discover",
33
+ "text": "We learn the site and its readers.",
34
+ "image": "/kit-fixtures/photo-1.svg"
35
+ },
36
+ {
37
+ "title": "Design",
38
+ "text": "We draw the pages and the system.",
39
+ "image": "/kit-fixtures/photo-2.svg"
40
+ },
41
+ {
42
+ "title": "Build",
43
+ "text": "We ship it, fast and accessible.",
44
+ "image": "/kit-fixtures/photo-3.svg",
45
+ "imageAlt": "A laptop showing the finished site"
46
+ }
47
+ ]
48
+ }
49
+ },
50
+ {
51
+ "name": "row-numbered",
52
+ "props": {
53
+ "layout": "row",
54
+ "items": [
55
+ {
56
+ "title": "Sign up",
57
+ "text": "One minute, no card."
58
+ },
59
+ {
60
+ "title": "Import",
61
+ "text": "Bring your content."
62
+ },
63
+ {
64
+ "title": "Edit",
65
+ "text": "Change it in Studio."
66
+ },
67
+ {
68
+ "title": "Publish",
69
+ "text": "Push and it is live."
70
+ }
71
+ ]
72
+ }
73
+ },
74
+ {
75
+ "name": "source-numbers",
76
+ "props": {
77
+ "heading": "Getting started",
78
+ "items": [
79
+ {
80
+ "number": "01",
81
+ "title": "Connect",
82
+ "text": "Point Calm Status at the services you already monitor."
83
+ },
84
+ {
85
+ "number": "02",
86
+ "title": "Write",
87
+ "text": "Pick the words customers see for each kind of problem."
88
+ },
89
+ {
90
+ "number": "03",
91
+ "title": "Publish",
92
+ "text": "Put the page live on your own domain."
93
+ }
94
+ ]
95
+ }
96
+ },
97
+ {
98
+ "name": "row-plain-source-numbers",
99
+ "props": {
100
+ "layout": "row",
101
+ "style": "plain",
102
+ "items": [
103
+ {
104
+ "number": "Step 1",
105
+ "title": "Call",
106
+ "text": "We learn what you make and who buys it."
107
+ },
108
+ {
109
+ "number": "Step 2",
110
+ "title": "Design and build",
111
+ "text": "Four weeks of weekly previews."
112
+ },
113
+ {
114
+ "number": "Step 3",
115
+ "title": "Launch",
116
+ "text": "We switch it on together."
117
+ }
118
+ ]
119
+ }
120
+ },
121
+ {
122
+ "name": "timeline-rail",
123
+ "props": {
124
+ "id": "history",
125
+ "heading": "Our story",
126
+ "kind": "timeline",
127
+ "marker": "dot",
128
+ "items": [
129
+ {
130
+ "date": "2019",
131
+ "title": "Founded",
132
+ "text": "Two people and a shared desk."
133
+ },
134
+ {
135
+ "date": "Mar 2021",
136
+ "title": "First customers",
137
+ "text": "The first twenty sites moved over."
138
+ },
139
+ {
140
+ "date": "2024",
141
+ "title": "Open source",
142
+ "text": "The toolkit went public.",
143
+ "current": true
144
+ }
145
+ ]
146
+ }
147
+ },
148
+ {
149
+ "name": "timeline-alternate-dashed",
150
+ "props": {
151
+ "kind": "timeline",
152
+ "layout": "alternate",
153
+ "connector": "dashed",
154
+ "items": [
155
+ {
156
+ "date": "2019",
157
+ "title": "Founded",
158
+ "text": "Two people and a shared desk."
159
+ },
160
+ {
161
+ "date": "Mar 2021",
162
+ "title": "First customers",
163
+ "text": "The first twenty sites moved over."
164
+ },
165
+ {
166
+ "date": "2024",
167
+ "title": "Open source",
168
+ "text": "The toolkit went public.",
169
+ "current": true
170
+ }
171
+ ]
172
+ }
173
+ },
174
+ {
175
+ "name": "timeline-no-connector",
176
+ "props": {
177
+ "kind": "timeline",
178
+ "layout": "rail",
179
+ "connector": "none",
180
+ "items": [
181
+ {
182
+ "date": "2019",
183
+ "title": "Founded",
184
+ "text": "Two people and a shared desk."
185
+ },
186
+ {
187
+ "date": "Mar 2021",
188
+ "title": "First customers",
189
+ "text": "The first twenty sites moved over."
190
+ },
191
+ {
192
+ "title": "No date here",
193
+ "text": "An item with no date reads as a step."
194
+ }
195
+ ]
196
+ }
197
+ },
198
+ {
199
+ "name": "rail-numbered",
200
+ "props": {
201
+ "layout": "rail",
202
+ "marker": "number",
203
+ "items": [
204
+ {
205
+ "title": "Connect",
206
+ "text": "Point us at your site; we read everything it publishes."
207
+ },
208
+ {
209
+ "title": "Review",
210
+ "text": "Check the plan: every page, model and redirect."
211
+ },
212
+ {
213
+ "title": "Launch",
214
+ "text": "Deploy the new site; every old address still works."
215
+ }
216
+ ]
217
+ }
218
+ }
7
219
  ]