fix(config): добавить новые зависимости и обновить конфигурацию компонентов
Docker images / prepare-release (push) Successful in 5s
Docker images / backend-image (push) Successful in 2m37s
Docker images / frontend-image (push) Successful in 2m22s
Docker images / updater-image (push) Successful in 38s
Docker images / notify-webhook (push) Has been skipped
Docker images / publish-release (push) Successful in 8s

This commit is contained in:
Denozordec
2026-06-30 21:30:40 +07:00
parent 009011a917
commit a1a9124f3d
80 changed files with 13310 additions and 1587 deletions
+31
View File
@@ -0,0 +1,31 @@
"use client"
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
interface FormFieldProps {
label: string
hint?: string
error?: string
required?: boolean
children: React.ReactNode
}
function FormField({ label, hint, error, required, children }: FormFieldProps) {
return (
<Field data-invalid={!!error}>
<FieldLabel>
{label}
{required && <span className="text-destructive ml-0.5">*</span>}
</FieldLabel>
{children}
{hint && !error && <FieldDescription>{hint}</FieldDescription>}
{error && <FieldDescription className="text-destructive">{error}</FieldDescription>}
</Field>
)
}
export { FormField, type FormFieldProps }
+24
View File
@@ -0,0 +1,24 @@
"use client"
import { Switch } from "@/components/ui/switch"
import { cn } from "@/lib/utils"
interface FormToggleProps {
checked: boolean
onChange: (value: boolean) => void
disabled?: boolean
className?: string
}
function FormToggle({ checked, onChange, disabled, className }: FormToggleProps) {
return (
<Switch
checked={checked}
onCheckedChange={onChange}
disabled={disabled}
className={cn(className)}
/>
)
}
export { FormToggle, type FormToggleProps }
+4
View File
@@ -0,0 +1,4 @@
export { FormField, type FormFieldProps } from "./form-field"
export { FormToggle, type FormToggleProps } from "./form-toggle"
export { SectionTitle, type SectionTitleProps } from "./section-title"
export { SegmentedControl, type SegmentedControlProps } from "./segmented-control"
+21
View File
@@ -0,0 +1,21 @@
import { cn } from "@/lib/utils"
interface SectionTitleProps {
children: React.ReactNode
icon?: React.ReactNode
className?: string
}
function SectionTitle({ children, icon, className }: SectionTitleProps) {
return (
<div className={cn("flex items-center gap-2 py-0.5", className)}>
{icon}
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
{children}
</span>
<div className="flex-1 h-px bg-border" />
</div>
)
}
export { SectionTitle, type SectionTitleProps }
+47
View File
@@ -0,0 +1,47 @@
"use client"
import { cn } from "@/lib/utils"
interface SegmentedControlProps<T extends string> {
value: T
onChange: (value: T) => void
options: { value: T; label: string; count?: number }[]
className?: string
}
function SegmentedControl<T extends string>({
value,
onChange,
options,
className,
}: SegmentedControlProps<T>) {
return (
<div
className={cn(
"flex items-center gap-1 rounded-md border border-border bg-muted/40 p-0.5 w-fit",
className,
)}
>
{options.map((option) => (
<button
key={option.value}
type="button"
onClick={() => onChange(option.value)}
className={cn(
"flex items-center gap-1.5 rounded px-3 py-1 text-sm transition-colors",
value === option.value
? "bg-background text-foreground shadow-sm"
: "text-muted-foreground hover:text-foreground",
)}
>
{option.label}
{option.count != null && (
<span className="text-xs tabular-nums opacity-60">{option.count}</span>
)}
</button>
))}
</div>
)
}
export { SegmentedControl, type SegmentedControlProps }