diff --git a/apps/web/api/ius/types.ts b/apps/web/api/ius/types.ts index a50a956..023e4f9 100644 --- a/apps/web/api/ius/types.ts +++ b/apps/web/api/ius/types.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -type MetaObject = { +export type MetaObject = { disabled: boolean; - fieldType: string; + fieldType: 'CHECKBOX' | 'DECIMAL' | 'INT' | 'STRING'; label: string; required: boolean; visible: boolean; diff --git a/apps/web/app/ius/[slug]/page.tsx b/apps/web/app/ius/[slug]/page.tsx index a5f8460..33294ee 100644 --- a/apps/web/app/ius/[slug]/page.tsx +++ b/apps/web/app/ius/[slug]/page.tsx @@ -1,6 +1,7 @@ import * as apiIUS from '@/api/ius/query'; import type { Request } from '@/api/ius/types'; -import { Background, Button, Content, Input, Title, Wrapper } from 'ui'; +import { mapFieldTypeElement } from '@/config/elements'; +import { Background, Button, Content, ElementContainer } from 'ui'; type Props = { params: { slug: string }; @@ -17,18 +18,21 @@ export default async function Page(props: Props) {
- {Object.keys(metaData).map((name) => ( - - - <Input - id={name} - type="text" - required={metaData[name].required} - defaultValue={data[name]} - disabled={metaData[name].disabled} - /> - </Wrapper> - ))} + {Object.keys(metaData).map((name) => { + const { fieldType } = metaData[name]; + const Element = mapFieldTypeElement[fieldType]; + + return ( + <ElementContainer key={name} id={name} title={metaData[name].label}> + <Element + id={name} + required={metaData[name].required} + defaultValue={data[name]} + disabled={metaData[name].disabled} + /> + </ElementContainer> + ); + })} </div> <div className="grid grid-cols-3 gap-5 pt-3"> <Button>Сохранить</Button> diff --git a/apps/web/config/elements.ts b/apps/web/config/elements.ts new file mode 100644 index 0000000..cbd9771 --- /dev/null +++ b/apps/web/config/elements.ts @@ -0,0 +1,13 @@ +import type { MetaObject } from '@/api/ius/types'; +import { Checkbox, Input } from 'ui'; + +function wrapMap<C, T extends Record<MetaObject['fieldType'], C>>(arg: T) { + return arg; +} + +export const mapFieldTypeElement = wrapMap({ + CHECKBOX: Checkbox, + DECIMAL: Input, + INT: Input, + STRING: Input, +}); diff --git a/apps/web/package.json b/apps/web/package.json index 7b0c4e0..9b3ae86 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@tailwindcss/forms": "^0.5.6", "next": "^14.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js index 33ad091..12a703d 100644 --- a/apps/web/postcss.config.js +++ b/apps/web/postcss.config.js @@ -3,4 +3,4 @@ module.exports = { tailwindcss: {}, autoprefixer: {}, }, -} +}; diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts index 660a7fb..20a62cb 100644 --- a/apps/web/tailwind.config.ts +++ b/apps/web/tailwind.config.ts @@ -1,4 +1,5 @@ import { COLORS } from './constants/colors'; +import tailwindForms from '@tailwindcss/forms'; import tailwindTints from 'tailwind-tints'; import type { Config } from 'tailwindcss'; @@ -25,6 +26,6 @@ const config: Config = { // }, // }, }, - plugins: [tints], + plugins: [tints, tailwindForms], }; export default config; diff --git a/packages/ui/checkbox.tsx b/packages/ui/checkbox.tsx new file mode 100644 index 0000000..96601f7 --- /dev/null +++ b/packages/ui/checkbox.tsx @@ -0,0 +1,24 @@ +import { cn } from './utils'; +import type { VariantProps } from 'class-variance-authority'; +import { cva } from 'class-variance-authority'; +import { forwardRef } from 'react'; + +const variants = cva( + 'w-4 h-4 focus:ring-transparent rounded-sm hover:border-primary-500 disabled:hover:border-gray-300 border-gray-300 text-sm text-primary outline-none transition-all ease-linear hover:transition-all focus:transition-all disabled:cursor-not-allowed disabled:text-opacity-30' +); + +export type CheckboxProps = React.InputHTMLAttributes<HTMLInputElement> & + VariantProps<typeof variants>; + +export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>( + ({ className, title, ...props }, ref) => ( + <div className="flex items-center"> + <input ref={ref} type="checkbox" className={cn(variants({ className }))} {...props} /> + {title && ( + <label htmlFor={props.id} className="ml-2 text-sm font-normal text-gray-900"> + {title} + </label> + )} + </div> + ) +); diff --git a/packages/ui/container.tsx b/packages/ui/container.tsx new file mode 100644 index 0000000..0b6e8f0 --- /dev/null +++ b/packages/ui/container.tsx @@ -0,0 +1,17 @@ +import type { HTMLAttributes, PropsWithChildren } from 'react'; + +export type ContainerProps = HTMLAttributes<HTMLDivElement> & PropsWithChildren; + +export function ElementContainer({ children, id, title, ...props }: ContainerProps) { + return ( + <div {...props} className="flex flex-col"> + <label + htmlFor={id} + className="mb-1 block overflow-hidden overflow-ellipsis whitespace-nowrap text-sm font-medium text-black text-opacity-90" + > + {title} + </label> + <div className="flex h-9 items-center">{children}</div> + </div> + ); +} diff --git a/packages/ui/element.tsx b/packages/ui/element.tsx deleted file mode 100644 index 79787bf..0000000 --- a/packages/ui/element.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { cn } from './utils'; -import type { VariantProps } from 'class-variance-authority'; -import { cva } from 'class-variance-authority'; -import type { PropsWithChildren } from 'react'; -import { forwardRef } from 'react'; - -const wrapperVariants = cva('flex flex-col'); - -export type DivProps = React.HTMLAttributes<HTMLDivElement> & - VariantProps<typeof wrapperVariants> & - PropsWithChildren; - -export const Wrapper = forwardRef<HTMLDivElement, DivProps>( - ({ children, className, ...props }, ref) => ( - <div {...props} className={cn(wrapperVariants({ className }))} ref={ref}> - {children} - </div> - ) -); - -const titleVariants = cva( - 'mb-1 block overflow-hidden overflow-ellipsis whitespace-nowrap text-sm font-medium text-black text-opacity-90' -); - -export type LabelProps = React.LabelHTMLAttributes<HTMLLabelElement>; - -export const Title = forwardRef<HTMLLabelElement, LabelProps>( - ({ className, htmlFor, title, ...props }, ref) => ( - <label {...props} htmlFor={htmlFor} className={cn(titleVariants({ className }))} ref={ref}> - {title} - </label> - ) -); diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx index 70cb42d..48f1192 100644 --- a/packages/ui/index.tsx +++ b/packages/ui/index.tsx @@ -1,6 +1,7 @@ export * from './background'; export * from './button'; +export * from './checkbox'; +export * from './container'; export * from './content'; -export * from './element'; export * from './header'; export * from './input'; diff --git a/packages/ui/input.tsx b/packages/ui/input.tsx index 4999878..d6e0e79 100644 --- a/packages/ui/input.tsx +++ b/packages/ui/input.tsx @@ -11,11 +11,5 @@ export type InputProps = React.InputHTMLAttributes<HTMLInputElement> & VariantProps<typeof variants>; export const Input = forwardRef<HTMLInputElement, InputProps>(({ className, ...props }, ref) => ( - <input - ref={ref} - type={props.type} - id={props.id} - className={cn(variants({ className }))} - {...props} - /> + <input ref={ref} type="text" id={props.id} className={cn(variants({ className }))} {...props} /> )); diff --git a/yarn.lock b/yarn.lock index b7c4054..2bdf457 100644 --- a/yarn.lock +++ b/yarn.lock @@ -710,6 +710,13 @@ dependencies: tslib "^2.4.0" +"@tailwindcss/forms@^0.5.6": + version "0.5.6" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.6.tgz#29c6c2b032b363e0c5110efed1499867f6d7e868" + integrity sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA== + dependencies: + mini-svg-data-uri "^1.2.3" + "@tootallnate/quickjs-emscripten@^0.23.0": version "0.23.0" resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" @@ -4001,6 +4008,11 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +mini-svg-data-uri@^1.2.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" + integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== + minimatch@4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.3.tgz#b4dcece1d674dee104bb0fb833ebb85a78cbbca6"