Как выбрать библиотеку стайлинга и заменить несколько дизайн-систем на одну. Часть 1 | Веб-студия Nat.od.ua
Как выбрать библиотеку стайлинга и заменить несколько дизайн-систем на одну. Часть 1
Привет! Меня зовут Вадим Казаченко, я лид фронта дизайн-системы ВТБ. Год назад устроился в банк и получил командную задачу — построить единую библиотеку компонентов, настолько универсальную, чтобы ее можно было использовать в любом продукте дизайн-системы банка, и при этом она не должна становиться «узким горлышком», как это обычно происходит с UI-китами в крупных компаниях. Дело в том, что в ВТБ существует множество дизайн-систем, над которыми работают десятки дизайнеров.
Непростая задача требовала проработки архитектуры дизайн-системы и сильно зависела от выбора решения для стайлинга. В этой статье подробно расскажу, от чего мы отталкивались и на чем остановили свой выбор.
К истории стилей
Первую версию CSS мы получили в далеком 1996 году, и с тех пор концептуально ничего не менялось: схема Selector { Property: Value } и полная статичность. Плюсом было только то, что грузятся стили из файла параллельно с загрузкой JS-кода. Если вы, конечно, не произвели весь стайлинг внутри HTML-страницы, что замедлило бы ее загрузку.
Работать со стилями стало приятнее с появлением препроцессоров. Некоторые из них добавляли улучшенный синтаксис, переменные и функции для генерации CSS, другие же, как postCSS, дали возможность совершать манипуляции со стилями.
Популярные расширения postCSS позволили автоматически добавлять префиксы для одинакового отображения стилей в браузерах, уменьшали размерность файлов для загрузки пользователями или же помогали проверять разработчикам код на ошибки линтерами.
Схема работы PostCSS
Кроме этого, пришлось еще решать существенную проблему: бесконечное число хаотично названных классов периодически создавали конфликты, что крайне мешало в работе над масштабным проектом.
Решением стало использование CSS-модулей в сочетании с методологией нейминга классов БЭМ (Блок, Элемент, Модификатор).
Пример использования классов в БЭМ:
Заголовок
Текст
Заголовок большой карточки
Текст большой карточки
БЭМ описала правила к наименованию компонентов, его составных частей и модификаций.
CSS-модули позволили безболезненно распиливать стили на разные файлы и ограничивать локальной областью, где к их классам добавился уникальный ключ, исключающий повторы в названиях.
В совокупности с препроцессорами эти решения так хорошо зашли, что до сих пор поставляются из коробки в самых современных фреймворках.
Итак, при использовании этого подхода получаем следующее:
Плюсы
Компоненты стилизуются модульно.
Нет наложения нейминга классов.
Статичный CSS загружается параллельно с JS.
Нет проблем с SSR.
Минусы
Сложно заводить и поддерживать токены для реализации тем.
Отсутствие типизации и подсказок без настройки IDE.
Чтобы соединить стили с компонентами, нужно маппить классы с пропсами.
Актуальный этап развития CSS = > CSS-in-JS
Давайте забьем на CSS и будем генерировать стили прямо из JS. Это легло в основу большинства библиотек, реализующих этот подход. Здесь не нужно прописывать какие-либо классы и разбираться, как компонентам их переключать. Под капот уходят все вопросы добавления префиксов, ключей к названиям и минификации.
Все стало крайне легко: берется функция styled, которая оборачивает HTML-тег, который нужно стилизовать. Стили добавляют через шаблонные строки, и в них же можно получать прямой доступ как к пропсам компонента, так и к общей теме, которую одним движением легко переключить со светлой на темную и так далее.
Пример использования styled-components
Итого, при использовании этого подхода получаем следующее:
Плюсы:
Не нужно думать о соединении стилей с пропсами.
Темы переключаются на лету.
SSR поддерживается, но есть нюансы.
Минусы:
Отсутствие типизации и подсказок.
Рендер стилей происходит только после загрузки JS.
Бесконечная генерация классов с хаотичным неймингом.
А что лучше, чем CSS-in-JS?
Логичным продолжением развития работы с CSS-in-JS стал переход к CSS-in-TS и его реализация в библиотеке stitches.dev с отличной документацией и широкими возможностями. Какие еще важные для нас преимущества можно отметить?
Пример базового добавления стилей в Stitches
Первый плюс — базовый стайлинг. Обертка styled практически такая же, как в styled-components, только стилизация происходит внутри объекта, а не строки. Для каждого CSS-свойства заданы типы, что позволяет без особого труда выставить стили с подсказками редактора кода и заняться более важными делами.
Вариативность стилей в Stitches
Второй плюс. Динамичность в этой библиотеке реализована с помощью вариантов: пропсы, которые передаются в компонент, переключают статичные объекты стилей. Помните, я упоминал БЭМ ранее в статье? Это по сути и есть его реализация, но без лишних движений!
Пример реализации БЭМ библиотекой Stitches
Плюс третий. Способ реализации stitches.dev исключает возможность использования функций и при этом повышает читаемость кода. В своих же бенчмарках (https://stitches.dev/docs/benchmarks) авторы сравнивают подход вариантов против полностью генерируемых стилей. Это не особо показывает реальную производительность, зато подсвечивает, что в других библиотеках достаточно легко можно допустить ошибку и потерять эффективность.
Стайлинг для UI-кита
Если библиотека позволяет стилизовать компоненты, это не значит, что ее будет удобно использовать в UI-ките. В вопросах типового стайлинга stitches.dev в целом понятная и удобная система, но давайте рассмотрим ее в рамках работы UI-кита — это непосредственно относится к нашей задаче.
Создание темы в Stitches
Stitches со стартового гайда предлагает создать файл конфигурации, в котором можно определить тему и общие параметры:
theme: Объявление токенов темы, которые самостоятельно соотносятся с CSS-параметрами.
media: Объявление брейкпоинтов для адаптивной верстки.
utils: Создание уникальных функций-утилит для удобства добавления стилей.
prefix: Добавление префикса для избежания конфликтов.
themeMap: Добавление соотношений кастомных токенов к CSS-параметрам.
Странно, что в других библиотеках темизация спрятана где-то в разделах Advanced, тогда как это уже практически стандарт для сайтов и приложений.
Токены в CSS variables
На этом приятные моменты не закончились. Токены в этой библиотеке — не что-то эфемерное, как переменные в том же SASS, а использование нативных CSS variables!
Достаточно на верхнем уровне передать значения новых токенов, а сами компоненты уже нативным CSS сменят свои стили.
Пропустим разбор брейкпоинтов — с ними создавать адаптивный дизайн здесь очень легко. Лучше перейдем к важнейшей части любой библиотеки компонентов, когда дизайн выходит за рамки готовой реализации и разработчикам приходится создавать кастомы самостоятельно.
Пример обертки компонентов в Stitches
С кастомизацией у stitches также нет проблем — это крайне нативный процесс, происходящий с помощью обертки styled или добавления CSS-пропса. При этом любой вариант кастомизации поддерживает работу токенов.
Добавление темной темы в Stitches
Отдельно стоит отметить простоту использования тем: базовая создается в стартовой конфигурации, а все последующие поверх уже перезаписываются токенами. Нужно лишь на верхнем уровне приложения добавить класс созданной темы. При этом внутри компонентов идет привязка токенов по объекту темы, поэтому при потере каких-либо токенов тайпскрипт сразу укажет на эту проблему.
Соответственно, для продуктовых команд можно предложить кастомизировать токены темы, не опасаясь их потерять. А предоставив доступ к низкоуровневому API компонентов, мы расширяем возможности кастомизации нашего набора компонентов до предела. Но об этом в другой раз 🙂
Итого, при использовании этого подхода получаем следующее:
Плюсы:
Типизация и подсказки.
Вариативность стилей по канонам БЭМ.
Нативный стайлинг внутри JS/TS.
Темы переключаются на лету.
Отличная документация.
SSR поддерживается, но есть нюансы.
Из минусов — рендер стилей только после загрузки JS.
Наш опыт
Более чем за шесть месяцев работы со stitches мы столкнулись только с одной проблемой — случайным порядком вариантов при генерации классов. Например, компонент Input имеет булевые варианты Error и Disabled, и стили первого перекрывали стили второго. А нам нужен как раз обратный эффект.
Решением этой проблемы стало банальное добавление !important или использование compoundVariants. Но в будущем рассчитываем, что ситуацию исправит добавление поддержки CSS layers в библиотеку.
В остальном stitches отлично подошла под требования в рамках дизайн-системы. В следующей статье расскажем о применении библиотеки в нашей архитектуре. До встречи!
Сравниваем структуры хоть и глубоко, но быстро / Хабр | Веб-студия Nat.od.ua
Сравниваем структуры хоть и глубоко, но быстро / Хабр
Здравствуйте, меня зовут Дмитрий Карловский и я.. автор множества микроскопических и самых шустрых в своём классе библиотек. Одна из них — $mol_compare_deep, умеющая сравнивать произвольные структуры, даже содержащие циклические ссылки. И сейчас я вам расскажу, как ей это удаётся.
Cперва, небольшая предыстория, почему эта библиотека вообще нам понадобилась для реализации реактивной системы.
Эквивалентные изменения
Порой значение меняется на эквивалентное. И тут есть разные подходы к отсечению вырожденных вычислений.
👯Every: Реакция на каждое действие
🆔Identity: Сравнение по ссылке
🎭Equality: Структурное сравнение
🔀Reconcile: Структурная сверка
Dupes: 👯Every
В библиотеках типа RxJS каждое значение является уникальным событием, что приводит к ненужному запуску реакций.
777 != 777
Чтобы этого не происходило, нужно писать дополнительный код, который часто забывают, и потом огребают.
Dupes: 🆔Identity
Многие библиотеки всё же умеют сравнивать значения. И если состояние не поменялось, то реакции не срабатывают. А если поменялось, даже на эквивалентное значение, то срабатывают.
777 == 777
!=Если мы нафильтровали новый массив, с тем же содержимым, то скорее всего нам не нужно запускать каскад вычислений. Но вручную уследить за всеми такими местами – мало реалистично.
Dupes: 🎭Equality
Наиболее продвинутые библиотеки, типа $mol_wire, делают глубокое сравнение нового и старого значения. В некоторых других, типа CellX, его можно включить в настройках.
777 == 777
== !=Это позволяет отсекать лишние вычисления как можно раньше — в момент внесения изменений. А не в момент рендеринга заново сгенерированного VDOM в реальный DOM, как это часто происходит в React, чтобы узнать, что в доме‑то менять и нечего.
Глубокое сравнение — это, безусловно, сама по себе более дорогая операция, чем просто сравнение двух ссылок. Однако, рано или поздно, сравнить всё содержимое всё равно придётся. Но гораздо быстрее это сделать пока данные рядом, а не когда они разлетятся по тысяче компонент в процессе рендеринга.
Тем не менее, если данные поменялись, то полетят дальше по приложению и будут глубоко сравниваться снова и снова, что никуда не годится. Поэтому тут важно реализовывать кеширование результата глубокого сравнения для каждой пары сравниваемых объектов.
Dupes: 🔀Reconcile
Наконец, можно пойти ещё дальше, и не просто глубоко сравнивать значения, но и делать их сверку, чтобы сохранить ссылки на старые объекты, когда они эквивалентны новым.
const A = { foo: 1, bar: [] }
const B = { foo: 2, bar: [] }
reconcile( A, B )
assert( B.foo === 2 )
assert( B.bar === A.bar )
Как видите, A и B у нас тут отличаются, но свойство bar осталось таким как было. Это хорошо с точки зрения GC, ведь мы переиспользуем объекты, находящиеся в старом поколении сборщика мусора. А объект из молодого поколения при сверке был выборошен, что очень быстро.
Кроме того, когда вдальнейшем в компоненте, что рендерит bar, будет снова произведена его сверка, то произойдёт это крайне быстро, ведь старое и новое значения будут идентичны. С другой стороны, если объекты всё же будут отличаться, то повторная сверка снова пойдёт по всем внутреннстям объекта. Тут опять же необходимо кеширование. Но..
Изменение полей нового объекта на значения из старого — это не всегда безопасная операция. Например, с DOM‑элементами такие финты проворачивать нельзя. В лучшем случае это не заработает, а в худшем вообще его сломает. В ряде случаев вы будете получать исключение при попытке изменить объект. Порой изменения будут попросту игнорироваться, а порой запускать сеттеры, делающие какие‑нибудь стрёмные дела.
К тому же, если объекты фактически идентичны, нам надо сначала их глубоко сравнить. И если они одинаковы, то вернуть старый, а если нет — начать менять новый. Ну либо сразу начать менять новый, чтобы потом выяснить, что мы поменяли все его свойства, так что вернуть надо старый.
Короче, данный подход не самый шустрый и надёжный, поэтому в $mol мы от него отказались в пользу глубокого сравнения с кешированием.
Когда реактивное состояние принимает новое значение, мы должны уведомить подписчиков об изменении. Но если изменение даёт эквивалентный результат, то можно ничего и не делать. Нам надо лишь понять: является ли изменение эквивалентным, или нет.
Например, если мы получили новый массив, но он поэлементно равен предыдущему, то даже если мы пересчитаем всё, зависящее от него, приложение, то для пользователя ничего не поменяется.
Получается нам надо уметь глубоко сравнивать новые данные и старые. Причём делать это быстро. Но тут на нашем пути может возникнуть ряд трудностей..
Некоторые объекты (например, Value Object) можно сравнивать структурно, другие же (например, DOM элементы или бизнес-сущности) – нельзя. Как их отличать?
Ну, стандартные типы (массивы, структуры, регулярки и тп) можно просто детектировать и сравнивать структурно.
С пользовательскими же чуть сложнее. По умолчанию не будем рисковать, а будем сравнивать их по ссылке. Но если в объекте объявлен метод Symbol.toPrimitive, то считаем, что это сериализуемый объект, а значит такие объекты можно сравнивать через сравнение их сериализованных представлений.
class Moment {
iso8601: string
timestamp: number
native: Date
( mode: ‘number’ | ‘string’ | ‘default’ ) {
switch( mode ) {
case ‘number’: return this.timestamp
case ‘string’: return this.iso8601
case ‘default’: return this.iso8601
}
}
}
Если мы сравнили глубокие структуры и выяснили, что они в целом отличаются, то, когда будем их поддеревья передавать дальше, было бы опрометчиво сравнивать их снова и снова, ведь мы это уже сделали ранее. Поэтому результат глубокого сравнения пар объектов мы будем кешировать в двойных WeakMap, что обеспечит нам автоматическую очистку кеша по мере сборки объектов сборщиком мусора.
После сравнения, один из объектов Left и Right обычно выкидывается. В первом случае это освободит и кеш целиком, и все его данные, а значит при изменении значения, у нас ничего лишнего в памяти не останется. Во втором же случае освободятся только данные, а сам кеш останется для будущих сравнений, что предотвращает лишнюю аллокацию кешей при частом прилёте эквивалентных значений.
Наконец, в данных могут встретится циклические ссылки. Как минимум тут нельзя уходить в бесконечный цикл. А желательно правильно их сравнивать.
Например, следующие два объекта структурно эквивалентны:
const left = { id: ‘leaf’, kids: [] }
left.kids.push({ id: ‘son’, parent: left })
const right = { id: ‘leaf’, kids: [] }
right.kids.push({ id: ‘son’, parent: right })
Оказывается, поддержать циклические ссылки совсем не сложно, когда у нас уже есть кеш. Сперва пишем в него, что объекты эквивалентны, и погружаемся в глубь. Если снова наткнёмся на эту пару объектов, то возьмём значение из кеша и пойдём дальше. Если же где-то найдём отличия, то и в кеше потом поправим, что объекты всё-таки не эквивалентны.
В результате, у нас получилась библиотека $mol_compare_deep, размером в 1 килобайт, которая быстрее любых других, представленных в NPM:
Поиграться с ней можно в нашей JS-песочнице или сразу в своём проекте. Баги и респекты присылайте в тему про $mol на форуме Гипер Дев.
Актуальный оригинал на $hyoo_page
Советы по веб-разработке, которые я дал бы себе 2 года назад / Хабр | Веб-студия Nat.od.ua
Советы по веб-разработке, которые я дал бы себе 2 года назад / Хабр
Веб-разработка — это быстрорастущая область карьеры, и спрос на квалифицированных веб-разработчиков высок. Будучи студентом, вы можете предпринять шаги, чтобы подготовиться к успешной карьере веб-разработчика после школы. Вот несколько советов о том, как стать отличным веб-разработчиком после школы.
Изучите основы
Чтобы стать отличным веб-разработчиком, важно иметь прочную основу в основах. Ознакомьтесь с HTML, CSS, JavaScript и другими широко используемыми языками программирования. Пройдите онлайн-курсы или посетите семинары, чтобы изучить эти языки и другие необходимые инструменты программирования.
Создайте сильное портфолио
Для веб-разработчика важно иметь портфолио своих работ. Подумайте о создании различных проектов, демонстрирующих ваши навыки и способности. Участвуйте в соревнованиях или соревнованиях по программированию, так как они также помогут вам освоить новые приемы и приемы.
Сосредоточьтесь на пользовательском опыте
Пользовательский опыт является неотъемлемой частью веб-разработки. Важно не только сделать сайт привлекательным, но и удобным для пользователя. Помните, что пользователи могут быть демотивированы, если они найдут веб-сайт, который сбивает с толку, непривлекателен или требует времени для загрузки.
Будьте в курсе последних тенденций
Тенденции веб-разработки постоянно меняются, поэтому важно быть в курсе новейших инструментов и технологий, чтобы оставаться конкурентоспособными. Присоединяйтесь к сообществам веб-разработчиков и подписывайтесь на интернет-публикации, чтобы всегда быть в курсе.
Самореклама
Как один из лучших способов выделиться на рынке труда веб-разработки, самореклама имеет решающее значение. Создайте профессиональный профиль на платформе веб-разработки, такой как GitHub или LinkedIn. Делитесь своими проектами и достижениями в социальных сетях, чтобы потенциальные сотрудники могли лучше вас найти.
Практикуйтесь постоянно
Частая практика, даже вне учебных занятий, является неотъемлемой частью того, чтобы стать великим веб-разработчиком. Подумайте о настройке среды разработки, создании экспериментальных веб-страниц или серии проектов, и в конечном итоге вы сможете стать мастером веб-разработчика.
Чтобы стать отличным веб-разработчиком, нужно время и практика, но следование этим советам может увеличить ваши шансы на успех. Помните, что сохранять позитивный настрой, быть открытым для обратной связи и уметь решать проблемы — важные качества отличного веб-разработчика.
Create react app умирает? / Хабр | Веб-студия Nat.od.ua
Create react app умирает? / Хабр
Зайдя на официальный сайт React я не сразу понял, что произошло.
Когда мы заходим на страницу документации React в раздел установки, мы можем увидеть различные предложенные варианты установки фреймворков React, а именно Next.js, Remix, Expo, Gatsby. Но при этом нет варианта установки самого React в чистом виде. Неужели React сдает позиции.
На самом деле это не так. Если присмотреться, то можно найти скрытую сноску с информацией о том, можно ли использовать React в чистом виде. Ниже я представлю перевод части данной сноски.
Вы определенно можете использовать React без фреймворка. Однако, если вы создаете новое приложение или сайт полностью с помощью React, мы рекомендуем использовать платформу.
И вот почему.
Даже если сначала вам не нужна маршрутизация или получение данных (data fetching), вы, скорее всего, потом заходите добавить необходимые для них библиотеки. По мере роста вашего Javascript приложения растет ваш код и вам придется выяснять, как разнести этот код для каждого роута по отдельности. Во время увеличения потребностей в получении данных вероятно придется столкнуться с проблемами водопадом между сервером и клиентом (server-client network waterfalls), что замедлит ваше приложение. Поскольку большинство пользователей из аудитории имеет плохие условия сетевого соединения и недорогие устройства, вам понадобится создать HTML с ранним отображением компонентов – либо на сервере, либо во время сборки. Изменение настроек для выполнения части кода на сервере или во время сборки может быть сложным.
. . . . . . .
Фреймворки React на этой странице решают подобные проблемы по умолчанию, без дополнительной работы с вашей стороны. Они позволяют вам начать очень экономно, а затем масштабировать ваше приложение в соответствии с вашими потребностями.
. . . . . . .
Если вы все еще не уверены, или ваше приложение имеет необычные ограничения, которые плохо обслуживаются этими фреймворками, и вы хотите развернуть свою собственную пользовательскую настройку, мы не можем остановить вас — дерзайте! Берите react и react-dom из npm, настраивайте свой пользовательский процесс сборки с помощью сборщика, такого как Vite или Parcel, и добавляйте другие инструменты по мере необходимости для маршрутизации, статической генерации или рендеринга на стороне сервера и многого другого.
Исходя из данной информации в принципе можно понять, что с React все в порядке. Просто разработчики говорят о том, что React – это библиотека, которая не имеет множества встроенных инструментов и лучше использовать какой-либо фреймворк, но при этом никто не перестает поддерживать и использовать React.
Но есть еще одна вещь, которую необходимо выяснить…
Где рекомендация create-react-app?
На данный момент на странице документации полностью исчезла информация о том, что мы можем использовать create-react-app. Даже в приведенной выше сноске говориться о том, что необходимо брать react, reac-dom, сборщик пакетов и настраивать под себя.
Также, если обратить внимание на репозиторий create-react-app, мы можем увидеть, что последний коммит был сделан 8 сентября.
В issue гитхаба уже начали появляться темы о том, что же происходит.
Пробежавшись по issue, я нашел ссылку на пост Reddit, в котором официальная команда React дала ссылку на более ранний issue с подробным описанием происходящего. Если вы хотите почитать, ссылку прикладываю ниже.
Ссылка
Заменить рекомендацию Создать приложение React на Vite на t3dotgg · Запрос на вытягивание #5487 · reactjs/react.dev (github.com)
Если говорить кратко, о том, что говориться в ответе, то Create React App решал множество проблем, но временем происходила стагнация, многие начали подмечать, что приложения, созданные с использованием Create React App становятся медленнее альтернативных. При всем при этом Create React App сильно отстает в технологиях, например, не поддерживает SSR/SSG, которые, как говорит разработчик, более эффективны и для многих сайтов были бы предпочтительнее. Поэтому к React надо относиться именно как к библиотеке и по возможности использовать фреймворки, которых много и это хорошо.
На данный момент Create React App не соответствует цели быть лучшей утилитой для создания приложения. Поэтому разработчики видят несколько вариантов действий, которые можно предпринять:
1) Создать новый фреймворк с нуля, при этом переквалифицировать Create React App под него. На данный момент не считается целесообразным.
2) Отказаться от Create React App и поддерживать другой сложный шаблон для создания приложения с использованием Vite.
3) Уменьшить использование или вовсе упразднить Create React App и продвигать фреймворки. При этом говориться, что фреймворки будут предпочтительными, но не обязательными. Но при этом возникает проблема в виде отсутствия фирменного CLI шлюза, что будет плохо влиять на бренд.
4) Выбрать какой-либо фреймворк и использовать Create React App для создания приложения уже на основе этого фреймворка. Но тогда у других фреймворков возникнет проблема в плане конкуренции, а также все старые туториалы сразу перестанут работать.
5) Сделать Create React App лаунчером. Create React App будет предлагать список рекомендуемых фреймворков, а также возможность использовать классический подход создания приложения без фреймворка (но, возможно с Vite под капотом)
В настоящее время разработчики склоняются к варианту под номером 5, чтобы пользователи явно понимали, что лучше использовать фреймворки, но при этом не лишать их возможности работы на чистом React.
Заключение
В заключение хочу сказать, что Create React App скорее всего не умрет и им дальше можно будет пользоваться, но нас ждут перемены в использовании данной утилиты.
P.S. Надеюсь, статья была полезна и информативна. Если кто-то имеет более свежую информацию, я буду рад ее почитать.
Трансплантация реактивности | Веб-студия Nat.od.ua
Трансплантация реактивности
Здравствуйте, меня зовут Дмитрий Карловский, и я.. тот самый чел, который написал реактивную библиотеку $mol_wire. Именно благодаря мне вам есть сейчас чем пугать детей перед сном.
Но просто написать классную библиотеку – слишком мелкая цель. Построить на ней богатый фреймворк с кучей батареек – уже интересней, но всё ещё не достаточно амбициозно. Разработанный мной подход может стать lingua franca в коммуникациях между библиотеками, состояниями браузера, и даже между удалёнными узлами.
Берегите синапсы, сейчас будет настоящий киберпанк..
Открыть ментальный сокет
Бестолковый дизайн / Хабр | Веб-студия Nat.od.ua
Бестолковый дизайн / Хабр
Здравствуйте, меня зовут Дмитрий Карловский и я.. нет, я не дизайнер. Так что не стоит воспринимать мои слова всерьёз. Я просто пользователь. И у меня пригорает от популярных дизайнерских решений, бездумно копируемых из одного приложения в другое..
Переключатель панелей
Дизайнер решил, что если все табы в экран не влезли, то тем хуже для этих табов, и им делается обрезание. Однако, часто пользователь не знает какие вообще есть табы, а чтобы узнать, надо поскроллить туда-сюда. При этом, если табы обрезались неудачно, то он может даже не догадываться, что там вообще есть что скроллить. А даже если пользователь и знает, что нужный ему таб тут есть, то он не может просто перейти к нему – надо елозить пальцем из стороны в сторону. И счастье, если дизайнер не додумался сделать переключение табов по одному, без возможности отскроллить к нужному и нажать на него.
А что если не выпендриваться, и просто сделать многострочный переключатель?
Тут все варианты сразу перед глазами. Переход к любой панели происходит за одно нажатие. Да, он может занять две строки, но эти сроки получаются меньше, так что по вертикали занимают примерно столько же места. Если же табы не умещаются и в 2 строки, то их число уже определённо больше, чем помещается в кошелёк Миллера, и стоит подумать о полноценном боковом меню с группировкой и поиском.
Поле ввода
Дизайнер хотел дать контенту больший приоритет, и поэтому решил написать все пояснения к полям буквами в два раза меньшего размера. Однако, пользователи с не слишком идеальным зрением, испытывают не просто трудности с чтением мелкого текста, а самую настоящую боль в глазах от повышенного их напряжения для фокусировки.
А что если не выпендриваться, и просто уменьшить контраст второстепенных текстов?
Тут уже лейблы и не перетягивают внимание на себя, и без проблем могут быть прочитаны при необходимости.
Меню действий
Один дизайнер решил, а другой с ним согласился, что аккуратное меню внизу экрана прелестно смотрится и не загораживает основной контент, располагающийся обычно сверху. Это всё, конечно, прекрасно, но когда нажимаешь кнопку вверху экрана, то, чтобы дотянуться до его нижнего края, нужно перехватывать девайс в руке. Порой это приходится делать в несколько движений, особенно в попытке дотянуться до самого труднодоступного левого нижнего угла экрана. Нередко это приводит к выпадению девайса из руки. А трещины, идущие через весь экран, – это уже не так красиво, как в дизайн-макетах.
А что если не выпендриваться, и просто показывать меню рядом с местом его вызова?
Скучно? Конечно! Но пользователь запустил наше приложение не для того, чтобы с менюшками развлекаться и девайсом жонглировать, а чтобы наименее энергозатратно решать свои задачи.
Селектор из списка
Один дизайнер долго подбирал идеальные цвета, тени, шрифты, отступы, самые сексуальные анимации и переходы.. а потом вывалил в селектор 50+ опций плоским списком и решил, что это хорошо, а другой с ним согласился.
Это только в демонстрациях перед менеджментом можно выбрать любое значение и пойти дальше. А при реальном использовании пользователь может минуту ковыряться в поисках нужного значения, вспоминая с какой буквы оно начинается и какая буква идёт после какой в алфавите. Особенно весело настраивать переводчик, число языков в котором исчисляется сотнями.
А что если не выпендриваться, и просто добавить полнотекстовую фильтрацию ко всем селекторам?
И нет, использование текстового поля с автозавершением, о котором подумал дизайнер, не является альтернативой, так как:
Фокусировка текстового поля открывает экранную клавиатуру, которая перекрывает опции.
Значения, выбираемые селектором, обычно являются внутренними идентификаторами, а пользователю показывается что-то более понятное для него.
Текстовые поля позволяют вводить не валидные значения, что требует ручного решения множества краевых случаев: валидация, нормализация, сигнализация и тд.
Селектор времени
Слева дизайнер решил, что крутить 3 барабана – это интуитивно, тактильно и весело. Да, весело, поиграться первые пару раз. А потом это сильно раздражает, что вместо двух простых тапов приходится:
Сначала вслепую мотать барабан на 12-24 значения.
Потом мотать его обратно, потому что перелетел нужное значение.
Ещё пару раз туда-сюда, замедляя скорость вращения.
Потом тоже самое со вторым барабаном уже на 60 значений.
Ну и третий вырожденный барабан на 2 значения ущипнуть при необходимости.
Справа дизайнер решил, что современный человек до сих пор пользуется стрелочными часами, так что мгновенно найдёт нужное число на круговом циферблате. Однако, реальность суровее:
Подавляющее большинство часов сейчас имеют числовой циферблат.
Многие люди имеют ощутимые трудности с поиском чисел в круге, по сравнением с линейным порядком.
Мелкие числа больше 12 искать сложно даже тем, кто привык ко круговому циферблату.
А что если не выпендриваться, и просто решить задачу пользователя?
Чтобы ввести время нужно всего два нажатия:
Выбрать час
Выбрать минуту
Либо можно тапнуть в поле ввода и ввести значение с клавиатуры или вставить из буфера обмена.
Да, точность такого селектора до 5 минут, но зачастую даже такая точность является избыточной. При необходимости же, можно ввести время вручную хоть с миллисекундами.
Призывы к действию
Подкидывайте в комментариях свои примеры бестолкового дизайна от именитых дизайнеров и компаний.
Присоединяйтесь ко критическим обсуждениям дизайна и пользовательского опыта в Гильдии Hyper Dev.
Рассказывайте, как вы сами элегантно решали интерфейсные проблемы, до чего другие не додумывались или не решались.
А главное – думайте о тех людях, которые реально пользуются вашими интерфейсами, а не о тех, которые только потеребонькать их открывают, но мнение имеют.
Актуальный оригинал на $hyoo_page.
Сообразим на троих. Троичные компьютеры / Хабр | Веб-студия Nat.od.ua
Сообразим на троих. Троичные компьютеры / Хабр
В повседневной жизни мы используем десятичную систему счисления. Почему именно её — это вопрос отдельный. В конце концов, существуют системы с основанием 12 (по фалангам пальцев без большого), 5 (пальцы на одной руке), 20, 60 и так далее. В компьютерах всё несколько проще — там (можно даже сказать, «Традиционно») используется двоичная система, как самая лёгкая для воплощения. Есть ток — нету тока. Есть отверстие в перфокарте — нет отверстия. Ноль или единица. Короче говоря, «да» или «нет» — третьего не дано. А что будет, если дать? Об этом и поговорим.
Собственно, существуют две возможности «дать» это самое третье: в виде «0, 1, 2» или в виде «-1, 0, 1». Первая система называется несимметричной, вторая — симметричной. Само по себе введение троичной системы счисления выгодно тем, что экономичность хранения данных для каждого разряда выше, чем для любой другой системы счисления. Связано это с тем, что, как говорится, «God counts by E», и наиболее экономичной является система с основанием, равным числу Эйлера (доказательство ищите на стр. 37), а тройка ближе к Е, чем двойка.
Но это ещё не всё — если несимметричная система является просто «расширением» двоичной, позволяя хранить в одной ячейке больше информации, то у симметричной системы выгод гораздо больше.
Одна из таких выгод — это появление значения «0», то есть «не определено». Как правило, 0 передаёт отсутствие значения, а 1 и -1 (иногда вместо цифр используются «+» и «-») — двоичное «да» и «нет». Чем это может быть выгодно? Вообще, зависит от того, как именно задана работа логики. Например, двоичный компьютер столкнувшись с парадоксальным запросом в духе «Второе утверждение истинно — первое утверждение ложно» впадёт в ступор. Троичный компьютер в ответ может просто выдать 0 — он не ответит, но избежит ответа. Или 1 — если работает на «логике парадокса». Ну, и помимо этого многие вопросы можно подвергнуть улучшению — например, не «наличие/отсутствие», а «недостаток/норма/избыток».
— Какой ужасный сон! Повсюду были нули и единицы. И мне показалось, что я увидел двойку!
— Бендер, это просто сон. Двоек не существует.
Выгода вторая — отрицательные значения. В двоичной системе, чтобы показать, что число имеет отрицательное значение, нужен дополнительный знак. В троичной системе если ведущий разряд числа отрицателен, то и число отрицательно. Смена знака с положительного на отрицательный и обратно достигается инвертированием всех его разрядов (что самое интересное, советский троичный компьютер «Сетунь» воспринимал «инвертирование» буквально — отрицательные числа печатались вверх ногами).
Из предыдущих двух пунктов выходит третий — увеличенная скорость вычислений при пониженном объёме занимаемой памяти. В двоичной системе нужно два разряда, чтобы показать знак числа, а вот в троичной системе нужен только один разряд (собственно, само число). Далее — сложение, самая часто выполняемая операция, которую сильно тормозят переносы из разряда в разряд — в случае двоичной системы они происходят в 50 % случаев, а в троичной (симметричной) системе — в 8 случаях из 27, т. е., примерно в 29,6% случаев. Большая скорость и меньшее количество элементов повышают быстродействие троичной машины примерно в 1,6 раза, и, соответственно, уменьшают энергопотребление.
Ну, или как-то так
Казалось бы, почему такое инженерное «wunderwaffe» не применяется повсеместно? На то есть несколько причин. Самая основная — их особенно-то никто и не разрабатывал. Самым известным примером троичного компьютера является советская «Сетунь» 50-х годов разработки. Уникальна она даже не потому, что является первой троичной ЭВМ (но не первой троичной вычислительной машиной), а потому, что сотрудники лаборатории ЭВМ МГУ собирали её буквально на коленке и из подручных материалов, потому что:
…мы должны были для МГУ получить машину М-2, которую сделали в лаборатории Брука. Но получилась неувязочка. На выборах академиков Сергей Львович Соболев — наш руководитель — проголосовал не за Брука, а за Лебедева. Брук обиделся и машину не дал.
Троичная счётная машина Фаулера — первый троичный калькулятор:
Помимо обычной
«Сетуни»
была также разработана «Сетунь-70» — принципиально новая машина со стеками команд и операндов (разработана, что характерно, к 100-летию со дня рождения Ленина). Ни оригинальная, ни 70-я «Сетуни» в большую серию не пошли — оригинал по не до конца понятным причинам весьма прозаично «задушили», а 70-я была единичным экземпляром. А помимо «Сетуни»… не было ничего. Американцы одно время экспериментировали с троичной логикой, и даже добились некоторого прогресса, но до строительства полноценных ЭВМ дело не дошло (максимум — эмулятор троичной логики «Ternac» для двоичной машины, который был написан на FORTRAN’е). В Канаде в 80-х был разработан чип ROM на основе несимметричной троичной логики (похожий чип можно и создать самостоятельно). В 90-х был разработан троичный
язык программирования TriINTERCAL
— опять же, на основе несимметричной троичной логики. Какие-то разработки ведутся до сих пор, хотя и не являются приоритетными. Другими словами, для их повсеместного применения просто нет ни опыта, ни материальной базы.
Собственно, «Сетунь». Достаточно компактна по сравнению с конкурентами
Из этого идёт вторая проблема — мы просто-напросто привыкли к двоичным компьютерам. Изначально они были гораздо более простым решением (сделать детектор «есть ток — нет тока» было гораздо легче, чем «ток ниже — ток номинальный — ток выше» — а ведь силу тока надо было точно контролировать…). Со временем их стало так много, и они стали так хорошо изучены, что нужды в каких-то более продвинутых системах пока (!) не возникает. Тем более, что все существующие на данный момент компьютерные программы заточены именно на бинарную логику. Если вводить троичные компьютеры в использование, то под них либо нужно писать свои собственные программы (что дорого и долго), либо делать их совместимыми с двоичными — а это не всегда возможно, и, возможно, даже сложнее.
Тем не менее, если кто-то всё-таки решится вложить время и деньги в разработку троичных машин и программ, то, потенциально, это приведёт к значительному росту мощностей компьютеров по всему миру, и, теоретически, может даже снизить необходимость в микропроцессорах с нанометровым техпроцессом. Плюс, не стоит забывать про такую весёлую вещь, как квантовые компьютеры. В квантовой физике мало что понимают даже те люди, которые полжизни ей занимаются. Например, квант может быть, как волной, так и частицей. Когда не ясно, в каком состоянии находится квант — это называется «Суперпозицией», отразить которую как раз может помочь дополнительное значение троичной логики. В общем, поле возможностей, открываемое троичными ЭВМ, бесконечно.
Непонятно только, когда и в какую сторону это поле начинать переходить.
Понять комбинаторные селекторы и селекторы потомков в CSS / Хабр | Веб-студия Nat.od.ua
Понять комбинаторные селекторы и селекторы потомков в CSS / Хабр
Периодически я сталкиваюсь с проблемой – не хочу ставить лишний класс элементу внутри различных кнопок, ссылок и label-ов. Зачастую это текст, который нужно подсветить или галочка чекбокса или маленькая иконка.
Как же справиться с такой проблемой? Тут самым простым и понятным решением будет наследование. Возьмём код ссылки с иконкой, которую нужно анимировать:
Все товары
Сделать это несложно, достаточно просто прописать несколько правил:
/*БАЗОВЫЕ ПРАВИЛА*/
a {
text-decoration: none;
color: inherit;
font-family: sans-serif;
}
.text_arrow-btn {
display: flex;
align-items: center;
font-size: 22px;
line-height: 142%;
}
/*ИСПОЛЬЗОВАНИЕ НАСЛЕДОВАНИЯ*/
.text_arrow-btn span { /*Для span которые внутри ссылки*/
margin-right: 16px;
}
.text_arrow-btn svg { /*Для svg которые внутри ссылки*/
transition: transform 0.3s;
width: 36px;
height: 14px;
}
.text_arrow-btn:hover span {
text-decoration: underline;
}
.text_arrow-btn:hover svg {
transform: translateX(12px);
}
Пробел обращается ко всем детям элемента с подходящим селектором. Символ “больше” > обратится только к прямому потомку.
Да, в CSS выглядет не очень, но в SASS всё уже немного приятнее:
a
text-decoration: none
color: inherit
font-family: sans-serif
color: #323F4C
.text_arrow-btn
display: flex
align-items: center
span
margin-right: 16px
svg
transition: transform 0.3s
width: 36px
height: 14px
path
transition: stroke 0.3s
&:hover
svg
transform: translateX(12px)
span
text-decoration: underline
&:active
color: #B6B5B5
path
stroke: #B6B5B5
Думаю что этим я глаза никому не открыл – вполне стандартная история.
Соседний комбинатор – “+”
Однако, на этом мы не останавливаемся. Теперь другая задача – стилизация чекбокса. Если вы хоть раз сталкивались с этой проблемой, то вы знаете лицо боли. Потому что убрать стандартные стили просто так не получится, получится только убрать чекбокс к чёртовой бабушке и стилизовать заново из div или span. Но чтобы добавить неинтерактивным элементам интерактивности придётся использовать JS. Или не придётся?..
Тут нам поможет волшебный + – это комбинатор родственных элементов. Он объединяет два элемента, находящихся на одном уровне, и второй должен следовать СРАЗУ за первым.
Звучит сложно – работает просто. Выбирается следующий сразу за элементом селектор. Вот так:
.main-checkbox
cursor: pointer
span
display: inline-block
width: 24px
height: 24px
background: #F8F8F8
display: flex
align-items: center
justify-content: center
transition: background 0.3s
svg
width: 12px
height: 9px
opacity: 0
transition: opacity 0.3s
&:hover
span
background: #EBEBEB
input
display: none
&:checked+span /*вот он*/
background: #F8F8F8
svg
opacity: 1
Обращаем внимание на: &:checked+span тут “+” говорит нам о том, что будет выбран следующий за чекнутым input span. И вуаля – чекбокс работает как часы и он стилизован.
Родственный комбинатор – “~”
Но мы не останавливаемся. Имеем ещё одну задачу: чекбокс у которого внутри идёт span и svg одновременно и нужно при наведении изменить цвет и текста и svg. Да, можно обернуть элементы в div и использовать +, но фу, лишний тег – это полный отстой.
Тут нам поможет тильда ~ (не путать с тильтом). Этот символ не выражает усталость и безысходность – совсем наоборот. Он даёт нам выбрать теги, находящиеся на одном уровне с элементом.
Вот наш чекбокс с иконкой:
И вот стили:
.radio-sort
font-family: sans-serif
margin-right: 48px
cursor: pointer
display: flex
align-items: center
&:last-child
margin-right: 0
input
display: none
span
display: inline-block
svg
width: 10px
height: 14px
display: inline-block
margin-left: 12px
input:checked + span
font-weight: 800
input:hover + span
color: #1eaf9f
input:hover ~ svg
path
stroke: #1eaf9f
тильда выберет следующий за span svg – очень удобно!
Итак, подведём итог.
Пробел – выберет все дочерние элементы, соответствующие селектору:
Знак больше > выберет только дочерние элементы, являющиеся прямыми потомками:
Знак + выберет следующего за элементом потомка:
Тильда ~ выберет всех одноуровневых потомков:
3 правила в веб-дизайне, которые упрощают жизнь разработчикам / Хабр | Веб-студия Nat.od.ua
3 правила в веб-дизайне, которые упрощают жизнь разработчикам / Хабр
С началом карьеры веб-дизайнера, я сталкивалась с ситуацией, когда макеты не верстались из-за бардака везде. Несколько раз приходилось переделывать работу, потому что верстальщики отправляли её обратно (с матюками). Нервные какие-то…
Закон жизни №1
Изрядно поколотив подушку, я собрала «волю в кулак» и оформила стандарты и правила, по которым макет сайта будет проектироваться. Назваю их микстурами от нервов. В этой статье я опишу, что «под капотом» моих макетов.
1 микстура от нервов — Grid options
С чего я начала? Конечно с размеров макетов и сетки. Тут не обойти вопрос: «Какую сетку использовать: Bootstrap или google.material?» Для себя я выбрала скомбинировать эти две методологии . Их системы сеток мне как дизайнеру понятны, а разработчики уже имеют наработки breakpoints.
Итак, фреймворк Bootstrap 5 предлагает создателям интерфейсов, 6 уровней сетки, в каждой из которых свой размер контейнера. На основе этих требований я строю модульные сетки (базовая сетка + колоночная) с шагом 8 px.
Разрешение XX-Large
Общая ширина макета 1480 px, а боковые отступы справа и слева по 80 px.
Дублирую информацию с картинки: Ширина макета 1480 px, ширина контейнера — 1320 px, количество колонок — 12, ширина 1 колонки — 88 px , ширина отступов — 24 px. Sitebar off — 64 px, type — left. Sitebar on — 200 px, type — left. Скачать image тут.
Этого мне показалось мало, и я решила в сетке XX-Large, X-Large и Large разместить фиксированный размер sitebar off и sitebar on. Эта заготовка на случай, когда сетка будет использоваться для 1 экрана с возможным выбором решения использовать боковое меню.
Разрешение X-Large
Общая ширина макета 1272 px, а боковые отступы справа и слева по 72 px.
Дублирую информацию с картинки: Ширина макета 1272 px, ширина контейнера — 1128 px, количество колонок — 12, ширина 1 колонки — 72 px , ширина отступов — 24 px. Sitebar off — 64 px, type — left. Sitebar on — 200 px, type — left. Скачать image тут.
Разрешение Large
Общая ширина макета 1096 px, а боковые отступы справа и слева по 80 px.
Дублирую информацию с картинки: Ширина макета 1096 px, ширина контейнера — 936 px, количество колонок — 12, ширина 1 колонки — 56 px , ширина отступов — 24 px. Sitebar off — 64 px, type — left. Sitebar on — 200 px, type — left. Скачать image тут.
Разрешение Medium
Общая ширина макета 808 px, а боковые отступы справа и слева по 32 px.
Дублирую информацию с картинки: Ширина макета 808 px, ширина контейнера — 744 px, количество колонок — 12, ширина 1 колонки — 40 px , ширина отступов — 24 px. Sitebar off — 48 px, type — left. Sitebar on — 160 px, type — left. Скачать image тут.
Разрешение Small
Общая ширина макета 592 px, а боковые отступы справа и слева по 16 px.
Дублирую информацию с картинки: Ширина макета 592 px, ширина контейнера — 560 px, количество колонок — 8, ширина 1 колонки — 56 px , ширина отступов — 16 px. Скачать image тут.
Фиксированный размер места для бургера 32×32 px, type Right, Top. Icon «Burger» — 21 px.
Место для бургерного меню
Меню раскрывается на 100% разрешения экрана. Оставляю себе напоминание об Icon «Clouse» — 21 px.
Пример как будет выглядеть раскрывшийся “бургер”
Разрешение Extra Small
Общая ширина макета 368 px, а боковые отступы справа и слева по 16 px.
Дублирую информацию с картинки: Ширина макета 368 px, ширина контейнера — Auto, количество колонок — 4, ширина 1 колонки — Auto , ширина отступов — 16 px. Скачать image тут.
Фиксированный размер места для бургера 24×24 px, type Right, Top. Icon «Burger» — 21 px.
Место для бургерного меню
Меню раскрывается на 100% разрешения экрана. Оставляю себе напоминание об Icon «Clouse» — 21 px.
Пример как будет выглядеть раскрывшийся “бургер”
Пояснение.
Несмотря на большое количество описанных сеток, я базово для клиента делаю 3 разрешения: XX-Large, Medium, Extra Small. Остальные разрешения выполняю только при просьбе подробно проработать дизайн.
2 микстура от нервов — Названия слоёв
Стоило однажды завести себе привычку правильно называть слои и всё — эти принципы навсегда уложились в голове. Работа стала намного быстрее и стало проще возвращаться к проектам спустя много лет.
Схема вложенности слоёв
Логика тут сказочная «игла в яйце, яйцо в утке, а утка в зайце». Поясню словами, container всегда только один. Его ширина определена выше, исходя из разрешения экрана. Я буду много опираться на размеры сеток, потому что принцип однообразия важен для лечения нервов разработчиков.
Основной принцип в веб-дизайне
Продолжаем разговор, в этом container лежат screen 1, screen 2 и т.п. Этим Screen будет, например, главный экран или призыв к действию (Call To Action). А внутри каждого screen содержание согласно ТЗ.
Главное, помнить-то 6 слов:
Container;
Screen;
Column (-s);
Image;
Raw (-s);
Icon (-s).
Скриншот расположения слоев
Скачать image тут.
3 микстура от нервов — Отступы
Куда отступать и по каким правилам учат курсы дизайна, называется это горизонтальным и вертикальным ритмами. Не буду подробно останавливаться, а скорее покажу свой вариант изменений расстояний в зависимости от размеров container.
Таблица размеров отступов в px
Скачать image тут.
Причем, 1 уровень использую как отступы между блоками. Какие уровни использовать и где, решает сам дизайнер. Думаю ясно, что в месте, где был отступ 48 px на XX-Large, в разрешении Medium он станет 32 px. Важно, чтобы из макета в макет использовать одни и те же значения, чтобы градус напряжения в команде (например, в больших проектах) был сведен к минимуму.
Заключение
Конечно, я не открыла новую страну, а только показала свои наработки. Эти 3 микстуры от нервов на курсах для веб-дизайнеров называют «базовыми знаниями» и рассказывают про правила их использования, но мало говорят о точных значениях.
А меня как человека очень дотошного интересуют только цифры и «сколько вешать в граммах». У разработчиков достаточно забот, поэтому не стоит добавлять к ним еще и мигрень с макетом.
И крепкий чай. Или не чай.
Бесплатный мультиязычный чат для сайта на Tawk + Notion + Telegram + chatGPT + GPT-Index / Хабр | Веб-студия Nat.od.ua
Бесплатный мультиязычный чат для сайта на Tawk + Notion + Telegram + chatGPT + GPT-Index / Хабр
В нашем современном мире создание онлайн-платформы для общения между клиентами и представителями компании – это необходимое требование для многих бизнесов. Онлайн-чат для сайта является одним из наиболее эффективных и удобных способов связи с потенциальными клиентами и удержания уже имеющихся из-за своей быстрой и простой обработки сообщений.
Я следил за различными видами использования chatGPT с момента его выхода. Описываемое далее решение я еще не встречал и поэтому думаю оно будет кому-то полезным.
Формулировка задачи
Необходимо создать онлайн-чата для сайта со следующими возможностями:
Общение с посетителями на любых языках
Запрос варита ответа на запрос посетителя у chatGPT, обученного на базе знаний компании
Реализовать все на бесплатных сервисах
Итак, поехали!
Шаг №1: Выбор сервиса для онлайн-чата
Для реализации задачи нам нужна возможность ставить свой обработчик на событие отправки сообщения посетителя. При этом сам сервис должен быть бесплатным.
По итогу был выбрал сервис Tawk.to, у которого есть вот эти два обработчика:
Шаг №2: Обучение chatGPT
Для формирования базы знаний компании мы будем использовать библиотеку:
🗂️ LlamaIndex 🦙 (GPT Index)
https://github.com/jerryjliu/llama_index
Вот пример использования библиотеки из официальной документации
!pip install llama-index
import os
os.environ = ‘YOUR_OPENAI_API_KEY’
from llama_index import GPTSimpleVectorIndex, SimpleDirectoryReader
documents = SimpleDirectoryReader(‘data’).load_data()
index = GPTSimpleVectorIndex(documents)
# save to disk
index.save_to_disk(‘index.json’)
# load from disk
index = GPTSimpleVectorIndex.load_from_disk(‘index.json’)
index.query(“
В качестве данных для формирование базы мы используем краткое описание компании и поместим его в текстовый файл:
# auras.txt
AURA Services
AURA Services, based in Tel Aviv, Israel, is a platform that mediates between local partner performers and clients and focused on short-term local services.
AURA do marketing and local advertisement to promote local partner performers.
The company acts as a broker and charges a commission from local partner performers for promotion of each service for clients.Шаг №3: Подготовка базы в Notion
Все поступающие сообщения от посетителей мы будем сохранять в Notion.
Вот шаблон таблицы:
https://candied-cactus-f66.notion.site/9cc1b8d874244cc0bef06d6de762d8df
Процесс создания интеграции хорошо описан в этой статье:
https://notionso.ru/kb/sozdanie-integratsiy-s-pomoschyu-api-notion/
У нас будет вот такая функция для создание записей в таблице Notion:
def insertDatabase(databaseId, record, token):
headers = {
“Accept”: “application/json”,
“Authorization”: “Bearer ” + token,
“Content-Type”: “application/json”,
“Notion-Version”: “2021-05-13”,
}
createUrl = “https://api.notion.com/v1/pages”
data = json.dumps(record)
res = requests.request(“POST”, createUrl, headers=headers, data=data)
return res
Пример записи в таблицу:
record = {“parent”: { “database_id”: notion_DB_id },”properties”: {}}
record = {“title”: }
record = {“rich_text”: }
record = {“rich_text”: }
insertDatabase(databaseId, record, token)Шаг №4: Создание Телеграм-бота
Найдите бота @BotFather и отправьте ему команду /start или /newbot, чтобы создать нового бота. Затем следуйте инструкциям, вводя название и короткое имя для вашего бота. После этого вы получите ответ с токеном бота и ссылкой на документацию. Важно сохранить токен в надежном месте, так как он необходим для авторизации и установки связи между вами и вашим ботом.
Шаг №5: Запуск HTTP API на Flask
Для обработки поступающих от посетителей сообщений нам необходимо написать небольшой Backend на Flask.
У нас будет только одна точка взода в API, которая принимает входящее сообщение, затем отправляет запрос в chatGPT и просит его ответить на 3-х языках. Полученные ответы мы отправляем в телеграм бот и в таблицу Notion.
Вот код нашего API:
from flask import Flask, render_template, redirect, url_for, request, session, jsonify
from flask_cors import CORS
from os import path
import json
import os
import requests
import datetime
import openai
import telebot
app = Flask(__name__)
CORS(app) # эта команда необходима для работы с API из React-приложений
bot = telebot.TeleBot(config.tg_bot_key)
# /api/v1.0/new_online_chat_message
@app.route(‘/api/v1.0/new_online_chat_message’, methods=)
def new_online_chat_message():
url = request.args.get(“url”, ‘-‘)
message = request.args.get(“message”, ‘-‘)
print(‘’)
notion_DB_id = ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’
record = {“parent”: { “database_id”: notion_DB_id },”properties”: {}}
record = {“title”: }
record = {“rich_text”: }
# Ask chatGPT
reply = ”
if message != ‘-‘:
index = GPTSimpleVectorIndex.load_from_disk(‘/wiki/index.json’)
# ID чата с телеграм ботом
chat_id = ‘XXXXXXXXX’
# English
response = index.query(message + ‘. Answer in English’, response_mode=”compact”)
record = {“rich_text”: }
reply = response.response
bot.send_message(chat_id, ‘🇬🇧n’ + reply)
# Spanish
response = index.query(message + ‘. Answer in Spanish’, response_mode=”compact”)
record = {“rich_text”: }
reply = response.response
bot.send_message(chat_id, ‘🇪🇸n’ + reply)
# German
response = index.query(message + ‘. Answer in German’, response_mode=”compact”)
record = {“rich_text”: }
reply = response.response
bot.send_message(chat_id, ‘🇩🇪n’ + reply)
res = notion_api.insertDatabase(notion_DB_id, record, config.notion_token)
print(res, res.text)
###
return reply
if __name__ == “__main__”:
app.run(debug=True, host=”0.0.0.0″, port=5000)Шаг №6: Отправка сообщений из чата на сайте на HTTP API
И финальная часть – мы добавляем обработчик в виджет чата Tawk.to:
Демонстрация работыИтог
Я надеюсь данное решение будет вам полезно и если вы используете его где-то, напишите пожалуйста про это в комментариях.
И конечно я готов ответить на все ваши вопросы, пишите в мой ТГ.