From 0328d2be55c801d01f728a9cd0ac9dfa796be6fc Mon Sep 17 00:00:00 2001 From: Fridemn <702625325@qq.com> Date: Mon, 27 Jul 2026 19:08:09 +0800 Subject: [PATCH 1/3] feat(markdown): add link safety controls and improve link styling --- .../src/components/content/Markdown.test.tsx | 8 ++++++ dashboard/src/components/content/content.scss | 26 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/dashboard/src/components/content/Markdown.test.tsx b/dashboard/src/components/content/Markdown.test.tsx index f884e145..113e3632 100644 --- a/dashboard/src/components/content/Markdown.test.tsx +++ b/dashboard/src/components/content/Markdown.test.tsx @@ -25,6 +25,14 @@ describe('Streamdown Markdown renderer', () => { expect(html).not.toContain('markdown-body--streaming'); }); + it('marks external links as link-safety controls', () => { + const html = renderToStaticMarkup(); + + expect(html).toContain('AstrBot'); + }); + it('defers rich controls while content is still streaming', () => { const html = renderToStaticMarkup(); diff --git a/dashboard/src/components/content/content.scss b/dashboard/src/components/content/content.scss index f82c308f..10382560 100644 --- a/dashboard/src/components/content/content.scss +++ b/dashboard/src/components/content/content.scss @@ -93,11 +93,35 @@ .markdown-body a, .markdown-body [data-streamdown='link'] { - color: var(--astrbot-text); + display: inline; + margin: 0; + padding: 0; + border: 0; + appearance: none; + background: transparent; + color: var(--astrbot-primary); + cursor: pointer; + font: inherit; + line-height: inherit; + text-align: inherit; + text-decoration: none; + vertical-align: baseline; +} + +.markdown-body a:hover, +.markdown-body [data-streamdown='link']:hover { + text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; } +.markdown-body a:focus-visible, +.markdown-body [data-streamdown='link']:focus-visible { + border-radius: 3px; + outline: 2px solid color-mix(in srgb, var(--astrbot-primary) 38%, transparent); + outline-offset: 2px; +} + .markdown-body [data-streamdown='strong'] { font-weight: 700; } From 8250ddec7a6157ea43f6fc0ed7f475980dcbcc53 Mon Sep 17 00:00:00 2001 From: Fridemn <702625325@qq.com> Date: Mon, 27 Jul 2026 19:21:06 +0800 Subject: [PATCH 2/3] feat(dashboard): add DisclosureButton component and update styles for disclosure controls --- .../src/components/ui/DisclosureButton.tsx | 51 ++++++++++++++++ .../src/components/ui/primitives.test.tsx | 27 +++++++++ .../src/i18n/locales/en-US/core/actions.json | 1 + .../src/i18n/locales/ru-RU/core/actions.json | 1 + .../src/i18n/locales/zh-CN/core/actions.json | 1 + .../src/routes/configuration/PlatformPage.tsx | 16 ++--- .../routes/extensions/ExtensionSections.tsx | 37 +++++++++--- .../src/styles/components/_primitives.scss | 59 +++++++++++++++++++ .../src/styles/features/_extensions.scss | 8 +-- dashboard/src/styles/features/_personas.scss | 3 +- dashboard/src/styles/features/_platforms.scss | 5 +- 11 files changed, 187 insertions(+), 22 deletions(-) create mode 100644 dashboard/src/components/ui/DisclosureButton.tsx diff --git a/dashboard/src/components/ui/DisclosureButton.tsx b/dashboard/src/components/ui/DisclosureButton.tsx new file mode 100644 index 00000000..2b77f2fa --- /dev/null +++ b/dashboard/src/components/ui/DisclosureButton.tsx @@ -0,0 +1,51 @@ +import { forwardRef, type ButtonHTMLAttributes } from 'react'; + +import { MdiIcon } from '@/components/icons/MdiIcon'; + +export type DisclosureButtonProps = Omit< + ButtonHTMLAttributes, + 'aria-expanded' | 'aria-label' | 'children' +> & { + collapseLabel: string; + compact?: boolean; + direction?: 'down' | 'right'; + expanded: boolean; + expandLabel: string; + label?: string; +}; + +export const DisclosureButton = forwardRef(function DisclosureButton( + { + className = '', + collapseLabel, + compact = false, + direction = 'down', + expanded, + expandLabel, + label = '', + title, + type = 'button', + ...props + }, + ref, +) { + const actionLabel = expanded ? collapseLabel : expandLabel; + const accessibleLabel = label ? `${actionLabel}: ${label}` : actionLabel; + + return ( + + ); +}); diff --git a/dashboard/src/components/ui/primitives.test.tsx b/dashboard/src/components/ui/primitives.test.tsx index 73e23e21..45c41e9f 100644 --- a/dashboard/src/components/ui/primitives.test.tsx +++ b/dashboard/src/components/ui/primitives.test.tsx @@ -5,6 +5,7 @@ import { describe, expect, it } from 'vitest'; import { Button } from './Button'; import { DataTable } from './DataTable'; +import { DisclosureButton } from './DisclosureButton'; import { DialogActions } from './DialogActions'; import { Pagination } from './Pagination'; import { SearchField } from './SearchField'; @@ -59,6 +60,32 @@ describe('shared UI primitives', () => { expect(markup).toContain('ui-status-chip--success'); }); + it('keeps disclosure controls centered and exposes their current state', () => { + const collapsed = renderToStaticMarkup( + , + ); + const expanded = renderToStaticMarkup( + , + ); + + expect(collapsed).toContain('aria-expanded="false"'); + expect(collapsed).toContain('aria-label="Expand: Config file"'); + expect(collapsed).toContain('ui-disclosure-button__icon'); + expect(expanded).toContain('aria-expanded="true"'); + expect(expanded).toContain('aria-label="Collapse: Tool details"'); + expect(expanded).toContain('ui-disclosure-button--compact'); + expect(expanded).toContain('ui-disclosure-button--tree'); + expect(expanded).toContain('mdi-chevron-right'); + expect(primitiveStyles).toContain(".ui-disclosure-button[aria-expanded='true']"); + }); + it('shares table selection, empty state and pagination structure', () => { const table = renderToStaticMarkup( - + /> {showConfigSection && ( -
+