Product Components/HomeFeedScreen
Screen

HomeFeedScreen

A typical home/feed screen for social, productivity, or content apps. Combines a navigation bar, search bar, segmented tabs, a list of cards, and an activity feed — all wired with SwiftDS components and consistent token-based spacing.

Preview

Home

All
Following
Trending
A

Design System v2.0 released

New

Ana Lima · 2m ago

J

Spring animations in SwiftUI

João M. · 1h ago

S

Token-based theming guide

Sara C. · 3h ago

Home
Explore
Inbox
Profile

Components used

DSNavigationBar

Title + trailing icon buttons

DSSearchBar

Inline search in the nav area

DSSegmentedControl

All / Following / Trending tabs

DSCard

Each feed item card

DSAvatar

Author avatar in each card

DSBadge

'New' badge on fresh content

DSTabs

Bottom tab navigation

DSSkeletonCard

Loading state for the feed

DSEmptyState

When feed has no content

Full implementation

HomeFeedScreen.swift
import SwiftUI
import SwiftDS

struct HomeFeedScreen: View {
    @StateObject private var vm = HomeFeedViewModel()
    @State private var selectedTab = "all"

    var body: some View {
        DSPageLayout {
            // Navigation bar
            DSNavigationBar(
                title: "Home",
                trailingItems: [
                    DSNavBarItem(icon: "plus", action: { vm.createPost() }),
                    DSNavBarItem(icon: "magnifyingglass", action: { vm.toggleSearch() }),
                ]
            )

            // Filter tabs
            DSSegmentedControl(
                options: [("All", "all"), ("Following", "following"), ("Trending", "trending")],
                selected: $selectedTab
            )
            .padding(.horizontal, DSSpacing.md)

            // Feed list
            if vm.isLoading {
                VStack(spacing: DSSpacing.md) {
                    ForEach(0..<4, id: \.self) { _ in DSSkeletonCard() }
                }
                .padding(DSSpacing.md)
            } else if vm.posts.isEmpty {
                DSEmptyState(
                    icon: "newspaper",
                    title: "Nothing here yet",
                    message: "Follow creators to see their posts.",
                    actionLabel: "Explore",
                    action: { selectedTab = "trending" }
                )
            } else {
                LazyVStack(spacing: DSSpacing.sm) {
                    ForEach(vm.filteredPosts(tab: selectedTab)) { post in
                        FeedCard(post: post)
                            .onTapGesture { vm.open(post) }
                    }
                }
                .padding(DSSpacing.md)
            }
        }
    }
}

struct FeedCard: View {
    let post: Post

    var body: some View {
        DSCard(variant: .outlined, isInteractive: true) {
            HStack(alignment: .top, spacing: DSSpacing.sm) {
                DSAvatar(
                    initials: post.authorInitials,
                    size: .sm,
                    status: post.isOnline ? .online : nil
                )
                VStack(alignment: .leading, spacing: DSSpacing.xs) {
                    HStack {
                        DSText(post.title, style: .callout)
                            .lineLimit(2)
                        Spacer()
                        if post.isNew {
                            DSBadge("New", variant: .filled)
                        }
                    }
                    HStack(spacing: DSSpacing.xs) {
                        DSText(post.author, style: .caption)
                            .foregroundColor(DSColor.textSecondary)
                        DSText("·", style: .caption)
                            .foregroundColor(DSColor.textSecondary)
                        DSText(post.timeAgo, style: .caption)
                            .foregroundColor(DSColor.textSecondary)
                    }
                }
            }
        }
    }
}