# Streamlit Patterns

## Session State Initialization

Always initialize session state at the start of the main function:

```python
# app.py
import streamlit as st

def main():
    # Initialize all session state variables
    if "session_id" not in st.session_state:
        st.session_state.session_id = None
    if "current_motion_index" not in st.session_state:
        st.session_state.current_motion_index = 0
    if "motions" not in st.session_state:
        st.session_state.motions = []
    if "show_results" not in st.session_state:
        st.session_state.show_results = False
    
    # Rest of app...
```

## Page Configuration

Set page config at the top of each page file:

```python
# pages/1_Stemwijzer.py
import streamlit as st

st.set_page_config(
    page_title="Stemwijzer",
    page_icon="🗳️",
    layout="centered",
)

from explorer import build_mp_quiz_tab
build_mp_quiz_tab("data/motions.db")
```

## Thin Page Wrapper Pattern

Pages delegate to shared functions in main modules:

```python
# pages/2_Explorer.py
import streamlit as st

st.set_page_config(
    page_title="Explorer",
    page_icon="🔭",
    layout="wide",
)

from explorer import build_explorer_tab
build_explorer_tab()
```

```python
# explorer.py
def build_explorer_tab():
    st.header("🔭 Politiek Explorer")
    
    tab1, tab2, tab3 = st.tabs([
        "Compass", 
        "Trajectories", 
        "Zoeken"
    ])
    
    with tab1:
        render_compass()
    with tab2:
        render_trajectories()
    with tab3:
        render_search()
```

## Sidebar Pattern

Use sidebar for configuration and navigation:

```python
# app.py
def main():
    with st.sidebar:
        st.header("Instellingen")
        
        motion_count = st.slider(
            "Aantal moties",
            min_value=5,
            max_value=25,
            value=10,
        )
        
        policy_area = st.selectbox("Beleidsgebied", config.POLICY_AREAS)
        
        if st.button("Start Nieuwe Sessie"):
            start_new_session(motion_count, policy_area)
```

## Callback Pattern for State Updates

Use callbacks to handle user interactions:

```python
def on_motion_vote(motion_id: int, vote: str):
    """Callback when user votes on a motion."""
    st.session_state.user_votes[motion_id] = vote
    
    # Move to next motion
    if st.session_state.current_motion_index < len(st.session_state.motions) - 1:
        st.session_state.current_motion_index += 1
    else:
        st.session_state.show_results = True
    
    st.rerun()

# In UI
col1, col2, col3 = st.columns(3)
with col1:
    st.button("👍 Voor", on_click=on_motion_vote, args=(motion_id, "Voor"))
with col2:
    st.button("👎 Tegen", on_click=on_motion_vote, args=(motion_id, "Tegen"))
with col3:
    st.button("❓ Onthouden", on_click=on_motion_vote, args=(motion_id, "Onthouden"))
```

## Container Pattern for Dynamic Content

Use containers for dynamic rendering:

```python
def show_motion_interface():
    if not st.session_state.motions:
        st.warning("Geen moties geladen")
        return
    
    current_idx = st.session_state.current_motion_index
    motion = st.session_state.motions[current_idx]
    
    with st.container():
        st.subheader(f"Motie {current_idx + 1} van {len(st.session_state.motions)}")
        st.markdown(f"**{motion['title']}**")
        st.caption(f"📅 {motion['date']} | 🏷️ {motion['policy_area']}")
        
        if motion.get("layman_explanation"):
            st.info(motion["layman_explanation"])
        
        # Voting buttons...
```

## Expander Pattern for Details

Use expanders for collapsible content:

```python
with st.expander("Meer details"):
    st.markdown(f"**Beschrijving:** {motion.get('description', 'N/A')}")
    
    if motion.get("voting_results"):
        results = json.loads(motion["voting_results"])
        st.json(results)
```

## Form Pattern for Batch Updates

Use forms for multiple related inputs:

```python
with st.form("session_settings"):
    st.subheader("Sessie Instellingen")
    
    col1, col2 = st.columns(2)
    with col1:
        count = st.number_input("Aantal moties", min_value=5, max_value=25)
    with col2:
        area = st.selectbox("Beleidsgebied", config.POLICY_AREAS)
    
    submitted = st.form_submit_button("Start Sessie")
    if submitted:
        start_session(count, area)
```

## Caching Pattern

Cache expensive computations:

```python
@st.cache_data(ttl=3600)  # Cache for 1 hour
def load_party_positions(window_id: str) -> Dict:
    """Load party positions from database."""
    return db.get_party_positions(window_id)

@st.cache_resource
def init_database():
    """Initialize database connection."""
    return MotionDatabase(config.DATABASE_PATH)
```

## Home Page Pattern

Landing page with navigation:

```python
# Home.py
import streamlit as st

st.set_page_config(
    page_title="Motief: de stematlas",
    page_icon="🗺️",
    layout="centered",
)

def main():
    st.title("🗺️ Motief: de stematlas")
    st.markdown("**Motief** brengt de Nederlandse Tweede Kamer in kaart...")
    
    col1, col2 = st.columns(2)
    with col1:
        st.page_link("pages/1_Stemwijzer.py", label="Open Stemwijzer", icon="🗳️")
    with col2:
        st.page_link("pages/2_Explorer.py", label="Open Explorer", icon="🔭")
```
