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 targetX = this.headerPosition.x;
|
||||||
let targetY = this.headerPosition.y;
|
let targetY = this.headerPosition.y;
|
||||||
|
|
||||||
|
console.log(`[MovementManager] Moving ${direction} from (${targetX}, ${targetY})`);
|
||||||
|
|
||||||
|
const windowSize = {
|
||||||
|
width: currentBounds.width,
|
||||||
|
height: currentBounds.height
|
||||||
|
};
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 'left': targetX -= this.stepSize; break;
|
case 'left': targetX -= this.stepSize; break;
|
||||||
case 'right': targetX += this.stepSize; break;
|
case 'right': targetX += this.stepSize; break;
|
||||||
@ -128,24 +135,42 @@ class SmoothMovementManager {
|
|||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const displays = screen.getAllDisplays();
|
// Find the display that contains or is nearest to the target position
|
||||||
let validPosition = displays.some(d => (
|
const nearestDisplay = screen.getDisplayNearestPoint({ x: targetX, y: targetY });
|
||||||
targetX >= d.workArea.x && targetX + currentBounds.width <= d.workArea.x + d.workArea.width &&
|
const { x: workAreaX, y: workAreaY, width: workAreaWidth, height: workAreaHeight } = nearestDisplay.workArea;
|
||||||
targetY >= d.workArea.y && targetY + currentBounds.height <= d.workArea.y + d.workArea.height
|
|
||||||
));
|
// Only clamp if the target position would actually go out of bounds
|
||||||
|
let clampedX = targetX;
|
||||||
if (!validPosition) {
|
let clampedY = targetY;
|
||||||
const nearestDisplay = screen.getDisplayNearestPoint({ x: targetX, y: targetY });
|
|
||||||
const { x, y, width, height } = nearestDisplay.workArea;
|
// Check horizontal bounds
|
||||||
targetX = Math.max(x, Math.min(x + width - currentBounds.width, targetX));
|
if (targetX < workAreaX) {
|
||||||
targetY = Math.max(y, Math.min(y + height - currentBounds.height, targetY));
|
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;
|
console.log(`[MovementManager] Final position: (${clampedX}, ${clampedY}), Work area: ${workAreaX},${workAreaY} ${workAreaWidth}x${workAreaHeight}`);
|
||||||
this.animateToPosition(header, targetX, targetY);
|
|
||||||
|
// 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;
|
if (!this._isWindowValid(header)) return;
|
||||||
|
|
||||||
this.isAnimating = true;
|
this.isAnimating = true;
|
||||||
@ -173,18 +198,25 @@ class SmoothMovementManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this._isWindowValid(header)) return;
|
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) {
|
if (progress < 1) {
|
||||||
this.animationFrameId = setTimeout(animate, 8);
|
this.animationFrameId = setTimeout(animate, 8);
|
||||||
} else {
|
} else {
|
||||||
this.animationFrameId = null;
|
this.animationFrameId = null;
|
||||||
this.headerPosition = { x: targetX, y: targetY };
|
this.isAnimating = false;
|
||||||
if (Number.isFinite(targetX) && Number.isFinite(targetY)) {
|
if (Number.isFinite(targetX) && Number.isFinite(targetY)) {
|
||||||
if (!this._isWindowValid(header)) return;
|
if (!this._isWindowValid(header)) return;
|
||||||
header.setPosition(Math.round(targetX), Math.round(targetY));
|
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();
|
this.updateLayout();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -198,20 +230,40 @@ class SmoothMovementManager {
|
|||||||
const display = this.getCurrentDisplay(header);
|
const display = this.getCurrentDisplay(header);
|
||||||
const { width, height } = display.workAreaSize;
|
const { width, height } = display.workAreaSize;
|
||||||
const { x: workAreaX, y: workAreaY } = display.workArea;
|
const { x: workAreaX, y: workAreaY } = display.workArea;
|
||||||
const headerBounds = header.getBounds();
|
|
||||||
const currentBounds = header.getBounds();
|
const currentBounds = header.getBounds();
|
||||||
|
|
||||||
|
const windowSize = {
|
||||||
|
width: currentBounds.width,
|
||||||
|
height: currentBounds.height
|
||||||
|
};
|
||||||
|
|
||||||
let targetX = currentBounds.x;
|
let targetX = currentBounds.x;
|
||||||
let targetY = currentBounds.y;
|
let targetY = currentBounds.y;
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 'left': targetX = workAreaX; break;
|
case 'left':
|
||||||
case 'right': targetX = workAreaX + width - headerBounds.width; break;
|
targetX = workAreaX;
|
||||||
case 'up': targetY = workAreaY; break;
|
break;
|
||||||
case 'down': targetY = workAreaY + height - headerBounds.height; 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 };
|
header.setBounds({
|
||||||
this.animateToPosition(header, targetX, targetY);
|
x: Math.round(targetX),
|
||||||
|
y: Math.round(targetY),
|
||||||
|
width: windowSize.width,
|
||||||
|
height: windowSize.height
|
||||||
|
});
|
||||||
|
|
||||||
|
this.headerPosition = { x: targetX, y: targetY };
|
||||||
|
this.updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -224,4 +276,4 @@ class SmoothMovementManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SmoothMovementManager;
|
module.exports = SmoothMovementManager;
|
||||||
|
@ -428,7 +428,13 @@ function createWindows() {
|
|||||||
contextIsolation: false,
|
contextIsolation: false,
|
||||||
backgroundThrottling: false,
|
backgroundThrottling: false,
|
||||||
webSecurity: 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') {
|
if (process.platform === 'darwin') {
|
||||||
header.setWindowButtonVisibility(false);
|
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));
|
ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility(movementManager));
|
||||||
|
|
||||||
@ -957,19 +966,49 @@ function setupIpcHandlers(movementManager) {
|
|||||||
ipcMain.handle('resize-header-window', (event, { width, height }) => {
|
ipcMain.handle('resize-header-window', (event, { width, height }) => {
|
||||||
const header = windowPool.get('header');
|
const header = windowPool.get('header');
|
||||||
if (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();
|
const wasResizable = header.isResizable();
|
||||||
if (!wasResizable) {
|
if (!wasResizable) {
|
||||||
header.setResizable(true);
|
header.setResizable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bounds = header.getBounds();
|
// Calculate the center point of the current window
|
||||||
const newX = bounds.x + Math.round((bounds.width - width) / 2);
|
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) {
|
if (!wasResizable) {
|
||||||
header.setResizable(false);
|
header.setResizable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update layout after resize
|
||||||
|
updateLayout();
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
return { success: false, error: 'Header window not found' };
|
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 { x: workAreaX, y: workAreaY, width, height } = targetDisplay.workArea;
|
||||||
const headerBounds = header.getBounds();
|
const headerBounds = header.getBounds();
|
||||||
|
|
||||||
const clampedX = Math.max(workAreaX, Math.min(workAreaX + width - headerBounds.width, newX));
|
// Only clamp if the new position would actually go out of bounds
|
||||||
const clampedY = Math.max(workAreaY, Math.min(workAreaY + height - headerBounds.height, newY));
|
// 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);
|
header.setPosition(clampedX, clampedY, false);
|
||||||
|
|
||||||
|
@ -98,6 +98,12 @@ export class AskView extends LitElement {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allow text selection in assistant responses */
|
||||||
|
.response-container, .response-container * {
|
||||||
|
user-select: text !important;
|
||||||
|
cursor: text !important;
|
||||||
|
}
|
||||||
|
|
||||||
.response-container pre {
|
.response-container pre {
|
||||||
background: rgba(0, 0, 0, 0.4) !important;
|
background: rgba(0, 0, 0, 0.4) !important;
|
||||||
border-radius: 8px !important;
|
border-radius: 8px !important;
|
||||||
|
@ -84,6 +84,87 @@ export class AssistantView extends LitElement {
|
|||||||
user-select: none;
|
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 {
|
.assistant-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user