Идеальный css-framework. Maxmertkit widget manager – build your own framework

b398a1eea708457c4ce10c5c5599bf09

Добрый день!
Как и обещал некоторое время назад, я выпустил бету maxmertkit widget manager. Я давно хотел npm или gem, но для css. Добавил несколько зависимостей в json-файл, набрал команду и все установилось. Это быстро и удобно. Хороших решений я не нашел, значит пора реализовать свое.

Почти все, что я опишу ниже, есть в этом видео. Я прошу прощения за качество звука, попытаюсь найти нормальный микрофон.

Требования

Перед реализацией любого проекта нужно определить основные требования, которым этот проект должен соответствовать.

  • Неймспейсы. Для всех классов фреймворка.
    • -<имя-виджета> – наименование виджета, например -table, -btn, -tooltip
    • -<имя-темы>- – наименование темы для виджета, например -primary-, -error-, -orange-
    • _<имя-размера> – размер, например _tiny, _small, _huge, _divine
    • _<имя-модификатора>_ – модификатор, например _top_, _active_, _hover_, _unclickable_
  • Модульность. Что я имею ввиду по модульностью? Есть виджет кнопка -btn и она используется в составе виджета -group. Во-первых, при создании виджета группы -group можно указать зависимость от виджета -btn и не описывать его еще раз (это легко добиться и при нативном css). Во-вторых, если я использую виджет -btn с темой -error-, то в составе группы я эту тему использовать не могу. Ну и наоборот, применив кастомную тему к группе, моя кнопка не должна поменяться. То есть виджеты должны быть совершенно независимы друг от друга. Для css это довольно сложно реализуемо, зато удобно и практично.
  • Capture theme. Когда я применяю тему к виджету-родителю, виджеты-дети должны унаследовать тему. Например, ставим группе тему -error-, и все элементы внутри группы должны изменить цвета на -error-. Это очень удобно.

Все эти требования реализованы в mwm – maxmertkit widget manager. Он работает как npm для node.js или как gem для ruby on rails. Его задача скачать нужные вам виджеты, темы, модификаторы и анимации, после чего скомпоновать их для компиляции. Первый шаг – установка mwm. Это нужно сделать глобально, поэтому чтобы избежать лишних вопросов привожу команду с sudo:

sudo npm install -g mwm

 

После установки убедитесь, что mwm установлен правильно, набрав вызов справки:

mwm -h

 

Если появился список команд, значит все в порядке.
Для инициализации maxmertkit, перейдем в корень вашего проекта (именно в корень, а не в папку с вашими стилями). Здесь мы можем создать конфигурационный файл, который укажет mwm путь к папке с вашими стилями. Имя файла: .mwmc. Пока что mwm поддерживает только одно поле:

{
    "directory": "path-to-your-stylesheets-from-projects-root"
}

 

Например, если мои стили относительно корня находятся в public/stylesheets, то

{
    "directory": "public/stylesheets"
}

 

Если вы создали конфигурационный файл, то запускайте mwm из корня вашего проекта, если же нет, то перейдите в папку со стилями.
Далее нужно инициализировать maxmertkit следующей командой:

mwm init

 

Mwm поспрашивает вас о названии, тегах и прочей ерунде (которую обязательно заполнять, если вы создаете виджет/тему/анимацию и собираетесь ее опубликовать) и создаст необходимые для компиляции файлы, а именно:

  • _imports.sass – включает в себя перечисление всех подключаемых виджетов, тем, модификаторов и анимаций.
  • _params.sass – содержит параметры, необходимые для компиляции проекта
  • _vars.sass – переменные, используемые в зависимых виджетах
  • _myvars.sass – переменные, используемые в текущем виджете
  • _index.sass – файл, в который можно писать свои стили, только оставьте импорты
  • maxmertkit.json – файл конфигурации проекта

Все эти файлы, кроме _index.sass и maxmertkit.json, не нужно менять, трогать, а в идеале – нужно не знать про их существование или не замечать.
Попробуем установить виджет btn. Для этого добавим в maxmertkit.json поле dependences:

{
    "type": "project",
    "name": "test",

    ...

    "dependences": {
        "btn": "0.0.9"
    }
}

 

Вместо версии 0.0.9 можно указать *, если вы хотите последнюю доступную версию этого виджета. Сохраняем и в терминале набираем

mwm install

 

Я не стал учить mwm компилировать sass-файлы, поэтому компилировать _index.sass вам нужно самим. Для этого можно открыть новое окно терминала, перейти в папку со стилями (не в корень) проекта и набрать

sass -w _index.sass:index.css

 

Можно оставить это окно терминала, теперь sass будет следить за изменениями в структуре файлов и перекомпилировать проект при необходимости (отслеживает он не очень, поэтому после mwm install рекомендую открыть _index.sass и сохранить его, чтобы компилятор сообразил, что нужно перекомпилить проект). Виджет кнопка -btn установлен. Можете использовать его в html-коде. Чтобы понять как, приветствуется зайти на www.maxmert.com в раздел widgets и почитать документацию. В нашем случае это

<a class="-btn">кнопка</a>

 

OK, а как же установить определенную тему для этого виджета? Нужно опять изменить maxmertkit.json:

{
    ...

    "dependences": {
        "btn": {
            "version": "0.0.9",
            "themes": {
                "error": "*",
                "orange": "*"
            }
        }
    }
}

 

И снова набрать

mwm install

 

Теперь с виджетом -btn можно использовать темы -error- и -orange-:

<a class="-btn -error-">Error button</a>
<a class="-btn -orange-">Orange button</a>
<a class="-btn">Default button</a>

 

Вот, собственно, и все что необходимо, чтобы использовать mwm для своих проектов.
Приведу пример файла maxmertkit.json

{
    "type": "widget",
    "name": "group",
    "version": "0.0.4",
    "description": "Standart group",
    "repository": "",
    "author": "maxmert",
    "themeUse": true,
    "tags": "button, buttons, group, input, label, appendix",
    "license": "BSD",

    "dependences": {
    	"bourbon": "3.1.8",
    	"object": "0.0.0",
        "btn": {
            "version": "0.0.9",
            "themes": {
                "primary": "*",
                "error": "*",
                "orange": "*"
            }
        },
        "forms": "0.0.5",
        "caret": "0.0.4"
    },

    "themes": {
    	"default": "*",
        "disabled": "*",
        "primary": "*"
    },

    "modifiers": {
        "tiny": "0.0.0",
        "small": "0.0.0",
        "minor": "0.0.0",
        "normal": "0.0.0",
        "major": "0.0.0",
        "big": "0.0.0",
        "huge": "0.0.0",
        "giant": "0.0.0",
        "divine": "0.0.0",

        "active": "*",
        "hover": "*",
        "unclickable": "*",

        "loading": "*",
        "unstyled": "*"
    },

    "animation": {
        "loading": "0.0.2"
    }
}

 

Использование портала

После sign up на maxmertkit.com у вас будут следующие возможности (я вообще никак не буду использовать ваши личные данные, обещаю):

  • Вы сможете собирать проект прямо на сайте и скачивать стили в архиве.
  • Можно сохранять необходимый набор виджетов/тем/модификаторов/анимаций в пресеты для отложенной компиляции или скачивания.
  • Можно сохранять в избранное, чтобы долго не искать (хотя есть поиск) или просто сообщить, что вам этот виджет нравится.
  • Можно создавать и публиковать свои виджеты, темы (темы — прямо на сайте, очень быстро и здорово), модификаторы и анимации.

Вся документация для виджетов доступна на сайте и без регистрации.

Создание виджета

Предположим, вы хотите сделать и опубликовать свой виджет. Первое, что вам нужно сделать, это зарегистрироваться наmaxmertkit.com, войти в свой профайл (кликнуть на своей аватарке в sidebar’е) и создать developer password. Он будет необходим при публикации вашего виджета.
После этого создаем папку, в котором будет коваться наш виджет, заходим туда и набираем

mwm init -w

 

Флаг -w означает, что мы инициализируем виджет, а не проект. Mwm создает необходимые файлы, в целом похожие на файлы проекта. В файл maxmertkit.json добавляем зависимости, модификаторы и анимации, которые будет использовать наш новый виджет (по аналогии с проектом, описано выше). Набираем

mwm install

 

а затем

sass -w _index.sass:index.css

 

и приступаем к правке основного файла виджета _index.sass.

Правим _index.sass

_index.sass – главный файл виджета, в котором прописаны все необходимые для виджета стили. Изначально он такой:

@import "imports"  
@import "params"  
@import "myvars" 
@import "vars"  

%#{$test} 
    @extend %object 

    // Set _minor to default size 
    $sizes: null!default 
    @if $sizes 
        @each $size in $sizes 
            $sz: #{nth($size, 1)} 
            @if $sz != _minor 
                &.#{nth($size, 1)} 
                    font-size: nth($size,2) 
                    padding: nth($size,2)/3 nth($size,2)/2 
            @else 
                font-size: nth($size,2) 
                padding: nth($size,2)/3 nth($size,2)/2 

    // Modifiers 

    // Themes 
    $themes: null!default 
    @if $themes 
        @each $theme in $themes  

            $index: 1 
            @if length( $themes ) != 1 
                $index: index( $themes, $theme ) 

            $imp: "" 
            @if $theme == "-disabled-" 
                $imp: !important 

            @if $theme != "default" 
                &.#{$theme} 
                    color: nth( $color-invert, $index ) 
                    border-color: nth( $border-color-lighten, $index ) 

                &:hover 
                    border-color: nth( $border-color-darken, $index )#{$imp} 

            @else 
                color: nth( $color-invert, $index ) 
                border-color: nth( $border-color-lighten, $index ) 

                &:hover 
                    border-color: nth( $border-color-darken, $index )#{$imp} 

@if $dependent == null 
    .#{$test} 
        @extend %#{$test}

 

Вместо $test будет название вашего виджета, например, если при инициализации вы сказали, что виджет будет называтьсяsuperbutton, то вместо $test будет $superbutton. Но далее будем считать, что мой виджет будет называться test.
Разберем код.

%#{$test}

 

% здесь используется, чтобы не добавлять класс в css в случае, если этот виджет будет зависимостью другого виджета (это extend-only селектор). Советую почитать об этом здесь.

Динамические размеры

 

$sizes: null!default 
@if $sizes 
    @each $size in $sizes 
        $sz: #{nth($size, 1)} 
        @if $sz != _minor 
            &.#{nth($size, 1)} 
                font-size: nth($size,2) 
                padding: nth($size,2)/3 nth($size,2)/2 
        @else 
            font-size: nth($size,2) 
            padding: nth($size,2)/3 nth($size,2)/2

 

В случае, если наш будущий виджет будет иметь различные размеры, нужно не забыть включить в зависимости виджет sizesи определить свойства нашего виджета в этом цикле. В данном случае для каждого размера (см. виджет sizes) определяемfont-size и padding. Конечно же можно определять и другие параметры, включив nth($size,2) в значение. Здесьnth($size,2) – определенное значение в px, соответствующее каждому из размеров. Его можно преобразовать по вашему вкусу. Как вы могли заметить, код здесь дублирующийся. Но это необходимо для определения размера по-умолчанию после else (код можно не дублировать, а выставить, например, какие-то заранее определенные значения).

Динамические темы

Теперь рассмотрим как добавлять темы.

$themes: null!default

    @if $themes 

        // Берем каждую из тем
        @each $theme in $themes 

            // В sass со списками все сложно, поэтому нужно проверить, является ли тема списком
            $index: 1 
            @if length( $themes ) != 1 
                $index: index( $themes, $theme ) 

            // Тема -disabled- всегда имеет приоритет, так что ставим !important, если эта тема текущая
            $imp: "" 
            @if $theme == "-disabled-" 
                $imp: !important 

     		// Если тема не default, используем название класса
            @if $theme != "default" 
                &.#{$theme} 
                    // Выставляем все необходимые параметры для нашего виджета
                    // В данном случае – это цвет текста и цвет границы
                    color: nth( $color-invert, $index ) 
                    border-color: nth( $border-color-lighten, $index ) 

                // Кроме того, указываем каким показывать виджет для :hover, :active
                // или других модификаторов, например .#{$mod-active} для использования виджета с модификатором _active_
                &:hover 
                    border-color: nth( $border-color-darken, $index )#{$imp}

                &.#{$mod-active}
                    background-color: nth( $background-color, $index )#{$imp}

            // И то же самое для темы по умолчанию без использования класса темы
            @else 
                color: nth( $color-invert, $index ) 
                border-color: nth( $border-color-lighten, $index ) 

                &:hover 
                    border-color: nth( $border-color-darken, $index )#{$imp}

                &.#{$mod-active}
                    background-color: nth( $background-color, $index )#{$imp}

 

Я постарался дать комментарии в source, однако стоит упомянуть, что в nth( $background-color, $index )#{$imp} вам нужно лишь менять background-color на наименование из списка, присутствующего в каждой теме, например тут – error theme. Это, например, colorcolor-invert-darkenbackground-color-invert-darkener и другие. При такой структуре темы будут автоматически применяться к вашему виджету. Попробуйте включить пару тем в зависимости и потестировать их.

@if $dependent == null 
    .#{$test} 
        @extend %#{$test}

 

Проверка, является ли ваш виджет зависимостью. Если да, то нет необходимости создавать селектор класса, но от него можно наследоваться. Если же нет, то создаем селектор класса.

Тесты и документация

Перейдем к тестам. Для публикации вы должны будете создать файл test.html и подключить в него скомпилированныйindex.css чтобы проверить, все ли правильно компилируется и работает. На портале ваш test.html будет отображаться в iframe после документации. Если вы указали github-репозиторий этого виджета в maxmertkit.json, то файл README.md будет взять оттуда. Если github-репозитория у виджета нет, то создайте файл README.md с рекомендациями по его использованию. Можно, конечно, без него, но как-то это плохо. Когда все протестировано, написано и готово, просто наберите

mwm publish

 

Помните, что ваше имя mwm возьмет из файла maxmertkit.json, поля author, а вот пароль ввести попросит. Далее можно следовать указаниям mwm. Виджет опубликован. Команда unpublish присутствует, но в тестовых целях, поэтому сервер будет ее игнорировать (вскоре она исчезнет из mwm совсем). Если вы вдруг поняли, что допустили ошибку, то вам прийдется ее исправить, повысить версию в maxmertkit.json и снова опубликовать виджет. Mwm хорошо поддерживает версионность, поэтому если кто-то уже использует старую версию вашего виджета, ничего не поломается.

Создание тем

Темы можно создавать прямо на сайте. Это быстро и удобно. Войдите с помощью одной из соцсетей, напротив меню themesпоявится +, нажав на который вы перейдете на страницу добавления темы. Достаточно ввести название и основные цвета: главный и инвертированный. Остальные поля можно оставить пустыми, они будут вычислены автоматически (см. плейсхолдеры этих полей).

Issues

Для mwm – https://github.com/maxmert/mwm/issues
Для виджетов, тем, модификаторов и анимаций (для sass и css) – https://github.com/maxmert/maxmertkit/issues
Мои проблемы с английским или русским (очень прошу помочь с правкой текстов) – в личку на habrahabr или на me@maxmert.com.

Конкурс

Я прошу вас, друзья, присылать мне на почту vetrenko.maxim@gmail.com готовые UI (укажите, пожалуйста, тему habrahabr — UI, чтобы я смог ориентироваться), которые вы хотели бы видеть реализованными в maxmertkit. Я по мере возможности, начиная с самых привлекательных, буду добавлять их. Будет здорово! Присылать можно jpg (в этом случае когда я начну реализацию, скорее всего попрошу psd) или сразу psd. Буду обновлять пост, чтобы было видно, что появится в ближайшее время.

P.S.: Друзья, прошу помощи с написанием английской статьи для распространения в зарубежных блогах. Дело в том, что по-английски я пишу по-русски, простите за каламбур. Скорее всего текст такой грамотной статьи я возьму на главную страницу и укажу вас как автора статьи. Да и аккаунтов на зарубежных блогах с соответствующей тематикой у меня, к сожалению, нет, так что прошу помощи и с этим.