Fix: Window things

This commit is contained in:
Hariharan Mudaliar 2025-08-24 00:06:31 +05:30
commit f84c0aafa4
2 changed files with 152 additions and 70 deletions

View file

@ -157,44 +157,66 @@ struct ClipboardPanelView: View {
} }
var body: some View { var body: some View {
VStack(spacing: 0) { ZStack {
// Header with tabs VStack(spacing: 0) {
ClipboardPanelHeader( // Header with tabs
selectedTab: $selectedTab, ClipboardPanelHeader(
searchText: $searchText, selectedTab: $selectedTab,
onClose: onClose searchText: $searchText,
) onClose: onClose
Divider()
.background(Color.gray.opacity(0.3))
// Content
if filteredItems.isEmpty {
ClipboardPanelEmptyState(
hasSearch: !searchText.isEmpty,
isHistoryTab: selectedTab == .history
) )
} else {
ScrollView { Divider()
LazyVStack(spacing: 1) { .background(Color.gray.opacity(0.3))
ForEach(filteredItems) { item in
ClipboardPanelItemRow( // Content
item: item, if filteredItems.isEmpty {
isHovered: hoveredItemId == item.id, ClipboardPanelEmptyState(
isPinned: clipboardManager.pinnedItems.contains(where: { $0.id == item.id }) hasSearch: !searchText.isEmpty,
) { hoverId in isHistoryTab: selectedTab == .history
hoveredItemId = hoverId )
} else {
ScrollView {
LazyVStack(spacing: 1) {
ForEach(filteredItems) { item in
ClipboardPanelItemRow(
item: item,
isHovered: hoveredItemId == item.id,
isPinned: clipboardManager.pinnedItems.contains(where: { $0.id == item.id })
) { hoverId in
hoveredItemId = hoverId
}
} }
} }
.padding(.vertical, 8)
} }
.padding(.vertical, 8)
} }
} }
.frame(width: 320, height: 400)
.background(VisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
.cornerRadius(12)
.shadow(color: .black.opacity(0.4), radius: 20, x: 0, y: 10)
// Close button positioned in top-left corner
VStack {
HStack {
Button(action: onClose) {
Image(systemName: "xmark")
.font(.system(size: 12, weight: .medium))
.foregroundColor(.white)
.frame(width: 24, height: 24)
.background(Color.red)
.clipShape(Circle())
}
.buttonStyle(PlainButtonStyle())
.padding(.leading, 12)
.padding(.top, 12)
Spacer()
}
Spacer()
}
} }
.frame(width: 320, height: 400)
.background(VisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
.cornerRadius(12)
.shadow(color: .black.opacity(0.4), radius: 20, x: 0, y: 10)
} }
} }
@ -234,13 +256,6 @@ struct ClipboardPanelHeader: View {
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
.disabled(selectedTab == .history ? clipboardManager.clipboardHistory.isEmpty : clipboardManager.pinnedItems.isEmpty) .disabled(selectedTab == .history ? clipboardManager.clipboardHistory.isEmpty : clipboardManager.pinnedItems.isEmpty)
Button(action: onClose) {
Image(systemName: "xmark")
.foregroundColor(.secondary)
.font(.system(size: 12, weight: .medium))
}
.buttonStyle(PlainButtonStyle())
} }
.padding(.horizontal, 16) .padding(.horizontal, 16)
.padding(.top, 12) .padding(.top, 12)

View file

@ -20,11 +20,12 @@ class ColorPickerPanelManager: ObservableObject {
hideColorPickerPanel() // Close any existing panel hideColorPickerPanel() // Close any existing panel
let newPanel = ColorPickerPanel() let newPanel = ColorPickerPanel()
newPanel.positionPanel()
self.panel = newPanel self.panel = newPanel
// Make the panel key and order front to ensure it can receive focus // Position the panel
newPanel.positionPanel()
// Make the panel visible and focused
newPanel.makeKeyAndOrderFront(nil) newPanel.makeKeyAndOrderFront(nil)
newPanel.orderFrontRegardless() newPanel.orderFrontRegardless()
@ -60,35 +61,52 @@ class ColorPickerPanelManager: ObservableObject {
class ColorPickerPanel: NSPanel { class ColorPickerPanel: NSPanel {
override var canBecomeKey: Bool { true } override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { false } override var canBecomeMain: Bool { true }
init() { init() {
super.init( super.init(
contentRect: NSRect(x: 0, y: 0, width: 450, height: 600), contentRect: .zero,
styleMask: [.titled, .closable, .fullSizeContentView], styleMask: [.borderless, .nonactivatingPanel],
backing: .buffered, backing: .buffered,
defer: false defer: true
) )
setupPanel() setupPanel()
} }
private func setupPanel() { private func setupPanel() {
title = "Color Picker" backgroundColor = .clear
level = .floating
isMovableByWindowBackground = true
backgroundColor = NSColor.clear
isOpaque = false isOpaque = false
hasShadow = true hasShadow = true
level = .floating
isMovableByWindowBackground = true
titlebarAppearsTransparent = true titlebarAppearsTransparent = true
titleVisibility = .hidden titleVisibility = .hidden
isFloatingPanel = true
// Allow dragging from any part of the window
styleMask.insert(.fullSizeContentView)
collectionBehavior = [
.canJoinAllSpaces,
.stationary,
.fullScreenAuxiliary // Float above full-screen apps
]
// Accept mouse moved events for proper hover behavior
acceptsMouseMovedEvents = true
let panelView = ColorPickerPanelView { let panelView = ColorPickerPanelView {
ColorPickerPanelManager.shared.hideColorPickerPanel() ColorPickerPanelManager.shared.hideColorPickerPanel()
} }
contentView = NSHostingView(rootView: panelView) let hostingView = NSHostingView(rootView: panelView)
contentView = hostingView
// Set initial size
let preferredSize = CGSize(width: 450, height: 600)
hostingView.setFrameSize(preferredSize)
setContentSize(preferredSize)
} }
func positionPanel() { func positionPanel() {
@ -97,11 +115,46 @@ class ColorPickerPanel: NSPanel {
let screenFrame = screen.visibleFrame let screenFrame = screen.visibleFrame
let panelFrame = frame let panelFrame = frame
let xPosition = screenFrame.midX - panelFrame.width / 2 // Check if we have a saved position
let yPosition = screenFrame.midY - panelFrame.height / 2 if let savedPosition = getSavedPosition() {
// Validate saved position is still on screen
let savedFrame = NSRect(origin: savedPosition, size: panelFrame.size)
if screenFrame.intersects(savedFrame) {
setFrameOrigin(savedPosition)
return
}
}
// Default to center of screen (not top center)
let xPosition = (screenFrame.width - panelFrame.width) / 2 + screenFrame.minX
let yPosition = (screenFrame.height - panelFrame.height) / 2 + screenFrame.minY
setFrameOrigin(NSPoint(x: xPosition, y: yPosition)) setFrameOrigin(NSPoint(x: xPosition, y: yPosition))
print("ColorPicker: Panel positioned at \(xPosition), \(yPosition)") }
private func getSavedPosition() -> NSPoint? {
let defaults = UserDefaults.standard
let x = defaults.double(forKey: "colorPickerPanelPositionX")
let y = defaults.double(forKey: "colorPickerPanelPositionY")
// Check if we have valid saved coordinates (not default 0.0)
if x != 0.0 || y != 0.0 {
return NSPoint(x: x, y: y)
}
return nil
}
private func saveCurrentPosition() {
let currentOrigin = frame.origin
let defaults = UserDefaults.standard
defaults.set(currentOrigin.x, forKey: "colorPickerPanelPositionX")
defaults.set(currentOrigin.y, forKey: "colorPickerPanelPositionY")
}
override func setFrameOrigin(_ point: NSPoint) {
super.setFrameOrigin(point)
// Save position whenever it changes (user dragging)
saveCurrentPosition()
} }
} }
@ -126,16 +179,38 @@ struct ColorPickerPanelView: View {
} }
var body: some View { var body: some View {
VStack(spacing: 0) { ZStack {
headerSection VStack(spacing: 0) {
headerSection
Divider()
.background(Color.gray.opacity(0.3))
contentSection
}
.background(ColorPickerVisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
.cornerRadius(12)
Divider() // Close button positioned in top-left corner
.background(Color.gray.opacity(0.3)) VStack {
HStack {
contentSection Button(action: onClose) {
Image(systemName: "xmark")
.font(.system(size: 12, weight: .medium))
.foregroundColor(.white)
.frame(width: 24, height: 24)
.background(Color.red)
.clipShape(Circle())
}
.buttonStyle(PlainButtonStyle())
.padding(.leading, 12)
.padding(.top, 12)
Spacer()
}
Spacer()
}
} }
.background(ColorPickerVisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
.cornerRadius(12)
.alert("Delete Color", isPresented: $showingDeleteAlert) { .alert("Delete Color", isPresented: $showingDeleteAlert) {
Button("Cancel", role: .cancel) { } Button("Cancel", role: .cancel) { }
Button("Delete", role: .destructive) { Button("Delete", role: .destructive) {
@ -195,14 +270,6 @@ struct ColorPickerPanelView: View {
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
.disabled(colorPickerManager.colorHistory.isEmpty) .disabled(colorPickerManager.colorHistory.isEmpty)
// Close Button
Button(action: onClose) {
Image(systemName: "xmark")
.font(.system(size: 14, weight: .medium))
.foregroundColor(.secondary)
}
.buttonStyle(PlainButtonStyle())
} }
} }