Adopt root-level tsswift app layout
CI / test (push) Has been cancelled

Move the app payload under swift/ while keeping git, package.json, and .smartconfig.json at the repo root. This standardizes the Swift app setup so build, test, run, and watch workflows match the other repos.
This commit is contained in:
2026-04-19 01:21:43 +02:00
parent d534964601
commit a6939453f8
61 changed files with 2341 additions and 3 deletions
+233
View File
@@ -0,0 +1,233 @@
import SwiftUI
struct AppSectionTitle: View {
let title: String
var subtitle: String? = nil
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.title3.weight(.semibold))
if let subtitle, !subtitle.isEmpty {
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
}
}
struct AppNotice: View {
let message: String
var tone: Color = AppTheme.accent
var body: some View {
HStack(spacing: 10) {
Image(systemName: "checkmark.circle.fill")
.font(.footnote.weight(.bold))
.foregroundStyle(tone)
Text(message)
.font(.subheadline.weight(.semibold))
}
.padding(.horizontal, 16)
.padding(.vertical, 12)
.background(tone.opacity(0.08), in: Capsule())
.overlay(
Capsule()
.stroke(AppTheme.border, lineWidth: 1)
)
}
}
struct AppStatusTag: View {
let title: String
var tone: Color = AppTheme.accent
var body: some View {
Text(title)
.font(.caption.weight(.semibold))
.lineLimit(1)
.minimumScaleFactor(0.8)
.fixedSize(horizontal: true, vertical: false)
.padding(.horizontal, 10)
.padding(.vertical, 6)
.background(tone.opacity(0.12), in: Capsule())
.foregroundStyle(tone)
}
}
struct AppKeyValue: View {
let label: String
let value: String
var monospaced: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(label.uppercased())
.font(.caption2.weight(.bold))
.foregroundStyle(.secondary)
Text(value)
.font(monospaced ? .subheadline.monospaced() : .subheadline.weight(.semibold))
.lineLimit(2)
.minimumScaleFactor(0.8)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct AppMetric: View {
let title: String
let value: String
var body: some View {
VStack(alignment: .leading, spacing: 6) {
Text(title.uppercased())
.font(.caption.weight(.bold))
.foregroundStyle(.secondary)
Text(value)
.font(.title3.weight(.bold))
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct AppTextSurface: View {
let text: String
var monospaced: Bool = false
var body: some View {
content
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
.background(AppTheme.mutedFill, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
.overlay(
RoundedRectangle(cornerRadius: 20, style: .continuous)
.stroke(AppTheme.border, lineWidth: 1)
)
}
@ViewBuilder
private var content: some View {
#if os(watchOS)
Text(text)
.font(monospaced ? .body.monospaced() : .body)
#else
Text(text)
.font(monospaced ? .body.monospaced() : .body)
.textSelection(.enabled)
#endif
}
}
struct AppTextEditorField: View {
@Binding var text: String
var minHeight: CGFloat = 120
var monospaced: Bool = true
var body: some View {
editor
.frame(minHeight: minHeight)
.background(AppTheme.mutedFill, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
.overlay(
RoundedRectangle(cornerRadius: 20, style: .continuous)
.stroke(AppTheme.border, lineWidth: 1)
)
}
@ViewBuilder
private var editor: some View {
#if os(watchOS)
Text(text)
.font(monospaced ? .body.monospaced() : .body)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(14)
#else
TextEditor(text: $text)
.font(monospaced ? .body.monospaced() : .body)
.scrollContentBackground(.hidden)
.autocorrectionDisabled()
.padding(14)
#endif
}
}
struct AppActionRow: View {
let title: String
var subtitle: String? = nil
let systemImage: String
var tone: Color = AppTheme.accent
var body: some View {
HStack(alignment: .top, spacing: 12) {
Image(systemName: systemImage)
.font(.subheadline.weight(.semibold))
.foregroundStyle(tone)
.frame(width: 28, height: 28)
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.headline)
if let subtitle, !subtitle.isEmpty {
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
.multilineTextAlignment(.leading)
}
}
Spacer(minLength: 0)
Image(systemName: "arrow.right")
.font(.footnote.weight(.bold))
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct AppActionTile: View {
let title: String
let systemImage: String
var tone: Color = AppTheme.accent
var isBusy: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 14) {
HStack(alignment: .center) {
ZStack {
Circle()
.fill(tone.opacity(0.10))
.frame(width: 38, height: 38)
if isBusy {
ProgressView()
.tint(tone)
} else {
Image(systemName: systemImage)
.font(.headline.weight(.semibold))
.foregroundStyle(tone)
}
}
Spacer(minLength: 0)
Image(systemName: "arrow.up.right")
.font(.caption.weight(.bold))
.foregroundStyle(.secondary)
}
Text(title)
.font(.headline)
.multilineTextAlignment(.leading)
.lineLimit(2)
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(16)
.frame(maxWidth: .infinity, minHeight: 92, alignment: .topLeading)
.appSurface(radius: 22)
}
}