Темы

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

Тема состоит из файлов 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 приложения может быть применена только одна. Однако существуют способы переключения между вариантами одной и той же темы и динамической загрузки дополнительных стилей поверх темы.

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

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

theme folder structure
Figure 1. Структура файлов папки темы
  • my-project - папка темы, также используется как имя темы

  • styles.css - основной файл стилей

  • my-project.css - точка входа для пользовательских стилей и импортов

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

Файл styles.css является точкой входа для стилей темы. Весь CSS, включая значения свойств Lumo и стили пользовательских компонентов, можно добавить в этот файл.

Можно также разделить CSS на несколько файлов, чтобы избежать загромождения основного файла стилей. Дополнительные файлы CSS загружаются с помощью директив @import. По умолчанию основной файл стилей проекта содержит единственный импорт файла <theme-name>.css, который определяет ваши стили и любые другие импорты.

styles.css
@import url('./my-project.css');

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

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

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

theme addon structure
Figure 2. Структура проекта с темой
  • 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 3. Пример примененной пользовательской темы

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

При разработке собственного дополнения можно создать файл с пользовательскими стилями в каталоге 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 4. Компонент 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