Прогресс
На этой странице
Берите определённую полосу всякий раз, когда знаете, сколько осталось: только она хоть что-то сообщает читателю. Опустите value — и полоса вместо этого анимируется, что говорит «всё ещё работаю» и больше ничего.
Определённый прогресс
stack({ gap: 'lg' },
progress({ value: 25 }),
progress({ value: 60 }),
progress({ value: 100 }),
)Неопределённый прогресс
progress()Полоса без label помечается aria-hidden: роль progressbar без доступного имени ничего не сообщает скринридеру, поэтому неподписанная полоса считается декорацией. Подписывайте всё, за чем читателю положено следить.
Подписи
Подпись называет происходящее; showValue добавляет справа проценты.
stack({ gap: 'lg' },
progress({ value: 72, label: 'Рендерим страницы', showValue: true }),
progress({ value: 30, max: 60, label: 'Оптимизируем изображения', showValue: true }),
progress({ label: 'Ждём развёртывания' }),
)Цвета и высота
stack({ gap: 'lg' },
progress({ value: 80, color: 'success', label: 'Успешно', showValue: true }),
progress({ value: 45, color: 'warning', label: 'С оговорками', showValue: true }),
progress({ value: 20, color: 'danger', label: 'Падает', showValue: true }),
progress({ value: 60, color: 'neutral', height: 'xs' }),
progress({ value: 60, color: 'primary', height: '1rem' }),
)Шкала не из 100
max позволяет передавать сырые числа — собранных страниц из общего числа — вместо того чтобы сначала считать проценты.
progress({ value: 118, max: 169, label: '118 из 169 страниц', showValue: true })Двигать её из браузера
Полоса — это HTML, отрисованный на сервере: процент лежит в пользовательском свойстве на заливке, а число — в aria-valuenow, и ничто на странице не меняет ни то, ни другое само по себе. Дайте полосе id, и setProgress сдвинет всё сразу — заливку, объявляемое значение и процент рядом с подписью.
import { setProgress } from 'sitelo/ui/client'
const request = new XMLHttpRequest()
request.upload.addEventListener('progress', (event) => {
setProgress('upload', event.loaded, { max: event.total })
})Максимум запоминается, так что дальше достаточно передавать значение. Или дотянитесь до модуля так же, как это делают компоненты, и обойдитесь без бандла вовсе:
button({ onclick: "import('/su/progress.js').then(m=>m.set('upload',100))" }, 'Завершить')Передача null — или чего угодно, что не является конечным числом — возвращает полосу к неопределённой анимации, поэтому работу, переставшую сообщать числа, не нужно выделять в отдельный случай. getProgress() читает текущее значение обратно, в собственной шкале полосы.
Попробуйте
Эта страница загружает рантайм, так что кнопки ниже действительно двигают полосу.
stack({ gap: 'md' },
progress({ id: 'demo-progress', value: 0, label: 'Загрузка', showValue: true }),
stack({ direction: 'row', gap: 'sm', wrap: true },
button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',0))" }, 'Сброс'),
button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',35))" }, '35%'),
button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',80))" }, '80%'),
button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',100))" }, 'Готово'),
button({ size: 'sm', variant: 'ghost', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',null))" }, 'Неизвестно'),
),
)Полоса без подписи тоже сдвинется, но останется aria-hidden — её намеренно отрисовали без имени, и объявить ей значение сейчас значило бы поместить в дерево доступности progressbar без имени.
Спиннер
Отдельного компонента-спиннера нет — спиннер это иконка, а вращает её spin. Как и любая иконка, он задаётся в em, поэтому подходит к любому соседнему тексту, и размер ему называть не нужно.
stack({ direction: 'row', gap: 'lg', align: 'center' },
icon('spinner', { spin: true, size: 'sm' }),
icon('spinner', { spin: true }),
icon('spinner', { spin: true, size: 'lg' }),
)Спиннер в контексте
Дайте одиночному спиннеру label, чтобы его объявляли. Спиннеру внутри кнопки это не нужно: кнопка и так говорит, что делает.
Получаем последнюю сборку…
stack({ gap: 'md' },
stack({ direction: 'row', gap: 'sm', align: 'center' },
icon('spinner', { spin: true, label: 'Загрузка' }),
text({ variant: 'small', tone: 'muted' }, 'Получаем последнюю сборку…'),
),
stack({ direction: 'row', gap: 'sm' },
button({ loading: true }, 'Разворачиваем'),
button({ variant: 'outline', loading: true }, 'Проверяем ссылки'),
),
)Пропсы
progress() — экспортируется также как progressBar:
| Проп | Тип | По умолчанию | Описание |
|---|---|---|---|
value | number | — | Насколько продвинулись. Опустите для неопределённой анимации. |
max | number | 100 | Какое значение считается завершением. |
color | 'primary' | 'neutral' | 'success' | 'warning' | 'danger' | 'primary' | Цвет заливки. |
label | Child | — | Текст над полосой; он же её доступное имя. |
showValue | boolean | false | Показывать проценты рядом с подписью. |
height | Space | '0.5rem' | Толщина полосы. |
setProgress() из sitelo/ui/client:
| Проп | Тип | По умолчанию | Описание |
|---|---|---|---|
target | Element | string | — | Полоса или её id. Если элемента с таким id нет, строка пробуется как селектор. |
value | number | null | — | Куда её сдвинуть. null возвращает её к неопределённой анимации. |
options.max | number | 100 | Что считается завершённым. Запоминается для последующих вызовов. |
Своих пропсов у спиннера нет — это icon('spinner', { spin: true }), и он принимает то же, что и icon().