Compare commits

..

2 Commits

Author SHA1 Message Date
pitfriedrich e477bbcc1f Merge pull request '[FEATURE] FontAwesome Icons' (#6) from feature/icons into main
Reviewed-on: #6
2026-07-19 21:41:08 +00:00
Pit Friedrich aca411ca9e [FEATURE] FontAwesome Icons
CI / build-and-test (pull_request) Successful in 1m9s
2026-07-19 23:39:10 +02:00
8 changed files with 74 additions and 11 deletions
+10
View File
@@ -7,6 +7,7 @@
"name": "no-name", "name": "no-name",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "6.7.2",
"@vaadin/aura": "25.2.0", "@vaadin/aura": "25.2.0",
"@vaadin/common-frontend": "0.0.22", "@vaadin/common-frontend": "0.0.22",
"@vaadin/react-components": "25.2.0", "@vaadin/react-components": "25.2.0",
@@ -1754,6 +1755,15 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/@fortawesome/fontawesome-free": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz",
"integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==",
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": {
"node": ">=6"
}
},
"node_modules/@jridgewell/gen-mapping": { "node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13", "version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+6 -2
View File
@@ -3,6 +3,7 @@
"license": "UNLICENSED", "license": "UNLICENSED",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "6.7.2",
"@vaadin/aura": "25.2.0", "@vaadin/aura": "25.2.0",
"@vaadin/common-frontend": "0.0.22", "@vaadin/common-frontend": "0.0.22",
"@vaadin/react-components": "25.2.0", "@vaadin/react-components": "25.2.0",
@@ -49,6 +50,7 @@
}, },
"vaadin": { "vaadin": {
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "6.7.2",
"@vaadin/aura": "25.2.0", "@vaadin/aura": "25.2.0",
"@vaadin/common-frontend": "0.0.22", "@vaadin/common-frontend": "0.0.22",
"@vaadin/react-components": "25.2.0", "@vaadin/react-components": "25.2.0",
@@ -93,8 +95,9 @@
"workbox-routing": "7.4.1", "workbox-routing": "7.4.1",
"workbox-strategies": "7.4.1" "workbox-strategies": "7.4.1"
}, },
"hash": "c759239a4f6d12f111d0cab12fe3ce6fdb558c5f8e2a3f33425bcfb33577e99b", "hash": "54350847a380a8c1b6cc526f6f7eff8dd9253d848e38919e7e1b633cec9f3aca",
"overrides": { "overrides": {
"@fortawesome/fontawesome-free": "$@fortawesome/fontawesome-free",
"@vaadin/a11y-base": "25.2.0", "@vaadin/a11y-base": "25.2.0",
"@vaadin/accordion": "25.2.0", "@vaadin/accordion": "25.2.0",
"@vaadin/app-layout": "25.2.0", "@vaadin/app-layout": "25.2.0",
@@ -273,6 +276,7 @@
"workbox-build": { "workbox-build": {
"glob": "13.0.6" "glob": "13.0.6"
}, },
"apexcharts": "$apexcharts" "apexcharts": "$apexcharts",
"@fortawesome/fontawesome-free": "$@fortawesome/fontawesome-free"
} }
} }
Binary file not shown.
@@ -4,6 +4,8 @@ import com.vaadin.flow.theme.aura.Aura;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.dependency.StyleSheet; import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.page.AppShellConfigurator; import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.component.page.Push; import com.vaadin.flow.component.page.Push;
@@ -12,6 +14,8 @@ import com.vaadin.flow.server.PWA;
@SpringBootApplication @SpringBootApplication
@StyleSheet(Aura.STYLESHEET) @StyleSheet(Aura.STYLESHEET)
@StyleSheet("styles.css") // Your custom styles @StyleSheet("styles.css") // Your custom styles
@NpmPackage(value = "@fortawesome/fontawesome-free", version = "6.7.2")
@CssImport("@fortawesome/fontawesome-free/css/all.min.css")
@Push @Push
@PWA(name = "Dialect Charts", shortName = "Dialect", offlinePath = "offline.html") @PWA(name = "Dialect Charts", shortName = "Dialect", offlinePath = "offline.html")
public class Application implements AppShellConfigurator { public class Application implements AppShellConfigurator {
@@ -0,0 +1,34 @@
package com.example.components;
import com.vaadin.flow.component.icon.FontIcon;
/**
* Font Awesome Free icon references, mirroring the ergonomics of
* {@code VaadinIcon.create()}. Backed by the {@code fa-*} CSS classes
* shipped in the bundled {@code @fortawesome/fontawesome-free} package.
*
* <p>Font Awesome paints glyphs via {@code content: var(--fa)} on
* {@code ::before}; the glyph-specific class (e.g. {@code fa-sun}) is what
* defines that {@code --fa} custom property, so both the family class
* ({@code fa-solid}) and the glyph class must be present.
*/
public enum Fa {
MOON("fa-solid", "fa-moon"),
SUN("fa-solid", "fa-sun"),
DASHBOARD("fa-solid", "fa-gauge-high"),
FORM("fa-solid", "fa-rectangle-list"),
TABLE("fa-solid", "fa-table"),
GLOBE("fa-solid", "fa-globe"),
SEARCH("fa-solid", "fa-magnifying-glass");
private final String[] classes;
Fa(String... classes) {
this.classes = classes;
}
public FontIcon create() {
return new FontIcon(classes);
}
}
@@ -1,5 +1,6 @@
package com.example.views; package com.example.views;
import com.example.components.Fa;
import com.example.js.CommonJS; import com.example.js.CommonJS;
import com.vaadin.flow.component.UI; import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.applayout.AppLayout; import com.vaadin.flow.component.applayout.AppLayout;
@@ -7,7 +8,6 @@ import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.Span; 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.MenuBar;
import com.vaadin.flow.component.menubar.MenuBarVariant; import com.vaadin.flow.component.menubar.MenuBarVariant;
import com.vaadin.flow.component.sidenav.SideNav; import com.vaadin.flow.component.sidenav.SideNav;
@@ -20,7 +20,7 @@ import java.util.Locale;
@Layout @Layout
public class MainLayout extends AppLayout { public class MainLayout extends AppLayout {
private final Button themeToggle = new Button(VaadinIcon.MOON.create()); private final Button themeToggle = new Button(Fa.MOON.create());
public MainLayout() { public MainLayout() {
DrawerToggle toggle = new DrawerToggle(); DrawerToggle toggle = new DrawerToggle();
@@ -44,11 +44,11 @@ public class MainLayout extends AppLayout {
SideNav nav = new SideNav(); SideNav nav = new SideNav();
nav.addItem(new SideNavItem(getTranslation("nav.dashboard"), DashboardView.class, nav.addItem(new SideNavItem(getTranslation("nav.dashboard"), DashboardView.class,
VaadinIcon.DASHBOARD.create())); Fa.DASHBOARD.create()));
nav.addItem(new SideNavItem(getTranslation("nav.form"), FormView.class, nav.addItem(new SideNavItem(getTranslation("nav.form"), FormView.class,
VaadinIcon.FORM.create())); Fa.FORM.create()));
nav.addItem(new SideNavItem(getTranslation("nav.table"), TableView.class, nav.addItem(new SideNavItem(getTranslation("nav.table"), TableView.class,
VaadinIcon.TABLE.create())); Fa.TABLE.create()));
addToDrawer(nav); addToDrawer(nav);
} }
@@ -57,7 +57,7 @@ public class MainLayout extends AppLayout {
MenuBar menuBar = new MenuBar(); MenuBar menuBar = new MenuBar();
menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE); menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE);
var root = menuBar.addItem(VaadinIcon.GLOBE_WIRE.create()); var root = menuBar.addItem(Fa.GLOBE.create());
root.setAriaLabel(getTranslation("action.language")); root.setAriaLabel(getTranslation("action.language"));
root.getSubMenu().addItem(getTranslation("lang.de"), e -> switchLanguage(Locale.GERMAN)); root.getSubMenu().addItem(getTranslation("lang.de"), e -> switchLanguage(Locale.GERMAN));
@@ -73,6 +73,6 @@ public class MainLayout extends AppLayout {
} }
private void applyIconFor(String theme) { private void applyIconFor(String theme) {
themeToggle.setIcon("dark".equals(theme) ? VaadinIcon.SUN_O.create() : VaadinIcon.MOON.create()); themeToggle.setIcon("dark".equals(theme) ? Fa.SUN.create() : Fa.MOON.create());
} }
} }
@@ -1,9 +1,9 @@
package com.example.views; package com.example.views;
import com.example.components.Card; import com.example.components.Card;
import com.example.components.Fa;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.dataview.GridListDataView; import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.data.value.ValueChangeMode;
@@ -45,7 +45,7 @@ public class TableView extends VerticalLayout implements HasDynamicTitle {
TextField suche = new TextField(); TextField suche = new TextField();
suche.setPlaceholder(getTranslation("table.search")); suche.setPlaceholder(getTranslation("table.search"));
suche.setPrefixComponent(VaadinIcon.SEARCH.create()); suche.setPrefixComponent(Fa.SEARCH.create());
suche.setClearButtonVisible(true); suche.setClearButtonVisible(true);
suche.setValueChangeMode(ValueChangeMode.EAGER); suche.setValueChangeMode(ValueChangeMode.EAGER);
suche.setWidthFull(); suche.setWidthFull();
@@ -63,6 +63,17 @@
border-style: solid; border-style: solid;
} }
/* Icon-only buttons (e.g. theme toggle): Font Awesome's icon-font metrics give
the button's label part an inflated line box, growing the button and pushing
the icon toward the top instead of centering it. Vaadin SVG icons didn't hit
this because they don't route through font line-height at all. */
vaadin-button[theme~="icon"]::part(label) {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
/* Top bar: solid white, opaque, divider + soft shadow below. /* Top bar: solid white, opaque, divider + soft shadow below.
Separates it from the sidebar/content instead of blending into one surface. */ Separates it from the sidebar/content instead of blending into one surface. */
vaadin-app-layout::part(navbar) { vaadin-app-layout::part(navbar) {