Skip to content

Commit

Permalink
add comments to lit example
Browse files Browse the repository at this point in the history
  • Loading branch information
sissbruecker committed Dec 9, 2024
1 parent 9c6bca2 commit 3d078b6
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 15 deletions.
10 changes: 9 additions & 1 deletion articles/components/dashboard/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,18 @@ include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardServi
endif::[]

ifdef::lit[]
[source,html]
[source,typescript]
----
include::{root}/frontend/demo/component/dashboard/dashboard-editable.ts[render,tags=snippet,indent=0,group=Lit]
----
[source,java]
----
include::{root}/src/main/java/com/vaadin/demo/component/dashboard/WidgetConfig.java[tags=snippet,indent=0,group=Lit]
----
[source,java]
----
include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardService.java[tags=snippet,indent=0,group=Lit]
----
endif::[]
--

Expand Down
198 changes: 191 additions & 7 deletions frontend/demo/component/dashboard/dashboard-editable.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,207 @@
import 'Frontend/demo/init'; // hidden-source-line
import '@vaadin/checkbox';
import '@vaadin/horizontal-layout';
import '@vaadin/menu-bar';
import '@vaadin/dashboard/vaadin-dashboard-layout.js';
import '@vaadin/dashboard/vaadin-dashboard.js';
import '@vaadin/dashboard/vaadin-dashboard-widget.js';
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { html, LitElement, render } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import type { Dashboard } from '@vaadin/dashboard';
import type { MenuBarItem, MenuBarItemSelectedEvent } from '@vaadin/menu-bar';
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 { DashboardService } from 'Frontend/generated/endpoints';
import { applyTheme } from 'Frontend/generated/theme';

// tag::snippet[]
// NOTE: This example uses the additional classes WidgetConfig and DashboardService,
// which you can find by switching to the respective file tab.

// This is the default configuration for the dashboard. Note that the order
// of the widgets in the array determines the order in which they are
// displayed in the dashboard.
const defaultConfig: 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 },
];

// 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',
};

// Helper type to allow defining a custom action for a menu item
type CustomMenuItem = MenuBarItem & {
action?(): unknown;
};

@customElement('dashboard-editable')
export class Example extends LitElement {
// Stores the current dashboard configuration. The vaadin-dashboard component
// will modify this array in place when editing, so there is no need to
// update it using events.
@state()
widgets: WidgetConfig[] = [];

@state()
editable = false;

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

protected override render() {
return html``;
firstUpdated() {
// Load the initial configuration of the dashboard
this.load();
}

toggleEditing() {
this.editable = !this.editable;
}

async load() {
// To load the dashboard configuration, we just load it from a server-side
// service. If there is no configuration saved, we use a copy of the default
// configuration.
const config = await DashboardService.loadDashboard();
this.widgets = config ?? [...defaultConfig];
}

save() {
// To save the dashboard configuration, we can just take the current
// widget items array and pass it to a server-side service for
// persisting it.
DashboardService.saveDashboard(this.widgets);
}

addWidget(type: WidgetType) {
// For adding a new widget, we retrieve the default configuration for the
// widget type and add a copy of that to the widgets array.
const defaultWidgetConfig = defaultConfig.find((widget) => widget.type === type);
if (defaultWidgetConfig) {
this.widgets = [...this.widgets, { ...defaultWidgetConfig }];
}
}

restore() {
// To restore defaults, we just set a copy of the default configuration
this.widgets = [...defaultConfig];
}

render() {
return html` ${this.renderMenu()} ${this.renderDashboard()} `;
}

renderMenu() {
const menuItems = [
{
text: this.editable ? 'Apply' : 'Edit',
action: this.toggleEditing.bind(this),
theme: 'primary',
},
{
text: 'Save',
action: this.save.bind(this),
},
{
text: 'Load',
action: this.load.bind(this),
},
{
text: 'Add widget',
children: Object.values(WidgetType).map((type) => ({
text: widgetTitles[type],
action: () => this.addWidget(type),
})),
},
{
text: 'Restore default',
action: this.restore.bind(this),
theme: 'error',
},
];

return html`
<vaadin-menu-bar
.items="${menuItems}"
@item-selected="${(e: MenuBarItemSelectedEvent) => {
const item = e.detail.value as CustomMenuItem;
item.action?.();
}}"
theme="dropdown-indicators"
></vaadin-menu-bar>
`;
}

renderDashboard() {
return html`
<vaadin-dashboard
style="--vaadin-dashboard-col-min-width: 150px; --vaadin-dashboard-col-max-count: 3;"
.editable="${this.editable}"
.items="${this.widgets}"
.renderer="${this.renderWidget}"
></vaadin-dashboard>
`;
}

renderWidget(root: HTMLElement, _dashboard: Dashboard, { item }: { item: WidgetConfig }) {
// This method is used to render the actual widgets into the dashboard.
// It is called by vaadin-dashboard once for each config in the widgets
// array and should render content into the provided root element. In
// this example all widget types have the same content, so we can use
// generic logic to render a widget.
render(
html`
<vaadin-dashboard-widget
.widgetTitle="${widgetTitles[item.type]}"
style="
--vaadin-dashboard-item-colspan: ${item.colspan ?? 1};
--vaadin-dashboard-item-rowspan: ${item.rowspan ?? 1};
"
>
<div class="dashboard-widget-content"></div>
</vaadin-dashboard-widget>
`,
root
);

// In practice, different widget types will have different content.
// In that case you can use a switch statement to render the widget
// content based on the type.
//
// let widget: TemplateResult;
//
// switch (item.type) {
// case WidgetType.Visitors:
// widget = html`
// <vaadin-dashboard-widget
// .widgetTitle="Visitors"
// style="
// --vaadin-dashboard-item-colspan: ${item.colspan ?? 1};
// --vaadin-dashboard-item-rowspan: ${item.rowspan ?? 1};
// "
// >
// <visitors-widget-content></visitors-widget-content>
// </vaadin-dashboard-widget>
// `;
// break;
// ...
// }
//
// render(widget, root);
}
}

// end::snippet[]
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ import React, { useEffect } from 'react'; // hidden-source-line
import { useSignals } from '@preact/signals-react/runtime'; // hidden-source-line
import { useSignal } from '@vaadin/hilla-react-signals';
import { MenuBar, type MenuBarItem } from '@vaadin/react-components';
import {
Dashboard,
type DashboardReactRendererProps,
DashboardWidget,
} from '@vaadin/react-components-pro';
import { Dashboard, DashboardWidget } from '@vaadin/react-components-pro';
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 { DashboardService } from 'Frontend/generated/endpoints';

// tag::snippet[]
// NOTE: This example uses the additional classes WidgetConfig and DashboardService,
// which you can find by switching to the respective file in the top of the example.
// which you can find by switching to the respective file tab.

// This is the default configuration for the dashboard. Note that the order
// of the widgets in the array determines the order in which they are
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class DashboardEditable extends Div {

// tag::snippet[]
// NOTE: This example uses the additional classes WidgetConfig and DashboardStorage,
// which you can find by switching to the respective file in the top of the example.
// which you can find by switching to the respective file tab.

// Since the default DashboardWidget class doesn't allow setting custom data,
// we create a custom class that extends DashboardWidget, and add a
Expand Down

0 comments on commit 3d078b6

Please sign in to comment.