
io.quarkus.devui.deployment.BuildTimeContentProcessor Maven / Gradle / Ivy
package io.quarkus.devui.deployment;
import static java.util.logging.Level.ALL;
import static java.util.logging.Level.CONFIG;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.FINER;
import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.OFF;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import static org.jboss.logmanager.Level.DEBUG;
import static org.jboss.logmanager.Level.ERROR;
import static org.jboss.logmanager.Level.FATAL;
import static org.jboss.logmanager.Level.INFO;
import static org.jboss.logmanager.Level.TRACE;
import static org.jboss.logmanager.Level.WARN;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.mvnpm.importmap.Aggregator;
import org.mvnpm.importmap.Location;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.quarkus.builder.Version;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
import io.quarkus.deployment.util.IoUtil;
import io.quarkus.devui.deployment.extension.Extension;
import io.quarkus.devui.spi.AbstractDevUIBuildItem;
import io.quarkus.devui.spi.DevUIContent;
import io.quarkus.devui.spi.buildtime.QuteTemplateBuildItem;
import io.quarkus.devui.spi.buildtime.StaticContentBuildItem;
import io.quarkus.devui.spi.page.AbstractPageBuildItem;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.FooterPageBuildItem;
import io.quarkus.devui.spi.page.MenuPageBuildItem;
import io.quarkus.devui.spi.page.Page;
import io.quarkus.devui.spi.page.PageBuilder;
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
import io.vertx.core.json.jackson.DatabindCodec;
/**
* This creates static content that is used in dev UI. For example the index.html and any other data (json) available on build
* time
*/
public class BuildTimeContentProcessor {
private static final String SLASH = "/";
private static final String DEV_UI = "dev-ui";
private static final String BUILD_TIME_PATH = "dev-ui-templates/build-time";
final Config config = ConfigProvider.getConfig();
/**
* Here we create references to internal dev ui files so that they can be imported by ref.
* This will be merged into the final importmap
*/
@BuildStep(onlyIf = IsDevelopment.class)
InternalImportMapBuildItem createKnownInternalImportMap(NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {
String contextRoot = nonApplicationRootPathBuildItem.getNonApplicationRootPath() + DEV_UI + SLASH;
InternalImportMapBuildItem internalImportMapBuildItem = new InternalImportMapBuildItem();
internalImportMapBuildItem.add("devui/", contextRoot);
// Quarkus Web Components
internalImportMapBuildItem.add("qwc/", contextRoot + "qwc/");
internalImportMapBuildItem.add("qwc-hot-reload-element", contextRoot + "qwc/qwc-hot-reload-element.js");
internalImportMapBuildItem.add("qwc-server-log", contextRoot + "qwc/qwc-server-log.js");
// Quarkus UI
internalImportMapBuildItem.add("qui/", contextRoot + "qui/");
internalImportMapBuildItem.add("qui-card", contextRoot + "qui/qui-card.js");
internalImportMapBuildItem.add("qui-badge", contextRoot + "qui/qui-badge.js");
internalImportMapBuildItem.add("qui-alert", contextRoot + "qui/qui-alert.js");
internalImportMapBuildItem.add("qui-code-block", contextRoot + "qui/qui-code-block.js");
// Echarts
internalImportMapBuildItem.add("echarts/", contextRoot + "echarts/");
internalImportMapBuildItem.add("echarts-gauge-grade", contextRoot + "echarts/echarts-gauge-grade.js");
internalImportMapBuildItem.add("echarts-pie", contextRoot + "echarts/echarts-pie.js");
internalImportMapBuildItem.add("echarts-horizontal-stacked-bar",
contextRoot + "echarts/echarts-horizontal-stacked-bar.js");
// Other assets
internalImportMapBuildItem.add("icon/", contextRoot + "icon/");
// Controllers
internalImportMapBuildItem.add("controller/", contextRoot + "controller/");
internalImportMapBuildItem.add("log-controller", contextRoot + "controller/log-controller.js");
internalImportMapBuildItem.add("storage-controller", contextRoot + "controller/storage-controller.js");
internalImportMapBuildItem.add("router-controller", contextRoot + "controller/router-controller.js");
internalImportMapBuildItem.add("notifier", contextRoot + "controller/notifier.js");
internalImportMapBuildItem.add("jsonrpc", contextRoot + "controller/jsonrpc.js");
// State
internalImportMapBuildItem.add("state/", contextRoot + "state/");
internalImportMapBuildItem.add("theme-state", contextRoot + "state/theme-state.js");
internalImportMapBuildItem.add("connection-state", contextRoot + "state/connection-state.js");
internalImportMapBuildItem.add("devui-state", contextRoot + "state/devui-state.js");
return internalImportMapBuildItem;
}
/**
* Here we map all the pages (as defined by the extensions) build time data
*
* @param pageBuildItems
* @param buildTimeConstProducer
*/
@BuildStep(onlyIf = IsDevelopment.class)
void mapPageBuildTimeData(List cards,
List menus,
List footers,
CurateOutcomeBuildItem curateOutcomeBuildItem,
BuildProducer buildTimeConstProducer) {
for (CardPageBuildItem card : cards) {
String extensionPathName = card.getExtensionPathName(curateOutcomeBuildItem);
Map buildTimeData = getBuildTimeDataForCard(curateOutcomeBuildItem, card);
if (!buildTimeData.isEmpty()) {
buildTimeConstProducer.produce(
new BuildTimeConstBuildItem(extensionPathName, buildTimeData));
}
}
for (MenuPageBuildItem menu : menus) {
String extensionPathName = menu.getExtensionPathName(curateOutcomeBuildItem);
Map buildTimeData = getBuildTimeDataForPage(menu);
if (!buildTimeData.isEmpty()) {
buildTimeConstProducer.produce(
new BuildTimeConstBuildItem(extensionPathName, buildTimeData));
}
}
for (FooterPageBuildItem footer : footers) {
String extensionPathName = footer.getExtensionPathName(curateOutcomeBuildItem);
Map buildTimeData = getBuildTimeDataForPage(footer);
if (!buildTimeData.isEmpty()) {
buildTimeConstProducer.produce(
new BuildTimeConstBuildItem(extensionPathName, buildTimeData));
}
}
}
private Map getBuildTimeDataForPage(AbstractPageBuildItem pageBuildItem) {
Map m = new HashMap<>();
if (pageBuildItem.hasBuildTimeData()) {
m.putAll(pageBuildItem.getBuildTimeData());
}
return m;
}
private Map getBuildTimeDataForCard(CurateOutcomeBuildItem curateOutcomeBuildItem,
CardPageBuildItem pageBuildItem) {
Map m = getBuildTimeDataForPage(pageBuildItem);
if (pageBuildItem.getOptionalCard().isPresent()) {
// Make the pages available for the custom card
List pages = new ArrayList<>();
List pageBuilders = pageBuildItem.getPages();
for (PageBuilder pageBuilder : pageBuilders) {
String path = pageBuildItem.getExtensionPathName(curateOutcomeBuildItem);
pageBuilder.namespace(path);
pageBuilder.extension(path);
pages.add(pageBuilder.build());
}
m.put("pages", pages);
}
return m;
}
/**
* Here we find all build time data and make then available via a const
*
* js components can import the const with "import {constName} from '{ext}-data';"
*
* @param pageBuildItems
* @param quteTemplateProducer
* @param internalImportMapProducer
*/
@BuildStep(onlyIf = IsDevelopment.class)
void createBuildTimeConstJsTemplate(CurateOutcomeBuildItem curateOutcomeBuildItem,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
List buildTimeConstBuildItems,
BuildProducer quteTemplateProducer,
BuildProducer internalImportMapProducer) {
String contextRoot = nonApplicationRootPathBuildItem.getNonApplicationRootPath() + DEV_UI + SLASH;
QuteTemplateBuildItem quteTemplateBuildItem = new QuteTemplateBuildItem(
QuteTemplateBuildItem.DEV_UI);
InternalImportMapBuildItem internalImportMapBuildItem = new InternalImportMapBuildItem();
for (BuildTimeConstBuildItem buildTimeConstBuildItem : buildTimeConstBuildItems) {
Map data = new HashMap<>();
if (buildTimeConstBuildItem.hasBuildTimeData()) {
for (Map.Entry pageData : buildTimeConstBuildItem.getBuildTimeData().entrySet()) {
try {
String key = pageData.getKey();
String value = DatabindCodec.prettyMapper().writeValueAsString(pageData.getValue());
data.put(key, value);
} catch (JsonProcessingException ex) {
ex.printStackTrace();
}
}
}
if (!data.isEmpty()) {
Map qutedata = new HashMap<>();
qutedata.put("buildTimeData", data);
String ref = buildTimeConstBuildItem.getExtensionPathName(curateOutcomeBuildItem) + "-data";
String file = ref + ".js";
quteTemplateBuildItem.add("build-time-data.js", file, qutedata);
internalImportMapBuildItem.add(ref, contextRoot + file);
}
}
quteTemplateProducer.produce(quteTemplateBuildItem);
internalImportMapProducer.produce(internalImportMapBuildItem);
}
/**
* Here we find all the mvnpm jars
*/
@BuildStep(onlyIf = IsDevelopment.class)
void gatherMvnpmJars(BuildProducer mvnpmProducer, CurateOutcomeBuildItem curateOutcomeBuildItem) {
Set mvnpmJars = new HashSet<>();
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
try {
Enumeration jarsWithImportMaps = tccl.getResources(Location.IMPORTMAP_PATH);
Set jarUrls = new HashSet(Collections.list(jarsWithImportMaps));
for (URL jarUrl : jarUrls) {
final JarURLConnection connection = (JarURLConnection) jarUrl.openConnection();
mvnpmJars.add(connection.getJarFileURL());
}
mvnpmProducer.produce(new MvnpmBuildItem(mvnpmJars));
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
/**
* Here we create index.html
* We aggregate all import maps into one
* This includes import maps from 3rd party libs from mvnpm.org and internal ones defined above
*
* @return The QuteTemplate Build item that will create the end result
*/
@BuildStep(onlyIf = IsDevelopment.class)
QuteTemplateBuildItem createIndexHtmlTemplate(
MvnpmBuildItem mvnpmBuildItem,
ThemeVarsBuildItem themeVarsBuildItem,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
List internalImportMapBuildItems) {
QuteTemplateBuildItem quteTemplateBuildItem = new QuteTemplateBuildItem(
QuteTemplateBuildItem.DEV_UI);
Aggregator aggregator = new Aggregator(mvnpmBuildItem.getMvnpmJars());
for (InternalImportMapBuildItem importMapBuildItem : internalImportMapBuildItems) {
Map importMap = importMapBuildItem.getImportMap();
aggregator.addMappings(importMap);
}
String importmap = aggregator.aggregateAsJson(nonApplicationRootPathBuildItem.getNonApplicationRootPath());
aggregator.reset();
String themeVars = themeVarsBuildItem.getTemplateValue();
String nonApplicationRoot = nonApplicationRootPathBuildItem.getNonApplicationRootPath();
String contextRoot = nonApplicationRoot + DEV_UI + SLASH;
Map data = Map.of(
"nonApplicationRoot", nonApplicationRoot,
"contextRoot", contextRoot,
"importmap", importmap,
"themeVars", themeVars);
quteTemplateBuildItem.add("index.html", data);
return quteTemplateBuildItem;
}
// Here load all templates
@BuildStep(onlyIf = IsDevelopment.class)
void loadAllBuildTimeTemplates(BuildProducer buildTimeContentProducer,
List templates) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
for (QuteTemplateBuildItem template : templates) {
List contentPerExtension = new ArrayList<>();
List templatesWithData = template.getTemplateDatas();
for (QuteTemplateBuildItem.TemplateData e : templatesWithData) {
String templateName = e.getTemplateName(); // Relative to BUILD_TIME_PATH
Map data = e.getData();
String resourceName = BUILD_TIME_PATH + SLASH + templateName;
String fileName = e.getFileName();
// TODO: What if we find more than one ?
try (InputStream templateStream = cl.getResourceAsStream(resourceName)) {
if (templateStream != null) {
byte[] templateContent = IoUtil.readBytes(templateStream);
// Internal runs on "naked" namespace
DevUIContent content = DevUIContent.builder()
.fileName(fileName)
.template(templateContent)
.addData(data)
.build();
contentPerExtension.add(content);
}
} catch (IOException ioe) {
throw new UncheckedIOException("An error occurred while processing " + resourceName, ioe);
}
}
buildTimeContentProducer.produce(new StaticContentBuildItem(
StaticContentBuildItem.DEV_UI, contentPerExtension));
}
}
/**
* Creates json data that is available in Javascript
*/
@BuildStep(onlyIf = IsDevelopment.class)
void createBuildTimeData(BuildProducer buildTimeConstProducer,
BuildProducer themeVarsProducer,
List internalPages,
ExtensionsBuildItem extensionsBuildItem,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {
BuildTimeConstBuildItem internalBuildTimeData = new BuildTimeConstBuildItem(AbstractDevUIBuildItem.DEV_UI);
addThemeBuildTimeData(internalBuildTimeData, themeVarsProducer);
addMenuSectionBuildTimeData(internalBuildTimeData, internalPages, extensionsBuildItem);
addFooterTabBuildTimeData(internalBuildTimeData, extensionsBuildItem);
addVersionInfoBuildTimeData(internalBuildTimeData, nonApplicationRootPathBuildItem);
buildTimeConstProducer.produce(internalBuildTimeData);
}
private void addThemeBuildTimeData(BuildTimeConstBuildItem internalBuildTimeData,
BuildProducer themeVarsProducer) {
// Theme details TODO: Allow configuration
Map> themes = new HashMap<>();
Map dark = new HashMap<>();
Map light = new HashMap<>();
computeColors(themes, dark, light);
internalBuildTimeData.addBuildTimeData("themes", themes);
// Also set at least one there for a default
themeVarsProducer.produce(new ThemeVarsBuildItem(light.keySet(), QUARKUS_BLUE.toString()));
}
private void addMenuSectionBuildTimeData(BuildTimeConstBuildItem internalBuildTimeData,
List internalPages,
ExtensionsBuildItem extensionsBuildItem) {
// Menu section
List sectionMenu = new ArrayList();
Collections.sort(internalPages, (t, t1) -> {
return ((Integer) t.getPosition()).compareTo(t1.getPosition());
});
for (InternalPageBuildItem internalPageBuildItem : internalPages) {
List pages = internalPageBuildItem.getPages();
for (Page page : pages) {
sectionMenu.add(page);
}
internalBuildTimeData.addAllBuildTimeData(internalPageBuildItem.getBuildTimeData());
}
// Menus from extensions
for (Extension e : extensionsBuildItem.getSectionMenuExtensions()) {
List pagesFromExtension = e.getMenuPages();
sectionMenu.addAll(pagesFromExtension);
}
internalBuildTimeData.addBuildTimeData("menuItems", sectionMenu);
}
private void addFooterTabBuildTimeData(BuildTimeConstBuildItem internalBuildTimeData,
ExtensionsBuildItem extensionsBuildItem) {
// Add the Footer tabs
List footerTabs = new ArrayList();
Page serverLog = Page.webComponentPageBuilder().internal()
.namespace("devui-logstream")
.title("Server")
.icon("font-awesome-solid:server")
.componentLink("qwc-server-log.js").build();
footerTabs.add(serverLog);
Page testLog = Page.webComponentPageBuilder().internal()
.namespace("devui-continuous-testing")
.title("Testing")
.icon("font-awesome-solid:flask-vial")
.componentLink("qwc-test-log.js").build();
footerTabs.add(testLog);
// This is only needed when extension developers work on an extension, so we only included it if you build from source.
if (Version.getVersion().equalsIgnoreCase("999-SNAPSHOT")) {
Page devUiLog = Page.webComponentPageBuilder().internal()
.namespace("devui-jsonrpcstream")
.title("Dev UI")
.icon("font-awesome-solid:satellite-dish")
.componentLink("qwc-jsonrpc-messages.js").build();
footerTabs.add(devUiLog);
}
// Add any Footer tabs from extensions
for (Extension e : extensionsBuildItem.getFooterTabsExtensions()) {
List tabsFromExtension = e.getFooterPages();
footerTabs.addAll(tabsFromExtension);
}
internalBuildTimeData.addBuildTimeData("footerTabs", footerTabs);
internalBuildTimeData.addBuildTimeData("loggerLevels", LEVELS);
}
private void addVersionInfoBuildTimeData(BuildTimeConstBuildItem internalBuildTimeData,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {
// Add version info
String contextRoot = nonApplicationRootPathBuildItem.getNonApplicationRootPath() + DEV_UI + SLASH;
Map applicationInfo = new HashMap<>();
applicationInfo.put("contextRoot", contextRoot);
applicationInfo.put("quarkusVersion", Version.getVersion());
applicationInfo.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse(""));
applicationInfo.put("applicationVersion",
config.getOptionalValue("quarkus.application.version", String.class).orElse(""));
internalBuildTimeData.addBuildTimeData("applicationInfo", applicationInfo);
}
private static final List LEVELS = List.of(
OFF.getName(),
SEVERE.getName(),
ERROR.getName(),
FATAL.getName(),
WARNING.getName(),
WARN.getName(),
INFO.getName(),
DEBUG.getName(),
TRACE.getName(),
CONFIG.getName(),
FINE.getName(),
FINER.getName(),
FINEST.getName(),
ALL.getName());
private static void computeColors(Map> themes, Map dark,
Map light) {
// Quarkus logo colors
light.put("--quarkus-blue", QUARKUS_BLUE.toString());
dark.put("--quarkus-blue", QUARKUS_BLUE.toString());
light.put("--quarkus-red", QUARKUS_RED.toString());
dark.put("--quarkus-red", QUARKUS_RED.toString());
light.put("--quarkus-center", QUARKUS_DARK.toString());
dark.put("--quarkus-center", QUARKUS_LIGHT.toString());
// Vaadin's Lumo (see https://vaadin.com/docs/latest/styling/lumo/design-tokens/color)
// Base
light.put("--lumo-base-color", Color.from(0, 100, 100).toString());
dark.put("--lumo-base-color", Color.from(210, 10, 23).toString());
// Grayscale
light.put("--lumo-contrast-5pct", Color.from(214, 61, 25, 0.05).toString());
dark.put("--lumo-contrast-5pct", Color.from(214, 65, 85, 0.06).toString());
light.put("--lumo-contrast-10pct", Color.from(214, 57, 24, 0.1).toString());
dark.put("--lumo-contrast-10pct", Color.from(214, 60, 80, 0.14).toString());
light.put("--lumo-contrast-20pct", Color.from(214, 53, 23, 0.16).toString());
dark.put("--lumo-contrast-20pct", Color.from(214, 64, 82, 0.23).toString());
light.put("--lumo-contrast-30pct", Color.from(214, 50, 22, 0.26).toString());
dark.put("--lumo-contrast-30pct", Color.from(214, 69, 84, 0.32).toString());
light.put("--lumo-contrast-40pct", Color.from(214, 47, 21, 0.38).toString());
dark.put("--lumo-contrast-40pct", Color.from(214, 73, 86, 0.41).toString());
light.put("--lumo-contrast-50pct", Color.from(214, 45, 20, 0.52).toString());
dark.put("--lumo-contrast-50pct", Color.from(214, 78, 88, 0.50).toString());
light.put("--lumo-contrast-60pct", Color.from(214, 43, 19, 0.6).toString());
dark.put("--lumo-contrast-60pct", Color.from(214, 82, 90, 0.6).toString());
light.put("--lumo-contrast-70pct", Color.from(214, 42, 18, 0.69).toString());
dark.put("--lumo-contrast-70pct", Color.from(214, 87, 92, 0.7).toString());
light.put("--lumo-contrast-80pct", Color.from(214, 41, 17, 0.83).toString());
dark.put("--lumo-contrast-80pct", Color.from(214, 91, 94, 0.8).toString());
light.put("--lumo-contrast-90pct", Color.from(214, 40, 16, 0.94).toString());
dark.put("--lumo-contrast-90pct", Color.from(214, 96, 96, 0.9).toString());
light.put("--lumo-contrast", Color.from(214, 35, 15).toString());
dark.put("--lumo-contrast", Color.from(214, 100, 98).toString());
// Primary
light.put("--lumo-primary-color-10pct", Color.from(214, 100, 60, 0.13).toString());
dark.put("--lumo-primary-color-10pct", Color.from(214, 90, 63, 0.1).toString());
light.put("--lumo-primary-color-50pct", Color.from(QUARKUS_BLUE, 0.76).toString());
dark.put("--lumo-primary-color-50pct", Color.from(QUARKUS_BLUE, 0.5).toString());
light.put("--lumo-primary-color", QUARKUS_BLUE.toString());
dark.put("--lumo-primary-color", QUARKUS_BLUE.toString());
light.put("--lumo-primary-text-color", QUARKUS_BLUE.toString());
dark.put("--lumo-primary-text-color", QUARKUS_BLUE.toString());
light.put("--lumo-primary-contrast-color", Color.from(0, 100, 100).toString());
dark.put("--lumo-primary-contrast-color", Color.from(0, 100, 100).toString());
// Error
light.put("--lumo-error-color-10pct", Color.from(3, 85, 49, 0.1).toString());
dark.put("--lumo-error-color-10pct", Color.from(3, 90, 63, 0.1).toString());
light.put("--lumo-error-color-50pct", Color.from(3, 85, 49, 0.5).toString());
dark.put("--lumo-error-color-50pct", Color.from(3, 90, 63, 0.5).toString());
light.put("--lumo-error-color", Color.from(3, 85, 48).toString());
dark.put("--lumo-error-color", Color.from(3, 90, 63).toString());
light.put("--lumo-error-text-color", Color.from(3, 89, 42).toString());
dark.put("--lumo-error-text-color", Color.from(3, 100, 67).toString());
light.put("--lumo-error-contrast-color", Color.from(0, 100, 100).toString());
dark.put("--lumo-error-contrast-color", Color.from(0, 100, 100).toString());
// Warning
light.put("--lumo-warning-color-10pct", Color.from(30, 100, 50, 0.1).toString());
dark.put("--lumo-warning-color-10pct", Color.from(30, 100, 50, 0.1).toString());
light.put("--lumo-warning-color-50pct", Color.from(30, 100, 50, 0.5).toString());
dark.put("--lumo-warning-color-50pct", Color.from(30, 100, 50, 0.5).toString());
light.put("--lumo-warning-color", Color.from(30, 100, 50).toString());
dark.put("--lumo-warning-color", Color.from(30, 100, 50).toString());
light.put("--lumo-warning-text-color", Color.from(30, 89, 42).toString());
dark.put("--lumo-warning-text-color", Color.from(30, 100, 67).toString());
light.put("--lumo-warning-contrast-color", Color.from(0, 100, 100).toString());
dark.put("--lumo-warning-contrast-color", Color.from(0, 100, 100).toString());
// Success
light.put("--lumo-success-color-10pct", Color.from(145, 72, 31, 0.1).toString());
dark.put("--lumo-success-color-10pct", Color.from(145, 65, 42, 0.1).toString());
light.put("--lumo-success-color-50pct", Color.from(145, 72, 31, 0.5).toString());
dark.put("--lumo-success-color-50pct", Color.from(145, 65, 42, 0.5).toString());
light.put("--lumo-success-color", Color.from(145, 72, 30).toString());
dark.put("--lumo-success-color", Color.from(145, 65, 42).toString());
light.put("--lumo-success-text-color", Color.from(145, 85, 25).toString());
dark.put("--lumo-success-text-color", Color.from(145, 85, 47).toString());
light.put("--lumo-success-contrast-color", Color.from(0, 100, 100).toString());
dark.put("--lumo-success-contrast-color", Color.from(0, 100, 100).toString());
// Text
light.put("--lumo-header-text-color", Color.from(214, 35, 15).toString());
dark.put("--lumo-header-text-color", Color.from(214, 100, 98).toString());
light.put("--lumo-body-text-color", Color.from(214, 40, 16, 0.94).toString());
dark.put("--lumo-body-text-color", Color.from(214, 96, 96, 0.9).toString());
light.put("--lumo-secondary-text-color", Color.from(214, 42, 18, 0.69).toString());
dark.put("--lumo-secondary-text-color", Color.from(214, 87, 92, 0.7).toString());
light.put("--lumo-tertiary-text-color", Color.from(214, 45, 20, 0.52).toString());
dark.put("--lumo-tertiary-text-color", Color.from(214, 78, 88, 0.5).toString());
light.put("--lumo-disabled-text-color", Color.from(214, 50, 22, 0.26).toString());
dark.put("--lumo-disabled-text-color", Color.from(214, 69, 84, 0.32).toString());
themes.put("dark", dark);
themes.put("light", light);
}
private static final Color QUARKUS_BLUE = Color.from(211, 63, 54);
private static final Color QUARKUS_RED = Color.from(343, 100, 50);
private static final Color QUARKUS_DARK = Color.from(180, 36, 5);
private static final Color QUARKUS_LIGHT = Color.from(0, 0, 90);
/**
* This represents a HSLA color
* see https://www.w3schools.com/html/html_colors_hsl.asp
*/
static class Color {
private int hue; // Defines a degree on the color wheel (from 0 to 360) - 0 (or 360) is red, 120 is green, 240 is blue
private int saturation; // Defines the saturation; 0% is a shade of gray and 100% is the full color (full saturation)
private int lightness; // Defines the lightness; 0% is black, 50% is normal, and 100% is white
private double alpha; // Defines the opacity; 0 is fully transparent, 100 is not transparent at all
private Color(int hue, int saturation, int lightness, double alpha) {
if (hue < 0 || hue > 360) {
throw new RuntimeException(
"Invalid hue, number needs to be between 0 and 360. Defines a degree on the color wheel");
}
this.hue = hue;
if (saturation < 0 || saturation > 100) {
throw new RuntimeException(
"Invalid saturation, number needs to be between 0 and 100. 0% is a shade of gray and 100% is the full color (full saturation)");
}
this.saturation = saturation;
if (lightness < 0 || lightness > 100) {
throw new RuntimeException(
"Invalid lightness, number needs to be between 0 and 100. 0% is black, 50% is normal, and 100% is white");
}
this.lightness = lightness;
if (alpha < 0 || alpha > 1) {
throw new RuntimeException(
"Invalid alpha, number needs to be between 0 and 1. 0 is fully transparent, 1 is not transparent at all");
}
this.alpha = alpha;
}
@Override
public String toString() {
return "hsla(" + this.hue + ", " + this.saturation + "%, " + this.lightness + "%, " + this.alpha + ")";
}
static Color from(Color color, double alpha) {
return new Color(color.hue, color.saturation, color.lightness, alpha);
}
static Color from(int hue, int saturation, int lightness) {
return new Color(hue, saturation, lightness, 1);
}
static Color from(int hue, int saturation, int lightness, double alpha) {
return new Color(hue, saturation, lightness, alpha);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy