Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add Dashboard documentation #4013

Merged
merged 14 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added articles/components/dashboard/dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
566 changes: 566 additions & 0 deletions articles/components/dashboard/index.adoc

Large diffs are not rendered by default.

136 changes: 136 additions & 0 deletions articles/components/dashboard/styling.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
title: Styling
description: Styling API reference for the Dashboard component.
order: 50
---
= Styling


include::../_styling-section-theming-props.adoc[tag=style-properties]

[cols="1,2,1"]
|===
| Feature | Property | Default Value

|Minimum column width
|`--vaadin-dashboard-col-min-width`
|`25rem`

|Maximum column width
|`--vaadin-dashboard-col-min-width`
|`1fr`

|Maximum column count
|`--vaadin-dashboard-col-max-count`
|

|Minimum row height
|`--vaadin-dashboard-row-min-height`
|`12rem`

|Dashboard padding (around contents)
|`--vaadin-dashboard-padding`
|`--lumo-space-m`

|Widget gap
|`--vaadin-dashboard-gap`
|`--lumo-space-m`

|Widget background
|`--vaadin-dashboard-widget-background`
|`--lumo-base-color`

|Widget corner radius
|`--vaadin-dashboard-widget-border-radius`
|`--lumo-border-radius-l`

|Widget border width
|`--vaadin-dashboard-widget-border-width`
|`--1px`

|Widget border color
|`--vaadin-dashboard-widget-border-color`
|`--lumo-contrast-20pct`

|Widget shadow (non-editable)
|`--vaadin-dashboard-widget-shadow`
|`0 0 0 0 transparent`

|Editable widget shadow
|`--vaadin-dashboard-widget-editable-shadow`
|`--lumo-box-shadow-s`

|Selected widget shadow
|`--vaadin-dashboard-widget-selected-shadow`
|`0 2px 4px -1px var(--lumo-primary-color-10pct), 0 3px 12px -1px var(--lumo-primary-color-50pct);`

|Drop target / resize box background color
|`--vaadin-dashboard-drop-target-background-color`
|`--lumo-primary-color-10pct`

|Drop target / resize box border
|`--vaadin-dashboard-drop-target-border`
|`--1px dashed var(--lumo-primary-color-50pct)`

|===



include::../_styling-section-intros.adoc[tag=selectors]

Dashboard root element:: `vaadin-dashboard`
Static Dashboard Layout (React & Lit):: `vaadin-dashboard-layout`


=== Widgets

Root element:: `vaadin-dashboard-widget`

==== Widget States
Editable:: `vaadin-dashboard-widget+++<wbr>+++**[editable]**`
Focused:: `vaadin-dashboard-widget+++<wbr>+++**[focused]**`
Selected:: `vaadin-dashboard-widget+++<wbr>+++**[selected]**`
Being dragged:: `vaadin-dashboard-widget+++<wbr>+++**[dragging]**`
Being resized:: `vaadin-dashboard-widget+++<wbr>+++**[resizing]**`
Accessible move mode:: `vaadin-dashboard-widget+++<wbr>+++**[move-mode]**`
Accessible resize mode:: `vaadin-dashboard-widget+++<wbr>+++**[resize-mode]**`

==== Widget Parts
Header:: `vaadin-dashboard-widget+++<wbr>+++**::part(header)**`
Title:: `vaadin-dashboard-widget+++<wbr>+++**::part(title)**`
Content area:: `vaadin-dashboard-widget+++<wbr>+++**::part(content)**`
Drag handle / Move button:: `vaadin-dashboard-widget+++<wbr>+++**::part(move-button)**`
Remove button:: `vaadin-dashboard-widget+++<wbr>+++**::part(remove-button)**`
Resize handle / button:: `vaadin-dashboard-widget+++<wbr>+++**::part(resize-button)**`


=== Sections

Root element:: `vaadin-dashboard-section`

==== Section States
Editable:: `vaadin-dashboard-section+++<wbr>+++**[editable]**`
Focused:: `vaadin-dashboard-section+++<wbr>+++**[focused]**`
Selected:: `vaadin-dashboard-section+++<wbr>+++**[selected]**`
Being dragged:: `vaadin-dashboard-section+++<wbr>+++**[dragging]**`
Accessible move mode:: `vaadin-dashboard-section+++<wbr>+++**[move-mode]**`

==== Section Parts
Header:: `vaadin-dashboard-section+++<wbr>+++**::part(header)**`
Title:: `vaadin-dashboard-section+++<wbr>+++**::part(title)**`
Drag handle / Move button:: `vaadin-dashboard-section+++<wbr>+++**::part(move-button)**`
Remove button:: `vaadin-dashboard-section+++<wbr>+++**::part(remove-button)**`


=== Accessible Move & Resize Modes

To target move-mode buttons on Sections, replace `vaadin-dashboard-widget` with `vaadin-dashboard-section` in the selectors below.

Move backward button:: `vaadin-dashboard-widget+++<wbr>+++**::part(move-backward-button)**`
Move forward button:: `vaadin-dashboard-widget+++<wbr>+++**::part(move-forward-button)**`
Move apply button:: `vaadin-dashboard-widget+++<wbr>+++**::part(move-apply-button)**`
Shrink width button:: `vaadin-dashboard-widget+++<wbr>+++**::part(resize-shrink-width-button)**`
Grow width button:: `vaadin-dashboard-widget+++<wbr>+++**::part(resize-grow-width-button)**`
Shrink height button:: `vaadin-dashboard-widget+++<wbr>+++**::part(resize-shrink-width-button)**`
Grow height button:: `vaadin-dashboard-widget+++<wbr>+++**::part(resize-grow-width-button)**`
Resize apply button:: `vaadin-dashboard-widget+++<wbr>+++**::part(resize-apply-button)**`
11 changes: 11 additions & 0 deletions articles/components/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,17 @@ include::board/index.adoc[tag=description]
<<{components-path-prefix}board#,See Board>>


[.component-card.commercial]
=== Dashboard

image::{components-path-prefix}dashboard/dashboard.png["", opts=inline, role="banner"]

include::dashboard/index.adoc[tag=description]

[.sr-only]
<<{components-path-prefix}dashboard#,See Dashboard>>


[.component-card]
=== Form Layout

Expand Down
149 changes: 149 additions & 0 deletions frontend/demo/component/dashboard/dashboard-announcements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import 'Frontend/demo/init'; // hidden-source-line
import '@vaadin/menu-bar';
import '@vaadin/dashboard/vaadin-dashboard.js';
import '@vaadin/dashboard/vaadin-dashboard-widget.js';
import { html, LitElement, render } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import type {
Dashboard,
DashboardItemMovedEvent,
DashboardItemMoveModeChangedEvent,
DashboardItemRemovedEvent,
DashboardItemResizedEvent,
DashboardItemResizeModeChangedEvent,
DashboardItemSelectedChangedEvent,
} from '@vaadin/dashboard';
import type WidgetConfig from 'Frontend/generated/com/vaadin/demo/component/dashboard/WidgetConfig';
import WidgetType from 'Frontend/generated/com/vaadin/demo/component/dashboard/WidgetConfig/WidgetType';
import { applyTheme } from 'Frontend/generated/theme';

// Define a mapping from widget types to human-readable titles
const widgetTitles: Record<WidgetType, string> = {
[WidgetType.VISITORS]: 'Visitors',
[WidgetType.DOWNLOADS]: 'Downloads',
[WidgetType.CONVERSIONS]: 'Conversions',
[WidgetType.VISITORS_BY_COUNTRY]: 'Visitors by country',
[WidgetType.BROWSER_DISTRIBUTION]: 'Browsers',
[WidgetType.CAT_IMAGE]: 'A kittykat!',
[WidgetType.VISITORS_BY_BROWSER]: 'Visitors by browser',
};

@customElement('dashboard-announcements')
export class Example extends LitElement {
@state()
widgets: WidgetConfig[] = [
{ type: WidgetType.VISITORS, colspan: 1, rowspan: 1 },
{ type: WidgetType.DOWNLOADS, colspan: 1, rowspan: 1 },
{ type: WidgetType.CONVERSIONS, colspan: 1, rowspan: 1 },
{ type: WidgetType.VISITORS_BY_COUNTRY, colspan: 1, rowspan: 2 },
{ type: WidgetType.BROWSER_DISTRIBUTION, colspan: 1, rowspan: 1 },
{ type: WidgetType.CAT_IMAGE, colspan: 1, rowspan: 1 },
{ type: WidgetType.VISITORS_BY_BROWSER, colspan: 2, rowspan: 1 },
];

// tag::snippet[]
@state()
announcement: string = '';

// end::snippet[]

protected override createRenderRoot() {
const root = super.createRenderRoot();
// Apply custom theme (only supported if your app uses one)
applyTheme(root);
return root;
}

// tag::snippet[]
handleSelectedChange(e: DashboardItemSelectedChangedEvent<WidgetConfig>) {
// This event is fired when the user starts or stops editing a widget
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const title = widgetTitles[(e.detail.item as WidgetConfig).type];
const selected = e.detail.value ? 'selected' : 'unselected';

this.announcement = `Widget ${title} ${selected}`;
}

handleMoveModeChange(e: DashboardItemMoveModeChangedEvent<WidgetConfig>) {
// This event is fired when the user enters or exits move mode
if (e.detail.value) {
this.announcement = 'Entered move mode';
} else {
this.announcement = 'Exited move mode';
}
}

handleResizeModeChange(e: DashboardItemResizeModeChangedEvent<WidgetConfig>) {
// This event is fired when the user enters or exits resize mode
if (e.detail.value) {
this.announcement = 'Entered resize mode';
} else {
this.announcement = 'Exited resize mode';
}
}

handleMove(e: DashboardItemMovedEvent<WidgetConfig>) {
// This event is fired when the user moves a widget
const index = e.detail.items.findIndex((widget) => widget === e.detail.item) + 1;
const total = e.detail.items.length;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const title = widgetTitles[(e.detail.item as WidgetConfig).type];

this.announcement = `Moved widget ${title} to position ${index} of ${total}`;
vursen marked this conversation as resolved.
Show resolved Hide resolved
}

handleResize(e: DashboardItemResizedEvent<WidgetConfig>) {
// This event is fired when the user resizes a widget
const colspan = e.detail.item.colspan;
const rowspan = e.detail.item.rowspan;
const title = widgetTitles[e.detail.item.type];

this.announcement = `Resized widget ${title} to ${colspan} columns, ${rowspan} rows`;
}

handleRemove(e: DashboardItemRemovedEvent<WidgetConfig>) {
// This event is fired when the user removes a widget
const title = widgetTitles[(e.detail.item as WidgetConfig).type];

this.announcement = `Removed widget ${title}`;
}

render() {
return html`
<p>Live announcement:</p>
<!--
Live region for screen reader announcements. Changing its text content will result
in a new announcement. This element is only visible for demonstration purposes. In
your application you should visually hide it using CSS, for example by using the
sr-only Lumo utility class:
<div className="sr-only" aria-live="polite">{announcement}</div>
-->
<div aria-live="polite">${this.announcement}</div>
<vaadin-dashboard
style="--vaadin-dashboard-col-min-width: 150px; --vaadin-dashboard-col-max-count: 3;"
editable
.items="${this.widgets}"
.renderer="${this.renderWidget}"
@dashboard-item-selected-changed="${this.handleSelectedChange}"
@dashboard-item-move-mode-changed="${this.handleMoveModeChange}"
@dashboard-item-resize-mode-changed="${this.handleResizeModeChange}"
@dashboard-item-moved="${this.handleMove}"
@dashboard-item-resized="${this.handleResize}"
@dashboard-item-removed="${this.handleRemove}"
></vaadin-dashboard>
`;
}

// end::snippet[]

renderWidget(root: HTMLElement, _dashboard: Dashboard, { item }: { item: WidgetConfig }) {
render(
html`
<vaadin-dashboard-widget .widgetTitle="${widgetTitles[item.type]}">
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
`,
root
);
}
}
54 changes: 54 additions & 0 deletions frontend/demo/component/dashboard/dashboard-basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'Frontend/demo/init'; // hidden-source-line
import '@vaadin/dashboard/vaadin-dashboard-layout.js';
import '@vaadin/dashboard/vaadin-dashboard-widget.js';
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { applyTheme } from 'Frontend/generated/theme';

@customElement('dashboard-basic')
export class Example extends LitElement {
protected override createRenderRoot() {
const root = super.createRenderRoot();
// Apply custom theme (only supported if your app uses one)
applyTheme(root);
return root;
}

render() {
return html`
<!-- tag::snippet[] -->
<vaadin-dashboard-layout
style="--vaadin-dashboard-col-min-width: 150px; --vaadin-dashboard-col-max-count: 3"
>
<vaadin-dashboard-widget widget-title="Visitors">
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
<vaadin-dashboard-widget widget-title="Downloads">
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
<vaadin-dashboard-widget widget-title="Conversions">
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
<vaadin-dashboard-widget
widget-title="Visitors by country"
style="--vaadin-dashboard-item-rowspan: 2;"
>
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
<vaadin-dashboard-widget widget-title="Browsers">
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
<vaadin-dashboard-widget widget-title="A kittykat!">
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
<vaadin-dashboard-widget
widget-title="Visitors by browser"
style="--vaadin-dashboard-item-colspan: 2;"
>
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
</vaadin-dashboard-layout>
<!-- end::snippet[] -->
`;
}
}
Loading
Loading