34
Standard-
Komponenten
VerticalLayout layout = new VerticalLayout();
TextField userName = new TextField();
userName.setCaption("Benutzername");
userName.setValue("Alex");
userName.addValueChangeListener(e -> profile.setName(e.getValue()));
layout.addComponent(userName);
ProfileView.java
GradeTopic
+ name: String
+ description: String
+ sectionWhys: String
GradeRating
+ Responsibility: {Team, SingleDev}
+ evolvability: Int
+ correctness: String
Collection<GradeTopic> gradeTopics = loadData();
Grid<GradeTopic> table = new Grid<>();
table.setItems(gradeTopics);
table.addColumn(GradeTopic::getName)
.setHeader(getTranslation("grade.name"))
.setSortable(true).setAutoWidth(true);
table.addColumn(this::formatTopic)
.setHeader(getTranslation("grade.grade"))
.setSortable(true).setAutoWidth(true);
table.addColumn(topic -> topic.getGradeRating().getResponsibility()
.setHeader(getTranslation("grade.rating.responsibility"))
.setSortable(true).setAutoWidth(true);
table.sort(List.of(new GridSortOrder<>(columnName, ASCENDING)));
table.addSelectionListener(event -> event.getFirstSelectedItem()
.ifPresent(this::openGradeTopic));
CompendiumView.java
https://vaadin.com/designer
Anchor Article Aside Description DescriptionList Div Emphasis Footer H1 H2
H3 H4 H5 H6 Header Image Label ListItem Main
NativeButton Nav OrderedList Paragraph Pre Section Span Term UnorderedList
HtmlContainer
public class GradeProgressBar extends FlexLayout {
public GradeProgressBar() {
setWidthFull();
setJustifyContentMode(JustifyContentMode.EVENLY);
setAlignItems(Alignment.END);
addClassName("grade-progress");
}
public void setDays(List<ProgressDay> days) {
days.forEach(this::add);
}
}
GradeProgressBar : FlexLayout
ProgressDay : Div
Span
public static class ProgressDay extends Div {
public ProgressDay(String tooltip) {
addClassName("grade-progress-day");
addToolTip(tooltip);
}
public void setDaySubmitted() {
addClassName("day-submitted");
}
public void setDayInFuture() {
addClassName("day-future");
}
private void addToolTip(String tooltip) {
addClassName("tooltip");
Span span = new Span(tooltip);
span.addClassName("tooltiptext");
span.addClassName("tooltip-bottom");
add(span);
}
}
.grade-progress {
height: 45px;
}
.grade-progress-day {
background-color: grey;
color: grey;
width: 10px;
height: 40px;
transition: border-top 0.8s;
top: 0;
bottom: 0;
}
.grade-progress-day:hover {
border-top: solid currentColor 10px;
}
.day-submitted {
background-color: green;
}
.day-future {
background-color: black;
}
content.add(new Html(getTranslation("about.info")));
content.add(new Html(getTranslation("about.info.technical")));
about.info = <p>Hast du schon einmal versucht den Weg eines <a href="https://clean-code-developer.de/" target="blank">Clean Code Developers</a> zu gehen und den weißen grad zu meistern? Diese Webapp hilft Dir diesen Weg einzuhalten und erinnert dich an deine aktuellen Ziele. Logge deinen Fortschritt und bekomme Belohnungen für deine erreichten Ziele 🏆.</p>
about.info.technical = <p>Dieses Projekt ist eine Beispielapplikation für eine <a href="https://vaadin.com/" target="blank">Vaadin 14</a> Porgressive Web App. Es nutzt <a href="https://spring.io/projects/spring-boot" target="blank">Spring Boot</a> und läuft auf <a href="https://www.oracle.com/technetwork/java/javase/12-relnote-issues-5211422.html" target="blank">Java 12</a>. Diese Demo löscht alle Nutzerdaten sobald die Session verloren geht.</p>
Benutzerdefinierte Elemente
HTML-Vorlagen
Shadow DOM
Polymer WebComponent - l2t-paper-color
developer.mozilla.org/de/docs/Web/Web_Components
web components library
web components library
Polymer 2.0
05.2017
Polymer 3.0
01.2018
LitElement
02.2019
import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';
class MyElement extends PolymerElement {
static get template() {
return html`
<style> .mood { color: orange; } </style>
<h2>Web Components are <span class="mood">[[message]]</span>!</h2>
`;
}
static get properties() { return { message: String }}
}
customElements.define('my-element', MyElement);
import {html, PolymerElement} from '@polymer/polymer/polymer-element.js';
import '@polymer/iron-icon/iron-icon';
import '@vaadin/vaadin-material-styles/color';
class LogEntry extends PolymerElement {
static get template() {
return html`<style>
#logentry {
width: 380px;
}
#header {
display: flex;
}
#title {
flex-grow: 1;
}
#username {
font-size: 18px;
}
#grade {
font-size: 16px;
line-height: 10px;
}
#date {
color: gray;
align-self: flex-end;
}
#content-head {
display: flex;
justify-content: space-between;
}
#experience {
display: flex;
align-self: flex-end;
}
#xp {
color: #22C4FA;
margin-left: 8px;
font-size: 18px;
}
#skill-points {
color: #20E87B;
}
#topic {
font-size: 18px;
}
#content {
display: flex;
flex-direction: column;
background-color: var(--material-secondary-background-color);
border-radius: 5px;
padding: 5px;
}
#actions {
align-self: flex-end;
}
#avatar{
margin-right: 5px;
}
iron-icon.avatar {
--iron-icon-height: 38px;
--iron-icon-width: 38px;
}
iron-icon.type {
--iron-icon-height: 18px;
--iron-icon-width: 18px;
}
iron-icon.action {
--iron-icon-height: 22px;
--iron-icon-width: 22px;
}
</style>
<div id="logentry">
<div id="header">
<div id="avatar">
<iron-icon class="avatar" icon="vaadin:user"></iron-icon>
</div>
<div id="title">
<div id="username">[[username]]</div>
<div id="grade">[[grade]]</div>
</div>
<div id="date">[[date]]</div>
</div>
<div id="content">
<div id="content-head">
<div id="topic">[[topic]]</div>
<div id="type">
<iron-icon class="type" icon="[[typeicon]]"></iron-icon>
</div>
</div>
<div id="comment">[[comment]]</div>
<div id="experience">
<div id="skill-points">[[skills]]</div>
<div id="xp">[[experience]]</div>
</div>
<div id="actions">
<iron-icon class="action" icon="vaadin:close-small"></iron-icon>
<iron-icon class="action" icon="vaadin:comment"></iron-icon>
<iron-icon class="action" icon="vaadin:pencil"></iron-icon></div>
</div>
</div>`;
}
static get is() {
return 'log-entry';
}
}
customElements.define(LogEntry.is, LogEntry);
@Tag("log-entry")
@JsModule("./src/log-entry.js")
public class LogEntryComponent extends PolymerTemplate<LogEntryModel> {
public LogEntryComponent() {
setId("logentry");
}
@Override
public LogEntryModel getModel() {
return super.getModel();
}
}
public interface LogEntryModel extends TemplateModel {
String getTypeicon();
void setTypeicon(String typeicon);
String getSkills();
void setSkills(String skills);
String getTopic();
void setTopic(String topic);
String getGrade();
void setGrade(String grade);
String getExperience();
void setExperience(String experience);
String getComment();
void setComment(String comment);
String getUsername();
void setUsername(String username);
String getDate();
void setDate(String date);
}
private void addLogEntry(LogEntry logEntry) {
var logEntryComponent = new LogEntryComponent();
LogEntryModel logEntryModel = logEntryComponent.getModel();
logEntryModel.setComment(logEntry.getComment());
logEntryModel.setUsername(logEntry.getName());
parent.add(logEntryComponent);
}
JournalView.java
@Tag("paper-fab-speed-dial")
@NpmPackage(value = "@cwmr/paper-fab-speed-dial", version = "3.0.0")
@JsModule("@cwmr/paper-fab-speed-dial/paper-fab-speed-dial.js")
public class SpeedDial extends Component implements HasEnabled {
public SpeedDialAction addMenuItem(String item, Icon icon) {
SpeedDialAction speedDialAction = new SpeedDialAction(item, icon);
getElement().appendChild(speedDialAction.getElement());
return speedDialAction;
}
public SpeedDialAction addMenuItem(String item, Icon icon,
ComponentEventListener<SpeedDialAction.ClickEvent> listener) {
SpeedDialAction speedDialAction = addMenuItem(item, icon);
speedDialAction.addClickListener(listener);
return speedDialAction;
}
@Synchronize("opened-changed")
public boolean isOpened() {
return getElement().getProperty("opened", false);
}
public void setBackdrop(boolean backdrop) {
if (backdrop) {
getElement().setAttribute("with-backdrop", EMPTY);
} else {
getElement().removeAttribute("with-backdrop");
}
}
public void close() {
getElement().setProperty("opened", false);
}
public void open() {
getElement().setProperty("opened", true);
}
@Override
public void setEnabled(boolean enabled) {
if (enabled) {
getElement().setAttribute("disabled", "disabled");
} else {
getElement().removeAttribute("disabled");
}
}
public void setColorAction(String color) {
setStyle("--paper-fab-speed-dial-action-background", color);
}
public void setColor(String color) {
setStyle("--paper-fab-speed-dial-background", color);
}
public void setMarginRight(String marginRight) {
setStyle("--paper-fab-speed-dial-right", marginRight);
}
private Style setStyle(String name, String value) {
return getElement().getStyle().set(name, value);
}
}
@Tag("paper-fab-speed-dial-action")
@NpmPackage(value = "@cwmr/paper-fab-speed-dial", version = "3.0.0")
@JsModule("@cwmr/paper-fab-speed-dial/paper-fab-speed-dial-action.js")
public class SpeedDialAction extends Label implements HasEnabled, HasSpeedDialStyle {
public SpeedDialAction(String text, Icon icon) {
super(text);
setIcon(icon);
}
public Element setIcon(Icon icon) {
return getElement().setAttribute("icon", getIconAttribute(icon));
}
public Registration addClickListener(ComponentEventListener<SpeedDialClickEvent> listener) {
return addListener(SpeedDialClickEvent.class, listener);
}
private String getIconAttribute(Icon icon) {
return icon.getElement().getAttribute("icon");
}
}
SpeedDialAction.java
SpeedDial speedDial = new SpeedDial();
speedDial.addMenuItem("Erfolg", VaadinIcon.TROPHY, e -> Notification.show("Clicked E"));
speedDial.addMenuItem("Log", VaadinIcon.NOTEBOOK, e -> Notification.show("Clicked L"));
speedDial.setBackdrop(true);
add(speedDial);
SpeedDialSampleView.java
public void setColorAction(String color) {
setStyle("--paper-fab-speed-dial-action-background", color);
}
SpeedDial speedDial = new SpeedDial();
setColor("var(--material-primary-text-color)");
setColorAction("var(--material-primary-text-color)");
add(speedDial);
SampleCssVar.java
SpeedDial.java
⭐ ServerSide ClickListener
⭐ Setters für alle 11 CSS Properties
⭐ Build in Support für Vaadin Icons
⭐ Vaadin Core - Pro Lizenz nicht erforderlich
Paper Speed Dial
@CssImport("./styles/shared-styles.css")
@Theme(value = Material.class, variant = Lumo.DARK)
@PWA(name = "Clean Code Developer Journal", backgroundColor = "#3B3B3B")
public class MainView extends AppLayout {
public MainView() {
addToNavbar(new DrawerToggle());
addToNavbar(new H4(getTranslation("app.name")));
addToDrawer(createMenuBar());
}
private VerticalLayout createMenuBar() {
RouterLink journal = new RouterLink("Journal", JournalView.class);
RouterLink profile = new RouterLink("Profil", ProfileView.class);
RouterLink achievements = new RouterLink("Erfolge", AchievementsView.class);
RouterLink compendium = new RouterLink("Compendium", CompendiumView.class);
RouterLink about = new RouterLink("Über", AboutView.class);
return new VerticalLayout(journal, profile, achievements, compendium, about);
}
}
MainView.java
Integriert
Mobile & Web
Offlinefähigkeit
Clean-Code.rocks
github.com/TobseF/CleanCodeDeveloperJournal
Clean-Code.rocks
github.com/TobseF/CleanCodeDeveloperJournal