|
|
@@ -12,16 +12,17 @@ struct ContentView: View {
|
|
|
@State private var appeared = false
|
|
|
@State private var glowPulse = false
|
|
|
@State private var currentNameIndex = 0
|
|
|
-
|
|
|
- // Add more names here later — the button cycles through them in order.
|
|
|
- private let names = ["Faiz", "Huzaifa"]
|
|
|
+ @State private var names = ["Faiz", "Huzaifa"]
|
|
|
+ @State private var newName = ""
|
|
|
|
|
|
private var displayText: String {
|
|
|
- "Hello \(names[currentNameIndex])"
|
|
|
+ guard !names.isEmpty else { return "Hello" }
|
|
|
+ return "Hello \(names[currentNameIndex])"
|
|
|
}
|
|
|
|
|
|
private var nextName: String {
|
|
|
- names[(currentNameIndex + 1) % names.count]
|
|
|
+ guard !names.isEmpty else { return "..." }
|
|
|
+ return names[(currentNameIndex + 1) % names.count]
|
|
|
}
|
|
|
private let vibrantColors: [Color] = [
|
|
|
Color(red: 1.0, green: 0.2, blue: 0.4),
|
|
|
@@ -109,6 +110,59 @@ struct ContentView: View {
|
|
|
.opacity(appeared ? 1.0 : 0.0)
|
|
|
.scaleEffect(appeared ? 1.0 : 0.8)
|
|
|
.animation(.spring(response: 0.7, dampingFraction: 0.55).delay(0.5), value: appeared)
|
|
|
+
|
|
|
+ HStack(spacing: 12) {
|
|
|
+ TextField("Enter a name", text: $newName)
|
|
|
+ .textFieldStyle(.plain)
|
|
|
+ .font(.system(size: 16, weight: .medium, design: .rounded))
|
|
|
+ .foregroundStyle(.white)
|
|
|
+ .padding(.horizontal, 16)
|
|
|
+ .padding(.vertical, 10)
|
|
|
+ .background(
|
|
|
+ Capsule()
|
|
|
+ .fill(Color.white.opacity(0.08))
|
|
|
+ .overlay(
|
|
|
+ Capsule()
|
|
|
+ .stroke(Color.white.opacity(0.2), lineWidth: 1)
|
|
|
+ )
|
|
|
+ )
|
|
|
+ .frame(width: 200)
|
|
|
+ .onSubmit(addName)
|
|
|
+
|
|
|
+ Button(action: addName) {
|
|
|
+ Text("Add Name")
|
|
|
+ .font(.system(size: 16, weight: .semibold, design: .rounded))
|
|
|
+ .foregroundStyle(
|
|
|
+ LinearGradient(
|
|
|
+ colors: [vibrantColors[2], vibrantColors[3]],
|
|
|
+ startPoint: .leading,
|
|
|
+ endPoint: .trailing
|
|
|
+ )
|
|
|
+ )
|
|
|
+ .padding(.horizontal, 20)
|
|
|
+ .padding(.vertical, 10)
|
|
|
+ .background(
|
|
|
+ Capsule()
|
|
|
+ .fill(Color.white.opacity(0.08))
|
|
|
+ .overlay(
|
|
|
+ Capsule()
|
|
|
+ .stroke(
|
|
|
+ LinearGradient(
|
|
|
+ colors: vibrantColors[2...3].map { $0.opacity(0.8) },
|
|
|
+ startPoint: .leading,
|
|
|
+ endPoint: .trailing
|
|
|
+ ),
|
|
|
+ lineWidth: 2
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ .buttonStyle(.plain)
|
|
|
+ .disabled(newName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
|
|
+ .opacity(newName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? 0.5 : 1.0)
|
|
|
+ }
|
|
|
+ .opacity(appeared ? 1.0 : 0.0)
|
|
|
+ .animation(.spring(response: 0.7, dampingFraction: 0.55).delay(0.65), value: appeared)
|
|
|
}
|
|
|
.padding()
|
|
|
}
|
|
|
@@ -125,12 +179,20 @@ struct ContentView: View {
|
|
|
}
|
|
|
|
|
|
private func cycleGreeting() {
|
|
|
+ guard !names.isEmpty else { return }
|
|
|
appeared = false
|
|
|
currentNameIndex = (currentNameIndex + 1) % names.count
|
|
|
withAnimation(.spring(response: 0.7, dampingFraction: 0.55)) {
|
|
|
appeared = true
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private func addName() {
|
|
|
+ let trimmed = newName.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
+ guard !trimmed.isEmpty, !names.contains(trimmed) else { return }
|
|
|
+ names.append(trimmed)
|
|
|
+ newName = ""
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#Preview {
|