feat(web): implement responsive modal pattern for mobile-friendly NPC chat
- Add hybrid modal/page navigation based on screen size (1024px breakpoint) - Desktop (>1024px): Uses modal overlays for quick interactions - Mobile (≤1024px): Navigates to dedicated full pages for better UX - Extract shared NPC chat content into reusable partial template - Add responsive navigation JavaScript (responsive-modals.js) - Create dedicated NPC chat page route with back button navigation - Add mobile-optimized CSS with sticky header and chat input - Fix HTMX indicator errors by using htmx-indicator class pattern - Document responsive modal pattern for future features Addresses mobile UX issues: cramped space, nested scrolling, keyboard conflicts, and lack of native back button support in modals. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -690,10 +690,66 @@ def do_travel(session_id: str):
|
||||
return f'<div class="error">Travel failed: {e}</div>', 500
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/npc/<npc_id>')
|
||||
@require_auth
|
||||
def npc_chat_page(session_id: str, npc_id: str):
|
||||
"""
|
||||
Dedicated NPC chat page (mobile-friendly full page view).
|
||||
Used on mobile devices for better UX.
|
||||
"""
|
||||
client = get_api_client()
|
||||
|
||||
try:
|
||||
# Get session to find character
|
||||
session_response = client.get(f'/api/v1/sessions/{session_id}')
|
||||
session_data = session_response.get('result', {})
|
||||
character_id = session_data.get('character_id')
|
||||
|
||||
# Get NPC details with relationship info
|
||||
npc_response = client.get(f'/api/v1/npcs/{npc_id}?character_id={character_id}')
|
||||
npc_data = npc_response.get('result', {})
|
||||
|
||||
npc = {
|
||||
'npc_id': npc_data.get('npc_id'),
|
||||
'name': npc_data.get('name'),
|
||||
'role': npc_data.get('role'),
|
||||
'appearance': npc_data.get('appearance', {}).get('brief', ''),
|
||||
'tags': npc_data.get('tags', []),
|
||||
'image_url': npc_data.get('image_url')
|
||||
}
|
||||
|
||||
# Get relationship info
|
||||
interaction_summary = npc_data.get('interaction_summary', {})
|
||||
relationship_level = interaction_summary.get('relationship_level', 50)
|
||||
interaction_count = interaction_summary.get('interaction_count', 0)
|
||||
|
||||
# Conversation history would come from character's npc_interactions
|
||||
# For now, we'll leave it empty - the API returns it in dialogue responses
|
||||
conversation_history = []
|
||||
|
||||
return render_template(
|
||||
'game/npc_chat_page.html',
|
||||
session_id=session_id,
|
||||
npc=npc,
|
||||
conversation_history=conversation_history,
|
||||
relationship_level=relationship_level,
|
||||
interaction_count=interaction_count
|
||||
)
|
||||
|
||||
except APINotFoundError:
|
||||
return render_template('errors/404.html', message="NPC not found"), 404
|
||||
except APIError as e:
|
||||
logger.error("failed_to_load_npc_chat_page", session_id=session_id, npc_id=npc_id, error=str(e))
|
||||
return render_template('errors/500.html', message=f"Failed to load NPC: {e}"), 500
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/npc/<npc_id>/chat')
|
||||
@require_auth
|
||||
def npc_chat_modal(session_id: str, npc_id: str):
|
||||
"""Get NPC chat modal with conversation history."""
|
||||
"""
|
||||
Get NPC chat modal with conversation history.
|
||||
Used on desktop for modal overlay experience.
|
||||
"""
|
||||
client = get_api_client()
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user