Темы

Темы используются для управления визуальным оформлением приложения.

Тема состоит из файлов CSS и других ресурсов, таких как изображения и шрифты.

Jmix предоставляет тему jmix-lumo, построенную на основе темы Lumo Vaadin.

Применение темы

Тема приложения применяется с помощью аннотации @Theme с именем папки темы в качестве параметра. Аннотация @Theme должна быть размещена на классе, который реализует интерфейс AppShellConfigurator, обычно это основной класс приложения.

@Theme(value = "my-theme")
public class MyProjectApplication implements AppShellConfigurator {
    ...
}

Вариант темы может быть указан в качестве дополнительного параметра, например dark или light.

@Theme(value = "my-theme", variant = "dark")
public class MyProjectApplication implements AppShellConfigurator {
    ...
}
Темы не могут быть переключены во время выполнения. Хотя проект может иметь несколько тем, для UI приложения может быть применена только одна. Однако существуют способы переключения между вариантами одной и той же темы и динамической загрузки дополнительных стилей поверх темы.

Тема приложения

Для использования в приложении каталог темы размещается внутри каталога src/main/frontend/themes. Проекты Jmix, созданные с помощью Studio, имеют предопределенный каталог темы с таким же именем, как и сам проект.

Например:

src
└── main
    └── frontend
        └── themes
            └── my-project
                ├── my-project.css
                ├── styles.css
                ├── theme.json
                └── view
                    ├── login-view.css
                    ├── main-view-top-menu.css
                    └── main-view.css
  • my-project - каталог темы. Имя каталога используется в качестве имени темы в аннотации @Theme.

  • my-project.css - файл кастомных стилей данной темы.

  • styles.css - основной файл стилей, является точкой входа для стилей данной темы.

  • theme.json - файл конфигурации темы. По умолчанию, определяет jmix-lumo в качестве родительской темы.

  • view - данный каталог содержит файлы CSS, определяющие стили для главного экрана и экрана логина, предоставляемых шаблоном проекта.

Весь код CSS, включая значения CSS-переменных и кастомные стили компонентов, может быть включен в основной файл styles.css. Однако по умолчанию этот файл содержит только директивы импорта, а фактический CSS организован в отдельные файлы, чтобы упростить поддержку кода:

styles.css
@import url('my-project.css');
@import url('view/main-view.css');
@import url('view/main-view-top-menu.css');
@import url('view/login-view.css');

Размещайте CSS-код вашего проекта в файле <theme_name>.css (в данном примере это my-project.css).

Используйте онлайн-редактор Lumo theme editor от Vaadin для быстрой настройки темы вашего приложения.

Настройте нужный внешний вид UI-компонентов, используя элементы управления в правой панели. Затем нажмите Download и вставьте сгенерированный CSS код, расположенный внутри тегов <style>, в ваш файл <theme_name>.css.

Переиспользуемая тема

Тема может быть использована в нескольких приложениях путем упаковки ее в виде JAR-зависимости.

Структура проекта c темой выглядит следующим образом:

src
└── main
    └── resources
        └── META-INF
            └── resources
                └── themes
                    └── cobalt
                        ├── styles.css
                        └── theme.json
  • cobalt - папка темы, также используется как имя темы

  • styles.css - основной файл стилей. Может содержать пользовательские стили и импорты, например:

    html {
        --lumo-border-radius: calc(var(--lumo-size-m) / 2);
    
        --lumo-primary-color: rgb(0, 85, 166);
        --lumo-primary-color-50pct: rgba(0, 85, 166, 0.5);
        --lumo-primary-color-10pct: rgba(0, 85, 166, 0.1);
        --lumo-primary-text-color: rgb(0, 85, 166);
    }
  • theme.json - файл конфигурации темы. Рекомендуется определить jmix-lumo в качестве родительской темы, чтобы ваша пользовательская тема включала стили jmix-lumo, необходимые для правильной работы компонентов и экранов Jmix UI. Например:

    {
      "parent": "jmix-lumo",
      "lumoImports":["typography","color","spacing","badge","utility"]
    }

Файл build.gradle проекта темы может выглядеть следующим образом:

plugins {
    id 'java'
    id 'com.gradle.plugin-publish' version '1.2.1'
}

group = 'com.company'
version = '0.0.1-SNAPSHOT'

repositories {
    mavenCentral()
    maven {
        url 'https://global.repo.jmix.io/repository/public'
    }
}

dependencies {
    implementation 'io.jmix.flowui:jmix-flowui-themes:2.3.0' (1)
}
1 Зависимость jmix-flowui-themes содержит тему jmix-lumo.

После того, как JAR c темой добавлен в качестве зависимости в проект, упакованную тему можно использовать как самостоятельную тему:

@Theme(value = "cobalt")
public class MyProjectApplication implements AppShellConfigurator {
    ...
}

или как родительскую для тем проекта, например:

theme.json
{
  "parent": "cobalt",
  "lumoImports":["typography","color","spacing","badge","utility"]
}

В этом случае тема проекта будет загружаться поверх базовой темы, расширяя ее.

custom theme
Figure 1. Пример примененной пользовательской темы

Подключаемые стили

При разработке собственного дополнения можно создать файл с пользовательскими стилями в каталоге src/main/resources/META-INF/resources/. Чтобы эти стили добавились в результирующее приложение, определите свойство jmix.ui.export-styles в файле module.properties. Значением этого свойства является путь относительно src/main/resources/META-INF/resources/, например, jmix.ui.export-styles = addon-styles/my-addon-styles.css.

my-addon-styles.css
.test {
    color: red;
}

Пользовательские стили добавляются как <style type="text/css"> в элемент <head>, например:

<style type="text/css">
.test {
    color: red;
}
</style>
Используйте этот подход только для небольшого набора стилей, которые нельзя применить к определенному UI-компоненту. Например, для утилитных CSS-классов для экранов внутри дополнения.

Изменение вариантов темы во время выполнения

Чтобы переключаться между вариантами темы, например, light и dark, фреймворк предоставляет статический вспомогательный класс, который работает вместе с файлом JavaScript.

Класс ThemeUtils предоставляет методы для переключения вариантов темы, что фактически означает установку варианта темы в Web Local Storage и выполнение JavaScript-кода для его применения.

Например, вы можете добавить dropdownButton в главный экран и переключаться между вариантами темы:

main-view.xml
<dropdownButton id="themeSwitcher"
                text="Theme" icon="ADJUST"
                classNames="ms-auto me-m"
                dropdownIndicatorVisible="false">
    <items>
        <actionItem id="systemThemeItem">
            <action id="systemThemeAction"
                    text="System" icon="ADJUST"/>
        </actionItem>
        <actionItem id="lightThemeItem">
            <action id="lightThemeAction"
                    text="Light" icon="SUN_O"/>
        </actionItem>
        <actionItem id="darkThemeItem">
            <action id="darkThemeAction"
                    text="Dark" icon="MOON_O"/>
        </actionItem>
    </items>
</dropdownButton>
MainView.java
@Subscribe("themeSwitcher.systemThemeItem.systemThemeAction")
public void onThemeSwitcherSystemThemeItemSystemThemeAction(final ActionPerformedEvent event) {
    ThemeUtils.applySystemTheme();
}

@Subscribe("themeSwitcher.lightThemeItem.lightThemeAction")
public void onThemeSwitcherLightThemeItemLightThemeAction(final ActionPerformedEvent event) {
    ThemeUtils.applyLightTheme();
}

@Subscribe("themeSwitcher.darkThemeItem.darkThemeAction")
public void onThemeSwitcherDarkThemeItemDarkThemeAction(final ActionPerformedEvent event) {
    ThemeUtils.applyDarkTheme();
}
theme switcher
Figure 2. Компонент ThemeSwitcher

Файл JavaScript содержит код, который применяет вариант темы к HTML-документу в зависимости от значения в Web Local Storage и подписывается на prefers-color-scheme, чтобы обновить вариант темы, если пользователь укажет свои предпочтения через настройки операционной системы (например, светлый или тёмный режим) или настройки user agent.

Его нужно импортировать в основной класс приложения:

@JsModule("./src/theme/color-scheme-switching-support.js")
@SpringBootApplication
public class OnboardingApplication implements AppShellConfigurator {
theme switcher