https://github.com/marinofaggiana/lucidbanner
Elegant and fully async SwiftUI banner system for iOS — lightweight, customizable, and concurrency-safe.
https://github.com/marinofaggiana/lucidbanner
animation banner glassmorphism hud ios ios-development message notifications open-source swift swift-package swiftui swiftui-animation swiftui-components toast ui-component uikit
Last synced: 16 days ago
JSON representation
Elegant and fully async SwiftUI banner system for iOS — lightweight, customizable, and concurrency-safe.
- Host: GitHub
- URL: https://github.com/marinofaggiana/lucidbanner
- Owner: marinofaggiana
- License: mit
- Created: 2025-10-27T15:05:12.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-03-26T14:45:02.000Z (4 months ago)
- Last Synced: 2026-03-27T04:27:43.187Z (4 months ago)
- Topics: animation, banner, glassmorphism, hud, ios, ios-development, message, notifications, open-source, swift, swift-package, swiftui, swiftui-animation, swiftui-components, toast, ui-component, uikit
- Language: Swift
- Homepage: https://github.com/marinofaggiana/LucidBanner
- Size: 835 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README



SwiftUI-based transient banners rendered in their own `UIWindow` above the status bar.
- No intrusive HUDs
- Scene-aware (iPad / multi-window)
- Queueable, updatable, dismissable
Originally developed for the **Nextcloud iOS** app.
Author: **Marino Faggiana** • License: **MIT** • Version: **0.0.1**
---
### 🚧 Work in Progress
LucidBanner is currently under **active development**.
While functional, the library should be considered **experimental**, and its APIs may change as development continues.
Production use is not recommended until a stable 1.0 release.
---
## Features
- **One-at-a-time display** with queueing policies:
- `.enqueue` – queue new banners
- `.replace` – dismiss current and show the new one
- `.drop` – ignore the new request if something is already visible
- **Flexible layout**
- Vertical: `.top`, `.center`, `.bottom`
- Horizontal: `.left`, `.center`, `.right`
- Safe-area aware margins
- **Interaction**
- Swipe-to-dismiss (direction-aware based on position)
- Optional scrim that blocks touches behind the banner
- Tap callback: `onTap(token, stage)`
- **Live updates**
- `update(...)` for title / subtitle / footnote / icon / animation / progress / stage
- **Lifecycle**
- Optional auto-dismiss timer
- Simple `isAlive(token)` check
- Works with multiple scenes (`UIWindowScene`) on iPhone/iPad (iOS 17+)
---
## Requirements
- iOS 17.0+
- Swift 6.0+
- SwiftUI + UIKit
---
## Installation (Swift Package Manager)
### Xcode
1. `File → Add Packages…`
2. Enter the repository URL:
```
https://example.com/your-org/LucidBanner.git
```
3. Choose tag **0.0.1**
4. Add **LucidBanner** to your target
### Package.swift
```swift
dependencies: [
.package(url: "https://example.com/your-org/LucidBanner.git", from: "0.0.1")
]
```
---
## Quick Start
```swift
import SwiftUI
import LucidBanner
struct ContentView: View {
@State private var token: Int = 0
private var currentWindowScene: UIWindowScene? {
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first { $0.activationState == .foregroundActive }
}
var body: some View {
VStack(spacing: 16) {
Button("Show Top Banner") {
guard let scene = currentWindowScene else { return }
token = LucidBanner.shared.show(
scene: scene,
title: "Upload started",
subtitle: "Keep the app active for best performance",
systemImage: "arrow.up.circle",
imageAnimation: .breathe,
vPosition: .top,
autoDismissAfter: 3.0,
onTap: { token, stage in
print("Banner tapped: token = \(token), stage = \(stage ?? "nil")")
}
) { state in
ToastBannerView(state: state)
}
}
Button("Update Progress") {
LucidBanner.shared.update(
progress: 0.66,
stage: "uploading",
for: token
)
}
Button("Dismiss") {
LucidBanner.shared.dismiss(for: token)
}
}
.padding()
}
}
```
SwiftUI banner example:
```swift
struct ToastBannerView: View {
@ObservedObject var state: LucidBannerState
var body: some View {
HStack(spacing: 12) {
if let systemImage = state.systemImage {
Image(systemName: systemImage)
.font(.system(size: 20, weight: .semibold))
}
VStack(alignment: .leading, spacing: 2) {
if let title = state.title {
Text(title)
.font(.headline)
}
if let subtitle = state.subtitle {
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
}
if let footnote = state.footnote {
Text(footnote)
.font(.footnote)
.foregroundStyle(.secondary)
}
if let progress = state.progress {
ProgressView(value: progress)
.progressViewStyle(.linear)
}
}
Spacer()
}
.padding(12)
.background(.regularMaterial, in: RoundedRectangle(cornerRadius: 14))
.shadow(radius: 12, y: 4)
}
}
```
---
## License
MIT License. See `LICENSE` file.