Logo Implementation: - Logo now appears on ALL pages automatically - Moved logo display to apply_custom_styles() function - 300px width, positioned at top with margin adjustments - Uses SBLM.jpg from src/notebookllama/ Login Page Improvements: - Sidebar completely hidden when not logged in - Cleaner login experience - No navigation shown to unauthenticated users - Title updated to "Sandbox-NotebookLM - Login" Admin Dashboard: - Replaced Observability Dashboard with Admin Dashboard - Shows platform usage statistics: * Total users, notebooks, documents, chat messages * Estimated costs (documents, chats, podcasts) * Recent activity (users, notebooks, documents) * Background task monitoring * User analytics (most active users) * System health (failed/pending tasks) Admin Access Control: - Only user ID 1 or users with "admin" in email can access - Admin link only shows in sidebar for admins - Protected with access check Cost Tracking: - Document processing: ~$0.60 each - Chat messages: ~$0.01 each - Podcasts: ~$0.50 each - Total cost estimate displayed Analytics Features: - Top 5 most active users by notebook count - Recent users/notebooks/documents lists - Background task status with color coding - System health indicators - Real-time statistics Files: - Created pages/5_Admin_Dashboard.py - Removed pages/5_Observability_Dashboard.py (backed up) - Updated styles.py with show_logo() function - Updated App.py navigation to show Admin conditionally 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
193 lines
4.7 KiB
Python
193 lines
4.7 KiB
Python
"""
|
|
Global CSS styles for NotebookLlaMa
|
|
Apply consistent typography and styling across all pages
|
|
"""
|
|
|
|
def get_custom_css():
|
|
"""Return custom CSS for the application"""
|
|
return """
|
|
<style>
|
|
/* Import Montserrat font */
|
|
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap');
|
|
|
|
/* Apply Montserrat globally */
|
|
* {
|
|
font-family: 'Montserrat', sans-serif !important;
|
|
}
|
|
|
|
/* Main headers - reduce from 44px to 20px */
|
|
h1 {
|
|
font-size: 20px !important;
|
|
font-weight: 600 !important;
|
|
line-height: 1.3 !important;
|
|
margin-bottom: 0.5rem !important;
|
|
}
|
|
|
|
/* Subheaders */
|
|
h2 {
|
|
font-size: 18px !important;
|
|
font-weight: 600 !important;
|
|
line-height: 1.3 !important;
|
|
margin-bottom: 0.5rem !important;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 16px !important;
|
|
font-weight: 600 !important;
|
|
line-height: 1.3 !important;
|
|
margin-bottom: 0.5rem !important;
|
|
}
|
|
|
|
/* Body text */
|
|
p, div, span {
|
|
font-size: 16px !important;
|
|
line-height: 1.5 !important;
|
|
}
|
|
|
|
/* Source citations - smaller text */
|
|
.stExpander summary {
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
.stMarkdown a, .stMarkdown small, .stCaption {
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
/* Chat messages */
|
|
.stChatMessage {
|
|
font-size: 16px !important;
|
|
}
|
|
|
|
.stChatMessage h1, .stChatMessage h2, .stChatMessage h3 {
|
|
font-size: 16px !important;
|
|
font-weight: 600 !important;
|
|
}
|
|
|
|
.stChatMessage strong {
|
|
font-size: 16px !important;
|
|
font-weight: 600 !important;
|
|
}
|
|
|
|
/* Buttons */
|
|
.stButton button {
|
|
font-family: 'Montserrat', sans-serif !important;
|
|
font-size: 14px !important;
|
|
font-weight: 500 !important;
|
|
}
|
|
|
|
/* Input fields */
|
|
input, textarea, select {
|
|
font-family: 'Montserrat', sans-serif !important;
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
/* Sidebar */
|
|
.css-1d391kg, [data-testid="stSidebar"] {
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
[data-testid="stSidebar"] h1 {
|
|
font-size: 16px !important;
|
|
font-weight: 600 !important;
|
|
}
|
|
|
|
[data-testid="stSidebar"] .stMarkdown h1,
|
|
[data-testid="stSidebar"] .stMarkdown h2,
|
|
[data-testid="stSidebar"] .stMarkdown h3 {
|
|
font-size: 14px !important;
|
|
font-weight: 600 !important;
|
|
}
|
|
|
|
/* Hide Streamlit's auto-generated page list (keep our custom navigation) */
|
|
section[data-testid="stSidebarNav"] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Keep our custom navigation visible */
|
|
[data-testid="stSidebar"] .stMarkdown {
|
|
display: block !important;
|
|
}
|
|
|
|
/* Sidebar user info - reduce username size */
|
|
[data-testid="stSidebar"] .element-container {
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
/* Expander headers */
|
|
.streamlit-expanderHeader {
|
|
font-size: 15px !important;
|
|
font-weight: 500 !important;
|
|
}
|
|
|
|
/* Source link badges */
|
|
.stMarkdown code {
|
|
font-size: 13px !important;
|
|
padding: 2px 6px !important;
|
|
}
|
|
|
|
/* Info/Warning/Error boxes */
|
|
.stAlert {
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
/* Captions */
|
|
.caption, small, .stCaption {
|
|
font-size: 13px !important;
|
|
color: #6c757d !important;
|
|
}
|
|
|
|
/* Reduce spacing for cleaner look */
|
|
.block-container {
|
|
padding-top: 2rem !important;
|
|
padding-bottom: 1rem !important;
|
|
}
|
|
|
|
/* Streamlit title */
|
|
[data-testid="stAppViewContainer"] h1:first-of-type {
|
|
font-size: 24px !important;
|
|
font-weight: 700 !important;
|
|
}
|
|
|
|
/* Hide deploy button in top right */
|
|
[data-testid="stToolbar"] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Hide keyboard shortcut hints */
|
|
[data-testid="stDecoration"] {
|
|
display: none !important;
|
|
}
|
|
|
|
.stDecorationBar {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Hide the keyboard shortcut text */
|
|
button[kind="header"] span {
|
|
display: none !important;
|
|
}
|
|
</style>
|
|
"""
|
|
|
|
|
|
def show_logo():
|
|
"""Display the logo at the top of the page"""
|
|
import streamlit as st
|
|
import base64
|
|
from pathlib import Path
|
|
|
|
logo_path = Path(__file__).parent / "SBLM.jpg"
|
|
if logo_path.exists():
|
|
with open(logo_path, "rb") as f:
|
|
logo_data = base64.b64encode(f.read()).decode()
|
|
st.markdown(
|
|
f'<div style="text-align: left; margin-bottom: 1.5rem; margin-top: -1rem;"><img src="data:image/jpeg;base64,{logo_data}" width="300"></div>',
|
|
unsafe_allow_html=True
|
|
)
|
|
|
|
|
|
def apply_custom_styles():
|
|
"""Apply custom CSS to the current page"""
|
|
import streamlit as st
|
|
st.markdown(get_custom_css(), unsafe_allow_html=True)
|
|
show_logo()
|