Files
yattee/Yattee/Views/Player/Panels/PanelPageBar.swift
Arkadiusz Fal bfbb729a8c Align side column page content and tabs with the grabber inset
The corner layout side column puts a 12pt resize grabber strip before the
panel, and every page then added the standard 16pt horizontal padding, so
content sat ~28pt from the left edge but 16pt from the right.

Add a PanelHorizontalInsets environment value with a panelHorizontalPadding()
modifier that the info, comments, related and chapters pages use instead of
.padding(.horizontal). The side column trims the leading inset by the grabber
width so content is 16pt from the column's outer edge on both sides; other
hosts keep the defaults. Queue and tracks are List-backed and get the same
leading delta as a scroll content margin. The page bar follows the same insets
so the first pill lines up with the content.
2026-09-24 22:01:01 +02:00

81 lines
2.5 KiB
Swift

//
// PanelPageBar.swift
// Yattee
//
// Scrolling pill row for switching details panel pages.
//
import SwiftUI
#if os(iOS) || os(macOS)
struct PanelPageBar: View {
let pages: [PanelPageConfiguration]
@Binding var selectedPage: PanelPageType
let accentColor: Color
var showLabels: Bool = true
@Environment(\.panelHorizontalInsets) private var insets
/// Pills sit 4pt closer to the edge than page content (12 vs 16 with the
/// standard inset); a host that trims the content inset (corner side
/// column) trims the bar the same way so the first pill lines up.
private static let pillEdgeOffset: CGFloat = 4
var body: some View {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 8) {
ForEach(pages) { page in
pageButton(page.pageType)
.id(page.pageType)
}
}
.padding(.leading, max(0, insets.leading - Self.pillEdgeOffset))
.padding(.trailing, max(0, insets.trailing - Self.pillEdgeOffset))
.padding(.vertical, 6)
}
.onChange(of: selectedPage) { _, newValue in
withAnimation(.easeInOut(duration: 0.2)) {
proxy.scrollTo(newValue, anchor: .center)
}
}
}
}
@ViewBuilder
private func pageButton(_ pageType: PanelPageType) -> some View {
let isSelected = pageType == selectedPage
Button {
withAnimation(.easeInOut(duration: 0.2)) {
selectedPage = pageType
}
} label: {
HStack(spacing: 5) {
Image(systemName: pageType.systemImage)
.font(.system(size: 13, weight: .medium))
if showLabels || isSelected {
Text(pageType.displayName)
.font(.subheadline)
.fontWeight(.medium)
.lineLimit(1)
.fixedSize()
}
}
.foregroundStyle(isSelected ? Color.white : Color.primary)
.padding(.horizontal, 12)
.padding(.vertical, 7)
.background {
Capsule()
.fill(isSelected ? AnyShapeStyle(accentColor) : AnyShapeStyle(.quaternary.opacity(0.6)))
}
.contentShape(Capsule())
}
.buttonStyle(.plain)
}
}
#endif