diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..c752985 Binary files /dev/null and b/.DS_Store differ diff --git a/packages/.DS_Store b/packages/.DS_Store new file mode 100644 index 0000000..0bf0f67 Binary files /dev/null and b/packages/.DS_Store differ diff --git a/packages/frontend/.gitignore b/packages/frontend/.gitignore index a547bf3..288bdc5 100644 --- a/packages/frontend/.gitignore +++ b/packages/frontend/.gitignore @@ -17,8 +17,10 @@ dist-ssr !.vscode/extensions.json .idea .DS_Store +**/.DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? + diff --git a/packages/frontend/package-lock.json b/packages/frontend/package-lock.json index d54b5d9..43fd993 100644 --- a/packages/frontend/package-lock.json +++ b/packages/frontend/package-lock.json @@ -8,8 +8,10 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "clsx": "^2.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-icons": "^5.3.0", "react-router-dom": "^6.27.0", "zustand": "^5.0.0" }, @@ -1682,6 +1684,14 @@ "node": ">= 6" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3011,6 +3021,14 @@ "react": "^18.3.1" } }, + "node_modules/react-icons": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-router": { "version": "6.27.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 552fef2..47f69b4 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "clsx": "^2.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-icons": "^5.3.0", "react-router-dom": "^6.27.0", "zustand": "^5.0.0" }, diff --git a/packages/frontend/src/lib/Button.tsx b/packages/frontend/src/lib/Button.tsx new file mode 100644 index 0000000..d798717 --- /dev/null +++ b/packages/frontend/src/lib/Button.tsx @@ -0,0 +1,26 @@ +import clsx from "clsx"; + +type ButtonProps = { + isDisabled?: boolean; + className?: string; +}; + +function Button({ isDisabled, className }: ButtonProps) { + return ( + + ); +} + +export default Button; diff --git a/packages/frontend/src/lib/Input.tsx b/packages/frontend/src/lib/Input.tsx new file mode 100644 index 0000000..8470c36 --- /dev/null +++ b/packages/frontend/src/lib/Input.tsx @@ -0,0 +1,149 @@ +import clsx from "clsx"; +import React, { useEffect, useState } from "react"; + +interface InputProps { + type?: "text" | "email" | "textarea" | "password"; + value: string; + onChange?: (value: string) => void; + label: string; + readOnly?: boolean; + name: string; + isRequired: boolean; + minLength?: number; + maxLength?: number; + bottomText?: string; + pattern?: string; + className?: string; + disabled?: boolean; + [key: string]: any; +} + +interface IsRequiredComponentProps { + isRequired: boolean; +} + +const Input: React.FC = ({ + type = "text", + value: propValue = "", + onChange, + label = "Name", + readOnly, + isRequired, + bottomText, + pattern, + minLength, + maxLength, + error, + disabled, + className, + name, + ...props +}) => { + const [inputValue, setInputValue] = useState(propValue); + const [showPassword, setShowPassword] = useState(false); + + useEffect(() => { + setInputValue(propValue); + }, [propValue]); + + const handleChange = ( + e: + | React.ChangeEvent + | React.ChangeEvent + ) => { + const newValue = e.target.value; + setInputValue(newValue); + if (onChange) { + onChange(newValue); + } + }; + + const togglePasswordVisibility = () => { + setShowPassword((prev) => !prev); + }; + + if (type === "textarea") { + return ( +
+ +