This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-23934 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 4bf8ac86477279f3cb55dd58a4dc5919f4940e63 Author: Claus Ibsen <[email protected]> AuthorDate: Wed Jul 8 15:03:29 2026 +0200 CAMEL-23934: Theme-aware markdown styles, metrics panel, and tab key shortcuts - Add Theme.markdownStyles() for theme-aware MarkdownView heading/code/link colors and apply to all 5 MarkdownView usages (Help, AI, CVE, Endpoints, Doc) - Wrap MetricsTab empty state in bordered panel for visual consistency - Style tab bar key shortcuts (1-9, 0) with Theme.hintKey() so they stand out on light theme — primaryTabHeader now returns styled Span[] instead of String - Use Theme.hintKey() for More dropdown mnemonic keys Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../apache/camel/dsl/jbang/core/commands/tui/AiPanel.java | 1 + .../camel/dsl/jbang/core/commands/tui/CamelMonitor.java | 2 +- .../camel/dsl/jbang/core/commands/tui/CveAuditTab.java | 1 + .../camel/dsl/jbang/core/commands/tui/DocViewerPopup.java | 1 + .../camel/dsl/jbang/core/commands/tui/EndpointsTab.java | 3 +++ .../camel/dsl/jbang/core/commands/tui/HelpOverlay.java | 1 + .../camel/dsl/jbang/core/commands/tui/MetricsTab.java | 12 +++++++++--- .../camel/dsl/jbang/core/commands/tui/PopupManager.java | 2 +- .../org/apache/camel/dsl/jbang/core/commands/tui/Theme.java | 13 +++++++++++++ .../apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java | 8 ++++++-- .../camel/dsl/jbang/core/commands/tui/TabBarRenderTest.java | 10 ++++++---- 11 files changed, 43 insertions(+), 11 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java index ca82ea8274a5..6f24b8b1df65 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java @@ -585,6 +585,7 @@ class AiPanel { MarkdownView view = MarkdownView.builder() .source(source) .scroll(scroll) + .styles(Theme.markdownStyles()) .build(); frame.renderWidget(view, contentArea); diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java index eb883ae17d27..37114e80abfb 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java @@ -1263,7 +1263,7 @@ public class CamelMonitor extends CamelCommand { // Infra mode: only Overview and Log tabs Line[] labels = { Line.from(TuiIcons.primaryTabHeader(TuiIcons.TAB_OVERVIEW, "1", "Overview")), - Line.from(TuiIcons.primaryTabHeader(TuiIcons.TAB_LOG, "2", "Log")), + Line.from(TuiIcons.primaryTabHeader(TuiIcons.TAB_LOG, "2", "Log")) }; // Map real tab index to infra tab index for highlight diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CveAuditTab.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CveAuditTab.java index 5da22a93da9c..201bbaac1b4d 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CveAuditTab.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CveAuditTab.java @@ -307,6 +307,7 @@ class CveAuditTab extends AbstractTableTab { .source(md.toString()) .scroll(detailScroll) .block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL).title(title).build()) + .styles(Theme.markdownStyles()) .build(), area); } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java index ba52a1763926..c0db7d7a22dc 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java @@ -433,6 +433,7 @@ class DocViewerPopup { .source(docContent) .scroll(docScroll) .block(block) + .styles(Theme.markdownStyles()) .build(); frame.renderWidget(view, popup); } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java index 63f8125da84c..866ce7fff829 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java @@ -699,6 +699,7 @@ class EndpointsTab extends AbstractTableTab { .source("*Select an endpoint*") .block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL) .title(" Endpoint Detail ").build()) + .styles(Theme.markdownStyles()) .build(), area); return; @@ -713,6 +714,7 @@ class EndpointsTab extends AbstractTableTab { .source("*No endpoint URI*") .block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL) .title(" Endpoint Detail ").build()) + .styles(Theme.markdownStyles()) .build(), area); return; @@ -812,6 +814,7 @@ class EndpointsTab extends AbstractTableTab { .scroll(detailScroll) .block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL) .title(title).build()) + .styles(Theme.markdownStyles()) .build(), area); } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java index fa96d14819e8..2e1dcafaf377 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java @@ -103,6 +103,7 @@ class HelpOverlay { .source(markdown) .scroll(scroll) .block(block) + .styles(Theme.markdownStyles()) .build(); frame.renderWidget(view, popup); } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java index dd5f8ddfc9e3..580f1c3b93bd 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java @@ -227,9 +227,15 @@ class MetricsTab extends AbstractTableTab { @Override protected void renderContent(Frame frame, Rect area, IntegrationInfo info) { if (info.meters.isEmpty()) { - Paragraph p = Paragraph.from(Line.from( - Span.styled("No metrics available. Run with --observe to enable micrometer.", LABEL))); - frame.renderWidget(p, area); + frame.renderWidget( + Paragraph.builder() + .text(Text.from(Line.from( + Span.styled(" No metrics available. Run with --observe to enable micrometer.", + LABEL)))) + .block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL) + .title(" Metrics ").build()) + .build(), + area); return; } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java index c65df93f072e..8fd96eab495a 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java @@ -409,7 +409,7 @@ class PopupManager { frame.renderWidget(Clear.INSTANCE, popup); - Style keyStyle = Theme.label().bold(); + Style keyStyle = Theme.hintKey(); ListItem[] items = morePopupItems(keyStyle); ListWidget list = ListWidget.builder() .items(items) diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java index 08fbe9d892a9..2952d7b3c31c 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java @@ -244,6 +244,19 @@ public final class Theme { return style("search-match", FALLBACK_SEARCH_MATCH); } + /** Theme-aware markdown styles for MarkdownView headings and other elements. */ + public static dev.tamboui.markdown.MarkdownStyles markdownStyles() { + return dev.tamboui.markdown.MarkdownStyles.builder() + .heading(1, label().bold()) + .heading(2, label().bold()) + .heading(3, label().bold()) + .inlineCode(Style.EMPTY.fg(accent())) + .codeBlock(muted()) + .listMarker(Style.EMPTY.fg(accent())) + .link(Style.EMPTY.fg(accent()).underlined()) + .build(); + } + /** Diagram box-drawing border color. */ public static synchronized Color diagramBorder() { return color("diagram-border", FALLBACK_DIAGRAM_BORDER); diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java index 9d524eef2624..c719a4221e7e 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java @@ -172,8 +172,12 @@ final class TuiIcons { * Primary tab bar label of the form {@code "<icon> <key> <name>"} with two spaces between the emoji and the key * digit so the two do not visually collide. Rendered without outer padding (compact) for every tab. */ - static String primaryTabHeader(String icon, String key, String name) { - return icon + " " + key + " " + name; + static dev.tamboui.text.Span[] primaryTabHeader(String icon, String key, String name) { + return new dev.tamboui.text.Span[] { + dev.tamboui.text.Span.raw(icon + " "), + dev.tamboui.text.Span.styled(key, Theme.hintKey()), + dev.tamboui.text.Span.raw(" " + name) + }; } /** Removes the {@value #MNEMONIC_MARKER} mnemonic marker from a label for display. */ diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabBarRenderTest.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabBarRenderTest.java index 7fa84d60afac..9f149007bae8 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabBarRenderTest.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabBarRenderTest.java @@ -35,7 +35,9 @@ class TabBarRenderTest { void primaryTabHeadersStartWithIconAndTwoSpaces() { String[] names = { "Overview", "Log", "Diagram", "Route", "Endpoint", "HTTP", "Health", "Inspect", "Errors" }; for (int i = 0; i < names.length; i++) { - String header = TuiIcons.primaryTabHeader(TuiIcons.PRIMARY_TAB_ICONS.get(i), String.valueOf(i + 1), names[i]); + String header + = Line.from(TuiIcons.primaryTabHeader(TuiIcons.PRIMARY_TAB_ICONS.get(i), String.valueOf(i + 1), names[i])) + .rawContent(); assertTrue(header.startsWith(TuiIcons.PRIMARY_TAB_ICONS.get(i) + " " + (i + 1)), "Tab header should be '<icon> <key> <name>': " + header); } @@ -43,7 +45,7 @@ class TabBarRenderTest { @Test void moreTabHeaderIncludesIconAndChevron() { - String header = TuiIcons.primaryTabHeader(TuiIcons.TAB_MORE, "0", TuiIcons.moreTabLabel()); + String header = Line.from(TuiIcons.primaryTabHeader(TuiIcons.TAB_MORE, "0", TuiIcons.moreTabLabel())).rawContent(); assertTrue(header.startsWith(TuiIcons.TAB_MORE)); assertTrue(header.contains(TuiIcons.MORE_CHEVRON)); } @@ -51,8 +53,8 @@ class TabBarRenderTest { @Test void routeAndTopLabelsHaveEqualWidth() { // toggling Top mode must not shift the tab bar - int route = CharWidth.of(TuiIcons.primaryTabHeader(TuiIcons.TAB_ROUTES, "4", "Route")); - int top = CharWidth.of(TuiIcons.primaryTabHeader(TuiIcons.TAB_ROUTES, "4", " Top ")); + int route = Line.from(TuiIcons.primaryTabHeader(TuiIcons.TAB_ROUTES, "4", "Route")).width(); + int top = Line.from(TuiIcons.primaryTabHeader(TuiIcons.TAB_ROUTES, "4", " Top ")).width(); assertEquals(route, top, "Route and Top tab cells must be the same width"); }
