93 lines
2.3 KiB
Swift
93 lines
2.3 KiB
Swift
//
|
|
// Swiftfin is subject to the terms of the Mozilla Public
|
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
//
|
|
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct BulletedList<Content: View>: View {
|
|
|
|
private var content: () -> Content
|
|
private var bullet: (Int) -> any View
|
|
|
|
var body: some View {
|
|
_VariadicView.Tree(BulletedListLayout(bullet: bullet)) {
|
|
content()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension BulletedList {
|
|
|
|
init(@ViewBuilder _ content: @escaping () -> Content) {
|
|
self.init(
|
|
content: content,
|
|
bullet: { _ in
|
|
ZStack {
|
|
Text(" ")
|
|
|
|
Circle()
|
|
.frame(width: 8)
|
|
.padding(.trailing, 5)
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
func bullet(@ViewBuilder _ content: @escaping (Int) -> any View) -> Self {
|
|
copy(modifying: \.bullet, with: content)
|
|
}
|
|
}
|
|
|
|
extension BulletedList {
|
|
|
|
struct BulletedListLayout: _VariadicView_UnaryViewRoot {
|
|
|
|
var bullet: (Int) -> any View
|
|
|
|
@ViewBuilder
|
|
func body(children: _VariadicView.Children) -> some View {
|
|
VStack(alignment: .leading, spacing: 0) {
|
|
ForEach(Array(zip(children.indices, children)), id: \.0) { child in
|
|
BulletedListItem(
|
|
bullet: AnyView(bullet(child.0)),
|
|
child: child.1
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct BulletedListItem<BulletContent: View, Bullet: View>: View {
|
|
|
|
@State
|
|
private var bulletSize: CGSize = .zero
|
|
@State
|
|
private var childSize: CGSize = .zero
|
|
|
|
let bullet: Bullet
|
|
let child: BulletContent
|
|
|
|
private var _bullet: some View {
|
|
bullet
|
|
.trackingSize($bulletSize)
|
|
}
|
|
|
|
// TODO: this can cause clipping issues with text since
|
|
// with .offset, find fix
|
|
var body: some View {
|
|
ZStack {
|
|
child
|
|
.trackingSize($childSize)
|
|
.overlay(alignment: .topLeading) {
|
|
_bullet
|
|
.offset(x: -bulletSize.width)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|