Update to v1.0.4: Multi-language Support (EN, RU, HE)
This commit is contained in:
BIN
MindShift-Windows/MindShift-v1.0.4.apk
Normal file
BIN
MindShift-Windows/MindShift-v1.0.4.apk
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mindshift-cbt-therapy",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"description": "MindShift - Your personal CBT therapy companion for Windows 11",
|
||||
"main": "src/main.js",
|
||||
"homepage": "./",
|
||||
|
||||
@@ -1,4 +1,55 @@
|
||||
import { authAPI, moodAPI, thoughtAPI, gratitudeAPI, progressAPI, notificationAPI, exerciseAPI, isAuthenticated, initializeAPI } from './offline-api.js';
|
||||
import { translations } from './translations.js';
|
||||
|
||||
// Language Management
|
||||
let currentLang = localStorage.getItem('appLang') || 'en';
|
||||
|
||||
function t(key) {
|
||||
const langObj = translations[currentLang] || translations['en'];
|
||||
return langObj[key] || key;
|
||||
}
|
||||
|
||||
function setLanguage(lang) {
|
||||
currentLang = lang;
|
||||
localStorage.setItem('appLang', lang);
|
||||
document.documentElement.lang = lang;
|
||||
document.documentElement.dir = lang === 'he' ? 'rtl' : 'ltr';
|
||||
|
||||
// Update Header
|
||||
updateHeaderTranslations();
|
||||
|
||||
// Re-render current section
|
||||
const activeNav = document.querySelector('.nav-item.active');
|
||||
if (activeNav) {
|
||||
// Identify section from onclick attribute or class
|
||||
// Simple re-render of home if unsure
|
||||
const onclick = activeNav.getAttribute('onclick');
|
||||
if (onclick && onclick.includes("'")) {
|
||||
const section = onclick.split("'")[1];
|
||||
showSection(section);
|
||||
} else {
|
||||
showSection('home');
|
||||
}
|
||||
} else {
|
||||
showSection('home');
|
||||
}
|
||||
|
||||
// Update nav labels
|
||||
document.querySelectorAll('.nav-label').forEach((el, index) => {
|
||||
const keys = ['nav_home', 'nav_mood', 'nav_thoughts', 'nav_gratitude', 'nav_progress'];
|
||||
if (keys[index]) el.textContent = t(keys[index]);
|
||||
});
|
||||
|
||||
// Update Proactive Badge
|
||||
const badge = document.getElementById('proactive-badge');
|
||||
if (badge) badge.textContent = t('proactive_badge');
|
||||
}
|
||||
|
||||
function updateHeaderTranslations() {
|
||||
// Update app title if dynamic, currently static in HTML but let's allow JS update
|
||||
// const title = document.querySelector('.app-title');
|
||||
// if (title) title.innerHTML = `<span class="material-icons">self_improvement</span> ${t('app_title')}`;
|
||||
}
|
||||
|
||||
// Sound Manager using Web Audio API
|
||||
class SoundManager {
|
||||
@@ -72,6 +123,11 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
try {
|
||||
console.log('App initialization started');
|
||||
|
||||
// Initial Language Setup
|
||||
document.documentElement.lang = currentLang;
|
||||
document.documentElement.dir = currentLang === 'he' ? 'rtl' : 'ltr';
|
||||
setLanguage(currentLang); // Updates Nav labels immediately
|
||||
|
||||
// Check authentication
|
||||
if (!isAuthenticated()) {
|
||||
console.log('User not authenticated, showing login modal');
|
||||
@@ -117,7 +173,7 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
console.error('Initialization error:', error);
|
||||
const loader = document.getElementById('initial-loader');
|
||||
if (loader) {
|
||||
loader.innerHTML = `<div style="color: red; padding: 20px;"><h3>Init Error</h3><p>${error.message}</p></div>`;
|
||||
loader.innerHTML = `<div style="color: red; padding: 20px;"><h3>${t('init_error')}</h3><p>${error.message}</p></div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -153,27 +209,37 @@ function triggerSuccessPing() {
|
||||
ping.parentNode.replaceChild(newPing, ping);
|
||||
}
|
||||
|
||||
// Quick Action Menu
|
||||
// Quick Action Menu & Language Selector
|
||||
function showQuickActionMenu() {
|
||||
const menu = document.createElement('div');
|
||||
menu.className = 'exercise-modal';
|
||||
menu.style.display = 'block';
|
||||
menu.innerHTML = `
|
||||
<div class="card">
|
||||
<h3>Quick Actions ⚡</h3>
|
||||
<h3>${t('quick_title')}</h3>
|
||||
|
||||
<div style="margin-bottom: 20px; padding: 10px; background: rgba(0,0,0,0.05); border-radius: 12px;">
|
||||
<label style="display:block; margin-bottom: 8px; font-size: 14px; font-weight: bold;">Language / שפה / Язык</label>
|
||||
<div style="display: flex; gap: 10px; justify-content: center;">
|
||||
<button class="btn btn-sm ${currentLang === 'en' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('en'); this.closest('.exercise-modal').remove()">English</button>
|
||||
<button class="btn btn-sm ${currentLang === 'ru' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('ru'); this.closest('.exercise-modal').remove()">Русский</button>
|
||||
<button class="btn btn-sm ${currentLang === 'he' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('he'); this.closest('.exercise-modal').remove()">עברית</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mood-grid" style="grid-template-columns: 1fr; gap: 10px;">
|
||||
<div class="mood-card" onclick="navigateTo('mood'); this.closest('.exercise-modal').remove()">
|
||||
<span class="mood-label">📝 Log Mood</span>
|
||||
<span class="mood-label">📝 ${t('home_log_mood')}</span>
|
||||
</div>
|
||||
<div class="mood-card" onclick="startBreathing(); this.closest('.exercise-modal').remove()">
|
||||
<span class="mood-label">🌬️ Breathe</span>
|
||||
<span class="mood-label">🌬️ ${t('home_breathe')}</span>
|
||||
</div>
|
||||
<div class="mood-card" onclick="quickRelax(); this.closest('.exercise-modal').remove()">
|
||||
<span class="mood-label">🧘 Relax Now</span>
|
||||
<span class="mood-label">🧘 ${t('quick_relax_now')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="exercise-actions">
|
||||
<button class="btn btn-secondary" onclick="this.closest('.exercise-modal').remove()">Close</button>
|
||||
<button class="btn btn-secondary" onclick="this.closest('.exercise-modal').remove()">${t('close')}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -187,39 +253,44 @@ function showLoginModal() {
|
||||
loginModal.innerHTML = `
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-card">
|
||||
<h2 class="auth-title">Welcome to MindShift</h2>
|
||||
<h2 class="auth-title">${t('auth_welcome')}</h2>
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: center; gap: 10px;">
|
||||
<button class="btn btn-sm ${currentLang === 'en' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('en'); showLoginModal(); document.getElementById('login-modal').remove();">EN</button>
|
||||
<button class="btn btn-sm ${currentLang === 'ru' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('ru'); showLoginModal(); document.getElementById('login-modal').remove();">RU</button>
|
||||
<button class="btn btn-sm ${currentLang === 'he' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('he'); showLoginModal(); document.getElementById('login-modal').remove();">HE</button>
|
||||
</div>
|
||||
<form id="login-form">
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<label>${t('auth_email')}</label>
|
||||
<input type="email" id="email" class="form-input" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<label>${t('auth_password')}</label>
|
||||
<input type="password" id="password" class="form-input" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
<button type="submit" class="btn btn-primary">${t('auth_login')}</button>
|
||||
<p class="switch-form">
|
||||
Don't have an account?
|
||||
<a href="#" onclick="showRegisterForm()">Register</a>
|
||||
${t('auth_no_account')}
|
||||
<a href="#" onclick="showRegisterForm()">${t('auth_register')}</a>
|
||||
</p>
|
||||
</form>
|
||||
<form id="register-form" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>Name</label>
|
||||
<label>${t('auth_name')}</label>
|
||||
<input type="text" id="reg-name" class="form-input" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<label>${t('auth_email')}</label>
|
||||
<input type="email" id="reg-email" class="form-input" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<label>${t('auth_password')}</label>
|
||||
<input type="password" id="reg-password" class="form-input" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Register</button>
|
||||
<button type="submit" class="btn btn-primary">${t('auth_register')}</button>
|
||||
<p class="switch-form">
|
||||
Already have an account?
|
||||
<a href="#" onclick="showLoginForm()">Login</a>
|
||||
${t('auth_has_account')}
|
||||
<a href="#" onclick="showLoginForm()">${t('auth_login')}</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
@@ -243,7 +314,7 @@ async function handleLogin(e) {
|
||||
document.getElementById('login-modal').remove();
|
||||
location.reload();
|
||||
} catch (error) {
|
||||
showToast('Login failed: ' + error.message, 'error');
|
||||
showToast(t('auth_login_failed') + ': ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +329,7 @@ async function handleRegister(e) {
|
||||
document.getElementById('login-modal').remove();
|
||||
location.reload();
|
||||
} catch (error) {
|
||||
showToast('Registration failed: ' + error.message, 'error');
|
||||
showToast(t('auth_reg_failed') + ': ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,14 +378,14 @@ async function saveMoodEntry() {
|
||||
const notes = notesInput ? notesInput.value : '';
|
||||
|
||||
if (!moodType) {
|
||||
showToast('Please select a mood', 'warning');
|
||||
showToast(t('mood_select_warning'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await moodAPI.trackMood(moodType, parseInt(intensity), notes);
|
||||
triggerSuccessPing(); // Alive Feedback
|
||||
showToast('Mood tracked successfully!');
|
||||
showToast(t('mood_saved_success'));
|
||||
|
||||
// Clear form
|
||||
document.querySelectorAll('.mood-card').forEach(card => {
|
||||
@@ -336,7 +407,7 @@ async function saveMoodEntry() {
|
||||
// Update progress
|
||||
await updateProgress();
|
||||
} catch (error) {
|
||||
showToast('Failed to save mood: ' + error.message, 'error');
|
||||
showToast(t('mood_save') + ' failed: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +419,7 @@ async function saveThoughtRecord() {
|
||||
const alternative = document.getElementById('alternative') ? document.getElementById('alternative').value : '';
|
||||
|
||||
if (!situation || !thoughts) {
|
||||
showToast('Please fill in at least the situation and thoughts', 'warning');
|
||||
showToast(t('thought_fill_warning'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -375,13 +446,13 @@ async function saveThoughtRecord() {
|
||||
});
|
||||
|
||||
triggerSuccessPing(); // Alive Feedback
|
||||
showToast('Thought record saved successfully!');
|
||||
showToast(t('thought_saved_success'));
|
||||
closeExercise('thought-record-exercise');
|
||||
|
||||
// Update progress
|
||||
await updateProgress();
|
||||
} catch (error) {
|
||||
showToast('Failed to save thought record: ' + error.message, 'error');
|
||||
showToast(t('thought_save') + ' failed: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +466,7 @@ async function saveGratitudeEntry() {
|
||||
});
|
||||
|
||||
if (entries.length === 0) {
|
||||
showToast('Please add at least one gratitude entry', 'warning');
|
||||
showToast(t('gratitude_empty_warning'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -406,13 +477,13 @@ async function saveGratitudeEntry() {
|
||||
});
|
||||
|
||||
triggerSuccessPing(); // Alive Feedback
|
||||
showToast('Gratitude entries saved successfully!');
|
||||
showToast(t('gratitude_saved_success'));
|
||||
closeExercise('gratitude-exercise');
|
||||
|
||||
// Update progress
|
||||
await updateProgress();
|
||||
} catch (error) {
|
||||
showToast('Failed to save gratitude entries: ' + error.message, 'error');
|
||||
showToast(t('gratitude_save') + ' failed: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,19 +522,19 @@ async function updateProgress() {
|
||||
const statsHTML = `
|
||||
<div class="progress-card">
|
||||
<div class="progress-value">${(stats.today && stats.today.mood_score) ? stats.today.mood_score : '-'}</div>
|
||||
<div class="progress-label">Today's Mood</div>
|
||||
<div class="progress-label">${t('home_stats_mood')}</div>
|
||||
</div>
|
||||
<div class="progress-card">
|
||||
<div class="progress-value">${(stats.totals && stats.totals.totalSessions) ? stats.totals.totalSessions : 0}</div>
|
||||
<div class="progress-label">Sessions</div>
|
||||
<div class="progress-label">${t('home_stats_sessions')}</div>
|
||||
</div>
|
||||
<div class="progress-card">
|
||||
<div class="progress-value">${(stats.week && stats.week.avgMood) ? (Math.round(stats.week.avgMood * 10) / 10) : '-'}</div>
|
||||
<div class="progress-label">Weekly Avg</div>
|
||||
<div class="progress-label">${t('home_stats_avg')}</div>
|
||||
</div>
|
||||
<div class="progress-card">
|
||||
<div class="progress-value">${(stats.totals && stats.totals.totalGratitude) ? stats.totals.totalGratitude : 0}</div>
|
||||
<div class="progress-label">Gratitude</div>
|
||||
<div class="progress-label">${t('home_stats_gratitude')}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -491,7 +562,7 @@ async function updateProgress() {
|
||||
<div class="progress-container">
|
||||
<div class="progress-card" onclick="updateProgress()">
|
||||
<div class="progress-value">⚠️</div>
|
||||
<div class="progress-label">Tap to Retry</div>
|
||||
<div class="progress-label">${t('home_retry')}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -540,6 +611,7 @@ window.addNotification = addNotification;
|
||||
window.logout = logout;
|
||||
window.toggleNotifications = toggleNotifications;
|
||||
window.renderHistory = renderHistory;
|
||||
window.setLanguage = setLanguage;
|
||||
|
||||
// Logout function
|
||||
async function logout() {
|
||||
@@ -619,19 +691,8 @@ function createParticles() {
|
||||
}
|
||||
|
||||
function startQuoteRotation() {
|
||||
const quotes = [
|
||||
"You are stronger than you think! 💪",
|
||||
"Every moment is a fresh beginning! 🌅",
|
||||
"Your potential is limitless! ✨",
|
||||
"You've got this! Keep going! 🚀",
|
||||
"Believe in yourself! 🌟"
|
||||
];
|
||||
|
||||
let quoteIndex = 0;
|
||||
setInterval(() => {
|
||||
quoteIndex = (quoteIndex + 1) % quotes.length;
|
||||
// You can display these quotes in a dedicated element
|
||||
}, 5000);
|
||||
// Quotes could also be translated, but keeping them static or random is fine for now
|
||||
// Ideally, add quotes to translations.js
|
||||
}
|
||||
|
||||
function initializeEmotionSliders() {
|
||||
@@ -679,7 +740,7 @@ function drawWeeklyChart(history) {
|
||||
const dayEntry = history.find(entry => entry.date === dateStr);
|
||||
const score = dayEntry ? dayEntry.mood_score : 0;
|
||||
|
||||
days.push(date.toLocaleDateString('en', { weekday: 'short' }));
|
||||
days.push(date.toLocaleDateString(currentLang, { weekday: 'short' })); // Localized dates
|
||||
scores.push(score);
|
||||
}
|
||||
|
||||
@@ -694,6 +755,11 @@ function drawWeeklyChart(history) {
|
||||
|
||||
scores.forEach((score, index) => {
|
||||
const barHeight = (score / maxValue) * (height - 40);
|
||||
|
||||
// RTL adjustment for chart drawing? No, canvas is coordinate based.
|
||||
// But the order of days might need to be right-to-left for Hebrew visually?
|
||||
// Standard charts usually go left-to-right (past -> future) even in RTL.
|
||||
|
||||
const x = index * spacing + (spacing - barWidth) / 2;
|
||||
const y = height - barHeight - 20;
|
||||
|
||||
@@ -745,7 +811,7 @@ async function initializeNotifications() {
|
||||
</button>
|
||||
</div>
|
||||
`).join('')
|
||||
: '<div class="no-notifications">No notifications</div>';
|
||||
: `<div class="no-notifications">${t('notifications_empty')}</div>`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load notifications:', error);
|
||||
@@ -777,7 +843,7 @@ async function initializeNotifications() {
|
||||
</button>
|
||||
</div>
|
||||
`).join('')
|
||||
: '<div class="no-notifications">No notifications</div>';
|
||||
: `<div class="no-notifications">${t('notifications_empty')}</div>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -787,10 +853,10 @@ function formatTime(timestamp) {
|
||||
const now = new Date();
|
||||
const diff = now - date;
|
||||
|
||||
if (diff < 60000) return 'Just now';
|
||||
if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
|
||||
if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
|
||||
return date.toLocaleDateString();
|
||||
if (diff < 60000) return t('just_now');
|
||||
if (diff < 3600000) return `${Math.floor(diff / 60000)}${t('ago_m')}`;
|
||||
if (diff < 86400000) return `${Math.floor(diff / 3600000)}${t('ago_h')}`;
|
||||
return date.toLocaleDateString(currentLang);
|
||||
}
|
||||
|
||||
async function deleteNotification(id) {
|
||||
@@ -861,16 +927,16 @@ async function renderHistory(type) {
|
||||
case 'mood':
|
||||
data = await moodAPI.getMoodHistory();
|
||||
if (data.length === 0) {
|
||||
content = '<div class="empty-state">No mood entries yet. Start tracking! 📝</div>';
|
||||
content = `<div class="empty-state">${t('history_empty_mood')}</div>`;
|
||||
} else {
|
||||
content = data.map(entry => `
|
||||
<div class="history-item" style="border-left: 4px solid var(--${entry.mood_type})">
|
||||
<div class="history-item" style="border-inline-start: 4px solid var(--${entry.mood_type})">
|
||||
<div class="history-header">
|
||||
<span class="history-type">${getMoodEmoji(entry.mood_type)} ${capitalize(entry.mood_type)}</span>
|
||||
<span class="history-type">${getMoodEmoji(entry.mood_type)} ${t('mood_' + entry.mood_type)}</span>
|
||||
<span class="history-date">${formatDate(entry.created_at)}</span>
|
||||
</div>
|
||||
<div class="history-details">
|
||||
Intensity: <strong>${entry.intensity}/10</strong>
|
||||
${t('mood_intensity')}: <strong>${entry.intensity}/10</strong>
|
||||
${entry.notes ? `<p class="history-notes">"${entry.notes}"</p>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
@@ -881,18 +947,18 @@ async function renderHistory(type) {
|
||||
case 'thoughts':
|
||||
data = await thoughtAPI.getThoughtRecords();
|
||||
if (data.length === 0) {
|
||||
content = '<div class="empty-state">No thought records yet. 🧠</div>';
|
||||
content = `<div class="empty-state">${t('history_empty_thoughts')}</div>`;
|
||||
} else {
|
||||
content = data.map(entry => `
|
||||
<div class="history-item" style="border-left: 4px solid var(--primary)">
|
||||
<div class="history-item" style="border-inline-start: 4px solid var(--primary)">
|
||||
<div class="history-header">
|
||||
<span class="history-type">Thought Record</span>
|
||||
<span class="history-type">${t('thought_title')}</span>
|
||||
<span class="history-date">${formatDate(entry.created_at)}</span>
|
||||
</div>
|
||||
<div class="history-details">
|
||||
<div style="margin-bottom: 4px;"><strong>Situation:</strong> ${entry.situation}</div>
|
||||
<div style="margin-bottom: 4px;"><strong>Thought:</strong> ${entry.automatic_thought}</div>
|
||||
<div><strong>Emotion:</strong> ${entry.emotion} (${entry.emotion_intensity}%)</div>
|
||||
<div style="margin-bottom: 4px;"><strong>${t('thought_situation').split('(')[0]}:</strong> ${entry.situation}</div>
|
||||
<div style="margin-bottom: 4px;"><strong>${t('thought_automatic').split('(')[0]}:</strong> ${entry.automatic_thought}</div>
|
||||
<div><strong>${t('thought_emotions')}:</strong> ${entry.emotion} (${entry.emotion_intensity}%)</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
@@ -902,12 +968,12 @@ async function renderHistory(type) {
|
||||
case 'gratitude':
|
||||
data = await gratitudeAPI.getGratitudeEntries();
|
||||
if (data.length === 0) {
|
||||
content = '<div class="empty-state">No gratitude entries yet. 🙏</div>';
|
||||
content = `<div class="empty-state">${t('history_empty_gratitude')}</div>`;
|
||||
} else {
|
||||
content = data.map(entry => `
|
||||
<div class="history-item" style="border-left: 4px solid var(--joy)">
|
||||
<div class="history-item" style="border-inline-start: 4px solid var(--joy)">
|
||||
<div class="history-header">
|
||||
<span class="history-type">Gratitude</span>
|
||||
<span class="history-type">${t('nav_gratitude')}</span>
|
||||
<span class="history-date">${formatDate(entry.created_at)}</span>
|
||||
</div>
|
||||
<div class="history-details">
|
||||
@@ -928,7 +994,7 @@ async function renderHistory(type) {
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
container.innerHTML = `<div class="error-state">Failed to load history: ${error.message}</div>`;
|
||||
container.innerHTML = `<div class="error-state">${error.message}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,7 +1012,7 @@ function capitalize(str) {
|
||||
|
||||
function formatDate(dateStr) {
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
||||
return date.toLocaleDateString(currentLang) + ' ' + date.toLocaleTimeString(currentLang, {hour: '2-digit', minute:'2-digit'});
|
||||
}
|
||||
|
||||
// Render Dynamic Content
|
||||
@@ -965,26 +1031,26 @@ function showSection(sectionId) {
|
||||
case 'home':
|
||||
mainContent.innerHTML = `
|
||||
<div class="card" style="animation: slideInUp 0.5s ease-out;">
|
||||
<h2 class="card-title">Welcome Back! 🌟</h2>
|
||||
<p style="margin-bottom: 20px;">Ready to shift your mind?</p>
|
||||
<h2 class="card-title">${t('home_welcome')}</h2>
|
||||
<p style="margin-bottom: 20px;">${t('home_subtitle')}</p>
|
||||
<div class="mood-grid" style="grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));">
|
||||
<div class="mood-card" onclick="navigateTo('mood')">
|
||||
<span class="mood-emoji">📝</span>
|
||||
<span class="mood-label">Log Mood</span>
|
||||
<span class="mood-label">${t('home_log_mood')}</span>
|
||||
</div>
|
||||
<div class="mood-card" onclick="navigateTo('thoughts')">
|
||||
<span class="mood-emoji">🧠</span>
|
||||
<span class="mood-label">Record Thought</span>
|
||||
<span class="mood-label">${t('home_record_thought')}</span>
|
||||
</div>
|
||||
<div class="mood-card" onclick="navigateTo('gratitude')">
|
||||
<span class="mood-emoji">🙏</span>
|
||||
<span class="mood-label">Gratitude</span>
|
||||
<span class="mood-label">${t('home_gratitude')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="animation: slideInUp 0.6s ease-out;">
|
||||
<h2 class="card-title">Daily Vibe Check 📊</h2>
|
||||
<h2 class="card-title">${t('home_daily_vibe')}</h2>
|
||||
<div id="home-stats-container">
|
||||
<!-- Stats loaded dynamically -->
|
||||
<div class="progress-container">
|
||||
@@ -996,15 +1062,15 @@ function showSection(sectionId) {
|
||||
</div>
|
||||
|
||||
<div class="card" style="animation: slideInUp 0.7s ease-out;">
|
||||
<h2 class="card-title">Quick Relief 🌿</h2>
|
||||
<h2 class="card-title">${t('home_quick_relief')}</h2>
|
||||
<div class="mood-grid" style="grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));">
|
||||
<div class="mood-card" onclick="startBreathing()">
|
||||
<span class="mood-emoji">🌬️</span>
|
||||
<span class="mood-label">Breathe</span>
|
||||
<span class="mood-label">${t('home_breathe')}</span>
|
||||
</div>
|
||||
<div class="mood-card" onclick="quickRelax()">
|
||||
<span class="mood-emoji">🧘</span>
|
||||
<span class="mood-label">Relax</span>
|
||||
<span class="mood-label">${t('home_relax')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1015,46 +1081,46 @@ function showSection(sectionId) {
|
||||
case 'mood':
|
||||
mainContent.innerHTML = `
|
||||
<div class="card" style="animation: fadeIn 0.5s;">
|
||||
<h2 class="card-title">How are you feeling?</h2>
|
||||
<h2 class="card-title">${t('mood_title')}</h2>
|
||||
<div class="mood-grid">
|
||||
<div class="mood-card" data-mood="joy" onclick="selectMood(this, 'joy')">
|
||||
<span class="mood-emoji">😊</span>
|
||||
<span class="mood-label">Joy</span>
|
||||
<span class="mood-label">${t('mood_joy')}</span>
|
||||
</div>
|
||||
<div class="mood-card" data-mood="peace" onclick="selectMood(this, 'peace')">
|
||||
<span class="mood-emoji">😌</span>
|
||||
<span class="mood-label">Peace</span>
|
||||
<span class="mood-label">${t('mood_peace')}</span>
|
||||
</div>
|
||||
<div class="mood-card" data-mood="energy" onclick="selectMood(this, 'energy')">
|
||||
<span class="mood-emoji">⚡</span>
|
||||
<span class="mood-label">Energy</span>
|
||||
<span class="mood-label">${t('mood_energy')}</span>
|
||||
</div>
|
||||
<div class="mood-card" data-mood="anxiety" onclick="selectMood(this, 'anxiety')">
|
||||
<span class="mood-emoji">😰</span>
|
||||
<span class="mood-label">Anxiety</span>
|
||||
<span class="mood-label">${t('mood_anxiety')}</span>
|
||||
</div>
|
||||
<div class="mood-card" data-mood="sadness" onclick="selectMood(this, 'sadness')">
|
||||
<span class="mood-emoji">😢</span>
|
||||
<span class="mood-label">Sadness</span>
|
||||
<span class="mood-label">${t('mood_sadness')}</span>
|
||||
</div>
|
||||
<div class="mood-card" data-mood="anger" onclick="selectMood(this, 'anger')">
|
||||
<span class="mood-emoji">😠</span>
|
||||
<span class="mood-label">Anger</span>
|
||||
<span class="mood-label">${t('mood_anger')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="intensity-container">
|
||||
<div class="intensity-label">
|
||||
<span>Intensity</span>
|
||||
<span>${t('mood_intensity')}</span>
|
||||
<span id="intensityValue" style="color: var(--primary); font-weight: bold;">5</span>
|
||||
</div>
|
||||
<input type="range" class="slider" min="1" max="10" value="5" oninput="updateIntensity(this.value)">
|
||||
</div>
|
||||
|
||||
<textarea id="moodNotes" class="form-input" placeholder="Any thoughts?" style="width: 100%; margin: 20px 0; min-height: 100px;"></textarea>
|
||||
<textarea id="moodNotes" class="form-input" placeholder="${t('mood_notes_placeholder')}" style="width: 100%; margin: 20px 0; min-height: 100px;"></textarea>
|
||||
|
||||
<button class="btn btn-primary btn-block" onclick="saveMoodEntry()">
|
||||
Save Mood
|
||||
${t('mood_save')}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
@@ -1063,36 +1129,36 @@ function showSection(sectionId) {
|
||||
case 'thoughts':
|
||||
mainContent.innerHTML = `
|
||||
<div id="thought-record-exercise" class="card" style="animation: fadeIn 0.5s;">
|
||||
<h2 class="card-title">Thought Record 🧠</h2>
|
||||
<h2 class="card-title">${t('thought_title')}</h2>
|
||||
<div class="form-group">
|
||||
<label>Situation (Who, what, where, when?)</label>
|
||||
<label>${t('thought_situation')}</label>
|
||||
<textarea id="situation" class="form-input" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Automatic Thoughts (What went through your mind?)</label>
|
||||
<label>${t('thought_automatic')}</label>
|
||||
<textarea id="thoughts" class="form-input" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Emotions</label>
|
||||
<label>${t('thought_emotions')}</label>
|
||||
<div id="emotion-inputs-container">
|
||||
<div class="emotion-inputs">
|
||||
<input type="text" class="form-input emotion-name" placeholder="Emotion">
|
||||
<input type="text" class="form-input emotion-name" placeholder="${t('thought_emotions')}">
|
||||
<input type="range" class="emotion-slider" min="0" max="100" value="50">
|
||||
<span class="emotion-value">50</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary btn-sm" onclick="addEmotionInput()">+ Add Emotion</button>
|
||||
<button type="button" class="btn btn-secondary btn-sm" onclick="addEmotionInput()">${t('thought_add_emotion')}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Evidence For/Against</label>
|
||||
<label>${t('thought_evidence')}</label>
|
||||
<textarea id="evidence" class="form-input" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Alternative Thought</label>
|
||||
<label>${t('thought_alternative')}</label>
|
||||
<textarea id="alternative" class="form-input" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="exercise-actions">
|
||||
<button class="btn btn-primary" onclick="saveThoughtRecord()">Save Record</button>
|
||||
<button class="btn btn-primary" onclick="saveThoughtRecord()">${t('thought_save')}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1102,16 +1168,16 @@ function showSection(sectionId) {
|
||||
case 'gratitude':
|
||||
mainContent.innerHTML = `
|
||||
<div id="gratitude-exercise" class="card" style="animation: fadeIn 0.5s;">
|
||||
<h2 class="card-title">Gratitude Journal 🙏</h2>
|
||||
<p class="exercise-intro">List 3 things you are grateful for today:</p>
|
||||
<h2 class="card-title">${t('gratitude_title')}</h2>
|
||||
<p class="exercise-intro">${t('gratitude_intro')}</p>
|
||||
<div class="gratitude-list gratitude-inputs">
|
||||
<input type="text" class="form-input gratitude-input" placeholder="1. I am grateful for...">
|
||||
<input type="text" class="form-input gratitude-input" placeholder="2. I am grateful for...">
|
||||
<input type="text" class="form-input gratitude-input" placeholder="3. I am grateful for...">
|
||||
<input type="text" class="form-input gratitude-input" placeholder="${t('gratitude_placeholder')}">
|
||||
<input type="text" class="form-input gratitude-input" placeholder="${t('gratitude_placeholder')}">
|
||||
<input type="text" class="form-input gratitude-input" placeholder="${t('gratitude_placeholder')}">
|
||||
</div>
|
||||
<button class="btn btn-secondary" onclick="addGratitudeInput()" style="margin-bottom: 20px;">+ Add Another</button>
|
||||
<button class="btn btn-secondary" onclick="addGratitudeInput()" style="margin-bottom: 20px;">${t('gratitude_add')}</button>
|
||||
<div class="exercise-actions">
|
||||
<button class="btn btn-primary" onclick="saveGratitudeEntry()">Save Entry</button>
|
||||
<button class="btn btn-primary" onclick="saveGratitudeEntry()">${t('gratitude_save')}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1120,29 +1186,28 @@ function showSection(sectionId) {
|
||||
case 'progress':
|
||||
mainContent.innerHTML = `
|
||||
<div class="card" style="animation: slideInUp 0.5s;">
|
||||
<h2 class="card-title">Your Progress 📈</h2>
|
||||
<h2 class="card-title">${t('progress_title')}</h2>
|
||||
<div id="progress-stats" class="progress-container">
|
||||
<!-- Stats will be loaded here -->
|
||||
<div class="progress-card"><div class="progress-value"><div class="spinner" style="width: 24px; height: 24px; border-width: 3px;"></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="animation: slideInUp 0.6s;">
|
||||
<h2 class="card-title">Weekly Mood 📅</h2>
|
||||
<h2 class="card-title">${t('progress_weekly')}</h2>
|
||||
<div class="chart-container">
|
||||
<canvas id="weeklyChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="animation: slideInUp 0.7s;">
|
||||
<h2 class="card-title">Recent History 📜</h2>
|
||||
<h2 class="card-title">${t('progress_history')}</h2>
|
||||
<div class="tabs" style="display: flex; gap: 10px; margin-bottom: 20px;">
|
||||
<button class="btn btn-secondary btn-sm" onclick="renderHistory('mood')">Moods</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="renderHistory('thoughts')">Thoughts</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="renderHistory('gratitude')">Gratitude</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="renderHistory('mood')">${t('history_tab_moods')}</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="renderHistory('thoughts')">${t('history_tab_thoughts')}</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="renderHistory('gratitude')">${t('history_tab_gratitude')}</button>
|
||||
</div>
|
||||
<div id="history-container" class="history-list">
|
||||
<!-- History items will be loaded here -->
|
||||
<div style="text-align: center; color: var(--on-surface-variant);">Select a category to view history</div>
|
||||
<div style="text-align: center; color: var(--on-surface-variant);">${t('history_select_prompt')}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1152,43 +1217,6 @@ function showSection(sectionId) {
|
||||
}
|
||||
}
|
||||
|
||||
// Keep existing navigation and UI functions
|
||||
function showSection_OLD(sectionId) {
|
||||
document.querySelectorAll('.section').forEach(section => {
|
||||
section.classList.remove('active');
|
||||
});
|
||||
|
||||
document.getElementById(sectionId).classList.add('active');
|
||||
|
||||
document.querySelectorAll('.nav-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
event.target.closest('.nav-item').classList.add('active');
|
||||
|
||||
if (sectionId === 'analytics') {
|
||||
loadAnalyticsData();
|
||||
}
|
||||
}
|
||||
|
||||
function showSituationBuilder() {
|
||||
showSection('situation-builder');
|
||||
document.querySelectorAll('.nav-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
}
|
||||
|
||||
function generateExercises() {
|
||||
showSection('exercises');
|
||||
document.querySelectorAll('.nav-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
document.querySelectorAll('.nav-item')[1].classList.add('active');
|
||||
}
|
||||
|
||||
function startExercise(type) {
|
||||
alert(`Starting ${type} exercise... This would open the exercise interface.`);
|
||||
}
|
||||
|
||||
function quickRelax() {
|
||||
// Launch the new Guided Grounding Experience
|
||||
startGuidedRelaxation();
|
||||
@@ -1198,53 +1226,58 @@ function quickRelax() {
|
||||
let relaxationState = {
|
||||
step: 0,
|
||||
isActive: false,
|
||||
steps: [
|
||||
steps: [] // Will be populated dynamically based on language
|
||||
};
|
||||
|
||||
function getRelaxationSteps() {
|
||||
return [
|
||||
{
|
||||
title: "Sight",
|
||||
instruction: "Look around you.",
|
||||
sub: "Find 5 things you can see.",
|
||||
title: t('guided_sight_title'),
|
||||
instruction: t('guided_sight_instruction'),
|
||||
sub: t('guided_sight_sub'),
|
||||
count: 5,
|
||||
icon: "👁️",
|
||||
color: "#64B5F6"
|
||||
},
|
||||
{
|
||||
title: "Touch",
|
||||
instruction: "Feel the textures.",
|
||||
sub: "Find 4 things you can touch.",
|
||||
title: t('guided_touch_title'),
|
||||
instruction: t('guided_touch_instruction'),
|
||||
sub: t('guided_touch_sub'),
|
||||
count: 4,
|
||||
icon: "✋",
|
||||
color: "#81C784"
|
||||
},
|
||||
{
|
||||
title: "Sound",
|
||||
instruction: "Listen carefully.",
|
||||
sub: "Identify 3 sounds you hear.",
|
||||
title: t('guided_sound_title'),
|
||||
instruction: t('guided_sound_instruction'),
|
||||
sub: t('guided_sound_sub'),
|
||||
count: 3,
|
||||
icon: "👂",
|
||||
color: "#FFB74D"
|
||||
},
|
||||
{
|
||||
title: "Smell",
|
||||
instruction: "Breathe in deep.",
|
||||
sub: "Notice 2 things you can smell.",
|
||||
title: t('guided_smell_title'),
|
||||
instruction: t('guided_smell_instruction'),
|
||||
sub: t('guided_smell_sub'),
|
||||
count: 2,
|
||||
icon: "👃",
|
||||
color: "#BA68C8"
|
||||
},
|
||||
{
|
||||
title: "Taste",
|
||||
instruction: "Focus on your mouth.",
|
||||
sub: "Find 1 thing you can taste.",
|
||||
title: t('guided_taste_title'),
|
||||
instruction: t('guided_taste_instruction'),
|
||||
sub: t('guided_taste_sub'),
|
||||
count: 1,
|
||||
icon: "👅",
|
||||
color: "#E57373"
|
||||
}
|
||||
]
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
function startGuidedRelaxation() {
|
||||
relaxationState.step = 0;
|
||||
relaxationState.isActive = true;
|
||||
relaxationState.steps = getRelaxationSteps();
|
||||
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'guided-relaxation-overlay';
|
||||
@@ -1280,7 +1313,7 @@ function renderRelaxationStep() {
|
||||
</div>
|
||||
|
||||
<button class="guided-action-btn" onclick="nextRelaxationSubStep()">
|
||||
I found one
|
||||
${t('guided_found_btn')}
|
||||
</button>
|
||||
`;
|
||||
|
||||
@@ -1320,13 +1353,13 @@ function finishGuidedRelaxation() {
|
||||
if (overlay) {
|
||||
overlay.innerHTML = `
|
||||
<div class="guided-step-icon">🌟</div>
|
||||
<div class="guided-instruction">You did great!</div>
|
||||
<div class="guided-sub">Feeling more grounded?</div>
|
||||
<div class="guided-instruction">${t('guided_complete_title')}</div>
|
||||
<div class="guided-sub">${t('guided_complete_sub')}</div>
|
||||
<button class="guided-action-btn" onclick="closeGuidedRelaxation()">
|
||||
Complete
|
||||
${t('guided_complete_btn')}
|
||||
</button>
|
||||
`;
|
||||
speakText("You did great. Feeling more grounded?");
|
||||
speakText(`${t('guided_complete_title')} ${t('guided_complete_sub')}`);
|
||||
triggerSuccessPing();
|
||||
}
|
||||
}
|
||||
@@ -1353,6 +1386,15 @@ function speakText(text) {
|
||||
const utterance = new SpeechSynthesisUtterance(text);
|
||||
utterance.rate = 0.9;
|
||||
utterance.pitch = 1.0;
|
||||
|
||||
// Map language codes to TTS locales
|
||||
const langMap = {
|
||||
'en': 'en-US',
|
||||
'ru': 'ru-RU',
|
||||
'he': 'he-IL'
|
||||
};
|
||||
utterance.lang = langMap[currentLang] || 'en-US';
|
||||
|
||||
window.speechSynthesis.speak(utterance);
|
||||
}
|
||||
}
|
||||
@@ -1361,7 +1403,7 @@ function finishRelaxSession(btn) {
|
||||
btn.closest('.exercise-modal').remove();
|
||||
exerciseAPI.logSession('relaxation', 120).then(() => {
|
||||
triggerSuccessPing();
|
||||
showSuccessMessage('Relaxation session logged! 🧘');
|
||||
showToast(t('mood_saved_success')); // Reuse success message or create new
|
||||
updateProgress();
|
||||
});
|
||||
}
|
||||
@@ -1375,23 +1417,20 @@ function emergencyHelp() {
|
||||
}
|
||||
|
||||
function startThoughtRecord() {
|
||||
document.getElementById('thought-record-exercise').style.display = 'block';
|
||||
document.getElementById('exercises').classList.add('blur-background');
|
||||
showSection('thoughts');
|
||||
}
|
||||
|
||||
function startMindfulness() {
|
||||
document.getElementById('mindfulness-exercise').style.display = 'block';
|
||||
document.getElementById('exercises').classList.add('blur-background');
|
||||
// Implement or route
|
||||
}
|
||||
|
||||
function startGratitude() {
|
||||
document.getElementById('gratitude-exercise').style.display = 'block';
|
||||
document.getElementById('exercises').classList.add('blur-background');
|
||||
showSection('gratitude');
|
||||
}
|
||||
|
||||
function closeExercise(exerciseId) {
|
||||
document.getElementById(exerciseId).style.display = 'none';
|
||||
document.getElementById('exercises').classList.remove('blur-background');
|
||||
showSection('home');
|
||||
}
|
||||
|
||||
function addEmotionInput() {
|
||||
@@ -1399,7 +1438,7 @@ function addEmotionInput() {
|
||||
const newEmotionInput = document.createElement('div');
|
||||
newEmotionInput.className = 'emotion-inputs';
|
||||
newEmotionInput.innerHTML = `
|
||||
<input type="text" class="form-input emotion-name" placeholder="Emotion">
|
||||
<input type="text" class="form-input emotion-name" placeholder="${t('thought_emotions')}">
|
||||
<input type="range" class="emotion-slider" min="0" max="100" value="50">
|
||||
<span class="emotion-value">50</span>
|
||||
<button type="button" class="btn-remove" onclick="this.parentElement.remove()">×</button>
|
||||
@@ -1413,7 +1452,7 @@ function addGratitudeInput() {
|
||||
const newInput = document.createElement('input');
|
||||
newInput.type = 'text';
|
||||
newInput.className = 'form-input gratitude-input';
|
||||
newInput.placeholder = 'Something you\'re grateful for...';
|
||||
newInput.placeholder = t('gratitude_placeholder');
|
||||
gratitudeContainer.appendChild(newInput);
|
||||
}
|
||||
|
||||
@@ -1424,46 +1463,52 @@ let breathingState = {
|
||||
timer: null
|
||||
};
|
||||
|
||||
const breathingTechniques = {
|
||||
function getBreathingTechniques() {
|
||||
return {
|
||||
balance: {
|
||||
name: 'Balance',
|
||||
label: 'Coherent Breathing',
|
||||
label: t('breath_balance'),
|
||||
phases: [
|
||||
{ name: 'inhale', duration: 5500, label: 'Breathe In', scale: 1.8 },
|
||||
{ name: 'exhale', duration: 5500, label: 'Breathe Out', scale: 1.0 }
|
||||
{ name: 'inhale', duration: 5500, label: t('breath_in'), scale: 1.8 },
|
||||
{ name: 'exhale', duration: 5500, label: t('breath_out'), scale: 1.0 }
|
||||
]
|
||||
},
|
||||
relax: {
|
||||
name: 'Relax',
|
||||
label: '4-7-8 Relief',
|
||||
label: t('breath_relax'),
|
||||
phases: [
|
||||
{ name: 'inhale', duration: 4000, label: 'Breathe In', scale: 1.8 },
|
||||
{ name: 'hold', duration: 7000, label: 'Hold', scale: 1.8 },
|
||||
{ name: 'exhale', duration: 8000, label: 'Breathe Out', scale: 1.0 }
|
||||
{ name: 'inhale', duration: 4000, label: t('breath_in'), scale: 1.8 },
|
||||
{ name: 'hold', duration: 7000, label: t('breath_hold'), scale: 1.8 },
|
||||
{ name: 'exhale', duration: 8000, label: t('breath_out'), scale: 1.0 }
|
||||
]
|
||||
},
|
||||
focus: {
|
||||
name: 'Focus',
|
||||
label: 'Box Breathing',
|
||||
label: t('breath_focus'),
|
||||
phases: [
|
||||
{ name: 'inhale', duration: 4000, label: 'Breathe In', scale: 1.8 },
|
||||
{ name: 'hold', duration: 4000, label: 'Hold', scale: 1.8 },
|
||||
{ name: 'exhale', duration: 4000, label: 'Breathe Out', scale: 1.0 },
|
||||
{ name: 'hold', duration: 4000, label: 'Hold', scale: 1.0 }
|
||||
{ name: 'inhale', duration: 4000, label: t('breath_in'), scale: 1.8 },
|
||||
{ name: 'hold', duration: 4000, label: t('breath_hold'), scale: 1.8 },
|
||||
{ name: 'exhale', duration: 4000, label: t('breath_out'), scale: 1.0 },
|
||||
{ name: 'hold', duration: 4000, label: t('breath_hold'), scale: 1.0 }
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function startBreathing() {
|
||||
// Create immersive overlay
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'smart-breathing-overlay';
|
||||
overlay.className = 'breathing-overlay';
|
||||
|
||||
// Render techniques dynamically
|
||||
const techniques = getBreathingTechniques();
|
||||
|
||||
overlay.innerHTML = `
|
||||
<div class="technique-selector">
|
||||
<button class="technique-btn" onclick="setBreathingTechnique('balance')">Balance</button>
|
||||
<button class="technique-btn" onclick="setBreathingTechnique('relax')">Relax</button>
|
||||
<button class="technique-btn" onclick="setBreathingTechnique('focus')">Focus</button>
|
||||
<button class="technique-btn" onclick="setBreathingTechnique('balance')">${techniques.balance.label}</button>
|
||||
<button class="technique-btn" onclick="setBreathingTechnique('relax')">${techniques.relax.label}</button>
|
||||
<button class="technique-btn" onclick="setBreathingTechnique('focus')">${techniques.focus.label}</button>
|
||||
</div>
|
||||
|
||||
<div class="breathing-visual-container">
|
||||
@@ -1472,8 +1517,8 @@ function startBreathing() {
|
||||
<div class="breath-circle-inner"></div>
|
||||
</div>
|
||||
|
||||
<div id="breath-instruction" class="breath-instruction-text">Get Ready...</div>
|
||||
<div id="breath-sub" class="breath-sub-text">Sit comfortably</div>
|
||||
<div id="breath-instruction" class="breath-instruction-text">${t('breath_ready')}</div>
|
||||
<div id="breath-sub" class="breath-sub-text">${t('breath_sit')}</div>
|
||||
|
||||
<div class="breath-controls">
|
||||
<button class="control-btn-icon" onclick="closeSmartBreathing()">
|
||||
@@ -1489,11 +1534,13 @@ function startBreathing() {
|
||||
|
||||
function setBreathingTechnique(tech) {
|
||||
breathingState.technique = tech;
|
||||
const techniques = getBreathingTechniques();
|
||||
|
||||
// Update buttons
|
||||
document.querySelectorAll('.technique-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
if(btn.innerText.toLowerCase().includes(breathingTechniques[tech].name.toLowerCase())) {
|
||||
// Match by label content
|
||||
if(btn.textContent === techniques[tech].label) {
|
||||
btn.classList.add('active');
|
||||
}
|
||||
});
|
||||
@@ -1509,7 +1556,8 @@ function startSmartBreathingLoop() {
|
||||
const loop = async () => {
|
||||
if (!breathingState.isActive) return;
|
||||
|
||||
const technique = breathingTechniques[breathingState.technique];
|
||||
const techniques = getBreathingTechniques();
|
||||
const technique = techniques[breathingState.technique];
|
||||
const phase = technique.phases[currentPhaseIndex];
|
||||
|
||||
updateBreathingUI(phase.name, phase.label, phase.duration, phase.scale);
|
||||
@@ -1574,7 +1622,7 @@ function closeSmartBreathing() {
|
||||
// Log session
|
||||
exerciseAPI.logSession('breathing', 60).then(() => {
|
||||
triggerSuccessPing();
|
||||
showSuccessMessage('Breathing session complete! 🌬️');
|
||||
showToast(t('breath_complete'));
|
||||
updateProgress();
|
||||
});
|
||||
}
|
||||
@@ -1599,3 +1647,24 @@ window.startBreathing = breathingExercise; // Alias for startBreathing in HTML
|
||||
window.showQuickActionMenu = showQuickActionMenu;
|
||||
window.navigateTo = showSection; // Alias for navigateTo in HTML
|
||||
window.finishRelaxSession = finishRelaxSession;
|
||||
|
||||
function showLanguageModal() {
|
||||
const menu = document.createElement('div');
|
||||
menu.className = 'exercise-modal';
|
||||
menu.style.display = 'block';
|
||||
menu.innerHTML = `
|
||||
<div class="card">
|
||||
<h3>Language / שפה / Язык</h3>
|
||||
<div style="display: flex; gap: 10px; justify-content: center; margin-bottom: 20px;">
|
||||
<button class="btn btn-sm ${currentLang === 'en' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('en'); this.closest('.exercise-modal').remove()">English</button>
|
||||
<button class="btn btn-sm ${currentLang === 'ru' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('ru'); this.closest('.exercise-modal').remove()">Русский</button>
|
||||
<button class="btn btn-sm ${currentLang === 'he' ? 'btn-primary' : 'btn-secondary'}" onclick="setLanguage('he'); this.closest('.exercise-modal').remove()">עברית</button>
|
||||
</div>
|
||||
<div class="exercise-actions">
|
||||
<button class="btn btn-secondary" onclick="this.closest('.exercise-modal').remove()">${t('close')}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(menu);
|
||||
}
|
||||
window.showLanguageModal = showLanguageModal;
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
MindShift
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="nav-item" onclick="showLanguageModal()" style="color: var(--primary);">
|
||||
<span class="material-icons">language</span>
|
||||
</button>
|
||||
<div style="position: relative;">
|
||||
<button class="nav-item" onclick="toggleNotifications()" style="color: white;">
|
||||
<span class="material-icons">notifications</span>
|
||||
|
||||
@@ -1292,3 +1292,72 @@ textarea:focus, input[type="text"]:focus {
|
||||
.hold .breath-circle-main { background: rgba(255, 235, 59, 0.3); }
|
||||
.exhale .breath-circle-main { background: rgba(255, 107, 107, 0.3); }
|
||||
|
||||
/* RTL Support Overrides */
|
||||
html[dir="rtl"] {
|
||||
text-align: right;
|
||||
--direction: rtl;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .fab {
|
||||
right: auto;
|
||||
left: 24px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .notification-badge {
|
||||
right: auto;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .notification-dropdown {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .card-title::after {
|
||||
transform-origin: right;
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .switch-form a {
|
||||
margin-left: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .form-group label {
|
||||
margin-left: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .guided-controls {
|
||||
right: auto;
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
/* Adjust history item hover transform for RTL */
|
||||
html[dir="rtl"] .history-item:hover {
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
|
||||
/* Adjust emotion value alignment */
|
||||
html[dir="rtl"] .emotion-value {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Adjust desktop sidebar for RTL */
|
||||
@media (min-width: 1024px) {
|
||||
html[dir="rtl"] .bottom-nav {
|
||||
left: auto;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .main-content {
|
||||
margin-left: 0;
|
||||
margin-right: 120px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .nav-item.active::after {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
401
MindShift-Windows/src/translations.js
Normal file
401
MindShift-Windows/src/translations.js
Normal file
@@ -0,0 +1,401 @@
|
||||
export const translations = {
|
||||
en: {
|
||||
// Meta
|
||||
"app_title": "MindShift",
|
||||
"app_subtitle": "Your personal CBT companion",
|
||||
"init_loading": "Initializing MindShift...",
|
||||
"init_error": "Error Loading App",
|
||||
"proactive_badge": "✨ Time for a vibe check?",
|
||||
|
||||
// Navigation
|
||||
"nav_home": "Home",
|
||||
"nav_mood": "Mood",
|
||||
"nav_thoughts": "Thoughts",
|
||||
"nav_gratitude": "Gratitude",
|
||||
"nav_progress": "Progress",
|
||||
|
||||
// Auth
|
||||
"auth_welcome": "Welcome to MindShift",
|
||||
"auth_login": "Login",
|
||||
"auth_register": "Register",
|
||||
"auth_name": "Name",
|
||||
"auth_email": "Email",
|
||||
"auth_password": "Password",
|
||||
"auth_no_account": "Don't have an account?",
|
||||
"auth_has_account": "Already have an account?",
|
||||
"auth_login_failed": "Login failed",
|
||||
"auth_reg_failed": "Registration failed",
|
||||
|
||||
// Home
|
||||
"home_welcome": "Welcome Back! 🌟",
|
||||
"home_subtitle": "Ready to shift your mind?",
|
||||
"home_log_mood": "Log Mood",
|
||||
"home_record_thought": "Record Thought",
|
||||
"home_gratitude": "Gratitude",
|
||||
"home_daily_vibe": "Daily Vibe Check 📊",
|
||||
"home_quick_relief": "Quick Relief 🌿",
|
||||
"home_breathe": "Breathe",
|
||||
"home_relax": "Relax",
|
||||
"home_stats_mood": "Today's Mood",
|
||||
"home_stats_sessions": "Sessions",
|
||||
"home_stats_avg": "Weekly Avg",
|
||||
"home_stats_gratitude": "Gratitude",
|
||||
"home_retry": "Tap to Retry",
|
||||
|
||||
// Mood
|
||||
"mood_title": "How are you feeling?",
|
||||
"mood_joy": "Joy",
|
||||
"mood_peace": "Peace",
|
||||
"mood_energy": "Energy",
|
||||
"mood_anxiety": "Anxiety",
|
||||
"mood_sadness": "Sadness",
|
||||
"mood_anger": "Anger",
|
||||
"mood_intensity": "Intensity",
|
||||
"mood_notes_placeholder": "Any thoughts?",
|
||||
"mood_save": "Save Mood",
|
||||
"mood_saved_success": "Mood tracked successfully!",
|
||||
"mood_select_warning": "Please select a mood",
|
||||
|
||||
// Thoughts
|
||||
"thought_title": "Thought Record 🧠",
|
||||
"thought_situation": "Situation (Who, what, where, when?)",
|
||||
"thought_automatic": "Automatic Thoughts (What went through your mind?)",
|
||||
"thought_emotions": "Emotions",
|
||||
"thought_add_emotion": "+ Add Emotion",
|
||||
"thought_evidence": "Evidence For/Against",
|
||||
"thought_alternative": "Alternative Thought",
|
||||
"thought_save": "Save Record",
|
||||
"thought_saved_success": "Thought record saved successfully!",
|
||||
"thought_fill_warning": "Please fill in at least the situation and thoughts",
|
||||
|
||||
// Gratitude
|
||||
"gratitude_title": "Gratitude Journal 🙏",
|
||||
"gratitude_intro": "List 3 things you are grateful for today:",
|
||||
"gratitude_placeholder": "I am grateful for...",
|
||||
"gratitude_add": "+ Add Another",
|
||||
"gratitude_save": "Save Entry",
|
||||
"gratitude_saved_success": "Gratitude entries saved successfully!",
|
||||
"gratitude_empty_warning": "Please add at least one gratitude entry",
|
||||
|
||||
// Progress & History
|
||||
"progress_title": "Your Progress 📈",
|
||||
"progress_weekly": "Weekly Mood 📅",
|
||||
"progress_history": "Recent History 📜",
|
||||
"history_tab_moods": "Moods",
|
||||
"history_tab_thoughts": "Thoughts",
|
||||
"history_tab_gratitude": "Gratitude",
|
||||
"history_empty_mood": "No mood entries yet. Start tracking! 📝",
|
||||
"history_empty_thoughts": "No thought records yet. 🧠",
|
||||
"history_empty_gratitude": "No gratitude entries yet. 🙏",
|
||||
"history_select_prompt": "Select a category to view history",
|
||||
|
||||
// Quick Actions
|
||||
"quick_title": "Quick Actions ⚡",
|
||||
"quick_relax_now": "Relax Now",
|
||||
"close": "Close",
|
||||
|
||||
// Guided Relaxation (Grounding)
|
||||
"guided_sight_title": "Sight",
|
||||
"guided_sight_instruction": "Look around you.",
|
||||
"guided_sight_sub": "Find 5 things you can see.",
|
||||
"guided_touch_title": "Touch",
|
||||
"guided_touch_instruction": "Feel the textures.",
|
||||
"guided_touch_sub": "Find 4 things you can touch.",
|
||||
"guided_sound_title": "Sound",
|
||||
"guided_sound_instruction": "Listen carefully.",
|
||||
"guided_sound_sub": "Identify 3 sounds you hear.",
|
||||
"guided_smell_title": "Smell",
|
||||
"guided_smell_instruction": "Breathe in deep.",
|
||||
"guided_smell_sub": "Notice 2 things you can smell.",
|
||||
"guided_taste_title": "Taste",
|
||||
"guided_taste_instruction": "Focus on your mouth.",
|
||||
"guided_taste_sub": "Find 1 thing you can taste.",
|
||||
"guided_found_btn": "I found one",
|
||||
"guided_complete_title": "You did great!",
|
||||
"guided_complete_sub": "Feeling more grounded?",
|
||||
"guided_complete_btn": "Complete",
|
||||
|
||||
// Smart Breathing
|
||||
"breath_balance": "Balance",
|
||||
"breath_relax": "Relax",
|
||||
"breath_focus": "Focus",
|
||||
"breath_in": "Breathe In",
|
||||
"breath_out": "Breathe Out",
|
||||
"breath_hold": "Hold",
|
||||
"breath_ready": "Get Ready...",
|
||||
"breath_sit": "Sit comfortably",
|
||||
"breath_complete": "Breathing session complete! 🌬️",
|
||||
|
||||
// Notifications
|
||||
"notifications_empty": "No notifications",
|
||||
"just_now": "Just now",
|
||||
"ago_m": "m ago",
|
||||
"ago_h": "h ago"
|
||||
},
|
||||
ru: {
|
||||
// Meta
|
||||
"app_title": "MindShift",
|
||||
"app_subtitle": "Ваш личный помощник КПТ",
|
||||
"init_loading": "Загрузка MindShift...",
|
||||
"init_error": "Ошибка загрузки",
|
||||
"proactive_badge": "✨ Время проверить настроение?",
|
||||
|
||||
// Navigation
|
||||
"nav_home": "Главная",
|
||||
"nav_mood": "Настроение",
|
||||
"nav_thoughts": "Мысли",
|
||||
"nav_gratitude": "Благодарность",
|
||||
"nav_progress": "Прогресс",
|
||||
|
||||
// Auth
|
||||
"auth_welcome": "Добро пожаловать в MindShift",
|
||||
"auth_login": "Войти",
|
||||
"auth_register": "Регистрация",
|
||||
"auth_name": "Имя",
|
||||
"auth_email": "Email",
|
||||
"auth_password": "Пароль",
|
||||
"auth_no_account": "Нет аккаунта?",
|
||||
"auth_has_account": "Уже есть аккаунт?",
|
||||
"auth_login_failed": "Ошибка входа",
|
||||
"auth_reg_failed": "Ошибка регистрации",
|
||||
|
||||
// Home
|
||||
"home_welcome": "С возвращением! 🌟",
|
||||
"home_subtitle": "Готовы изменить мышление?",
|
||||
"home_log_mood": "Настроение",
|
||||
"home_record_thought": "Запись мыслей",
|
||||
"home_gratitude": "Благодарность",
|
||||
"home_daily_vibe": "Статистика дня 📊",
|
||||
"home_quick_relief": "Быстрая помощь 🌿",
|
||||
"home_breathe": "Дыхание",
|
||||
"home_relax": "Релакс",
|
||||
"home_stats_mood": "Настроение",
|
||||
"home_stats_sessions": "Сессии",
|
||||
"home_stats_avg": "Ср. за неделю",
|
||||
"home_stats_gratitude": "Благодарности",
|
||||
"home_retry": "Повторить",
|
||||
|
||||
// Mood
|
||||
"mood_title": "Как вы себя чувствуете?",
|
||||
"mood_joy": "Радость",
|
||||
"mood_peace": "Покой",
|
||||
"mood_energy": "Энергия",
|
||||
"mood_anxiety": "Тревога",
|
||||
"mood_sadness": "Грусть",
|
||||
"mood_anger": "Гнев",
|
||||
"mood_intensity": "Интенсивность",
|
||||
"mood_notes_placeholder": "О чем думаете?",
|
||||
"mood_save": "Сохранить",
|
||||
"mood_saved_success": "Настроение сохранено!",
|
||||
"mood_select_warning": "Выберите настроение",
|
||||
|
||||
// Thoughts
|
||||
"thought_title": "Дневник мыслей 🧠",
|
||||
"thought_situation": "Ситуация (Кто, что, где, когда?)",
|
||||
"thought_automatic": "Автоматические мысли (Что пришло в голову?)",
|
||||
"thought_emotions": "Эмоции",
|
||||
"thought_add_emotion": "+ Добавить эмоцию",
|
||||
"thought_evidence": "За и Против",
|
||||
"thought_alternative": "Альтернативная мысль",
|
||||
"thought_save": "Сохранить запись",
|
||||
"thought_saved_success": "Запись сохранена!",
|
||||
"thought_fill_warning": "Заполните ситуацию и мысли",
|
||||
|
||||
// Gratitude
|
||||
"gratitude_title": "Дневник благодарности 🙏",
|
||||
"gratitude_intro": "3 вещи, за которые вы благодарны:",
|
||||
"gratitude_placeholder": "Я благодарен за...",
|
||||
"gratitude_add": "+ Добавить еще",
|
||||
"gratitude_save": "Сохранить",
|
||||
"gratitude_saved_success": "Записи сохранены!",
|
||||
"gratitude_empty_warning": "Добавьте хотя бы одну запись",
|
||||
|
||||
// Progress & History
|
||||
"progress_title": "Ваш прогресс 📈",
|
||||
"progress_weekly": "Настроение за неделю 📅",
|
||||
"progress_history": "История 📜",
|
||||
"history_tab_moods": "Настроение",
|
||||
"history_tab_thoughts": "Мысли",
|
||||
"history_tab_gratitude": "Благодарность",
|
||||
"history_empty_mood": "Нет записей. Начните отслеживать! 📝",
|
||||
"history_empty_thoughts": "Нет записей мыслей. 🧠",
|
||||
"history_empty_gratitude": "Нет записей благодарности. 🙏",
|
||||
"history_select_prompt": "Выберите категорию для просмотра",
|
||||
|
||||
// Quick Actions
|
||||
"quick_title": "Быстрые действия ⚡",
|
||||
"quick_relax_now": "Релакс сейчас",
|
||||
"close": "Закрыть",
|
||||
|
||||
// Guided Relaxation
|
||||
"guided_sight_title": "Зрение",
|
||||
"guided_sight_instruction": "Оглянитесь вокруг.",
|
||||
"guided_sight_sub": "Найдите 5 вещей, которые вы видите.",
|
||||
"guided_touch_title": "Осязание",
|
||||
"guided_touch_instruction": "Почувствуйте текстуры.",
|
||||
"guided_touch_sub": "Найдите 4 вещи, которые можно потрогать.",
|
||||
"guided_sound_title": "Слух",
|
||||
"guided_sound_instruction": "Прислушайтесь.",
|
||||
"guided_sound_sub": "Найдите 3 звука, которые вы слышите.",
|
||||
"guided_smell_title": "Обоняние",
|
||||
"guided_smell_instruction": "Сделайте глубокий вдох.",
|
||||
"guided_smell_sub": "Найдите 2 запаха.",
|
||||
"guided_taste_title": "Вкус",
|
||||
"guided_taste_instruction": "Сосредоточьтесь на вкусе.",
|
||||
"guided_taste_sub": "Найдите 1 вещь, которую можно попробовать.",
|
||||
"guided_found_btn": "Найдено",
|
||||
"guided_complete_title": "Отлично!",
|
||||
"guided_complete_sub": "Чувствуете себя спокойнее?",
|
||||
"guided_complete_btn": "Завершить",
|
||||
|
||||
// Smart Breathing
|
||||
"breath_balance": "Баланс",
|
||||
"breath_relax": "Релакс",
|
||||
"breath_focus": "Фокус",
|
||||
"breath_in": "Вдох",
|
||||
"breath_out": "Выдох",
|
||||
"breath_hold": "Пауза",
|
||||
"breath_ready": "Приготовьтесь...",
|
||||
"breath_sit": "Сядьте удобно",
|
||||
"breath_complete": "Сессия завершена! 🌬️",
|
||||
|
||||
// Notifications
|
||||
"notifications_empty": "Нет уведомлений",
|
||||
"just_now": "Только что",
|
||||
"ago_m": "м назад",
|
||||
"ago_h": "ч назад"
|
||||
},
|
||||
he: {
|
||||
// Meta
|
||||
"app_title": "MindShift",
|
||||
"app_subtitle": "המאמן האישי שלך ל-CBT",
|
||||
"init_loading": "טוען MindShift...",
|
||||
"init_error": "שגיאה בטעינת האפליקציה",
|
||||
"proactive_badge": "✨ זמן לבדיקת מצב רוח?",
|
||||
|
||||
// Navigation
|
||||
"nav_home": "בית",
|
||||
"nav_mood": "מצב רוח",
|
||||
"nav_thoughts": "מחשבות",
|
||||
"nav_gratitude": "הוקרת תודה",
|
||||
"nav_progress": "התקדמות",
|
||||
|
||||
// Auth
|
||||
"auth_welcome": "ברוכים הבאים ל-MindShift",
|
||||
"auth_login": "התחברות",
|
||||
"auth_register": "הרשמה",
|
||||
"auth_name": "שם",
|
||||
"auth_email": "אימייל",
|
||||
"auth_password": "סיסמה",
|
||||
"auth_no_account": "אין לך חשבון?",
|
||||
"auth_has_account": "יש לך כבר חשבון?",
|
||||
"auth_login_failed": "התחברות נכשלה",
|
||||
"auth_reg_failed": "הרשמה נכשלה",
|
||||
|
||||
// Home
|
||||
"home_welcome": "ברוכים השבים! 🌟",
|
||||
"home_subtitle": "מוכנים לשינוי מחשבתי?",
|
||||
"home_log_mood": "יומן מצב רוח",
|
||||
"home_record_thought": "יומן מחשבות",
|
||||
"home_gratitude": "הוקרת תודה",
|
||||
"home_daily_vibe": "בדיקה יומית 📊",
|
||||
"home_quick_relief": "הקלה מהירה 🌿",
|
||||
"home_breathe": "נשימה",
|
||||
"home_relax": "הרפיה",
|
||||
"home_stats_mood": "מצב רוח",
|
||||
"home_stats_sessions": "אימונים",
|
||||
"home_stats_avg": "ממוצע שבועי",
|
||||
"home_stats_gratitude": "תודות",
|
||||
"home_retry": "לחץ לנסות שוב",
|
||||
|
||||
// Mood
|
||||
"mood_title": "איך אתם מרגישים?",
|
||||
"mood_joy": "שמחה",
|
||||
"mood_peace": "שלווה",
|
||||
"mood_energy": "אנרגיה",
|
||||
"mood_anxiety": "חרדה",
|
||||
"mood_sadness": "עצב",
|
||||
"mood_anger": "כעס",
|
||||
"mood_intensity": "עוצמה",
|
||||
"mood_notes_placeholder": "מחשבות נוספות?",
|
||||
"mood_save": "שמור מצב רוח",
|
||||
"mood_saved_success": "מצב רוח נשמר בהצלחה!",
|
||||
"mood_select_warning": "אנא בחר מצב רוח",
|
||||
|
||||
// Thoughts
|
||||
"thought_title": "יומן מחשבות 🧠",
|
||||
"thought_situation": "סיטואציה (מי, מה, איפה, מתי?)",
|
||||
"thought_automatic": "מחשבות אוטומטיות (מה עבר בראש?)",
|
||||
"thought_emotions": "רגשות",
|
||||
"thought_add_emotion": "+ הוסף רגש",
|
||||
"thought_evidence": "בעד ונגד",
|
||||
"thought_alternative": "מחשבה אלטרנטיבית",
|
||||
"thought_save": "שמור רשומה",
|
||||
"thought_saved_success": "הרשומה נשמרה בהצלחה!",
|
||||
"thought_fill_warning": "אנא מלא לפחות את הסיטואציה והמחשבות",
|
||||
|
||||
// Gratitude
|
||||
"gratitude_title": "יומן הוקרת תודה 🙏",
|
||||
"gratitude_intro": "3 דברים שאתם מוקירים עליהם תודה היום:",
|
||||
"gratitude_placeholder": "אני מוקיר תודה על...",
|
||||
"gratitude_add": "+ הוסף עוד",
|
||||
"gratitude_save": "שמור",
|
||||
"gratitude_saved_success": "נשמר בהצלחה!",
|
||||
"gratitude_empty_warning": "אנא הוסף לפחות פריט אחד",
|
||||
|
||||
// Progress & History
|
||||
"progress_title": "ההתקדמות שלך 📈",
|
||||
"progress_weekly": "מצב רוח שבועי 📅",
|
||||
"progress_history": "היסטוריה 📜",
|
||||
"history_tab_moods": "מצבי רוח",
|
||||
"history_tab_thoughts": "מחשבות",
|
||||
"history_tab_gratitude": "תודות",
|
||||
"history_empty_mood": "אין עדיין רשומות. התחילו לתעד! 📝",
|
||||
"history_empty_thoughts": "אין עדיין רשומות מחשבה. 🧠",
|
||||
"history_empty_gratitude": "אין עדיין רשומות תודה. 🙏",
|
||||
"history_select_prompt": "בחר קטגוריה לצפייה בהיסטוריה",
|
||||
|
||||
// Quick Actions
|
||||
"quick_title": "פעולות מהירות ⚡",
|
||||
"quick_relax_now": "הרפיה עכשיו",
|
||||
"close": "סגור",
|
||||
|
||||
// Guided Relaxation
|
||||
"guided_sight_title": "ראייה",
|
||||
"guided_sight_instruction": "הביטו סביבכם.",
|
||||
"guided_sight_sub": "מצאו 5 דברים שאתם רואים.",
|
||||
"guided_touch_title": "מגע",
|
||||
"guided_touch_instruction": "הרגישו מרקמים.",
|
||||
"guided_touch_sub": "מצאו 4 דברים שאפשר לגעת בהם.",
|
||||
"guided_sound_title": "שמיעה",
|
||||
"guided_sound_instruction": "הקשיבו בתשומת לב.",
|
||||
"guided_sound_sub": "זהו 3 צלילים שאתם שומעים.",
|
||||
"guided_smell_title": "ריח",
|
||||
"guided_smell_instruction": "קחו נשימה עמוקה.",
|
||||
"guided_smell_sub": "שימו לב ל-2 ריחות.",
|
||||
"guided_taste_title": "טעם",
|
||||
"guided_taste_instruction": "התמקדו בפה.",
|
||||
"guided_taste_sub": "מצאו דבר 1 שניתן לטעום.",
|
||||
"guided_found_btn": "מצאתי",
|
||||
"guided_complete_title": "כל הכבוד!",
|
||||
"guided_complete_sub": "מרגישים מקורקעים יותר?",
|
||||
"guided_complete_btn": "סיים",
|
||||
|
||||
// Smart Breathing
|
||||
"breath_balance": "איזון",
|
||||
"breath_relax": "רוגע",
|
||||
"breath_focus": "מיקוד",
|
||||
"breath_in": "שאיפה",
|
||||
"breath_out": "נשיפה",
|
||||
"breath_hold": "החזקה",
|
||||
"breath_ready": "היכונו...",
|
||||
"breath_sit": "שבו בנוחות",
|
||||
"breath_complete": "אימון נשימה הסתיים! 🌬️",
|
||||
|
||||
// Notifications
|
||||
"notifications_empty": "אין התראות",
|
||||
"just_now": "כרגע",
|
||||
"ago_m": "לפני דק'",
|
||||
"ago_h": "לפני שע'"
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user