Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/toad/native_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Native widgets declare their layout before their first stylesheet application."""

from typing import ClassVar

from textual.app import App
from textual.css.native import NativeDeclaration, NativeStyleResolver
from textual.widget import Widget


class NativeLayout(Widget):
"""The shared registration point for a widget's own layout declarations."""

def _post_register(self, app: App) -> None:
super()._post_register(app)
self.apply_native_layout()

def apply_native_layout(self) -> None:
"""A widget without additional layout keeps its inherited native defaults."""


class NativeTheme(Widget):
"""Native property declarations follow the app's current theme value owner."""

native_theme: ClassVar[tuple[NativeDeclaration, ...]] = ()

def native_declarations(self) -> tuple[NativeDeclaration, ...]:
"""Providers may extend this cooperatively when their declarations overlap."""
return self.native_theme

def apply_native_styles(self, resolver: NativeStyleResolver) -> None:
super().apply_native_styles(resolver)
self.styles.merge(resolver.native_styles(*self.native_declarations()))
76 changes: 66 additions & 10 deletions src/toad/screens/session_resume_modal.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from datetime import UTC, datetime
from agent_comms.nominal.field_codec import RecordedTimestamp

from textual import containers, getters, on, widgets
from textual.app import ComposeResult
from textual.css.native import Keyword, NativeDeclaration, Percent, TextVariable, Variable
from textual.css.styles import Styles
from textual.widgets._markdown import MarkdownH1
from ui_theme.scheme import PrimaryColour, WarningColour

from toad.native_layout import NativeLayout, NativeTheme
from toad.screens.modal import DismissibleScreen

from toad.db import DB, Session
Expand All @@ -14,23 +20,73 @@
"""


class SessionResumeModal(DismissibleScreen[Session]):
class ResumeHeading(NativeLayout, MarkdownH1):
def apply_native_layout(self) -> None:
self.styles.margin = (1, 0)


class ResumeHelp(widgets.Markdown):
BLOCKS = widgets.Markdown.BLOCKS | {f"h{ResumeHeading.LEVEL}": ResumeHeading}


class ResumeWarning(NativeTheme, NativeLayout, widgets.Static):
native_theme = (
NativeDeclaration.of(Styles.border, Keyword("round"), Variable(WarningColour.name)),
NativeDeclaration.of(Styles.color, TextVariable(WarningColour.name)),
)

def apply_native_layout(self) -> None:
self.styles.padding = (0, 1)
self.styles.margin = (0, 0, 1, 1)


class ResumeFrame(NativeTheme, NativeLayout, containers.VerticalGroup):
native_theme = (
NativeDeclaration.of(Styles.border, Keyword("thick"), Variable(PrimaryColour.name), Percent(20)),
)

def apply_native_layout(self) -> None:
self.styles.margin = (2, 4, 1, 4)
self.styles.padding = (0, 1, 0, 0)
self.styles.max_width = 100
self.styles.height = "auto"


class ResumeTableContainer(NativeLayout, containers.Center):
def apply_native_layout(self) -> None:
self.styles.height = "auto"
self.styles.padding = (0, 0, 0, 1)


class ResumeTable(NativeLayout, widgets.DataTable):
def apply_native_layout(self) -> None:
self.styles.width = "1fr"
self.styles.height = 12


class ResumeButtons(NativeLayout, containers.HorizontalGroup):
def apply_native_layout(self) -> None:
self.styles.margin = (1, 0, 0, 0)
self.styles.align = ("right", "top")


class SessionResumeModal(NativeLayout, DismissibleScreen[Session]):
"""Dialog to select a session to resume."""

CSS_PATH = "session_resume_modal.tcss"
session_table = getters.query_one("#sessions", ResumeTable)

session_table = getters.query_one("#sessions", widgets.DataTable)
def apply_native_layout(self) -> None:
self.styles.align = ("center", "middle")

def compose(self) -> ComposeResult:
with containers.VerticalGroup(id="container"):
yield widgets.Markdown(HELP)
yield widgets.Static(
with ResumeFrame(id="container"):
yield ResumeHelp(HELP)
yield ResumeWarning(
"⚠ Not all ACP agents currently support resume",
classes="warning",
)
with containers.Center(id="table-container"):
yield widgets.DataTable(id="sessions", cursor_type="row")
with containers.HorizontalGroup(id="buttons"):
with ResumeTableContainer(id="table-container"):
yield ResumeTable(id="sessions", cursor_type="row")
with ResumeButtons(id="buttons"):
yield widgets.Button(
"Resume", id="resume", variant="primary", disabled=True
)
Expand Down
35 changes: 0 additions & 35 deletions src/toad/screens/session_resume_modal.tcss

This file was deleted.

Loading