iOS drawer: declutter controls, bigger header, more top spacing
- remove the show-all / hide-all buttons (rarely needed with a few calendars; the web has none). The calendar section now shows a 'Calendars' header + a slim Sort toggle. - larger header (avatar, name, action icons) with more padding - more vertical breathing room between header / view switcher / groups / list Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -34,40 +34,40 @@ struct CalendarDrawer: View {
|
|||||||
// MARK: – Header
|
// MARK: – Header
|
||||||
|
|
||||||
private var header: some View {
|
private var header: some View {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 14) {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(Color.accentColor)
|
.fill(Color.accentColor)
|
||||||
.frame(width: 40, height: 40)
|
.frame(width: 48, height: 48)
|
||||||
.overlay {
|
.overlay {
|
||||||
Text(appState.username.prefix(1).uppercased())
|
Text(appState.username.prefix(1).uppercased())
|
||||||
.font(.headline).foregroundStyle(.white)
|
.font(.title3.bold()).foregroundStyle(.white)
|
||||||
}
|
}
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
Text(appState.username).font(.headline).lineLimit(1)
|
Text(appState.username).font(.title3.weight(.semibold)).lineLimit(1)
|
||||||
Text(appState.serverURL
|
Text(appState.serverURL
|
||||||
.replacingOccurrences(of: "https://", with: "")
|
.replacingOccurrences(of: "https://", with: "")
|
||||||
.replacingOccurrences(of: "http://", with: ""))
|
.replacingOccurrences(of: "http://", with: ""))
|
||||||
.font(.caption).foregroundStyle(.secondary).lineLimit(1)
|
.font(.footnote).foregroundStyle(.secondary).lineLimit(1)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
HStack(spacing: 18) {
|
HStack(spacing: 20) {
|
||||||
Button { onSync() } label: {
|
Button { onSync() } label: {
|
||||||
Image(systemName: "arrow.triangle.2.circlepath").font(.system(size: 16, weight: .medium))
|
Image(systemName: "arrow.triangle.2.circlepath").font(.system(size: 19, weight: .medium))
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain).foregroundStyle(Color.accentColor)
|
.buttonStyle(.plain).foregroundStyle(Color.accentColor)
|
||||||
.accessibilityLabel(L10n.t("menu.sync", appLang))
|
.accessibilityLabel(L10n.t("menu.sync", appLang))
|
||||||
Button { onOpenMenu() } label: {
|
Button { onOpenMenu() } label: {
|
||||||
Image(systemName: "gearshape").font(.system(size: 16, weight: .medium))
|
Image(systemName: "gearshape").font(.system(size: 19, weight: .medium))
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain).foregroundStyle(Color.accentColor)
|
.buttonStyle(.plain).foregroundStyle(Color.accentColor)
|
||||||
.accessibilityLabel(L10n.t("menu.section.settings", appLang))
|
.accessibilityLabel(L10n.t("menu.section.settings", appLang))
|
||||||
Button { onClose() } label: {
|
Button { onClose() } label: {
|
||||||
Image(systemName: "xmark").font(.system(size: 15, weight: .semibold))
|
Image(systemName: "xmark").font(.system(size: 17, weight: .semibold))
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain).foregroundStyle(.secondary)
|
.buttonStyle(.plain).foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 16).padding(.top, 12).padding(.bottom, 10)
|
.padding(.horizontal, 18).padding(.top, 20).padding(.bottom, 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: – View switcher
|
// MARK: – View switcher
|
||||||
@@ -88,7 +88,7 @@ struct CalendarDrawer: View {
|
|||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 16).padding(.vertical, 8)
|
.padding(.horizontal, 16).padding(.vertical, 13)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ struct CalendarDrawer: View {
|
|||||||
selected: store.activeGroup?.id == g.id) { onSwitchGroup(g) }
|
selected: store.activeGroup?.id == g.id) { onSwitchGroup(g) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 16).padding(.vertical, 8)
|
.padding(.horizontal, 16).padding(.vertical, 13)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,24 +61,22 @@ struct CalendarFilterContent: View {
|
|||||||
.task { await load() }
|
.task { await load() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Above the list so it stays tappable even while the list is in edit mode.
|
// Section header + sort toggle, above the list so it stays tappable while
|
||||||
|
// the list is in edit mode. (No show/hide-all buttons — rarely needed with a
|
||||||
|
// handful of calendars, and the web has none either.)
|
||||||
private var controlBar: some View {
|
private var controlBar: some View {
|
||||||
HStack(spacing: 8) {
|
HStack {
|
||||||
Button(L10n.t("filter.show_all", appLang)) {
|
Text(L10n.t("filter.title", appLang))
|
||||||
hidden = []; store.setHiddenCalendars(hidden)
|
.font(.subheadline.weight(.semibold))
|
||||||
}
|
.foregroundStyle(.secondary)
|
||||||
.buttonStyle(.bordered)
|
|
||||||
Button(L10n.t("filter.hide_all", appLang)) {
|
|
||||||
hidden = allKeys; store.setHiddenCalendars(hidden)
|
|
||||||
}
|
|
||||||
.buttonStyle(.bordered)
|
|
||||||
Spacer()
|
Spacer()
|
||||||
Button(isSorting ? L10n.t("filter.done", appLang) : L10n.t("filter.sort", appLang)) {
|
Button(isSorting ? L10n.t("filter.done", appLang) : L10n.t("filter.sort", appLang)) {
|
||||||
withAnimation { isSorting.toggle() }
|
withAnimation { isSorting.toggle() }
|
||||||
}
|
}
|
||||||
.buttonStyle(.bordered)
|
.buttonStyle(.borderless)
|
||||||
|
.font(.subheadline)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 16).padding(.vertical, 8)
|
.padding(.horizontal, 16).padding(.top, 6).padding(.bottom, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func move(from source: IndexSet, to destination: Int) {
|
private func move(from source: IndexSet, to destination: Int) {
|
||||||
|
|||||||
Reference in New Issue
Block a user