iPhone Duo (fase 1): navegación adaptativa por size class y layouts regular×regular

- ContentView: un único TabView (sidebarAdaptable en iOS 18+) para todas las
  size classes; desaparece el cambio de jerarquía iPhone/iPad, así abrir o
  cerrar el Duo conserva el estado de cada pestaña. @SceneStorage de la tab.
- Fuentes y Diario: NavigationSplitView (lista + detalle a la vez en ancho
  regular, stack colapsable en compacto) con selección nativa de List.
- Dashboard: Quick Update como .inspector (panel lateral junto a los gráficos
  en regular, sheet en compacto).
- Gráficos: chartHeightScale (+35% de alto en regular) vía chartFrame(height:),
  sin ignoresSafeArea en contenido interactivo.
- Liquid Glass (glassEffect) en las etiquetas flotantes del Diario en iOS 26+.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F1u4K16xy7eQVtgsYNZ9Vn
This commit is contained in:
alexandrev-tibco
2026-09-16 11:44:50 +02:00
parent a8a9ad64f3
commit 680255f69d
17 changed files with 485 additions and 547 deletions
@@ -22,7 +22,7 @@ struct PerformanceBarChart: View {
Text("Compound Annual Growth Rate (CAGR)")
.font(.caption)
.foregroundColor(.secondary)
.foregroundStyle(.secondary)
if !data.isEmpty {
ChartStatsRow(stats: perfStats)
@@ -44,14 +44,14 @@ struct PerformanceBarChart: View {
.padding(.top, 8)
} else {
Text("No performance data available")
.foregroundColor(.secondary)
.frame(height: 250)
.foregroundStyle(.secondary)
.chartFrame(height: 250)
.frame(maxWidth: .infinity)
}
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(AppConstants.UI.cornerRadius)
.clipShape(RoundedRectangle(cornerRadius: AppConstants.UI.cornerRadius))
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
}
@@ -62,11 +62,11 @@ struct PerformanceBarChart: View {
y: .value("CAGR", item.cagr)
)
.foregroundStyle(Color(hex: item.color) ?? .gray)
.cornerRadius(4)
.clipShape(RoundedRectangle(cornerRadius: 4))
.annotation(position: item.cagr >= 0 ? .top : .bottom) {
Text(String(format: "%.1f%%", item.cagr))
.font(.caption2)
.foregroundColor(item.cagr >= 0 ? .positiveGreen : .negativeRed)
.foregroundStyle(item.cagr >= 0 ? Color.positiveGreen : Color.negativeRed)
}
}
.chartXAxis {
@@ -91,7 +91,7 @@ struct PerformanceBarChart: View {
}
}
}
.frame(height: 250)
.chartFrame(height: 250)
}
private var horizontalChart: some View {
@@ -101,11 +101,11 @@ struct PerformanceBarChart: View {
y: .value("Category", item.category)
)
.foregroundStyle(Color(hex: item.color) ?? .gray)
.cornerRadius(4)
.clipShape(RoundedRectangle(cornerRadius: 4))
.annotation(position: item.cagr >= 0 ? .trailing : .leading) {
Text(String(format: "%.1f%%", item.cagr))
.font(.caption2)
.foregroundColor(item.cagr >= 0 ? .positiveGreen : .negativeRed)
.foregroundStyle(item.cagr >= 0 ? Color.positiveGreen : Color.negativeRed)
}
}
.chartXAxis {
@@ -147,12 +147,12 @@ struct PerformanceBarChart: View {
Text(String(format: "%.2f%%", item.cagr))
.font(.subheadline.weight(.semibold))
.foregroundColor(item.cagr >= 0 ? .positiveGreen : .negativeRed)
.foregroundStyle(item.cagr >= 0 ? Color.positiveGreen : Color.negativeRed)
if onDrillDown != nil {
Image(systemName: "chevron.right")
.font(.caption2.weight(.semibold))
.foregroundColor(.secondary)
.foregroundStyle(.secondary)
}
}
if let onDrillDown {
@@ -213,7 +213,7 @@ struct HorizontalPerformanceChart: View {
Text(String(format: "%.2f%%", item.cagr))
.font(.subheadline.weight(.semibold))
.foregroundColor(item.cagr >= 0 ? .positiveGreen : .negativeRed)
.foregroundStyle(item.cagr >= 0 ? Color.positiveGreen : Color.negativeRed)
}
GeometryReader { geometry in
@@ -224,12 +224,12 @@ struct HorizontalPerformanceChart: View {
Rectangle()
.fill(Color.gray.opacity(0.1))
.frame(height: 8)
.cornerRadius(4)
.clipShape(RoundedRectangle(cornerRadius: 4))
Rectangle()
.fill(item.cagr >= 0 ? Color.positiveGreen : Color.negativeRed)
.frame(width: barWidth, height: 8)
.cornerRadius(4)
.clipShape(RoundedRectangle(cornerRadius: 4))
}
}
.frame(height: 8)
@@ -238,7 +238,7 @@ struct HorizontalPerformanceChart: View {
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(AppConstants.UI.cornerRadius)
.clipShape(RoundedRectangle(cornerRadius: AppConstants.UI.cornerRadius))
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
}
}