Pattern · AI Chat

New

Chat Welcome SwiftUI Block

The start of a new assistant chat: a greeting, suggestion cards by intent that page sideways, Shuffle, and recent chats to continue.

The empty start of a new chat. A greeting with the person's name sits over a prompt line, intents (Write, Learn, Plan, Code) pick a two-row grid of suggestion cards that pages sideways, and a tapped card hands its prompt to your app and marks itself. Shuffle fetches fresh suggestions with its own working and failed states, and Continue where you left off lists the three most recent chats with See all.

  • SwiftUI
  • iOS 17.0+
  • chat-welcome
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • A greeting by time of day with the person's name, in the brand's display face
  • Write, Learn, Plan and Code over a two-row grid of cards that pages sideways
  • Tapping a card hands its prompt to your app and marks it
  • Shuffle fetches fresh suggestions with working and failed states
  • The three most recent chats with See all, ghosts while loading

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

A greeting in the brand's display face ("Good morning, Maya", by the time of day) sits over a one-line prompt. Under it, the intents (Write, Learn, Plan, Code) are a row of chips with the chosen one inked, and the chosen intent's suggestions are cards in a two-row grid that pages sideways four at a time, with dots under it. Each card has a symbol, a title and one line; tapping it hands its prompt to your closure and marks it with a check and an inked outline for a moment. Shuffle asks your closure for fresh suggestions, shows a spinner while it works and the error under the grid if it throws. Continue where you left off lists the three most recent chats with their last line and when, and See all. Pass nil while the welcome loads and the block draws grey shapes in its own layout; with no recent chats that group is left out.

Notes

  • ChatWelcomeBlock(welcome:onPick:onOpenRecent:onSeeAll:onShuffle:) takes one Welcome value. It is a section: no navigation stack, background, padding or vertical scroll view of its own. The suggestion pages scroll sideways.
  • ChatWelcomeBlock.Welcome holds the person's name (nil greets without one), the prompt line ("What would you like to work on?" by default), the intents and the recents. Welcome.sample is Maya's welcome from the preview.
  • An Intent has an id, a title and its suggestions. A Suggestion has an id, a title, a detail line, the prompt that onPick receives and an SF Symbol. A Recent has an id, title, snippet and date; the three newest show.
  • onPick runs with the prompt when a card is tapped: put it in your composer or send it. The card stays marked for about a second and a half.
  • onShuffle returns fresh suggestions for the chosen intent; they replace its cards and the grid goes back to the first page. Throw to show the error's errorDescription (or "Couldn't load new suggestions. Try again.") under the grid; throw CancellationError() to back out quietly. Leave it out to hide Shuffle.
  • onOpenRecent opens a recent chat and onSeeAll your history. Leave either out to hide it.
  • Times read the time today, "Yesterday", the weekday within a week, else the date.
  • A haptic marks each pick and a failed shuffle.
  • VoiceOver reads the greeting as a header, each card as its title with its line and a hint, the dots as "Page 1 of 2", and announces new suggestions. At accessibility sizes Shuffle keeps its symbol only, and cards and rows grow with the text.
  • ChatWelcomeBlockExample at the end of ChatWelcomeBlock.swift is the new chat screen from the preview: Maya's welcome over a composer that a tapped suggestion fills. Pass wrapsInNavigationStack: false to push it in your own stack.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • The greeting is the one display moment: type.face at 28 points, type.displayWeight capped at semibold, in textPrimary; when the face isn't bundled it falls back to type.figureDesign, or type.textDesign when figures are monospaced. The prompt is type.body in textSecondary.
  • Intent chips are fill with textSecondary; the chosen one is textPrimary with bg text.
  • Cards are color.surface at radius.lg with 16 point padding, the symbol in textSecondary, the title in type.subhead semibold and the line in type.footnote. A picked card gets a 1.5 point textPrimary outline and a check.
  • The recents card is surface at radius.lg with SPHairline dividers; titles type.body, snippets type.subhead in textSecondary, times type.footnote in textTertiary. The group title is type.headline.
  • Errors are danger. Changes use motion.snappy and motion.smooth, short fades under Reduce Motion.