feat(web): собрать экраны из блоков ReUI PRO
CD / update-wiki (push) Successful in 6s
quality / commitlint (push) Skipped
quality / changes (push) Successful in 11s
quality / api (push) Skipped
quality / docker-check (push) Skipped
quality / web (push) Failing after 52s
CD / quality (push) Failing after 1m5s
CD / publish (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / commitlint (push) Skipped
quality / changes (push) Successful in 11s
quality / api (push) Skipped
quality / docker-check (push) Skipped
quality / web (push) Failing after 52s
CD / quality (push) Failing after 1m5s
CD / publish (push) Skipped
Подключить stats-12, card-12, settings-3 и empty-state-12 к оболочке, спискам, карточкам и настройкам, чтобы метрики и пустые состояния шли из одних блоков. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
73f5380768
commit
2418344551
58 files changed
+1846
-689
No files matched your search
@@ -41,6 +41,14 @@ import {
|
||||
redirectToPortalLogout,
|
||||
resetPortalHandoff,
|
||||
} from '@/lib/auth'
|
||||
import {
|
||||
readContrast,
|
||||
readDensity,
|
||||
writeContrast,
|
||||
writeDensity,
|
||||
type ContrastMode,
|
||||
type DensityMode,
|
||||
} from '@/lib/appearance-mode'
|
||||
|
||||
/** Sidebar footer account menu — ReUI app-shell-1 NavUser. @see https://reui.io/preview/base/app-shell-1 */
|
||||
|
||||
@@ -107,6 +115,98 @@ function ThemeSegmentedToggle() {
|
||||
)
|
||||
}
|
||||
|
||||
function SegmentedChoice<T extends string>({
|
||||
label,
|
||||
value,
|
||||
options,
|
||||
onChange,
|
||||
}: {
|
||||
label: string
|
||||
value: T
|
||||
options: readonly { value: T; label: string }[]
|
||||
onChange: (value: T) => void
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
role="radiogroup"
|
||||
aria-label={label}
|
||||
className="bg-muted/60 inline-flex items-center gap-0.5 rounded-full p-0.5"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
{options.map((option) => {
|
||||
const isActive = value === option.value
|
||||
return (
|
||||
<Button
|
||||
key={option.value}
|
||||
type="button"
|
||||
role="radio"
|
||||
aria-checked={isActive}
|
||||
size="xs"
|
||||
variant={isActive ? 'secondary' : 'ghost'}
|
||||
onClick={() => onChange(option.value)}
|
||||
>
|
||||
{option.label}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function AppearanceToggles() {
|
||||
const [contrast, setContrast] = useState<ContrastMode>('standard')
|
||||
const [density, setDensity] = useState<DensityMode>('normal')
|
||||
const [mounted, setMounted] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setContrast(readContrast())
|
||||
setDensity(readDensity())
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!mounted) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenuItem className="cursor-default focus:bg-transparent">
|
||||
<span className="text-sm">Контраст</span>
|
||||
<div className="ml-auto">
|
||||
<SegmentedChoice
|
||||
label="Контраст"
|
||||
value={contrast}
|
||||
options={[
|
||||
{ value: 'standard', label: 'Обычный' },
|
||||
{ value: 'high', label: 'Высокий' },
|
||||
]}
|
||||
onChange={(next) => {
|
||||
setContrast(next)
|
||||
writeContrast(next)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="cursor-default focus:bg-transparent">
|
||||
<span className="text-sm">Плотность</span>
|
||||
<div className="ml-auto">
|
||||
<SegmentedChoice
|
||||
label="Плотность"
|
||||
value={density}
|
||||
options={[
|
||||
{ value: 'normal', label: 'Обычная' },
|
||||
{ value: 'compact', label: 'Компакт' },
|
||||
]}
|
||||
onChange={(next) => {
|
||||
setDensity(next)
|
||||
writeDensity(next)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function initials(name: string, email: string): string {
|
||||
const base = name.trim() || email.trim()
|
||||
if (!base) return '?'
|
||||
@@ -202,6 +302,7 @@ export function NavUser() {
|
||||
<ThemeSegmentedToggle />
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<AppearanceToggles />
|
||||
</DropdownMenuGroup>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
Reference in new issue
Block a user