Files
onyx/Packages/OnyxKit/Sources/OnyxWidgetKit/WidgetGrid.swift
T
ScarriffleandClaude Opus 5 edb327cabe Kacheln und Fenster sprechen dieselbe Sprache
Alle Kacheln, Popovers und Fenster auf die Designschicht umgestellt: rund
hundert gesetzte Schriftgrößen und 159 gesetzte Abstände und Radien sind jetzt
Token. Übrig bleibt `spacing: 0` — das ist eine Aussage, keine geratene Zahl.

Die Einstellungen bekommen eine Seitenleiste statt sieben Reitern, deren
deutsche Beschriftungen zusammen 880 Punkte brauchten. Panel-Token stehen nicht
mehr in Fenstern: dort gilt Systemsemantik, damit der Hellmodus nicht schwarz
auf schwarz endet.

Neu ist ein Schaufenster, das alle Bauteile nebeneinander zeigt — ohne das
lässt sich eine Änderung an einem Token nur prüfen, indem man die App bedient,
bis jede Kachel einmal zu sehen war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:05:51 +02:00

62 lines
2.4 KiB
Swift

import SwiftUI
import OnyxDesign
/// Zeichnet ein aufgelöstes Layout.
///
/// Die Positionen kommen aus `LayoutEngine`, nicht aus einem SwiftUI-Grid. Ein
/// `LazyVGrid` kann keine Kacheln über zwei Zeilen führen, und genau das braucht
/// der Mini-Monat.
public struct WidgetGrid: View {
private let resolved: [ResolvedPlacement]
private let panelSize: CGSize
public init(placements: [WidgetPlacement], availableWidth: CGFloat) {
self.resolved = LayoutEngine.resolve(placements, availableWidth: availableWidth)
self.panelSize = LayoutEngine.panelSize(for: placements, availableWidth: availableWidth)
}
public var body: some View {
ZStack(alignment: .topLeading) {
ForEach(resolved) { item in
let frame = LayoutEngine.frame(for: item)
widgetView(for: item)
.frame(width: frame.width, height: frame.height)
// Beschneiden ist Pflicht, kein Feinschliff: quillt der
// Inhalt über, zeichnet er über die Nachbarkachel — und
// ganz oben über die Notch.
.clipped()
.offset(x: frame.minX, y: frame.minY)
}
}
.frame(width: panelSize.width, height: panelSize.height, alignment: .topLeading)
}
@ViewBuilder
private func widgetView(for item: ResolvedPlacement) -> some View {
if let widget = WidgetRegistry.shared.widget(id: item.placement.widgetID) {
OnyxTile { widget.makeView() }
} else {
// Sollte nach dem Filtern in LayoutStore nicht vorkommen. Falls doch,
// ist eine sichtbare Lücke mit Namen besser als ein stiller Ausfall.
OnyxTile {
VStack(spacing: Onyx.Space.xs) {
Image(systemName: "questionmark.square.dashed")
Text(item.placement.widgetID)
.font(Onyx.Font.caption)
}
.foregroundStyle(Onyx.Color.textTertiary)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
/// Die Größe, die das Panel für dieses Layout braucht — der Controller
/// stellt das Fenster darauf ein.
public static func panelSize(for placements: [WidgetPlacement],
availableWidth: CGFloat) -> CGSize {
LayoutEngine.panelSize(for: placements, availableWidth: availableWidth)
}
}