Merge branch 'main' of https://github.com/pickle-com/glass
This commit is contained in:
commit
2a1edb6ed8
35
package-lock.json
generated
35
package-lock.json
generated
@ -4172,6 +4172,28 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-temp": {
|
||||
"version": "1.2.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"random-path": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-xattr": {
|
||||
"version": "0.3.1",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"!win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
@ -5136,6 +5158,19 @@
|
||||
"lru-cache": "6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/macos-alias": {
|
||||
"version": "0.2.12",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"dependencies": {
|
||||
"nan": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/make-fetch-happen": {
|
||||
"version": "10.2.1",
|
||||
"dev": true,
|
||||
|
@ -25,15 +25,14 @@ export class ApiKeyHeader extends LitElement {
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
transform: translate3d(0, 0, 0);
|
||||
backface-visibility: hidden;
|
||||
transition: opacity 0.25s ease-out;
|
||||
display: block;
|
||||
transition: opacity 0.3s ease-in, transform 0.3s ease-in;
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
:host(.sliding-out) {
|
||||
animation: slideOutUp 0.3s ease-in forwards;
|
||||
will-change: opacity, transform;
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
|
||||
:host(.hidden) {
|
||||
@ -41,17 +40,6 @@ export class ApiKeyHeader extends LitElement {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes slideOutUp {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
cursor: default;
|
||||
@ -60,6 +48,7 @@ export class ApiKeyHeader extends LitElement {
|
||||
}
|
||||
|
||||
.container {
|
||||
-webkit-app-region: drag;
|
||||
width: 350px;
|
||||
min-height: 260px;
|
||||
padding: 18px 20px;
|
||||
@ -89,6 +78,7 @@ export class ApiKeyHeader extends LitElement {
|
||||
}
|
||||
|
||||
.close-button {
|
||||
-webkit-app-region: no-drag;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
@ -168,6 +158,7 @@ export class ApiKeyHeader extends LitElement {
|
||||
}
|
||||
|
||||
.api-input {
|
||||
-webkit-app-region: no-drag;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
@ -195,6 +186,7 @@ export class ApiKeyHeader extends LitElement {
|
||||
.provider-column { flex: 1; display: flex; flex-direction: column; align-items: center; }
|
||||
.provider-label { color: rgba(255, 255, 255, 0.7); font-size: 11px; font-weight: 500; margin-bottom: 6px; }
|
||||
.api-input, .provider-select {
|
||||
-webkit-app-region: no-drag;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
@ -221,6 +213,7 @@ export class ApiKeyHeader extends LitElement {
|
||||
|
||||
|
||||
.action-button {
|
||||
-webkit-app-region: no-drag;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
@ -266,37 +259,10 @@ export class ApiKeyHeader extends LitElement {
|
||||
font-weight: 500; /* Medium */
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
|
||||
/* ────────────────[ GLASS BYPASS ]─────────────── */
|
||||
:host-context(body.has-glass) .container,
|
||||
:host-context(body.has-glass) .api-input,
|
||||
:host-context(body.has-glass) .provider-select,
|
||||
:host-context(body.has-glass) .action-button,
|
||||
:host-context(body.has-glass) .close-button {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .container::after,
|
||||
:host-context(body.has-glass) .action-button::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .action-button:hover,
|
||||
:host-context(body.has-glass) .provider-select:hover,
|
||||
:host-context(body.has-glass) .close-button:hover {
|
||||
background: transparent !important;
|
||||
}
|
||||
`
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.dragState = null
|
||||
this.wasJustDragged = false
|
||||
this.isLoading = false
|
||||
this.errorMessage = ""
|
||||
this.successMessage = ""
|
||||
@ -358,8 +324,6 @@ export class ApiKeyHeader extends LitElement {
|
||||
this.loadProviderConfig();
|
||||
//////// after_modelStateService ////////
|
||||
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this)
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this)
|
||||
this.handleKeyPress = this.handleKeyPress.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
this.handleInput = this.handleInput.bind(this)
|
||||
@ -1533,7 +1497,6 @@ export class ApiKeyHeader extends LitElement {
|
||||
|
||||
handleUsePicklesKey(e) {
|
||||
e.preventDefault()
|
||||
if (this.wasJustDragged) return
|
||||
|
||||
console.log("Requesting Firebase authentication from main process...")
|
||||
if (window.require) {
|
||||
|
@ -9,10 +9,7 @@ export class MainHeader extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
transform: translate3d(0, 0, 0);
|
||||
backface-visibility: hidden;
|
||||
transition: transform 0.2s cubic-bezier(0.23, 1, 0.32, 1), opacity 0.2s ease-out;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
:host(.hiding) {
|
||||
@ -33,65 +30,6 @@ export class MainHeader extends LitElement {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
filter: blur(0px);
|
||||
}
|
||||
30% {
|
||||
opacity: 0.7;
|
||||
transform: translateY(-20%) scale(0.98);
|
||||
filter: blur(0.5px);
|
||||
}
|
||||
70% {
|
||||
opacity: 0.3;
|
||||
transform: translateY(-80%) scale(0.92);
|
||||
filter: blur(1.5px);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(-150%) scale(0.85);
|
||||
filter: blur(2px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-150%) scale(0.85);
|
||||
filter: blur(2px);
|
||||
}
|
||||
30% {
|
||||
opacity: 0.5;
|
||||
transform: translateY(-50%) scale(0.92);
|
||||
filter: blur(1px);
|
||||
}
|
||||
65% {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-5%) scale(0.99);
|
||||
filter: blur(0.2px);
|
||||
}
|
||||
85% {
|
||||
opacity: 0.98;
|
||||
transform: translateY(2%) scale(1.005);
|
||||
filter: blur(0px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
filter: blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
@ -100,6 +38,7 @@ export class MainHeader extends LitElement {
|
||||
}
|
||||
|
||||
.header {
|
||||
-webkit-app-region: drag;
|
||||
width: max-content;
|
||||
height: 47px;
|
||||
padding: 2px 10px 2px 13px;
|
||||
@ -141,6 +80,7 @@ export class MainHeader extends LitElement {
|
||||
}
|
||||
|
||||
.listen-button {
|
||||
-webkit-app-region: no-drag;
|
||||
height: 26px;
|
||||
padding: 0 13px;
|
||||
background: transparent;
|
||||
@ -193,6 +133,7 @@ export class MainHeader extends LitElement {
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
-webkit-app-region: no-drag;
|
||||
height: 26px;
|
||||
box-sizing: border-box;
|
||||
justify-content: flex-start;
|
||||
@ -264,6 +205,7 @@ export class MainHeader extends LitElement {
|
||||
}
|
||||
|
||||
.settings-button {
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 5px;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
@ -291,125 +233,20 @@ export class MainHeader extends LitElement {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* ────────────────[ GLASS BYPASS ]─────────────── */
|
||||
:host-context(body.has-glass) .header,
|
||||
:host-context(body.has-glass) .listen-button,
|
||||
:host-context(body.has-glass) .header-actions,
|
||||
:host-context(body.has-glass) .settings-button {
|
||||
background: transparent !important;
|
||||
filter: none !important;
|
||||
box-shadow: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
:host-context(body.has-glass) .icon-box {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .header::before,
|
||||
:host-context(body.has-glass) .header::after,
|
||||
:host-context(body.has-glass) .listen-button::before,
|
||||
:host-context(body.has-glass) .listen-button::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .header-actions:hover,
|
||||
:host-context(body.has-glass) .settings-button:hover,
|
||||
:host-context(body.has-glass) .listen-button:hover::before {
|
||||
background: transparent !important;
|
||||
}
|
||||
:host-context(body.has-glass) * {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
transform: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .header,
|
||||
:host-context(body.has-glass) .listen-button,
|
||||
:host-context(body.has-glass) .header-actions,
|
||||
:host-context(body.has-glass) .settings-button,
|
||||
:host-context(body.has-glass) .icon-box {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
:host-context(body.has-glass) {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
transform: none !important;
|
||||
will-change: auto !important;
|
||||
}
|
||||
`;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.shortcuts = {};
|
||||
this.dragState = null;
|
||||
this.wasJustDragged = false;
|
||||
this.isVisible = true;
|
||||
this.isAnimating = false;
|
||||
this.hasSlidIn = false;
|
||||
this.settingsHideTimer = null;
|
||||
this.isSessionActive = false;
|
||||
this.animationEndTimer = null;
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.handleAnimationEnd = this.handleAnimationEnd.bind(this);
|
||||
}
|
||||
|
||||
async handleMouseDown(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
const initialPosition = await ipcRenderer.invoke('get-header-position');
|
||||
|
||||
this.dragState = {
|
||||
initialMouseX: e.screenX,
|
||||
initialMouseY: e.screenY,
|
||||
initialWindowX: initialPosition.x,
|
||||
initialWindowY: initialPosition.y,
|
||||
moved: false,
|
||||
};
|
||||
|
||||
window.addEventListener('mousemove', this.handleMouseMove, { capture: true });
|
||||
window.addEventListener('mouseup', this.handleMouseUp, { once: true, capture: true });
|
||||
}
|
||||
|
||||
handleMouseMove(e) {
|
||||
if (!this.dragState) return;
|
||||
|
||||
const deltaX = Math.abs(e.screenX - this.dragState.initialMouseX);
|
||||
const deltaY = Math.abs(e.screenY - this.dragState.initialMouseY);
|
||||
|
||||
if (deltaX > 3 || deltaY > 3) {
|
||||
this.dragState.moved = true;
|
||||
}
|
||||
|
||||
const newWindowX = this.dragState.initialWindowX + (e.screenX - this.dragState.initialMouseX);
|
||||
const newWindowY = this.dragState.initialWindowY + (e.screenY - this.dragState.initialMouseY);
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('move-header-to', newWindowX, newWindowY);
|
||||
}
|
||||
|
||||
handleMouseUp(e) {
|
||||
if (!this.dragState) return;
|
||||
|
||||
const wasDragged = this.dragState.moved;
|
||||
|
||||
window.removeEventListener('mousemove', this.handleMouseMove, { capture: true });
|
||||
this.dragState = null;
|
||||
|
||||
if (wasDragged) {
|
||||
this.wasJustDragged = true;
|
||||
setTimeout(() => {
|
||||
this.wasJustDragged = false;
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
toggleVisibility() {
|
||||
if (this.isAnimating) {
|
||||
console.log('[MainHeader] Animation already in progress, ignoring toggle');
|
||||
@ -431,58 +268,29 @@ export class MainHeader extends LitElement {
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.classList.remove('showing', 'hidden');
|
||||
this.classList.remove('showing');
|
||||
this.classList.add('hiding');
|
||||
this.isVisible = false;
|
||||
|
||||
this.animationEndTimer = setTimeout(() => {
|
||||
if (this.classList.contains('hiding')) {
|
||||
this.handleAnimationEnd({ target: this });
|
||||
}
|
||||
}, 350);
|
||||
}
|
||||
|
||||
|
||||
show() {
|
||||
this.classList.remove('hiding', 'hidden');
|
||||
this.classList.add('showing');
|
||||
this.isVisible = true;
|
||||
|
||||
this.animationEndTimer = setTimeout(() => {
|
||||
if (this.classList.contains('showing')) {
|
||||
this.handleAnimationEnd({ target: this });
|
||||
}
|
||||
}, 400);
|
||||
}
|
||||
|
||||
|
||||
handleAnimationEnd(e) {
|
||||
if (e.target !== this) return;
|
||||
|
||||
if (this.animationEndTimer) {
|
||||
clearTimeout(this.animationEndTimer);
|
||||
this.animationEndTimer = null;
|
||||
}
|
||||
|
||||
|
||||
this.isAnimating = false;
|
||||
|
||||
|
||||
if (this.classList.contains('hiding')) {
|
||||
this.classList.remove('hiding');
|
||||
this.classList.add('hidden');
|
||||
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.send('header-animation-complete', 'hidden');
|
||||
window.require('electron').ipcRenderer.send('header-animation-finished', 'hidden');
|
||||
}
|
||||
} else if (this.classList.contains('showing')) {
|
||||
this.classList.remove('showing');
|
||||
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.send('header-animation-complete', 'visible');
|
||||
window.require('electron').ipcRenderer.send('header-animation-finished', 'visible');
|
||||
}
|
||||
} else if (this.classList.contains('sliding-in')) {
|
||||
this.classList.remove('sliding-in');
|
||||
this.hasSlidIn = true;
|
||||
console.log('[MainHeader] Slide-in animation completed');
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,50 +338,37 @@ export class MainHeader extends LitElement {
|
||||
}
|
||||
|
||||
invoke(channel, ...args) {
|
||||
if (this.wasJustDragged) {
|
||||
return;
|
||||
}
|
||||
if (window.require) {
|
||||
window.require('electron').ipcRenderer.invoke(channel, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
showWindow(name, element) {
|
||||
if (this.wasJustDragged) return;
|
||||
showSettingsWindow(element) {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
console.log(`[MainHeader] showWindow('${name}') called at ${Date.now()}`);
|
||||
console.log(`[MainHeader] showSettingsWindow called at ${Date.now()}`);
|
||||
|
||||
ipcRenderer.send('cancel-hide-window', name);
|
||||
ipcRenderer.send('cancel-hide-settings-window');
|
||||
|
||||
if (name === 'settings' && element) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
ipcRenderer.send('show-window', {
|
||||
name: 'settings',
|
||||
bounds: {
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
width: rect.width,
|
||||
height: rect.height
|
||||
}
|
||||
if (element) {
|
||||
const { left, top, width, height } = element.getBoundingClientRect();
|
||||
ipcRenderer.send('show-settings-window', {
|
||||
x: left,
|
||||
y: top,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
} else {
|
||||
ipcRenderer.send('show-window', name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hideWindow(name) {
|
||||
if (this.wasJustDragged) return;
|
||||
hideSettingsWindow() {
|
||||
if (window.require) {
|
||||
console.log(`[MainHeader] hideWindow('${name}') called at ${Date.now()}`);
|
||||
window.require('electron').ipcRenderer.send('hide-window', name);
|
||||
console.log(`[MainHeader] hideSettingsWindow called at ${Date.now()}`);
|
||||
window.require('electron').ipcRenderer.send('hide-settings-window');
|
||||
}
|
||||
}
|
||||
|
||||
cancelHideWindow(name) {
|
||||
|
||||
}
|
||||
|
||||
renderShortcut(accelerator) {
|
||||
if (!accelerator) return html``;
|
||||
@ -600,7 +395,7 @@ export class MainHeader extends LitElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="header" @mousedown=${this.handleMouseDown}>
|
||||
<div class="header">
|
||||
<button
|
||||
class="listen-button ${this.isSessionActive ? 'active' : ''}"
|
||||
@click=${() => this.invoke(this.isSessionActive ? 'close-session' : 'toggle-feature', 'listen')}
|
||||
@ -646,8 +441,8 @@ export class MainHeader extends LitElement {
|
||||
|
||||
<button
|
||||
class="settings-button"
|
||||
@mouseenter=${(e) => this.showWindow('settings', e.currentTarget)}
|
||||
@mouseleave=${() => this.hideWindow('settings')}
|
||||
@mouseenter=${(e) => this.showSettingsWindow(e.currentTarget)}
|
||||
@mouseleave=${() => this.hideSettingsWindow()}
|
||||
>
|
||||
<div class="settings-icon">
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
@ -4,14 +4,13 @@ export class PermissionHeader extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
transform: translate3d(0, 0, 0);
|
||||
backface-visibility: hidden;
|
||||
transition: opacity 0.25s ease-out;
|
||||
transition: opacity 0.3s ease-in, transform 0.3s ease-in;
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
:host(.sliding-out) {
|
||||
animation: slideOutUp 0.3s ease-in forwards;
|
||||
will-change: opacity, transform;
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
|
||||
:host(.hidden) {
|
||||
@ -19,17 +18,6 @@ export class PermissionHeader extends LitElement {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes slideOutUp {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
cursor: default;
|
||||
@ -38,6 +26,7 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
|
||||
.container {
|
||||
-webkit-app-region: drag;
|
||||
width: 285px;
|
||||
height: 220px;
|
||||
padding: 18px 20px;
|
||||
@ -67,6 +56,7 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
|
||||
.close-button {
|
||||
-webkit-app-region: no-drag;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
@ -157,6 +147,7 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
|
||||
.action-button {
|
||||
-webkit-app-region: no-drag;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
@ -198,6 +189,7 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
|
||||
.continue-button {
|
||||
-webkit-app-region: no-drag;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
background: rgba(34, 197, 94, 0.8);
|
||||
@ -237,30 +229,6 @@ export class PermissionHeader extends LitElement {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* ────────────────[ GLASS BYPASS ]─────────────── */
|
||||
:host-context(body.has-glass) .container,
|
||||
:host-context(body.has-glass) .action-button,
|
||||
:host-context(body.has-glass) .continue-button,
|
||||
:host-context(body.has-glass) .close-button {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .container::after,
|
||||
:host-context(body.has-glass) .action-button::after,
|
||||
:host-context(body.has-glass) .continue-button::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .action-button:hover,
|
||||
:host-context(body.has-glass) .continue-button:hover,
|
||||
:host-context(body.has-glass) .close-button:hover {
|
||||
background: transparent !important;
|
||||
}
|
||||
`;
|
||||
|
||||
static properties = {
|
||||
@ -276,9 +244,6 @@ export class PermissionHeader extends LitElement {
|
||||
this.screenGranted = 'unknown';
|
||||
this.isChecking = false;
|
||||
this.continueCallback = null;
|
||||
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
@ -298,61 +263,6 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
async handleMouseDown(e) {
|
||||
if (e.target.tagName === 'BUTTON') {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
const initialPosition = await ipcRenderer.invoke('get-header-position');
|
||||
|
||||
this.dragState = {
|
||||
initialMouseX: e.screenX,
|
||||
initialMouseY: e.screenY,
|
||||
initialWindowX: initialPosition.x,
|
||||
initialWindowY: initialPosition.y,
|
||||
moved: false,
|
||||
};
|
||||
|
||||
window.addEventListener('mousemove', this.handleMouseMove);
|
||||
window.addEventListener('mouseup', this.handleMouseUp, { once: true });
|
||||
}
|
||||
|
||||
handleMouseMove(e) {
|
||||
if (!this.dragState) return;
|
||||
|
||||
const deltaX = Math.abs(e.screenX - this.dragState.initialMouseX);
|
||||
const deltaY = Math.abs(e.screenY - this.dragState.initialMouseY);
|
||||
|
||||
if (deltaX > 3 || deltaY > 3) {
|
||||
this.dragState.moved = true;
|
||||
}
|
||||
|
||||
const newWindowX = this.dragState.initialWindowX + (e.screenX - this.dragState.initialMouseX);
|
||||
const newWindowY = this.dragState.initialWindowY + (e.screenY - this.dragState.initialMouseY);
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('move-header-to', newWindowX, newWindowY);
|
||||
}
|
||||
|
||||
handleMouseUp(e) {
|
||||
if (!this.dragState) return;
|
||||
|
||||
const wasDragged = this.dragState.moved;
|
||||
|
||||
window.removeEventListener('mousemove', this.handleMouseMove);
|
||||
this.dragState = null;
|
||||
|
||||
if (wasDragged) {
|
||||
this.wasJustDragged = true;
|
||||
setTimeout(() => {
|
||||
this.wasJustDragged = false;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
async checkPermissions() {
|
||||
if (!window.require || this.isChecking) return;
|
||||
|
||||
@ -390,7 +300,7 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
|
||||
async handleMicrophoneClick() {
|
||||
if (!window.require || this.microphoneGranted === 'granted' || this.wasJustDragged) return;
|
||||
if (!window.require || this.microphoneGranted === 'granted') return;
|
||||
|
||||
console.log('[PermissionHeader] Requesting microphone permission...');
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
@ -423,7 +333,7 @@ export class PermissionHeader extends LitElement {
|
||||
}
|
||||
|
||||
async handleScreenClick() {
|
||||
if (!window.require || this.screenGranted === 'granted' || this.wasJustDragged) return;
|
||||
if (!window.require || this.screenGranted === 'granted') return;
|
||||
|
||||
console.log('[PermissionHeader] Checking screen recording permission...');
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
@ -453,8 +363,7 @@ export class PermissionHeader extends LitElement {
|
||||
async handleContinue() {
|
||||
if (this.continueCallback &&
|
||||
this.microphoneGranted === 'granted' &&
|
||||
this.screenGranted === 'granted' &&
|
||||
!this.wasJustDragged) {
|
||||
this.screenGranted === 'granted') {
|
||||
// Mark permissions as completed
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
@ -481,7 +390,7 @@ export class PermissionHeader extends LitElement {
|
||||
const allGranted = this.microphoneGranted === 'granted' && this.screenGranted === 'granted';
|
||||
|
||||
return html`
|
||||
<div class="container" @mousedown=${this.handleMouseDown}>
|
||||
<div class="container">
|
||||
<button class="close-button" @click=${this.handleClose} title="Close application">
|
||||
<svg width="8" height="8" viewBox="0 0 10 10" fill="currentColor">
|
||||
<path d="M1 1L9 9M9 1L1 9" stroke="currentColor" stroke-width="1.2" />
|
||||
|
@ -136,16 +136,6 @@ export class PickleGlassApp extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
requestWindowResize() {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('resize-window', {
|
||||
isMainViewVisible: this.isMainViewVisible,
|
||||
view: this.currentView,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setStatus(text) {
|
||||
this.statusText = text;
|
||||
}
|
||||
|
@ -237,63 +237,62 @@
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const app = document.getElementById('pickle-glass');
|
||||
let animationTimeout = null;
|
||||
|
||||
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
|
||||
// --- REFACTORED: Event-driven animation handling ---
|
||||
app.addEventListener('animationend', (event) => {
|
||||
// 숨김 애니메이션이 끝나면 main 프로세스에 알려 창을 실제로 숨깁니다.
|
||||
if (event.animationName === 'slideUpToHeader' || event.animationName === 'settingsCollapseToButton') {
|
||||
console.log(`Animation finished: ${event.animationName}. Notifying main process.`);
|
||||
ipcRenderer.send('animation-finished');
|
||||
|
||||
// 완료 후 애니메이션 클래스 정리
|
||||
app.classList.remove('window-sliding-up', 'settings-window-hide');
|
||||
app.classList.add('window-hidden');
|
||||
} else if (event.animationName === 'slideDownFromHeader' || event.animationName === 'settingsPopFromButton') {
|
||||
// 보이기 애니메이션 완료 후 클래스 정리
|
||||
app.classList.remove('window-sliding-down', 'settings-window-show');
|
||||
}
|
||||
});
|
||||
|
||||
ipcRenderer.on('window-show-animation', () => {
|
||||
console.log('Starting window show animation');
|
||||
app.classList.remove('window-hidden', 'window-sliding-up', 'settings-window-hide');
|
||||
app.classList.add('window-sliding-down');
|
||||
|
||||
if (animationTimeout) clearTimeout(animationTimeout);
|
||||
animationTimeout = setTimeout(() => {
|
||||
app.classList.remove('window-sliding-down');
|
||||
}, 120);
|
||||
});
|
||||
|
||||
|
||||
ipcRenderer.on('window-hide-animation', () => {
|
||||
console.log('Starting window hide animation');
|
||||
app.classList.remove('window-sliding-down', 'settings-window-show');
|
||||
app.classList.add('window-sliding-up');
|
||||
|
||||
if (animationTimeout) clearTimeout(animationTimeout);
|
||||
animationTimeout = setTimeout(() => {
|
||||
app.classList.remove('window-sliding-up');
|
||||
app.classList.add('window-hidden');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
|
||||
ipcRenderer.on('settings-window-hide-animation', () => {
|
||||
console.log('Starting settings window hide animation');
|
||||
app.classList.remove('window-sliding-down', 'settings-window-show');
|
||||
app.classList.add('settings-window-hide');
|
||||
|
||||
if (animationTimeout) clearTimeout(animationTimeout);
|
||||
animationTimeout = setTimeout(() => {
|
||||
app.classList.remove('settings-window-hide');
|
||||
app.classList.add('window-hidden');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
|
||||
// --- UNCHANGED: Existing logic for listen window movement ---
|
||||
ipcRenderer.on('listen-window-move-to-center', () => {
|
||||
console.log('Moving listen window to center');
|
||||
app.classList.add('listen-window-moving');
|
||||
app.classList.remove('listen-window-left');
|
||||
app.classList.add('listen-window-center');
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
app.classList.remove('listen-window-moving');
|
||||
}, 350);
|
||||
});
|
||||
|
||||
|
||||
ipcRenderer.on('listen-window-move-to-left', () => {
|
||||
console.log('Moving listen window to left');
|
||||
app.classList.add('listen-window-moving');
|
||||
app.classList.remove('listen-window-center');
|
||||
app.classList.add('listen-window-left');
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
app.classList.remove('listen-window-moving');
|
||||
}, 350);
|
||||
@ -305,6 +304,11 @@
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.get('glass') === 'true') {
|
||||
document.body.classList.add('has-glass');
|
||||
// --- ADDED: Link to centralized glass-bypass styles ---
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = '../common/styles/glass-bypass.css';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
@ -22,6 +22,11 @@
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.get('glass') === 'true') {
|
||||
document.body.classList.add('has-glass');
|
||||
// --- ADDED: Link to centralized glass-bypass styles ---
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = '../common/styles/glass-bypass.css';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
@ -213,13 +213,21 @@ class ModelStateService {
|
||||
const llmModels = PROVIDERS['openai-glass']?.llmModels;
|
||||
const sttModels = PROVIDERS['openai-glass']?.sttModels;
|
||||
|
||||
if (!this.state.selectedModels.llm && llmModels?.length > 0) {
|
||||
// When logging in with Pickle, prioritize Pickle's models over existing selections
|
||||
if (virtualKey && llmModels?.length > 0) {
|
||||
this.state.selectedModels.llm = llmModels[0].id;
|
||||
console.log(`[ModelStateService] Prioritized Pickle LLM model: ${llmModels[0].id}`);
|
||||
}
|
||||
if (!this.state.selectedModels.stt && sttModels?.length > 0) {
|
||||
if (virtualKey && sttModels?.length > 0) {
|
||||
this.state.selectedModels.stt = sttModels[0].id;
|
||||
console.log(`[ModelStateService] Prioritized Pickle STT model: ${sttModels[0].id}`);
|
||||
}
|
||||
this._autoSelectAvailableModels();
|
||||
|
||||
// If logging out (virtualKey is null), run auto-selection to find alternatives
|
||||
if (!virtualKey) {
|
||||
this._autoSelectAvailableModels();
|
||||
}
|
||||
|
||||
this._saveState();
|
||||
this._logCurrentSelection();
|
||||
}
|
||||
|
12
src/common/styles/glass-bypass.css
Normal file
12
src/common/styles/glass-bypass.css
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
이 파일은 body.has-glass 클래스가 적용되었을 때 모든 애니메이션, 트랜지션,
|
||||
배경, 테두리 등을 비활성화하여 깨끗한 투명 효과(Glass)를 보장합니다.
|
||||
*/
|
||||
body.has-glass * {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
@ -78,13 +78,6 @@ function updateLayout() {
|
||||
let movementManager = null;
|
||||
|
||||
|
||||
const featureWindows = ['listen','ask','settings'];
|
||||
// const featureWindows = ['listen','ask','settings','shortcut-settings'];
|
||||
function isAllowed(name) {
|
||||
if (name === 'header') return true;
|
||||
return featureWindows.includes(name) && currentHeaderState === 'main';
|
||||
}
|
||||
|
||||
function createFeatureWindows(header, namesToCreate) {
|
||||
// if (windowPool.has('listen')) return;
|
||||
|
||||
@ -305,6 +298,7 @@ function createFeatureWindows(header, namesToCreate) {
|
||||
}
|
||||
|
||||
function destroyFeatureWindows() {
|
||||
const featureWindows = ['listen','ask','settings','shortcut-settings'];
|
||||
if (settingsHideTimer) {
|
||||
clearTimeout(settingsHideTimer);
|
||||
settingsHideTimer = null;
|
||||
@ -337,78 +331,35 @@ function getDisplayById(displayId) {
|
||||
|
||||
|
||||
|
||||
function toggleAllWindowsVisibility(movementManager) {
|
||||
function toggleAllWindowsVisibility() {
|
||||
const header = windowPool.get('header');
|
||||
if (!header) return;
|
||||
|
||||
|
||||
if (header.isVisible()) {
|
||||
console.log('[Visibility] Smart hiding - calculating nearest edge');
|
||||
|
||||
const headerBounds = header.getBounds();
|
||||
const display = screen.getPrimaryDisplay();
|
||||
const { width: screenWidth, height: screenHeight } = display.workAreaSize;
|
||||
|
||||
const centerX = headerBounds.x + headerBounds.width / 2;
|
||||
const centerY = headerBounds.y + headerBounds.height / 2;
|
||||
|
||||
const distances = {
|
||||
top: centerY,
|
||||
bottom: screenHeight - centerY,
|
||||
left: centerX,
|
||||
right: screenWidth - centerX,
|
||||
};
|
||||
|
||||
const nearestEdge = Object.keys(distances).reduce((nearest, edge) => (distances[edge] < distances[nearest] ? edge : nearest));
|
||||
|
||||
console.log(`[Visibility] Nearest edge: ${nearestEdge} (distance: ${distances[nearestEdge].toFixed(1)}px)`);
|
||||
|
||||
lastVisibleWindows.clear();
|
||||
lastVisibleWindows.add('header');
|
||||
|
||||
windowPool.forEach((win, name) => {
|
||||
if (win.isVisible()) {
|
||||
lastVisibleWindows.add(name);
|
||||
if (name !== 'header') {
|
||||
// win.webContents.send('window-hide-animation');
|
||||
// setTimeout(() => {
|
||||
// if (!win.isDestroyed()) {
|
||||
// win.hide();
|
||||
// }
|
||||
// }, 200);
|
||||
win.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[Visibility] Visible windows before hide:', Array.from(lastVisibleWindows));
|
||||
|
||||
movementManager.hideToEdge(nearestEdge, () => {
|
||||
header.hide();
|
||||
console.log('[Visibility] Smart hide completed');
|
||||
}, { instant: true });
|
||||
} else {
|
||||
console.log('[Visibility] Smart showing from hidden position');
|
||||
console.log('[Visibility] Restoring windows:', Array.from(lastVisibleWindows));
|
||||
|
||||
header.show();
|
||||
|
||||
movementManager.showFromEdge(() => {
|
||||
lastVisibleWindows.forEach(name => {
|
||||
if (name === 'header') return;
|
||||
const win = windowPool.get(name);
|
||||
if (win && !win.isDestroyed()) {
|
||||
win.show();
|
||||
win.webContents.send('window-show-animation');
|
||||
}
|
||||
});
|
||||
|
||||
setImmediate(updateLayout);
|
||||
setTimeout(updateLayout, 120);
|
||||
|
||||
console.log('[Visibility] Smart show completed');
|
||||
});
|
||||
lastVisibleWindows.clear();
|
||||
|
||||
windowPool.forEach((win, name) => {
|
||||
if (win && !win.isDestroyed() && win.isVisible()) {
|
||||
lastVisibleWindows.add(name);
|
||||
}
|
||||
});
|
||||
|
||||
lastVisibleWindows.forEach(name => {
|
||||
if (name === 'header') return;
|
||||
const win = windowPool.get(name);
|
||||
if (win && !win.isDestroyed()) win.hide();
|
||||
});
|
||||
header.hide();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lastVisibleWindows.forEach(name => {
|
||||
const win = windowPool.get(name);
|
||||
if (win && !win.isDestroyed())
|
||||
win.show();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function createWindows() {
|
||||
@ -470,6 +421,7 @@ function createWindows() {
|
||||
});
|
||||
}
|
||||
windowPool.set('header', header);
|
||||
header.on('moved', updateLayout);
|
||||
layoutManager = new WindowLayoutManager(windowPool);
|
||||
|
||||
header.webContents.once('dom-ready', () => {
|
||||
@ -513,7 +465,7 @@ function createWindows() {
|
||||
updateLayout();
|
||||
});
|
||||
|
||||
ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility(movementManager));
|
||||
ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility());
|
||||
|
||||
ipcMain.handle('toggle-feature', async (event, featureName) => {
|
||||
if (!windowPool.get(featureName) && currentHeaderState === 'main') {
|
||||
@ -596,13 +548,6 @@ function createWindows() {
|
||||
} else {
|
||||
console.log('[WindowManager] No response found, closing window');
|
||||
askWindow.webContents.send('window-hide-animation');
|
||||
|
||||
setTimeout(() => {
|
||||
if (!askWindow.isDestroyed()) {
|
||||
askWindow.hide();
|
||||
updateLayout();
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[WindowManager] Error checking Ask window state:', error);
|
||||
@ -631,13 +576,6 @@ function createWindows() {
|
||||
} else {
|
||||
windowToToggle.webContents.send('window-hide-animation');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!windowToToggle.isDestroyed()) {
|
||||
windowToToggle.hide();
|
||||
updateLayout();
|
||||
}
|
||||
}, 250);
|
||||
} else {
|
||||
try {
|
||||
windowToToggle.show();
|
||||
@ -773,9 +711,17 @@ function setupIpcHandlers(movementManager) {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('show-window', (event, args) => {
|
||||
const { name, bounds } = typeof args === 'object' && args !== null ? args : { name: args, bounds: null };
|
||||
const win = windowPool.get(name);
|
||||
ipcMain.on('animation-finished', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (win && !win.isDestroyed()) {
|
||||
console.log(`[WindowManager] Hiding window after animation.`);
|
||||
win.hide();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('show-settings-window', (event, bounds) => {
|
||||
if (!bounds) return;
|
||||
const win = windowPool.get('settings');
|
||||
|
||||
if (win && !win.isDestroyed()) {
|
||||
if (settingsHideTimer) {
|
||||
@ -783,78 +729,60 @@ function setupIpcHandlers(movementManager) {
|
||||
settingsHideTimer = null;
|
||||
}
|
||||
|
||||
if (name === 'settings') {
|
||||
// Adjust position based on button bounds
|
||||
const header = windowPool.get('header');
|
||||
const headerBounds = header?.getBounds() ?? { x: 0, y: 0 };
|
||||
const settingsBounds = win.getBounds();
|
||||
// Adjust position based on button bounds
|
||||
const header = windowPool.get('header');
|
||||
const headerBounds = header?.getBounds() ?? { x: 0, y: 0 };
|
||||
const settingsBounds = win.getBounds();
|
||||
|
||||
const disp = getCurrentDisplay(header);
|
||||
const { x: waX, y: waY, width: waW, height: waH } = disp.workArea;
|
||||
const disp = getCurrentDisplay(header);
|
||||
const { x: waX, y: waY, width: waW, height: waH } = disp.workArea;
|
||||
|
||||
let x = Math.round(headerBounds.x + (bounds?.x ?? 0) + (bounds?.width ?? 0) / 2 - settingsBounds.width / 2);
|
||||
let y = Math.round(headerBounds.y + (bounds?.y ?? 0) + (bounds?.height ?? 0) + 31);
|
||||
let x = Math.round(headerBounds.x + (bounds?.x ?? 0) + (bounds?.width ?? 0) / 2 - settingsBounds.width / 2);
|
||||
let y = Math.round(headerBounds.y + (bounds?.y ?? 0) + (bounds?.height ?? 0) + 31);
|
||||
|
||||
x = Math.max(waX + 10, Math.min(waX + waW - settingsBounds.width - 10, x));
|
||||
y = Math.max(waY + 10, Math.min(waY + waH - settingsBounds.height - 10, y));
|
||||
|
||||
win.setBounds({ x, y });
|
||||
win.__lockedByButton = true;
|
||||
console.log(`[WindowManager] Positioning settings window at (${x}, ${y}) based on button bounds.`);
|
||||
}
|
||||
x = Math.max(waX + 10, Math.min(waX + waW - settingsBounds.width - 10, x));
|
||||
y = Math.max(waY + 10, Math.min(waY + waH - settingsBounds.height - 10, y));
|
||||
|
||||
win.setBounds({ x, y });
|
||||
win.__lockedByButton = true;
|
||||
console.log(`[WindowManager] Positioning settings window at (${x}, ${y}) based on button bounds.`);
|
||||
|
||||
win.show();
|
||||
win.moveTop();
|
||||
|
||||
if (name === 'settings') {
|
||||
win.setAlwaysOnTop(true);
|
||||
}
|
||||
// updateLayout();
|
||||
win.setAlwaysOnTop(true);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('hide-window', (event, name) => {
|
||||
const window = windowPool.get(name);
|
||||
ipcMain.on('hide-settings-window', (event) => {
|
||||
const window = windowPool.get("settings");
|
||||
if (window && !window.isDestroyed()) {
|
||||
if (name === 'settings') {
|
||||
if (settingsHideTimer) {
|
||||
clearTimeout(settingsHideTimer);
|
||||
}
|
||||
settingsHideTimer = setTimeout(() => {
|
||||
// window.setAlwaysOnTop(false);
|
||||
// window.hide();
|
||||
if (window && !window.isDestroyed()) {
|
||||
window.setAlwaysOnTop(false);
|
||||
window.hide();
|
||||
}
|
||||
settingsHideTimer = null;
|
||||
}, 200);
|
||||
} else {
|
||||
window.hide();
|
||||
if (settingsHideTimer) {
|
||||
clearTimeout(settingsHideTimer);
|
||||
}
|
||||
settingsHideTimer = setTimeout(() => {
|
||||
if (window && !window.isDestroyed()) {
|
||||
window.setAlwaysOnTop(false);
|
||||
window.hide();
|
||||
}
|
||||
settingsHideTimer = null;
|
||||
}, 200);
|
||||
|
||||
window.__lockedByButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('cancel-hide-window', (event, name) => {
|
||||
if (name === 'settings' && settingsHideTimer) {
|
||||
ipcMain.on('cancel-hide-settings-window', (event) => {
|
||||
if (settingsHideTimer) {
|
||||
clearTimeout(settingsHideTimer);
|
||||
settingsHideTimer = null;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('hide-all', () => {
|
||||
windowPool.forEach(win => {
|
||||
if (win.isFocused()) return;
|
||||
win.hide();
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle('quit-application', () => {
|
||||
app.quit();
|
||||
});
|
||||
|
||||
ipcMain.handle('is-window-visible', (event, windowName) => {
|
||||
ipcMain.handle('is-ask-window-visible', (event, windowName) => {
|
||||
const window = windowPool.get(windowName);
|
||||
if (window && !window.isDestroyed()) {
|
||||
return window.isVisible();
|
||||
@ -888,15 +816,6 @@ function setupIpcHandlers(movementManager) {
|
||||
destroyFeatureWindows();
|
||||
}
|
||||
loadAndRegisterShortcuts(movementManager);
|
||||
|
||||
for (const [name, win] of windowPool) {
|
||||
if (!isAllowed(name) && !win.isDestroyed()) {
|
||||
win.hide();
|
||||
}
|
||||
if (isAllowed(name) && win.isVisible()) {
|
||||
win.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('update-keybinds', (event, newKeybinds) => {
|
||||
@ -969,9 +888,6 @@ function setupIpcHandlers(movementManager) {
|
||||
|
||||
setupApiKeyIPC();
|
||||
|
||||
ipcMain.handle('resize-window', () => {});
|
||||
|
||||
ipcMain.handle('resize-for-view', () => {});
|
||||
|
||||
ipcMain.handle('resize-header-window', (event, { width, height }) => {
|
||||
const header = windowPool.get('header');
|
||||
@ -1024,74 +940,19 @@ function setupIpcHandlers(movementManager) {
|
||||
return { success: false, error: 'Header window not found' };
|
||||
});
|
||||
|
||||
ipcMain.on('header-animation-complete', (event, state) => {
|
||||
ipcMain.on('header-animation-finished', (event, state) => {
|
||||
const header = windowPool.get('header');
|
||||
if (!header) return;
|
||||
|
||||
if (!header || header.isDestroyed()) return;
|
||||
|
||||
if (state === 'hidden') {
|
||||
header.hide();
|
||||
console.log('[WindowManager] Header hidden after animation.');
|
||||
} else if (state === 'visible') {
|
||||
lastVisibleWindows.forEach(name => {
|
||||
if (name === 'header') return;
|
||||
const win = windowPool.get(name);
|
||||
if (win) win.show();
|
||||
});
|
||||
|
||||
setImmediate(updateLayout);
|
||||
setTimeout(updateLayout, 120);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-header-position', () => {
|
||||
const header = windowPool.get('header');
|
||||
if (header) {
|
||||
const [x, y] = header.getPosition();
|
||||
return { x, y };
|
||||
}
|
||||
return { x: 0, y: 0 };
|
||||
});
|
||||
|
||||
ipcMain.handle('move-header', (event, newX, newY) => {
|
||||
const header = windowPool.get('header');
|
||||
if (header) {
|
||||
const currentY = newY !== undefined ? newY : header.getBounds().y;
|
||||
header.setPosition(newX, currentY, false);
|
||||
|
||||
console.log('[WindowManager] Header shown after animation.');
|
||||
updateLayout();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('move-header-to', (event, newX, newY) => {
|
||||
const header = windowPool.get('header');
|
||||
if (header) {
|
||||
const targetDisplay = screen.getDisplayNearestPoint({ x: newX, y: newY });
|
||||
const { x: workAreaX, y: workAreaY, width, height } = targetDisplay.workArea;
|
||||
const headerBounds = header.getBounds();
|
||||
|
||||
// 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);
|
||||
|
||||
updateLayout();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('move-window-step', (event, direction) => {
|
||||
if (movementManager) {
|
||||
@ -1105,13 +966,6 @@ function setupIpcHandlers(movementManager) {
|
||||
console.log(`[WindowManager] Force closing window: ${windowName}`);
|
||||
|
||||
window.webContents.send('window-hide-animation');
|
||||
|
||||
setTimeout(() => {
|
||||
if (!window.isDestroyed()) {
|
||||
window.hide();
|
||||
updateLayout();
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1405,7 +1259,7 @@ function updateGlobalShortcuts(keybinds, mainWindow, sendToRenderer, movementMan
|
||||
if (state === 'apikey') {
|
||||
if (keybinds.toggleVisibility) {
|
||||
try {
|
||||
globalShortcut.register(keybinds.toggleVisibility, () => toggleAllWindowsVisibility(movementManager));
|
||||
globalShortcut.register(keybinds.toggleVisibility, () => toggleAllWindowsVisibility());
|
||||
} catch (error) {
|
||||
console.error(`Failed to register toggleVisibility (${keybinds.toggleVisibility}):`, error);
|
||||
}
|
||||
@ -1441,7 +1295,7 @@ function updateGlobalShortcuts(keybinds, mainWindow, sendToRenderer, movementMan
|
||||
let callback;
|
||||
switch(action) {
|
||||
case 'toggleVisibility':
|
||||
callback = () => toggleAllWindowsVisibility(movementManager);
|
||||
callback = () => toggleAllWindowsVisibility();
|
||||
break;
|
||||
case 'nextStep':
|
||||
callback = () => {
|
||||
@ -1611,9 +1465,6 @@ module.exports = {
|
||||
createWindows,
|
||||
windowPool,
|
||||
fixedYPosition,
|
||||
//////// before_modelStateService ////////
|
||||
// setApiKey,
|
||||
//////// before_modelStateService ////////
|
||||
getStoredApiKey,
|
||||
getStoredProvider,
|
||||
getCurrentModelInfo,
|
||||
|
@ -41,56 +41,6 @@ export class AskView extends LitElement {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
filter: blur(0px);
|
||||
}
|
||||
30% {
|
||||
opacity: 0.7;
|
||||
transform: translateY(-20%) scale(0.98);
|
||||
filter: blur(0.5px);
|
||||
}
|
||||
70% {
|
||||
opacity: 0.3;
|
||||
transform: translateY(-80%) scale(0.92);
|
||||
filter: blur(1.5px);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(-150%) scale(0.85);
|
||||
filter: blur(2px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-150%) scale(0.85);
|
||||
filter: blur(2px);
|
||||
}
|
||||
30% {
|
||||
opacity: 0.5;
|
||||
transform: translateY(-50%) scale(0.92);
|
||||
filter: blur(1px);
|
||||
}
|
||||
65% {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-5%) scale(0.99);
|
||||
filter: blur(0.2px);
|
||||
}
|
||||
85% {
|
||||
opacity: 0.98;
|
||||
transform: translateY(2%) scale(1.005);
|
||||
filter: blur(0px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
filter: blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
@ -252,20 +202,6 @@ export class AskView extends LitElement {
|
||||
animation: fadeInOut 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
@ -422,19 +358,6 @@ export class AskView extends LitElement {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
opacity: 0.3;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
40% {
|
||||
opacity: 1;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
.response-line {
|
||||
position: relative;
|
||||
padding: 2px 0;
|
||||
@ -596,42 +519,6 @@ export class AskView extends LitElement {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* ────────────────[ GLASS BYPASS ]─────────────── */
|
||||
:host-context(body.has-glass) .ask-container,
|
||||
:host-context(body.has-glass) .response-header,
|
||||
:host-context(body.has-glass) .response-icon,
|
||||
:host-context(body.has-glass) .copy-button,
|
||||
:host-context(body.has-glass) .close-button,
|
||||
:host-context(body.has-glass) .line-copy-button,
|
||||
:host-context(body.has-glass) .text-input-container,
|
||||
:host-context(body.has-glass) .response-container pre,
|
||||
:host-context(body.has-glass) .response-container p code,
|
||||
:host-context(body.has-glass) .response-container pre code {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .ask-container::before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .copy-button:hover,
|
||||
:host-context(body.has-glass) .close-button:hover,
|
||||
:host-context(body.has-glass) .line-copy-button,
|
||||
:host-context(body.has-glass) .line-copy-button:hover,
|
||||
:host-context(body.has-glass) .response-line:hover {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .response-container::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) .response-container::-webkit-scrollbar-thumb {
|
||||
background: transparent !important;
|
||||
}
|
||||
`;
|
||||
|
||||
constructor() {
|
||||
|
@ -27,56 +27,6 @@ export class AssistantView extends LitElement {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
filter: blur(0px);
|
||||
}
|
||||
30% {
|
||||
opacity: 0.7;
|
||||
transform: translateY(-20%) scale(0.98);
|
||||
filter: blur(0.5px);
|
||||
}
|
||||
70% {
|
||||
opacity: 0.3;
|
||||
transform: translateY(-80%) scale(0.92);
|
||||
filter: blur(1.5px);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(-150%) scale(0.85);
|
||||
filter: blur(2px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-150%) scale(0.85);
|
||||
filter: blur(2px);
|
||||
}
|
||||
30% {
|
||||
opacity: 0.5;
|
||||
transform: translateY(-50%) scale(0.92);
|
||||
filter: blur(1px);
|
||||
}
|
||||
65% {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-5%) scale(0.99);
|
||||
filter: blur(0.2px);
|
||||
}
|
||||
85% {
|
||||
opacity: 0.98;
|
||||
transform: translateY(2%) scale(1.005);
|
||||
filter: blur(0px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
filter: blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
@ -245,17 +195,6 @@ export class AssistantView extends LitElement {
|
||||
animation: slideIn 0.3s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(10%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bar-controls {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
@ -349,134 +288,6 @@ export class AssistantView extends LitElement {
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
/* ────────────────[ GLASS BYPASS ]─────────────── */
|
||||
:host-context(body.has-glass) .assistant-container,
|
||||
:host-context(body.has-glass) .top-bar,
|
||||
:host-context(body.has-glass) .toggle-button,
|
||||
:host-context(body.has-glass) .copy-button,
|
||||
:host-context(body.has-glass) .transcription-container,
|
||||
:host-context(body.has-glass) .insights-container,
|
||||
:host-context(body.has-glass) .stt-message,
|
||||
:host-context(body.has-glass) .outline-item,
|
||||
:host-context(body.has-glass) .request-item,
|
||||
:host-context(body.has-glass) .markdown-content,
|
||||
:host-context(body.has-glass) .insights-container pre,
|
||||
:host-context(body.has-glass) .insights-container p code,
|
||||
:host-context(body.has-glass) .insights-container pre code {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .assistant-container::before,
|
||||
:host-context(body.has-glass) .assistant-container::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .toggle-button:hover,
|
||||
:host-context(body.has-glass) .copy-button:hover,
|
||||
:host-context(body.has-glass) .outline-item:hover,
|
||||
:host-context(body.has-glass) .request-item.clickable:hover,
|
||||
:host-context(body.has-glass) .markdown-content:hover {
|
||||
background: transparent !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .transcription-container::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) .transcription-container::-webkit-scrollbar-thumb,
|
||||
:host-context(body.has-glass) .insights-container::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) .insights-container::-webkit-scrollbar-thumb {
|
||||
background: transparent !important;
|
||||
}
|
||||
:host-context(body.has-glass) * {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
transform: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .assistant-container,
|
||||
:host-context(body.has-glass) .stt-message,
|
||||
:host-context(body.has-glass) .toggle-button,
|
||||
:host-context(body.has-glass) .copy-button {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) ::-webkit-scrollbar,
|
||||
:host-context(body.has-glass) ::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) ::-webkit-scrollbar-thumb {
|
||||
background: transparent !important;
|
||||
width: 0 !important; /* 스크롤바 자체 숨기기 */
|
||||
}
|
||||
:host-context(body.has-glass) .assistant-container,
|
||||
:host-context(body.has-glass) .top-bar,
|
||||
:host-context(body.has-glass) .toggle-button,
|
||||
:host-context(body.has-glass) .copy-button,
|
||||
:host-context(body.has-glass) .transcription-container,
|
||||
:host-context(body.has-glass) .insights-container,
|
||||
:host-context(body.has-glass) .stt-message,
|
||||
:host-context(body.has-glass) .outline-item,
|
||||
:host-context(body.has-glass) .request-item,
|
||||
:host-context(body.has-glass) .markdown-content,
|
||||
:host-context(body.has-glass) .insights-container pre,
|
||||
:host-context(body.has-glass) .insights-container p code,
|
||||
:host-context(body.has-glass) .insights-container pre code {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .assistant-container::before,
|
||||
:host-context(body.has-glass) .assistant-container::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .toggle-button:hover,
|
||||
:host-context(body.has-glass) .copy-button:hover,
|
||||
:host-context(body.has-glass) .outline-item:hover,
|
||||
:host-context(body.has-glass) .request-item.clickable:hover,
|
||||
:host-context(body.has-glass) .markdown-content:hover {
|
||||
background: transparent !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .transcription-container::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) .transcription-container::-webkit-scrollbar-thumb,
|
||||
:host-context(body.has-glass) .insights-container::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) .insights-container::-webkit-scrollbar-thumb {
|
||||
background: transparent !important;
|
||||
}
|
||||
:host-context(body.has-glass) * {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
transform: none !important;
|
||||
filter: none !important;
|
||||
backdrop-filter: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) .assistant-container,
|
||||
:host-context(body.has-glass) .stt-message,
|
||||
:host-context(body.has-glass) .toggle-button,
|
||||
:host-context(body.has-glass) .copy-button {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
:host-context(body.has-glass) ::-webkit-scrollbar,
|
||||
:host-context(body.has-glass) ::-webkit-scrollbar-track,
|
||||
:host-context(body.has-glass) ::-webkit-scrollbar-thumb {
|
||||
background: transparent !important;
|
||||
width: 0 !important;
|
||||
}
|
||||
`;
|
||||
|
||||
static properties = {
|
||||
|
@ -412,7 +412,7 @@ export class SummaryView extends LitElement {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
try {
|
||||
const isAskViewVisible = await ipcRenderer.invoke('is-window-visible', 'ask');
|
||||
const isAskViewVisible = await ipcRenderer.invoke('is-ask-window-visible', 'ask');
|
||||
|
||||
if (!isAskViewVisible) {
|
||||
await ipcRenderer.invoke('toggle-feature', 'ask');
|
||||
|
@ -367,11 +367,6 @@ export class SettingsView extends LitElement {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
@ -1030,14 +1025,14 @@ export class SettingsView extends LitElement {
|
||||
handleMouseEnter = () => {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.send('cancel-hide-window', 'settings');
|
||||
ipcRenderer.send('cancel-hide-settings-window');
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseLeave = () => {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.send('hide-window', 'settings');
|
||||
ipcRenderer.send('hide-settings-window');
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user