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
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:
@@ -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 }
|
||||
@@ -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 }
|
||||
@@ -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"
|
||||
@@ -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 }
|
||||
@@ -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 }
|
||||
Reference in New Issue
Block a user