import SwiftUI import AppKit /// Die Vibrancy-Ebene hinter dem Panel. /// /// `.hudWindow` mit `behindWindow` lässt den Hintergrund durchscheinen, ohne ihn /// lesbar zu lassen. Der Tint darüber macht daraus schwarzen Stein statt grauem Glas. public struct OnyxVisualEffect: NSViewRepresentable { public init() {} public func makeNSView(context: Context) -> NSVisualEffectView { let view = NSVisualEffectView() view.material = .hudWindow view.blendingMode = .behindWindow view.state = .active view.appearance = NSAppearance(named: .darkAqua) return view } public func updateNSView(_ view: NSVisualEffectView, context: Context) {} } /// Der Hintergrund des Panels: Vibrancy, Tint, ein sehr flacher Glanz von oben /// und eine Haarlinie als Innenkante. public struct OnyxSurface: View { private let cornerRadius: CGFloat public init(cornerRadius: CGFloat = Onyx.Metric.panelCornerRadius) { self.cornerRadius = cornerRadius } public var body: some View { let shape = RoundedRectangle(cornerRadius: cornerRadius, style: .continuous) shape .fill(Onyx.Color.surface.opacity(Onyx.Color.surfaceOpacity)) .background(OnyxVisualEffect().clipShape(shape)) .overlay { // Die Bänderung des Steins: oben ein Hauch heller, nach 40 % // vollständig verlaufen. Mehr wirkt sofort billig. shape.fill( LinearGradient( stops: [ .init(color: .white.opacity(0.02), location: 0), .init(color: .clear, location: 0.4), ], startPoint: .top, endPoint: .bottom)) } .overlay { shape.strokeBorder(Onyx.Color.hairline, lineWidth: Onyx.Metric.hairlineWidth) } } } /// Eine Kachel auf der Panelfläche. public struct OnyxTile: View { private let content: Content public init(@ViewBuilder content: () -> Content) { self.content = content() } public var body: some View { let shape = RoundedRectangle(cornerRadius: Onyx.Metric.tileCornerRadius, style: .continuous) content .padding(12) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) .background(shape.fill(Onyx.Color.elevated)) .overlay(shape.strokeBorder(Onyx.Color.hairline, lineWidth: Onyx.Metric.hairlineWidth)) } }