Skip to content

Instantly share code, notes, and snippets.

@gtokman
Created May 23, 2025 15:59
Show Gist options
  • Save gtokman/e604df05b74a5c33680671a649f3c528 to your computer and use it in GitHub Desktop.
Save gtokman/e604df05b74a5c33680671a649f3c528 to your computer and use it in GitHub Desktop.
import SwiftUI
import MarkdownUI
import Splash
@available(iOS 18.0, *)
struct Think: View {
@Environment(\.colorScheme) private var colorScheme
@Namespace private var ns
@State private var position = ScrollPosition(edge: .top)
@Binding var isScrolling: Bool
@State private var scrollTask: Task<Void, Never>? = nil
let text: String
var theme: Splash.Theme {
switch colorScheme {
case .dark:
return .midnight(withFont: .init(size: 16))
default:
return .sunset(withFont: .init(size: 16))
}
}
var backgroundColor: SwiftUI.Color {
colorScheme == .dark ? .black : .white
}
var body: some View {
ScrollView {
HStack {
Text(text)
Spacer()
}
}
.contentMargins(.top, 12)
.contentMargins(.bottom, 8)
.scrollPosition($position)
.frame(height: 100)
.overlay(alignment: .top) {
LinearGradient(
gradient: Gradient(colors: [
backgroundColor,
backgroundColor.opacity(0),
]),
startPoint: .top,
endPoint: .bottom
)
.opacity(1)
.frame(height: 20)
.allowsHitTesting(false)
}
.overlay(alignment: .bottom) {
LinearGradient(
gradient: Gradient(colors: [
backgroundColor,
backgroundColor.opacity(0),
]),
startPoint: .bottom,
endPoint: .top
)
.opacity(1)
.frame(height: 20)
.allowsHitTesting(false)
}
.onChange(of: text) { _, new in
scrollTask?.cancel()
scrollTask = Task { @MainActor in
try? await Task.sleep(for: .milliseconds(300))
if !isScrolling {
isScrolling = true
withAnimation(.easeOut(duration: 0.25)) {
position.scrollTo(edge: .bottom)
} completion: {
isScrolling = false
}
}
}
}
}
}
#Preview {
if #available(iOS 18.0, *) {
Think(isScrolling: .constant(false), text: "")
} else {
// Fallback on earlier versions
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment