Merge branch 'main' into feature/firebase
This commit is contained in:
		
						commit
						594f9e8d19
					
				@ -120,6 +120,13 @@ class SmoothMovementManager {
 | 
			
		||||
        let targetX = this.headerPosition.x;
 | 
			
		||||
        let targetY = this.headerPosition.y;
 | 
			
		||||
 | 
			
		||||
        console.log(`[MovementManager] Moving ${direction} from (${targetX}, ${targetY})`);
 | 
			
		||||
 | 
			
		||||
        const windowSize = {
 | 
			
		||||
            width: currentBounds.width,
 | 
			
		||||
            height: currentBounds.height
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        switch (direction) {
 | 
			
		||||
            case 'left': targetX -= this.stepSize; break;
 | 
			
		||||
            case 'right': targetX += this.stepSize; break;
 | 
			
		||||
@ -128,24 +135,42 @@ class SmoothMovementManager {
 | 
			
		||||
            default: return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const displays = screen.getAllDisplays();
 | 
			
		||||
        let validPosition = displays.some(d => (
 | 
			
		||||
            targetX >= d.workArea.x && targetX + currentBounds.width <= d.workArea.x + d.workArea.width &&
 | 
			
		||||
            targetY >= d.workArea.y && targetY + currentBounds.height <= d.workArea.y + d.workArea.height
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        if (!validPosition) {
 | 
			
		||||
            const nearestDisplay = screen.getDisplayNearestPoint({ x: targetX, y: targetY });
 | 
			
		||||
            const { x, y, width, height } = nearestDisplay.workArea;
 | 
			
		||||
            targetX = Math.max(x, Math.min(x + width - currentBounds.width, targetX));
 | 
			
		||||
            targetY = Math.max(y, Math.min(y + height - currentBounds.height, targetY));
 | 
			
		||||
        // Find the display that contains or is nearest to the target position
 | 
			
		||||
        const nearestDisplay = screen.getDisplayNearestPoint({ x: targetX, y: targetY });
 | 
			
		||||
        const { x: workAreaX, y: workAreaY, width: workAreaWidth, height: workAreaHeight } = nearestDisplay.workArea;
 | 
			
		||||
        
 | 
			
		||||
        // Only clamp if the target position would actually go out of bounds
 | 
			
		||||
        let clampedX = targetX;
 | 
			
		||||
        let clampedY = targetY;
 | 
			
		||||
        
 | 
			
		||||
        // Check horizontal bounds
 | 
			
		||||
        if (targetX < workAreaX) {
 | 
			
		||||
            clampedX = workAreaX;
 | 
			
		||||
        } else if (targetX + currentBounds.width > workAreaX + workAreaWidth) {
 | 
			
		||||
            clampedX = workAreaX + workAreaWidth - currentBounds.width;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Check vertical bounds
 | 
			
		||||
        if (targetY < workAreaY) {
 | 
			
		||||
            clampedY = workAreaY;
 | 
			
		||||
            console.log(`[MovementManager] Clamped Y to top edge: ${clampedY}`);
 | 
			
		||||
        } else if (targetY + currentBounds.height > workAreaY + workAreaHeight) {
 | 
			
		||||
            clampedY = workAreaY + workAreaHeight - currentBounds.height;
 | 
			
		||||
            console.log(`[MovementManager] Clamped Y to bottom edge: ${clampedY}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (targetX === this.headerPosition.x && targetY === this.headerPosition.y) return;
 | 
			
		||||
        this.animateToPosition(header, targetX, targetY);
 | 
			
		||||
        console.log(`[MovementManager] Final position: (${clampedX}, ${clampedY}), Work area: ${workAreaX},${workAreaY} ${workAreaWidth}x${workAreaHeight}`);
 | 
			
		||||
 | 
			
		||||
        // Only move if there's an actual change in position
 | 
			
		||||
        if (clampedX === this.headerPosition.x && clampedY === this.headerPosition.y) {
 | 
			
		||||
            console.log(`[MovementManager] No position change, skipping animation`);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        this.animateToPosition(header, clampedX, clampedY, windowSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    animateToPosition(header, targetX, targetY) {
 | 
			
		||||
    animateToPosition(header, targetX, targetY, windowSize) {
 | 
			
		||||
        if (!this._isWindowValid(header)) return;
 | 
			
		||||
        
 | 
			
		||||
        this.isAnimating = true;
 | 
			
		||||
@ -173,18 +198,25 @@ class SmoothMovementManager {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!this._isWindowValid(header)) return;
 | 
			
		||||
            header.setPosition(Math.round(currentX), Math.round(currentY));
 | 
			
		||||
            const { width, height } = windowSize || header.getBounds();
 | 
			
		||||
            header.setBounds({
 | 
			
		||||
                x: Math.round(currentX),
 | 
			
		||||
                y: Math.round(currentY),
 | 
			
		||||
                width,
 | 
			
		||||
                height
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (progress < 1) {
 | 
			
		||||
                this.animationFrameId = setTimeout(animate, 8);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.animationFrameId = null;
 | 
			
		||||
                this.headerPosition = { x: targetX, y: targetY };
 | 
			
		||||
                this.isAnimating = false;
 | 
			
		||||
                if (Number.isFinite(targetX) && Number.isFinite(targetY)) {
 | 
			
		||||
                    if (!this._isWindowValid(header)) return;
 | 
			
		||||
                    header.setPosition(Math.round(targetX), Math.round(targetY));
 | 
			
		||||
                    // Update header position to the actual final position
 | 
			
		||||
                    this.headerPosition = { x: Math.round(targetX), y: Math.round(targetY) };
 | 
			
		||||
                }
 | 
			
		||||
                this.isAnimating = false;
 | 
			
		||||
                this.updateLayout();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
@ -198,20 +230,40 @@ class SmoothMovementManager {
 | 
			
		||||
        const display = this.getCurrentDisplay(header);
 | 
			
		||||
        const { width, height } = display.workAreaSize;
 | 
			
		||||
        const { x: workAreaX, y: workAreaY } = display.workArea;
 | 
			
		||||
        const headerBounds = header.getBounds();
 | 
			
		||||
        const currentBounds = header.getBounds();
 | 
			
		||||
        
 | 
			
		||||
        const windowSize = {
 | 
			
		||||
            width: currentBounds.width,
 | 
			
		||||
            height: currentBounds.height
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let targetX = currentBounds.x;
 | 
			
		||||
        let targetY = currentBounds.y;
 | 
			
		||||
 | 
			
		||||
        switch (direction) {
 | 
			
		||||
            case 'left': targetX = workAreaX; break;
 | 
			
		||||
            case 'right': targetX = workAreaX + width - headerBounds.width; break;
 | 
			
		||||
            case 'up': targetY = workAreaY; break;
 | 
			
		||||
            case 'down': targetY = workAreaY + height - headerBounds.height; break;
 | 
			
		||||
            case 'left': 
 | 
			
		||||
                targetX = workAreaX; 
 | 
			
		||||
                break;
 | 
			
		||||
            case 'right': 
 | 
			
		||||
                targetX = workAreaX + width - windowSize.width; 
 | 
			
		||||
                break;
 | 
			
		||||
            case 'up': 
 | 
			
		||||
                targetY = workAreaY; 
 | 
			
		||||
                break;
 | 
			
		||||
            case 'down': 
 | 
			
		||||
                targetY = workAreaY + height - windowSize.height; 
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.headerPosition = { x: currentBounds.x, y: currentBounds.y };
 | 
			
		||||
        this.animateToPosition(header, targetX, targetY);
 | 
			
		||||
        header.setBounds({
 | 
			
		||||
            x: Math.round(targetX),
 | 
			
		||||
            y: Math.round(targetY),
 | 
			
		||||
            width: windowSize.width,
 | 
			
		||||
            height: windowSize.height
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.headerPosition = { x: targetX, y: targetY };
 | 
			
		||||
        this.updateLayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
@ -224,4 +276,4 @@ class SmoothMovementManager {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = SmoothMovementManager;
 | 
			
		||||
module.exports = SmoothMovementManager;
 | 
			
		||||
 | 
			
		||||
@ -428,7 +428,13 @@ function createWindows() {
 | 
			
		||||
            contextIsolation: false,
 | 
			
		||||
            backgroundThrottling: false,
 | 
			
		||||
            webSecurity: false,
 | 
			
		||||
            enableRemoteModule: false,
 | 
			
		||||
            // Ensure proper rendering and prevent pixelation
 | 
			
		||||
            experimentalFeatures: false,
 | 
			
		||||
        },
 | 
			
		||||
        // Prevent pixelation and ensure proper rendering
 | 
			
		||||
        useContentSize: true,
 | 
			
		||||
        disableAutoHideCursor: true,
 | 
			
		||||
    });
 | 
			
		||||
    if (process.platform === 'darwin') {
 | 
			
		||||
        header.setWindowButtonVisibility(false);
 | 
			
		||||
@ -492,7 +498,10 @@ function createWindows() {
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    header.on('resize', updateLayout);
 | 
			
		||||
    header.on('resize', () => {
 | 
			
		||||
        console.log('[WindowManager] Header resize event triggered');
 | 
			
		||||
        updateLayout();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility(movementManager));
 | 
			
		||||
 | 
			
		||||
@ -957,19 +966,49 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
    ipcMain.handle('resize-header-window', (event, { width, height }) => {
 | 
			
		||||
        const header = windowPool.get('header');
 | 
			
		||||
        if (header) {
 | 
			
		||||
            console.log(`[WindowManager] Resize request: ${width}x${height}`);
 | 
			
		||||
            
 | 
			
		||||
            // Prevent resizing during animations or if already at target size
 | 
			
		||||
            if (movementManager && movementManager.isAnimating) {
 | 
			
		||||
                console.log('[WindowManager] Skipping resize during animation');
 | 
			
		||||
                return { success: false, error: 'Cannot resize during animation' };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const currentBounds = header.getBounds();
 | 
			
		||||
            console.log(`[WindowManager] Current bounds: ${currentBounds.width}x${currentBounds.height} at (${currentBounds.x}, ${currentBounds.y})`);
 | 
			
		||||
            
 | 
			
		||||
            // Skip if already at target size to prevent unnecessary operations
 | 
			
		||||
            if (currentBounds.width === width && currentBounds.height === height) {
 | 
			
		||||
                console.log('[WindowManager] Already at target size, skipping resize');
 | 
			
		||||
                return { success: true };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const wasResizable = header.isResizable();
 | 
			
		||||
            if (!wasResizable) {
 | 
			
		||||
                header.setResizable(true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const bounds = header.getBounds();
 | 
			
		||||
            const newX = bounds.x + Math.round((bounds.width - width) / 2);
 | 
			
		||||
            // Calculate the center point of the current window
 | 
			
		||||
            const centerX = currentBounds.x + currentBounds.width / 2;
 | 
			
		||||
            // Calculate new X position to keep the window centered
 | 
			
		||||
            const newX = Math.round(centerX - width / 2);
 | 
			
		||||
 | 
			
		||||
            header.setBounds({ x: newX, y: bounds.y, width, height });
 | 
			
		||||
            // Get the current display to ensure we stay within bounds
 | 
			
		||||
            const display = getCurrentDisplay(header);
 | 
			
		||||
            const { x: workAreaX, width: workAreaWidth } = display.workArea;
 | 
			
		||||
            
 | 
			
		||||
            // Clamp the new position to stay within display bounds
 | 
			
		||||
            const clampedX = Math.max(workAreaX, Math.min(workAreaX + workAreaWidth - width, newX));
 | 
			
		||||
 | 
			
		||||
            header.setBounds({ x: clampedX, y: currentBounds.y, width, height });
 | 
			
		||||
 | 
			
		||||
            if (!wasResizable) {
 | 
			
		||||
                header.setResizable(false);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Update layout after resize
 | 
			
		||||
            updateLayout();
 | 
			
		||||
            
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        }
 | 
			
		||||
        return { success: false, error: 'Header window not found' };
 | 
			
		||||
@ -1019,8 +1058,24 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
            const { x: workAreaX, y: workAreaY, width, height } = targetDisplay.workArea;
 | 
			
		||||
            const headerBounds = header.getBounds();
 | 
			
		||||
 | 
			
		||||
            const clampedX = Math.max(workAreaX, Math.min(workAreaX + width - headerBounds.width, newX));
 | 
			
		||||
            const clampedY = Math.max(workAreaY, Math.min(workAreaY + height - headerBounds.height, newY));
 | 
			
		||||
            // Only clamp if the new position would actually go out of bounds
 | 
			
		||||
            // This prevents progressive restriction of movement
 | 
			
		||||
            let clampedX = newX;
 | 
			
		||||
            let clampedY = newY;
 | 
			
		||||
            
 | 
			
		||||
            // Check if we need to clamp X position
 | 
			
		||||
            if (newX < workAreaX) {
 | 
			
		||||
                clampedX = workAreaX;
 | 
			
		||||
            } else if (newX + headerBounds.width > workAreaX + width) {
 | 
			
		||||
                clampedX = workAreaX + width - headerBounds.width;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Check if we need to clamp Y position  
 | 
			
		||||
            if (newY < workAreaY) {
 | 
			
		||||
                clampedY = workAreaY;
 | 
			
		||||
            } else if (newY + headerBounds.height > workAreaY + height) {
 | 
			
		||||
                clampedY = workAreaY + height - headerBounds.height;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            header.setPosition(clampedX, clampedY, false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -98,6 +98,12 @@ export class AskView extends LitElement {
 | 
			
		||||
            user-select: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Allow text selection in assistant responses */
 | 
			
		||||
        .response-container, .response-container * {
 | 
			
		||||
            user-select: text !important;
 | 
			
		||||
            cursor: text !important;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .response-container pre {
 | 
			
		||||
            background: rgba(0, 0, 0, 0.4) !important;
 | 
			
		||||
            border-radius: 8px !important;
 | 
			
		||||
 | 
			
		||||
@ -84,6 +84,87 @@ export class AssistantView extends LitElement {
 | 
			
		||||
            user-select: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
/* Allow text selection in insights responses */
 | 
			
		||||
.insights-container, .insights-container *, .markdown-content {
 | 
			
		||||
    user-select: text !important;
 | 
			
		||||
    cursor: text !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* highlight.js 스타일 추가 */
 | 
			
		||||
.insights-container pre {
 | 
			
		||||
    background: rgba(0, 0, 0, 0.4) !important;
 | 
			
		||||
    border-radius: 8px !important;
 | 
			
		||||
    padding: 12px !important;
 | 
			
		||||
    margin: 8px 0 !important;
 | 
			
		||||
    overflow-x: auto !important;
 | 
			
		||||
    border: 1px solid rgba(255, 255, 255, 0.1) !important;
 | 
			
		||||
    white-space: pre !important;
 | 
			
		||||
    word-wrap: normal !important;
 | 
			
		||||
    word-break: normal !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.insights-container code {
 | 
			
		||||
    font-family: 'Monaco', 'Menlo', 'Consolas', monospace !important;
 | 
			
		||||
    font-size: 11px !important;
 | 
			
		||||
    background: transparent !important;
 | 
			
		||||
    white-space: pre !important;
 | 
			
		||||
    word-wrap: normal !important;
 | 
			
		||||
    word-break: normal !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.insights-container pre code {
 | 
			
		||||
    white-space: pre !important;
 | 
			
		||||
    word-wrap: normal !important;
 | 
			
		||||
    word-break: normal !important;
 | 
			
		||||
    display: block !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.insights-container p code {
 | 
			
		||||
    background: rgba(255, 255, 255, 0.1) !important;
 | 
			
		||||
    padding: 2px 4px !important;
 | 
			
		||||
    border-radius: 3px !important;
 | 
			
		||||
    color: #ffd700 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-keyword {
 | 
			
		||||
    color: #ff79c6 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-string {
 | 
			
		||||
    color: #f1fa8c !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-comment {
 | 
			
		||||
    color: #6272a4 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-number {
 | 
			
		||||
    color: #bd93f9 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-function {
 | 
			
		||||
    color: #50fa7b !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-title {
 | 
			
		||||
    color: #50fa7b !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-variable {
 | 
			
		||||
    color: #8be9fd !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-built_in {
 | 
			
		||||
    color: #ffb86c !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-attr {
 | 
			
		||||
    color: #50fa7b !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hljs-tag {
 | 
			
		||||
    color: #ff79c6 !important;
 | 
			
		||||
}
 | 
			
		||||
        .assistant-container {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user