Skip to content
Open
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
2 changes: 1 addition & 1 deletion zettel/screens/browse_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def _load_cards(self, filter_text: str = "") -> None:
cards = self.db.get_orphans()
title = "[bold red]ORPHANS[/] (No Connections)"
else:
cards = self.db.get_all_cards(limit=200)
cards = self.db.get_all_cards(order_by='zettel_id')
title = "[bold cyan]ZETTELKASTEN[/]"

self._all_cards = cards
Expand Down
44 changes: 23 additions & 21 deletions zettel/screens/tag_modal.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Tag Modal - Add/remove insight tags from a card."""

from typing import Callable, Optional
from typing import Callable

from textual.app import ComposeResult
from textual.screen import ModalScreen
from textual.widgets import Static, Input, Button, ListView, ListItem, Label
from textual.widgets import Static, Input, Button
from textual.containers import Vertical, Horizontal, ScrollableContainer
from textual.binding import Binding
from textual.reactive import reactive
Expand Down Expand Up @@ -51,7 +51,7 @@ def __init__(
def compose(self) -> ComposeResult:
"""Compose the tag modal."""
with Vertical(id="tag-container"):
yield Static(f"TAG CARD: {self.zettel_id}", id="tag-title")
yield Static("TAG CARD", id="tag-title")

# Current tags section
yield Static("Current tags:", id="tag-current-label")
Expand Down Expand Up @@ -122,19 +122,16 @@ def _load_suggestions(self, query: str) -> None:
def _render_suggestions(self) -> None:
"""Render the suggestions list."""
container = self.query_one("#tag-suggestions", Vertical)
container.remove_children()

# Build all content as a single update to avoid duplicate ID issues
lines = []

# Existing insights that match
for i, insight in enumerate(self._suggestions):
is_selected = (i == self.selected_index)
prefix = "→ " if is_selected else " "
style = "reverse" if is_selected else ""
item = Static(
f"{prefix}{insight['name']}",
id=f"suggestion-{i}",
classes=f"tag-suggestion {style}"
)
container.mount(item)
prefix = "[reverse]→ " if is_selected else " "
suffix = "[/]" if is_selected else ""
lines.append(f"{prefix}{insight['name']}{suffix}")

# "Create new" option if there's search text and no exact match
if self._search_text:
Expand All @@ -145,17 +142,17 @@ def _render_suggestions(self) -> None:
if not exact_match:
create_index = len(self._suggestions)
is_selected = (self.selected_index == create_index)
prefix = "→ " if is_selected else " "
style = "reverse" if is_selected else ""
create_item = Static(
f'{prefix}[green]+ Create "{self._search_text}"[/]',
id="suggestion-create",
classes=f"tag-suggestion tag-create {style}"
)
container.mount(create_item)
prefix = "[reverse]→ " if is_selected else " "
suffix = "[/]" if is_selected else ""
lines.append(f'{prefix}[green]+ Create "{self._search_text}"[/]{suffix}')

if not self._suggestions and not self._search_text:
container.mount(Static("[dim]No insights yet. Type to create one.[/]", classes="tag-empty"))
lines.append("[dim]No insights yet. Type to create one.[/]")

# Update the container with a single Static widget (no ID to avoid async removal race)
container.remove_children()
if lines:
container.mount(Static("\n".join(lines)))

def _get_max_index(self) -> int:
"""Get the maximum valid selection index."""
Expand All @@ -177,6 +174,11 @@ def on_input_changed(self, event: Input.Changed) -> None:
if event.input.id == "tag-input":
self._load_suggestions(event.value)

def on_input_submitted(self, event: Input.Submitted) -> None:
"""Handle Enter key in input - select current suggestion."""
if event.input.id == "tag-input":
self.action_select_suggestion()

def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle button presses."""
button_id = event.button.id
Expand Down
13 changes: 9 additions & 4 deletions zettel/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,12 @@ def get_paths(self, zettel_id: str, limit: int = 10) -> list[dict]:
conn.close()
return paths

def get_all_cards(self, limit: int = 100, order_by: str = 'created_at DESC') -> list[dict]:
def get_all_cards(self, limit: int = None, order_by: str = 'created_at DESC') -> list[dict]:
"""Get all cards with connection counts."""
conn = self.get_connection()
cursor = conn.cursor()

cursor.execute(f"""
query = f"""
SELECT
z.zettel_id,
z.note,
Expand All @@ -338,8 +338,13 @@ def get_all_cards(self, limit: int = 100, order_by: str = 'created_at DESC') ->
) as connection_count
FROM zettelkasten z
ORDER BY {order_by}
LIMIT ?
""", (limit,))
"""

if limit is not None:
query += " LIMIT ?"
cursor.execute(query, (limit,))
else:
cursor.execute(query)

cards = [dict(r) for r in cursor.fetchall()]
conn.close()
Expand Down