mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 10:36:35 +00:00
M8: list density tokens (scarfGoCompactListRow + scarfGoListDensity)
Apple's default List styling targets Reading/Notes-style apps: ~60pt rows, 10pt inter-row spacing, big vertical padding on grouped cells. ScarfGo's lists (Memory, Cron, Skills, More, Dashboard recent sessions) lean information-dense — devs want to see 4-6 items per screen, not 2. Two tokens in Scarf iOS/App/Theme/ListDensity.swift: - `.scarfGoCompactListRow()` — 6pt vertical listRowInsets (down from default ~12pt), explicit `.frame(minHeight: 44)` to preserve the Apple HIG tap target, and `.contentShape(Rectangle())` so rows can shrink below 44pt visually while keeping the full-row hit area. ~48pt rows end up net, vs. ~60pt default. - `.scarfGoListDensity()` — `.listRowSpacing(0)` kills inter-row gaps on the whole List, `.defaultMinListRowHeight(36)` sets the floor for rows that want to go smaller (e.g. `LabeledContent`). Applied to Memory, Cron, Skills, Dashboard, MoreTab. No visual change to Chat (it's not a List — different density patterns for M8 items 2.4–2.7). Research-backed: Fantastical / GitHub Mobile / Mona for Mastodon use similar spacing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -111,16 +111,19 @@ private struct MoreTab: View {
|
|||||||
} label: {
|
} label: {
|
||||||
Label("Cron jobs", systemImage: "clock.arrow.circlepath")
|
Label("Cron jobs", systemImage: "clock.arrow.circlepath")
|
||||||
}
|
}
|
||||||
|
.scarfGoCompactListRow()
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
SkillsListView(config: config)
|
SkillsListView(config: config)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Skills", systemImage: "sparkles")
|
Label("Skills", systemImage: "sparkles")
|
||||||
}
|
}
|
||||||
|
.scarfGoCompactListRow()
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
SettingsView(config: config)
|
SettingsView(config: config)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Settings", systemImage: "gearshape.fill")
|
Label("Settings", systemImage: "gearshape.fill")
|
||||||
}
|
}
|
||||||
|
.scarfGoCompactListRow()
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
@@ -143,6 +146,7 @@ private struct MoreTab: View {
|
|||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scarfGoListDensity()
|
||||||
.navigationTitle("More")
|
.navigationTitle("More")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.confirmationDialog(
|
.confirmationDialog(
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// ScarfGo's density tokens. Developer-tool context benefits from
|
||||||
|
/// tighter list rows than Apple's ~60pt default — we aim for ~48pt
|
||||||
|
/// rows that still meet the 44pt tap-target invariant. Research-
|
||||||
|
/// backed (M8 density pass): Fantastical, GitHub Mobile, Mona for
|
||||||
|
/// Mastodon use similar spacing.
|
||||||
|
public extension View {
|
||||||
|
/// Apply to individual `List` rows to shrink vertical padding
|
||||||
|
/// while keeping the full row hit-target ≥ 44pt. Use this on
|
||||||
|
/// every ScarfGo list that renders more than 3 rows per screen
|
||||||
|
/// (Memory, Cron, Skills, Settings, Dashboard recent sessions,
|
||||||
|
/// More).
|
||||||
|
///
|
||||||
|
/// Pair with `scarfGoListDensity()` on the containing List to
|
||||||
|
/// tighten inter-section spacing.
|
||||||
|
func scarfGoCompactListRow() -> some View {
|
||||||
|
self
|
||||||
|
.listRowInsets(EdgeInsets(top: 6, leading: 16, bottom: 6, trailing: 16))
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.frame(minHeight: 44)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply to a `List` to reduce the default minimum row height +
|
||||||
|
/// kill the inter-row spacing iOS 18 injects between rows. Works
|
||||||
|
/// with `.plain` and `.insetGrouped` list styles. Does not affect
|
||||||
|
/// section-header spacing.
|
||||||
|
func scarfGoListDensity() -> some View {
|
||||||
|
self
|
||||||
|
.environment(\.defaultMinListRowHeight, 36)
|
||||||
|
.listRowSpacing(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ struct CronListView: View {
|
|||||||
} onTap: {
|
} onTap: {
|
||||||
editingJob = job
|
editingJob = job
|
||||||
}
|
}
|
||||||
|
.scarfGoCompactListRow()
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
Task { await vm.delete(id: job.id) }
|
Task { await vm.delete(id: job.id) }
|
||||||
@@ -59,6 +60,7 @@ struct CronListView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scarfGoListDensity()
|
||||||
.navigationTitle("Cron jobs")
|
.navigationTitle("Cron jobs")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ struct DashboardView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.scarfGoListDensity()
|
||||||
.navigationTitle(config.displayName)
|
.navigationTitle(config.displayName)
|
||||||
.navigationBarTitleDisplayMode(.large)
|
.navigationBarTitleDisplayMode(.large)
|
||||||
.refreshable {
|
.refreshable {
|
||||||
|
|||||||
@@ -19,13 +19,17 @@ struct MemoryListView: View {
|
|||||||
List {
|
List {
|
||||||
Section {
|
Section {
|
||||||
memoryRow(.memory, context: ctx)
|
memoryRow(.memory, context: ctx)
|
||||||
|
.scarfGoCompactListRow()
|
||||||
memoryRow(.user, context: ctx)
|
memoryRow(.user, context: ctx)
|
||||||
|
.scarfGoCompactListRow()
|
||||||
memoryRow(.soul, context: ctx)
|
memoryRow(.soul, context: ctx)
|
||||||
|
.scarfGoCompactListRow()
|
||||||
} footer: {
|
} footer: {
|
||||||
Text("MEMORY.md and USER.md live under `~/.hermes/memories/`. SOUL.md lives at `~/.hermes/SOUL.md`.")
|
Text("MEMORY.md and USER.md live under `~/.hermes/memories/`. SOUL.md lives at `~/.hermes/SOUL.md`.")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scarfGoListDensity()
|
||||||
.navigationTitle("Memory")
|
.navigationTitle("Memory")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ struct SkillsListView: View {
|
|||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scarfGoCompactListRow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scarfGoListDensity()
|
||||||
.navigationTitle("Skills")
|
.navigationTitle("Skills")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.overlay {
|
.overlay {
|
||||||
|
|||||||
Reference in New Issue
Block a user