centralized keyframe
This commit is contained in:
		
							parent
							
								
									ae24d49fe5
								
							
						
					
					
						commit
						186f0a9839
					
				@ -15,15 +15,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) {
 | 
			
		||||
@ -31,17 +30,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;
 | 
			
		||||
@ -50,6 +38,7 @@ export class ApiKeyHeader extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .container {
 | 
			
		||||
            -webkit-app-region: drag;
 | 
			
		||||
            width: 350px;
 | 
			
		||||
            min-height: 260px;
 | 
			
		||||
            padding: 18px 20px;
 | 
			
		||||
@ -79,6 +68,7 @@ export class ApiKeyHeader extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .close-button {
 | 
			
		||||
            -webkit-app-region: no-drag;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: 10px;
 | 
			
		||||
            right: 10px;
 | 
			
		||||
@ -135,6 +125,7 @@ export class ApiKeyHeader extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .api-input {
 | 
			
		||||
            -webkit-app-region: no-drag;
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            height: 34px;
 | 
			
		||||
            background: rgba(255, 255, 255, 0.1);
 | 
			
		||||
@ -162,6 +153,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;
 | 
			
		||||
@ -188,6 +180,7 @@ export class ApiKeyHeader extends LitElement {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        .action-button {
 | 
			
		||||
            -webkit-app-region: no-drag;
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            height: 34px;
 | 
			
		||||
            background: rgba(255, 255, 255, 0.2);
 | 
			
		||||
@ -233,37 +226,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 = ""
 | 
			
		||||
    //////// after_modelStateService ////////
 | 
			
		||||
@ -275,8 +241,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)
 | 
			
		||||
@ -321,61 +285,6 @@ export class ApiKeyHeader extends LitElement {
 | 
			
		||||
    if (sttProviders.length > 0) this.sttProvider = sttProviders[0].id;
 | 
			
		||||
    
 | 
			
		||||
    this.requestUpdate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  async handleMouseDown(e) {
 | 
			
		||||
    if (e.target.tagName === "INPUT" || e.target.tagName === "BUTTON" || e.target.tagName === "SELECT") {
 | 
			
		||||
      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)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleInput(e) {
 | 
			
		||||
@ -473,7 +382,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) {
 | 
			
		||||
@ -515,7 +423,7 @@ export class ApiKeyHeader extends LitElement {
 | 
			
		||||
    const isButtonDisabled = this.isLoading || !this.llmApiKey.trim() || !this.sttApiKey.trim();
 | 
			
		||||
 | 
			
		||||
    return html`
 | 
			
		||||
        <div class="container" @mousedown=${this.handleMouseDown}>
 | 
			
		||||
        <div class="container">
 | 
			
		||||
            <h1 class="title">Enter Your API Keys</h1>
 | 
			
		||||
 | 
			
		||||
            <div class="providers-container">
 | 
			
		||||
 | 
			
		||||
@ -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,16 +338,12 @@ 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;
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            console.log(`[MainHeader] showWindow('${name}') called at ${Date.now()}`);
 | 
			
		||||
@ -564,7 +368,6 @@ export class MainHeader extends LitElement {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hideWindow(name) {
 | 
			
		||||
        if (this.wasJustDragged) return;
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            console.log(`[MainHeader] hideWindow('${name}') called at ${Date.now()}`);
 | 
			
		||||
            window.require('electron').ipcRenderer.send('hide-window', name);
 | 
			
		||||
@ -600,7 +403,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')}
 | 
			
		||||
 | 
			
		||||
@ -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" />
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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;
 | 
			
		||||
}
 | 
			
		||||
@ -359,12 +359,6 @@ function toggleAllWindowsVisibility(movementManager) {
 | 
			
		||||
            if (win.isVisible()) {
 | 
			
		||||
                lastVisibleWindows.add(name);
 | 
			
		||||
                if (name !== 'header') {
 | 
			
		||||
                    // win.webContents.send('window-hide-animation');
 | 
			
		||||
                    // setTimeout(() => {
 | 
			
		||||
                    //     if (!win.isDestroyed()) {
 | 
			
		||||
                    //         win.hide();
 | 
			
		||||
                    //     }
 | 
			
		||||
                    // }, 200);
 | 
			
		||||
                    win.hide();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -460,6 +454,7 @@ function createWindows() {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    windowPool.set('header', header);
 | 
			
		||||
    header.on('moved', updateLayout);
 | 
			
		||||
    layoutManager = new WindowLayoutManager(windowPool);
 | 
			
		||||
 | 
			
		||||
    header.webContents.once('dom-ready', () => {
 | 
			
		||||
@ -586,13 +581,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);
 | 
			
		||||
@ -621,13 +609,6 @@ function createWindows() {
 | 
			
		||||
                    } else {
 | 
			
		||||
                        windowToToggle.webContents.send('window-hide-animation');
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    setTimeout(() => {
 | 
			
		||||
                        if (!windowToToggle.isDestroyed()) {
 | 
			
		||||
                            windowToToggle.hide();
 | 
			
		||||
                            updateLayout();
 | 
			
		||||
                        }
 | 
			
		||||
                    }, 250);
 | 
			
		||||
                } else {
 | 
			
		||||
                    try {
 | 
			
		||||
                        windowToToggle.show();
 | 
			
		||||
@ -763,6 +744,14 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    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-window', (event, args) => {
 | 
			
		||||
        const { name, bounds } = typeof args === 'object' && args !== null ? args : { name: args, bounds: null };
 | 
			
		||||
        const win = windowPool.get(name);
 | 
			
		||||
@ -811,8 +800,6 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
                    clearTimeout(settingsHideTimer);
 | 
			
		||||
                }
 | 
			
		||||
                settingsHideTimer = setTimeout(() => {
 | 
			
		||||
                    // window.setAlwaysOnTop(false);
 | 
			
		||||
                    // window.hide();
 | 
			
		||||
                    if (window && !window.isDestroyed()) {
 | 
			
		||||
                        window.setAlwaysOnTop(false);
 | 
			
		||||
                        window.hide();
 | 
			
		||||
@ -1014,74 +1001,20 @@ 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);
 | 
			
		||||
 | 
			
		||||
            // 자식 창들을 다시 보여주는 로직은 toggleAllWindowsVisibility에 이미 있으므로 여기서는 중복 작업을 피합니다.
 | 
			
		||||
            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) {
 | 
			
		||||
@ -1095,13 +1028,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);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 = {
 | 
			
		||||
 | 
			
		||||
@ -366,11 +366,6 @@ export class SettingsView extends LitElement {
 | 
			
		||||
            margin-right: 6px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @keyframes spin {
 | 
			
		||||
            0% { transform: rotate(0deg); }
 | 
			
		||||
            100% { transform: rotate(360deg); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .hidden {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
@ -410,30 +405,7 @@ export class SettingsView extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
        .model-item { padding: 5px 8px; font-size: 11px; border-radius: 3px; cursor: pointer; transition: background-color 0.15s; }
 | 
			
		||||
        .model-item:hover { background-color: rgba(255,255,255,0.1); }
 | 
			
		||||
        .model-item.selected { background-color: rgba(0, 122, 255, 0.4); font-weight: 500; }
 | 
			
		||||
            
 | 
			
		||||
        /* ────────────────[ GLASS BYPASS ]─────────────── */
 | 
			
		||||
        :host-context(body.has-glass) {
 | 
			
		||||
            animation: none !important;
 | 
			
		||||
            transition: none !important;
 | 
			
		||||
            transform: none !important;
 | 
			
		||||
            will-change: auto !important;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        :host-context(body.has-glass) * {
 | 
			
		||||
            background: transparent !important;
 | 
			
		||||
            filter: none !important;
 | 
			
		||||
            backdrop-filter: none !important;
 | 
			
		||||
            box-shadow: none !important;
 | 
			
		||||
            outline: none !important;
 | 
			
		||||
            border: none !important;
 | 
			
		||||
            border-radius: 0 !important;
 | 
			
		||||
            transition: none !important;
 | 
			
		||||
            animation: none !important;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        :host-context(body.has-glass) .settings-container::before {
 | 
			
		||||
            display: none !important;
 | 
			
		||||
        .model-item.selected { background-color: rgba(0, 122, 255, 0.4); font-weight: 500;
 | 
			
		||||
        }
 | 
			
		||||
    `;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user