Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import SwiftUI

@MainActor
struct CapabilitiesBriefingView: View {
@Bindable var state: OnboardingState
var onComplete: () -> Void

@State private var firstParagraphDone = false
@State private var showSecondParagraph = false
@State private var showButtons = false
@State private var showCapabilitiesModal = false

private let firstText = "Okay, I think I\u{2019}ve got a good sense of where to start. Before we dive in \u{2014} quick road trip safety briefing."
private let secondText = "For now, think of it like you\u{2019}re driving and I\u{2019}m the passenger. I can navigate, handle stuff on my phone, keep us on track \u{2014} but you\u{2019}re steering."

var body: some View {
HStack(alignment: .center, spacing: VSpacing.xxxl) {
// Creature on the left, small like in interview step
CreatureView(visible: true, animated: false)
.scaleEffect(0.5)
.frame(width: 200, height: 200)

OnboardingPanel {
VStack(alignment: .leading, spacing: VSpacing.xl) {
// Framing text
VStack(alignment: .leading, spacing: VSpacing.lg) {
TypewriterText(
fullText: firstText,
speed: 0.03,
font: VFont.body,
onComplete: {
firstParagraphDone = true
withAnimation(.easeOut(duration: 0.4)) {
showSecondParagraph = true
}
}
)

if showSecondParagraph {
TypewriterText(
fullText: secondText,
speed: 0.03,
font: VFont.body,
onComplete: {
withAnimation(.easeOut(duration: 0.5)) {
showButtons = true
}
}
)
.transition(.opacity.combined(with: .offset(y: 6)))
}
}

// Action buttons
if showButtons {
VStack(spacing: VSpacing.md) {
OnboardingButton(
title: "Got it, let\u{2019}s go",
style: .primary,
fadeIn: true,
fadeDelay: 0.1
) {
state.capabilitiesBriefingShown = true
onComplete()
}

OnboardingButton(
title: "See what I can do",
style: .ghost,
fadeIn: true,
fadeDelay: 0.3
) {
showCapabilitiesModal = true
}
}
.transition(.opacity.combined(with: .offset(y: 8)))
}
}
}
.frame(maxWidth: 420)
}
.sheet(isPresented: $showCapabilitiesModal) {
CapabilitiesModalView()
}
}
}

#Preview {
ZStack {
MeadowBackground()
CapabilitiesBriefingView(
state: {
let s = OnboardingState()
s.currentStep = 3
s.assistantName = "Velly"
return s
}(),
onComplete: {}
)
}
.frame(width: 1366, height: 849)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import SwiftUI

@MainActor
struct CapabilitiesModalView: View {
@Environment(\.dismiss) private var dismiss

var body: some View {
VStack(spacing: 0) {
ScrollView {
VStack(alignment: .leading, spacing: VSpacing.xxl) {
sectionView(
icon: "sparkles",
iconColor: Emerald._500,
title: "What I can do",
items: [
"Browse the web and search for information",
"Read, write, and organize files",
"Manage tasks and reminders",
"Help with email drafts and replies",
"Take actions in apps on your behalf",
]
)

sectionView(
icon: "shield.lefthalf.filled",
iconColor: Rose._500,
title: "What I won\u{2019}t do",
items: [
"Act without asking when something\u{2019}s irreversible",
"Access your accounts without permission \u{2014} I\u{2019}ll always ask first",
"Store sensitive information like passwords",
"Make decisions that should be yours",
]
)

sectionView(
icon: "car.fill",
iconColor: Violet._500,
title: "How control works",
items: [
"You\u{2019}re always in the driver\u{2019}s seat",
"I\u{2019}ll ask before doing anything big",
"You can take over anytime",
"Say \u{201C}stop\u{201D} or press Escape to halt any action",
]
)
}
.padding(.horizontal, VSpacing.xxl)
.padding(.top, VSpacing.xxl)
.padding(.bottom, VSpacing.lg)
}

Divider()
.background(VColor.surfaceBorder.opacity(0.4))

VButton(label: "Got it", style: .primary, isFullWidth: true) {
dismiss()
}
.padding(.horizontal, VSpacing.xxl)
.padding(.vertical, VSpacing.lg)
}
.frame(width: 400, minHeight: 480)
.background(
RoundedRectangle(cornerRadius: VRadius.xl)
.fill(.ultraThinMaterial)
.overlay(
RoundedRectangle(cornerRadius: VRadius.xl)
.fill(Meadow.panelBackground)
)
.overlay(
RoundedRectangle(cornerRadius: VRadius.xl)
.stroke(Meadow.panelBorder, lineWidth: 1)
)
)
}

// MARK: - Section Builder

private func sectionView(
icon: String,
iconColor: Color,
title: String,
items: [String]
) -> some View {
VStack(alignment: .leading, spacing: VSpacing.md) {
HStack(spacing: VSpacing.sm) {
Image(systemName: icon)
.font(.system(size: 14, weight: .semibold))
.foregroundColor(iconColor)
Text(title)
.font(VFont.headline)
.foregroundColor(VColor.textPrimary)
}

VStack(alignment: .leading, spacing: VSpacing.sm) {
ForEach(items, id: \.self) { item in
HStack(alignment: .top, spacing: VSpacing.sm) {
Text("\u{2022}")
.font(VFont.body)
.foregroundColor(VColor.textMuted)
Text(item)
.font(VFont.body)
.foregroundColor(VColor.textSecondary)
.fixedSize(horizontal: false, vertical: true)
}
}
}
.padding(.leading, VSpacing.xs)
}
}
}

#Preview {
CapabilitiesModalView()
.frame(width: 420, height: 560)
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ struct FirstMeetingFlowView: View {
.font(VFont.headline)
.foregroundColor(VColor.textPrimary)
case 3:
Text("Capabilities briefing — coming soon")
.font(VFont.headline)
.foregroundColor(VColor.textPrimary)
CapabilitiesBriefingView(state: state, onComplete: { state.advance() })
case 4:
Text("Observation mode — coming soon")
.font(VFont.headline)
Expand Down