@@ -6,38 +6,42 @@ import com.example.components.LineChart;
|
||||
import com.example.components.PieChart;
|
||||
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.HasDynamicTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Route("")
|
||||
@PageTitle("Dashboard")
|
||||
public class DashboardView extends VerticalLayout {
|
||||
public class DashboardView extends VerticalLayout implements HasDynamicTitle {
|
||||
|
||||
public DashboardView() {
|
||||
addClassName("dialect-content");
|
||||
|
||||
List<String> months = List.of(
|
||||
getTranslation("month.jan"), getTranslation("month.feb"),
|
||||
getTranslation("month.mar"), getTranslation("month.apr"),
|
||||
getTranslation("month.may"), getTranslation("month.jun"));
|
||||
|
||||
LineChart lineChart = new LineChart();
|
||||
lineChart.setWidthFull();
|
||||
lineChart.setHeight("400px");
|
||||
lineChart.setData("Umsatz 2026",
|
||||
lineChart.setData(getTranslation("chart.revenueSeries"),
|
||||
List.of(30.0, 40.0, 35.0, 50.0, 49.0, 60.0),
|
||||
List.of("Jan", "Feb", "Mär", "Apr", "Mai", "Jun"));
|
||||
months);
|
||||
lineChart.addPointClickListener(e -> {
|
||||
Notification.show("Serie %d, Punkt %d"
|
||||
.formatted(e.getSeriesIndex(), e.getDataPointIndex()));
|
||||
Notification.show(getTranslation("chart.pointClick",
|
||||
e.getSeriesIndex(), e.getDataPointIndex()));
|
||||
});
|
||||
|
||||
BarChart barChart = new BarChart();
|
||||
barChart.setWidthFull();
|
||||
barChart.setHeight("400px");
|
||||
barChart.setData("Umsatz 2026",
|
||||
barChart.setData(getTranslation("chart.revenueSeries"),
|
||||
List.of(30.0, 40.0, 35.0, 50.0, 49.0, 60.0),
|
||||
List.of("Jan", "Feb", "Mär", "Apr", "Mai", "Jun"));
|
||||
months);
|
||||
barChart.addPointClickListener(e -> {
|
||||
Notification.show("Serie %d, Punkt %d"
|
||||
.formatted(e.getSeriesIndex(), e.getDataPointIndex()));
|
||||
Notification.show(getTranslation("chart.pointClick",
|
||||
e.getSeriesIndex(), e.getDataPointIndex()));
|
||||
});
|
||||
|
||||
PieChart pieChart = new PieChart();
|
||||
@@ -45,13 +49,19 @@ public class DashboardView extends VerticalLayout {
|
||||
pieChart.setHeight("400px");
|
||||
pieChart.setData(
|
||||
List.of(30.0, 40.0, 35.0, 50.0),
|
||||
List.of("Nord", "Süd", "Ost", "West"));
|
||||
List.of(getTranslation("region.north"), getTranslation("region.south"),
|
||||
getTranslation("region.east"), getTranslation("region.west")));
|
||||
pieChart.addPointClickListener(e -> {
|
||||
Notification.show("Slice %d".formatted(e.getDataPointIndex()));
|
||||
Notification.show(getTranslation("chart.sliceClick", e.getDataPointIndex()));
|
||||
});
|
||||
|
||||
add(new Card("Umsatz-Entwicklung", lineChart),
|
||||
new Card("Umsatz nach Monat", barChart),
|
||||
new Card("Umsatz nach Region", pieChart));
|
||||
add(new Card(getTranslation("card.revenueTrend"), lineChart),
|
||||
new Card(getTranslation("card.revenueByMonth"), barChart),
|
||||
new Card(getTranslation("card.revenueByRegion"), pieChart));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPageTitle() {
|
||||
return getTranslation("page.dashboard");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ 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.HasDynamicTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
@@ -33,30 +33,34 @@ import java.util.Locale;
|
||||
* to {@link Registration} via {@link Binder}.
|
||||
*/
|
||||
@Route("formular")
|
||||
@PageTitle("Formular")
|
||||
public class FormView extends VerticalLayout {
|
||||
public class FormView extends VerticalLayout implements HasDynamicTitle {
|
||||
|
||||
private final Binder<Registration> binder = new Binder<>(Registration.class);
|
||||
|
||||
public FormView() {
|
||||
addClassName("dialect-content");
|
||||
add(new Card("Registrierung", buildForm()));
|
||||
add(new Card(getTranslation("card.registration"), buildForm()));
|
||||
//<theme-editor-local-classname>
|
||||
addClassName("form-view-vertical-layout-1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPageTitle() {
|
||||
return getTranslation("page.form");
|
||||
}
|
||||
|
||||
private Component buildForm() {
|
||||
TextField vorname = new TextField("Vorname");
|
||||
TextField vorname = new TextField(getTranslation("form.firstName"));
|
||||
vorname.setAutofocus(true);
|
||||
TextField nachname = new TextField("Nachname");
|
||||
EmailField email = new EmailField("E-Mail");
|
||||
PasswordField passwort = new PasswordField("Passwort");
|
||||
TextField nachname = new TextField(getTranslation("form.lastName"));
|
||||
EmailField email = new EmailField(getTranslation("form.email"));
|
||||
PasswordField passwort = new PasswordField(getTranslation("form.password"));
|
||||
//<theme-editor-local-classname>
|
||||
passwort.addClassName("form-view-password-field-1");
|
||||
IntegerField alter = new IntegerField("Alter");
|
||||
IntegerField alter = new IntegerField(getTranslation("form.age"));
|
||||
alter.setReadOnly(true);
|
||||
BigDecimalField gehalt = new BigDecimalField("Gehalt (€)");
|
||||
DatePicker geburtsdatum = new DatePicker("Geburtsdatum");
|
||||
BigDecimalField gehalt = new BigDecimalField(getTranslation("form.salary"));
|
||||
DatePicker geburtsdatum = new DatePicker(getTranslation("form.birthdate"));
|
||||
geburtsdatum.setLocale(Locale.GERMANY);
|
||||
|
||||
DateFormatSymbols symbols = new DateFormatSymbols(Locale.GERMANY);
|
||||
@@ -69,44 +73,48 @@ vorname.setAutofocus(true);
|
||||
.setWeekdays(wochentage)
|
||||
.setWeekdaysShort(wochentageKurz)
|
||||
.setFirstDayOfWeek(1)
|
||||
.setToday("Heute")
|
||||
.setCancel("Abbrechen"));
|
||||
TimePicker uhrzeit = new TimePicker("Bevorzugte Uhrzeit");
|
||||
.setToday(getTranslation("form.today"))
|
||||
.setCancel(getTranslation("form.cancel")));
|
||||
TimePicker uhrzeit = new TimePicker(getTranslation("form.time"));
|
||||
|
||||
ComboBox<String> land = new ComboBox<>("Land");
|
||||
land.setItems("Deutschland", "Österreich", "Schweiz", "Frankreich", "Niederlande");
|
||||
ComboBox<String> land = new ComboBox<>(getTranslation("form.country"));
|
||||
land.setItems(getTranslation("country.de"), getTranslation("country.at"),
|
||||
getTranslation("country.ch"), getTranslation("country.fr"), getTranslation("country.nl"));
|
||||
|
||||
Select<String> abteilung = new Select<>();
|
||||
abteilung.setLabel("Abteilung");
|
||||
abteilung.setItems("Vertrieb", "Marketing", "Entwicklung", "Support", "Geschäftsführung");
|
||||
abteilung.setLabel(getTranslation("form.department"));
|
||||
abteilung.setItems(getTranslation("dept.sales"), getTranslation("dept.marketing"),
|
||||
getTranslation("dept.dev"), getTranslation("dept.support"), getTranslation("dept.management"));
|
||||
|
||||
CheckboxGroup<String> interessen = new CheckboxGroup<>();
|
||||
interessen.setLabel("Interessen");
|
||||
interessen.setItems("Newsletter-Themen", "Webinare", "Produkt-Updates", "Events");
|
||||
interessen.setLabel(getTranslation("form.interests"));
|
||||
interessen.setItems(getTranslation("interest.newsletter"), getTranslation("interest.webinars"),
|
||||
getTranslation("interest.updates"), getTranslation("interest.events"));
|
||||
|
||||
RadioButtonGroup<String> geschlecht = new RadioButtonGroup<>();
|
||||
geschlecht.setLabel("Anrede");
|
||||
geschlecht.setItems("Frau", "Herr", "Divers", "Keine Angabe");
|
||||
geschlecht.setLabel(getTranslation("form.salutation"));
|
||||
geschlecht.setItems(getTranslation("salutation.mrs"), getTranslation("salutation.mr"),
|
||||
getTranslation("salutation.diverse"), getTranslation("salutation.none"));
|
||||
|
||||
Checkbox newsletter = new Checkbox("Newsletter abonnieren");
|
||||
Checkbox newsletter = new Checkbox(getTranslation("form.newsletter"));
|
||||
|
||||
TextArea bemerkung = new TextArea("Bemerkung");
|
||||
TextArea bemerkung = new TextArea(getTranslation("form.remark"));
|
||||
bemerkung.setMaxLength(500);
|
||||
|
||||
binder.forField(vorname)
|
||||
.asRequired("Vorname wird benötigt")
|
||||
.asRequired(getTranslation("valid.firstNameRequired"))
|
||||
.bind(Registration::getVorname, Registration::setVorname);
|
||||
binder.forField(nachname)
|
||||
.asRequired("Nachname wird benötigt")
|
||||
.asRequired(getTranslation("valid.lastNameRequired"))
|
||||
.bind(Registration::getNachname, Registration::setNachname);
|
||||
binder.forField(email)
|
||||
.asRequired("E-Mail wird benötigt")
|
||||
.withValidator(new EmailValidator("Ungültige E-Mail-Adresse"))
|
||||
.asRequired(getTranslation("valid.emailRequired"))
|
||||
.withValidator(new EmailValidator(getTranslation("valid.emailInvalid")))
|
||||
.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))
|
||||
.withValidator(new IntegerRangeValidator(getTranslation("valid.ageRange"), 0, 120))
|
||||
.bind(Registration::getAlter, Registration::setAlter);
|
||||
binder.forField(gehalt)
|
||||
.bind(Registration::getGehalt, Registration::setGehalt);
|
||||
@@ -143,20 +151,20 @@ vorname.setAutofocus(true);
|
||||
formLayout.setColspan(bemerkung, 2);
|
||||
formLayout.add(interessen, geschlecht, newsletter, bemerkung);
|
||||
|
||||
Button speichern = new Button("Speichern", e -> {
|
||||
Button speichern = new Button(getTranslation("form.save"), e -> {
|
||||
Registration ziel = new Registration();
|
||||
if (binder.writeBeanIfValid(ziel)) {
|
||||
Notification erfolg = Notification.show(
|
||||
"Gespeichert: %s %s".formatted(ziel.getVorname(), ziel.getNachname()));
|
||||
getTranslation("notify.saved", ziel.getVorname(), ziel.getNachname()));
|
||||
erfolg.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
||||
} else {
|
||||
Notification fehler = Notification.show("Bitte Eingaben prüfen");
|
||||
Notification fehler = Notification.show(getTranslation("notify.checkInput"));
|
||||
fehler.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||
}
|
||||
});
|
||||
speichern.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
|
||||
Button zuruecksetzen = new Button("Zurücksetzen",
|
||||
Button zuruecksetzen = new Button(getTranslation("form.reset"),
|
||||
e -> binder.readBean(new Registration()));
|
||||
|
||||
HorizontalLayout buttons = new HorizontalLayout(speichern, zuruecksetzen);
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package com.example.views;
|
||||
|
||||
import com.example.js.CommonJS;
|
||||
import com.vaadin.flow.component.UI;
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.applayout.DrawerToggle;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.menubar.MenuBar;
|
||||
import com.vaadin.flow.component.menubar.MenuBarVariant;
|
||||
import com.vaadin.flow.component.sidenav.SideNav;
|
||||
import com.vaadin.flow.component.sidenav.SideNavItem;
|
||||
import com.vaadin.flow.router.Layout;
|
||||
import com.vaadin.flow.server.VaadinSession;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Layout
|
||||
public class MainLayout extends AppLayout {
|
||||
@@ -19,32 +25,53 @@ public class MainLayout extends AppLayout {
|
||||
public MainLayout() {
|
||||
DrawerToggle toggle = new DrawerToggle();
|
||||
|
||||
Span title = new Span("Chart App");
|
||||
Span title = new Span(getTranslation("app.title"));
|
||||
title.addClassName("dialect-title");
|
||||
|
||||
Span spacer = new Span();
|
||||
spacer.getStyle().set("flex-grow", "1");
|
||||
|
||||
MenuBar languageMenu = buildLanguageMenu();
|
||||
|
||||
themeToggle.addThemeVariants(ButtonVariant.TERTIARY, ButtonVariant.LUMO_ICON);
|
||||
themeToggle.setAriaLabel("Farbschema wechseln");
|
||||
themeToggle.setAriaLabel(getTranslation("action.themeToggle"));
|
||||
themeToggle.addClickListener(e ->
|
||||
getElement().executeJs(CommonJS.TOGGLE_THEME_JS).then(String.class, this::applyIconFor));
|
||||
|
||||
addToNavbar(toggle, title, spacer, themeToggle);
|
||||
addToNavbar(toggle, title, spacer, languageMenu, themeToggle);
|
||||
|
||||
getElement().executeJs(CommonJS.INIT_THEME_JS).then(String.class, this::applyIconFor);
|
||||
|
||||
SideNav nav = new SideNav();
|
||||
nav.addItem(new SideNavItem("Dashboard", DashboardView.class,
|
||||
nav.addItem(new SideNavItem(getTranslation("nav.dashboard"), DashboardView.class,
|
||||
VaadinIcon.DASHBOARD.create()));
|
||||
nav.addItem(new SideNavItem("Formular", FormView.class,
|
||||
nav.addItem(new SideNavItem(getTranslation("nav.form"), FormView.class,
|
||||
VaadinIcon.FORM.create()));
|
||||
nav.addItem(new SideNavItem("Tabelle", TableView.class,
|
||||
nav.addItem(new SideNavItem(getTranslation("nav.table"), TableView.class,
|
||||
VaadinIcon.TABLE.create()));
|
||||
|
||||
addToDrawer(nav);
|
||||
}
|
||||
|
||||
private MenuBar buildLanguageMenu() {
|
||||
MenuBar menuBar = new MenuBar();
|
||||
menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE);
|
||||
|
||||
var root = menuBar.addItem(VaadinIcon.GLOBE_WIRE.create());
|
||||
root.setAriaLabel(getTranslation("action.language"));
|
||||
|
||||
root.getSubMenu().addItem(getTranslation("lang.de"), e -> switchLanguage(Locale.GERMAN));
|
||||
root.getSubMenu().addItem(getTranslation("lang.en"), e -> switchLanguage(Locale.ENGLISH));
|
||||
root.getSubMenu().addItem(getTranslation("lang.es"), e -> switchLanguage(Locale.of("es")));
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
||||
private void switchLanguage(Locale locale) {
|
||||
VaadinSession.getCurrent().setLocale(locale);
|
||||
UI.getCurrent().getPage().reload();
|
||||
}
|
||||
|
||||
private void applyIconFor(String theme) {
|
||||
themeToggle.setIcon("dark".equals(theme) ? VaadinIcon.SUN_O.create() : VaadinIcon.MOON.create());
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.HasDynamicTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
@@ -19,8 +19,7 @@ import java.util.Locale;
|
||||
* live text filter across all columns.
|
||||
*/
|
||||
@Route("tabelle")
|
||||
@PageTitle("Tabelle")
|
||||
public class TableView extends VerticalLayout {
|
||||
public class TableView extends VerticalLayout implements HasDynamicTitle {
|
||||
|
||||
private record Mitarbeiter(String name, String abteilung, String stadt, double gehalt) {
|
||||
}
|
||||
@@ -45,7 +44,7 @@ public class TableView extends VerticalLayout {
|
||||
addClassName("dialect-content");
|
||||
|
||||
TextField suche = new TextField();
|
||||
suche.setPlaceholder("Suchen…");
|
||||
suche.setPlaceholder(getTranslation("table.search"));
|
||||
suche.setPrefixComponent(VaadinIcon.SEARCH.create());
|
||||
suche.setClearButtonVisible(true);
|
||||
suche.setValueChangeMode(ValueChangeMode.EAGER);
|
||||
@@ -53,10 +52,10 @@ public class TableView extends VerticalLayout {
|
||||
|
||||
Grid<Mitarbeiter> grid = new Grid<>();
|
||||
grid.setWidthFull();
|
||||
grid.addColumn(Mitarbeiter::name).setHeader("Name").setSortable(true);
|
||||
grid.addColumn(Mitarbeiter::abteilung).setHeader("Abteilung").setSortable(true);
|
||||
grid.addColumn(Mitarbeiter::stadt).setHeader("Stadt").setSortable(true);
|
||||
grid.addColumn(m -> GEHALT_FORMAT.format(m.gehalt())).setHeader("Gehalt (€)").setSortable(true);
|
||||
grid.addColumn(Mitarbeiter::name).setHeader(getTranslation("col.name")).setSortable(true);
|
||||
grid.addColumn(Mitarbeiter::abteilung).setHeader(getTranslation("col.department")).setSortable(true);
|
||||
grid.addColumn(Mitarbeiter::stadt).setHeader(getTranslation("col.city")).setSortable(true);
|
||||
grid.addColumn(m -> GEHALT_FORMAT.format(m.gehalt())).setHeader(getTranslation("col.salary")).setSortable(true);
|
||||
|
||||
GridListDataView<Mitarbeiter> dataView = grid.setItems(MITARBEITER);
|
||||
suche.addValueChangeListener(e -> dataView.refreshAll());
|
||||
@@ -66,7 +65,12 @@ public class TableView extends VerticalLayout {
|
||||
content.setPadding(false);
|
||||
content.setSpacing(true);
|
||||
|
||||
add(new Card("Mitarbeiter", content));
|
||||
add(new Card(getTranslation("card.employees"), content));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPageTitle() {
|
||||
return getTranslation("page.table");
|
||||
}
|
||||
|
||||
private static boolean matches(Mitarbeiter mitarbeiter, String filter) {
|
||||
|
||||
Reference in New Issue
Block a user