Skip to content

Commit e902b30

Browse files
authored
Increase popover height and add expand/collapse view (#9)
- Increase popover height from 540 to 700 for better content visibility - Add expand button next to tab bar to show full-height content view - Add smooth spring animation for expand/collapse transitions - Add dev.sh script for quick build-and-run during development Closes #8
1 parent 3b0de89 commit e902b30

3 files changed

Lines changed: 137 additions & 40 deletions

File tree

Sources/ClearDisk/ClearDiskApp.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
3737

3838
// Create popover
3939
popover = NSPopover()
40-
popover.contentSize = NSSize(width: 380, height: 540)
40+
popover.contentSize = NSSize(width: 380, height: 700)
4141
popover.behavior = .transient
4242
popover.contentViewController = NSHostingController(
4343
rootView: MainView(diskMonitor: diskMonitor)

Sources/ClearDisk/MainView.swift

Lines changed: 121 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct MainView: View {
1818
@State private var showCleanSelectedCachesConfirm = false
1919
@State private var projectFilterMode: ProjectFilterMode = .all
2020
@State private var isCleaning = false
21+
@State private var isExpanded = false
2122

2223
enum Tab: String, CaseIterable {
2324
case developer = "Developer"
@@ -59,7 +60,7 @@ struct MainView: View {
5960
mainScreen
6061
}
6162
}
62-
.frame(width: 380, height: 540)
63+
.frame(width: 380, height: 700)
6364
.alert("Clean Cache", isPresented: $showCleanConfirm) {
6465
Button("Cancel", role: .cancel) { }
6566
Button("Move to Trash", role: .destructive) {
@@ -156,49 +157,130 @@ struct MainView: View {
156157
// MARK: - Main Screen
157158
var mainScreen: some View {
158159
ZStack {
159-
VStack(spacing: 0) {
160-
// Header
161-
headerView
162-
163-
Divider()
164-
165-
// Permission warnings (if any)
166-
if diskMonitor.notificationPermission == .denied {
167-
permissionBanner
160+
if isExpanded {
161+
// Expanded view: full-height content with back button
162+
VStack(spacing: 0) {
163+
HStack {
164+
Button(action: { withAnimation(.spring(response: 0.4, dampingFraction: 0.85)) { isExpanded = false } }) {
165+
HStack(spacing: 4) {
166+
Image(systemName: "chevron.left")
167+
.font(.system(size: 11))
168+
Text("Back")
169+
.font(.system(size: 12))
170+
}
171+
.padding(.horizontal, 8)
172+
.padding(.vertical, 6)
173+
.contentShape(Rectangle())
174+
}
175+
.buttonStyle(.plain)
176+
.foregroundColor(.blue)
177+
178+
Spacer()
179+
180+
Text(selectedTab.rawValue)
181+
.font(.system(size: 13, weight: .semibold))
182+
183+
Spacer()
184+
185+
if diskMonitor.isScanning {
186+
ProgressView()
187+
.scaleEffect(0.7)
188+
}
189+
Button(action: { diskMonitor.scan() }) {
190+
Image(systemName: "arrow.clockwise")
191+
.font(.system(size: 12))
192+
}
193+
.buttonStyle(.plain)
194+
.help("Refresh")
195+
}
196+
.padding(.horizontal, 12)
197+
.padding(.vertical, 8)
198+
168199
Divider()
169-
}
170-
171-
// Cleanable summary card (only when there's stuff to clean)
172-
let artifactTotal = diskMonitor.projectArtifacts.reduce(Int64(0)) { $0 + $1.size }
173-
if diskMonitor.safeCleanable > 10_485_760 || diskMonitor.riskyCleanable > 10_485_760 || artifactTotal > 10_485_760 {
174-
cleanableSummary
200+
201+
ScrollView {
202+
switch selectedTab {
203+
case .overview:
204+
overviewContent
205+
case .developer:
206+
developerContent
207+
case .projects:
208+
projectsContent
209+
case .largeFiles:
210+
largeFilesContent
211+
}
212+
}
213+
.frame(maxHeight: .infinity)
214+
175215
Divider()
216+
217+
footerView
176218
}
177-
178-
// Tab bar
179-
tabBar
180-
181-
Divider()
182-
183-
// Content
184-
ScrollView {
185-
switch selectedTab {
186-
case .overview:
187-
overviewContent
188-
case .developer:
189-
developerContent
190-
case .projects:
191-
projectsContent
192-
case .largeFiles:
193-
largeFilesContent
219+
.transition(.asymmetric(
220+
insertion: .move(edge: .bottom).combined(with: .opacity),
221+
removal: .move(edge: .bottom).combined(with: .opacity)
222+
))
223+
} else {
224+
// Normal view
225+
VStack(spacing: 0) {
226+
// Header
227+
headerView
228+
229+
Divider()
230+
231+
// Permission warnings (if any)
232+
if diskMonitor.notificationPermission == .denied {
233+
permissionBanner
234+
Divider()
235+
}
236+
237+
// Cleanable summary card (only when there's stuff to clean)
238+
let artifactTotal = diskMonitor.projectArtifacts.reduce(Int64(0)) { $0 + $1.size }
239+
if diskMonitor.safeCleanable > 10_485_760 || diskMonitor.riskyCleanable > 10_485_760 || artifactTotal > 10_485_760 {
240+
cleanableSummary
241+
Divider()
194242
}
243+
244+
// Tab bar with expand button
245+
HStack(spacing: 0) {
246+
tabBar
247+
248+
Button(action: { withAnimation(.spring(response: 0.4, dampingFraction: 0.85)) { isExpanded = true } }) {
249+
Image(systemName: "arrow.up.left.and.arrow.down.right")
250+
.font(.system(size: 11))
251+
.foregroundColor(.secondary)
252+
.frame(width: 32, height: 28)
253+
.contentShape(Rectangle())
254+
}
255+
.buttonStyle(.plain)
256+
}
257+
258+
Divider()
259+
260+
// Content
261+
ScrollView {
262+
switch selectedTab {
263+
case .overview:
264+
overviewContent
265+
case .developer:
266+
developerContent
267+
case .projects:
268+
projectsContent
269+
case .largeFiles:
270+
largeFilesContent
271+
}
272+
}
273+
.frame(maxHeight: .infinity)
274+
275+
Divider()
276+
277+
// Footer
278+
footerView
195279
}
196-
.frame(maxHeight: .infinity)
197-
198-
Divider()
199-
200-
// Footer
201-
footerView
280+
.transition(.asymmetric(
281+
insertion: .move(edge: .top).combined(with: .opacity),
282+
removal: .move(edge: .top).combined(with: .opacity)
283+
))
202284
}
203285

204286
// Onboarding overlay (first launch)

dev.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
# ClearDisk dev script - build .app bundle, kill old, launch new
3+
set -e
4+
5+
echo ">> Killing old ClearDisk..."
6+
pkill -f "ClearDisk" 2>/dev/null || true
7+
sleep 0.5
8+
9+
echo ">> Building .app bundle..."
10+
./build_app.sh
11+
12+
echo ">> Launching..."
13+
open ClearDisk.app
14+
15+
echo ">> Done! Check menu bar."

0 commit comments

Comments
 (0)