Skip to content

Commit 5543e3f

Browse files
authored
desktop: shrink dashboard Tasks/Goals cards to fit content (#6902)
## Summary Both `TasksWidget` and `GoalsWidget` had `.frame(maxHeight: .infinity, alignment: .topLeading)` at their root. With `ChatMessagesView` below them (also `maxHeight: .infinity`), the two siblings competed for vertical space and each grabbed roughly half the dashboard — even when the Tasks card had 2–3 rows and the Goals card had 1–2 goals. This PR removes the maxHeight infinity from both widget roots and the inner Spacers in the non-empty branches, so the cards size to their content. The Grid in `DashboardPage.expandedWidgets` still equalizes the row to the taller of the two intrinsic heights. ## Test plan - [ ] Open the dashboard with a small number of tasks (≤3) and goals (≤2) — both cards should hug their content; chat should fill the rest. - [ ] Scale up tasks to ~10 — Tasks card grows to fit 3 rows + "View all" footer (`prefix(3)` is unchanged); Goals card matches its height. - [ ] Empty state for both — cards display their empty-state content with reasonable padding instead of large empty centered area. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
2 parents 899a9f6 + 50df480 commit 5543e3f

3 files changed

Lines changed: 57 additions & 73 deletions

File tree

desktop/CHANGELOG.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
2-
"unreleased": [],
2+
"unreleased": [
3+
"Dashboard Tasks/Goals cards now shrink to fit content instead of stretching to fill the screen"
4+
],
35
"releases": [
46
{
57
"version": "0.11.343",

desktop/Desktop/Sources/MainWindow/Components/GoalsWidget.swift

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,29 @@ struct GoalsWidget: View {
3838

3939
if goals.isEmpty {
4040
// Empty state — header already has a + button, so just offer
41-
// the AI generation action centered in the empty area.
42-
VStack {
43-
Spacer(minLength: 0)
44-
45-
Button(action: { triggerGoalGeneration() }) {
46-
HStack(spacing: 6) {
47-
if isGeneratingGoal {
48-
ProgressView()
49-
.scaleEffect(0.6)
50-
.frame(width: 12, height: 12)
51-
} else {
52-
Image(systemName: "sparkles")
53-
.scaledFont(size: 12)
54-
}
55-
Text(isGeneratingGoal ? "Generating..." : "Generate AI Goal")
56-
.scaledFont(size: 13, weight: .medium)
41+
// the AI generation action below.
42+
Button(action: { triggerGoalGeneration() }) {
43+
HStack(spacing: 6) {
44+
if isGeneratingGoal {
45+
ProgressView()
46+
.scaleEffect(0.6)
47+
.frame(width: 12, height: 12)
48+
} else {
49+
Image(systemName: "sparkles")
50+
.scaledFont(size: 12)
5751
}
58-
.foregroundColor(OmiColors.purplePrimary)
59-
.padding(.horizontal, 14)
60-
.padding(.vertical, 9)
61-
.omiControlSurface(fill: OmiColors.purplePrimary.opacity(0.12), radius: OmiChrome.chipRadius)
52+
Text(isGeneratingGoal ? "Generating..." : "Generate AI Goal")
53+
.scaledFont(size: 13, weight: .medium)
6254
}
63-
.buttonStyle(.plain)
64-
.disabled(isGeneratingGoal)
65-
66-
Spacer(minLength: 0)
55+
.foregroundColor(OmiColors.purplePrimary)
56+
.padding(.horizontal, 14)
57+
.padding(.vertical, 9)
58+
.omiControlSurface(fill: OmiColors.purplePrimary.opacity(0.12), radius: OmiChrome.chipRadius)
6759
}
68-
.frame(maxWidth: .infinity, maxHeight: .infinity)
60+
.buttonStyle(.plain)
61+
.disabled(isGeneratingGoal)
62+
.frame(maxWidth: .infinity)
63+
.padding(.vertical, 12)
6964
} else {
7065
// Goals list
7166
VStack(spacing: 14) {
@@ -85,7 +80,7 @@ struct GoalsWidget: View {
8580
}
8681
}
8782
.padding(22)
88-
.frame(maxHeight: .infinity, alignment: .topLeading)
83+
.frame(maxWidth: .infinity, alignment: .topLeading)
8984
.omiPanel(fill: OmiColors.backgroundSecondary)
9085
.sheet(isPresented: $showingCreateSheet) {
9186
GoalEditSheet(

desktop/Desktop/Sources/MainWindow/Components/TodaysTasksWidget.swift

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,64 +31,51 @@ struct TasksWidget: View {
3131

3232
if totalTaskCount == 0 {
3333
// Empty state
34-
VStack {
35-
Spacer(minLength: 0)
36-
37-
VStack(spacing: 8) {
38-
Image(systemName: "checkmark.circle")
39-
.scaledFont(size: 28)
40-
.foregroundColor(OmiColors.textQuaternary)
41-
Text("No incomplete tasks")
42-
.scaledFont(size: 13)
43-
.foregroundColor(OmiColors.textTertiary)
44-
}
45-
46-
Spacer(minLength: 0)
34+
VStack(spacing: 8) {
35+
Image(systemName: "checkmark.circle")
36+
.scaledFont(size: 28)
37+
.foregroundColor(OmiColors.textQuaternary)
38+
Text("No incomplete tasks")
39+
.scaledFont(size: 13)
40+
.foregroundColor(OmiColors.textTertiary)
4741
}
4842
.frame(maxWidth: .infinity)
49-
.frame(maxHeight: .infinity)
43+
.padding(.vertical, 12)
5044
} else {
5145
let allTasks = (combinedTodayTasks + recentTasks).prefix(3)
5246

53-
VStack(spacing: 0) {
54-
Spacer(minLength: 0)
55-
56-
VStack(spacing: 10) {
57-
ForEach(Array(allTasks)) { task in
58-
TaskRowView(
59-
task: task,
60-
onToggle: { onToggleCompletion(task) }
61-
)
62-
}
63-
}
64-
65-
Button(action: {
66-
NotificationCenter.default.post(
67-
name: .navigateToTasks,
68-
object: nil
47+
VStack(spacing: 10) {
48+
ForEach(Array(allTasks)) { task in
49+
TaskRowView(
50+
task: task,
51+
onToggle: { onToggleCompletion(task) }
6952
)
70-
}) {
71-
HStack {
72-
Spacer()
73-
Text("View all tasks")
74-
.scaledFont(size: 12, weight: .semibold)
75-
.foregroundColor(OmiColors.textSecondary)
76-
Image(systemName: "chevron.right")
77-
.scaledFont(size: 10)
78-
.foregroundColor(OmiColors.textSecondary)
79-
Spacer()
80-
}
8153
}
82-
.buttonStyle(.plain)
83-
.padding(.top, 8)
54+
}
8455

85-
Spacer(minLength: 0)
56+
Button(action: {
57+
NotificationCenter.default.post(
58+
name: .navigateToTasks,
59+
object: nil
60+
)
61+
}) {
62+
HStack {
63+
Spacer()
64+
Text("View all tasks")
65+
.scaledFont(size: 12, weight: .semibold)
66+
.foregroundColor(OmiColors.textSecondary)
67+
Image(systemName: "chevron.right")
68+
.scaledFont(size: 10)
69+
.foregroundColor(OmiColors.textSecondary)
70+
Spacer()
71+
}
8672
}
87-
.frame(maxWidth: .infinity, maxHeight: .infinity)
73+
.buttonStyle(.plain)
74+
.padding(.top, 4)
8875
}
8976
}
9077
.padding(22)
91-
.frame(maxHeight: .infinity, alignment: .topLeading)
78+
.frame(maxWidth: .infinity, alignment: .topLeading)
9279
.omiPanel(fill: OmiColors.backgroundSecondary)
9380
}
9481
}

0 commit comments

Comments
 (0)