Buttons
Provider Sign In
Кнопка входа через провайдера: знак прижат к левому краю, а подпись центрируется по всей ширине, поэтому колонка кнопок держит общую ось.
- button
- auth
- oauth
- sign-in
Превью
Использовать с AI
- 1. Скопируйте ссылку.
- 2. Напишите агенту своими словами и вставьте её в предложение.
- 3. Агент откроет ссылку и поставит компонент из registry.
размести это в шапке: https://vibeui.ru/c/button-048
Показать полную инструкцию
То, что лежит по ссылке в развёрнутом виде. Нужна, если агент не может открыть ссылку — тогда вставьте этот текст целиком.
# Установка и размещение «button-048» (Provider Sign In) из VibeUI
## 1. Сначала установка — не пропускай, не пересоздавай
Выполни эту команду до того, как писать код:
npx shadcn@latest add https://vibeui.ru/r/button-048.json
Registry item: https://vibeui.ru/r/button-048.json
Ставится в: components/vibeui/button-048.tsx (точный путь следует алиасам components.json этого проекта).
npm-зависимости: нет.
Registry-зависимости: нет.
Ставь из реестра. Не пересоздавай по описанию, не подменяй похожим
компонентом из другой библиотеки и не переписывай под стиль проекта.
## 2. Что это
Кнопка входа через провайдера: знак прижат к левому краю, а подпись центрируется по всей ширине, поэтому колонка кнопок держит общую ось.
Белая кнопка входа через внешнего провайдера. Знак лежит абсолютом у левого края, поэтому подпись центрируется по всей кнопке и колонка «Продолжить с …» выстраивается по одной оси. Три провайдера меняют и знак, и подпись по умолчанию. Знаки нарисованы CSS, картинок нет. Ноль зависимостей, один файл.
## 3. Как использовать
import { Button048 } from "@/components/vibeui/button-048"
<Button048 provider="google" onClick={signIn} />
Полный список пропсов — в установленном файле.
## 4. Куда поставить
Это мелкий inline-компонент. Поставь его ровно туда, куда просил
пользователь, внутрь существующей разметки. Не создавай ради него
новую страницу, секцию или обёртку. Если на этом месте уже стоит похожий
контрол — замени его, а не добавляй второй.
Куда поставить: ___
(Эту строку заполняет пользователь. Если она осталась пустой — спроси,
а не угадывай.)
## 5. Сохранить как установлено
- знак вне потока: если положить его в строку, подпись сместится и колонка кнопок потеряет общую ось
- белую поверхность с рамкой — привычная форма кнопки входа, по которой её узнают
- подпись вида «Продолжить с …»: она честнее, чем «Войти», потому что покрывает и регистрацию
- правый паддинг, равный левому: без него центрированная подпись уезжает вправо
- focus-visible с отступом: кнопки входа часто первые в порядке обхода
- постоянную высоту 2.75rem — колонка провайдеров должна быть ровной
## 6. Можно менять
- провайдера — проп provider, он меняет знак и подпись по умолчанию
- подпись — проп label, если нужна своя формулировка
- обработчик onClick и остальные нативные пропсы button
- знак: замените CSS-фигуру на настоящий логотип провайдера
- предельную ширину через className
## 7. Правила
- Знаки здесь условные. Перед публикацией поставьте официальные логотипы: у провайдеров свои правила использования марки.
- Не переводи название провайдера: «Гугл» вместо Google выглядит подделкой.
- Не клади знак в поток ради «простоты» — сломается выравнивание подписей в колонке.
- Не выноси CSS-переменные в globals.css: компонент должен оставаться одним файлом.
## 8. Проверка
- рендерится без ошибок в консоли;
- выглядит так же, как превью на странице VibeUI, откуда взята ссылка;
- если нет — ты изменил что-то из раздела 5, верни как было.Для разработчика
npx shadcn@latest add https://vibeui.ru/r/button-048.jsonhttps://vibeui.ru/r/button-048.jsonКомпонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-button-048-*. Серверный компонент. Знак вынут из потока (position:absolute) и не влияет на центрирование подписи — из-за этого несколько кнопок разных провайдеров выстраиваются с общей осью текста. Знаки условные, собраны из conic-gradient и псевдоэлементов; реальные логотипы приносит проект. Подпись по умолчанию берётся из карты LABELS по значению provider.
Исходник компонента
Тот же файл, который поставит агент. Нужен, если вы предпочитаете скопировать код руками.
import type { ComponentPropsWithoutRef, CSSProperties } from "react"
export type Button048Props = Omit<
ComponentPropsWithoutRef<"button">,
"children"
> & {
/** Провайдер входа: от него зависят подпись и знак слева. */
provider?: "google" | "github" | "apple"
label?: string
}
// Идея компонента: кнопка входа через провайдера. Знак прибит к левому краю,
// а подпись центрируется по всей кнопке — так ряд кнопок разных провайдеров
// выстраивается в колонку с общей осью текста. Знаки здесь условные, из CSS:
// настоящие логотипы приносит проект, у них свои правила использования.
const STYLES = `
:where([data-vibeui-block="button-048"]){
--vibeui-button-048-surface:oklch(1 0 0);
--vibeui-button-048-border:oklch(0.87 0.006 265);
--vibeui-button-048-fg:oklch(0.24 0.02 265);
--vibeui-button-048-ring:oklch(0.55 0.02 265 / 65%);
--vibeui-button-048-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="button-048"]{
position:relative;appearance:none;cursor:pointer;box-sizing:border-box;
display:flex;align-items:center;justify-content:center;
width:100%;max-width:20rem;height:2.75rem;padding:0 3rem;
border:1px solid var(--vibeui-button-048-border);border-radius:0.625rem;
background:var(--vibeui-button-048-surface);color:var(--vibeui-button-048-fg);
font-family:var(--vibeui-button-048-font);font-size:0.875rem;font-weight:600;line-height:1;
box-shadow:0 1px 2px oklch(0 0 0 / 6%);
transition:background-color .16s ease,border-color .16s ease;
}
[data-vibeui-block="button-048"]:hover:not(:disabled){
background:oklch(0.97 0.003 265);border-color:oklch(0.8 0.008 265);
}
[data-vibeui-block="button-048"]:focus-visible{outline:2px solid var(--vibeui-button-048-ring);outline-offset:2px}
[data-vibeui-block="button-048"]:disabled{cursor:not-allowed;opacity:.55}
/* Знак прижат к краю, подпись центрируется по всей ширине кнопки. */
[data-vibeui-block="button-048"] [data-part="mark"]{
position:absolute;left:0.9375rem;top:50%;margin-top:-0.5625rem;
width:1.125rem;height:1.125rem;border-radius:50%;
}
[data-vibeui-block="button-048"][data-provider="google"] [data-part="mark"]{
background:conic-gradient(oklch(0.62 0.22 27) 0 25%,oklch(0.8 0.16 85) 0 50%,oklch(0.6 0.16 150) 0 75%,oklch(0.55 0.19 260) 0);
}
[data-vibeui-block="button-048"][data-provider="google"] [data-part="mark"]::after{
content:"";position:absolute;left:50%;top:50%;width:0.5rem;height:0.5rem;
margin:-0.25rem 0 0 -0.25rem;border-radius:50%;background:var(--vibeui-button-048-surface);
}
[data-vibeui-block="button-048"][data-provider="github"] [data-part="mark"]{
background:oklch(0.24 0.01 265);
}
[data-vibeui-block="button-048"][data-provider="github"] [data-part="mark"]::after{
content:"";position:absolute;left:50%;top:0.5rem;width:0.625rem;height:0.4375rem;
margin-left:-0.3125rem;border-radius:0.25rem 0.25rem 0 0;
background:var(--vibeui-button-048-surface);
}
[data-vibeui-block="button-048"][data-provider="apple"] [data-part="mark"]{
background:oklch(0.2 0 0);border-radius:0.375rem;
}
[data-vibeui-block="button-048"][data-provider="apple"] [data-part="mark"]::after{
content:"";position:absolute;left:50%;top:50%;width:0.4375rem;height:0.4375rem;
margin:-0.21875rem 0 0 -0.21875rem;border-radius:50% 50% 50% 0;
background:var(--vibeui-button-048-surface);transform:rotate(-45deg);
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="button-048"]{transition:none!important}}
`
const LABELS = {
google: "Продолжить с Google",
github: "Продолжить с GitHub",
apple: "Продолжить с Apple",
}
/**
* Кнопка входа через провайдера: знак у края, подпись по центру.
* Один файл, ноль зависимостей, собственная палитра.
*/
export function Button048({
provider = "google",
label,
type = "button",
className,
style,
...props
}: Button048Props) {
return (
<>
<style href="vibeui-button-048" precedence="medium">
{STYLES}
</style>
<button
{...props}
type={type}
data-vibeui-block="button-048"
data-provider={provider}
className={className}
style={style as CSSProperties}
>
<span data-part="mark" aria-hidden="true" />
{label ?? LABELS[provider]}
</button>
</>
)
}