feat(ios): unify list cards and loading states
This commit is contained in:
@@ -14,23 +14,22 @@ struct FleetView: View {
|
||||
ScrollView {
|
||||
LazyVStack(spacing: 12) {
|
||||
searchField
|
||||
if let errorMessage = model.errorMessage {
|
||||
AIStatusBanner(errorMessage, tint: AITheme.danger, systemImage: "exclamationmark.triangle")
|
||||
}
|
||||
if model.selectionMode {
|
||||
selectionBar
|
||||
}
|
||||
if model.isLoading && model.rows.isEmpty {
|
||||
AILoadingCard("正在同步实例")
|
||||
}
|
||||
if model.rows.isEmpty && !model.isLoading {
|
||||
AICard {
|
||||
VStack(spacing: 10) {
|
||||
Image(systemName: "server.rack")
|
||||
.font(.system(size: 28))
|
||||
.foregroundStyle(AITheme.muted)
|
||||
Text("暂无实例")
|
||||
.font(.headline)
|
||||
Text("添加 SimAdmin 实例后即可开始管理。")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 18)
|
||||
AIEmptyState(
|
||||
systemImage: "server.rack",
|
||||
title: "暂无实例",
|
||||
message: "添加 SimAdmin 实例后即可开始管理。"
|
||||
)
|
||||
}
|
||||
}
|
||||
ForEach(model.rows) { row in
|
||||
@@ -50,22 +49,23 @@ struct FleetView: View {
|
||||
}
|
||||
}
|
||||
.navigationTitle("节点总览")
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .primaryAction) {
|
||||
Button {
|
||||
model.selectionMode.toggle()
|
||||
model.selectedIDs.removeAll()
|
||||
} label: {
|
||||
Label(model.selectionMode ? "完成" : "批量选择", systemImage: model.selectionMode ? "xmark" : "checklist")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .secondary, size: .regular))
|
||||
.aiBottomActionBar {
|
||||
if !model.selectionMode {
|
||||
HStack(spacing: 10) {
|
||||
Button {
|
||||
model.selectionMode = true
|
||||
} label: {
|
||||
Label("批量选择", systemImage: "checklist")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .secondary, size: .regular, fillsWidth: true))
|
||||
|
||||
Button {
|
||||
model.showingForm = true
|
||||
} label: {
|
||||
Label("添加实例", systemImage: "plus")
|
||||
Button {
|
||||
model.showingForm = true
|
||||
} label: {
|
||||
Label("添加实例", systemImage: "plus")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true))
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular))
|
||||
}
|
||||
}
|
||||
.confirmationDialog(
|
||||
@@ -110,7 +110,13 @@ struct FleetView: View {
|
||||
systemImage: "checkmark.circle"
|
||||
)
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .secondary, size: .compact))
|
||||
.buttonStyle(
|
||||
AIButtonStyle(
|
||||
kind: .secondary,
|
||||
size: .compact,
|
||||
fixedWidth: AITheme.footerSecondaryButtonWidth
|
||||
)
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -123,7 +129,13 @@ struct FleetView: View {
|
||||
} label: {
|
||||
Label("删除", systemImage: "trash")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .danger, size: .compact))
|
||||
.buttonStyle(
|
||||
AIButtonStyle(
|
||||
kind: .danger,
|
||||
size: .compact,
|
||||
fixedWidth: AITheme.footerSecondaryButtonWidth
|
||||
)
|
||||
)
|
||||
.disabled(model.selectedIDs.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -143,6 +155,8 @@ struct FleetView: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.frame(width: 32, height: 32)
|
||||
.accessibilityLabel(model.selectedIDs.contains(row.id) ? "取消选择" : "选择")
|
||||
.accessibilityAddTraits(model.selectedIDs.contains(row.id) ? .isSelected : [])
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack(spacing: 8) {
|
||||
@@ -155,6 +169,8 @@ struct FleetView: View {
|
||||
Text(row.instance.origin.absoluteString)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
if !row.instance.tags.isEmpty {
|
||||
HStack(spacing: 6) {
|
||||
ForEach(row.instance.tags, id: \.self) { tag in
|
||||
|
||||
Reference in New Issue
Block a user