AISqlGeneratorApp / src /themes.py
Vivek0912's picture
added new code
cce43bc
"""
Theme management for the AI Database Assistant.
Handles CSS injection and theme-specific styling.
"""
import streamlit as st
from typing import Dict
class ThemeManager:
"""Manages themes and CSS styling for the application."""
def __init__(self):
self.themes = {
"Light": self._get_light_theme(),
"Dark": self._get_dark_theme(),
"Custom": self._get_custom_theme()
}
def _get_light_theme(self) -> str:
"""Returns CSS for light theme."""
return """
/* Light Theme - Clean and Professional */
body, .stApp {
background: #f8fafc !important;
color: #1f2937 !important;
}
/* Ensure all text is dark in light mode */
div, p, span, label, h1, h2, h3, h4, h5, h6 {
color: #1f2937 !important;
}
/* Professional header colors for light theme */
.main-header h1 {
color: #1f2937 !important;
}
.main-header p {
color: #6b7280 !important;
}
.chat-container { max-width: 900px; margin: auto; }
.user-bubble {
background: linear-gradient(90deg, #e3f2fd, #ffffff);
color: #222 !important; float: right; clear: both;
}
.ai-bubble {
background: linear-gradient(90deg, #f3e5f5, #ffffff);
color: #222 !important; float: left; clear: both;
}
.error-bubble {
background: #ffebee; color: #b71c1c !important; font-weight: bold;
float: left; clear: both;
}
/* Sidebar styling */
section[data-testid="stSidebar"] {
background: #e3f2fd !important;
border-right: 2px solid #1976d2;
}
/* Sidebar text should be dark */
section[data-testid="stSidebar"] * {
color: #1f2937 !important;
}
.sidebar-content { padding: 1rem; }
/* Input fields in light mode */
.stTextInput > div > div > input {
background-color: #ffffff !important;
color: #1f2937 !important;
border: 1px solid #d1d5db !important;
}
/* Select boxes in light mode */
.stSelectbox > div > div > select {
background-color: #ffffff !important;
color: #1f2937 !important;
border: 1px solid #d1d5db !important;
}
/* Dropdown options in light mode */
.stSelectbox > div > div > select > option {
background-color: #ffffff !important;
color: #1f2937 !important;
}
/* Buttons in light mode - Strong selectors for all buttons */
.stButton > button {
background: linear-gradient(45deg, #667eea, #764ba2) !important;
color: #ffffff !important;
border: none !important;
font-weight: 600 !important;
border-radius: 8px !important;
padding: 0.6rem 1.2rem !important;
min-height: 2.8rem !important;
font-size: 14px !important;
transition: all 0.2s ease !important;
}
.stButton > button:hover {
background: linear-gradient(45deg, #5a67d8, #6b46c1) !important;
color: #ffffff !important;
transform: translateY(-1px) !important;
}
/* Ensure button text stays white - stronger selectors */
.stButton > button span,
.stButton > button div,
.stButton > button *,
.stButton > button p {
color: #ffffff !important;
font-weight: 600 !important;
}
/* Specific targeting for all button states and text elements */
button[kind="primary"],
button[kind="secondary"],
div[data-testid="stButton"] > button,
.stButton button {
background: linear-gradient(45deg, #667eea, #764ba2) !important;
color: #ffffff !important;
border: none !important;
font-weight: 600 !important;
}
/* All text inside buttons must be white */
button[kind="primary"] *,
button[kind="primary"] span,
button[kind="primary"] div,
button[kind="primary"] p,
button[kind="secondary"] *,
button[kind="secondary"] span,
button[kind="secondary"] div,
button[kind="secondary"] p,
div[data-testid="stButton"] > button *,
div[data-testid="stButton"] > button span,
div[data-testid="stButton"] > button div,
div[data-testid="stButton"] > button p,
.stButton button *,
.stButton button span,
.stButton button div,
.stButton button p {
color: #ffffff !important;
font-weight: 600 !important;
}
button[kind="primary"]:hover,
button[kind="secondary"]:hover,
div[data-testid="stButton"] > button:hover,
.stButton button:hover {
background: linear-gradient(45deg, #5a67d8, #6b46c1) !important;
color: #ffffff !important;
}
/* Hover state text colors */
button[kind="primary"]:hover *,
button[kind="secondary"]:hover *,
div[data-testid="stButton"] > button:hover *,
.stButton button:hover * {
color: #ffffff !important;
}
/* Force all button text elements to be white */
.stButton > button * {
color: #ffffff !important;
}
/* Disabled button styling */
.stButton > button:disabled {
background: #9ca3af !important;
color: #ffffff !important;
opacity: 0.6 !important;
}
.stButton > button:disabled * {
color: #ffffff !important;
}
/* Copy button styling in light mode */
.copy-button {
background: #6b7280 !important;
color: #ffffff !important;
border: none !important;
}
.copy-button:hover {
background: #4b5563 !important;
color: #ffffff !important;
}
/* Labels and form elements */
.stTextInput label, .stSelectbox label, .stRadio label, .stCheckbox label {
color: #1f2937 !important;
font-weight: 500 !important;
}
/* Metrics in light mode */
[data-testid="metric-container"] {
background: #ffffff !important;
border: 1px solid #e5e7eb !important;
color: #1f2937 !important;
}
[data-testid="metric-container"] * {
color: #1f2937 !important;
}
/* Additional button overrides for light theme */
div[data-testid="column"] .stButton > button {
background: linear-gradient(45deg, #667eea, #764ba2) !important;
color: #ffffff !important;
}
/* Force override of any inherited text colors */
.stButton > button p, .stButton > button div, .stButton > button span {
color: #ffffff !important;
}
/* Hide Streamlit toolbar and menu */
.stToolbar {
display: none !important;
}
/* Hide Streamlit header menu */
header[data-testid="stHeader"] {
display: none !important;
}
/* Hide the running/rerun indicator */
.stAppView > .main .block-container {
padding-top: 1rem !important;
}
"""
def _get_dark_theme(self) -> str:
"""Returns CSS for dark theme."""
return """
/* Modern Dark Theme - High Contrast & Clean */
body, .stApp {
background: #1a1a1a !important;
color: #ffffff !important;
}
/* Override all text colors for visibility */
div, p, span, label, h1, h2, h3, h4, h5, h6 {
color: #ffffff !important;
}
/* Professional header colors for dark theme */
.main-header h1 {
color: #ffffff !important;
}
.main-header p {
color: #9ca3af !important;
}
/* Main container */
.chat-container {
max-width: 900px;
margin: auto;
}
/* User message bubble - Clean Blue */
.user-bubble {
background: #2563eb !important;
color: #ffffff !important;
float: right;
clear: both;
border: none !important;
box-shadow: 0 2px 10px rgba(37, 99, 235, 0.4) !important;
}
/* AI message bubble - Clean Dark Gray */
.ai-bubble {
background: #374151 !important;
color: #ffffff !important;
float: left;
clear: both;
border: 1px solid #4b5563 !important;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3) !important;
}
/* Error bubble - Clean Red */
.error-bubble {
background: #dc2626 !important;
color: #ffffff !important;
font-weight: bold;
float: left;
clear: both;
border: none !important;
box-shadow: 0 2px 10px rgba(220, 38, 38, 0.4) !important;
}
/* Sidebar - Clean Dark */
section[data-testid="stSidebar"] {
background: #2d2d2d !important;
border-right: 2px solid #4b5563 !important;
}
/* Sidebar content visibility */
section[data-testid="stSidebar"] * {
color: #ffffff !important;
}
/* Input fields - High contrast */
.stTextInput > div > div > input {
background-color: #374151 !important;
color: #ffffff !important;
border: 2px solid #6b7280 !important;
}
/* Select boxes - High contrast */
.stSelectbox > div > div > select {
background-color: #374151 !important;
color: #ffffff !important;
border: 2px solid #6b7280 !important;
}
/* Dropdown options styling */
.stSelectbox > div > div > select > option {
background-color: #374151 !important;
color: #ffffff !important;
}
/* Alternative dropdown styling for better browser support */
div[data-baseweb="select"] {
background-color: #374151 !important;
}
div[data-baseweb="select"] > div {
background-color: #374151 !important;
color: #ffffff !important;
border: 2px solid #6b7280 !important;
}
/* Dropdown menu styling */
ul[role="listbox"] {
background-color: #374151 !important;
border: 1px solid #6b7280 !important;
}
li[role="option"] {
background-color: #374151 !important;
color: #ffffff !important;
}
li[role="option"]:hover {
background-color: #4b5563 !important;
color: #ffffff !important;
}
/* Buttons - Clean and visible - Strong selectors for all buttons */
.stButton > button {
background: #2563eb !important;
color: #ffffff !important;
border: none !important;
font-weight: 600 !important;
border-radius: 8px !important;
padding: 0.6rem 1.2rem !important;
min-height: 2.8rem !important;
font-size: 14px !important;
transition: all 0.2s ease !important;
}
.stButton > button:hover {
background: #1d4ed8 !important;
color: #ffffff !important;
transform: translateY(-1px) !important;
}
/* Ensure button text stays white - stronger selectors */
.stButton > button span,
.stButton > button div,
.stButton > button *,
.stButton > button p {
color: #ffffff !important;
font-weight: 600 !important;
}
/* Specific targeting for all button states and text elements */
button[kind="primary"],
button[kind="secondary"],
div[data-testid="stButton"] > button,
.stButton button {
background: #2563eb !important;
color: #ffffff !important;
border: none !important;
font-weight: 600 !important;
}
/* All text inside buttons must be white */
button[kind="primary"] *,
button[kind="primary"] span,
button[kind="primary"] div,
button[kind="primary"] p,
button[kind="secondary"] *,
button[kind="secondary"] span,
button[kind="secondary"] div,
button[kind="secondary"] p,
div[data-testid="stButton"] > button *,
div[data-testid="stButton"] > button span,
div[data-testid="stButton"] > button div,
div[data-testid="stButton"] > button p,
.stButton button *,
.stButton button span,
.stButton button div,
.stButton button p {
color: #ffffff !important;
font-weight: 600 !important;
}
button[kind="primary"]:hover,
button[kind="secondary"]:hover,
div[data-testid="stButton"] > button:hover,
.stButton button:hover {
background: #1d4ed8 !important;
color: #ffffff !important;
}
/* Hover state text colors */
button[kind="primary"]:hover *,
button[kind="secondary"]:hover *,
div[data-testid="stButton"] > button:hover *,
.stButton button:hover * {
color: #ffffff !important;
}
/* Expander - Clean styling */
.streamlit-expanderHeader {
background-color: #374151 !important;
color: #ffffff !important;
border: 1px solid #6b7280 !important;
}
/* Metrics - High visibility */
[data-testid="metric-container"] {
background: #374151 !important;
border: 1px solid #6b7280 !important;
color: #ffffff !important;
}
[data-testid="metric-container"] * {
color: #ffffff !important;
}
/* Code blocks - GitHub dark style */
pre, code {
background-color: #0d1117 !important;
color: #f0f6fc !important;
border: 1px solid #30363d !important;
}
/* Tables - Clean dark */
.dataframe, .dataframe * {
background-color: #374151 !important;
color: #ffffff !important;
}
/* Table headers */
.dataframe th {
background-color: #2563eb !important;
color: #ffffff !important;
}
/* Streamlit widgets override */
.stRadio > div, .stCheckbox > div {
color: #ffffff !important;
}
.stRadio > div > label, .stCheckbox > div > label {
color: #ffffff !important;
}
/* Spinner for dark theme */
.stSpinner > div {
border-top-color: #2563eb !important;
}
/* Success/Info messages */
.stSuccess, .stInfo {
background-color: #374151 !important;
color: #ffffff !important;
border: 1px solid #6b7280 !important;
}
/* Warning messages */
.stWarning {
background-color: #f59e0b !important;
color: #000000 !important;
}
/* Error messages */
.stError {
background-color: #dc2626 !important;
color: #ffffff !important;
}
/* Additional dropdown fixes */
.stSelectbox [data-testid="stMarkdownContainer"] {
color: #ffffff !important;
}
/* Streamlit's custom selectbox */
div[data-testid="stSelectbox"] div[data-testid="stMarkdownContainer"] p {
color: #ffffff !important;
}
/* Multi-select components */
.stMultiSelect > div > div > div {
background-color: #374151 !important;
color: #ffffff !important;
border: 2px solid #6b7280 !important;
}
/* Radio button labels */
.stRadio div[role="radiogroup"] label {
color: #ffffff !important;
}
/* Hide Streamlit toolbar and menu */
.stToolbar {
display: none !important;
}
/* Hide Streamlit header menu */
header[data-testid="stHeader"] {
display: none !important;
}
/* Hide the running/rerun indicator */
.stAppView > .main .block-container {
padding-top: 1rem !important;
}
"""
def _get_custom_theme(self) -> str:
"""Returns CSS for custom theme."""
return """
body, .stApp { background: #fffbe7 !important; }
.chat-container { max-width: 900px; margin: auto; }
.user-bubble {
background: linear-gradient(90deg, #ffe082, #fffbe7);
color: #6d4c00;
float: right;
clear: both;
}
.ai-bubble {
background: linear-gradient(90deg, #b2dfdb, #fffbe7);
color: #004d40;
float: left;
clear: both;
}
.error-bubble {
background: #ffe0b2; color: #b71c1c; font-weight: bold;
float: left; clear: both;
}
section[data-testid="stSidebar"] { background: #ffe082 !important; }
/* Hide Streamlit toolbar and menu */
.stToolbar {
display: none !important;
}
/* Hide Streamlit header menu */
header[data-testid="stHeader"] {
display: none !important;
}
/* Hide the running/rerun indicator */
.stAppView > .main .block-container {
padding-top: 1rem !important;
}
"""
def _get_common_styles(self) -> str:
"""Returns common CSS styles for all themes."""
return """
/* Professional header styling */
.main-header h1 {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif !important;
font-weight: 600 !important;
line-height: 1.2 !important;
margin: 0 !important;
}
.main-header p {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif !important;
font-weight: 400 !important;
line-height: 1.4 !important;
margin: 0 !important;
}
.user-bubble, .ai-bubble, .error-bubble {
border-radius: 14px;
padding: 10px 14px;
margin: 6px 0;
display: inline-block;
max-width: 75%;
word-wrap: break-word;
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}
.spinner {
display: inline-block;
width: 1.3em;
height: 1.3em;
border: 3px solid #e0e0e0;
border-top: 3px solid #2193b0;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-right: 0.7em;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Enhanced button styling for all themes */
.stButton > button {
border-radius: 8px !important;
font-weight: 600 !important;
transition: all 0.2s ease !important;
padding: 0.6rem 1.2rem !important;
min-height: 2.8rem !important;
font-size: 14px !important;
border: none !important;
}
.stButton > button:hover {
transform: translateY(-1px) !important;
}
/* Force all button text elements to maintain proper colors - Super strong selectors */
.stButton > button *,
.stButton > button p,
.stButton > button div,
.stButton > button span,
.stButton > button strong,
.stButton > button em,
.stButton > button i,
.stButton > button b,
div[data-testid="stButton"] > button *,
div[data-testid="stButton"] > button p,
div[data-testid="stButton"] > button div,
div[data-testid="stButton"] > button span,
div[data-testid="stButton"] > button strong,
div[data-testid="stButton"] > button em,
div[data-testid="stButton"] > button i,
div[data-testid="stButton"] > button b,
button[kind="primary"] *,
button[kind="primary"] p,
button[kind="primary"] div,
button[kind="primary"] span,
button[kind="primary"] strong,
button[kind="primary"] em,
button[kind="primary"] i,
button[kind="primary"] b,
button[kind="secondary"] *,
button[kind="secondary"] p,
button[kind="secondary"] div,
button[kind="secondary"] span,
button[kind="secondary"] strong,
button[kind="secondary"] em,
button[kind="secondary"] i,
button[kind="secondary"] b,
.stButton button *,
.stButton button p,
.stButton button div,
.stButton button span,
.stButton button strong,
.stButton button em,
.stButton button i,
.stButton button b {
font-weight: 600 !important;
/* Note: color is set by individual themes */
}
/* Additional strong selectors for buttons */
div[data-testid="stButton"] button,
.stButton button,
button[data-testid],
[data-testid="stButton"] button {
border-radius: 8px !important;
font-weight: 600 !important;
transition: all 0.2s ease !important;
padding: 0.6rem 1.2rem !important;
min-height: 2.8rem !important;
font-size: 14px !important;
border: none !important;
}
/* Ensure ALL button content inherits button color */
.stButton > button,
div[data-testid="stButton"] > button,
button[kind="primary"],
button[kind="secondary"],
.stButton button {
/* Background and text colors are set by individual themes */
}
/* Critical: Force text color inheritance from button */
.stButton > button *,
div[data-testid="stButton"] > button *,
button[kind="primary"] *,
button[kind="secondary"] *,
.stButton button * {
color: inherit !important;
}
/* Scrollbar styling */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: rgba(0,0,0,0.1);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: rgba(128,128,128,0.4);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(128,128,128,0.6);
}
"""
def inject_theme(self, theme_name: str) -> None:
"""Inject the selected theme CSS into the Streamlit app."""
if theme_name not in self.themes:
theme_name = "Light" # Default fallback
theme_css = self.themes[theme_name]
common_css = self._get_common_styles()
combined_css = theme_css + common_css
st.markdown(f"<style>{combined_css}</style>", unsafe_allow_html=True)