1818from IPython .display import display , HTML , Markdown
1919from plotly .offline import get_plotlyjs
2020
21+ DEFAULT_SUBTITLE_TOGGLE_LABEL : str = "See more"
22+
2123# Simple HTML template for rendering a card with a title, subtitle, and body with
2224# scrollable overflow. Subtitles are rendered in a <div> with max-height overflow
2325# so that any HTML content (tables, lists, etc.) is valid and clipped correctly
5456 display: none;
5557}}
5658</style>
57- <div class="card">
59+ <div class="card" id="{card_id}" >
5860 <div class="card-header">
5961 <b>{title_str}</b>
6062 <div class="card-subtitle">{subtitle_str}</div>
61- <button class="card-subtitle-toggle">See more </button>
63+ <button class="card-subtitle-toggle">{toggle_text} </button>
6264 </div>
6365 <div class="card-body">
6466 {body_html}
6567 </div>
6668</div>
6769<script>
6870(function() {{
69- var card = document.currentScript.previousElementSibling;
71+ var card = document.getElementById('{card_id}');
72+ if (!card) return;
7073 var subtitle = card.querySelector('.card-subtitle');
7174 var toggle = card.querySelector('.card-subtitle-toggle');
7275 if (subtitle && toggle) {{
76+ var originalText = toggle.textContent;
7377 requestAnimationFrame(function() {{
7478 if (subtitle.scrollHeight > subtitle.clientHeight
7579 || subtitle.scrollWidth > subtitle.clientWidth) {{
8185 subtitle.style.maxHeight = '1.4em';
8286 subtitle.style.whiteSpace = 'nowrap';
8387 subtitle.style.textOverflow = 'ellipsis';
84- toggle.textContent = 'See more' ;
88+ toggle.textContent = originalText ;
8589 }} else {{
8690 subtitle.style.maxHeight = 'none';
8791 subtitle.style.whiteSpace = 'normal';
@@ -154,6 +158,7 @@ class AnalysisCardBase(SortableBase, ABC):
154158
155159 title : str
156160 subtitle : str
161+ subtitle_toggle_label : str
157162
158163 _timestamp : datetime
159164
@@ -163,6 +168,7 @@ def __init__(
163168 title : str ,
164169 subtitle : str ,
165170 timestamp : datetime | None = None ,
171+ subtitle_toggle_label : str = DEFAULT_SUBTITLE_TOGGLE_LABEL ,
166172 ) -> None :
167173 """
168174 Args:
@@ -175,10 +181,16 @@ def __init__(
175181 timestamp: The time at which the Analysis was computed. This can be
176182 especially useful when querying the database for the most recently
177183 produced artifacts.
184+ subtitle_toggle_label: Custom label for the subtitle
185+ expansion toggle. When non-empty, replaces the default
186+ "See more" text. An empty string is converted to the
187+ default. Persisted to storage and used by both notebook
188+ and web UI rendering.
178189 """
179190 self .name = name
180191 self .title = title
181192 self .subtitle = subtitle
193+ self .subtitle_toggle_label = subtitle_toggle_label
182194 self ._timestamp = timestamp if timestamp is not None else datetime .now ()
183195
184196 @abstractmethod
@@ -258,10 +270,16 @@ def _repr_html_(self) -> str:
258270 return plotlyjs_script + self ._to_html (depth = 0 )
259271
260272 def _to_html (self , depth : int ) -> str :
273+ toggle_text = self .subtitle_toggle_label or DEFAULT_SUBTITLE_TOGGLE_LABEL
274+ # Use id(self) so each card gets a unique HTML element ID even when
275+ # multiple cards share the same name.
276+ card_id = f"ax-card-{ id (self )} "
261277 return html_card_template .format (
278+ card_id = card_id ,
262279 title_str = self .title ,
263280 subtitle_str = self .subtitle ,
264281 body_html = self ._body_html (depth = depth ),
282+ toggle_text = toggle_text ,
265283 )
266284
267285
@@ -282,6 +300,7 @@ def __init__(
282300 subtitle : str | None ,
283301 children : Sequence [AnalysisCardBase ],
284302 timestamp : datetime | None = None ,
303+ subtitle_toggle_label : str = DEFAULT_SUBTITLE_TOGGLE_LABEL ,
285304 ) -> None :
286305 """
287306 Args:
@@ -294,12 +313,16 @@ def __init__(
294313 timestamp: The time at which the Analysis was computed. This can be
295314 especially useful when querying the database for the most recently
296315 produced artifacts.
316+ subtitle_toggle_label: Custom label for the subtitle expansion
317+ toggle. When non-empty, replaces the default "See more" text.
318+ An empty string is converted to the default.
297319 """
298320 super ().__init__ (
299321 name = name ,
300322 title = title ,
301323 subtitle = subtitle if subtitle is not None else "" ,
302324 timestamp = timestamp ,
325+ subtitle_toggle_label = subtitle_toggle_label ,
303326 )
304327
305328 self .children = [
@@ -404,6 +427,7 @@ def __init__(
404427 df : pd .DataFrame ,
405428 blob : str ,
406429 timestamp : datetime | None = None ,
430+ subtitle_toggle_label : str = DEFAULT_SUBTITLE_TOGGLE_LABEL ,
407431 ) -> None :
408432 """
409433 Args:
@@ -417,12 +441,16 @@ def __init__(
417441 timestamp: The time at which the Analysis was computed. This can be
418442 especially useful when querying the database for the most recently
419443 produced artifacts.
444+ subtitle_toggle_label: Custom label for the subtitle expansion
445+ toggle. When non-empty, replaces the default "See more" text.
446+ An empty string is converted to the default.
420447 """
421448 super ().__init__ (
422449 name = name ,
423450 title = title ,
424451 subtitle = subtitle ,
425452 timestamp = timestamp ,
453+ subtitle_toggle_label = subtitle_toggle_label ,
426454 )
427455
428456 self .df = df
0 commit comments