import type { OneTapUrls } from '@/lib/one-tap-examples'; export type ButtonSize = 's' | 'm' | 'l' | 'xl'; export type ButtonTheme = 'light' | 'dark'; export type ButtonView = 'main' | 'icon'; export type ButtonIcon = 'id' | 'none'; export interface ButtonBuilderOptions { clientId: string; providerName: string; redirectUri: string; size: ButtonSize; theme: ButtonTheme; view: ButtonView; radius: number; icon: ButtonIcon; // Пустая строка = использовать цвет темы по умолчанию. bg: string; bgHover: string; border: string; borderHover: string; text: string; } export interface SizePreset { height: number; font: number; padX: number; gap: number; badge: number; radius: number; } // Должно совпадать с SIZE_PRESETS в apps/frontend/public/sso-widget.js. export const SIZE_PRESETS: Record = { s: { height: 32, font: 13, padX: 12, gap: 8, badge: 20, radius: 16 }, m: { height: 40, font: 14, padX: 16, gap: 10, badge: 24, radius: 20 }, l: { height: 44, font: 15, padX: 18, gap: 10, badge: 28, radius: 22 }, xl: { height: 52, font: 16, padX: 22, gap: 12, badge: 32, radius: 26 } }; export interface ButtonPalette { bg: string; bgHover: string; border: string; borderHover: string; text: string; badgeBg: string; badgeColor: string; } // Должно совпадать с themePalette в apps/frontend/public/sso-widget.js. export function themePalette(theme: ButtonTheme): ButtonPalette { if (theme === 'dark') { return { bg: '#1f2430', bgHover: '#2a3040', border: 'transparent', borderHover: 'transparent', text: '#ffffff', badgeBg: '#ffffff', badgeColor: '#1f2430' }; } return { bg: '#ffffff', bgHover: '#f6f8fb', border: '#e4e8ef', borderHover: '#d4dae6', text: '#1f2430', badgeBg: '#111111', badgeColor: '#ffffff' }; } export const SIZE_OPTIONS: Array<{ value: ButtonSize; label: string }> = [ { value: 's', label: 'S — 32px' }, { value: 'm', label: 'M — 40px' }, { value: 'l', label: 'L — 44px' }, { value: 'xl', label: 'XL — 52px' } ]; export const THEME_OPTIONS: Array<{ value: ButtonTheme; label: string }> = [ { value: 'light', label: 'Светлая' }, { value: 'dark', label: 'Тёмная' } ]; export const VIEW_OPTIONS: Array<{ value: ButtonView; label: string }> = [ { value: 'main', label: 'Кнопка с текстом' }, { value: 'icon', label: 'Только иконка' } ]; export const ICON_OPTIONS: Array<{ value: ButtonIcon; label: string }> = [ { value: 'id', label: 'Значок ID' }, { value: 'none', label: 'Без значка' } ]; export const DEFAULT_BUILDER_OPTIONS: ButtonBuilderOptions = { clientId: 'YOUR_CLIENT_ID', providerName: 'MVK ID', redirectUri: 'https://app.example.com/auth/callback', size: 'xl', theme: 'light', view: 'main', radius: 26, icon: 'id', bg: '', bgHover: '', border: '', borderHover: '', text: '' }; export interface ResolvedButtonStyle { preset: SizePreset; palette: ButtonPalette; bg: string; bgHover: string; border: string; borderHover: string; text: string; radius: number; iconOnly: boolean; showBadge: boolean; } export function resolveButtonStyle(options: ButtonBuilderOptions): ResolvedButtonStyle { const preset = SIZE_PRESETS[options.size] ?? SIZE_PRESETS.xl; const palette = themePalette(options.theme === 'dark' ? 'dark' : 'light'); const radius = Number.isFinite(options.radius) ? options.radius : preset.radius; return { preset, palette, bg: options.bg || palette.bg, bgHover: options.bgHover || palette.bgHover, border: options.border || palette.border, borderHover: options.borderHover || palette.borderHover, text: options.text || palette.text, radius, iconOnly: options.view === 'icon', showBadge: options.icon !== 'none' }; } export function buildButtonSnippet(options: ButtonBuilderOptions, urls: OneTapUrls): string { const providerName = options.providerName || urls.projectName; const lines: string[] = [ ` src="${urls.widgetUrl}"`, ` data-client-id="${options.clientId || 'YOUR_CLIENT_ID'}"`, ` data-idp-url="${urls.apiBase}"`, ` data-idp-frontend-url="${urls.frontendBase}"`, ` data-provider-name="${providerName}"`, ` data-redirect-uri="${options.redirectUri}"`, ` data-button-container="mvkid-button"`, ` data-button-size="${options.size}"`, ` data-button-theme="${options.theme}"`, ` data-button-view="${options.view}"`, ` data-button-radius="${options.radius}"`, ` data-button-icon="${options.icon}"` ]; if (options.bg) lines.push(` data-button-bg="${options.bg}"`); if (options.bgHover) lines.push(` data-button-bg-hover="${options.bgHover}"`); if (options.border) lines.push(` data-button-border="${options.border}"`); if (options.borderHover) lines.push(` data-button-border-hover="${options.borderHover}"`); if (options.text) lines.push(` data-button-text="${options.text}"`); lines.push(' data-on-success="onMvkIdLogin"'); return `
`; }