Initial commit of MindShift CBT Therapy app
This commit is contained in:
185
MindShift-Windows/src/api.js
Normal file
185
MindShift-Windows/src/api.js
Normal file
@@ -0,0 +1,185 @@
|
||||
// API Configuration
|
||||
const API_BASE_URL = 'http://localhost:12004/api';
|
||||
|
||||
// Authentication token management
|
||||
let authToken = localStorage.getItem('authToken');
|
||||
|
||||
// API helper function
|
||||
async function apiCall(endpoint, options = {}) {
|
||||
const url = `${API_BASE_URL}${endpoint}`;
|
||||
const config = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(authToken && { 'Authorization': `Bearer ${authToken}` }),
|
||||
...options.headers
|
||||
},
|
||||
...options
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, config);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'API request failed');
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API Error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Authentication API
|
||||
export const authAPI = {
|
||||
async register(name, email, password) {
|
||||
const data = await apiCall('/auth/register', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name, email, password })
|
||||
});
|
||||
authToken = data.token;
|
||||
localStorage.setItem('authToken', authToken);
|
||||
return data;
|
||||
},
|
||||
|
||||
async login(email, password) {
|
||||
const data = await apiCall('/auth/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ email, password })
|
||||
});
|
||||
authToken = data.token;
|
||||
localStorage.setItem('authToken', authToken);
|
||||
return data;
|
||||
},
|
||||
|
||||
async logout() {
|
||||
await apiCall('/auth/logout', { method: 'POST' });
|
||||
authToken = null;
|
||||
localStorage.removeItem('authToken');
|
||||
},
|
||||
|
||||
async getProfile() {
|
||||
return await apiCall('/auth/profile');
|
||||
}
|
||||
};
|
||||
|
||||
// Mood tracking API
|
||||
export const moodAPI = {
|
||||
async trackMood(moodType, intensity, notes) {
|
||||
return await apiCall('/mood/track', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ moodType, intensity, notes })
|
||||
});
|
||||
},
|
||||
|
||||
async getMoodHistory() {
|
||||
return await apiCall('/mood/history');
|
||||
}
|
||||
};
|
||||
|
||||
// Thought record API
|
||||
export const thoughtAPI = {
|
||||
async saveThoughtRecord(thoughtData) {
|
||||
return await apiCall('/thoughts', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(thoughtData)
|
||||
});
|
||||
},
|
||||
|
||||
async getThoughtRecords() {
|
||||
return await apiCall('/thoughts');
|
||||
},
|
||||
|
||||
async updateThoughtRecord(id, thoughtData) {
|
||||
return await apiCall(`/thoughts/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(thoughtData)
|
||||
});
|
||||
},
|
||||
|
||||
async deleteThoughtRecord(id) {
|
||||
return await apiCall(`/thoughts/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Gratitude API
|
||||
export const gratitudeAPI = {
|
||||
async saveGratitudeEntry(entry) {
|
||||
return await apiCall('/gratitude', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(entry)
|
||||
});
|
||||
},
|
||||
|
||||
async getGratitudeEntries() {
|
||||
return await apiCall('/gratitude');
|
||||
},
|
||||
|
||||
async updateGratitudeEntry(id, entry) {
|
||||
return await apiCall(`/gratitude/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(entry)
|
||||
});
|
||||
},
|
||||
|
||||
async deleteGratitudeEntry(id) {
|
||||
return await apiCall(`/gratitude/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Progress API
|
||||
export const progressAPI = {
|
||||
async getProgressStats() {
|
||||
return await apiCall('/progress/stats');
|
||||
},
|
||||
|
||||
async getProgressHistory() {
|
||||
return await apiCall('/progress/history');
|
||||
}
|
||||
};
|
||||
|
||||
// Notification API
|
||||
export const notificationAPI = {
|
||||
async getNotifications() {
|
||||
return await apiCall('/notifications');
|
||||
},
|
||||
|
||||
async markAsRead(notificationId) {
|
||||
return await apiCall(`/notifications/${notificationId}/read`, {
|
||||
method: 'PUT'
|
||||
});
|
||||
},
|
||||
|
||||
async deleteNotification(notificationId) {
|
||||
return await apiCall(`/notifications/${notificationId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
},
|
||||
|
||||
async addNotification(notification) {
|
||||
return await apiCall('/notifications', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(notification)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Check if user is authenticated
|
||||
export function isAuthenticated() {
|
||||
return !!authToken;
|
||||
}
|
||||
|
||||
// Initialize API with token check
|
||||
export function initializeAPI() {
|
||||
if (!authToken) {
|
||||
// Redirect to login or show login modal
|
||||
console.log('User not authenticated');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
1106
MindShift-Windows/src/app.js
Normal file
1106
MindShift-Windows/src/app.js
Normal file
File diff suppressed because it is too large
Load Diff
111
MindShift-Windows/src/index.html
Normal file
111
MindShift-Windows/src/index.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MindShift - CBT Therapy App</title>
|
||||
|
||||
<!-- PWA Meta Tags -->
|
||||
<meta name="theme-color" content="#FF6B6B">
|
||||
<meta name="description" content="Your personal CBT therapy companion for mood management and mental wellness">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
<meta name="apple-mobile-web-app-title" content="MindShift">
|
||||
<meta name="application-name" content="MindShift">
|
||||
<meta name="msapplication-TileColor" content="#FF6B6B">
|
||||
<meta name="msapplication-config" content="browserconfig.xml">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Animated Background Orbs -->
|
||||
<div class="background-orbs">
|
||||
<div class="orb orb-1"></div>
|
||||
<div class="orb orb-2"></div>
|
||||
<div class="orb orb-3"></div>
|
||||
</div>
|
||||
|
||||
<!-- Success Ping Container -->
|
||||
<div id="success-ping" class="success-ping"></div>
|
||||
|
||||
<!-- Proactive Badge -->
|
||||
<div id="proactive-badge" class="proactive-badge">✨ Time for a vibe check?</div>
|
||||
|
||||
<!-- Welcome Overlay -->
|
||||
<div id="welcome-overlay" class="welcome-overlay">
|
||||
<div class="welcome-emoji">🧠</div>
|
||||
<h1 class="welcome-title">MindShift</h1>
|
||||
<p class="welcome-subtitle">Your personal CBT companion</p>
|
||||
</div>
|
||||
|
||||
<!-- Header -->
|
||||
<header class="app-header">
|
||||
<div class="header-content">
|
||||
<div class="app-title">
|
||||
<span class="material-icons">self_improvement</span>
|
||||
MindShift
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<div style="position: relative;">
|
||||
<button class="nav-item" onclick="toggleNotifications()" style="color: white;">
|
||||
<span class="material-icons">notifications</span>
|
||||
<span id="notification-badge" class="notification-badge" style="display: none;">0</span>
|
||||
</button>
|
||||
<div id="notification-list" class="notification-dropdown">
|
||||
<!-- Notifications will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
<button class="nav-item" onclick="logout()" style="color: white;">
|
||||
<span class="material-icons">logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main id="main-content" class="main-content">
|
||||
<!-- Content will be dynamically loaded here -->
|
||||
</main>
|
||||
|
||||
<!-- Bottom Navigation -->
|
||||
<nav class="bottom-nav">
|
||||
<button class="nav-item active" onclick="navigateTo('home')">
|
||||
<span class="material-icons">home</span>
|
||||
<span class="nav-label">Home</span>
|
||||
</button>
|
||||
<button class="nav-item" onclick="navigateTo('mood')">
|
||||
<span class="material-icons">mood</span>
|
||||
<span class="nav-label">Mood</span>
|
||||
</button>
|
||||
<button class="nav-item" onclick="navigateTo('thoughts')">
|
||||
<span class="material-icons">psychology</span>
|
||||
<span class="nav-label">Thoughts</span>
|
||||
</button>
|
||||
<button class="nav-item" onclick="navigateTo('gratitude')">
|
||||
<span class="material-icons">favorite</span>
|
||||
<span class="nav-label">Gratitude</span>
|
||||
</button>
|
||||
<button class="nav-item" onclick="navigateTo('progress')">
|
||||
<span class="material-icons">insights</span>
|
||||
<span class="nav-label">Progress</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- Floating Action Button -->
|
||||
<button class="fab" onclick="showQuickActionMenu()">
|
||||
<span class="material-icons">add</span>
|
||||
</button>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script type="module" src="api.js"></script>
|
||||
<script type="module" src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
348
MindShift-Windows/src/main.js
Normal file
348
MindShift-Windows/src/main.js
Normal file
@@ -0,0 +1,348 @@
|
||||
const { app, BrowserWindow, Menu, ipcMain, shell, dialog, nativeImage } = require('electron');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Keep a global reference of the window object
|
||||
let mainWindow;
|
||||
let isDev = process.argv.includes('--dev');
|
||||
|
||||
// Windows 11 specific configurations
|
||||
const windowsConfig = {
|
||||
icon: path.join(__dirname, '../assets/icon.ico'),
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
frame: true,
|
||||
titleBarStyle: 'default',
|
||||
minWidth: 800,
|
||||
minHeight: 600,
|
||||
// DPI and scaling optimizations
|
||||
backgroundColor: '#667eea',
|
||||
hasShadow: true,
|
||||
thickFrame: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
enableRemoteModule: false,
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
// Enable zoom and scaling
|
||||
zoomFactor: 1.0,
|
||||
// Better rendering
|
||||
experimentalFeatures: true,
|
||||
// Enable smooth scrolling
|
||||
smoothScroll: true
|
||||
}
|
||||
};
|
||||
|
||||
function createWindow() {
|
||||
// Get primary display for DPI scaling
|
||||
const { screen } = require('electron');
|
||||
const primaryDisplay = screen.getPrimaryDisplay();
|
||||
const scaleFactor = primaryDisplay.scaleFactor;
|
||||
|
||||
// Calculate window size based on DPI
|
||||
const baseWidth = 1200;
|
||||
const baseHeight = 800;
|
||||
const scaledWidth = Math.floor(baseWidth * scaleFactor);
|
||||
const scaledHeight = Math.floor(baseHeight * scaleFactor);
|
||||
|
||||
// Create the browser window with Windows 11 styling
|
||||
mainWindow = new BrowserWindow({
|
||||
...windowsConfig,
|
||||
width: scaledWidth,
|
||||
height: scaledHeight,
|
||||
// DPI awareness
|
||||
deviceScaleFactor: scaleFactor,
|
||||
webPreferences: {
|
||||
...windowsConfig.webPreferences,
|
||||
// Enable features for Windows 11
|
||||
experimentalFeatures: true,
|
||||
spellcheck: true,
|
||||
// DPI scaling
|
||||
zoomFactor: 1.0 / scaleFactor
|
||||
}
|
||||
});
|
||||
|
||||
// Load the app
|
||||
if (isDev) {
|
||||
// Load from dev server on port 12005 in development
|
||||
mainWindow.loadURL('http://localhost:12005');
|
||||
} else {
|
||||
// Load from local file in production
|
||||
mainWindow.loadFile('src/index.html');
|
||||
}
|
||||
|
||||
// Show window when ready to prevent visual flash
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
|
||||
// Focus the window on show
|
||||
if (isDev) {
|
||||
mainWindow.webContents.openDevTools();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle window closed
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
// Set Windows 11 specific handlers
|
||||
setupWindowsHandlers();
|
||||
}
|
||||
|
||||
function setupWindowsHandlers() {
|
||||
// Handle Windows notifications
|
||||
mainWindow.webContents.on('did-finish-load', () => {
|
||||
// Inject Windows 11 specific styles
|
||||
mainWindow.webContents.insertCSS(`
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--surface: #1e1e1e;
|
||||
--surface-variant: #2d2d2d;
|
||||
--on-surface: #ffffff;
|
||||
--on-surface-variant: #cccccc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Windows 11 specific styling */
|
||||
.titlebar {
|
||||
-webkit-app-region: drag;
|
||||
height: 32px;
|
||||
background: transparent;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.titlebar button {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
/* Windows 11 Mica effect (if supported) */
|
||||
@supports (backdrop-filter: blur(20px)) {
|
||||
.app-header {
|
||||
backdrop-filter: blur(20px) saturate(180%);
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.app-header {
|
||||
background: rgba(30, 30, 30, 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
// Handle external links
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
shell.openExternal(url);
|
||||
return { action: 'deny' };
|
||||
});
|
||||
}
|
||||
|
||||
// Create application menu for Windows
|
||||
function createMenu() {
|
||||
const template = [
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Export Data',
|
||||
accelerator: 'CmdOrCtrl+E',
|
||||
click: () => {
|
||||
mainWindow.webContents.send('export-data');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Import Data',
|
||||
accelerator: 'CmdOrCtrl+I',
|
||||
click: () => {
|
||||
mainWindow.webContents.send('import-data');
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Exit',
|
||||
accelerator: process.platform === 'win32' ? 'Alt+F4' : 'CmdOrCtrl+Q',
|
||||
click: () => {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: 'undo', label: 'Undo' },
|
||||
{ role: 'redo', label: 'Redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut', label: 'Cut' },
|
||||
{ role: 'copy', label: 'Copy' },
|
||||
{ role: 'paste', label: 'Paste' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload', label: 'Reload' },
|
||||
{ role: 'forceReload', label: 'Force Reload' },
|
||||
{ role: 'toggleDevTools', label: 'Toggle Developer Tools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom', label: 'Actual Size' },
|
||||
{ role: 'zoomIn', label: 'Zoom In' },
|
||||
{ role: 'zoomOut', label: 'Zoom Out' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen', label: 'Toggle Fullscreen' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: 'minimize', label: 'Minimize' },
|
||||
{ role: 'close', label: 'Close' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About MindShift',
|
||||
click: () => {
|
||||
dialog.showMessageBox(mainWindow, {
|
||||
type: 'info',
|
||||
title: 'About MindShift',
|
||||
message: 'MindShift CBT Therapy',
|
||||
detail: 'Version 1.0.0\n\nYour personal CBT therapy companion for mood management and mental wellness.\n\n© 2024 MindShift Team',
|
||||
buttons: ['OK']
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
}
|
||||
|
||||
// App event handlers
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
createMenu();
|
||||
|
||||
// Handle Windows 11 taskbar integration
|
||||
if (process.platform === 'win32') {
|
||||
app.setUserTasks([
|
||||
{
|
||||
program: process.execPath,
|
||||
arguments: '--quick-relax',
|
||||
title: 'Quick Relax',
|
||||
description: 'Start a quick relaxation exercise',
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0
|
||||
},
|
||||
{
|
||||
program: process.execPath,
|
||||
arguments: '--mood-check',
|
||||
title: 'Mood Check',
|
||||
description: 'Check your current mood',
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Windows 11 notifications
|
||||
ipcMain.handle('show-notification', (event, title, body) => {
|
||||
const { Notification } = require('electron');
|
||||
|
||||
if (Notification.isSupported()) {
|
||||
const notification = new Notification({
|
||||
title: title,
|
||||
body: body,
|
||||
icon: path.join(__dirname, '../assets/icon.ico'),
|
||||
silent: false
|
||||
});
|
||||
|
||||
notification.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Handle file operations
|
||||
ipcMain.handle('save-file', async (event, data, filename) => {
|
||||
try {
|
||||
const result = await dialog.showSaveDialog(mainWindow, {
|
||||
defaultPath: filename,
|
||||
filters: [
|
||||
{ name: 'JSON Files', extensions: ['json'] },
|
||||
{ name: 'CSV Files', extensions: ['csv'] },
|
||||
{ name: 'All Files', extensions: ['*'] }
|
||||
]
|
||||
});
|
||||
|
||||
if (!result.canceled) {
|
||||
fs.writeFileSync(result.filePath, data);
|
||||
return { success: true, path: result.filePath };
|
||||
}
|
||||
|
||||
return { success: false, cancelled: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('open-file', async (event) => {
|
||||
try {
|
||||
const result = await dialog.showOpenDialog(mainWindow, {
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
{ name: 'JSON Files', extensions: ['json'] },
|
||||
{ name: 'CSV Files', extensions: ['csv'] },
|
||||
{ name: 'All Files', extensions: ['*'] }
|
||||
]
|
||||
});
|
||||
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
const data = fs.readFileSync(result.filePaths[0], 'utf8');
|
||||
return { success: true, data: data, path: result.filePaths[0] };
|
||||
}
|
||||
|
||||
return { success: false, cancelled: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
// Handle protocol for deep linking
|
||||
app.setAsDefaultProtocolClient('mindshift');
|
||||
|
||||
// Handle Windows 11 system theme changes
|
||||
if (process.platform === 'win32') {
|
||||
const { systemPreferences } = require('electron');
|
||||
|
||||
systemPreferences.on('color-changed', () => {
|
||||
// Notify renderer about theme change
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('theme-changed', systemPreferences.isDarkMode());
|
||||
}
|
||||
});
|
||||
}
|
||||
70
MindShift-Windows/src/preload.js
Normal file
70
MindShift-Windows/src/preload.js
Normal file
@@ -0,0 +1,70 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
// Expose protected methods that allow the renderer process to use
|
||||
// the ipcRenderer without exposing the entire object
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// Notification handling
|
||||
showNotification: (title, body) => ipcRenderer.invoke('show-notification', title, body),
|
||||
|
||||
// File operations
|
||||
saveFile: (data, filename) => ipcRenderer.invoke('save-file', data, filename),
|
||||
openFile: () => ipcRenderer.invoke('open-file'),
|
||||
|
||||
// Theme handling
|
||||
onThemeChange: (callback) => ipcRenderer.on('theme-changed', callback),
|
||||
|
||||
// Data export/import
|
||||
exportData: () => ipcRenderer.invoke('export-data'),
|
||||
importData: () => ipcRenderer.invoke('import-data'),
|
||||
|
||||
// App info
|
||||
getVersion: () => process.env.npm_package_version || '1.0.0',
|
||||
getPlatform: () => process.platform
|
||||
});
|
||||
|
||||
// Expose localStorage operations for persistence
|
||||
contextBridge.exposeInMainWorld('storage', {
|
||||
get: (key) => localStorage.getItem(key),
|
||||
set: (key, value) => localStorage.setItem(key, value),
|
||||
remove: (key) => localStorage.removeItem(key),
|
||||
clear: () => localStorage.clear(),
|
||||
getAll: () => {
|
||||
const data = {};
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
data[key] = localStorage.getItem(key);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
});
|
||||
|
||||
// Windows 11 specific API
|
||||
contextBridge.exposeInMainWorld('windowsAPI', {
|
||||
// Check if running on Windows
|
||||
isWindows: () => process.platform === 'win32',
|
||||
|
||||
// Get Windows version info
|
||||
getWindowsVersion: () => {
|
||||
if (process.platform === 'win32') {
|
||||
return {
|
||||
platform: 'win32',
|
||||
arch: process.arch,
|
||||
version: process.getSystemVersion?.() || 'Unknown'
|
||||
};
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// Check for Windows 11 features
|
||||
supportsMica: () => {
|
||||
// Check if Windows 11 (build 22000+) for Mica effect
|
||||
if (process.platform === 'win32') {
|
||||
const version = process.getSystemVersion?.();
|
||||
if (version) {
|
||||
const buildNumber = parseInt(version.split('.')?.[2] || '0');
|
||||
return buildNumber >= 22000;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
674
MindShift-Windows/src/styles.css
Normal file
674
MindShift-Windows/src/styles.css
Normal file
@@ -0,0 +1,674 @@
|
||||
/* Base Styles & Variables */
|
||||
:root {
|
||||
--primary: #FF6B6B;
|
||||
--primary-light: #FF8E8E;
|
||||
--primary-dark: #E55555;
|
||||
--primary-container: #FFE5E5;
|
||||
--on-primary: #FFFFFF;
|
||||
--on-primary-container: #410002;
|
||||
--secondary: #FFB74D;
|
||||
--secondary-container: #FFF3E0;
|
||||
--on-secondary: #FFFFFF;
|
||||
--on-secondary-container: #4E2B00;
|
||||
--tertiary: #4FC3F7;
|
||||
--tertiary-container: #E1F5FE;
|
||||
--surface: rgba(255, 255, 255, 0.9);
|
||||
--surface-variant: #F5F5F5;
|
||||
--on-surface: #212121;
|
||||
--on-surface-variant: #757575;
|
||||
--outline: #BDBDBD;
|
||||
--shadow: rgba(0,0,0,0.1);
|
||||
--error: #FF5252;
|
||||
--success: #66BB6A;
|
||||
--warning: #FFA726;
|
||||
--joy: #AB47BC;
|
||||
--peace: #26A69A;
|
||||
--energy: #FFEE58;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #FF6B6B 100%);
|
||||
background-size: 400% 400%;
|
||||
animation: gradientBG 15s ease infinite;
|
||||
color: var(--on-surface);
|
||||
line-height: 1.5;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@keyframes gradientBG {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
/* Animated Background Orbs */
|
||||
.background-orbs {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.orb {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(60px);
|
||||
opacity: 0.6;
|
||||
animation: orbFloat 20s infinite alternate cubic-bezier(0.45, 0.05, 0.55, 0.95);
|
||||
}
|
||||
|
||||
.orb-1 {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
background: var(--primary);
|
||||
top: -100px;
|
||||
left: -100px;
|
||||
animation-duration: 25s;
|
||||
}
|
||||
|
||||
.orb-2 {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
background: var(--secondary);
|
||||
bottom: -50px;
|
||||
right: -50px;
|
||||
animation-duration: 18s;
|
||||
animation-delay: -5s;
|
||||
}
|
||||
|
||||
.orb-3 {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
background: var(--tertiary);
|
||||
top: 40%;
|
||||
left: 60%;
|
||||
animation-duration: 22s;
|
||||
animation-delay: -10s;
|
||||
}
|
||||
|
||||
@keyframes orbFloat {
|
||||
0% { transform: translate(0, 0) rotate(0deg); }
|
||||
33% { transform: translate(50px, 100px) rotate(120deg); }
|
||||
66% { transform: translate(-50px, 50px) rotate(240deg); }
|
||||
100% { transform: translate(0, 0) rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Welcome Overlay */
|
||||
.welcome-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #FF6B6B 0%, #4ECDC4 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 2000;
|
||||
color: white;
|
||||
animation: fadeOut 0.5s ease-out 2s forwards;
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 16px;
|
||||
animation: slideInUp 0.8s ease-out;
|
||||
}
|
||||
|
||||
.welcome-subtitle {
|
||||
font-size: 20px;
|
||||
opacity: 0.9;
|
||||
animation: slideInUp 0.8s ease-out 0.2s both;
|
||||
}
|
||||
|
||||
.welcome-emoji {
|
||||
font-size: 80px;
|
||||
margin-bottom: 24px;
|
||||
animation: bounce 1s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
to { opacity: 0; visibility: hidden; }
|
||||
}
|
||||
|
||||
@keyframes slideInUp {
|
||||
from { transform: translateY(30px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
|
||||
40% { transform: translateY(-30px); }
|
||||
60% { transform: translateY(-15px); }
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.app-header {
|
||||
background-color: rgba(255, 107, 107, 0.95);
|
||||
color: var(--on-primary);
|
||||
padding: 16px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
backdrop-filter: blur(10px);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.app-header:hover {
|
||||
background-color: rgba(255, 107, 107, 1);
|
||||
box-shadow: 0 6px 24px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Notification Badge Pulse */
|
||||
.notification-badge {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background: var(--secondary);
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
padding: 2px 5px;
|
||||
border-radius: 10px;
|
||||
min-width: 16px;
|
||||
text-align: center;
|
||||
animation: pulseBadge 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulseBadge {
|
||||
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 183, 77, 0.7); }
|
||||
70% { transform: scale(1.1); box-shadow: 0 0 0 6px rgba(255, 183, 77, 0); }
|
||||
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 183, 77, 0); }
|
||||
}
|
||||
|
||||
.notification-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||||
padding: 16px;
|
||||
min-width: 300px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
animation: slideInDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
@keyframes slideInDown {
|
||||
from { transform: translateY(-10px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
.bottom-nav {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 -4px 20px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 12px 0;
|
||||
z-index: 100;
|
||||
border-top-left-radius: 20px;
|
||||
border-top-right-radius: 20px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--on-surface-variant);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
color: var(--primary);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.nav-item.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: var(--primary);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 10px var(--primary);
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
color: var(--primary);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.nav-item .material-icons {
|
||||
font-size: 24px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-item:hover .material-icons {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
/* Main Content & Cards */
|
||||
.main-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 16px;
|
||||
padding-bottom: 100px;
|
||||
min-height: calc(100vh - 120px);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
border-radius: 24px;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-8px) scale(1.01);
|
||||
box-shadow: 0 12px 40px rgba(0,0,0,0.2);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
color: var(--on-surface);
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.card-title::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, var(--primary), transparent);
|
||||
transform: scaleX(0);
|
||||
transform-origin: left;
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
.card:hover .card-title::after {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
/* Mood Selector - Enhanced */
|
||||
.mood-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
|
||||
gap: 16px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.mood-card {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border: 2px solid transparent;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mood-card:hover {
|
||||
transform: translateY(-8px) scale(1.05) rotate(2deg);
|
||||
box-shadow: 0 15px 35px rgba(0,0,0,0.2);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
|
||||
.mood-card.selected {
|
||||
border-color: var(--primary);
|
||||
background: linear-gradient(135deg, var(--primary-container), white);
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 0 4px rgba(255, 107, 107, 0.2);
|
||||
}
|
||||
|
||||
.mood-emoji {
|
||||
font-size: 48px;
|
||||
margin-bottom: 12px;
|
||||
display: block;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.mood-card:hover .mood-emoji {
|
||||
animation: moodBounce 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
|
||||
@keyframes moodBounce {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.4); }
|
||||
100% { transform: scale(1.2); }
|
||||
}
|
||||
|
||||
/* Buttons - Alive */
|
||||
.btn {
|
||||
padding: 16px 32px;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* Shimmer Effect */
|
||||
.btn::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.btn:hover::after {
|
||||
left: 100%;
|
||||
transition: 0.7s ease-in-out;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(45deg, var(--primary), var(--secondary));
|
||||
color: white;
|
||||
box-shadow: 0 8px 20px rgba(255, 107, 107, 0.4);
|
||||
animation: breathBtn 3s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes breathBtn {
|
||||
0% { transform: scale(1); box-shadow: 0 8px 20px rgba(255, 107, 107, 0.4); }
|
||||
50% { transform: scale(1.02); box-shadow: 0 12px 24px rgba(255, 107, 107, 0.6); }
|
||||
100% { transform: scale(1); box-shadow: 0 8px 20px rgba(255, 107, 107, 0.4); }
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-4px) scale(1.05);
|
||||
box-shadow: 0 15px 30px rgba(255, 107, 107, 0.5);
|
||||
animation: none; /* Stop breathing on hover to focus */
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: linear-gradient(45deg, var(--tertiary), var(--peace));
|
||||
color: white;
|
||||
box-shadow: 0 8px 20px rgba(79, 195, 247, 0.4);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
transform: translateY(-4px) scale(1.05);
|
||||
box-shadow: 0 15px 30px rgba(79, 195, 247, 0.5);
|
||||
}
|
||||
|
||||
/* Inputs & Sliders */
|
||||
.slider {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
background: rgba(0,0,0,0.1);
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.slider:hover {
|
||||
height: 10px;
|
||||
background: rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 10px rgba(255, 107, 107, 0.4);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.slider:hover::-webkit-slider-thumb {
|
||||
transform: scale(1.2);
|
||||
box-shadow: 0 6px 15px rgba(255, 107, 107, 0.6);
|
||||
}
|
||||
|
||||
textarea, input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
border: 2px solid rgba(0,0,0,0.1);
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
font-size: 16px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
textarea:focus, input[type="text"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 4px rgba(255, 107, 107, 0.1);
|
||||
transform: scale(1.01);
|
||||
}
|
||||
|
||||
/* Proactive Badges */
|
||||
.proactive-badge {
|
||||
position: absolute;
|
||||
background: var(--joy);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 4px 15px rgba(171, 71, 188, 0.4);
|
||||
animation: floatBadge 3s ease-in-out infinite;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.5s, transform 0.5s;
|
||||
}
|
||||
|
||||
.proactive-badge.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
@keyframes floatBadge {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
|
||||
/* Breathing Exercise - Super Alive */
|
||||
.breathing-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.breathing-circle {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 30% 30%, var(--tertiary), var(--primary));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 60px rgba(79, 195, 247, 0.4);
|
||||
position: relative;
|
||||
transition: all 4s cubic-bezier(0.45, 0.05, 0.55, 0.95);
|
||||
}
|
||||
|
||||
.breathing-circle::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: -20px;
|
||||
right: -20px;
|
||||
bottom: -20px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
animation: ripple 4s infinite;
|
||||
}
|
||||
|
||||
.breathing-circle.inhale {
|
||||
transform: scale(1.5);
|
||||
box-shadow: 0 0 100px rgba(79, 195, 247, 0.6);
|
||||
filter: hue-rotate(30deg);
|
||||
}
|
||||
|
||||
.breathing-circle.exhale {
|
||||
transform: scale(0.8);
|
||||
box-shadow: 0 0 30px rgba(79, 195, 247, 0.2);
|
||||
filter: hue-rotate(0deg);
|
||||
}
|
||||
|
||||
.breathing-text {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
text-shadow: 0 2px 10px rgba(0,0,0,0.2);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% { transform: scale(0.8); opacity: 1; }
|
||||
100% { transform: scale(1.5); opacity: 0; }
|
||||
}
|
||||
|
||||
/* FAB - Alive */
|
||||
.fab {
|
||||
position: fixed;
|
||||
bottom: 90px;
|
||||
right: 24px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 8px 25px rgba(255, 107, 107, 0.5);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.fab:hover {
|
||||
transform: scale(1.15) rotate(90deg);
|
||||
box-shadow: 0 12px 35px rgba(255, 107, 107, 0.6);
|
||||
}
|
||||
|
||||
.fab .material-icons {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
/* Success Ping */
|
||||
.success-ping {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.ping-circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(102, 187, 106, 0.6);
|
||||
animation: pingExpand 1s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes pingExpand {
|
||||
0% { width: 0; height: 0; opacity: 1; }
|
||||
100% { width: 500px; height: 500px; opacity: 0; }
|
||||
}
|
||||
|
||||
/* Mobile Adaptation */
|
||||
@media (max-width: 480px) {
|
||||
.welcome-title { font-size: 36px; }
|
||||
.card { padding: 16px; border-radius: 20px; }
|
||||
.btn { padding: 14px 24px; width: 100%; }
|
||||
.mood-emoji { font-size: 40px; }
|
||||
.breathing-circle { width: 180px; height: 180px; }
|
||||
.bottom-nav { padding: 8px 0; }
|
||||
.nav-item { padding: 6px 12px; }
|
||||
.nav-label { font-size: 10px; }
|
||||
}
|
||||
|
||||
/* Desktop Sidebar */
|
||||
@media (min-width: 1024px) {
|
||||
.bottom-nav { display: none; }
|
||||
/* ... (keep existing desktop styles if needed, but adapt to new look) ... */
|
||||
}
|
||||
Reference in New Issue
Block a user