import streamlit as st from typing import List, Dict, Tuple, Optional, Any import traceback class StreamlitTutorial: """ Main class for the Streamlit Tutorial application. Handles rendering of all tutorial content, user interaction, and state management. Provides modular components for different tutorial topics and interactive examples. """ def __init__(self): """ Initializes the Streamlit Tutorial application. Sets up page configuration, session state, and custom styling. Prepares the application environment for tutorial content. """ st.set_page_config(page_title="Learn Streamlit", layout="wide") self.init_session_state() self.setup_styles() def init_session_state(self) -> None: """ Initializes session state variables for persistent data storage. Creates state variables for code input and current topic tracking. Ensures consistent state across reruns. Returns: None """ if 'code_input' not in st.session_state: st.session_state.code_input = "" st.session_state.current_topic = "Basic Text Elements" def setup_styles(self) -> None: """ Configures custom CSS styles for the application. Sets up consistent styling for code examples, outputs, and layout. Enhances visual presentation of tutorial content. Returns: None """ st.markdown(""" """, unsafe_allow_html=True) # Add these helper methods in the StreamlitTutorial class def _get_basic_concepts_content(self) -> str: """ Provides content for Basic Concepts section. Contains fundamental explanations and examples. Returns: str: Markdown formatted basic concepts content """ return """ **What are Text Elements?** - Basic building blocks for displaying text - Range from titles to formatted text - Support markdown formatting **Key Components:** 1. Title & Headers 2. Regular text 3. Formatted text 4. Colored text """ def _get_best_practices_content(self) -> str: """ Provides content for Best Practices section. Contains guidelines and recommended approaches. Returns: str: Markdown formatted best practices content """ return """ **Writing Tips:** 1. Use appropriate heading levels 2. Keep text concise and clear 3. Use formatting for emphasis 4. Add visual hierarchy with headers **Code Structure:** ```python st.title('Main Title') st.header('Section Header') st.subheader('Sub-section') st.write('Regular text') ``` """ def _get_examples_content(self) -> str: """ Provides content for Examples section. Contains practical examples and use cases. Returns: str: Markdown formatted examples content """ return """ **Common Patterns:** 1. Page Structure ```python st.title('Dashboard') st.header('Sales Data') st.subheader('Monthly Trends') ``` 2. Formatted Text ```python st.markdown('**Bold** and *italic*') st.markdown(':blue[Colored text]') ``` 3. Mixed Elements ```python st.title('Report') st.write('Regular text') st.markdown('- Bullet point') ``` """ def _get_common_mistakes_content(self) -> str: """ Provides content for Common Mistakes section. Contains typical errors and how to avoid them. Returns: str: Markdown formatted common mistakes content """ return """ 1. Skipping header levels 2. Overusing formatting 3. Inconsistent styling 4. Missing hierarchy **How to Avoid:** - Plan your page structure - Use consistent formatting - Test different screen sizes - Keep it simple """ def _get_widgets_help_content(self) -> str: """ Enhanced help content for widgets section """ return """ **Widget Best Practices:** 1. Input Validation ```python # Add validation to inputs age = st.number_input('Age', min_value=0, max_value=150, key='age_1') if age < 18: st.warning('Must be 18 or older') ``` 2. Default Values ```python # Provide sensible defaults st.text_input('Name', value='Guest User', key='name_2') st.slider('Rating', 1, 5, value=3, key='rating_1') ``` 3. Responsive Widgets ```python # React to widget changes if st.checkbox('Show advanced options', key='advanced_1'): st.number_input('Threshold', key='threshold_1') st.slider('Sensitivity', key='sensitivity_1') ``` 4. Form Submission ```python with st.form('my_form'): st.text_input('Username', key='form_user') st.text_input('Password', type='password', key='form_pass') submitted = st.form_submit_button('Login') ``` 5. File Handling ```python file = st.file_uploader('Upload CSV', key='file_2') if file is not None: # Handle file upload st.success('File uploaded!') ``` 6. Interactive Filters ```python col1, col2 = st.columns(2) with col1: category = st.selectbox('Category', ['A', 'B', 'C'], key='cat_1') with col2: subcategory = st.multiselect('Subcategory', ['X', 'Y', 'Z'], key='subcat_1') ``` **Tips for Widget Usage:** - Use clear, concise labels - Group related widgets together - Provide help text when needed - Use appropriate widget types - Handle all possible states - Validate inputs properly - Always use unique keys - Consider mobile responsiveness """ def _get_advanced_tips_content(self) -> str: """ Provides content for Advanced Tips section. Contains advanced usage and techniques. Returns: str: Markdown formatted advanced tips content """ return """ **Advanced Formatting:** ```python # Custom HTML st.markdown(''' Custom styled text ''', unsafe_allow_html=True) # Complex Markdown st.markdown(''' # Title ## Subtitle * Point 1 * Subpoint > Quote ''') ``` **Layout Combinations:** ```python col1, col2 = st.columns(2) with col1: st.header('Column 1') with col2: st.header('Column 2') ``` """ def get_text_elements(self) -> List[Tuple[str, str]]: """ Provides collection of text element examples with corresponding code. Defines basic text manipulation and display examples. Used for generating code examples and quick snippets. Returns: List[Tuple[str, str]]: List of (element name, code snippet) pairs """ return [ ("Title", "st.title('Main Title')"), ("Header", "st.header('Header')"), ("Subheader", "st.subheader('Subheader')"), ("Normal text", "st.write('Normal text')"), ("Markdown text", "st.markdown('**Bold** and *italic*')"), ("Colored text", "st.markdown(':blue[Blue text]')") ] def render_text_elements(self, col: st.delta_generator.DeltaGenerator) -> None: """ Renders text element examples in the specified column. Displays code snippets with live output for each text element. Creates interactive learning environment for text elements. Arguments: col: Streamlit column object for content rendering Returns: None """ with col: st.markdown("### 📝 Code Examples") for title, code in self.get_text_elements(): with st.container(border=True): st.markdown(f"**{title}**") st.code(code) st.markdown("Live output:") with st.container(border=True): exec(code) def get_input_elements(self) -> List[Tuple[str, str]]: """ Cross-validated collection of input widgets with unique keys """ return [ ("Text Input", """st.text_input('Enter your name', key='text_input_demo_1', placeholder='John Doe')"""), ("Text Area", """st.text_area('Enter long text', key='text_area_demo_1', height=100, placeholder='Write something...')"""), ("Number Input", """st.number_input('Enter a number', key='number_input_demo_1', min_value=0, max_value=100, value=50, step=5)"""), ("Slider", """st.slider('Select value', key='slider_demo_1', min_value=0, max_value=100, value=50, step=5)"""), ("Select Box", """st.selectbox('Choose an option', key='select_box_demo_1', options=['Option 1', 'Option 2', 'Option 3'], index=0)""") ] def render_input_elements(self, col: st.delta_generator.DeltaGenerator) -> None: """ Renders input examples with unique keys for both examples and live output """ with col: st.markdown("### 📝 Code Examples") for idx, (title, code) in enumerate(self.get_input_elements()): with st.container(border=True, key=f"demo_container_{idx}"): st.markdown(f"**{title}**") st.code(code) st.markdown("Live output:") with st.container(border=True, key=f"output_container_{idx}"): try: # Create runtime version with unique key runtime_code = code.replace('demo_1', f'runtime_{idx}') exec(runtime_code) except Exception as e: st.error(f"Error: {str(e)}") def render_help_section(self, col: st.delta_generator.DeltaGenerator) -> None: """ Renders comprehensive help content in the specified column. Provides educational content, best practices, and examples. Creates expandable sections for different learning topics. Arguments: col: Streamlit column object for content rendering Returns: None """ with col: st.markdown("### 📚 Learning Guide") # Basic Concepts Section with st.expander("🎯 Basic Concepts", expanded=True): st.markdown(self._get_basic_concepts_content()) # Best Practices Section with st.expander("💡 Best Practices"): st.markdown(self._get_best_practices_content()) # Examples Section with st.expander("🔍 Examples & Use Cases"): st.markdown(self._get_examples_content()) # Common Mistakes Section with st.expander("⚠️ Common Mistakes"): st.markdown(self._get_common_mistakes_content()) # Advanced Tips Section with st.expander("🚀 Advanced Tips"): st.markdown(self._get_advanced_tips_content()) def render_playground(self, col: st.delta_generator.DeltaGenerator, snippets: Dict[str, str]) -> None: """ Renders interactive coding playground with live execution. Arguments: col: Streamlit column object for rendering snippets: Dictionary of available code snippets """ with col: st.markdown("### 💻 Practice Playground") # Code input area code_input = st.text_area( "Try Streamlit commands:", key="playground_input", value=st.session_state.get('code_input', ''), height=200, placeholder="Example:\nst.title('My Title')" ) # Quick Snippets section st.markdown("#### Quick Snippets") # Split into two columns with better ratio for button alignment snippet_col, button_col = st.columns([4, 1]) with snippet_col: selected_snippet = st.selectbox( "Choose snippet:", list(snippets.keys()), label_visibility="collapsed" ) with button_col: if st.button("Add", type="primary", use_container_width=True): if 'code_input' not in st.session_state: st.session_state.code_input = snippets[selected_snippet] else: # Add new line only if there's existing code existing_code = st.session_state.code_input.strip() new_code = snippets[selected_snippet] st.session_state.code_input = f"{existing_code}\n{new_code}" if existing_code else new_code st.rerun() # Control buttons in equal columns col1, col2, col3 = st.columns(3) with col1: if st.button("▶️ Run", use_container_width=True): try: if code_input.strip(): exec(code_input) except Exception as e: st.error(f"Error: {str(e)}") with col2: if st.button("🔄 Reset", use_container_width=True): st.session_state.code_input = "" st.rerun() with col3: if st.button("💾 Copy", use_container_width=True): st.code(code_input) # Live output section st.markdown("#### 🎨 Live Output") with st.container(border=True): if code_input.strip(): try: exec(code_input) except Exception as e: st.error(f"Error: {str(e)}") # Tips section with st.expander("💡 Tips & Help"): st.markdown(""" **Quick Tips:** - Type or paste Streamlit commands - Use snippets for quick start - Click Run to see results - Reset to clear all code """) def render_widget_help(self, col: st.delta_generator.DeltaGenerator) -> None: """ Renders comprehensive widget help content """ with col: st.markdown("### 📚 Widget Guide") with st.expander("🎯 Basic Concepts", expanded=True): st.markdown(""" **Widget Types:** - Input widgets (text, numbers, dates) - Selection widgets (dropdown, checkbox, radio) - File widgets (uploaders, downloads) - Display widgets (progress, status) **Key Features:** - Real-time updates - State management - Input validation - Responsive layout - Form handling - Unique widget keys """) with st.expander("💡 Best Practices"): st.markdown(self._get_widgets_help_content()) with st.expander("🔍 Examples"): st.code(""" # Basic form example with st.form('contact'): name = st.text_input('Name', key='contact_name') email = st.text_input('Email', key='contact_email') message = st.text_area('Message', key='contact_message') submit = st.form_submit_button('Send') if submit: st.success('Message sent!') """) def get_topic_tips(self, topic: str) -> str: """ Provides topic-specific tips and guidance. Returns formatted markdown string with helpful information. Customizes content based on current tutorial topic. Arguments: topic: Current tutorial topic name Returns: str: Markdown formatted tips and help content """ tips = { "Basic Text Elements": """ **Quick Tips:** - Use markdown for formatting - Try different header levels - Combine text elements - Use colored text with :color[text] """, "Input Widgets": """ **Quick Tips:** - Use unique keys for widgets - Store widget values in variables - Add validation for inputs - Combine widgets for complex inputs """ } return tips.get(topic, "Tips coming soon!") def run(self) -> None: """ Main execution method for the Streamlit Tutorial application. Handles topic selection and content rendering. Manages overall application flow and state. """ with st.sidebar: st.title("Streamlit Tutorial") st.session_state.current_topic = st.radio( "Choose a Topic:", ["Basic Text Elements", "Input Widgets", "Layouts & Containers", "Data Display", "Charts & Plots", "Interactive Components"] ) if st.session_state.current_topic == "Basic Text Elements": cols = st.columns([1.2, 1, 1]) self.render_text_elements(cols[0]) self.render_help_section(cols[1]) self.render_playground(cols[2], dict(self.get_text_elements())) elif st.session_state.current_topic == "Input Widgets": cols = st.columns([1.2, 1, 1]) self.render_input_elements(cols[0]) self.render_help_section(cols[1]) self.render_playground(cols[2], dict(self.get_input_elements())) def main(): try: app = StreamlitTutorial() app.run() except Exception as e: st.error(f"Application Error: {str(e)}") st.write(f"Traceback: {traceback.format_exc()}") if __name__ == "__main__": main()