File size: 3,199 Bytes
fec7628
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# edit_history.py
import difflib
from datetime import datetime
import streamlit as st


def init_edit_history():
    """Ensure edit history list exists in session_state."""
    if "edit_history" not in st.session_state:
        st.session_state.edit_history = []


def add_edit(old_text: str, new_text: str, source: str | None = None):
    """
    Append an edit event to history.

    - old_text: text before edit
    - new_text: text after edit
    - source: where this edit came from (e.g., "In-place Chat", "System")
    """
    init_edit_history()
    st.session_state.edit_history.append(
        {
            "old": old_text,
            "new": new_text,
            "source": source,
            "ts": datetime.now().strftime("%H:%M:%S"),
        }
    )


def _render_diff_html(old: str, new: str) -> str:
    """
    Return HTML for a git-style diff:
    - removed tokens: red, strikethrough
    - added tokens: green
    - unchanged: normal
    """
    # word-level diff
    diff = difflib.ndiff(old.split(), new.split())
    parts: list[str] = []

    for token in diff:
        code = token[:2]  # "+ ", "- ", or "  "
        word = token[2:]

        if code == "+ ":
            # Added text in green
            parts.append(
                f"<span style='color:#22c55e;'>{word}</span>"
            )
        elif code == "- ":
            # Removed text in red with strikethrough
            parts.append(
                f"<span style='color:#ef4444;text-decoration:line-through;'>{word}</span>"
            )
        else:
            parts.append(word)

    return " ".join(parts)


def render_edit_history_sidebar(max_items: int = 20):
    """
    Render the edit history inside the sidebar.

    Call this inside a sidebar container.
    """
    init_edit_history()

    with st.expander("Edit history", expanded=True):
        history = st.session_state.edit_history

        if not history:
            st.caption("No edits yet. Edits will appear here.")
            return

        # Show most recent first
        for idx, item in enumerate(reversed(history[-max_items:]), start=1):
            header_html = "<div style='margin-bottom:0.15rem;'>"

            # Title + meta info
            meta_bits = []
            if "ts" in item:
                meta_bits.append(item["ts"])
            if item.get("source"):
                meta_bits.append(item["source"])

            meta_html = " · ".join(meta_bits)

            header_html += f"<strong>Edit {len(history) - idx + 1}</strong>"
            if meta_html:
                header_html += (
                    f" <span style='font-size:0.75rem;color:#9ca3af;'>"
                    f"{meta_html}</span>"
                )
            header_html += "</div>"

            st.markdown(header_html, unsafe_allow_html=True)

            diff_html = _render_diff_html(item["old"], item["new"])
            st.markdown(
                f"<div style='font-size:0.85rem;'>{diff_html}</div>",
                unsafe_allow_html=True,
            )

            st.markdown(
                "<hr style='margin:0.35rem 0;border:none;border-top:1px solid #e5e7eb;'/>",
                unsafe_allow_html=True,
            )