168 lines
5.5 KiB
Swift

import SwiftUI
// MARK: - VBox Control
struct VBoxControl: View {
let schema: ControlSchema
@ObservedObject var engine: BricksEngine
var body: some View {
VStack(alignment: .leading, spacing: spacing) {
if let subwidgets = schema.subwidgets {
SubWidgetsView(subwidgets: subwidgets, engine: engine)
}
}
.padding(padding)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(backgroundColor)
.cornerRadius(cornerRadius)
.overlay(
RoundedRectangle(cornerRadius: cornerRadius)
.stroke(borderColor, lineWidth: borderWidth)
)
.contentShape(Rectangle())
.onTapGesture {
Task {
await engine.triggerEvent(widgetId: schema.effectiveId, event: "click")
}
}
}
private var spacing: CGFloat { CGFloat(schema.options.spacing ?? 8) }
private var padding: CGFloat { parsePadding(schema.options.padding) }
private var cornerRadius: CGFloat {
(schema.options.css?.contains("card") ?? false) ? 8 : 0
}
private var borderWidth: CGFloat {
(schema.options.css?.contains("card") ?? false) ? 1 : 0
}
private var borderColor: Color {
(schema.options.css?.contains("card") ?? false) ? Color.secondary.opacity(0.2) : .clear
}
private var backgroundColor: Color {
if let bg = schema.options.bgcolor {
return Color.fromCSS(bg)
}
if schema.options.css?.contains("card") ?? false {
return Color.secondary.opacity(0.05)
}
return .clear
}
private func parsePadding(_ padding: String?) -> CGFloat {
guard let p = padding else { return 0 }
if let val = Double(p.replacingOccurrences(of: "px", with: "")) {
return CGFloat(val)
}
return 8
}
}
// MARK: - HBox Control
struct HBoxControl: View {
let schema: ControlSchema
@ObservedObject var engine: BricksEngine
var body: some View {
HStack(alignment: verticalAlignment, spacing: spacing) {
if let subwidgets = schema.subwidgets {
SubWidgetsView(subwidgets: subwidgets, engine: engine)
}
}
.padding(padding)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(backgroundColor)
.cornerRadius(8)
}
private var spacing: CGFloat { CGFloat(schema.options.spacing ?? 8) }
private var padding: CGFloat { parsePadding(schema.options.padding) }
private var verticalAlignment: VerticalAlignment {
switch schema.options.alignItems {
case "center": return .center
case "flex-end", "end": return .bottom
default: return .top
}
}
private var backgroundColor: Color {
if let bg = schema.options.bgcolor { return Color.fromCSS(bg) }
return .clear
}
private func parsePadding(_ padding: String?) -> CGFloat {
guard let p = padding else { return 0 }
if let val = Double(p.replacingOccurrences(of: "px", with: "")) { return CGFloat(val) }
return 8
}
}
// MARK: - ScrollPanel Control
struct ScrollPanelControl: View {
let schema: ControlSchema
@ObservedObject var engine: BricksEngine
var body: some View {
if schema.widgettype == "HScrollPanel" {
ScrollView(.horizontal, showsIndicators: true) {
HStack(alignment: .top, spacing: spacing) {
if let subwidgets = schema.subwidgets {
SubWidgetsView(subwidgets: subwidgets, engine: engine)
}
}
.padding(padding)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
ScrollView(.vertical, showsIndicators: true) {
VStack(alignment: .leading, spacing: spacing) {
if let subwidgets = schema.subwidgets {
SubWidgetsView(subwidgets: subwidgets, engine: engine)
}
}
.padding(padding)
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
private var spacing: CGFloat { CGFloat(schema.options.spacing ?? 8) }
private var padding: CGFloat {
if let p = schema.options.padding, let val = Double(p.replacingOccurrences(of: "px", with: "")) {
return CGFloat(val)
}
return 8
}
}
// MARK: - DynamicColumn Control
struct DynamicColumnControl: View {
let schema: ControlSchema
@ObservedObject var engine: BricksEngine
private let columns = [GridItem(.adaptive(minimum: 200), spacing: 12)]
var body: some View {
ScrollView {
LazyVGrid(columns: resolvedColumns, spacing: gap) {
if let subwidgets = schema.subwidgets {
ForEach(Array(subwidgets.enumerated()), id: \.offset) { _, sub in
ControlRenderer(schema: sub, engine: engine)
.frame(maxWidth: .infinity)
}
}
}
.padding(8)
}
}
private var gap: CGFloat { CGFloat(schema.options.col_cgap ?? 1) * 12 }
private var resolvedColumns: [GridItem] {
let minWidth = CGFloat(schema.options.col_cwidth ?? 20) * 8
return [GridItem(.adaptive(minimum: minWidth), spacing: gap)]
}
}