diff --git a/app/routes.py b/app/routes.py index fa5657c..2c80d71 100644 --- a/app/routes.py +++ b/app/routes.py @@ -113,56 +113,74 @@ def extract_main_content(soup): @main_bp.route('/settings', methods=['GET', 'POST']) def settings(): if request.method == 'POST': - secret_key = request.form.get('secret_key') - if secret_key != os.getenv('SECRET_KEY'): - flash('Invalid secret key', 'error') + # Check if this is the Gemini settings form (which includes a google_gemini_key) + if 'google_gemini_key' in request.form: + # We assume the secret key was already verified and stored in the session. + # Optionally, you could re-check here, but we'll trust the session. + google_gemini_key = request.form.get('google_gemini_key') or '' + enable_gemini = 'enable_gemini' in request.form + gemini_model = request.form.get('gemini_model') or 'gemini-1.0-pro' + flask_port = request.form.get('flask_port') or '8080' + + # Update the .env file with the new settings + env_path = os.path.join(os.path.dirname(__file__), '../.env') + with open(env_path, 'r') as file: + lines = file.readlines() + with open(env_path, 'w') as file: + for line in lines: + if line.startswith('GOOGLE_GEMINI_API_KEY='): + file.write(f'GOOGLE_GEMINI_API_KEY={google_gemini_key}\n') + elif line.startswith('ENABLE_GEMINI_API='): + file.write(f'ENABLE_GEMINI_API={"true" if enable_gemini else "false"}\n') + elif line.startswith('GEMINI_MODEL='): + file.write(f'GEMINI_MODEL={gemini_model}\n') + elif line.startswith('FLASK_RUN_PORT='): + file.write(f'FLASK_RUN_PORT={flask_port}\n') + else: + file.write(line) + + # Update environment variables and reinitialize Gemini AI + os.environ['GOOGLE_GEMINI_API_KEY'] = google_gemini_key + os.environ['ENABLE_GEMINI_API'] = 'true' if enable_gemini else 'false' + os.environ['GEMINI_MODEL'] = gemini_model + gemini_ai._initialize() + + flash('Settings updated successfully', 'success') return redirect(url_for('main.settings')) - session['secret_key_verified'] = True - google_gemini_key = request.form.get('google_gemini_key') or '' - enable_gemini = 'enable_gemini' in request.form - gemini_model = request.form.get('gemini_model') or 'gemini-1.0-pro' - flask_port = request.form.get('flask_port') or '8080' - - # Update .env file - with open(os.path.join(os.path.dirname(__file__), '../.env'), 'r') as file: - lines = file.readlines() - with open(os.path.join(os.path.dirname(__file__), '../.env'), 'w') as file: - for line in lines: - if line.startswith('GOOGLE_GEMINI_API_KEY='): - file.write(f'GOOGLE_GEMINI_API_KEY={google_gemini_key}\n') - elif line.startswith('ENABLE_GEMINI_API='): - file.write(f'ENABLE_GEMINI_API={"true" if enable_gemini else "false"}\n') - elif line.startswith('GEMINI_MODEL='): - file.write(f'GEMINI_MODEL={gemini_model}\n') - elif line.startswith('FLASK_RUN_PORT='): - file.write(f'FLASK_RUN_PORT={flask_port}\n') - else: - file.write(line) - - # Re-initialize Gemini AI with new settings - os.environ['GOOGLE_GEMINI_API_KEY'] = google_gemini_key - os.environ['ENABLE_GEMINI_API'] = 'true' if enable_gemini else 'false' - os.environ['GEMINI_MODEL'] = gemini_model - gemini_ai._initialize() - - flash('Settings updated successfully', 'success') - return redirect(url_for('main.settings')) + else: + # This is the secret key verification form. + secret_key = request.form.get('secret_key') + # Compare against the environment variable (set elsewhere) + if secret_key != os.getenv('SECRET_KEY'): + flash('Invalid secret key', 'error') + return redirect(url_for('main.settings')) + + # If the secret key is valid, store a flag in session. + session['secret_key_verified'] = True + session['secret_key'] = secret_key # Save it if needed later + flash('Secret key verified and saved!', 'success') + return redirect(url_for('main.settings')) + # GET method: render the settings page. if not session.get('secret_key_verified'): return render_template('settings.html', secret_key_verified=False) + # If secret key has been verified, load current settings. google_gemini_key = os.getenv('GOOGLE_GEMINI_API_KEY', '') enable_gemini = os.getenv('ENABLE_GEMINI_API', 'false').lower() == 'true' gemini_model = os.getenv('GEMINI_MODEL', 'gemini-1.0-pro') flask_port = os.getenv('FLASK_RUN_PORT', '8080') - return render_template('settings.html', - secret_key_verified=True, - google_gemini_key=google_gemini_key, - enable_gemini=enable_gemini, - gemini_model=gemini_model, - flask_port=flask_port, - secret_key=session.get('secret_key')) + + return render_template( + 'settings.html', + secret_key_verified=True, + google_gemini_key=google_gemini_key, + enable_gemini=enable_gemini, + gemini_model=gemini_model, + flask_port=flask_port, + secret_key=session.get('secret_key') + ) @main_bp.route('/json/version') def json_version(): diff --git a/app/static/images/Blue_FLower.png b/app/static/images/Blue_FLower.png new file mode 100644 index 0000000..7419bd6 Binary files /dev/null and b/app/static/images/Blue_FLower.png differ diff --git a/app/static/images/Capybara.png b/app/static/images/Capybara.png new file mode 100644 index 0000000..ac74e4e Binary files /dev/null and b/app/static/images/Capybara.png differ diff --git a/app/static/images/Day_BG.png b/app/static/images/Day_BG.png new file mode 100644 index 0000000..b567ee7 Binary files /dev/null and b/app/static/images/Day_BG.png differ diff --git a/app/static/images/Duck.png b/app/static/images/Duck.png new file mode 100644 index 0000000..659d506 Binary files /dev/null and b/app/static/images/Duck.png differ diff --git a/app/static/images/Night_BG.png b/app/static/images/Night_BG.png new file mode 100644 index 0000000..16fbc94 Binary files /dev/null and b/app/static/images/Night_BG.png differ diff --git a/app/static/images/Orange_Flower.png b/app/static/images/Orange_Flower.png new file mode 100644 index 0000000..9361482 Binary files /dev/null and b/app/static/images/Orange_Flower.png differ diff --git a/app/static/images/Purple_Flowers.png b/app/static/images/Purple_Flowers.png new file mode 100644 index 0000000..c55fdf3 Binary files /dev/null and b/app/static/images/Purple_Flowers.png differ diff --git a/app/static/images/Red_Flower.png b/app/static/images/Red_Flower.png new file mode 100644 index 0000000..67736cf Binary files /dev/null and b/app/static/images/Red_Flower.png differ diff --git a/app/static/images/Worm.gif b/app/static/images/Worm.gif new file mode 100644 index 0000000..a0703c4 Binary files /dev/null and b/app/static/images/Worm.gif differ diff --git a/app/static/images/Yellow_Flower.png b/app/static/images/Yellow_Flower.png new file mode 100644 index 0000000..3b941f2 Binary files /dev/null and b/app/static/images/Yellow_Flower.png differ diff --git a/app/static/js/local.js b/app/static/js/local.js index 3dea275..83a7e58 100644 --- a/app/static/js/local.js +++ b/app/static/js/local.js @@ -96,5 +96,9 @@ function showToast(message, type = 'error') { toast.classList.add('hidden'); }, 3000); } - +module.exports = { + plugins: [ + require('@tailwindcss/aspect-ratio'), + ], + } console.log('Local JS file loaded'); \ No newline at end of file diff --git a/app/templates/reader.html b/app/templates/reader.html index 4614891..ef16a08 100644 --- a/app/templates/reader.html +++ b/app/templates/reader.html @@ -13,17 +13,16 @@ -
+ + +
-
+ {% endblock %} {% block head %} @@ -70,67 +72,98 @@

-document.addEventListener('DOMContentLoaded', function() { - // ------------------------------ - // ELEMENT REFERENCES & INITIAL STATE - // ------------------------------ - const originalTitle = document.title; - const readerContent = document.getElementById('reader-content'); - const fontDecrease = document.getElementById('font-decrease'); - const fontIncrease = document.getElementById('font-increase'); - const fontFamily = document.getElementById('font-family'); - const spacingDecrease = document.getElementById('spacing-decrease'); - const spacingIncrease = document.getElementById('spacing-increase'); - const annotationMode = document.getElementById('annotation-mode'); - const readAloud = document.getElementById('read-aloud'); - const cookieConsent = document.getElementById('cookie-consent'); - const acceptCookies = document.getElementById('accept-cookies'); - const denyCookies = document.getElementById('deny-cookies'); - const focusDraining = document.getElementById('focus-draining'); - const focusProgress = document.getElementById('focus-progress'); - const focusTimeDisplay = document.getElementById('focus-time'); - const gardenElements = document.getElementById('garden-elements'); - const fontColorDropdown = document.getElementById('font-color'); - const annotationToggle = document.getElementById('annotation-toggle'); - const url = '{{ url }}'; - - // Load saved articles from local storage - const savedArticles = JSON.parse(localStorage.getItem('savedArticles')) || []; - const articlePreferences = savedArticles.find(article => article.url === url) || {}; - if (articlePreferences.fontSize) { - readerContent.style.fontSize = articlePreferences.fontSize; - } - if (articlePreferences.fontFamily) { - readerContent.style.fontFamily = articlePreferences.fontFamily; - fontFamily.value = articlePreferences.fontFamily; - } - if (articlePreferences.fontColor) { - readerContent.style.color = articlePreferences.fontColor; - fontColorDropdown.value = articlePreferences.fontColor; - } - if (articlePreferences.lineHeight) { - readerContent.style.lineHeight = articlePreferences.lineHeight; - } - if (articlePreferences.highlights) { - readerContent.innerHTML = articlePreferences.highlights; - } - if (articlePreferences.annotations) { - articlePreferences.annotations.forEach(annotation => { - addAnnotation(annotation.text, annotation.note); - }); - } + document.addEventListener('DOMContentLoaded', function () { + // ------------------------------ + // ELEMENT REFERENCES & INITIAL STATE + // ------------------------------ + const originalTitle = document.title; + const readerContent = document.getElementById('reader-content'); + const fontDecrease = document.getElementById('font-decrease'); + const fontIncrease = document.getElementById('font-increase'); + const fontFamily = document.getElementById('font-family'); + const spacingDecrease = document.getElementById('spacing-decrease'); + const spacingIncrease = document.getElementById('spacing-increase'); + const annotationMode = document.getElementById('annotation-mode'); + const readAloud = document.getElementById('read-aloud'); + const cookieConsent = document.getElementById('cookie-consent'); + const acceptCookies = document.getElementById('accept-cookies'); + const denyCookies = document.getElementById('deny-cookies'); + const focusDraining = document.getElementById('focus-draining'); + const focusProgress = document.getElementById('focus-progress'); + const focusTimeDisplay = document.getElementById('focus-time'); + const gardenElements = document.getElementById('garden-elements'); + const fontColorDropdown = document.getElementById('font-color'); + const annotationToggle = document.getElementById('annotation-toggle'); + const url = '{{ url }}'; + + // Load saved articles from localStorage + const savedArticles = JSON.parse(localStorage.getItem('savedArticles')) || []; + const articlePreferences = savedArticles.find(article => article.url === url) || {}; + if (articlePreferences.fontSize) { + readerContent.style.fontSize = articlePreferences.fontSize; + } + if (articlePreferences.fontFamily) { + readerContent.style.fontFamily = articlePreferences.fontFamily; + fontFamily.value = articlePreferences.fontFamily; + } + if (articlePreferences.fontColor) { + readerContent.style.color = articlePreferences.fontColor; + fontColorDropdown.value = articlePreferences.fontColor; + } + if (articlePreferences.lineHeight) { + readerContent.style.lineHeight = articlePreferences.lineHeight; + } + if (articlePreferences.highlights) { + readerContent.innerHTML = articlePreferences.highlights; + } + if (articlePreferences.annotations) { + articlePreferences.annotations.forEach(annotation => { + addAnnotation(annotation.text, annotation.note); + }); + } - // Save preferences to local storage - function savePreferences() { - const preferences = { - url: url, - title: '{{ title }}', - fontSize: readerContent.style.fontSize, - fontFamily: readerContent.style.fontFamily, - fontColor: readerContent.style.color, - lineHeight: readerContent.style.lineHeight, - highlights: readerContent.innerHTML, - annotations: getAnnotations() - }; - const index = savedArticles.findIndex(article => article.url === url); - if (index !== -1) { - savedArticles[index] = preferences; - } else { - savedArticles.push(preferences); - } - localStorage.setItem('savedArticles', JSON.stringify(savedArticles)); - localStorage.setItem('evilModeActive', JSON.stringify(evilModeActive)); - } + // Save preferences to localStorage + function savePreferences() { + const preferences = { + url: url, + title: '{{ title }}', + fontSize: readerContent.style.fontSize, + fontFamily: readerContent.style.fontFamily, + fontColor: readerContent.style.color, + lineHeight: readerContent.style.lineHeight, + highlights: readerContent.innerHTML, + annotations: getAnnotations() + }; + const index = savedArticles.findIndex(article => article.url === url); + if (index !== -1) { + savedArticles[index] = preferences; + } else { + savedArticles.push(preferences); + } + localStorage.setItem('savedArticles', JSON.stringify(savedArticles)); + localStorage.setItem('evilModeActive', JSON.stringify(evilModeActive)); + } - function getAnnotations() { - const annotations = []; - document.querySelectorAll('.annotation').forEach(annotation => { - annotations.push({ - text: annotation.dataset.text, - note: annotation.querySelector('.annotation-note').value + function getAnnotations() { + const annotations = []; + document.querySelectorAll('.annotation').forEach(annotation => { + annotations.push({ + text: annotation.dataset.text, + note: annotation.querySelector('.annotation-note').value + }); }); - }); - return annotations; - } - - let currentFontSize = parseInt(window.getComputedStyle(readerContent).fontSize); - let currentLineHeight = 1.6; - let isAnnotationMode = false; - let isReading = false; - let speechUtterance = null; - let cookiesAccepted = false; - - // Focus mode variables - let focusModeActive = true; // Set true to start focus mode automatically - let focusMinutes = 0; - let focusTimer = null; - let drainTimer = null; - let elapsedSeconds = 0; // Track seconds within the current minute - const evilModeToggle = document.getElementById('evil-mode-toggle'); - const COOKIE_CONSENT_NAME = 'bookworm_cookie_consent'; - const FOCUS_MINUTES_NAME = 'bookworm_focus_minutes'; - const GARDEN_PLANTS_NAME = 'bookworm_garden_plants'; - const PLANTS_PER_MINUTE = 1; // 1 plant per minute - - // Toolbar modifications for evil mode - const toolbarButtons = document.querySelectorAll( - '#font-decrease, #font-increase, #read-aloud, #spacing-decrease, #spacing-increase, #highlight-toggle, #eraser-toggle, #chat-toggle, #magic-highlight' - ); - const originalToolbarHTML = {}; - toolbarButtons.forEach(btn => { - originalToolbarHTML[btn.id] = btn.innerHTML; - }); - const fontFamilySelect = document.getElementById('font-family'); - const originalFontFamilyOptions = fontFamilySelect ? fontFamilySelect.innerHTML : ''; + return annotations; + } - function activateEvilMode() { - // Replace toolbar buttons' content with an evil emoji + let currentFontSize = parseInt(window.getComputedStyle(readerContent).fontSize); + let currentLineHeight = 1.6; + let isAnnotationMode = false; + let isReading = false; + let speechUtterance = null; + let cookiesAccepted = false; + + // Focus mode variables + let focusModeActive = true; // Set true to start focus mode automatically + let focusMinutes = 0; + let focusTimer = null; + let drainTimer = null; + let elapsedSeconds = 0; // Track seconds within the current minute + const evilModeToggle = document.getElementById('evil-mode-toggle'); + const COOKIE_CONSENT_NAME = 'bookworm_cookie_consent'; + const FOCUS_MINUTES_NAME = 'bookworm_focus_minutes'; + const GARDEN_PLANTS_NAME = 'bookworm_garden_plants'; + const PLANTS_PER_MINUTE = 1; // 1 plant per minute + + // Toolbar modifications for evil mode + const toolbarButtons = document.querySelectorAll( + '#font-decrease, #font-increase, #read-aloud, #spacing-decrease, #spacing-increase, #highlight-toggle, #eraser-toggle, #chat-toggle, #magic-highlight' + ); + const originalToolbarHTML = {}; toolbarButtons.forEach(btn => { - const evilEmojis = ['😈', '👹', '👺', '💀', '👻', '👽', '🤖', '👾']; - const randomEmoji = evilEmojis[Math.floor(Math.random() * evilEmojis.length)]; - btn.innerHTML = randomEmoji; + originalToolbarHTML[btn.id] = btn.innerHTML; }); - // Change the font-family dropdown to evil choices - if (fontFamilySelect) { - fontFamilySelect.innerHTML = ``; - } - // Change the reader content to use a less readable font (e.g. Wingdings) - if (readerContent) { - readerContent.style.fontFamily = 'Wingdings, sans-serif'; + const fontFamilySelect = document.getElementById('font-family'); + const originalFontFamilyOptions = fontFamilySelect ? fontFamilySelect.innerHTML : ''; + + function activateEvilMode() { + // Replace toolbar buttons' content with an evil emoji + toolbarButtons.forEach(btn => { + const evilEmojis = ['😈', '👹', '👺', '💀', '👻', '👽', '🤖', '👾']; + const randomEmoji = evilEmojis[Math.floor(Math.random() * evilEmojis.length)]; + btn.innerHTML = randomEmoji; + }); + // Change the font-family dropdown to evil choices + if (fontFamilySelect) { + fontFamilySelect.innerHTML = ``; + } + // Change the reader content to use a less readable font (e.g. Wingdings) + if (readerContent) { + readerContent.style.fontFamily = 'Wingdings, sans-serif'; + } + // Additional evil modifications can be added here } - // Additional evil modifications can be added here - } - - function deactivateEvilMode() { - // Restore original toolbar buttons - toolbarButtons.forEach(btn => { - if (originalToolbarHTML[btn.id]) { - btn.innerHTML = originalToolbarHTML[btn.id]; + + function deactivateEvilMode() { + // Restore original toolbar buttons + toolbarButtons.forEach(btn => { + if (originalToolbarHTML[btn.id]) { + btn.innerHTML = originalToolbarHTML[btn.id]; + } + }); + // Restore original font-family dropdown options + if (fontFamilySelect) { + fontFamilySelect.innerHTML = originalFontFamilyOptions; } - }); - // Restore original font-family dropdown options - if (fontFamilySelect) { - fontFamilySelect.innerHTML = originalFontFamilyOptions; + // Restore the reader content font + if (readerContent) { + readerContent.style.fontFamily = ''; + } + // Additional restoration code can be added here } - // Restore the reader content font - if (readerContent) { - readerContent.style.fontFamily = ''; + + // Load evil mode state from localStorage + let evilModeActive = JSON.parse(localStorage.getItem('evilModeActive')) || false; + if (evilModeActive) { + activateEvilMode(); } - // Additional restoration code can be added here - } - // Load evil mode state from local storage - let evilModeActive = JSON.parse(localStorage.getItem('evilModeActive')) || false; - if (evilModeActive) { - activateEvilMode(); - } + // ------------------------------ + // HELPER FUNCTIONS + // ------------------------------ + // Reverse a string (for evil read-aloud) + function reverseText(text) { + return text.split('').reverse().join(''); + } - // ------------------------------ - // HELPER FUNCTIONS - // ------------------------------ - // Reverse a string (for evil read-aloud) - function reverseText(text) { - return text.split('').reverse().join(''); - } + // ------------------------------ + // COOKIE FUNCTIONS & DATA LOADING + // ------------------------------ + function checkCookieConsent() { + const consent = getCookie(COOKIE_CONSENT_NAME); + // If accepted, we can store data. If denied, we hide banner but do not store data. + if (consent === 'accepted') { + cookiesAccepted = true; + } else if (consent === 'denied') { + cookiesAccepted = false; + } else { + cookieConsent.classList.remove('hidden'); + } + } - // ------------------------------ - // COOKIE FUNCTIONS & DATA LOADING - // ------------------------------ - function checkCookieConsent() { - const consent = getCookie(COOKIE_CONSENT_NAME); - if (consent === 'accepted') { - cookiesAccepted = true; - } else { - cookieConsent.classList.remove('hidden'); + function setCookie(name, value, days) { + // Only set other cookies if user has accepted or if this is the consent cookie + if (!cookiesAccepted && name !== COOKIE_CONSENT_NAME) return; + let expires = ''; + if (days) { + const date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = '; expires=' + date.toUTCString(); + } + document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/'; } - } - function setCookie(name, value, days) { - if (!cookiesAccepted && name !== COOKIE_CONSENT_NAME) return; - let expires = ''; - if (days) { - const date = new Date(); - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - expires = '; expires=' + date.toUTCString(); - } - document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/'; - } - function getCookie(name) { - const nameEQ = name + '='; - const ca = document.cookie.split(';'); - for (let i = 0; i < ca.length; i++) { - let c = ca[i].trim(); - if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length)); - } - return null; - } - function loadFocusData() { - const savedMinutes = getCookie(FOCUS_MINUTES_NAME); - if (savedMinutes) { - focusMinutes = parseInt(savedMinutes); - focusTimeDisplay.textContent = focusMinutes; - updateProgressBar(0); - } - const savedPlants = getCookie(GARDEN_PLANTS_NAME); - if (savedPlants) { - try { - const plants = JSON.parse(savedPlants); - plants.forEach(plant => { - addGardenElement(plant.icon, plant.height, plant.color); + + function getCookie(name) { + const nameEQ = name + '='; + const ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i].trim(); + if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length)); + } + return null; + } + + function loadFocusData() { + const savedMinutes = getCookie(FOCUS_MINUTES_NAME); + if (savedMinutes) { + focusMinutes = parseInt(savedMinutes); + focusTimeDisplay.textContent = focusMinutes; + updateProgressBar(0); + } + const savedPlants = getCookie(GARDEN_PLANTS_NAME); + if (savedPlants) { + try { + const plants = JSON.parse(savedPlants); + plants.forEach(plant => { + addGardenElement(plant.image, plant.height); + }); + } catch (e) { + console.error('Failed to parse garden plants cookie', e); + } + } + } + + function saveFocusData() { + if (cookiesAccepted) { + setCookie(FOCUS_MINUTES_NAME, focusMinutes.toString(), 365); + const plants = []; + document.querySelectorAll('.garden-plant').forEach(plant => { + const img = plant.querySelector('img'); + if (img) { + plants.push({ + image: img.getAttribute('src').replace('/static/images/', ''), + height: img.style.height + }); + } }); - } catch (e) { - console.error('Failed to parse garden plants cookie', e); + setCookie(GARDEN_PLANTS_NAME, JSON.stringify(plants), 365); } } - } - function saveFocusData() { + + // Cookie Consent Buttons + acceptCookies.addEventListener('click', function () { + setCookie(COOKIE_CONSENT_NAME, 'accepted', 365); + cookiesAccepted = true; + cookieConsent.classList.add('hidden'); + // Now that user accepted, we can load or save data + loadFocusData(); + }); + + denyCookies.addEventListener('click', function () { + setCookie(COOKIE_CONSENT_NAME, 'denied', 365); + cookiesAccepted = false; + cookieConsent.classList.add('hidden'); + }); + + checkCookieConsent(); if (cookiesAccepted) { - setCookie(FOCUS_MINUTES_NAME, focusMinutes.toString(), 365); - const plants = []; - document.querySelectorAll('.garden-plant').forEach(plant => { - const icon = plant.querySelector('i').className; - const height = plant.querySelector('i').style.fontSize; - const match = icon.match(/text-[a-z]+-\d+/); - const colorClass = match ? match[0] : ''; - plants.push({ icon, height, color: colorClass }); - }); - setCookie(GARDEN_PLANTS_NAME, JSON.stringify(plants), 365); + loadFocusData(); } - } - checkCookieConsent(); - if (cookiesAccepted) { - loadFocusData(); - } - // ------------------------------ - // EVIL MODE TOGGLE & MODIFICATIONS - // ------------------------------ - evilModeToggle.addEventListener('click', function() { - evilModeActive = !evilModeActive; - if (evilModeActive) { - activateEvilMode(); - } else { - deactivateEvilMode(); - } - localStorage.setItem('evilModeActive', JSON.stringify(evilModeActive)); - }); + // ------------------------------ + // EVIL MODE TOGGLE & MODIFICATIONS + // ------------------------------ + evilModeToggle.addEventListener('click', function () { + evilModeActive = !evilModeActive; + if (evilModeActive) { + activateEvilMode(); + } else { + deactivateEvilMode(); + } + localStorage.setItem('evilModeActive', JSON.stringify(evilModeActive)); + }); - // ------------------------------ - // FOCUS MODE FUNCTIONS - // ------------------------------ - function startFocusMode() { - console.log("DEBUG: Starting focus mode, current focus minutes:", focusMinutes); - elapsedSeconds = 0; - focusTimer = setInterval(() => { - elapsedSeconds++; - updateProgressBar(elapsedSeconds); - if (elapsedSeconds >= 60) { - focusMinutes++; - elapsedSeconds = 0; - focusTimeDisplay.textContent = focusMinutes; - console.log("DEBUG: Focus minute incremented to:", focusMinutes); + // ------------------------------ + // FOCUS MODE FUNCTIONS + // ------------------------------ + function startFocusMode() { + console.log("DEBUG: Starting focus mode, current focus minutes:", focusMinutes); + elapsedSeconds = 0; + focusTimer = setInterval(() => { + elapsedSeconds++; + updateProgressBar(elapsedSeconds); + if (elapsedSeconds >= 60) { + focusMinutes++; + elapsedSeconds = 0; + focusTimeDisplay.textContent = focusMinutes; + console.log("DEBUG: Focus minute incremented to:", focusMinutes); + addRandomGardenElement(); + saveFocusData(); + } + }, 1000); + const expectedPlants = Math.floor(focusMinutes * PLANTS_PER_MINUTE); + const currentPlants = document.querySelectorAll('.garden-plant').length; + if (currentPlants < expectedPlants) { addRandomGardenElement(); - saveFocusData(); } - }, 1000); - const expectedPlants = Math.floor(focusMinutes * PLANTS_PER_MINUTE); - const currentPlants = document.querySelectorAll('.garden-plant').length; - if (currentPlants < expectedPlants) { - addRandomGardenElement(); } - } - function updateProgressBar(seconds) { - const progress = (seconds / 60) * 100; - focusProgress.style.width = `${progress}%`; - } - function addRandomGardenElement() { - console.log("DEBUG: Adding random garden element."); - const plantTypes = [ - { icon: 'fa-seedling', height: '30px', color: 'text-accent-500' }, - { icon: 'fa-leaf', height: '40px', color: 'text-accent-600' }, - { icon: 'fa-tree', height: '50px', color: 'text-accent-700' }, - { icon: 'fa-pagelines', height: '45px', color: 'text-accent-500' } - ]; - const randomPlant = plantTypes[Math.floor(Math.random() * plantTypes.length)]; - addGardenElement(randomPlant.icon, randomPlant.height, randomPlant.color); - } - function addGardenElement(icon, height, color) { - console.log("DEBUG: Adding garden element with icon:", icon, "height:", height, "color:", color); - const element = document.createElement('div'); - element.className = 'garden-plant'; - element.style.position = 'absolute'; - const containerBox = gardenElements.closest('.relative'); - if (containerBox) { - const containerWidth = containerBox.offsetWidth; - const containerHeight = containerBox.offsetHeight; - const randomTop = containerHeight - 60; - let randomLeft; - let overlap; - do { - randomLeft = Math.random() * (containerWidth - 40); - overlap = Array.from(gardenElements.children).some(existingElement => { - const existingRect = existingElement.getBoundingClientRect(); - const newRect = { - left: randomLeft, - top: randomTop, - right: randomLeft + 40, - bottom: randomTop + 40 - }; - return !(newRect.right < existingRect.left || - newRect.left > existingRect.right || - newRect.bottom < existingRect.top || - newRect.top > existingRect.bottom); - }); - } while (overlap); - element.style.left = randomLeft + 'px'; - element.style.top = randomTop + 'px'; - console.log("DEBUG: Plant positioned at:", randomLeft, randomTop); + + function updateProgressBar(seconds) { + const progress = (seconds / 60) * 100; + focusProgress.style.width = `${progress}%`; } - element.innerHTML = ``; - gardenElements.appendChild(element); - } - function startFocusDraining() { - console.log("DEBUG: Starting focus draining."); - clearInterval(focusTimer); - focusTimer = null; - focusDraining.classList.remove('hidden'); - document.title = '⚠️ Focus Draining'; - drainTimer = setInterval(() => { - console.log("DEBUG: Draining focus minute. Current focus minutes:", focusMinutes); - if (focusMinutes > 0) { - focusMinutes--; - focusTimeDisplay.textContent = focusMinutes; - updateProgressBar(0); - saveFocusData(); - if (gardenElements.children.length > 0) { - console.log("DEBUG: Removing a garden element due to focus drain."); - gardenElements.removeChild(gardenElements.lastChild); + + function addRandomGardenElement() { + console.log("DEBUG: Adding random garden element."); + const plantTypes = [{ + image: 'Orange_Flower.png', + height: '50px' + }, + { + image: 'Red_Flower.png', + height: '50px' + }, + { + image: 'Capybara.png', + height: '50px' + }, + { + image: 'Duck.png', + height: '50px' + }, + { + image: 'worm.gif', + height: '50px' + }, + { + image: 'Yellow_Flower.png', + height: '50px' + }, + { + image: 'Purple_Flower.png', + height: '50px' + }, + { + image: 'Blue_Flower.png', + height: '50px' } - } - }, 30000); - } - function stopFocusDraining() { - console.log("DEBUG: Stopping focus draining."); - clearInterval(drainTimer); - drainTimer = null; - focusDraining.classList.add('hidden'); - document.title = originalTitle; - } - document.addEventListener('visibilitychange', function () { - if (document.hidden) { - if (focusModeActive) { - startFocusDraining(); - } - } else { - stopFocusDraining(); - if (focusModeActive && !focusTimer) { - startFocusMode(); - } + + ]; + const randomPlant = plantTypes[Math.floor(Math.random() * plantTypes.length)]; + addGardenElement(randomPlant.image, randomPlant.height); } - }); - // ------------------------------ - // OTHER FUNCTIONALITY (Read Aloud, Font/Spacing, Annotation) - // ------------------------------ - readAloud.addEventListener('click', () => { - if (!isReading) { - isReading = true; - readAloud.classList.add('bg-accent-200', 'dark:bg-accent-800'); - const originalText = readerContent.innerText; - // If evil mode is active, reverse the text before speaking and lower the pitch - const textToSpeak = evilModeActive ? reverseText(originalText) : originalText; - speechUtterance = new SpeechSynthesisUtterance(textToSpeak); - if (evilModeActive) { - speechUtterance.pitch = 0.1; // Lower the pitch for evil mode - speechUtterance.rate = 1.2; // Increase the rate for evil mode + function addGardenElement(image, height) { + const element = document.createElement('div'); + element.className = 'garden-plant'; + element.style.position = 'absolute'; + + const containerBox = gardenElements.closest('.relative'); + if (containerBox) { + const containerWidth = containerBox.offsetWidth; + const containerHeight = containerBox.offsetHeight; + + // We'll assume the hill is roughly in the bottom 40% of the image + const hillStartY = containerHeight * 0.6; + + let randomTop; + let randomLeft; + let overlap; + do { + randomTop = hillStartY + Math.random() * ((containerHeight - 60) - hillStartY); + randomLeft = Math.random() * (containerWidth - 40); + + overlap = Array.from(gardenElements.children).some(existingElement => { + const existingRect = existingElement.getBoundingClientRect(); + const newRect = { + left: randomLeft, + top: randomTop, + right: randomLeft + 40, + bottom: randomTop + 40 + }; + return !( + newRect.right < existingRect.left || + newRect.left > existingRect.right || + newRect.bottom < existingRect.top || + newRect.top > existingRect.bottom + ); + }); + } while (overlap); + + element.style.left = randomLeft + 'px'; + element.style.top = randomTop + 'px'; } - speechUtterance.onend = () => { - isReading = false; - readAloud.classList.remove('bg-accent-200', 'dark:bg-accent-800'); - }; - speechSynthesis.speak(speechUtterance); - } else { - isReading = false; - readAloud.classList.remove('bg-accent-200', 'dark:bg-accent-800'); - speechSynthesis.cancel(); + element.innerHTML = `Flower`; + gardenElements.appendChild(element); } - }); - window.highlightText = function(text) { - console.log('Highlighting text:', text); - const content = readerContent.innerHTML; - const highlightedContent = content.replace(new RegExp(text, 'gi'), match => `${match}`); - readerContent.innerHTML = highlightedContent; - savePreferences(); - } + function startFocusDraining() { + console.log("DEBUG: Starting focus draining."); + clearInterval(focusTimer); + focusTimer = null; + focusDraining.classList.remove('hidden'); + document.title = '⚠️ Focus Draining'; + drainTimer = setInterval(() => { + console.log("DEBUG: Draining focus minute. Current focus minutes:", focusMinutes); + if (focusMinutes > 0) { + focusMinutes--; + focusTimeDisplay.textContent = focusMinutes; + updateProgressBar(0); + saveFocusData(); + if (gardenElements.children.length > 0) { + console.log("DEBUG: Removing a garden element due to focus drain."); + gardenElements.removeChild(gardenElements.lastChild); + } + } + }, 30000); + } - window.removeHighlight = function(text) { - console.log('Removing highlight for text:', text); - const content = readerContent.innerHTML; - const unhighlightedContent = content.replace(/(.*?)<\/span>/gi, (match, p1) => { - return p1.includes(text) ? p1 : match; + function stopFocusDraining() { + console.log("DEBUG: Stopping focus draining."); + clearInterval(drainTimer); + drainTimer = null; + focusDraining.classList.add('hidden'); + document.title = originalTitle; + } + document.addEventListener('visibilitychange', function () { + if (document.hidden) { + if (focusModeActive) { + startFocusDraining(); + } + } else { + stopFocusDraining(); + if (focusModeActive && !focusTimer) { + startFocusMode(); + } + } }); - readerContent.innerHTML = unhighlightedContent; - savePreferences(); - } - const magicHighlight = document.getElementById('magic-highlight'); - const loadingScreen = document.getElementById('loading-screen'); - - magicHighlight.addEventListener('click', function() { - loadingScreen.style.display = 'flex'; - const content = document.getElementById('reader-content').innerText; - - fetch('/api/chat', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - message: `You are a text summarization agent, which has the capability to highlight important aspects or key points of an article below. For all of the text in the article, please respond with a highlight(text) function, stating the exact text that you want highlighted. Separate these functions by semicolons, and ONLY respond with the function calls and nothing else. Feel free to highlight more often, but in shorter segments, as this will help the user. Make the text to highlight EXACTLY what is listed in the article, otherwise the system will not highlight for you. Here is the article: ${content}` - }) - }) - .then(response => response.json()) - .then(data => { - console.log(data); - if (data.success) { - const highlights = data.response.match(/highlight\((.*?)\);/g); - if (highlights) { - highlights.forEach(call => { - const textToHighlight = call.match(/highlight\((.*?)\);/)[1]; - highlightText(textToHighlight.replace(/['"]/g, '')); - }); - } + // ------------------------------ + // OTHER FUNCTIONALITY (Read Aloud, Font/Spacing, Annotation) + // ------------------------------ + readAloud.addEventListener('click', () => { + if (!isReading) { + isReading = true; + readAloud.classList.add('bg-accent-200', 'dark:bg-accent-800'); + const originalText = readerContent.innerText; + // If evil mode is active, reverse the text before speaking and lower the pitch + const textToSpeak = evilModeActive ? reverseText(originalText) : originalText; + speechUtterance = new SpeechSynthesisUtterance(textToSpeak); + if (evilModeActive) { + speechUtterance.pitch = 0.1; // Lower the pitch for evil mode + speechUtterance.rate = 1.2; // Increase the rate for evil mode + } + speechUtterance.onend = () => { + isReading = false; + readAloud.classList.remove('bg-accent-200', 'dark:bg-accent-800'); + }; + speechSynthesis.speak(speechUtterance); } else { - showToast('Error: ' + data.error); + isReading = false; + readAloud.classList.remove('bg-accent-200', 'dark:bg-accent-800'); + speechSynthesis.cancel(); } - }) - .catch(error => { - showToast('Error: ' + error.message); - }) - .finally(() => { - loadingScreen.style.display = 'none'; }); - }); - fontDecrease.addEventListener('click', () => { - if (currentFontSize > 12) { - currentFontSize -= 1; - readerContent.style.fontSize = currentFontSize + 'px'; + window.highlightText = function (text) { + console.log('Highlighting text:', text); + const content = readerContent.innerHTML; + const highlightedContent = content.replace(new RegExp(text, 'gi'), match => + `${match}`); + readerContent.innerHTML = highlightedContent; savePreferences(); } - if (evilModeActive === true) { - readerContent.style.fontSize = '1px'; - } - }); - fontIncrease.addEventListener('click', () => { - if (currentFontSize < 24) { - currentFontSize += 1; - readerContent.style.fontSize = currentFontSize + 'px'; + + window.removeHighlight = function (text) { + console.log('Removing highlight for text:', text); + const content = readerContent.innerHTML; + const unhighlightedContent = content.replace(/(.*?)<\/span>/gi, ( + match, p1) => { + return p1.includes(text) ? p1 : match; + }); + readerContent.innerHTML = unhighlightedContent; savePreferences(); } - if (evilModeActive === true) { - readerContent.style.fontSize = '300px'; - } - }); - fontFamily.addEventListener('change', () => { - switch(fontFamily.value) { - case 'sans': - readerContent.style.fontFamily = 'Arial, ui-sans-serif, system-ui, sans-serif'; - break; - case 'serif': - readerContent.style.fontFamily = 'Georgia, ui-serif, serif'; - break; - case 'mono': - readerContent.style.fontFamily = 'Courier New, ui-monospace, monospace'; - break; - case 'comic': - readerContent.style.fontFamily = 'Comic Sans MS, Comic Sans, cursive'; - break; - case 'times': - readerContent.style.fontFamily = 'Times New Roman, ui-serif, serif'; - break; - case 'verdana': - readerContent.style.fontFamily = 'Verdana, ui-sans-serif, system-ui, sans-serif'; - break; - case 'lex': - readerContent.style.fontFamily = 'OpenDyslexic, ui-sans-serif, system-ui, sans-serif'; - break; - } - savePreferences(); - }); - spacingDecrease.addEventListener('click', () => { - if (currentLineHeight > 1.2) { - currentLineHeight -= 0.1; - readerContent.style.lineHeight = currentLineHeight; + + const magicHighlight = document.getElementById('magic-highlight'); + const loadingScreen = document.getElementById('loading-screen'); + + magicHighlight.addEventListener('click', function () { + loadingScreen.style.display = 'flex'; + const content = document.getElementById('reader-content').innerText; + + fetch('/api/chat', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + message: `You are a text summarization agent, which has the capability to highlight important aspects or key points of an article below. For all of the text in the article, please respond with a highlight(text) function, stating the exact text that you want highlighted. Separate these functions by semicolons, and ONLY respond with the function calls and nothing else. Feel free to highlight more often, but in shorter segments, as this will help the user. Make the text to highlight EXACTLY what is listed in the article, otherwise the system will not highlight for you. Here is the article: ${content}` + }) + }) + .then(response => response.json()) + .then(data => { + console.log(data); + if (data.success) { + const highlights = data.response.match(/highlight\((.*?)\);/g); + if (highlights) { + highlights.forEach(call => { + const textToHighlight = call.match(/highlight\((.*?)\);/)[ + 1]; + highlightText(textToHighlight.replace(/['"]/g, '')); + }); + } + } else { + showToast('Error: ' + data.error); + } + }) + .catch(error => { + showToast('Error: ' + error.message); + }) + .finally(() => { + loadingScreen.style.display = 'none'; + }); + }); + + fontDecrease.addEventListener('click', () => { + if (currentFontSize > 12) { + currentFontSize -= 1; + readerContent.style.fontSize = currentFontSize + 'px'; + savePreferences(); + } + if (evilModeActive === true) { + readerContent.style.fontSize = '1px'; + } + }); + fontIncrease.addEventListener('click', () => { + if (currentFontSize < 24) { + currentFontSize += 1; + readerContent.style.fontSize = currentFontSize + 'px'; + savePreferences(); + } + if (evilModeActive === true) { + readerContent.style.fontSize = '300px'; + } + }); + fontFamily.addEventListener('change', () => { + switch (fontFamily.value) { + case 'sans': + readerContent.style.fontFamily = 'Arial, ui-sans-serif, system-ui, sans-serif'; + break; + case 'serif': + readerContent.style.fontFamily = 'Georgia, ui-serif, serif'; + break; + case 'mono': + readerContent.style.fontFamily = 'Courier New, ui-monospace, monospace'; + break; + case 'comic': + readerContent.style.fontFamily = 'Comic Sans MS, Comic Sans, cursive'; + break; + case 'times': + readerContent.style.fontFamily = 'Times New Roman, ui-serif, serif'; + break; + case 'verdana': + readerContent.style.fontFamily = 'Verdana, ui-sans-serif, system-ui, sans-serif'; + break; + case 'lex': + readerContent.style.fontFamily = + 'OpenDyslexic, ui-sans-serif, system-ui, sans-serif'; + break; + } savePreferences(); - } - }); - spacingIncrease.addEventListener('click', () => { - if (currentLineHeight < 2.5) { - currentLineHeight += 0.1; - readerContent.style.lineHeight = currentLineHeight; + }); + spacingDecrease.addEventListener('click', () => { + if (currentLineHeight > 1.2) { + currentLineHeight -= 0.1; + readerContent.style.lineHeight = currentLineHeight; + savePreferences(); + } + }); + spacingIncrease.addEventListener('click', () => { + if (currentLineHeight < 2.5) { + currentLineHeight += 0.1; + readerContent.style.lineHeight = currentLineHeight; + savePreferences(); + } + }); + fontColorDropdown.addEventListener('change', function () { + const selectedColor = this.value; + switch (selectedColor) { + case 'red': + readerContent.style.color = 'red'; + break; + case 'blue': + readerContent.style.color = 'blue'; + break; + case 'green': + readerContent.style.color = 'green'; + break; + case 'yellow': + readerContent.style.color = 'yellow'; + break; + case 'purple': + readerContent.style.color = 'purple'; + break; + default: + readerContent.style.color = ''; + break; + } savePreferences(); - } - }); - fontColorDropdown.addEventListener('change', function() { - const selectedColor = this.value; - switch(selectedColor) { - case 'red': - readerContent.style.color = 'red'; - break; - case 'blue': - readerContent.style.color = 'blue'; - break; - case 'green': - readerContent.style.color = 'green'; - break; - case 'yellow': - readerContent.style.color = 'yellow'; - break; - case 'purple': - readerContent.style.color = 'purple'; - break; - default: - readerContent.style.color = ''; - break; - } - savePreferences(); - }); + }); - // ------------------------------ - // START FOCUS MODE IF ACTIVE - // ------------------------------ - if (focusModeActive) { - console.log("DEBUG: Page loaded and focus mode active. Starting focus mode."); - startFocusMode(); - } + // ------------------------------ + // START FOCUS MODE IF ACTIVE + // ------------------------------ + if (focusModeActive) { + console.log("DEBUG: Page loaded and focus mode active. Starting focus mode."); + startFocusMode(); + } - // Annotation mode and highlight/eraser tools - const highlightToggle = document.getElementById('highlight-toggle'); - const eraserToggle = document.getElementById('eraser-toggle'); - let activeTool = null; - - function setActiveTool(tool) { - activeTool = tool; - highlightToggle.classList.toggle('bg-primary-200', tool === 'highlight'); - eraserToggle.classList.toggle('bg-primary-200', tool === 'eraser'); - annotationToggle.classList.toggle('bg-primary-200', tool === 'annotation'); - document.body.style.cursor = tool === 'highlight' || tool === 'eraser' || tool === 'annotation' ? 'text' : 'default'; - } + // Annotation mode and highlight/eraser tools + const highlightToggle = document.getElementById('highlight-toggle'); + const eraserToggle = document.getElementById('eraser-toggle'); + let activeTool = null; + + function setActiveTool(tool) { + activeTool = tool; + highlightToggle.classList.toggle('bg-primary-200', tool === 'highlight'); + eraserToggle.classList.toggle('bg-primary-200', tool === 'eraser'); + annotationToggle.classList.toggle('bg-primary-200', tool === 'annotation'); + document.body.style.cursor = tool === 'highlight' || tool === 'eraser' || tool === 'annotation' ? + 'text' : 'default'; + } - highlightToggle.addEventListener('click', function() { - setActiveTool('highlight'); - }); + highlightToggle.addEventListener('click', function () { + setActiveTool('highlight'); + }); - eraserToggle.addEventListener('click', function() { - setActiveTool('eraser'); - }); + eraserToggle.addEventListener('click', function () { + setActiveTool('eraser'); + }); - annotationToggle.addEventListener('click', function() { - setActiveTool('annotation'); - }); + annotationToggle.addEventListener('click', function () { + setActiveTool('annotation'); + }); - document.addEventListener('mouseup', function() { - const selectedText = window.getSelection().toString().trim(); - if (activeTool === 'highlight' && selectedText) { - highlightText(selectedText); - savePreferences(); - } else if (activeTool === 'eraser' && selectedText) { - removeHighlight(selectedText); - savePreferences(); - } else if (activeTool === 'annotation' && selectedText) { - addAnnotation(selectedText); - savePreferences(); - } - }); + document.addEventListener('mouseup', function () { + const selectedText = window.getSelection().toString().trim(); + if (activeTool === 'highlight' && selectedText) { + highlightText(selectedText); + savePreferences(); + } else if (activeTool === 'eraser' && selectedText) { + removeHighlight(selectedText); + savePreferences(); + } else if (activeTool === 'annotation' && selectedText) { + addAnnotation(selectedText); + savePreferences(); + } + }); - function addAnnotation(text, note = '') { - console.log('Adding annotation for text:', text); - const content = readerContent.innerHTML; - const annotatedContent = content.replace(new RegExp(text, 'gi'), match => `${match}`); - readerContent.innerHTML = annotatedContent; - const annotationElement = document.createElement('div'); - annotationElement.className = 'annotation-box'; - annotationElement.innerHTML = ` + function addAnnotation(text, note = '') { + console.log('Adding annotation for text:', text); + const content = readerContent.innerHTML; + const annotatedContent = content.replace(new RegExp(text, 'gi'), match => + `${match}`); + readerContent.innerHTML = annotatedContent; + const annotationElement = document.createElement('div'); + annotationElement.className = 'annotation-box'; + annotationElement.innerHTML = ` `; - document.body.appendChild(annotationElement); - annotationElement.querySelector('.delete-annotation').addEventListener('click', function() { - annotationElement.remove(); - removeAnnotation(text); + document.body.appendChild(annotationElement); + annotationElement.querySelector('.delete-annotation').addEventListener('click', function () { + annotationElement.remove(); + removeAnnotation(text); + savePreferences(); + }); + annotationElement.querySelector('.edit-annotation').addEventListener('click', function () { + annotationElement.querySelector('.annotation-note').disabled = false; + }); + annotationElement.querySelector('.save-annotation').addEventListener('click', function () { + annotationElement.querySelector('.annotation-note').disabled = true; + savePreferences(); + }); savePreferences(); + } + + function removeAnnotation(text) { + const content = readerContent.innerHTML; + const unannotatedContent = content.replace( + /(.*?)<\/span>/gi, (match, p1, + p2) => { + return p1.includes(text) ? p2 : match; + }); + readerContent.innerHTML = unannotatedContent; + } + }); + const colorBlindDropdown = document.getElementById('color-blind'); + + colorBlindDropdown.addEventListener('change', function () { + const selectedValue = this.value; + // Get all images within the reader content container + const images = document.querySelectorAll('#reader-content img'); + + // Remove any previously applied filter classes from all images + images.forEach(img => { + img.classList.remove('deuteranomaly-filter', 'protanomaly-filter', 'deuteranopia-filter', + 'protanopia-filter'); }); - annotationElement.querySelector('.edit-annotation').addEventListener('click', function() { - annotationElement.querySelector('.annotation-note').disabled = false; - }); - annotationElement.querySelector('.save-annotation').addEventListener('click', function() { - annotationElement.querySelector('.annotation-note').disabled = true; - savePreferences(); + + // Apply the appropriate filter based on the user's selection + if (selectedValue === 'deuteranomaly') { + images.forEach(img => img.classList.add('deuteranomaly-filter')); + } else if (selectedValue === 'protanomaly') { + images.forEach(img => img.classList.add('protanomaly-filter')); + } else if (selectedValue === 'deuteranopia') { + images.forEach(img => img.classList.add('deuteranopia-filter')); + } else if (selectedValue === 'protanopia') { + images.forEach(img => img.classList.add('protanopia-filter')); + } + // If "default" is selected, no extra filter classes are applied. + }); + document.addEventListener('DOMContentLoaded', function () { + // Get button and container elements for each dropdown + const btnFontColor = document.getElementById('toggle-font-color'); + const btnFontFamily = document.getElementById('toggle-font-family'); + const btnColorBlind = document.getElementById('toggle-color-blind'); + + const containerFontColor = document.getElementById('dropdown-font-color'); + const containerFontFamily = document.getElementById('dropdown-font-family'); + const containerColorBlind = document.getElementById('dropdown-color-blind'); + + // Toggle font color dropdown + btnFontColor.addEventListener('click', function () { + containerFontColor.classList.toggle('hidden'); }); - savePreferences(); - } - function removeAnnotation(text) { - const content = readerContent.innerHTML; - const unannotatedContent = content.replace(/(.*?)<\/span>/gi, (match, p1, p2) => { - return p1.includes(text) ? p2 : match; + // Toggle font family dropdown + btnFontFamily.addEventListener('click', function () { + containerFontFamily.classList.toggle('hidden'); }); - readerContent.innerHTML = unannotatedContent; - } -}); -const colorBlindDropdown = document.getElementById('color-blind'); -colorBlindDropdown.addEventListener('change', function() { - const selectedValue = this.value; - // Get all images within the reader content container - const images = document.querySelectorAll('#reader-content img'); + // Toggle color blindness dropdown + btnColorBlind.addEventListener('click', function () { + containerColorBlind.classList.toggle('hidden'); + }); + // Close dropdowns when clicking outside + document.addEventListener('click', function (event) { + if (!containerFontColor.contains(event.target) && !btnFontColor.contains(event.target)) { + containerFontColor.classList.add('hidden'); + } + if (!containerFontFamily.contains(event.target) && !btnFontFamily.contains(event.target)) { + containerFontFamily.classList.add('hidden'); + } + if (!containerColorBlind.contains(event.target) && !btnColorBlind.contains(event.target)) { + containerColorBlind.classList.add('hidden'); + } + }); - // Remove any previously applied filter classes from all images - images.forEach(img => { - img.classList.remove('deuteranomaly-filter', 'protanomaly-filter', 'deuteranopia-filter', 'protanopia-filter'); + document.getElementById('font-color').addEventListener('change', function () { + containerFontColor.classList.add('hidden'); + }); + document.getElementById('font-family').addEventListener('change', function () { + containerFontFamily.classList.add('hidden'); + }); + document.getElementById('color-blind').addEventListener('change', function () { + containerColorBlind.classList.add('hidden'); + }); }); - - // Apply the appropriate filter based on the user's selection - if (selectedValue === 'deuteranomaly') { - images.forEach(img => img.classList.add('deuteranomaly-filter')); - } else if (selectedValue === 'protanomaly') { - images.forEach(img => img.classList.add('protanomaly-filter')); - } else if (selectedValue === 'deuteranopia') { - images.forEach(img => img.classList.add('deuteranopia-filter')); - } else if (selectedValue === 'protanopia') { - images.forEach(img => img.classList.add('protanopia-filter')); - } - // If "default" is selected, no extra filter classes are applied. -}); -document.addEventListener('DOMContentLoaded', function() { - // Get button and container elements for each dropdown - const btnFontColor = document.getElementById('toggle-font-color'); - const btnFontFamily = document.getElementById('toggle-font-family'); - const btnColorBlind = document.getElementById('toggle-color-blind'); - - const containerFontColor = document.getElementById('dropdown-font-color'); - const containerFontFamily = document.getElementById('dropdown-font-family'); - const containerColorBlind = document.getElementById('dropdown-color-blind'); - - // Toggle font color dropdown - btnFontColor.addEventListener('click', function() { - containerFontColor.classList.toggle('hidden'); - }); - - // Toggle font family dropdown - btnFontFamily.addEventListener('click', function() { - containerFontFamily.classList.toggle('hidden'); - }); - - // Toggle color blindness dropdown - btnColorBlind.addEventListener('click', function() { - containerColorBlind.classList.toggle('hidden'); - }); - // Close dropdowns when clicking outside - document.addEventListener('click', function(event) { - if (!containerFontColor.contains(event.target) && !btnFontColor.contains(event.target)) { - containerFontColor.classList.add('hidden'); - } - if (!containerFontFamily.contains(event.target) && !btnFontFamily.contains(event.target)) { - containerFontFamily.classList.add('hidden'); - } - if (!containerColorBlind.contains(event.target) && !btnColorBlind.contains(event.target)) { - containerColorBlind.classList.add('hidden'); - } - }); - - document.getElementById('font-color').addEventListener('change', function() { - containerFontColor.classList.add('hidden'); - }); - document.getElementById('font-family').addEventListener('change', function() { - containerFontFamily.classList.add('hidden'); - }); - document.getElementById('color-blind').addEventListener('change', function() { - containerColorBlind.classList.add('hidden'); - }); -}); -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/app/templates/settings.html b/app/templates/settings.html index 5c27155..0e053e3 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -16,6 +16,7 @@

Setti id="secret-key" name="secret_key" required + value="{{ secret_key }}" class="mt-1 block w-full px-3 py-2 border border-primary-300 dark:border-primary-700 rounded-md shadow-sm focus:outline-none focus:ring-accent-500 focus:border-accent-500 sm:text-sm">
@@ -28,7 +29,7 @@

Setti {% else %}
- +

Google Gemini Configuration

@@ -50,20 +51,7 @@

Go Enable Gemini AI Chat API

- -
- - -
-

- +

Flask Configuration

@@ -85,4 +73,6 @@

Fl {% endif %}

-{% endblock %} \ No newline at end of file +{% endblock %} + + \ No newline at end of file