| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Aron - Your AI Productivity Assistant</title> |
| | <script src="https://cdn.tailwindcss.com"></script> |
| | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| | <style> |
| | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap'); |
| | |
| | body { |
| | font-family: 'Roboto', sans-serif; |
| | background-color: #0a0a0a; |
| | color: #00ff9d; |
| | height: 100vh; |
| | overflow: hidden; |
| | } |
| | |
| | .terminal-text { |
| | color: #00ff9d; |
| | text-shadow: 0 0 5px rgba(0, 255, 157, 0.3); |
| | } |
| | |
| | .pulse { |
| | animation: pulse 2s infinite; |
| | } |
| | |
| | @keyframes pulse { |
| | 0% { opacity: 0.7; } |
| | 50% { opacity: 1; } |
| | 100% { opacity: 0.7; } |
| | } |
| | |
| | .message-bubble { |
| | max-width: 80%; |
| | border-radius: 18px; |
| | padding: 12px 16px; |
| | margin-bottom: 12px; |
| | position: relative; |
| | animation: fadeIn 0.3s ease-out; |
| | } |
| | |
| | @keyframes fadeIn { |
| | from { opacity: 0; transform: translateY(10px); } |
| | to { opacity: 1; transform: translateY(0); } |
| | } |
| | |
| | .user-message { |
| | background-color: #1a2e1a; |
| | align-self: flex-end; |
| | border-bottom-right-radius: 4px; |
| | } |
| | |
| | .aron-message { |
| | background-color: #0d1a0d; |
| | align-self: flex-start; |
| | border-bottom-left-radius: 4px; |
| | } |
| | |
| | .typing-indicator span { |
| | display: inline-block; |
| | width: 8px; |
| | height: 8px; |
| | border-radius: 50%; |
| | background-color: #00ff9d; |
| | margin-right: 4px; |
| | animation: bounce 1.5s infinite ease-in-out; |
| | } |
| | |
| | .typing-indicator span:nth-child(2) { |
| | animation-delay: 0.2s; |
| | } |
| | |
| | .typing-indicator span:nth-child(3) { |
| | animation-delay: 0.4s; |
| | } |
| | |
| | @keyframes bounce { |
| | 0%, 100% { transform: translateY(0); } |
| | 50% { transform: translateY(-5px); } |
| | } |
| | |
| | .glow-border { |
| | border: 1px solid #00ff9d; |
| | box-shadow: 0 0 10px rgba(0, 255, 157, 0.3); |
| | } |
| | |
| | .task-item { |
| | border-left: 3px solid #00ff9d; |
| | transition: all 0.3s ease; |
| | } |
| | |
| | .task-item:hover { |
| | background-color: #0d1a0d; |
| | } |
| | |
| | |
| | ::-webkit-scrollbar { |
| | width: 6px; |
| | } |
| | |
| | ::-webkit-scrollbar-track { |
| | background: #000; |
| | } |
| | |
| | ::-webkit-scrollbar-thumb { |
| | background: #00ff9d; |
| | border-radius: 3px; |
| | } |
| | |
| | .status-indicator { |
| | width: 10px; |
| | height: 10px; |
| | border-radius: 50%; |
| | display: inline-block; |
| | margin-right: 6px; |
| | } |
| | |
| | .status-listening { |
| | background-color: #00ff9d; |
| | box-shadow: 0 0 5px #00ff9d; |
| | } |
| | |
| | .status-waiting { |
| | background-color: #ff9900; |
| | box-shadow: 0 0 5px #ff9900; |
| | } |
| | |
| | .status-off { |
| | background-color: #ff3333; |
| | box-shadow: 0 0 5px #ff3333; |
| | } |
| | </style> |
| | </head> |
| | <body class="flex flex-col h-screen"> |
| | |
| | <header class="bg-black p-4 border-b border-green-500 flex justify-between items-center"> |
| | <div class="flex items-center"> |
| | <div class="w-10 h-10 rounded-full bg-green-900 flex items-center justify-center mr-3"> |
| | <i class="fas fa-robot text-green-400 text-xl"></i> |
| | </div> |
| | <div> |
| | <h1 class="text-green-400 font-bold text-xl">Aron</h1> |
| | <p class="text-green-600 text-xs flex items-center"> |
| | <span id="statusIndicator" class="status-indicator status-off"></span> |
| | <span id="statusText">Offline</span> |
| | </p> |
| | </div> |
| | </div> |
| | <div class="flex items-center space-x-3"> |
| | <button id="voiceBtn" class="w-10 h-10 rounded-full bg-green-900 flex items-center justify-center"> |
| | <i class="fas fa-microphone text-green-400"></i> |
| | </button> |
| | <button id="settingsBtn" class="w-10 h-10 rounded-full bg-green-900 flex items-center justify-center"> |
| | <i class="fas fa-cog text-green-400"></i> |
| | </button> |
| | </div> |
| | </header> |
| |
|
| | |
| | <main class="flex-1 overflow-hidden flex flex-col"> |
| | |
| | <div id="chatArea" class="flex-1 overflow-y-auto p-4 space-y-3"> |
| | |
| | <div class="message-bubble aron-message"> |
| | <p class="terminal-text">Hello! I'm Aron, your AI productivity assistant. Say "Hey Aron" or tap the mic button to get started.</p> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="taskList" class="hidden flex-1 overflow-y-auto p-4"> |
| | <div class="flex justify-between items-center mb-4"> |
| | <h2 class="text-xl font-bold text-green-400">Your Tasks</h2> |
| | <button id="addTaskBtn" class="bg-green-900 text-green-400 px-3 py-1 rounded-lg flex items-center"> |
| | <i class="fas fa-plus mr-1"></i> Add Task |
| | </button> |
| | </div> |
| | |
| | <div id="tasksContainer" class="space-y-2"> |
| | |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="addTaskModal" class="hidden fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50"> |
| | <div class="bg-black border border-green-500 rounded-lg p-6 w-full max-w-md mx-4"> |
| | <h3 class="text-xl font-bold text-green-400 mb-4">Add New Task</h3> |
| | |
| | <div class="mb-4"> |
| | <label class="block text-green-400 mb-2">Task Name</label> |
| | <input type="text" id="taskNameInput" class="w-full bg-black border border-green-500 rounded-lg px-3 py-2 text-green-400 focus:outline-none focus:ring-1 focus:ring-green-500"> |
| | </div> |
| | |
| | <div class="mb-4"> |
| | <label class="block text-green-400 mb-2">Due Date</label> |
| | <input type="datetime-local" id="taskDateInput" class="w-full bg-black border border-green-500 rounded-lg px-3 py-2 text-green-400 focus:outline-none focus:ring-1 focus:ring-green-500"> |
| | </div> |
| | |
| | <div class="flex justify-end space-x-3"> |
| | <button id="cancelTaskBtn" class="px-4 py-2 border border-green-500 text-green-400 rounded-lg">Cancel</button> |
| | <button id="saveTaskBtn" class="px-4 py-2 bg-green-900 text-green-400 rounded-lg">Save Task</button> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="p-4 border-t border-green-500"> |
| | <div id="voiceInputIndicator" class="hidden mb-2 text-center"> |
| | <div class="inline-block bg-green-900 px-4 py-2 rounded-full"> |
| | <span class="typing-indicator"> |
| | <span></span> |
| | <span></span> |
| | <span></span> |
| | </span> |
| | <span class="text-green-400 ml-2">Listening for "Hey Aron"...</span> |
| | </div> |
| | </div> |
| | |
| | <div class="flex items-center"> |
| | <input type="text" id="messageInput" placeholder="Type your message or say 'Hey Aron'..." class="flex-1 bg-black border border-green-500 rounded-l-lg px-4 py-3 text-green-400 focus:outline-none focus:ring-1 focus:ring-green-500"> |
| | <button id="sendBtn" class="bg-green-900 text-green-400 px-4 py-3 rounded-r-lg"> |
| | <i class="fas fa-paper-plane"></i> |
| | </button> |
| | </div> |
| | </div> |
| | </main> |
| |
|
| | |
| | <nav class="bg-black border-t border-green-500 flex justify-around p-2"> |
| | <button id="chatTab" class="flex flex-col items-center p-2 text-green-400"> |
| | <i class="fas fa-comment-dots text-xl"></i> |
| | <span class="text-xs mt-1">Chat</span> |
| | </button> |
| | <button id="tasksTab" class="flex flex-col items-center p-2 text-green-600"> |
| | <i class="fas fa-tasks text-xl"></i> |
| | <span class="text-xs mt-1">Tasks</span> |
| | </button> |
| | <button id="remindersTab" class="flex flex-col items-center p-2 text-green-600"> |
| | <i class="fas fa-bell text-xl"></i> |
| | <span class="text-xs mt-1">Reminders</span> |
| | </button> |
| | <button id="helpTab" class="flex flex-col items-center p-2 text-green-600"> |
| | <i class="fas fa-question-circle text-xl"></i> |
| | <span class="text-xs mt-1">Help</span> |
| | </button> |
| | </nav> |
| |
|
| | |
| | <div id="voiceModal" class="hidden fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50"> |
| | <div class="bg-black border-2 border-green-500 rounded-full w-64 h-64 flex items-center justify-center flex-col"> |
| | <div class="pulse mb-4"> |
| | <i class="fas fa-microphone text-green-400 text-4xl"></i> |
| | </div> |
| | <p class="text-green-400 text-center">Listening...<br>Say "Hey Aron" followed by your command</p> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | |
| | const chatArea = document.getElementById('chatArea'); |
| | const messageInput = document.getElementById('messageInput'); |
| | const sendBtn = document.getElementById('sendBtn'); |
| | const voiceBtn = document.getElementById('voiceBtn'); |
| | const voiceInputIndicator = document.getElementById('voiceInputIndicator'); |
| | const voiceModal = document.getElementById('voiceModal'); |
| | const chatTab = document.getElementById('chatTab'); |
| | const tasksTab = document.getElementById('tasksTab'); |
| | const taskList = document.getElementById('taskList'); |
| | const tasksContainer = document.getElementById('tasksContainer'); |
| | const addTaskBtn = document.getElementById('addTaskBtn'); |
| | const addTaskModal = document.getElementById('addTaskModal'); |
| | const taskNameInput = document.getElementById('taskNameInput'); |
| | const taskDateInput = document.getElementById('taskDateInput'); |
| | const saveTaskBtn = document.getElementById('saveTaskBtn'); |
| | const cancelTaskBtn = document.getElementById('cancelTaskBtn'); |
| | const statusIndicator = document.getElementById('statusIndicator'); |
| | const statusText = document.getElementById('statusText'); |
| | |
| | |
| | let tasks = [ |
| | { id: 1, name: "Complete project presentation", due: new Date(Date.now() + 86400000).toISOString().slice(0, 16), completed: false }, |
| | { id: 2, name: "Buy groceries", due: new Date(Date.now() + 3600000).toISOString().slice(0, 16), completed: false }, |
| | { id: 3, name: "Morning workout", due: new Date().toISOString().slice(0, 16), completed: true } |
| | ]; |
| | |
| | |
| | const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; |
| | const SpeechSynthesisUtterance = window.SpeechSynthesisUtterance; |
| | const synth = window.speechSynthesis; |
| | |
| | let recognition; |
| | let isListening = false; |
| | let wakeWordDetected = false; |
| | let finalTranscript = ''; |
| | let apiKey = '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'; |
| | |
| | |
| | function init() { |
| | if (SpeechRecognition) { |
| | setupSpeechRecognition(); |
| | updateStatus('waiting'); |
| | } else { |
| | updateStatus('off'); |
| | addAronMessage("Your browser doesn't support speech recognition. Please use Chrome or Edge for full functionality."); |
| | } |
| | |
| | renderTasks(); |
| | setupEventListeners(); |
| | simulateInitialGreeting(); |
| | checkForReminders(); |
| | } |
| | |
| | |
| | function setupSpeechRecognition() { |
| | recognition = new SpeechRecognition(); |
| | recognition.continuous = true; |
| | recognition.interimResults = true; |
| | recognition.maxAlternatives = 1; |
| | |
| | recognition.onstart = () => { |
| | isListening = true; |
| | updateStatus('listening'); |
| | }; |
| | |
| | recognition.onend = () => { |
| | isListening = false; |
| | if (!wakeWordDetected) { |
| | updateStatus('waiting'); |
| | } |
| | }; |
| | |
| | recognition.onresult = (event) => { |
| | let interimTranscript = ''; |
| | |
| | for (let i = event.resultIndex; i < event.results.length; i++) { |
| | const transcript = event.results[i][0].transcript; |
| | |
| | if (event.results[i].isFinal) { |
| | finalTranscript += transcript; |
| | |
| | |
| | if (finalTranscript.toLowerCase().includes('hey aron') || finalTranscript.toLowerCase().includes('aron')) { |
| | wakeWordDetected = true; |
| | finalTranscript = finalTranscript.toLowerCase().replace('hey aron', '').replace('aron', '').trim(); |
| | handleVoiceCommand(finalTranscript); |
| | finalTranscript = ''; |
| | } |
| | } else { |
| | interimTranscript += transcript; |
| | } |
| | } |
| | |
| | |
| | if (interimTranscript && wakeWordDetected) { |
| | messageInput.value = interimTranscript; |
| | } |
| | }; |
| | |
| | recognition.onerror = (event) => { |
| | console.error('Speech recognition error', event.error); |
| | updateStatus('off'); |
| | addAronMessage("Sorry, I encountered an error with voice recognition. Please try again."); |
| | }; |
| | |
| | |
| | try { |
| | recognition.start(); |
| | } catch (e) { |
| | console.error('Speech recognition start failed:', e); |
| | updateStatus('off'); |
| | } |
| | } |
| | |
| | |
| | function updateStatus(status) { |
| | statusIndicator.className = 'status-indicator'; |
| | |
| | switch (status) { |
| | case 'listening': |
| | statusIndicator.classList.add('status-listening'); |
| | statusText.textContent = 'Listening'; |
| | break; |
| | case 'waiting': |
| | statusIndicator.classList.add('status-waiting'); |
| | statusText.textContent = 'Waiting'; |
| | break; |
| | case 'off': |
| | statusIndicator.classList.add('status-off'); |
| | statusText.textContent = 'Offline'; |
| | break; |
| | } |
| | } |
| | |
| | |
| | function setupEventListeners() { |
| | |
| | sendBtn.addEventListener('click', sendMessage); |
| | messageInput.addEventListener('keypress', (e) => { |
| | if (e.key === 'Enter') sendMessage(); |
| | }); |
| | |
| | |
| | voiceBtn.addEventListener('click', toggleVoiceRecognition); |
| | |
| | |
| | chatTab.addEventListener('click', () => switchTab('chat')); |
| | tasksTab.addEventListener('click', () => switchTab('tasks')); |
| | |
| | |
| | addTaskBtn.addEventListener('click', () => addTaskModal.classList.remove('hidden')); |
| | saveTaskBtn.addEventListener('click', saveTask); |
| | cancelTaskBtn.addEventListener('click', () => addTaskModal.classList.add('hidden')); |
| | } |
| | |
| | |
| | function toggleVoiceRecognition() { |
| | if (!isListening) { |
| | voiceModal.classList.remove('hidden'); |
| | voiceInputIndicator.classList.remove('hidden'); |
| | wakeWordDetected = true; |
| | |
| | |
| | } else { |
| | voiceModal.classList.add('hidden'); |
| | voiceInputIndicator.classList.add('hidden'); |
| | wakeWordDetected = false; |
| | |
| | if (recognition) { |
| | recognition.stop(); |
| | } |
| | } |
| | } |
| | |
| | |
| | function handleVoiceCommand(command) { |
| | if (!command.trim()) return; |
| | |
| | addUserMessage(command); |
| | processCommand(command); |
| | |
| | |
| | voiceModal.classList.remove('hidden'); |
| | setTimeout(() => { |
| | voiceModal.classList.add('hidden'); |
| | }, 1000); |
| | } |
| | |
| | |
| | function switchTab(tab) { |
| | |
| | chatTab.classList.remove('text-green-400'); |
| | chatTab.classList.add('text-green-600'); |
| | tasksTab.classList.remove('text-green-400'); |
| | tasksTab.classList.add('text-green-600'); |
| | |
| | |
| | chatArea.classList.add('hidden'); |
| | taskList.classList.add('hidden'); |
| | |
| | |
| | if (tab === 'chat') { |
| | chatTab.classList.remove('text-green-600'); |
| | chatTab.classList.add('text-green-400'); |
| | chatArea.classList.remove('hidden'); |
| | } else if (tab === 'tasks') { |
| | tasksTab.classList.remove('text-green-600'); |
| | tasksTab.classList.add('text-green-400'); |
| | taskList.classList.remove('hidden'); |
| | } |
| | } |
| | |
| | |
| | function sendMessage() { |
| | const message = messageInput.value.trim(); |
| | if (message) { |
| | addUserMessage(message); |
| | processCommand(message); |
| | messageInput.value = ''; |
| | } |
| | } |
| | |
| | |
| | async function processCommand(command) { |
| | |
| | const typingIndicator = document.createElement('div'); |
| | typingIndicator.className = 'message-bubble aron-message typing-indicator'; |
| | typingIndicator.innerHTML = '<span></span><span></span><span></span>'; |
| | chatArea.appendChild(typingIndicator); |
| | chatArea.scrollTop = chatArea.scrollHeight; |
| | |
| | try { |
| | |
| | if (!wakeWordDetected && !command.toLowerCase().includes('hey aron') && !command.toLowerCase().includes('aron')) { |
| | addAronMessage("Please say 'Hey Aron' before your command so I know you're talking to me."); |
| | return; |
| | } |
| | |
| | |
| | const cleanCommand = command.toLowerCase().replace('hey aron', '').replace('aron', '').trim(); |
| | |
| | if (cleanCommand.includes('task') || cleanCommand.includes('remind') || cleanCommand.includes('add')) { |
| | await handleTaskCommand(cleanCommand); |
| | } else if (cleanCommand.includes('today') || cleanCommand.includes('schedule') || cleanCommand.includes('what have we got')) { |
| | await showTodaysTasks(); |
| | } else if (cleanCommand.includes('hello') || cleanCommand.includes('hi')) { |
| | speakResponse(getRandomGreeting()); |
| | } else { |
| | |
| | await getChatGPTResponse(cleanCommand); |
| | } |
| | } catch (error) { |
| | console.error('Error processing command:', error); |
| | addAronMessage("Sorry, I encountered an error processing your request. Please try again."); |
| | } finally { |
| | |
| | typingIndicator.remove(); |
| | } |
| | } |
| | |
| | |
| | async function handleTaskCommand(command) { |
| | if (command.includes('add') || command.includes('new') || command.includes('create')) { |
| | |
| | let taskName = command.replace('add', '').replace('task', '').replace('new', '').replace('create', '').trim(); |
| | let dueDate = new Date(); |
| | |
| | if (command.includes('tomorrow')) { |
| | dueDate.setDate(dueDate.getDate() + 1); |
| | } |
| | |
| | if (command.includes('at') && command.match(/\d{1,2}\s?(am|pm)/i)) { |
| | const timeMatch = command.match(/\d{1,2}\s?(am|pm)/i)[0]; |
| | let hours = parseInt(timeMatch); |
| | const isPM = timeMatch.toLowerCase().includes('pm'); |
| | |
| | if (isPM && hours < 12) hours += 12; |
| | if (!isPM && hours === 12) hours = 0; |
| | |
| | dueDate.setHours(hours); |
| | dueDate.setMinutes(0); |
| | } |
| | |
| | |
| | const newTask = { |
| | id: tasks.length + 1, |
| | name: taskName || "New Task", |
| | due: dueDate.toISOString().slice(0, 16), |
| | completed: false |
| | }; |
| | |
| | tasks.push(newTask); |
| | renderTasks(); |
| | |
| | const response = `I've added the task "${newTask.name}" to your list. You've got this!`; |
| | speakResponse(response); |
| | } else { |
| | const response = "I can help you manage tasks. Try saying 'Hey Aron, add a task to call mom tomorrow at 5 PM'"; |
| | speakResponse(response); |
| | } |
| | } |
| | |
| | |
| | async function showTodaysTasks() { |
| | const today = new Date().toISOString().slice(0, 10); |
| | const todaysTasks = tasks.filter(task => task.due.startsWith(today)); |
| | |
| | if (todaysTasks.length > 0) { |
| | let taskList = todaysTasks.map(task => { |
| | const time = new Date(task.due).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); |
| | return `${task.name} at ${time}`; |
| | }).join(', '); |
| | |
| | const response = `Today, you have ${taskList} to complete. Let's make it a productive day!`; |
| | speakResponse(response); |
| | } else { |
| | const response = "You have no tasks scheduled for today. Enjoy your free time or add some tasks to stay productive!"; |
| | speakResponse(response); |
| | } |
| | } |
| | |
| | |
| | async function getChatGPTResponse(query) { |
| | try { |
| | const response = await fetch('https://api.openai.com/v1/chat/completions', { |
| | method: 'POST', |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | 'Authorization': `Bearer ${apiKey}` |
| | }, |
| | body: JSON.stringify({ |
| | model: "gpt-3.5-turbo", |
| | messages: [ |
| | { |
| | role: "system", |
| | content: "You are Aron, a friendly and helpful AI productivity assistant. Respond in a conversational tone, keeping responses concise but helpful. Use motivational language when appropriate." |
| | }, |
| | { |
| | role: "user", |
| | content: query |
| | } |
| | ], |
| | temperature: 0.7, |
| | max_tokens: 150 |
| | }) |
| | }); |
| | |
| | const data = await response.json(); |
| | |
| | if (data.choices && data.choices[0].message) { |
| | const chatGPTResponse = data.choices[0].message.content; |
| | speakResponse(chatGPTResponse); |
| | } else { |
| | throw new Error('Invalid response from API'); |
| | } |
| | } catch (error) { |
| | console.error('Error calling ChatGPT API:', error); |
| | const fallbackResponse = "I'm having trouble connecting to my AI brain right now. Here's what I can tell you about '" + query + "': It's important to stay focused and break tasks into manageable chunks."; |
| | speakResponse(fallbackResponse); |
| | } |
| | } |
| | |
| | |
| | function speakResponse(text) { |
| | addAronMessage(text); |
| | |
| | if (synth && SpeechSynthesisUtterance) { |
| | const utterance = new SpeechSynthesisUtterance(text); |
| | utterance.voice = synth.getVoices().find(voice => voice.name.includes('Google US English') || voice.lang.includes('en-US')); |
| | utterance.rate = 0.9; |
| | utterance.pitch = 1; |
| | synth.speak(utterance); |
| | } |
| | } |
| | |
| | |
| | function addUserMessage(message) { |
| | const messageDiv = document.createElement('div'); |
| | messageDiv.className = 'message-bubble user-message'; |
| | messageDiv.innerHTML = `<p class="terminal-text">${message}</p>`; |
| | chatArea.appendChild(messageDiv); |
| | chatArea.scrollTop = chatArea.scrollHeight; |
| | } |
| | |
| | |
| | function addAronMessage(message) { |
| | const messageDiv = document.createElement('div'); |
| | messageDiv.className = 'message-bubble aron-message'; |
| | messageDiv.innerHTML = `<p class="terminal-text">${message}</p>`; |
| | chatArea.appendChild(messageDiv); |
| | chatArea.scrollTop = chatArea.scrollHeight; |
| | } |
| | |
| | |
| | function getRandomGreeting() { |
| | const greetings = [ |
| | "Hello there! How can I assist you today?", |
| | "Hi! Ready to boost your productivity?", |
| | "Greetings! What's on your mind today?", |
| | "Hey! Let's make today productive together." |
| | ]; |
| | return greetings[Math.floor(Math.random() * greetings.length)]; |
| | } |
| | |
| | |
| | function renderTasks() { |
| | tasksContainer.innerHTML = ''; |
| | |
| | if (tasks.length === 0) { |
| | tasksContainer.innerHTML = '<p class="text-green-600 text-center py-4">No tasks yet. Add your first task!</p>'; |
| | return; |
| | } |
| | |
| | |
| | const sortedTasks = [...tasks].sort((a, b) => new Date(a.due) - new Date(b.due)); |
| | |
| | sortedTasks.forEach(task => { |
| | const taskElement = document.createElement('div'); |
| | taskElement.className = `task-item bg-black p-3 rounded-lg flex items-center justify-between ${task.completed ? 'opacity-60' : ''}`; |
| | |
| | const dueDate = new Date(task.due); |
| | const timeString = dueDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); |
| | const dateString = dueDate.toLocaleDateString(); |
| | |
| | taskElement.innerHTML = ` |
| | <div class="flex items-center"> |
| | <input type="checkbox" ${task.completed ? 'checked' : ''} data-id="${task.id}" class="mr-3 h-5 w-5 text-green-500 rounded focus:ring-green-400"> |
| | <div> |
| | <p class="text-green-400 ${task.completed ? 'line-through' : ''}">${task.name}</p> |
| | <p class="text-green-600 text-xs">${dateString} at ${timeString}</p> |
| | </div> |
| | </div> |
| | <button data-id="${task.id}" class="text-green-600 hover:text-green-400"> |
| | <i class="fas fa-trash-alt"></i> |
| | </button> |
| | `; |
| | |
| | tasksContainer.appendChild(taskElement); |
| | }); |
| | |
| | |
| | document.querySelectorAll('.task-item input[type="checkbox"]').forEach(checkbox => { |
| | checkbox.addEventListener('change', toggleTaskCompletion); |
| | }); |
| | |
| | document.querySelectorAll('.task-item button').forEach(button => { |
| | button.addEventListener('click', deleteTask); |
| | }); |
| | } |
| | |
| | |
| | function toggleTaskCompletion(e) { |
| | const taskId = parseInt(e.target.dataset.id); |
| | const task = tasks.find(t => t.id === taskId); |
| | |
| | if (task) { |
| | task.completed = e.target.checked; |
| | |
| | |
| | if (task.completed) { |
| | setTimeout(() => { |
| | const response = `Great job completing "${task.name}"! Keep up the good work!`; |
| | speakResponse(response); |
| | }, 500); |
| | } |
| | } |
| | } |
| | |
| | |
| | function deleteTask(e) { |
| | const taskId = parseInt(e.currentTarget.dataset.id); |
| | const task = tasks.find(t => t.id === taskId); |
| | |
| | if (task) { |
| | tasks = tasks.filter(t => t.id !== taskId); |
| | renderTasks(); |
| | |
| | const response = `I've removed "${task.name}" from your tasks.`; |
| | speakResponse(response); |
| | } |
| | } |
| | |
| | |
| | function saveTask() { |
| | const name = taskNameInput.value.trim(); |
| | const due = taskDateInput.value; |
| | |
| | if (name && due) { |
| | const newTask = { |
| | id: tasks.length + 1, |
| | name, |
| | due, |
| | completed: false |
| | }; |
| | |
| | tasks.push(newTask); |
| | renderTasks(); |
| | addTaskModal.classList.add('hidden'); |
| | taskNameInput.value = ''; |
| | taskDateInput.value = ''; |
| | |
| | |
| | switchTab('tasks'); |
| | |
| | |
| | setTimeout(() => { |
| | const response = `I've added "${name}" to your tasks. You've got this!`; |
| | speakResponse(response); |
| | }, 500); |
| | } |
| | } |
| | |
| | |
| | function checkForReminders() { |
| | const now = new Date(); |
| | const soon = new Date(now.getTime() + 30 * 60000); |
| | |
| | tasks.forEach(task => { |
| | if (!task.completed) { |
| | const taskDue = new Date(task.due); |
| | |
| | if (taskDue > now && taskDue < soon) { |
| | setTimeout(() => { |
| | const response = `Sir, you've got "${task.name}" coming up soon at ${taskDue.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}. Just a friendly reminder!`; |
| | speakResponse(response); |
| | }, taskDue - now - 5 * 60000); |
| | } |
| | } |
| | }); |
| | |
| | |
| | setTimeout(checkForReminders, 60000); |
| | } |
| | |
| | |
| | function simulateInitialGreeting() { |
| | setTimeout(() => { |
| | speakResponse("Welcome back! I'm here to help you stay productive and organized."); |
| | |
| | setTimeout(() => { |
| | speakResponse("You can ask me things like:"); |
| | |
| | setTimeout(() => { |
| | speakResponse("'Hey Aron, what's on my schedule for today?'"); |
| | |
| | setTimeout(() => { |
| | speakResponse("'Hey Aron, add a task to call mom tomorrow at 5 PM'"); |
| | |
| | setTimeout(() => { |
| | speakResponse("Or just tap the microphone button to speak to me directly."); |
| | }, 1000); |
| | }, 1000); |
| | }, 1000); |
| | }, 1000); |
| | }, 1500); |
| | } |
| | |
| | |
| | init(); |
| | </script> |
| | <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=meer012/aron-2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| | </html> |