This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch feat-granular-theming in repository https://gitbox.apache.org/repos/asf/superset.git
commit 9e5233eda250071a27e339985000ef34c2d42acb Author: Evan Rusackas <[email protected]> AuthorDate: Mon Dec 15 16:52:20 2025 -0800 feat(dashboard): integrate ComponentHeaderControls into Markdown Replace the old Markdown component UI controls with the new standardized ComponentHeaderControls menu: Changes: - Add ComponentHeaderControls to Markdown component (top-right position) - Remove MarkdownModeDropdown from WithPopoverMenu - Remove HoverMenu with DeleteComponentButton - Add MarkdownControlsWrapper for positioning (shows on hover) New menu includes: - Edit/Preview toggle (replaces MarkdownModeDropdown) - Apply theme (placeholder for theme selector modal) - Delete (replaces DeleteComponentButton) This brings Markdown in line with the chart component menu pattern, providing a consistent UI across all dashboard components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> --- docs/GRANULAR_THEMING_PLAN.md | 18 +++- .../gridComponents/Markdown/Markdown.jsx | 100 ++++++++++++++++++--- 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/docs/GRANULAR_THEMING_PLAN.md b/docs/GRANULAR_THEMING_PLAN.md index 47b0d5e09c9..49c99546203 100644 --- a/docs/GRANULAR_THEMING_PLAN.md +++ b/docs/GRANULAR_THEMING_PLAN.md @@ -359,7 +359,21 @@ _Ongoing notes as we implement..._ - Shows "Change theme (name)" when theme applied **Next Steps:** -1. Integrate ComponentHeaderControls into Markdown component +1. ~~Integrate ComponentHeaderControls into Markdown component~~ DONE 2. Test with simple Edit/Preview + Theme + Delete menu -3. Remove old MarkdownModeDropdown +3. ~~Remove old MarkdownModeDropdown~~ DONE + +### Session 1 - Markdown Integration +- Integrated `ComponentHeaderControls` into Markdown component +- Replaced old UI elements: + - Removed `HoverMenu` with `DeleteComponentButton` + - Removed `MarkdownModeDropdown` from `WithPopoverMenu.menuItems` +- New menu includes: Edit/Preview toggle, Apply Theme, Delete +- Added `MarkdownControlsWrapper` for top-right positioning +- Menu shows on hover in edit mode + +**Files modified:** +- `src/dashboard/components/gridComponents/Markdown/Markdown.jsx` + +**Status:** Ready for visual testing in browser diff --git a/superset-frontend/src/dashboard/components/gridComponents/Markdown/Markdown.jsx b/superset-frontend/src/dashboard/components/gridComponents/Markdown/Markdown.jsx index 6b451a3faaf..82952b78a3e 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Markdown/Markdown.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Markdown/Markdown.jsx @@ -23,14 +23,15 @@ import cx from 'classnames'; import { t, css, styled } from '@apache-superset/core/ui'; import { SafeMarkdown } from '@superset-ui/core/components'; +import { Icons } from '@superset-ui/core/components/Icons'; import { EditorHost } from 'src/core/editors'; +import ComponentHeaderControls, { + ComponentMenuKeys, +} from 'src/dashboard/components/menu/ComponentHeaderControls'; import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; -import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; import { Draggable } from 'src/dashboard/components/dnd/DragDroppable'; -import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; -import MarkdownModeDropdown from 'src/dashboard/components/menu/MarkdownModeDropdown'; import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import { componentShape } from 'src/dashboard/util/propShapes'; import { ROW_TYPE, COLUMN_TYPE } from 'src/dashboard/util/componentTypes'; @@ -85,6 +86,22 @@ Click here to learn more about [markdown formatting](https://bit.ly/1dQOfRK)`; const MARKDOWN_ERROR_MESSAGE = t('This markdown component has an error.'); +const MarkdownControlsWrapper = styled.div` + ${({ theme }) => css` + position: absolute; + top: ${theme.sizeUnit}px; + right: ${theme.sizeUnit}px; + z-index: 10; + opacity: 0; + transition: opacity 0.2s; + + .dashboard-markdown:hover &, + .dashboard-markdown:focus-within & { + opacity: 1; + } + `} +`; + const MarkdownStyles = styled.div` ${({ theme }) => css` &.dashboard-markdown { @@ -138,6 +155,8 @@ class Markdown extends PureComponent { this.handleResizeStart = this.handleResizeStart.bind(this); this.setEditor = this.setEditor.bind(this); this.shouldFocusMarkdown = this.shouldFocusMarkdown.bind(this); + this.handleMenuClick = this.handleMenuClick.bind(this); + this.getMenuItems = this.getMenuItems.bind(this); } componentDidMount() { @@ -278,6 +297,62 @@ class Markdown extends PureComponent { } } + handleMenuClick(key) { + switch (key) { + case ComponentMenuKeys.EditContent: + this.handleChangeEditorMode('edit'); + break; + case ComponentMenuKeys.PreviewContent: + this.handleChangeEditorMode('preview'); + break; + case ComponentMenuKeys.ApplyTheme: + // TODO: Open theme selector modal + break; + case ComponentMenuKeys.Delete: + this.handleDeleteComponent(); + break; + default: + break; + } + } + + getMenuItems() { + const { editorMode } = this.state; + const isEditing = editorMode === 'edit'; + + const items = [ + // Edit/Preview toggle + { + key: isEditing + ? ComponentMenuKeys.PreviewContent + : ComponentMenuKeys.EditContent, + label: isEditing ? t('Preview') : t('Edit'), + icon: isEditing ? ( + <Icons.EyeOutlined /> + ) : ( + <Icons.EditOutlined /> + ), + }, + { type: 'divider' }, + // Theme selection + { + key: ComponentMenuKeys.ApplyTheme, + label: t('Apply theme'), + icon: <Icons.BgColorsOutlined />, + }, + { type: 'divider' }, + // Delete + { + key: ComponentMenuKeys.Delete, + label: t('Delete'), + icon: <Icons.DeleteOutlined />, + danger: true, + }, + ]; + + return items; + } + shouldFocusMarkdown(event, container, menuRef) { if (container?.contains(event.target)) return true; if (menuRef?.contains(event.target)) return true; @@ -368,13 +443,7 @@ class Markdown extends PureComponent { <WithPopoverMenu onChangeFocus={this.handleChangeFocus} shouldFocus={this.shouldFocusMarkdown} - menuItems={[ - <MarkdownModeDropdown - id={`${component.id}-mode`} - value={this.state.editorMode} - onChange={this.handleChangeEditorMode} - />, - ]} + menuItems={[]} editMode={editMode} > <MarkdownStyles @@ -407,11 +476,14 @@ class Markdown extends PureComponent { data-test="dashboard-component-chart-holder" > {editMode && ( - <HoverMenu position="top"> - <DeleteComponentButton - onDelete={this.handleDeleteComponent} + <MarkdownControlsWrapper> + <ComponentHeaderControls + componentId={component.id} + menuItems={this.getMenuItems()} + onMenuClick={this.handleMenuClick} + editMode={editMode} /> - </HoverMenu> + </MarkdownControlsWrapper> )} {editMode && isEditing ? this.renderEditMode()
