This commit is contained in:
@@ -10,11 +10,13 @@ public abstract class AxisChart extends ApexChart {
|
||||
}
|
||||
|
||||
public void setData(String seriesName, List<Double> values, List<String> categories) {
|
||||
Map<String, Object> options = Map.of(
|
||||
"chart", Map.of("type", getChartType(), "height", "100%"),
|
||||
"series", List.of(Map.of("name", seriesName, "data", values)),
|
||||
"xaxis", Map.of("categories", categories)
|
||||
);
|
||||
Map<String, Object> options = DialectTheme.baseOptions(getChartType());
|
||||
options.put("series", List.of(Map.of("name", seriesName, "data", values)));
|
||||
options.put("xaxis", Map.of(
|
||||
"categories", categories,
|
||||
"axisBorder", Map.of("show", false),
|
||||
"axisTicks", Map.of("show", false)
|
||||
));
|
||||
|
||||
sendOptions(options);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.example.components;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Shared ApexCharts styling for the Dialect design system
|
||||
* (https://www.figma.com/design/6DRThj0vmRgfjMIdsmkaIy).
|
||||
*/
|
||||
public final class DialectTheme {
|
||||
|
||||
/** Categorical palette, primary orange first. */
|
||||
public static final List<String> COLORS = List.of(
|
||||
"#E86C00", // primary orange
|
||||
"#4C9BE8", // blue
|
||||
"#2FB7A6", // teal
|
||||
"#F6B93B", // gold
|
||||
"#8E7CD6", // purple
|
||||
"#E5544B", // red
|
||||
"#3F51B5" // indigo
|
||||
);
|
||||
|
||||
private static final String FONT_FAMILY =
|
||||
"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
||||
|
||||
/**
|
||||
* Mirrors {@code --dialect-border} in styles.css. Charts render via JS/SVG,
|
||||
* not CSS, so this can't read the custom property directly — keep both in sync
|
||||
* by hand if the token changes.
|
||||
*/
|
||||
private static final String BORDER_COLOR = "#E6EAF0";
|
||||
|
||||
/** Mirrors {@code --dialect-ink} in styles.css. See {@link #BORDER_COLOR} note. */
|
||||
private static final String INK_COLOR = "#14171F";
|
||||
|
||||
private DialectTheme() {
|
||||
}
|
||||
|
||||
/** Common option fragments merged into every chart before series/labels are added. */
|
||||
public static Map<String, Object> baseOptions(String chartType) {
|
||||
Map<String, Object> options = new LinkedHashMap<>();
|
||||
|
||||
Map<String, Object> chart = new LinkedHashMap<>();
|
||||
chart.put("type", chartType);
|
||||
chart.put("height", "100%");
|
||||
chart.put("fontFamily", FONT_FAMILY);
|
||||
chart.put("toolbar", Map.of("show", false));
|
||||
options.put("chart", chart);
|
||||
|
||||
options.put("colors", COLORS);
|
||||
|
||||
options.put("grid", Map.of(
|
||||
"borderColor", BORDER_COLOR,
|
||||
"strokeDashArray", 4
|
||||
));
|
||||
|
||||
options.put("legend", Map.of(
|
||||
"position", "bottom",
|
||||
"labels", Map.of("colors", INK_COLOR)
|
||||
));
|
||||
|
||||
options.put("dataLabels", Map.of("enabled", false));
|
||||
|
||||
options.put("tooltip", Map.of("theme", "light"));
|
||||
|
||||
if ("line".equals(chartType)) {
|
||||
options.put("stroke", Map.of("curve", "smooth", "width", 3));
|
||||
} else if ("bar".equals(chartType)) {
|
||||
options.put("stroke", Map.of("width", 0));
|
||||
options.put("plotOptions", Map.of(
|
||||
"bar", Map.of(
|
||||
"borderRadius", 6,
|
||||
"borderRadiusApplication", "end",
|
||||
"columnWidth", "55%"
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,9 @@ public class PieChart extends ApexChart {
|
||||
}
|
||||
|
||||
public void setData(List<Double> values, List<String> labels) {
|
||||
Map<String, Object> options = Map.of(
|
||||
"chart", Map.of("type", "pie", "height", "100%"),
|
||||
"series", values,
|
||||
"labels", labels
|
||||
);
|
||||
Map<String, Object> options = DialectTheme.baseOptions("pie");
|
||||
options.put("series", values);
|
||||
options.put("labels", labels);
|
||||
|
||||
sendOptions(options);
|
||||
}
|
||||
|
||||
@@ -3,16 +3,22 @@ package com.example.views;
|
||||
import com.example.components.BarChart;
|
||||
import com.example.components.LineChart;
|
||||
import com.example.components.PieChart;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.html.H3;
|
||||
import com.vaadin.flow.component.notification.Notification;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Route("")
|
||||
@PageTitle("Dashboard")
|
||||
public class DashboardView extends VerticalLayout {
|
||||
|
||||
public DashboardView() {
|
||||
addClassName("dialect-content");
|
||||
|
||||
LineChart lineChart = new LineChart();
|
||||
lineChart.setWidthFull();
|
||||
lineChart.setHeight("400px");
|
||||
@@ -45,6 +51,20 @@ public class DashboardView extends VerticalLayout {
|
||||
Notification.show("Slice %d".formatted(e.getDataPointIndex()));
|
||||
});
|
||||
|
||||
add(lineChart, barChart, pieChart);
|
||||
add(card("Umsatz-Entwicklung", lineChart),
|
||||
card("Umsatz nach Monat", barChart),
|
||||
card("Umsatz nach Region", pieChart));
|
||||
}
|
||||
|
||||
private Component card(String title, Component chart) {
|
||||
H3 heading = new H3(title);
|
||||
heading.addClassName("dialect-card__title");
|
||||
|
||||
VerticalLayout card = new VerticalLayout(heading, chart);
|
||||
card.addClassName("dialect-card");
|
||||
card.setWidthFull();
|
||||
card.setPadding(false);
|
||||
card.setSpacing(false);
|
||||
return card;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.example.views;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.checkbox.Checkbox;
|
||||
import com.vaadin.flow.component.checkbox.CheckboxGroup;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.datepicker.DatePicker;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.html.H3;
|
||||
import com.vaadin.flow.component.notification.Notification;
|
||||
import com.vaadin.flow.component.notification.NotificationVariant;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.radiobutton.RadioButtonGroup;
|
||||
import com.vaadin.flow.component.select.Select;
|
||||
import com.vaadin.flow.component.textfield.BigDecimalField;
|
||||
import com.vaadin.flow.component.textfield.EmailField;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
import com.vaadin.flow.component.textfield.PasswordField;
|
||||
import com.vaadin.flow.component.textfield.TextArea;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.component.timepicker.TimePicker;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
import com.vaadin.flow.data.validator.EmailValidator;
|
||||
import com.vaadin.flow.data.validator.IntegerRangeValidator;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
|
||||
|
||||
/**
|
||||
* Example view demonstrating a broad set of Vaadin form controls bound
|
||||
* to {@link Registration} via {@link Binder}.
|
||||
*/
|
||||
@Route("formular")
|
||||
@PageTitle("Formular")
|
||||
public class FormView extends VerticalLayout {
|
||||
|
||||
private final Binder<Registration> binder = new Binder<>(Registration.class);
|
||||
|
||||
public FormView() {
|
||||
addClassName("dialect-content");
|
||||
add(card("Registrierung", buildForm()));
|
||||
}
|
||||
|
||||
private Component buildForm() {
|
||||
TextField vorname = new TextField("Vorname");
|
||||
TextField nachname = new TextField("Nachname");
|
||||
EmailField email = new EmailField("E-Mail");
|
||||
PasswordField passwort = new PasswordField("Passwort");
|
||||
IntegerField alter = new IntegerField("Alter");
|
||||
BigDecimalField gehalt = new BigDecimalField("Gehalt (€)");
|
||||
DatePicker geburtsdatum = new DatePicker("Geburtsdatum");
|
||||
TimePicker uhrzeit = new TimePicker("Bevorzugte Uhrzeit");
|
||||
|
||||
ComboBox<String> land = new ComboBox<>("Land");
|
||||
land.setItems("Deutschland", "Österreich", "Schweiz", "Frankreich", "Niederlande");
|
||||
|
||||
Select<String> abteilung = new Select<>();
|
||||
abteilung.setLabel("Abteilung");
|
||||
abteilung.setItems("Vertrieb", "Marketing", "Entwicklung", "Support", "Geschäftsführung");
|
||||
|
||||
CheckboxGroup<String> interessen = new CheckboxGroup<>();
|
||||
interessen.setLabel("Interessen");
|
||||
interessen.setItems("Newsletter-Themen", "Webinare", "Produkt-Updates", "Events");
|
||||
|
||||
RadioButtonGroup<String> geschlecht = new RadioButtonGroup<>();
|
||||
geschlecht.setLabel("Anrede");
|
||||
geschlecht.setItems("Frau", "Herr", "Divers", "Keine Angabe");
|
||||
|
||||
Checkbox newsletter = new Checkbox("Newsletter abonnieren");
|
||||
|
||||
TextArea bemerkung = new TextArea("Bemerkung");
|
||||
bemerkung.setMaxLength(500);
|
||||
|
||||
binder.forField(vorname)
|
||||
.asRequired("Vorname wird benötigt")
|
||||
.bind(Registration::getVorname, Registration::setVorname);
|
||||
binder.forField(nachname)
|
||||
.asRequired("Nachname wird benötigt")
|
||||
.bind(Registration::getNachname, Registration::setNachname);
|
||||
binder.forField(email)
|
||||
.asRequired("E-Mail wird benötigt")
|
||||
.withValidator(new EmailValidator("Ungültige E-Mail-Adresse"))
|
||||
.bind(Registration::getEmail, Registration::setEmail);
|
||||
binder.forField(passwort)
|
||||
.bind(Registration::getPasswort, Registration::setPasswort);
|
||||
binder.forField(alter)
|
||||
.withValidator(new IntegerRangeValidator("Alter muss zwischen 0 und 120 liegen", 0, 120))
|
||||
.bind(Registration::getAlter, Registration::setAlter);
|
||||
binder.forField(gehalt)
|
||||
.bind(Registration::getGehalt, Registration::setGehalt);
|
||||
binder.forField(geburtsdatum)
|
||||
.bind(Registration::getGeburtsdatum, Registration::setGeburtsdatum);
|
||||
binder.forField(uhrzeit)
|
||||
.bind(Registration::getUhrzeit, Registration::setUhrzeit);
|
||||
binder.forField(land)
|
||||
.bind(Registration::getLand, Registration::setLand);
|
||||
binder.forField(abteilung)
|
||||
.bind(Registration::getAbteilung, Registration::setAbteilung);
|
||||
binder.forField(interessen)
|
||||
.bind(Registration::getInteressen, Registration::setInteressen);
|
||||
binder.forField(geschlecht)
|
||||
.bind(Registration::getGeschlecht, Registration::setGeschlecht);
|
||||
binder.forField(newsletter)
|
||||
.bind(Registration::isNewsletter, Registration::setNewsletter);
|
||||
binder.forField(bemerkung)
|
||||
.bind(Registration::getBemerkung, Registration::setBemerkung);
|
||||
|
||||
Registration registration = new Registration();
|
||||
binder.readBean(registration);
|
||||
|
||||
FormLayout formLayout = new FormLayout();
|
||||
formLayout.setResponsiveSteps(
|
||||
new FormLayout.ResponsiveStep("0", 1),
|
||||
new FormLayout.ResponsiveStep("500px", 2));
|
||||
formLayout.add(vorname, nachname, email, passwort, alter, gehalt,
|
||||
geburtsdatum, uhrzeit, land, abteilung);
|
||||
formLayout.setColspan(interessen, 2);
|
||||
formLayout.setColspan(geschlecht, 2);
|
||||
formLayout.setColspan(newsletter, 2);
|
||||
formLayout.setColspan(bemerkung, 2);
|
||||
formLayout.add(interessen, geschlecht, newsletter, bemerkung);
|
||||
|
||||
Button speichern = new Button("Speichern", e -> {
|
||||
Registration ziel = new Registration();
|
||||
if (binder.writeBeanIfValid(ziel)) {
|
||||
Notification erfolg = Notification.show(
|
||||
"Gespeichert: %s %s".formatted(ziel.getVorname(), ziel.getNachname()));
|
||||
erfolg.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
||||
} else {
|
||||
Notification fehler = Notification.show("Bitte Eingaben prüfen");
|
||||
fehler.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||
}
|
||||
});
|
||||
speichern.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
|
||||
Button zuruecksetzen = new Button("Zurücksetzen",
|
||||
e -> binder.readBean(new Registration()));
|
||||
|
||||
HorizontalLayout buttons = new HorizontalLayout(speichern, zuruecksetzen);
|
||||
|
||||
VerticalLayout wrapper = new VerticalLayout(formLayout, buttons);
|
||||
wrapper.setPadding(false);
|
||||
wrapper.setSpacing(true);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private Component card(String title, Component body) {
|
||||
H3 heading = new H3(title);
|
||||
heading.addClassName("dialect-card__title");
|
||||
|
||||
VerticalLayout card = new VerticalLayout(heading, body);
|
||||
card.addClassName("dialect-card");
|
||||
card.setWidthFull();
|
||||
card.setPadding(false);
|
||||
card.setSpacing(false);
|
||||
return card;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.views;
|
||||
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.applayout.DrawerToggle;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.sidenav.SideNav;
|
||||
import com.vaadin.flow.component.sidenav.SideNavItem;
|
||||
import com.vaadin.flow.router.Layout;
|
||||
|
||||
@Layout
|
||||
public class MainLayout extends AppLayout {
|
||||
|
||||
public MainLayout() {
|
||||
DrawerToggle toggle = new DrawerToggle();
|
||||
|
||||
Span title = new Span("Chart App");
|
||||
title.addClassName("dialect-title");
|
||||
|
||||
addToNavbar(toggle, title);
|
||||
|
||||
SideNav nav = new SideNav();
|
||||
nav.addItem(new SideNavItem("Dashboard", DashboardView.class,
|
||||
VaadinIcon.DASHBOARD.create()));
|
||||
nav.addItem(new SideNavItem("Formular", FormView.class,
|
||||
VaadinIcon.FORM.create()));
|
||||
|
||||
addToDrawer(nav);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.example.views;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Plain POJO backing the example form on {@link FormView}. Bound via
|
||||
* {@link com.vaadin.flow.data.binder.Binder} — one field per showcased
|
||||
* Vaadin control type.
|
||||
*/
|
||||
public class Registration {
|
||||
|
||||
private String vorname;
|
||||
private String nachname;
|
||||
private String email;
|
||||
private String passwort;
|
||||
private Integer alter;
|
||||
private BigDecimal gehalt;
|
||||
private LocalDate geburtsdatum;
|
||||
private LocalTime uhrzeit;
|
||||
private String land;
|
||||
private String abteilung;
|
||||
private Set<String> interessen = new HashSet<>();
|
||||
private String geschlecht;
|
||||
private boolean newsletter;
|
||||
private String bemerkung;
|
||||
|
||||
public String getVorname() {
|
||||
return vorname;
|
||||
}
|
||||
|
||||
public void setVorname(String vorname) {
|
||||
this.vorname = vorname;
|
||||
}
|
||||
|
||||
public String getNachname() {
|
||||
return nachname;
|
||||
}
|
||||
|
||||
public void setNachname(String nachname) {
|
||||
this.nachname = nachname;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPasswort() {
|
||||
return passwort;
|
||||
}
|
||||
|
||||
public void setPasswort(String passwort) {
|
||||
this.passwort = passwort;
|
||||
}
|
||||
|
||||
public Integer getAlter() {
|
||||
return alter;
|
||||
}
|
||||
|
||||
public void setAlter(Integer alter) {
|
||||
this.alter = alter;
|
||||
}
|
||||
|
||||
public BigDecimal getGehalt() {
|
||||
return gehalt;
|
||||
}
|
||||
|
||||
public void setGehalt(BigDecimal gehalt) {
|
||||
this.gehalt = gehalt;
|
||||
}
|
||||
|
||||
public LocalDate getGeburtsdatum() {
|
||||
return geburtsdatum;
|
||||
}
|
||||
|
||||
public void setGeburtsdatum(LocalDate geburtsdatum) {
|
||||
this.geburtsdatum = geburtsdatum;
|
||||
}
|
||||
|
||||
public LocalTime getUhrzeit() {
|
||||
return uhrzeit;
|
||||
}
|
||||
|
||||
public void setUhrzeit(LocalTime uhrzeit) {
|
||||
this.uhrzeit = uhrzeit;
|
||||
}
|
||||
|
||||
public String getLand() {
|
||||
return land;
|
||||
}
|
||||
|
||||
public void setLand(String land) {
|
||||
this.land = land;
|
||||
}
|
||||
|
||||
public String getAbteilung() {
|
||||
return abteilung;
|
||||
}
|
||||
|
||||
public void setAbteilung(String abteilung) {
|
||||
this.abteilung = abteilung;
|
||||
}
|
||||
|
||||
public Set<String> getInteressen() {
|
||||
return interessen;
|
||||
}
|
||||
|
||||
public void setInteressen(Set<String> interessen) {
|
||||
this.interessen = interessen;
|
||||
}
|
||||
|
||||
public String getGeschlecht() {
|
||||
return geschlecht;
|
||||
}
|
||||
|
||||
public void setGeschlecht(String geschlecht) {
|
||||
this.geschlecht = geschlecht;
|
||||
}
|
||||
|
||||
public boolean isNewsletter() {
|
||||
return newsletter;
|
||||
}
|
||||
|
||||
public void setNewsletter(boolean newsletter) {
|
||||
this.newsletter = newsletter;
|
||||
}
|
||||
|
||||
public String getBemerkung() {
|
||||
return bemerkung;
|
||||
}
|
||||
|
||||
public void setBemerkung(String bemerkung) {
|
||||
this.bemerkung = bemerkung;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user