diff --git a/package-lock.json b/package-lock.json index 3d7401c..66138b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1211,6 +1211,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.1.14", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", diff --git a/src/app/components/FormInput/DatePicker.jsx b/src/app/components/FormInput/DatePicker.jsx new file mode 100644 index 0000000..3a3451f --- /dev/null +++ b/src/app/components/FormInput/DatePicker.jsx @@ -0,0 +1,23 @@ +import React, { useState } from "react"; + +export const DatePicker = ({ label = "Select Date", onChange }) => { + const [date, setDate] = useState(""); + + const handleChange = (e) => { + setDate(e.target.value); + if (onChange) onChange(e.target.value); + }; + + return ( +
+ + + {date &&

Selected Date: {date}

} +
+ ); +}; diff --git a/src/app/components/FormInput/FileUpload.jsx b/src/app/components/FormInput/FileUpload.jsx new file mode 100644 index 0000000..df3fb85 --- /dev/null +++ b/src/app/components/FormInput/FileUpload.jsx @@ -0,0 +1,45 @@ +import React, { useState } from "react"; + +export const FileUpload = ({ onFileSelect }) => { + const [file, setFile] = useState(null); + + const handleFile = (file) => { + setFile(file); + if (onFileSelect) onFileSelect(file); + }; + + const handleDrop = (e) => { + e.preventDefault(); + handleFile(e.dataTransfer.files[0]); + }; + + const handleChange = (e) => { + handleFile(e.target.files[0]); + }; + + return ( +
+ +
+ ); +}; diff --git a/src/app/components/FormInput/FormValidation.jsx b/src/app/components/FormInput/FormValidation.jsx new file mode 100644 index 0000000..ba426b5 --- /dev/null +++ b/src/app/components/FormInput/FormValidation.jsx @@ -0,0 +1,33 @@ +import React, { useState } from "react"; + +export const FormValidation = ({ minLength = 3, onSubmit }) => { + const [value, setValue] = useState(""); + const [error, setError] = useState(""); + + const handleSubmit = (e) => { + e.preventDefault(); + if (value.trim() === "") { + setError("Field cannot be empty"); + } else if (value.length < minLength) { + setError(`Minimum ${minLength} characters required`); + } else { + setError(""); + if (onSubmit) onSubmit(value); + alert("Form submitted: " + value); + } + }; + + return ( +
+ setValue(e.target.value)} + style={{ padding: "0.5rem", marginRight: "0.5rem" }} + placeholder="Enter text" + /> + + {error &&

{error}

} +
+ ); +}; diff --git a/src/app/components/FormInput/Slider.jsx b/src/app/components/FormInput/Slider.jsx new file mode 100644 index 0000000..fc59b45 --- /dev/null +++ b/src/app/components/FormInput/Slider.jsx @@ -0,0 +1,24 @@ +import React, { useState } from "react"; + +export const Slider = ({ min = 0, max = 100, step = 1, onChange }) => { + const [value, setValue] = useState((min + max) / 2); + + const handleChange = (e) => { + setValue(e.target.value); + if (onChange) onChange(e.target.value); + }; + + return ( +
+ +

Value: {value}

+
+ ); +}; diff --git a/src/app/components/page.jsx b/src/app/components/page.jsx index 566a5d8..3d75511 100644 --- a/src/app/components/page.jsx +++ b/src/app/components/page.jsx @@ -1,9 +1,9 @@ "use client"; -import React, { useState, useEffect } from 'react' -import { Search, X } from 'lucide-react' +import React, { useState, useEffect } from "react"; +import { Search, X } from "lucide-react"; -import { useAnalytics } from '../context/AnalyticsContext' -import { useTheme } from '../context/ThemeContext' +import { useAnalytics } from "../context/AnalyticsContext"; +import { useTheme } from "../context/ThemeContext"; // Button Imports // import PrimaryButton from '@/components/buttons/PrimaryButton' // import SecondaryButton from '@/components/buttons/SecondaryButton' @@ -53,11 +53,17 @@ import Pagination from "./navigation/Pagination"; import UserCard from "@/app/components/cards/UserCard"; import RainbowButton from "@/app/components/buttons/RainbowButton"; +// form Input + +import { DatePicker } from "./FormInput/DatePicker"; +import { FileUpload } from "./FormInput/FileUpload"; +import { FormValidation } from "./FormInput/FormValidation"; +import { Slider } from "./FormInput/Slider"; export default function Page() { // Search and Filter State - const [searchTerm, setSearchTerm] = useState(''); - const [filterType, setFilterType] = useState('all'); + const [searchTerm, setSearchTerm] = useState(""); + const [filterType, setFilterType] = useState("all"); // Analytics @@ -68,7 +74,7 @@ export default function Page() { // Track page view - only once on mount useEffect(() => { - trackComponentView('ComponentsPage'); + trackComponentView("ComponentsPage"); }, []); // Empty dependency array to run only once // Inputs @@ -76,8 +82,6 @@ export default function Page() { const [selectValue, setSelectValue] = React.useState(""); const [checkboxValue, setCheckboxValue] = React.useState(false); - - // Data const selectOptions = [ { value: "option1", label: "Option 1" }, @@ -108,11 +112,129 @@ export default function Page() { { label: "Breadcrumb" }, ]; - - // All components with search data const allComponents = { buttons: [ + { + name: "Primary Button", + component: Primary, + keywords: ["primary", "main", "action", "cta"], + desc: "Used for Main Actions", + }, + { + name: "Secondary Button", + component: Secondary, + keywords: ["secondary", "alternate"], + desc: "Used for secondary Actions", + }, + { + name: "Ghost Button", + component: Ghost, + keywords: ["ghost", "transparent", "subtle"], + desc: "Used for minimal actions", + }, + { + name: "Outline Button", + component: Outline, + keywords: ["outline", "border", "stroke"], + desc: "Used for gives outline", + }, + { + name: "Danger Button", + component: Danger, + keywords: ["danger", "error", "delete", "warning", "red"], + desc: "Used for destructive actions", + }, + { + name: "Success Button", + component: Success, + keywords: ["success", "confirm", "done", "green"], + desc: "Used for success actions", + }, + { + name: "Icon Button", + component: , + keywords: ["icon", "star", "symbol"], + desc: "Used for icons", + }, + { + name: "Rainbow Button", + component: Rainbow, + keywords: ["rainbow", "action", "colorful"], + desc: "Used for call to actions", + }, + ], + cards: [ + { + name: "Simple Card", + component: ( + + ), + keywords: ["simple", "basic", "minimal"], + }, + { + name: "Image Card", + component: ( + + ), + keywords: ["image", "picture", "visual"], + }, + { + name: "Feature Card", + component: ( + + ), + keywords: ["feature", "highlight", "benefit"], + }, + { + name: "Pricing Card", + component: ( + + ), + keywords: ["pricing", "plan", "subscription", "price"], + }, + { + name: "Data Card", + component: ( + + ), + keywords: ["data", "stats", "analytics", "metrics"], + }, + ], + inputs: [ + { + name: "Text Input", + component: , + keywords: ["text", "input", "field", "form"], + }, + { + name: "Select", + component: , keywords: ['select', 'dropdown', 'options', 'choice'] }, { name: 'Checkbox', component: { }} />, keywords: ['checkbox', 'check', 'toggle', 'boolean'] } + ], navigation: [ - { name: 'Breadcrumb', component: , keywords: ['breadcrumb', 'navigation', 'path', 'hierarchy'] }, - { name: 'Tabs', component: , keywords: ['tabs', 'navigation', 'switch', 'toggle'] }, - { name: 'Pagination', component: , keywords: ['pagination', 'pages', 'navigation', 'paging'] } - ] + { + name: "Breadcrumb", + component: , + keywords: ["breadcrumb", "navigation", "path", "hierarchy"], + }, + { + name: "Tabs", + component: , + keywords: ["tabs", "navigation", "switch", "toggle"], + }, + { + name: "Pagination", + component: ( + + ), + keywords: ["pagination", "pages", "navigation", "paging"], + }, + ], }; // Filter logic @@ -147,7 +284,7 @@ export default function Page() { let components = {}; // Apply type filter - if (filterType === 'all') { + if (filterType === "all") { components = allComponents; } else { components = { [filterType]: allComponents[filterType] }; @@ -156,10 +293,13 @@ export default function Page() { // Apply search filter if (searchTerm) { const filtered = {}; - Object.keys(components).forEach(type => { - const matchedComponents = components[type].filter(comp => - comp.name.toLowerCase().includes(searchTerm.toLowerCase()) || - comp.keywords.some(keyword => keyword.toLowerCase().includes(searchTerm.toLowerCase())) + Object.keys(components).forEach((type) => { + const matchedComponents = components[type].filter( + (comp) => + comp.name.toLowerCase().includes(searchTerm.toLowerCase()) || + comp.keywords.some((keyword) => + keyword.toLowerCase().includes(searchTerm.toLowerCase()) + ) ); if (matchedComponents.length > 0) { filtered[type] = matchedComponents; @@ -172,7 +312,10 @@ export default function Page() { }; const filteredComponents = getFilteredComponents(); - const totalResults = Object.values(filteredComponents).reduce((total, components) => total + components.length, 0); + const totalResults = Object.values(filteredComponents).reduce( + (total, components) => total + components.length, + 0 + ); return (
@@ -202,7 +345,7 @@ export default function Page() { /> {searchTerm && (
); -} \ No newline at end of file +}