fix(datepicker): убрать скачки и поправить адаптив

- Числовой формат даты (01.06.2026) — постоянная ширина в любой локали,
  раньше короткое имя месяца («мая» vs «сент.») меняло ширину кнопки.
- min-w + justify-start + truncate на триггере: плейсхолдер и выбранная
  дата дают одинаковую ширину — поле не прыгает по горизонтали.
- fixedWeeks + showOutsideDays: всегда 6 недель, высота календаря не
  скачет при листании месяцев (5↔6 рядов).
- collisionPadding + max-w-[calc(100vw-1rem)]: поповер не вылезает за край
  экрана на мобайле.
- Контейнеры диапазона дат (продажи, трафик) переведены на flex-wrap /
  full-width на мобайле — два поля больше не вылезают за ширину.
This commit is contained in:
c0mrade
2026-06-02 16:38:56 +03:00
parent 54998c8195
commit c880517169
3 changed files with 14 additions and 7 deletions

View File

@@ -51,10 +51,12 @@ export function DateField({ value, onChange, placeholder, min, max, className }:
const selected = parseISO(value); const selected = parseISO(value);
const locale = LOCALES[i18n.language as keyof typeof LOCALES] ?? enUS; const locale = LOCALES[i18n.language as keyof typeof LOCALES] ?? enUS;
// Numeric format keeps a constant button width across dates and locales
// (a "short" month name varies in length and makes the trigger jitter).
const display = selected const display = selected
? selected.toLocaleDateString(i18n.language, { ? selected.toLocaleDateString(i18n.language, {
day: '2-digit', day: '2-digit',
month: 'short', month: '2-digit',
year: 'numeric', year: 'numeric',
}) })
: ''; : '';
@@ -72,18 +74,21 @@ export function DateField({ value, onChange, placeholder, min, max, className }:
type="button" type="button"
className={ className={
className ?? className ??
'flex items-center gap-2 rounded-lg border border-dark-600 bg-dark-800 px-3 py-1.5 text-sm text-dark-200 transition-colors hover:border-dark-500' 'flex min-w-[8rem] items-center justify-start gap-2 whitespace-nowrap rounded-lg border border-dark-600 bg-dark-800 px-3 py-1.5 text-sm text-dark-200 transition-colors hover:border-dark-500'
} }
> >
<CalendarIcon className="h-4 w-4 shrink-0 text-dark-500" /> <CalendarIcon className="h-4 w-4 shrink-0 text-dark-500" />
<span className={selected ? '' : 'text-dark-500'}>{display || placeholder}</span> <span className={`truncate ${selected ? '' : 'text-dark-500'}`}>
{display || placeholder}
</span>
</button> </button>
</Popover.Trigger> </Popover.Trigger>
<Popover.Portal> <Popover.Portal>
<Popover.Content <Popover.Content
align="start" align="start"
sideOffset={6} sideOffset={6}
className="rdp-dark z-50 rounded-xl border border-dark-700 bg-dark-800 p-2 shadow-xl" collisionPadding={8}
className="rdp-dark z-50 max-w-[calc(100vw-1rem)] rounded-xl border border-dark-700 bg-dark-800 p-2 shadow-xl"
> >
<DayPicker <DayPicker
mode="single" mode="single"
@@ -91,6 +96,8 @@ export function DateField({ value, onChange, placeholder, min, max, className }:
selected={selected} selected={selected}
defaultMonth={selected} defaultMonth={selected}
disabled={disabled} disabled={disabled}
fixedWeeks
showOutsideDays
components={{ Chevron: NavChevron }} components={{ Chevron: NavChevron }}
onSelect={(d) => { onSelect={(d) => {
if (d) { if (d) {

View File

@@ -42,8 +42,8 @@ export function PeriodSelector({
if (dateMode) { if (dateMode) {
return ( return (
<div className="flex items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
<CalendarIcon className="h-4 w-4" /> <CalendarIcon className="h-4 w-4 shrink-0" />
<span className="text-xs text-dark-400">{t('admin.trafficUsage.dateFrom')}</span> <span className="text-xs text-dark-400">{t('admin.trafficUsage.dateFrom')}</span>
<DateField <DateField
value={customStart} value={customStart}

View File

@@ -68,7 +68,7 @@ export function PeriodSelector({ value, onChange }: PeriodSelectorProps) {
</button> </button>
{showCustom && ( {showCustom && (
<div className="flex items-center gap-2"> <div className="flex w-full flex-wrap items-center gap-2 sm:w-auto">
<DateField <DateField
value={value.startDate || ''} value={value.startDate || ''}
onChange={(v) => handleDateChange('startDate', v)} onChange={(v) => handleDateChange('startDate', v)}