Привет! Меня зовут Сергей Топунов, я фронт-разработчик в SM Lab. Недавно мы сделали редизайн одной из наших внутренних систем, о чем я и хочу вам сегодня рассказать.
«Оценка вклада» — это внутренняя Backoffice-система, которая нужна для регулярной оценки сотрудников. Она позволяет отметить точки роста, рабочий прогресс коллег, а также получить отзыв от других сотрудников.
Старый интерфейс
Основная задача, которая стояла перед нашей командой, заключалась в том, чтобы качественно и за ограниченное время обновить интерфейс Backoffice-системы. Интерфейс был собран с использованием фреймворка Vuetify, представляющего из себя стандартную дизайн-систему Material Design от Google. Были достаточно серьезные недостатки и проблемы, связанные с UX/UI, потому что версию делали в определенной спешке.
Сразу было принято решение — оставить Vuetify как основной фреймворк, а свои компоненты делать только при крайней необходимости. Задача состояла в том, чтобы придумать простые и универсальные правила, которые не конфликтовали бы с Vuetify и позволяли бы легко подключать новые компоненты.
Внутри компании была разработана внутренняя дизайн-система FLEXO.
В ней есть весь необходимый нам функционал: календарь, кнопки, текстовые поля, слайдеры и прочие полезные штуковины.
В команде появился дизайнер, и на базе корпоративной системы был отрисован дизайн с новым поведением.
Как внедряли
В дизайн-системе обычно есть различные сущности — цвета, шрифты, размеры, тени, компоненты и представления. Основных цветов шесть, у каждого их них десять градаций. Каждый цвет именуется по цифро-буквенному индексу, он представляет собой RGBA-цвет без прозрачности.
То же самое со шрифтами, они варьируются от extra small до extra large с индексом. Можно посмотреть, как какой-нибудь шрифт выглядит в Figma.
Здесь задается начертание, размер, интерлиньяж и название самого шрифта. Также есть 17 отступов, в характеристиках которых указываются индекс, padding и margin. Аналогичная ситуация со скруглениями — их 12 штук.
Как выглядят компоненты
На примере checkbox посмотрим, как выглядят компоненты. Разобравшись с тем, как строится checkbox, который является атомом в нашей системе, станет понятно, как строятся все остальные компоненты.
Здесь есть несколько цветов, есть скругление, шрифт, его цвет и margin. Все компоненты имеют определенные свойства, например, размеры.
Также у checkbox есть четыре поведения.
Каждый компонент — это составная часть другого, более крупного компонента. Вот пример.
Как всё устроено
У нас было не очень много времени, поэтому мы не успели бы собрать собственный UI Kit, как уже было сказано выше. На проекте уже был Vue второй версии, Vuetify и препроцессор Sass. Была поставлена задача собрать за лето на текущих технологиях новый дизайн. Нужно было доделать недостающие компоненты, натянуть стили, чтобы это выглядело так, как в Figma.
Проблема Material Design в Vuetify в том, что его сложно настроить. У него есть свои характеристики, тот же checkbox бывает маленьким или большим, внутрь там приходит svg-иконка. Всё это вызывает определенные ограничения: если нужно сделать пятое состояние или засунуть две иконки, то это достаточно сложно. Если нам нужно использовать стандартный checkbox, то мы можем использовать его из Vuetify и навесить на него стиль, а если есть необходимость расширить его, то проще сделать обычный компонент. В этом и состояла дилемма между использованием Vuetify и своих компонентов.
Структура нашего проекта следующая: CSS, компоненты, разделенные по смыслу, виджеты, иконки, UI-компоненты, привязанные по смыслу к views, сами views и так далее.
Мы создали глобальные CSS, чтобы иметь возможность использовать стили во всех кастомных, так и ко всем компонентах из Vuetify. Цвет задается с помощью переменной, дальше мы задаем два стиля для background и для color. Если у нас какой-нибудь div, то мы делаем background вторым классом. Если какой-нибудь шрифт или border, то делаем стандартным классом color.
То же самое со шрифтами: они задаются сгруппированным свойством, когда размер, начертание и семейство идут вместе, чтобы их было удобно использовать как переменную.
.mx-2_5 {
margin-right: 10px !important;
margin-left: 10px !important;
}
body.flexo .mx-12 {
margin-right: 48px !important;
margin-left: 48px !important;
}
С полями похожая история, но есть нюанс. В стандартном Vuetify уже есть свой список размеров. Рассмотрим, например, margin, у него bottom или X, если в обе стороны по горизонтали, или Y, если в обе стороны по вертикали, и дальше size, который меняется от 0 до 12. Мы просто расширили значения и добавили недостающие: получилось несколько дробных значений и еще несколько в конце.
А ещё радиусы. Они называются rounded, мы их назвали точно так же, чтобы не противоречить стандартам Vuetify. У нас получилось, что они не совпадают с нумерацией Figma. Тени тоже можно использовать как класс.
Поскольку мы используем Vuetify как основной фреймворк для компонентов, пришлось сделать для некоторых глобально используемых элементов, например, для кнопок, файл overrides, что скорее является антипаттерном. Если мы используем кнопку, чтобы не делать обертку над стандартным элементом и дополнительный компонент, можно сделать базовую кнопку, и добавить в overrides глобальный стиль, который будет это перекрывать. Это достаточно удобно, потому что не надо делать дополнительных компонентов, так как перезаписывается стандартная тема.
В работе
Итак, сначала выделяются компоненты, переопределяются стили там, где нужно, делается тестовая страница, а потом — тестовый запуск.
Давайте на примере нашего любимого checkbox. Если делать его как обычный компонент, то это достаточно управляемая вещь, это удобно. Если нам нужно кастомизировать его и мы понимаем, что конкретно нужно сделать, то это легко и понятно. Встраивается он тоже стандартным образом.
Второй вариант — сделать через overrides стандартный checkbox и перекрыть из Vuetify. Здесь перекрыты практически все кейсы, которые нужны, это работает, но здесь тоже стандартное поведение. Можно использовать оба подхода. Если нам нужно сделать checkbox, который будет работать со стандартным поведением, то мы используем стандартный Vuetify и мы можем использовать overrides. А если нужно сделать какое-то собственное поведение, то делается обертка или собственный UI-компонент.
Полученный компонент мы встраиваем в родительский, а потом в представление.
Как показала практика, использование такого подхода ускорило разработку, и мы достаточно быстро обновили дизайн и функционал системы.
Конечно, есть нюансы, такой подход хорош, но он не совсем чистый. Если бы было больше времени, то на базе системы FLEXO можно было бы создать собственную дизайн-систему, но там есть существенный минус — это требует команды и постоянной поддержки.
А второй вариант – сделать полноценную тему для Vuetify или подобного фреймворка, чтобы подключение было проще и удобнее.