diff --git a/Background_Dark.jpg b/Background_Dark.jpg new file mode 100644 index 0000000..91e0d73 Binary files /dev/null and b/Background_Dark.jpg differ diff --git a/TalkHeal.py b/TalkHeal.py index e0068fa..6597dbe 100644 --- a/TalkHeal.py +++ b/TalkHeal.py @@ -41,16 +41,6 @@ model = configure_gemini() -col_toggle, col_main = st.columns([0.05, 0.95]) - -with col_toggle: - if st.button("☰", key="persistent_sidebar_toggle", help="Toggle Sidebar"): - if st.session_state.sidebar_state == "expanded": - st.session_state.sidebar_state = "collapsed" - else: - st.session_state.sidebar_state = "expanded" - st.rerun() - render_sidebar() render_header() diff --git a/blue.png b/blue.png new file mode 100644 index 0000000..25ecc70 Binary files /dev/null and b/blue.png differ diff --git a/components/__pycache__/__init__.cpython-313.pyc b/components/__pycache__/__init__.cpython-313.pyc index b5eb29b..171d2dd 100644 Binary files a/components/__pycache__/__init__.cpython-313.pyc and b/components/__pycache__/__init__.cpython-313.pyc differ diff --git a/components/__pycache__/chat_interface.cpython-313.pyc b/components/__pycache__/chat_interface.cpython-313.pyc index c6cb3be..c6e50f5 100644 Binary files a/components/__pycache__/chat_interface.cpython-313.pyc and b/components/__pycache__/chat_interface.cpython-313.pyc differ diff --git a/components/__pycache__/header.cpython-313.pyc b/components/__pycache__/header.cpython-313.pyc index 3599f89..333a96c 100644 Binary files a/components/__pycache__/header.cpython-313.pyc and b/components/__pycache__/header.cpython-313.pyc differ diff --git a/components/__pycache__/sidebar.cpython-313.pyc b/components/__pycache__/sidebar.cpython-313.pyc index 6b26cef..7b7f4d1 100644 Binary files a/components/__pycache__/sidebar.cpython-313.pyc and b/components/__pycache__/sidebar.cpython-313.pyc differ diff --git a/components/__pycache__/theme_toggle.cpython-313.pyc b/components/__pycache__/theme_toggle.cpython-313.pyc new file mode 100644 index 0000000..aea237e Binary files /dev/null and b/components/__pycache__/theme_toggle.cpython-313.pyc differ diff --git a/components/chat_interface.py b/components/chat_interface.py index c7b52e7..a0343c8 100644 --- a/components/chat_interface.py +++ b/components/chat_interface.py @@ -1,5 +1,6 @@ import streamlit as st from core.utils import get_current_time, get_ai_response +from core.theme import toggle_theme, get_current_theme import streamlit.components.v1 as components import streamlit as st diff --git a/components/header.py b/components/header.py index c8ec43b..c419e22 100644 --- a/components/header.py +++ b/components/header.py @@ -4,6 +4,24 @@ def render_header(): with st.container(): + # Top bar with hamburger menu and theme toggle + col1, col2, col3 = st.columns([0.1, 0.8, 0.1]) + + with col1: + if st.button("☰", key="top_hamburger_menu", help="Toggle Sidebar", use_container_width=True): + if st.session_state.sidebar_state == "expanded": + st.session_state.sidebar_state = "collapsed" + else: + st.session_state.sidebar_state = "expanded" + st.rerun() + + with col3: + is_dark = st.session_state.get('dark_mode', False) + if st.button("🌙" if is_dark else "â˜€ī¸", key="top_theme_toggle", help="Toggle Light/Dark Mode", use_container_width=True): + st.session_state.dark_mode = not is_dark + st.session_state.theme_changed = True + st.rerun() + st.markdown("""

TalkHeal

diff --git a/components/sidebar.py b/components/sidebar.py index 6d9aeee..7765a57 100644 --- a/components/sidebar.py +++ b/components/sidebar.py @@ -2,6 +2,7 @@ import webbrowser from datetime import datetime from core.utils import create_new_conversation, get_current_time +from core.theme import get_current_theme, toggle_theme, set_palette, PALETTES # Emergency contacts and resources emergency_resources = { @@ -288,6 +289,44 @@ def render_sidebar(): for number in numbers: st.markdown(f"â€ĸ {number}") + # Theme toggle in sidebar + with st.expander("🎨 Theme Settings"): + current_theme = get_current_theme() + is_dark = current_theme["name"] == "Dark" + + # Palette selector (only for light mode) + if not is_dark: + palette_names = [p["name"] for p in PALETTES] + selected_palette = st.selectbox( + "Choose a soothing color palette:", + palette_names, + index=palette_names.index(st.session_state.get("palette_name", "Light")), + key="palette_selector", + ) + if selected_palette != st.session_state.get("palette_name", "Light"): + set_palette(selected_palette) + + # Current theme display with better styling + st.markdown(""" +
+ Current Theme:
+ {} Mode +
+ """.format(current_theme['name']), unsafe_allow_html=True) + + # Theme toggle button with better styling + button_text = "🌙 Dark Mode" if not is_dark else "â˜€ī¸ Light Mode" + button_color = "primary" if not is_dark else "secondary" + + if st.button( + button_text, + key="sidebar_theme_toggle", + use_container_width=True, + type=button_color + ): + toggle_theme() + + with st.expander("â„šī¸ About TalkHeal"): st.markdown(""" **TalkHeal** is your compassionate mental health companion, designed to provide: diff --git a/components/theme_toggle.py b/components/theme_toggle.py new file mode 100644 index 0000000..e4e2dd1 --- /dev/null +++ b/components/theme_toggle.py @@ -0,0 +1,68 @@ +import streamlit as st +from core.theme import toggle_theme, get_current_theme + +def render_theme_toggle(): + """Render the theme toggle button in the top right corner.""" + current_theme = get_current_theme() + is_dark = current_theme["name"] == "Dark" + + # Create a container for the theme toggle + with st.container(): + # Use columns to position the toggle on the right + col1, col2, col3 = st.columns([0.7, 0.2, 0.1]) + + with col3: + # Theme toggle button + button_text = "🌙 Dark Mode" if is_dark else "â˜€ī¸ Light Mode" + button_color = "primary" if is_dark else "secondary" + + if st.button( + button_text, + key="theme_toggle", + help="Toggle Light/Dark Mode", + use_container_width=True, + type=button_color + ): + toggle_theme() + + # Add some custom CSS to style the toggle button + st.markdown(""" + + """, unsafe_allow_html=True) \ No newline at end of file diff --git a/core/__pycache__/__init__.cpython-313.pyc b/core/__pycache__/__init__.cpython-313.pyc index 0c7aeb7..ae8bca5 100644 Binary files a/core/__pycache__/__init__.cpython-313.pyc and b/core/__pycache__/__init__.cpython-313.pyc differ diff --git a/core/__pycache__/config.cpython-313.pyc b/core/__pycache__/config.cpython-313.pyc index aab7895..190a42e 100644 Binary files a/core/__pycache__/config.cpython-313.pyc and b/core/__pycache__/config.cpython-313.pyc differ diff --git a/core/__pycache__/theme.cpython-313.pyc b/core/__pycache__/theme.cpython-313.pyc new file mode 100644 index 0000000..face49c Binary files /dev/null and b/core/__pycache__/theme.cpython-313.pyc differ diff --git a/core/__pycache__/utils.cpython-313.pyc b/core/__pycache__/utils.cpython-313.pyc index 84cbc69..33e809a 100644 Binary files a/core/__pycache__/utils.cpython-313.pyc and b/core/__pycache__/utils.cpython-313.pyc differ diff --git a/core/theme.py b/core/theme.py new file mode 100644 index 0000000..a52edc3 --- /dev/null +++ b/core/theme.py @@ -0,0 +1,249 @@ +import streamlit as st +from typing import Dict, Any + +# Light theme (current default) +LIGHT_THEME = { + "name": "Light", + "background_image": "Background.jpg", + "primary": "#6366f1", + "primary_light": "#818cf8", + "primary_dark": "#4f46e5", + "secondary": "#ec4899", + "success": "#10b981", + "warning": "#f59e0b", + "danger": "#ef4444", + "surface": "rgba(255, 255, 255, 0.15)", + "surface_alt": "rgba(255, 255, 255, 0.25)", + "text_primary": "#1e293b", + "text_secondary": "#64748b", + "text_muted": "#94a3b8", + "border": "rgba(255, 255, 255, 0.3)", + "border_light": "rgba(255, 255, 255, 0.2)", + "shadow": "rgba(0, 0, 0, 0.15)", + "shadow_lg": "rgba(0, 0, 0, 0.25)", + "light_transparent_bg": "rgba(255, 255, 255, 0.4)", + "light_transparent_bg_hover": "rgba(255, 255, 255, 0.6)", + "light_transparent_border": "rgba(255, 255, 255, 0.5)", + "active_conversation_bg": "linear-gradient(135deg, rgba(99, 102, 241, 0.9) 0%, rgba(129, 140, 248, 0.9) 100%)", + "active_conversation_border": "rgba(99, 102, 241, 0.8)", + "active_conversation_shadow": "rgba(99, 102, 241, 0.4)", + "background_overlay": "rgba(0, 0, 0, 0.3)", + "main_text_color": "white", + "sidebar_bg": "rgba(255, 255, 255, 0.15)", + "sidebar_text": "#1e293b", + "input_bg": "purple", + "input_text": "white" +} + +# Additional soothing palettes +CALM_BLUE = { + "name": "Calm Blue", + "background_image": "blue.png", + "background_gradient": "linear-gradient(135deg, #3674B5 0%, #578FCA 40%, #A1E3F9 75%, #D1F8EF 100%)", + "primary": "#3674B5", + "primary_light": "#578FCA", + "primary_dark": "#3674B5", + "secondary": "#A1E3F9", + "success": "#578FCA", + "warning": "#A1E3F9", + "danger": "#D1F8EF", + "surface": "rgba(255, 255, 255, 0.25)", + "surface_alt": "rgba(255, 255, 255, 0.35)", + "text_primary": "#2d3436", + "text_secondary": "#636e72", + "text_muted": "#b2bec3", + "border": "rgba(87, 143, 202, 0.2)", + "border_light": "rgba(87, 143, 202, 0.1)", + "shadow": "rgba(87, 143, 202, 0.08)", + "shadow_lg": "rgba(87, 143, 202, 0.15)", + "light_transparent_bg": "rgba(255, 255, 255, 0.5)", + "light_transparent_bg_hover": "rgba(255, 255, 255, 0.7)", + "light_transparent_border": "rgba(87, 143, 202, 0.2)", + "active_conversation_bg": "linear-gradient(135deg, #3674B5 0%, #578FCA 60%, #A1E3F9 100%)", + "active_conversation_border": "#3674B5", + "active_conversation_shadow": "rgba(87, 143, 202, 0.2)", + "background_overlay": "rgba(255, 255, 255, 0.2)", + "main_text_color": "#2d3436", + "sidebar_bg": "rgba(255, 255, 255, 0.25)", + "sidebar_text": "#2d3436", + "input_bg": "#D1F8EF", + "input_text": "#2d3436" +} + +MINT = { + "name": "Mint", + "background_image": "mint.png", + "background_gradient": "linear-gradient(135deg, #3D8D7A 0%, #B3D8A8 40%, #FBFFE4 75%, #A3D1C6 100%)", + "primary": "#3D8D7A", + "primary_light": "#B3D8A8", + "primary_dark": "#3D8D7A", + "secondary": "#FBFFE4", + "success": "#B3D8A8", + "warning": "#A3D1C6", + "danger": "#FBFFE4", + "surface": "rgba(255, 255, 255, 0.25)", + "surface_alt": "rgba(255, 255, 255, 0.35)", + "text_primary": "#2d3436", + "text_secondary": "#636e72", + "text_muted": "#b2bec3", + "border": "rgba(179, 216, 168, 0.2)", + "border_light": "rgba(179, 216, 168, 0.1)", + "shadow": "rgba(179, 216, 168, 0.08)", + "shadow_lg": "rgba(179, 216, 168, 0.15)", + "light_transparent_bg": "rgba(255, 255, 255, 0.5)", + "light_transparent_bg_hover": "rgba(255, 255, 255, 0.7)", + "light_transparent_border": "rgba(179, 216, 168, 0.2)", + "active_conversation_bg": "linear-gradient(135deg, #3D8D7A 0%, #B3D8A8 60%, #A3D1C6 100%)", + "active_conversation_border": "#3D8D7A", + "active_conversation_shadow": "rgba(179, 216, 168, 0.2)", + "background_overlay": "rgba(255, 255, 255, 0.2)", + "main_text_color": "#2C3930", + "sidebar_bg": "rgba(255, 255, 255, 0.25)", + "sidebar_text": "#2C3930", + "input_bg": "#FBFFE4", + "input_text": "#2C3930" +} + +LAVENDER = { + "name": "Lavender", + "background_image": "lavender.png", + "background_gradient": "linear-gradient(135deg, #756AB6 0%, #AC87C5 40%, #E0AED0 75%, #FFE5E5 100%)", + "primary": "#756AB6", + "primary_light": "#AC87C5", + "primary_dark": "#756AB6", + "secondary": "#E0AED0", + "success": "#AC87C5", + "warning": "#E0AED0", + "danger": "#FFE5E5", + "surface": "rgba(255, 255, 255, 0.25)", + "surface_alt": "rgba(255, 255, 255, 0.35)", + "text_primary": "#2d3436", + "text_secondary": "#636e72", + "text_muted": "#b2bec3", + "border": "rgba(172, 135, 197, 0.2)", + "border_light": "rgba(172, 135, 197, 0.1)", + "shadow": "rgba(172, 135, 197, 0.08)", + "shadow_lg": "rgba(172, 135, 197, 0.15)", + "light_transparent_bg": "rgba(255, 255, 255, 0.5)", + "light_transparent_bg_hover": "rgba(255, 255, 255, 0.7)", + "light_transparent_border": "rgba(172, 135, 197, 0.2)", + "active_conversation_bg": "linear-gradient(135deg, #756AB6 0%, #AC87C5 60%, #E0AED0 100%)", + "active_conversation_border": "#756AB6", + "active_conversation_shadow": "rgba(172, 135, 197, 0.2)", + "background_overlay": "rgba(255, 255, 255, 0.2)", + "main_text_color": "#2d3436", + "sidebar_bg": "rgba(255, 255, 255, 0.25)", + "sidebar_text": "#2d3436", + "input_bg": "#FFE5E5", + "input_text": "#2d3436" +} + +Pink = { + "name": "Pink", + "background_image": "pink.png", + "background_gradient": "linear-gradient(135deg, #921A40 0%, #C75B7A 40%, #D9ABAB 75%, #F4D9D0 100%)", + "primary": "#921A40", + "primary_light": "#C75B7A", + "primary_dark": "#921A40", + "secondary": "#D9ABAB", + "success": "#C75B7A", + "warning": "#D9ABAB", + "danger": "#F4D9D0", + "surface": "rgba(255, 255, 255, 0.25)", + "surface_alt": "rgba(255, 255, 255, 0.35)", + "text_primary": "#2d3436", + "text_secondary": "#636e72", + "text_muted": "#b2bec3", + "border": "rgba(199, 91, 122, 0.2)", + "border_light": "rgba(199, 91, 122, 0.1)", + "shadow": "rgba(199, 91, 122, 0.08)", + "shadow_lg": "rgba(199, 91, 122, 0.15)", + "light_transparent_bg": "rgba(255, 255, 255, 0.5)", + "light_transparent_bg_hover": "rgba(255, 255, 255, 0.7)", + "light_transparent_border": "rgba(199, 91, 122, 0.2)", + "active_conversation_bg": "linear-gradient(135deg, #921A40 0%, #C75B7A 60%, #D9ABAB 100%)", + "active_conversation_border": "#921A40", + "active_conversation_shadow": "rgba(199, 91, 122, 0.2)", + "background_overlay": "rgba(255, 255, 255, 0.2)", + "main_text_color": "#2d3436", + "sidebar_bg": "rgba(255, 255, 255, 0.25)", + "sidebar_text": "#2d3436", + "input_bg": "#F4D9D0", + "input_text": "#2d3436" +} + +# Dark theme +DARK_THEME = { + "name": "Dark", + "background_image": "dark.png", + "primary": "#6366f1", + "primary_light": "#818cf8", + "primary_dark": "#4f46e5", + "secondary": "#ec4899", + "success": "#10b981", + "warning": "#f59e0b", + "danger": "#ef4444", + "surface": "rgba(0, 0, 0, 0.4)", + "surface_alt": "rgba(0, 0, 0, 0.5)", + "text_primary": "#f8fafc", + "text_secondary": "#cbd5e1", + "text_muted": "#94a3b8", + "border": "rgba(255, 255, 255, 0.2)", + "border_light": "rgba(255, 255, 255, 0.1)", + "shadow": "rgba(0, 0, 0, 0.4)", + "shadow_lg": "rgba(0, 0, 0, 0.6)", + "light_transparent_bg": "rgba(0, 0, 0, 0.5)", + "light_transparent_bg_hover": "rgba(0, 0, 0, 0.7)", + "light_transparent_border": "rgba(255, 255, 255, 0.2)", + "active_conversation_bg": "linear-gradient(135deg, rgba(99, 102, 241, 0.8) 0%, rgba(129, 140, 248, 0.8) 100%)", + "active_conversation_border": "rgba(99, 102, 241, 0.6)", + "active_conversation_shadow": "rgba(99, 102, 241, 0.3)", + "background_overlay": "rgba(0, 0, 0, 0.6)", + "main_text_color": "#f8fafc", + "sidebar_bg": "rgba(0, 0, 0, 0.4)", + "sidebar_text": "#f8fafc", + "input_bg": "#374151", + "input_text": "#f8fafc" +} + +PALETTES = [ + LIGHT_THEME, + CALM_BLUE, + MINT, + LAVENDER, + Pink +] + +PALETTE_NAME_TO_CONFIG = {p["name"]: p for p in PALETTES} + + +def initialize_theme_state(): + """Initialize theme-related session state variables.""" + if "dark_mode" not in st.session_state: + st.session_state.dark_mode = False + if "theme_changed" not in st.session_state: + st.session_state.theme_changed = False + if "palette_name" not in st.session_state: + st.session_state.palette_name = "Light" + + +def get_current_theme() -> Dict[str, Any]: + """Get the current theme configuration based on session state.""" + initialize_theme_state() + if st.session_state.dark_mode: + return DARK_THEME + else: + palette = PALETTE_NAME_TO_CONFIG.get(st.session_state.get("palette_name", "Light"), LIGHT_THEME) + return palette + +def set_palette(palette_name: str): + st.session_state.palette_name = palette_name + st.session_state.theme_changed = True + st.rerun() + +def toggle_theme(): + """Toggle between light and dark themes.""" + initialize_theme_state() + st.session_state.dark_mode = not st.session_state.dark_mode + st.session_state.theme_changed = True + st.rerun() \ No newline at end of file diff --git a/css/__pycache__/styles.cpython-313.pyc b/css/__pycache__/styles.cpython-313.pyc index 5fe2de4..afa6719 100644 Binary files a/css/__pycache__/styles.cpython-313.pyc and b/css/__pycache__/styles.cpython-313.pyc differ diff --git a/css/styles.py b/css/styles.py index 37fe904..b2399aa 100644 --- a/css/styles.py +++ b/css/styles.py @@ -8,11 +8,27 @@ def get_base64_of_bin_file(bin_file): return base64.b64encode(data).decode() def apply_custom_css(): - # Path to your background image - background_image_path = "Background.jpg" + # Import theme configuration + from core.theme import get_current_theme + theme_config = get_current_theme() - # Encode the image to base64 - base64_image = get_base64_of_bin_file(background_image_path) + # Path to background image based on theme + background_image_path = theme_config.get('background_image', 'Background.jpg') + background_gradient = theme_config.get('background_gradient', None) + + base64_image = None + if background_image_path: + try: + base64_image = get_base64_of_bin_file(background_image_path) + except Exception: + base64_image = None + + if base64_image: + background_css = f'background-image: url("data:image/jpeg;base64,{base64_image}");' + elif background_gradient: + background_css = f'background-image: {background_gradient};' + else: + background_css = '' st.markdown(f""" """, unsafe_allow_html=True) \ No newline at end of file diff --git a/dark.png b/dark.png new file mode 100644 index 0000000..c2fae89 Binary files /dev/null and b/dark.png differ diff --git a/lavender.png b/lavender.png new file mode 100644 index 0000000..09135cf Binary files /dev/null and b/lavender.png differ diff --git a/mint.png b/mint.png new file mode 100644 index 0000000..cdeb254 Binary files /dev/null and b/mint.png differ diff --git a/pink.png b/pink.png new file mode 100644 index 0000000..96b8df8 Binary files /dev/null and b/pink.png differ