announcement-banner
Generates an in-app announcement banner system with remote configuration, scheduling, deep link actions, and dismiss tracking. Use when user wants in-app banners, promotional notices, maintenance alerts, or contextual announcements.
What this skill does
# Announcement Banner Generator
Generate a configurable in-app announcement/banner system that displays contextual messages (maintenance alerts, new feature highlights, promotions) from remote config or local definitions. Supports dismissal, deep link actions, and scheduling.
## When This Skill Activates
Use this skill when the user:
- Asks to "add announcement banner" or "in-app banner"
- Wants "app announcement" or "notification banner"
- Mentions "promotional banner" or "promo banner"
- Asks about "maintenance notice" or "maintenance alert"
- Wants "in-app messaging" or "contextual banners"
- Asks to "show announcements" or "display alerts to users"
- Mentions "feature highlight banner" or "what's new banner"
## Pre-Generation Checks
### 1. Project Context Detection
- [ ] Check Swift version (requires Swift 5.9+)
- [ ] Check deployment target (iOS 16+ / macOS 13+)
- [ ] Check for @Observable support (iOS 17+ / macOS 14+)
- [ ] Identify source file locations
### 2. Conflict Detection
Search for existing banner/toast code:
```
Glob: **/*Banner*.swift, **/*Announcement*.swift, **/*Toast*.swift, **/*InAppMessage*.swift
Grep: "AnnouncementBanner" or "InAppBanner" or "ToastView" or "BannerView"
```
If third-party library found (Firebase In-App Messaging, Braze, Intercom):
- Ask if user wants to replace or keep it
- If keeping, don't generate — advise on integration patterns instead
### 3. Deep Linking Detection
Check for existing deep linking setup:
```
Grep: "deepLink" or "DeepLink" or "universalLink" or "openURL" or "onOpenURL"
```
If deep linking exists, integrate with it. If not, generate standalone action handling.
## Configuration Questions
Ask user via AskUserQuestion:
1. **Banner position?**
- Top (slides in from top) — recommended for alerts
- Bottom (slides in from bottom)
- Floating (centered overlay with dimmed background)
2. **Content source?**
- Local only (hardcoded announcements in code)
- Remote JSON (fetch from server endpoint)
- Both (remote with local fallbacks) — recommended
3. **Action type?**
- Deep link (navigate to in-app screen)
- URL (open in Safari/SFSafariViewController)
- Dismiss only (informational, no action button)
- All of the above — recommended
4. **Include scheduling (start/end dates)?**
- Yes (time-limited announcements with date ranges) — recommended
- No (always-active until dismissed)
## Generation Process
### Step 1: Read Templates
Read `templates.md` for production Swift code.
### Step 2: Create Core Files
Generate these files:
1. `Announcement.swift` — Model with style, action, priority, scheduling
2. `AnnouncementManager.swift` — @Observable manager: loads, filters, tracks dismissals
3. `AnnouncementProvider.swift` — Protocol + local/remote implementations with caching
### Step 3: Create UI Files
4. `AnnouncementBannerView.swift` — SwiftUI banner with style-aware colors and animations
5. `AnnouncementBannerModifier.swift` — ViewModifier for overlay placement and action routing
### Step 4: Create Optional Files
Based on configuration:
- `AnnouncementScheduler.swift` — If scheduling selected (date range filtering, timezone handling)
### Step 5: Determine File Location
Check project structure:
- If `Sources/` exists -> `Sources/AnnouncementBanner/`
- If `App/` exists -> `App/AnnouncementBanner/`
- Otherwise -> `AnnouncementBanner/`
## Output Format
After generation, provide:
### Files Created
```
AnnouncementBanner/
├── Announcement.swift # Model with style, action, priority
├── AnnouncementManager.swift # Observable manager with dismiss tracking
├── AnnouncementProvider.swift # Protocol + local/remote providers
├── AnnouncementBannerView.swift # SwiftUI banner view
├── AnnouncementBannerModifier.swift# ViewModifier for overlay + actions
└── AnnouncementScheduler.swift # Date range filtering (optional)
```
### Integration Steps
**Add banner overlay to root view:**
```swift
// In your root ContentView or NavigationStack
ContentView()
.announcementBanner()
```
**With custom position:**
```swift
ContentView()
.announcementBanner(position: .bottom)
```
**With deep link action handler:**
```swift
ContentView()
.announcementBanner { action in
switch action {
case .deepLink(let destination):
router.navigate(to: destination)
case .url(let url):
openURL(url)
case .dismiss:
break
}
}
```
**Define local announcements:**
```swift
let provider = LocalAnnouncementProvider(announcements: [
Announcement(
id: "maintenance-2024",
title: "Scheduled Maintenance",
message: "We'll be performing maintenance on Saturday 9-11 AM EST.",
style: .warning,
action: .dismiss,
priority: 10,
startDate: maintenanceStart,
endDate: maintenanceEnd
),
Announcement(
id: "new-feature-photos",
title: "New: Photo Library",
message: "Check out our new photo library with AI-powered search!",
style: .promotion,
action: .deepLink("app://features/photos"),
priority: 5,
isDismissible: true
)
])
```
**Fetch from remote config:**
```swift
let provider = RemoteAnnouncementProvider(
url: URL(string: "https://api.example.com/announcements")!,
cacheDuration: 3600 // 1 hour
)
```
### Testing
```swift
@Test
func dismissedAnnouncementsAreHidden() async throws {
let manager = AnnouncementManager(
provider: MockAnnouncementProvider(announcements: [testAnnouncement]),
dismissalStore: InMemoryDismissalStore()
)
await manager.loadAnnouncements()
#expect(manager.activeAnnouncement != nil)
manager.dismiss(testAnnouncement)
#expect(manager.activeAnnouncement == nil)
}
@Test
func highestPriorityAnnouncementShownFirst() async throws {
let lowPriority = Announcement(id: "low", title: "Low", message: "...", style: .info, priority: 1)
let highPriority = Announcement(id: "high", title: "High", message: "...", style: .warning, priority: 10)
let manager = AnnouncementManager(
provider: MockAnnouncementProvider(announcements: [lowPriority, highPriority])
)
await manager.loadAnnouncements()
#expect(manager.activeAnnouncement?.id == "high")
}
@Test
func expiredAnnouncementsAreFiltered() async throws {
let expired = Announcement(
id: "expired",
title: "Old",
message: "...",
style: .info,
endDate: Date.distantPast
)
let manager = AnnouncementManager(
provider: MockAnnouncementProvider(announcements: [expired])
)
await manager.loadAnnouncements()
#expect(manager.activeAnnouncement == nil)
}
```
## Common Patterns
### Show Maintenance Banner
```swift
Announcement(
id: "maintenance-\(date)",
title: "Scheduled Maintenance",
message: "Service will be unavailable Saturday 2-4 AM EST.",
style: .warning,
action: .url(URL(string: "https://status.example.com")!),
priority: 100, // High priority overrides other banners
startDate: Calendar.current.date(byAdding: .day, value: -1, to: maintenanceDate)!,
endDate: maintenanceEndDate,
isDismissible: false // Can't dismiss maintenance warnings
)
```
### Promote New Feature
```swift
Announcement(
id: "feature-v2.5-darkmode",
title: "Dark Mode is Here!",
message: "Try our new dark mode in Settings.",
style: .promotion,
action: .deepLink("app://settings/appearance"),
priority: 5,
isDismissible: true
)
```
### Time-Limited Promotion
```swift
Announcement(
id: "promo-summer-2024",
title: "Summer Sale - 40% Off!",
message: "Upgrade to Pro at our lowest price ever.",
style: .promotion,
action: .deepLink("app://subscription/upgrade"),
priority: 8,
startDate: promoStart,
endDate: promoEnd,
isDismissible: true,
targetAudience: .freeUsers
)
```
## Gotchas
1. **Banner stacking**Related in Data & Analytics
clawarr-suite
IncludedComprehensive management for self-hosted media stacks (Sonarr, Radarr, Lidarr, Readarr, Prowlarr, Bazarr, Overseerr, Plex, Tautulli, SABnzbd, Recyclarr, Unpackerr, Notifiarr, Maintainerr, Kometa, FlareSolverr). Deep library exploration, analytics, dashboard generation, content management, request handling, subtitle management, indexer control, download monitoring, quality profile sync, library cleanup automation, notification routing, collection/overlay management, and media tracker integration (Trakt, Letterboxd, Simkl).
querying-soql
IncludedSOQL query generation, optimization, and analysis with 100-point scoring. Use this skill when the user needs SOQL/SOSL authoring or optimization: natural-language-to-query generation, relationship queries, aggregates, query-plan analysis, and performance or safety improvements for Salesforce queries. TRIGGER when: user writes, optimizes, or debugs SOQL/SOSL queries, touches .soql files, or asks about relationship queries, aggregates, or query performance. DO NOT TRIGGER when: bulk data operations (use handling-sf-data), Apex DML logic (use generating-apex), or report/dashboard queries.
app-store-optimization
IncludedApp Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklists, and tracking ranking changes.
habit-flow
IncludedAI-powered atomic habit tracker with natural language logging, streak tracking, smart reminders, and coaching. Use for creating habits, logging completions naturally ("I meditated today"), viewing progress, and getting personalized coaching.
app-store-optimization
IncludedApp Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklists, and tracking ranking changes.
visualizing-data
IncludedBuilds dashboards, reports, and data-driven interfaces requiring charts, graphs, or visual analytics. Provides systematic framework for selecting appropriate visualizations based on data characteristics and analytical purpose. Includes 24+ visualization types organized by purpose (trends, comparisons, distributions, relationships, flows, hierarchies, geospatial), accessibility patterns (WCAG 2.1 AA compliance), colorblind-safe palettes, and performance optimization strategies. Use when creating visualizations, choosing chart types, displaying data graphically, or designing data interfaces.