Geist UI: Утонченная эстетика UI в React

Одно из лучших достоинств сайта Next.js  —  оптимальный и минималистичный дизайн. Он не содержит ничего лишнего и обеспечивает простую навигацию. 

Главная страница сайта Next.js

Однако воспроизвести их эстетику невероятно сложно. Стилизация и отзывчивый дизайн требуют написания тонн кода. 

И вот тут самое время рассказать о библиотеке Geist UI, которая предоставляет набор компонентов, созданных на основе дизайна Vercel. С ее помощью вы также сможете менять темы, ограничиваясь лишь небольшими объемами кода. 

Из статьи вы узнаете принципы использования пакета Geist UI. А итогом нашей работы станет следующий результат: 

Начало 

Инициализация проекта 

Создаем проект React, выполняя команду терминала: 

npx create-react-app geist-tutorial

Далее устанавливаем для приложения необходимые зависимости. 

Установка модулей

Требуемые пакеты: 

  • @geist-ui/react: основная зависимость проекта. 
  • @geist-ui/react-icons: обеспечивает доступ к набору иконок библиотеки.

Выполняем следующую команду и получаем эти зависимости: 

npm i @geist-ui/react @geist-ui/react-icons

Стандартные компоненты 

Текст

Компонент Text позволяет отображать стандартный текст и присваивать ему стили. 

В каталоге src создаем файл TextExample.js и прописываем такой код: 

import { Text } from "@geist-ui/react";

export default function TextExample() {
return (
<div>
<Text>Standard Text page </Text>
<Text h1>Next.js</Text>
<Text size="2em">The React Framework for production </Text>
<Text b>Great for blogs</Text>
<Text blockquote> Incredibly easy</Text>
<Text type="success"> Try it out</Text>
</div>
);
}
  • Строка 6: Создаем стандартный элемент Text без стиля.
  • Строка 7: Свойство h1 дает указание React отобразить заголовок h1
  • Строка 8: Увеличиваем размер текста до 2em.
  • Строка 11: Свойство type изменяет цвет Text

На последнем этапе нужно отобразить TextExample в DOM. Для этого переходим в App.js и пишем код: 

import { GeistProvider, CssBaseline } from "@geist-ui/react";
import TextExample from "./TextExample";
function App() {
return (
<div className="App">
<GeistProvider>
<CssBaseline />
<TextExample />
</GeistProvider>
</div>
);
}
export default App;
  • Строка 6: Обертываем пользовательским компонентом теги GeistProvider, таким образом применяя темы и стили к странице. 
  • Строка 7: Элемент CSSBaseline нормализует стили. 
  • Строка 8: Наконец, отображаем компонент TextExample

Получаем следующий результат:

Выглядит отлично! Далее знакомимся с кнопками. 

Кнопка 

В каталоге src создаем файл ButtonExample.js, в котором прописываем код: 

import { Button, Text } from "@geist-ui/react";
import { useState } from "react";

export default function ButtonExample() {
const [number, setNumber] = useState(0);
return (
<div>
<Text>{number}</Text>
<Button
size="small"
type={"success"}
onClick={() => setNumber((number) => number + 1)}
>
+
</Button>
<Button
size="large"
type={"error"}
ghost
onClick={() => setNumber((number) => number - 1)}
>
-
</Button>
</div>
);
}
  • Строка 8: Отображаем значение хука number
  • Lines 9–13: Отрисовываем компонент Button размера small и меняем его цвет. При нажатии значение переменной number увеличивается.
  • Строка 16–21: Отрисовываем компонент Button размера large и меняем его цвет. При нажатии значение number уменьшается. 

Итоговый результат:

Отлично! Код работает. Можно отключить функцию нажатия кнопки через свойство disabled:

<Button disabled> Click me</Button>

Далее займемся кодом для вывода изображений. 

Изображения 

Для этого пишем следующий код: 

import { Image, Text } from "@geist-ui/react";

export default function ImageExample() {
return (
<div>
<Text>A keyboard:</Text>
<Image
width={540}
height={160}
src="https://wallpapercave.com/wp/wp4947509.jpg"
/>
</div>
);
}
  • Строки 8–9: Свойства width и height изменяют размеры изображения. 

По умолчанию при чрезмерно долгой загрузке React отобразит плейсхолдер skeleton. С помощью Deelay возможна имитация разных типов интернет-соединения.

return (
<div>
<Text>A keyboard(delayed):</Text>
<Image
width={540}
height={160}
src="https://deelay.me/3000/https://wallpapercave.com/wp/wp4947509.jpg"
/>
</div>
);
  • Строка 7: Выводим изображение через 3 секунды. 

Полученный результат:

Компонент Display позволяет добавлять подписи к изображениям. 

import { Image, Text, Display } from "@geist-ui/react";

export default function ImageExample() {
return (
<div>
<Text>A keyboard:</Text>
<Display caption={<Text> A simple Windows keyboard</Text>}>
<Image
width={540}
height={160}
src="https://deelay.me/3000/https://wallpapercave.com/wp/wp4947509.jpg"
/>
</Display>
</div>
);
}
  • Строка 7: С помощью свойства caption добавляем подпись. 

Код превосходно работает! 

Помимо этого, можно добавить к изображениям рамку в стиле браузера: 

<Image.Browser url="https://medium.com/">
<Image
width={540}
height={160}
src="https://wallpapercave.com/wp/wp4947509.jpg"
/>
</Image.Browser>

Свойство url в Image.Browser инструктирует React  —  при нажатии пользователем на изображение перенаправить его к указанному URL. 

Иконки 

Компонент Geist Icon отображает графику SVG, предоставляя удобный способ взаимодействия с данными. 

Напишем код для отрисовки простой иконки: 

import { Text } from "@geist-ui/react";
import * as Icon from "@geist-ui/react-icons";

export default function IconExample() {
return (
<div>
<Text>Go down</Text>
<Icon.ArrowDown size="8em" />
<Icon.ArrowUp color="blue" size="8em" />
<Text>
Follow us on :<Icon.Facebook />
</Text>
<Text>
Or <Icon.Instagram />
</Text>
</div>
);
}
  • Строка 8: Отрисовываем иконку ArrowDown и увеличиваем ее размер до 8em.
  • Строка 9: Отрисовываем иконку ArrowUp и меняем ее цвет на blue.

Получаем результат:

Используя свойство icon, можно отрисовывать иконки в Button

<Button icon={<Icon.ArrowUp />} type="success">
Go up
</Button>

Спиннер загрузки 

Показывает пользователю иконку “загрузки”, сообщая ему о том, что данные загружаются. 

В каталоге src создаем файл SpinnerExample.js, где прописываем код: 

import { Text, Spinner } from "@geist-ui/react";
import { useEffect, useState } from "react";

export default function SpinnerExample() {
const [loading, setLoading] = useState(true);

useEffect(() => {
setTimeout(() => setLoading(false), 2 * 1000);
}, []);

return (
<div>{loading ? <Spinner size="large" /> : <Text> Loaded!</Text>}</div>
);
}
  • Строка 7: Через 2 секунды устанавливаем для хука loading значение false.
  • Строка 11: Используем условную отрисовку. Если loading —  true, отображаем иконку Spinner, в противном случае сообщаем пользователю о завершении загрузки приложения. 

А вот и результат кода: 

Данный раздел статьи исчерпан! Рассмотрим применение Geist для создания отзывчивых интерфейсов. 

Отзывчивые макеты 

Отзывчивый дизайн позволяет создавать веб-страницы, которые подстраиваются под устройство. При правильной настройке они будут великолепно смотреться на таких устройствах, как мобильные телефоны, планшеты и стационарные компьютеры.  

Сначала познакомимся с элементом Grid

Grid-контейнеры 

Grid-контейнер идентичен свойству grid в CSS. Создаем файл GridExample.js и пишем в нем код: 

import { Text, Grid } from "@geist-ui/react";

function MockComponent({ number }) {
return (
<div style={{ backgroundColor: "blue", width: "100%", height: "100px" }}>
<Text>{number}</Text>
</div>
);
}

export default function GridExample() {
return (
<div>
<Grid.Container gap={3} justify="center">
<Grid sm={6} xs={2}>
<MockComponent number={1} />
</Grid>
<Grid sm={6} xs={2}>
<MockComponent number={2} />
</Grid>
<Grid sm={6} xs={2}>
<MockComponent number={3} />
</Grid>
</Grid.Container>
</div>
);
}
  • Строка 14: Между элементами в Grid устанавливаем расстояние в 3 единицы. Свойство justify выравнивает эти элементы по центру. 
  • Строка 15: На маленьких экранах и побольше (контрольная точка прерывания sm) размер элемента составляет 6 единиц. В случае совсем маленького устройства (контрольная точка прерывания xs), уменьшаем элемент до 2 единиц. 
  • Строка 16: Отрисовываем MockComponent в контейнере Grid.

Поздравляю  —  отлично работающий код! 

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

return (
<div>
<Grid.Container gap={3} justify="center">
<Grid sm={10} xs={2}>
<MockComponent number={1} />
</Grid>
<Grid sm={6} xs={2}>
<MockComponent number={2} />
</Grid>
<Grid sm={9} xs={2}>
<MockComponent number={3} />
</Grid>
<Grid xs>
<MockComponent number={4} />
</Grid>
</Grid.Container>
</div>
);
  • Строка 13: Оставляем свойство xs пустым, тем самым обеспечивая автоматическое заполнение остающегося пространства. 

Переходим к компоненту Spacer

Компонент Spacer

Рассмотрим данный фрагмент кода: 

return (
<div>
<Button type="success" />
<Button type="error" />
</div>
);

Здесь мы отобразили две кнопки Buttons разных цветов. 

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

import { Spacer, Button } from "@geist-ui/react";

export default function SpacerExample() {
return (
<div>
<Button type="success" />
<Spacer y={4} />
<Button type="error" />
</div>
);
}
  • Строка 7: Между компонентами по оси y должно быть расстояние в 4 единицы. 

Можно даже обеспечить расстояние между элементами по горизонтали, обернув их тегами Container:

return (
<Container>
<Button type="success" />
<Spacer x={4} />
<Button type="error" />
</Container>
);

Дополнительные полезные функциональности 

Сворачиваемый и раскрывающийся текст 

Компонент Collapse позволяет отображать большие объемы текста в секциях сворачивания/разворачивания. Для его отрисовки пишем следующий код: 

import { Collapse, Text } from "@geist-ui/react";

export default function CollapseExample() {
return (
<div>
<Collapse.Group>
<Collapse title="How are you?">
<Text> I'm fine!</Text>
<Text b> How are you though?</Text>
</Collapse>
<Collapse title="What is your website">
<Text> It's on Medium</Text>
</Collapse>
</Collapse.Group>
</div>
);
}
  • Строка 6: Отображаем Collapse.Group. Здесь мы объединим все секции. 
  • Строка 7: Отрисовываем первый Collapse и указываем его название с помощью свойства title

Можно добавить и подзаголовки:

return (
<div>
<Collapse.Group>
<Collapse title="How are you?" subtitle="The definite answer">
<Text> I'm fine!</Text>
<Text b> How are you though?</Text>
</Collapse>
<Collapse
title="What is your website"
subtitle={<Text b> The definite answer</Text>}
>
<Text> It's on Medium</Text>
</Collapse>
</Collapse.Group>
</div>
);
  • Строки 4 и 10: Указываем подзаголовки, используя свойство subtitle.

Полученный результат: 

Всплывающие сообщения 

Хук useToasts позволяет показывать всплывающие сообщения. 

import { Button, useToasts } from "@geist-ui/react";

export default function ToastExample() {
const [toast, setToast] = useToasts();

const click = () => {
setToast({ text: "Lorem ipsum" });
};

return (
<div>
<Button onClick={() => click()}> Display</Button>
</div>
);
}
  • Строка 12: При нажатии на кнопку вызывается метод click, что приводит к появлению всплывающего сообщения. 

Можем поиграть с цветами этих сообщений: 

import { Button, useToasts } from "@geist-ui/react";

export default function ToastExample() {
const [toast, setToast] = useToasts();

const click = (type) => {
setToast({ text: "Lorem ipsum", type });
};

return (
<div>
<Button onClick={() => click("secondary")}> Display</Button>
<Button onClick={() => click("error")}> Show error</Button>
</div>
);
}
  • Строка 12: Отрисовываем сообщение типа secondary.
  • Строка 13: При нажатии на кнопку отображается сообщение типа error.

Смена тем 

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

В App.js пишем следующий код: 

import { GeistProvider, CssBaseline, Button } from "@geist-ui/react";
import ToastExample from "./ToastExample";
import { useState } from "react";

function App() {
const [theme, setTheme] = useState("light");

const changeTheme = () => {
setTheme((last) => (last === "dark" ? "light" : "dark"));
};
return (
<div className="App">
<GeistProvider themeType={theme}>
<CssBaseline />
<Button onClick={() => changeTheme()}> Change themes</Button>
<ToastExample />
</GeistProvider>
</div>
);
}
export default App;
  • Строка 6: Создаем состояние theme. Его начальным значением будет light.
  • Строки 8–10: Если текущее значение theme — dark, то меняем его на lightи наоборот. 
  • Строка 15: При нажатии вызывается метод changeTheme, а тема переключается.

Дополнительные ресурсы 

Код GitHub 

The code for this demo.

Материал для дальнейшего чтения 

Документация Geist UI

Заключение 

Если вам нужен набор компонентов UI, которые и выглядят отлично, и ресурсов много не требуют, то библиотека Geist UI превосходно подходит для веб-приложения. К тому же вам не придется писать тонны кода для переключения тем  —  а это преимущество что надо. 

Благодарю за внимание!

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Hussain Arif: Build Beautiful UIs in React With Geist UI

Предыдущая статьяОсновы языка освоены. Что дальше?
Следующая статьяBamboolib  -  одна из самых полезных библиотек Python