Skip to content

Instantly share code, notes, and snippets.

@badrinathvm
Last active April 16, 2023 23:51
Show Gist options
  • Save badrinathvm/50f595e75bb19aa9d60ce12d28583a82 to your computer and use it in GitHub Desktop.
Save badrinathvm/50f595e75bb19aa9d60ce12d28583a82 to your computer and use it in GitHub Desktop.
Generalized Sidebar
import SwiftUI
enum MenuItem: String, CaseIterable, Identifiable {
case pinned = "Pinned"
case activity = "Activity"
case legal = "Legal"
var id: MenuItem { MenuItem(rawValue: self.rawValue) ?? .pinned }
}
class MenuItemViewModel: ObservableObject {
@Published var isMenuOpened:Bool
@Published var selectedMenuItem: MenuItem
init(isMenuOpened: Bool = false, selectedMenuItem: MenuItem = .pinned) {
self.isMenuOpened = isMenuOpened
self.selectedMenuItem = selectedMenuItem
}
}
struct SideBar<Content,Item>: View where Content: View, Item: Identifiable {
typealias Completion = () -> Void
private var items: [Item]
private let content: (Item.ID, @escaping Completion) -> Content
@EnvironmentObject var menuItemViewModel: MenuItemViewModel
let sidebarWidth = UIScreen.main.bounds.size.width / 1.2
init(items: [Item], content: @escaping (Item.ID, @escaping Completion) -> Content) {
self.content = content
self.items = items
}
var body: some View {
HStack {
VStack {
ForEach(items) { item in
self.content(item.id) {
self.menuItemViewModel.isMenuOpened.toggle()
self.menuItemViewModel.selectedMenuItem = item.id as? MenuItem ?? MenuItem.pinned
}
}
Spacer()
}
.foregroundColor(.primary)
.frame(width: sidebarWidth)
.background(Color.white.edgesIgnoringSafeArea(.all))
.overlay(
Rectangle()
.stroke(Color.primary.opacity(0.2), lineWidth: 1)
.shadow(radius: 2)
.edgesIgnoringSafeArea(.all)
)
.offset(x: menuItemViewModel.isMenuOpened ? 0 : -sidebarWidth)
Spacer()
}
.background(Color.primary.opacity(menuItemViewModel.isMenuOpened ? 0.2 : 0).edgesIgnoringSafeArea(.all))
}
}
struct SideBarView: View {
@StateObject var viewModel = MenuItemViewModel()
let sidebarWidth = UIScreen.main.bounds.size.width / 1.2 // 1
private var menuContent: some View {
switch viewModel.selectedMenuItem {
case .pinned:
return Text("Pinned")
case .activity:
return Text("Activity")
case .legal:
return Text("Legal")
}
}
var body: some View {
ZStack {
GeometryReader { _ in
VStack {
Button {
withAnimation {
viewModel.isMenuOpened.toggle()
}
} label: {
Image(systemName: "line.horizontal.3")
.resizable()
.frame(width: 24, height: 24)
}
.padding()
.foregroundColor(Color.primary)
}
}
menuContent
SideBar(items: MenuItem.allCases) { item, completion in
HStack {
Button {
completion()
} label: {
Text(item.rawValue)
}
Spacer()
}
.padding(.horizontal)
}
.environmentObject(viewModel)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment