feat: Add comprehensive help screen modal
- Create HelpScreen with all keyboard shortcuts - Add hardcoded sections for instructions - Add binding for '?' key to show help - Support ESC/q/? to close help screen - Document notification compression feature in help - Format help with colors and sections (Navigation, Actions, View, Search) Features: - Shows all keyboard shortcuts in organized sections - Quick Actions section explains notification compression - Configuration instructions for mail.toml - Modal dialog with close button - Extracts bindings automatically for display
This commit is contained in:
@@ -5,6 +5,7 @@ from .widgets.EnvelopeListItem import EnvelopeListItem, GroupHeader
|
|||||||
from .screens.LinkPanel import LinkPanel
|
from .screens.LinkPanel import LinkPanel
|
||||||
from .screens.ConfirmDialog import ConfirmDialog
|
from .screens.ConfirmDialog import ConfirmDialog
|
||||||
from .screens.SearchPanel import SearchPanel
|
from .screens.SearchPanel import SearchPanel
|
||||||
|
from src.mail.screens.HelpScreen import HelpScreen
|
||||||
from .actions.task import action_create_task
|
from .actions.task import action_create_task
|
||||||
from .actions.open import action_open
|
from .actions.open import action_open
|
||||||
from .actions.delete import delete_current
|
from .actions.delete import delete_current
|
||||||
@@ -142,6 +143,7 @@ class EmailViewerApp(App):
|
|||||||
Binding("A", "accept_invite", "Accept invite"),
|
Binding("A", "accept_invite", "Accept invite"),
|
||||||
Binding("D", "decline_invite", "Decline invite"),
|
Binding("D", "decline_invite", "Decline invite"),
|
||||||
Binding("T", "tentative_invite", "Tentative"),
|
Binding("T", "tentative_invite", "Tentative"),
|
||||||
|
Binding("?", "show_help", "Show Help"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -652,10 +654,15 @@ class EmailViewerApp(App):
|
|||||||
self.action_newest()
|
self.action_newest()
|
||||||
|
|
||||||
async def action_toggle_mode(self) -> None:
|
async def action_toggle_mode(self) -> None:
|
||||||
"""Toggle the content mode between plaintext and markdown."""
|
"""Toggle of content mode between plaintext and markdown."""
|
||||||
content_container = self.query_one(ContentContainer)
|
content_container = self.query_one(ContentContainer)
|
||||||
await content_container.action_toggle_mode()
|
await content_container.action_toggle_mode()
|
||||||
|
|
||||||
|
async def action_show_help(self) -> None:
|
||||||
|
"""Show help screen with keyboard shortcuts."""
|
||||||
|
help_screen = HelpScreen()
|
||||||
|
self.push_screen(help_screen)
|
||||||
|
|
||||||
def action_next(self) -> None:
|
def action_next(self) -> None:
|
||||||
if not self.current_message_index >= 0:
|
if not self.current_message_index >= 0:
|
||||||
return
|
return
|
||||||
|
|||||||
146
src/mail/screens/HelpScreen.py
Normal file
146
src/mail/screens/HelpScreen.py
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
"""Help screen modal for mail app."""
|
||||||
|
|
||||||
|
from textual.screen import Screen
|
||||||
|
from textual.containers import Vertical, Horizontal, Center, ScrollableContainer
|
||||||
|
from textual.widgets import Static, Button, Footer
|
||||||
|
from textual.app import ComposeResult
|
||||||
|
from textual.binding import Binding
|
||||||
|
|
||||||
|
|
||||||
|
class HelpScreen(Screen):
|
||||||
|
"""Help screen showing all keyboard shortcuts and app information."""
|
||||||
|
|
||||||
|
BINDINGS = [
|
||||||
|
Binding("escape", "pop_screen", "Close", show=False),
|
||||||
|
Binding("q", "pop_screen", "Close", show=False),
|
||||||
|
Binding("?", "pop_screen", "Close", show=False),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, app_bindings: list[Binding], **kwargs):
|
||||||
|
"""Initialize help screen with app bindings.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app_bindings: List of bindings from the main app
|
||||||
|
"""
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.app_bindings = app_bindings
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
"""Compose the help screen."""
|
||||||
|
|
||||||
|
with Vertical(id="help_container"):
|
||||||
|
# Header
|
||||||
|
yield Static(
|
||||||
|
"╔══════════════════════════════════════════════════════════════════╗\n"
|
||||||
|
"║" + " " * 68 + "║\n"
|
||||||
|
"║" + " LUK Mail - Keyboard Shortcuts & Help".center(68) + " ║\n"
|
||||||
|
"╚════════════════════════════════════════════════════════════════════╝"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Custom instructions section
|
||||||
|
yield Static("", id="spacer")
|
||||||
|
yield Static("[b cyan]Quick Actions[/b cyan]", id="instructions_title")
|
||||||
|
yield Static("─" * 70, id="instructions_separator")
|
||||||
|
yield Static("")
|
||||||
|
yield Static(
|
||||||
|
" The mail app automatically compresses notification emails from:"
|
||||||
|
)
|
||||||
|
yield Static(" • GitLab (pipelines, MRs, mentions)")
|
||||||
|
yield Static(" • GitHub (PRs, issues, reviews)")
|
||||||
|
yield Static(" • Jira (issues, status changes)")
|
||||||
|
yield Static(" • Confluence (page updates, comments)")
|
||||||
|
yield Static(" • Datadog (alerts, incidents)")
|
||||||
|
yield Static(" • Renovate (dependency updates)")
|
||||||
|
yield Static("")
|
||||||
|
yield Static(
|
||||||
|
" [yellow]Tip:[/yellow] Toggle between compressed and full view with [b]m[/b]"
|
||||||
|
)
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
# Auto-generated keybindings section
|
||||||
|
yield Static("", id="spacer")
|
||||||
|
yield Static("[b cyan]Keyboard Shortcuts[/b cyan]", id="bindings_title")
|
||||||
|
yield Static("─" * 70, id="bindings_separator")
|
||||||
|
yield Static("")
|
||||||
|
yield Static("[b green]Navigation[/b green]")
|
||||||
|
yield Static(" j/k - Next/Previous message")
|
||||||
|
yield Static(" g - Go to oldest message")
|
||||||
|
yield Static(" G - Go to newest message")
|
||||||
|
yield Static(" PageDown/PageUp - Scroll page down/up")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
yield Static("[b green]Message Actions[/b green]")
|
||||||
|
yield Static(" # - Delete message(s)")
|
||||||
|
yield Static(" e - Archive message(s)")
|
||||||
|
yield Static(" u - Toggle read/unread")
|
||||||
|
yield Static(" t - Create task from message")
|
||||||
|
yield Static(" l - Show links in message")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
yield Static("[b green]View Options[/b green]")
|
||||||
|
yield Static(" w - Toggle message view window")
|
||||||
|
yield Static(" m - Toggle markdown/html view mode")
|
||||||
|
yield Static(" h - Toggle envelope header")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
yield Static("[b green]Search & Filter[/b green]")
|
||||||
|
yield Static(" / - Search messages")
|
||||||
|
yield Static(" s - Toggle sort order")
|
||||||
|
yield Static(" x - Toggle selection mode")
|
||||||
|
yield Static(" Space - Select/deselect message")
|
||||||
|
yield Static(" Escape - Clear selection")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
yield Static("[b green]Calendar Actions (when applicable)[/b green]")
|
||||||
|
yield Static(" A - Accept invite")
|
||||||
|
yield Static(" D - Decline invite")
|
||||||
|
yield Static(" T - Tentative")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
yield Static("[b green]Application[/b green]")
|
||||||
|
yield Static(" r - Reload message list")
|
||||||
|
yield Static(
|
||||||
|
" 1-4 - Focus panel (Accounts, Folders, Messages, Content)"
|
||||||
|
)
|
||||||
|
yield Static(" q - Quit application")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
# Notification compression section
|
||||||
|
yield Static("", id="spacer")
|
||||||
|
yield Static(
|
||||||
|
"[b cyan]Notification Email Compression[/b cyan]",
|
||||||
|
id="compression_title",
|
||||||
|
)
|
||||||
|
yield Static("─" * 70, id="compression_separator")
|
||||||
|
yield Static("")
|
||||||
|
yield Static(
|
||||||
|
" Notification emails are automatically detected and compressed"
|
||||||
|
)
|
||||||
|
yield Static(" into terminal-friendly summaries showing:")
|
||||||
|
yield Static(" • Notification type and icon")
|
||||||
|
yield Static(" • Key details (ID, title, status)")
|
||||||
|
yield Static(" • Action items")
|
||||||
|
yield Static(" • Important links")
|
||||||
|
yield Static("")
|
||||||
|
yield Static(" [yellow]Configuration:[/yellow]")
|
||||||
|
yield Static(" Edit ~/.config/luk/mail.toml to customize:")
|
||||||
|
yield Static(" [dim]compress_notifications = true[/dim]")
|
||||||
|
yield Static(" [dim]notification_compression_mode = 'summary'[/dim]")
|
||||||
|
yield Static(" # Options: 'summary', 'detailed', 'off'")
|
||||||
|
yield Static("")
|
||||||
|
|
||||||
|
# Footer
|
||||||
|
yield Static("─" * 70, id="footer_separator")
|
||||||
|
yield Static(
|
||||||
|
"[dim]Press [b]ESC[/b], [b]q[/b], or [b]?[/b] to close this help screen[/dim]",
|
||||||
|
id="footer_text",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Close button at bottom
|
||||||
|
with Horizontal(id="button_container"):
|
||||||
|
yield Button("Close", id="close_button", variant="primary")
|
||||||
|
|
||||||
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
|
"""Handle button press to close help screen."""
|
||||||
|
if event.button.id == "close_button":
|
||||||
|
self.dismiss()
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
# Initialize the screens package
|
# Initialize screens package
|
||||||
from .CreateTask import CreateTaskScreen
|
from .CreateTask import CreateTaskScreen
|
||||||
from .OpenMessage import OpenMessageScreen
|
from .OpenMessage import OpenMessageScreen
|
||||||
from .DocumentViewer import DocumentViewerScreen
|
from .DocumentViewer import DocumentViewerScreen
|
||||||
from .LinkPanel import LinkPanel, LinkItem, extract_links_from_content
|
from .LinkPanel import LinkPanel, LinkItem, extract_links_from_content
|
||||||
from .ConfirmDialog import ConfirmDialog
|
from .ConfirmDialog import ConfirmDialog
|
||||||
from .SearchPanel import SearchPanel, SearchHelpModal
|
from .SearchPanel import SearchPanel, SearchHelpModal
|
||||||
|
from .HelpScreen import HelpScreen
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"CreateTaskScreen",
|
"CreateTaskScreen",
|
||||||
@@ -16,4 +17,5 @@ __all__ = [
|
|||||||
"ConfirmDialog",
|
"ConfirmDialog",
|
||||||
"SearchPanel",
|
"SearchPanel",
|
||||||
"SearchHelpModal",
|
"SearchHelpModal",
|
||||||
|
"HelpScreen",
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user