| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Voice Dialogue</title> |
| | <style> |
| | :root { |
| | --mac-accent: #0071e3; |
| | --mac-accent-light: #2d8aeb; |
| | --mac-accent-dark: #0060bf; |
| | --mac-bg: #f5f5f7; |
| | --mac-text: #1d1d1f; |
| | --mac-text-secondary: #86868b; |
| | --mac-white: #ffffff; |
| | --mac-border-radius: 10px; |
| | --mac-blur-bg: rgba(255, 255, 255, 0.7); |
| | } |
| | |
| | * { |
| | margin: 0; |
| | padding: 0; |
| | box-sizing: border-box; |
| | } |
| | |
| | body { |
| | margin: 0; |
| | padding: 0; |
| | display: flex; |
| | justify-content: center; |
| | align-items: center; |
| | min-height: 100vh; |
| | background-color: var(--mac-bg); |
| | font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; |
| | overflow: hidden; |
| | position: relative; |
| | } |
| | |
| | .window-container { |
| | width: 480px; |
| | max-width: 90%; |
| | backdrop-filter: blur(20px); |
| | -webkit-backdrop-filter: blur(20px); |
| | background-color: var(--mac-blur-bg); |
| | border-radius: 12px; |
| | box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); |
| | overflow: hidden; |
| | animation: fadeIn 0.5s ease; |
| | } |
| | |
| | .window-header { |
| | height: 40px; |
| | width: 100%; |
| | display: flex; |
| | align-items: center; |
| | position: fixed; |
| | top: 4px; |
| | left: 12px; |
| | -webkit-app-region: drag; |
| | cursor: move; |
| | } |
| | |
| | .window-controls { |
| | display: flex; |
| | -webkit-app-region: no-drag; |
| | cursor: pointer; |
| | } |
| | |
| | .window-button { |
| | width: 24px; |
| | height: 24px; |
| | border: none; |
| | background: transparent; |
| | border-radius: 4px; |
| | cursor: pointer; |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | transition: background-color 0.2s; |
| | padding: 0; |
| | } |
| | |
| | |
| | .window-button img { |
| | width: 12px; |
| | height: 12px; |
| | transition: opacity 0.2s; |
| | } |
| | |
| | .window-button .focus-icon { |
| | display: none; |
| | } |
| | .window-controls:hover .window-button .default-icon, |
| | .window-controls:focus-within .window-button .default-icon { |
| | display: none; |
| | } |
| | |
| | .window-controls:hover .window-button .focus-icon, |
| | .window-controls:focus-within .window-button .focus-icon { |
| | display: inline; |
| | } |
| | |
| | .window-title { |
| | position: absolute; |
| | left: 0; |
| | right: 0; |
| | text-align: center; |
| | color: var(--mac-text-secondary); |
| | font-size: 13px; |
| | font-weight: 500; |
| | } |
| | |
| | .window-content { |
| | padding: 40px 30px; |
| | width: 100%; |
| | display: flex; |
| | flex-direction: column; |
| | align-items: center; |
| | } |
| | |
| | .app-icon { |
| | width: 80px; |
| | height: 80px; |
| | margin-bottom: 24px; |
| | position: relative; |
| | animation: iconPulse 2s ease-in-out infinite; |
| | } |
| | |
| | .app-icon-inner { |
| | width: 80px; |
| | height: 80px; |
| | border-radius: 20px; |
| | background: linear-gradient(135deg, #5AC8FA, #007AFF); |
| | box-shadow: 1px 1px 6px 2px rgba(0, 122, 255, 0.3); |
| | display: flex; |
| | justify-content: center; |
| | align-items: center; |
| | color: white; |
| | font-size: 40px; |
| | font-weight: 600; |
| | } |
| | |
| | .app-title { |
| | color: var(--mac-text); |
| | font-size: 22px; |
| | font-weight: 600; |
| | margin-bottom: 8px; |
| | } |
| | |
| | .app-subtitle { |
| | color: var(--mac-text-secondary); |
| | font-size: 14px; |
| | margin-bottom: 32px; |
| | text-align: center; |
| | max-width: 340px; |
| | } |
| | |
| | .spinner { |
| | width: 22px; |
| | height: 22px; |
| | margin-bottom: 24px; |
| | border: 2px solid rgba(0, 113, 227, 0.2); |
| | border-left-color: var(--mac-accent); |
| | border-radius: 50%; |
| | animation: spin 1s linear infinite; |
| | } |
| | |
| | .progress-container { |
| | width: 80%; |
| | height: 6px; |
| | background-color: rgba(0, 113, 227, 0.1); |
| | border-radius: 3px; |
| | overflow: hidden; |
| | margin-bottom: 12px; |
| | } |
| | |
| | .progress-bar { |
| | height: 100%; |
| | background-color: var(--mac-accent); |
| | width: 0%; |
| | transition: width 0.4s ease; |
| | border-radius: 3px; |
| | } |
| | |
| | .status-container { |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | width: 80%; |
| | margin-bottom: 28px; |
| | } |
| | .status-text { |
| | color: var(--mac-text-secondary); |
| | font-size: 12px; |
| | } |
| | |
| | .percent-text { |
| | color: var(--mac-text-secondary); |
| | font-size: 12px; |
| | font-feature-settings: "tnum"; |
| | font-variant-numeric: tabular-nums; |
| | } |
| | |
| | .notification { |
| | width: 80%; |
| | padding: 14px; |
| | border-radius: 8px; |
| | background-color: rgba(0, 0, 0, 0.03); |
| | display: flex; |
| | align-items: flex-start; |
| | margin-top: 8px; |
| | } |
| | |
| | .notification-icon { |
| | margin-right: 12px; |
| | margin-top: 2px; |
| | } |
| | |
| | .notification-icon svg { |
| | width: 16px; |
| | height: 16px; |
| | color: var(--mac-accent); |
| | } |
| | |
| | .notification-content { |
| | flex: 1; |
| | } |
| | |
| | .notification-title { |
| | font-size: 13px; |
| | font-weight: 500; |
| | color: var(--mac-text); |
| | margin-bottom: 4px; |
| | } |
| | |
| | .notification-text { |
| | font-size: 12px; |
| | color: var(--mac-text-secondary); |
| | line-height: 1.5; |
| | } |
| | |
| | @keyframes spin { |
| | 0% { transform: rotate(0deg); } |
| | 100% { transform: rotate(360deg); } |
| | } |
| | |
| | @keyframes iconPulse { |
| | 0% { transform: scale(1); } |
| | 50% { transform: scale(1.05); } |
| | 100% { transform: scale(1); } |
| | } |
| | |
| | @keyframes fadeIn { |
| | 0% { opacity: 0; transform: translateY(10px); } |
| | 100% { opacity: 1; transform: translateY(0); } |
| | } |
| | |
| | @keyframes warningPulse { |
| | 0% { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); } |
| | 50% { box-shadow: 0 8px 32px rgba(255, 193, 7, 0.3); } |
| | 100% { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); } |
| | } |
| | |
| | .notification.warning-theme { |
| | animation: warningPulse 1s ease-in-out infinite; |
| | background-color: rgba(255, 0, 0, 0.1); |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <div class="window-header"> |
| | <div class="window-controls"> |
| | <button class="window-button close" onclick="closeWindow()"> |
| | <img class="default-icon" |
| | src="./assets/images/red.png" |
| | alt="close"> |
| | <img class="focus-icon" |
| | src="./assets/images/close.png" |
| | alt="close-focus"> |
| | </button> |
| | <button class="window-button minimize" onclick="minimizeWindow()"> |
| | <img class="default-icon" |
| | src="./assets/images/yellow.png" |
| | alt="minimize"> |
| | <img class="focus-icon" |
| | src="./assets/images/min.png" |
| | alt="minimize-focus"> |
| | </button> |
| | <button class="window-button maximize" onclick="maximizeWindow()"> |
| | <img class="default-icon" |
| | src="./assets/images/green.png" |
| | alt="maximize"> |
| | <img class="focus-icon" |
| | src="./assets/images/max.png" |
| | alt="maximize-focus"> |
| | </button> |
| | </div> |
| | </div> |
| | <div class="window-content"> |
| | <div class="app-icon"> |
| | <div class="app-icon-inner"><img width="100" height="100" src="./build/icon.png" alt=""></div> |
| | </div> |
| | <h1 class="app-title">Voice Dialogue</h1> |
| | |
| | <p class="app-subtitle"> </p> |
| | <div class="spinner"></div> |
| | <p class="app-subtitle"> </p> |
| | <div class="progress-container"> |
| | <div class="progress-bar" id="progressBar"></div> |
| | </div> |
| |
|
| | <div class="status-container"> |
| | <div class="status-text" id="statusText">Initializing...</div> |
| | <div class="percent-text" id="percentText">0%</div> |
| | </div> |
| |
|
| | <div class="notification info-theme" id="firstRunNotification" style="display: none;"> |
| | <div class="notification-icon"> |
| | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> |
| | <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" /> |
| | </svg> |
| | </div> |
| | <div class="notification-content"> |
| | <h3 class="notification-title">First Launch Notice</h3> |
| | <p class="notification-text"> |
| | First launch may take longer as we set up your environment and optimize resources. Subsequent launches will be much faster. |
| | </p> |
| | </div> |
| | </div> |
| |
|
| | <div class="notification warning-theme" id="resourceWarningNotification" style="display: none;"> |
| | <div class="notification-icon"> |
| | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="color: #ffc107;"> |
| | <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" /> |
| | </svg> |
| | </div> |
| | <div class="notification-content"> |
| | <h3 class="notification-title">System Resource Warning</h3> |
| | <p class="notification-text" id="resourceWarningText"> |
| | Your system resources are running low. This may affect app performance. Please consider closing other applications or freeing up memory. |
| | </p> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | |
| | function minimizeWindow () |
| | { |
| | if (window.electronAPI && window.electronAPI.minimizeWindow) { |
| | window.electronAPI.minimizeWindow(); |
| | } else { |
| | console.warn('Electron API not available'); |
| | } |
| | } |
| | |
| | function maximizeWindow () |
| | { |
| | if (window.electronAPI && window.electronAPI.maximizeWindow) { |
| | window.electronAPI.maximizeWindow(); |
| | } else { |
| | console.warn('Electron API not available'); |
| | } |
| | } |
| | |
| | function closeWindow () |
| | { |
| | if (window.electronAPI && window.electronAPI.closeWindow) { |
| | window.electronAPI.closeWindow(); |
| | } else { |
| | console.warn('Electron API not available'); |
| | } |
| | } |
| | |
| | async function checkFirstRun() { |
| | try { |
| | if (window.electronAPI && window.electronAPI.getFirstRunStatus) { |
| | const isFirstRun = await window.electronAPI.getFirstRunStatus(); |
| | console.log('isFirstRun', isFirstRun); |
| | if (isFirstRun) { |
| | const notification = document.getElementById('firstRunNotification'); |
| | if (notification) { |
| | notification.style.display = 'flex'; |
| | } |
| | } |
| | } |
| | } catch (error) { |
| | console.log('Could not check first run status:', error); |
| | } |
| | } |
| | |
| | |
| | checkFirstRun(); |
| | |
| | |
| | async function checkSystemResources() { |
| | try { |
| | if (window.electronAPI && window.electronAPI.getSystemCpuUsage && window.electronAPI.getSystemFreeMemory) { |
| | const [cpuUsage, memoryFree] = await Promise.all([ |
| | window.electronAPI.getSystemCpuUsage(), |
| | window.electronAPI.getSystemFreeMemory() |
| | ]); |
| | |
| | console.log('CPU Usage:', cpuUsage + '%'); |
| | console.log('Memory Info:', memoryFree); |
| | |
| | |
| | const isCpuHigh = cpuUsage > 80; |
| | const isMemoryLow = memoryFree < 3; |
| | console.log('isCpuHigh', isCpuHigh); |
| | console.log('isMemoryLow', isMemoryLow); |
| | if (isCpuHigh || isMemoryLow) { |
| | const notification = document.getElementById('resourceWarningNotification'); |
| | const warningText = document.getElementById('resourceWarningText'); |
| | |
| | let warningMessage = ''; |
| | if (isCpuHigh && isMemoryLow) { |
| | warningMessage = `High CPU usage and insufficient memory detected. This may significantly affect app performance. Please close other applications to free up resources.`; |
| | } else if (isCpuHigh) { |
| | warningMessage = `High CPU usage detected. This may affect app performance. Please close CPU-intensive applications.`; |
| | } else if (isMemoryLow) { |
| | warningMessage = `Insufficient memory detected. This may affect app performance. Please close some applications to free up memory.`; |
| | } |
| | |
| | warningText.textContent = warningMessage; |
| | notification.style.display = 'flex'; |
| | notification.classList.add('warning-notification'); |
| | } |
| | } |
| | } catch (error) { |
| | console.log('Could not check system resources:', error); |
| | } |
| | } |
| | |
| | checkSystemResources(); |
| | |
| | let progress = 0; |
| | const progressBar = document.getElementById('progressBar'); |
| | const percentText = document.getElementById('percentText'); |
| | const statusText = document.getElementById('statusText'); |
| | |
| | const statusMessages = [ |
| | "Initializing...", |
| | "Checking system requirements...", |
| | "Loading components...", |
| | "Preparing documents...", |
| | "Optimizing performance...", |
| | "Almost ready..." |
| | ]; |
| | |
| | function updateProgress() { |
| | if (progress < 100) { |
| | |
| | let increment; |
| | |
| | if (progress < 20) { |
| | |
| | increment = Math.random() * 2 + 0.5; |
| | } else if (progress < 50) { |
| | |
| | increment = Math.random() * 1 + 0.2; |
| | } else if (progress < 85) { |
| | |
| | increment = Math.random() * 1.5 + 0.3; |
| | } else { |
| | |
| | increment = Math.random() * 0.8 + 0.1; |
| | |
| | |
| | if (progress > 99) progress = 99; |
| | } |
| | |
| | progress += increment; |
| | progress = Math.min(progress, 99.9); |
| | |
| | |
| | progressBar.style.width = progress + '%'; |
| | percentText.textContent = Math.floor(progress) + '%'; |
| | |
| | |
| | const statusIndex = Math.min(Math.floor(progress / 20), statusMessages.length - 1); |
| | statusText.textContent = statusMessages[statusIndex]; |
| | |
| | |
| | let delay; |
| | if (progress < 30) { |
| | delay = 100 + Math.random() * 200; |
| | } else if (progress < 60) { |
| | delay = 200 + Math.random() * 300; |
| | } else if (progress < 85) { |
| | delay = 150 + Math.random() * 250; |
| | } else { |
| | delay = 300 + Math.random() * 500; |
| | } |
| | |
| | setTimeout(updateProgress, delay); |
| | } else { |
| | |
| | progressBar.style.width = '100%'; |
| | percentText.textContent = '100%'; |
| | statusText.textContent = 'Ready'; |
| | |
| | |
| | } |
| | } |
| | |
| | |
| | setTimeout(updateProgress, 600); |
| | </script> |
| | </body> |
| | </html> |
| |
|