├── src ├── assets │ ├── styles │ │ ├── Block │ │ │ └── index.css │ │ ├── Flex │ │ │ └── index.css │ │ ├── skeleton │ │ │ └── index.css │ │ ├── Container │ │ │ └── index.css │ │ ├── Separator │ │ │ └── index.css │ │ ├── Avatar │ │ │ └── index.css │ │ ├── confirmationDialog │ │ │ └── index.css │ │ ├── tooltip │ │ │ └── index.css │ │ ├── accordion │ │ │ └── index.css │ │ ├── HoverCard │ │ │ └── index.css │ │ ├── Checkbox │ │ │ └── index.css │ │ ├── Breadcrumb │ │ │ └── index.css │ │ ├── Badge │ │ │ └── index.css │ │ ├── index.css │ │ ├── Button │ │ │ └── index.css │ │ ├── model │ │ │ └── index.css │ │ ├── Typography │ │ │ └── index.css │ │ ├── context-menu │ │ │ └── index.css │ │ └── drop-down-menu │ │ │ └── index.css │ ├── fonts │ │ └── index.ts │ ├── svg │ │ └── index.ts │ └── react.svg ├── components │ ├── HOC │ │ ├── index.ts │ │ └── theme │ │ │ ├── index.ts │ │ │ └── theme-provider.tsx │ ├── config │ │ ├── index.ts │ │ └── ui │ │ │ ├── index.ts │ │ │ ├── colors-variants │ │ │ └── index.ts │ │ │ └── asElement │ │ │ ├── index.ts │ │ │ └── asElement.ts │ ├── ui │ │ ├── Avatar │ │ │ ├── index.ts │ │ │ └── Avatar.tsx │ │ ├── Badge │ │ │ ├── index.ts │ │ │ └── Badge.tsx │ │ ├── Model │ │ │ ├── index.ts │ │ │ ├── utils │ │ │ │ └── model-variants.ts │ │ │ └── Model.tsx │ │ ├── CheckBox │ │ │ ├── index.ts │ │ │ └── Checkbox.tsx │ │ ├── Skeleton │ │ │ ├── index.ts │ │ │ └── Skeleton.tsx │ │ ├── ToolTip │ │ │ ├── index.ts │ │ │ └── ToolTip.tsx │ │ ├── Accordion │ │ │ ├── index.ts │ │ │ └── Accordion.tsx │ │ ├── Breadcrumb │ │ │ ├── index.ts │ │ │ └── Breadcrumb.tsx │ │ ├── ContextMenu │ │ │ ├── index.ts │ │ │ └── Contextmenu.tsx │ │ ├── HoverCard │ │ │ ├── index.ts │ │ │ └── HoverCard.tsx │ │ ├── Separator │ │ │ ├── index.ts │ │ │ └── Separator.tsx │ │ ├── Common │ │ │ ├── index.ts │ │ │ └── colors-blocks.ts │ │ ├── DropDownMenu │ │ │ ├── index.ts │ │ │ └── DropDownMenu.tsx │ │ ├── Block │ │ │ ├── index.ts │ │ │ └── Block.tsx │ │ ├── ConfirmationDialog │ │ │ ├── index.ts │ │ │ └── ConfirmationDialog.tsx │ │ ├── Container │ │ │ ├── index.ts │ │ │ └── Container.tsx │ │ ├── Button │ │ │ ├── index.ts │ │ │ ├── utils │ │ │ │ └── ButtonVariants.ts │ │ │ └── button.tsx │ │ ├── Typography │ │ │ ├── index.ts │ │ │ ├── utils │ │ │ │ ├── text-color.ts │ │ │ │ └── TypographyClasses.ts │ │ │ └── Typography.tsx │ │ ├── Grid │ │ │ ├── index.ts │ │ │ ├── utils │ │ │ │ └── style-object.ts │ │ │ ├── Grid.tsx │ │ │ └── GridItem │ │ │ │ └── index.tsx │ │ ├── Flex │ │ │ ├── index.ts │ │ │ ├── Flex.tsx │ │ │ └── utils │ │ │ │ └── style-object.ts │ │ ├── types.ts │ │ └── index.ts │ ├── shared │ │ ├── Label │ │ │ ├── index.ts │ │ │ └── Label.tsx │ │ ├── index.ts │ │ └── Form │ │ │ └── Form.tsx │ └── hooks │ │ ├── useTheme │ │ ├── index.ts │ │ └── useTheme.ts │ │ └── index.ts ├── vite-env.d.ts ├── @types │ └── commonTypes.ts ├── main.tsx ├── utils │ └── className │ │ └── index.ts ├── tailwind.css └── App.tsx ├── docs ├── projects.md ├── _images │ ├── code.png │ ├── fork.png │ ├── plus.png │ ├── vite.png │ ├── repository.png │ ├── typescript.png │ ├── use-this-template.png │ ├── create-new-repository.png │ └── react.svg └── index.md ├── postcss.config.js ├── cspell.json ├── .eslintignore ├── .husky └── pre-commit ├── tsconfig.node.json ├── .gitignore ├── index.html ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── codeql.yml ├── vite.config.ts ├── LICENCE.md ├── public └── vite.svg ├── SECURITY.md ├── tsconfig.json ├── package.json ├── tailwind.config.js ├── .eslintrc.cjs ├── CODE_OF_CONDUCT.md └── README.md /src/assets/styles/Block/index.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/styles/Flex/index.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/projects.md: -------------------------------------------------------------------------------- 1 | # project intro structure 2 | -------------------------------------------------------------------------------- /src/components/HOC/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./theme"; 2 | -------------------------------------------------------------------------------- /src/components/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ui"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Avatar/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Avatar"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Badge/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Badge"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Model/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Model"; 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/components/shared/Label/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Label"; 2 | -------------------------------------------------------------------------------- /src/components/shared/index.ts: -------------------------------------------------------------------------------- 1 | export { Label } from "./Label"; 2 | -------------------------------------------------------------------------------- /src/components/ui/CheckBox/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Checkbox"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Skeleton/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Skeleton"; 2 | -------------------------------------------------------------------------------- /src/components/ui/ToolTip/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ToolTip"; 2 | -------------------------------------------------------------------------------- /src/components/HOC/theme/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./theme-provider"; 2 | -------------------------------------------------------------------------------- /src/components/hooks/useTheme/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./useTheme"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Accordion/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Accordion"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Breadcrumb/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Breadcrumb"; 2 | -------------------------------------------------------------------------------- /src/components/ui/ContextMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Contextmenu"; 2 | -------------------------------------------------------------------------------- /src/components/ui/HoverCard/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./HoverCard"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Separator/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Separator"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Common/index.ts: -------------------------------------------------------------------------------- 1 | // export * from "@Components/config"; 2 | -------------------------------------------------------------------------------- /src/components/ui/DropDownMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./DropDownMenu"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Block/index.ts: -------------------------------------------------------------------------------- 1 | export { Block, type BlockProps } from "./Block"; 2 | -------------------------------------------------------------------------------- /src/components/ui/ConfirmationDialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ConfirmationDialog"; 2 | -------------------------------------------------------------------------------- /src/components/ui/Container/index.ts: -------------------------------------------------------------------------------- 1 | export { type ContainerProps, Container } from "./Container"; 2 | -------------------------------------------------------------------------------- /docs/_images/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/code.png -------------------------------------------------------------------------------- /docs/_images/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/fork.png -------------------------------------------------------------------------------- /docs/_images/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/plus.png -------------------------------------------------------------------------------- /docs/_images/vite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/vite.png -------------------------------------------------------------------------------- /src/components/config/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./asElement"; 2 | export * from "./colors-variants"; 3 | -------------------------------------------------------------------------------- /src/components/ui/Button/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./button"; 2 | export * from "./utils/ButtonVariants"; 3 | -------------------------------------------------------------------------------- /docs/_images/repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/repository.png -------------------------------------------------------------------------------- /docs/_images/typescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/typescript.png -------------------------------------------------------------------------------- /src/assets/styles/skeleton/index.css: -------------------------------------------------------------------------------- 1 | .skeleton { 2 | @apply animate-pulse rounded-md bg-muted-light/20; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/ui/Typography/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils/TypographyClasses"; 2 | export * from "./Typography"; 3 | -------------------------------------------------------------------------------- /src/@types/commonTypes.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2 | export type AnyType = any; 3 | -------------------------------------------------------------------------------- /docs/_images/use-this-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/use-this-template.png -------------------------------------------------------------------------------- /docs/_images/create-new-repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepumandal/react-template/HEAD/docs/_images/create-new-repository.png -------------------------------------------------------------------------------- /src/components/ui/Grid/index.ts: -------------------------------------------------------------------------------- 1 | export { type GridProps, Grid } from "./Grid"; 2 | export { type GridItemProps, GridItem } from "./GridItem"; 3 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | "postcss-import": {}, 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/assets/fonts/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * import custom hooks from here. 3 | * 4 | * You should not change this file without necessary requirements. 5 | */ 6 | -------------------------------------------------------------------------------- /src/assets/svg/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * import custom hooks from here. 3 | * 4 | * You should not change this file without necessary requirements. 5 | */ 6 | -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "language": "en", 4 | "words": ["LICENCE"], 5 | "ignorePaths": ["node_modules", "dist", "build"], 6 | "ignoreWords": [] 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/styles/Container/index.css: -------------------------------------------------------------------------------- 1 | .base-container { 2 | @apply p-2 overflow-x-hidden Hide-Scroll-Track mx-auto; 3 | } 4 | 5 | .full-height { 6 | @apply h-full min-h-screen; 7 | } 8 | -------------------------------------------------------------------------------- /src/components/hooks/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * import custom hooks from here. 3 | * 4 | * You should not change this file without necessary requirements. 5 | */ 6 | export * from "./useTheme"; 7 | -------------------------------------------------------------------------------- /src/assets/styles/Separator/index.css: -------------------------------------------------------------------------------- 1 | .separator { 2 | @apply shrink-0 bg-border; 3 | } 4 | 5 | .separator-horizontal { 6 | @apply h-[1px] w-full; 7 | } 8 | .separator-vertical { 9 | @apply h-full w-[1px]; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/config/ui/colors-variants/index.ts: -------------------------------------------------------------------------------- 1 | type ColorVariantsType = 2 | | "default" 3 | | "primary" 4 | | "secondary" 5 | | "muted" 6 | | "accent" 7 | | "destructive" 8 | | "background"; 9 | 10 | export { type ColorVariantsType }; 11 | -------------------------------------------------------------------------------- /src/components/ui/Flex/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Flex, 3 | type FlexProps, 4 | type AlignContentType, 5 | type AlignItemsType, 6 | type AriaRole, 7 | type FlexDirectionType, 8 | type FlexElementType, 9 | type JustifyContentType, 10 | } from "./Flex"; 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .eslintrc.json 2 | package.json 3 | .gitignore 4 | pnpm-lock.yaml 5 | READEME.md 6 | vite.config.ts 7 | tailwind.config.ts 8 | tailwind.config.js 9 | tsconfig.json 10 | tsconfig.app.json 11 | tsconfig.node.json 12 | cspell.json 13 | LICENCE.md 14 | SECURITY.md -------------------------------------------------------------------------------- /src/components/ui/Skeleton/Skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@Utils/className"; 2 | 3 | const Skeleton = ({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) => ( 7 |
8 | ); 9 | 10 | export { Skeleton }; 11 | -------------------------------------------------------------------------------- /src/assets/styles/Avatar/index.css: -------------------------------------------------------------------------------- 1 | .avatar { 2 | @apply relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full; 3 | } 4 | 5 | .avatar-image { 6 | @apply aspect-square h-full w-full; 7 | } 8 | .avatar-fallback { 9 | @apply flex h-full w-full items-center justify-center rounded-full bg-muted; 10 | } 11 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | . "$(dirname -- "$0")/husky.sh" 2 | 3 | echo " " 4 | 5 | echo "🌟 Starting the code commit process! 🚀" 6 | 7 | echo " " 8 | 9 | # Run lint-staged script 10 | pnpm lint-staged 11 | 12 | echo " " 13 | echo " " 14 | 15 | # Display a completion message 16 | echo "✅ Code commit process completed successfully! 🎉" -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true 10 | }, 11 | "include": ["vite.config.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | #app 27 | .env -------------------------------------------------------------------------------- /src/assets/styles/confirmationDialog/index.css: -------------------------------------------------------------------------------- 1 | .dialog-content { 2 | @apply !top-[30%]; 3 | } 4 | 5 | .dialog-title { 6 | @apply !text-lg !font-semibold; 7 | } 8 | 9 | .dialog-description { 10 | @apply !text-sm !mt-4; 11 | } 12 | 13 | .dialog-footer { 14 | @apply !mt-6; 15 | } 16 | 17 | .dialog-delete { 18 | @apply !px-4; 19 | } 20 | 21 | .dialog-close { 22 | @apply px-4; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/hooks/useTheme/useTheme.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { ThemeProviderContext } from "@Components/HOC"; 3 | 4 | const useTheme = () => { 5 | const context = useContext(ThemeProviderContext); 6 | 7 | // if (context === undefined) 8 | // throw new Error("useTheme must be used within a ThemeProvider"); 9 | 10 | return context; 11 | }; 12 | 13 | export { useTheme }; 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/styles/tooltip/index.css: -------------------------------------------------------------------------------- 1 | .tooltip-content { 2 | @apply z-50 overflow-hidden rounded-md border bg-white px-3 py-1.5 text-sm text-text shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2; 3 | } 4 | -------------------------------------------------------------------------------- /src/assets/styles/accordion/index.css: -------------------------------------------------------------------------------- 1 | .accordion-root { 2 | @apply w-full; 3 | } 4 | 5 | .accordion-trigger { 6 | @apply flex 7 | flex-1 8 | text-heading 9 | items-center 10 | justify-between 11 | py-4 12 | font-medium 13 | /* transition-all */ 14 | hover:underline 15 | /* [&[data-state=open]>svg]:rotate-180; */; 16 | 17 | .accordion-icon { 18 | @apply h-4 w-4 shrink-0 transition-transform duration-200; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/styles/HoverCard/index.css: -------------------------------------------------------------------------------- 1 | .hoverCardContent { 2 | @apply z-50 w-64 rounded-md border bg-white p-4 text-text shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2; 3 | } 4 | -------------------------------------------------------------------------------- /src/assets/styles/Checkbox/index.css: -------------------------------------------------------------------------------- 1 | .checkbox { 2 | @apply h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-text; 3 | } 4 | 5 | .checkbox-indicator { 6 | @apply flex items-center justify-center text-current; 7 | } 8 | .box-size { 9 | @apply h-4 w-4; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/ui/Common/colors-blocks.ts: -------------------------------------------------------------------------------- 1 | import { type ColorVariantsType } from "@Components/config"; 2 | 3 | export const color: Record = { 4 | default: "bg-transparent", 5 | accent: "bg-accent", 6 | background: "bg-background", 7 | // border: "bg-border", 8 | // card: "bg-card", 9 | destructive: "bg-destructive", 10 | // input: "bg-input", 11 | muted: "bg-muted", 12 | primary: "bg-primary", 13 | // ring: "bg-ring", 14 | secondary: "bg-secondary", 15 | }; 16 | -------------------------------------------------------------------------------- /src/assets/styles/Breadcrumb/index.css: -------------------------------------------------------------------------------- 1 | .breadcrumb-list { 2 | @apply flex flex-wrap items-center gap-1.5 break-words text-sm text-muted sm:gap-2.5; 3 | } 4 | 5 | .breadcrumb-Item { 6 | @apply inline-flex items-center gap-1.5; 7 | } 8 | 9 | .breadcrumb-link { 10 | @apply transition-colors hover:text-text; 11 | } 12 | 13 | .breadcrumb-page { 14 | @apply font-normal text-text; 15 | } 16 | 17 | .breadcrumb-separator { 18 | @apply [&>svg]:size-3.5; 19 | } 20 | 21 | .breadcrumb-ellipsis { 22 | @apply flex h-9 w-9 items-center justify-center; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/ui/types.ts: -------------------------------------------------------------------------------- 1 | export { type BlockProps } from "./Block"; 2 | export { type ContainerProps } from "./Container"; 3 | export { 4 | type AlignItemsType, 5 | type AlignContentType, 6 | type FlexDirectionType, 7 | type FlexElementType, 8 | type FlexProps, 9 | type JustifyContentType, 10 | } from "./Flex"; 11 | export { type GridItemProps, type GridProps } from "./Grid"; 12 | export { type TypographyProps, type asElementObjectType } from "./Typography"; 13 | export { type ButtonProps } from "./Button"; 14 | export { type AccordionProps } from "./Accordion"; 15 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-named-as-default-member */ 2 | /* eslint-disable import/default */ 3 | import { StrictMode } from "react"; 4 | import ReactDOM from "react-dom/client"; 5 | import { ThemeProvider } from "@Components/HOC"; 6 | import App from "./App"; 7 | import "./tailwind.css"; 8 | 9 | const root = document.getElementById("root"); 10 | if (root) { 11 | ReactDOM.createRoot(root).render( 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | } else { 19 | throw new Error("Root element not found"); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/ui/Model/utils/model-variants.ts: -------------------------------------------------------------------------------- 1 | import { cva } from "class-variance-authority"; 2 | 3 | const modelVariants = cva("", { 4 | variants: { 5 | BackgroundColor: { 6 | primary: "text-heading bg-primary", 7 | destructive: "bg-destructive text-heading", 8 | outline: "border border-input text-heading bg-background text-heading", 9 | secondary: "bg-secondary text-heading hover:bg-secondary/80", 10 | default: "bg-background text-heading", 11 | }, 12 | }, 13 | defaultVariants: { 14 | BackgroundColor: "default", 15 | }, 16 | }); 17 | export { modelVariants }; 18 | -------------------------------------------------------------------------------- /src/assets/styles/Badge/index.css: -------------------------------------------------------------------------------- 1 | .base-badge { 2 | @apply inline-flex items-center rounded-full border px-3 py-1 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2; 3 | } 4 | .default-badge { 5 | @apply border-transparent bg-primary text-text-dark hover:bg-primary/80; 6 | } 7 | 8 | .secondary-badge { 9 | @apply border-transparent bg-secondary text-text hover:bg-secondary/80; 10 | } 11 | 12 | .destructive-badge { 13 | @apply border-transparent bg-destructive text-text-dark hover:bg-destructive/80; 14 | } 15 | 16 | .outline-badge { 17 | @apply text-text; 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/styles/index.css: -------------------------------------------------------------------------------- 1 | @import "./container/index.css"; 2 | @import "./model/index.css"; 3 | @import "./drop-down-menu/index.css"; 4 | @import "./accordion/index.css"; 5 | @import "./Avatar/index.css"; 6 | @import "./Badge/index.css"; 7 | @import "./Block/index.css"; 8 | @import "./Breadcrumb/index.css"; 9 | @import "./Button/index.css"; 10 | @import "./Checkbox/index.css"; 11 | @import "./confirmationDialog/index.css"; 12 | @import "./context-menu/index.css"; 13 | @import "./Flex/index.css"; 14 | @import "./HoverCard/index.css"; 15 | @import "./Separator/index.css"; 16 | @import "./skeleton/index.css"; 17 | @import "./tooltip/index.css"; 18 | @import "./Typography/index.css"; 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/components/ui/Typography/utils/text-color.ts: -------------------------------------------------------------------------------- 1 | import { type HeadingColorType, type TextColorType } from "@Components/config"; 2 | import { ClassType } from "@Utils/className"; 3 | 4 | export const TextColor: Record = { 5 | accent: "text-accent", 6 | default: "text-text", 7 | destructive: "text-destructive", 8 | muted: "text-muted", 9 | primary: "text-primary", 10 | secondary: "text-secondary", 11 | }; 12 | 13 | export const HeadingColor: Record = { 14 | accent: "text-accent", 15 | default: "text-text", 16 | destructive: "text-destructive", 17 | muted: "text-muted", 18 | primary: "text-primary", 19 | secondary: "text-secondary", 20 | }; 21 | -------------------------------------------------------------------------------- /src/components/ui/Button/utils/ButtonVariants.ts: -------------------------------------------------------------------------------- 1 | import { cva } from "class-variance-authority"; 2 | 3 | const buttonVariants = cva("base-button", { 4 | variants: { 5 | variant: { 6 | default: "default-button", 7 | destructive: "destructive-button", 8 | outline: "outline-button", 9 | secondary: "secondary-button", 10 | ghost: "ghost-button", 11 | link: "button-link", 12 | }, 13 | size: { 14 | default: "button-default-size", 15 | sm: "button-small-size", 16 | lg: "button-large-size", 17 | icon: "button-icon", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | size: "default", 23 | }, 24 | }); 25 | 26 | export { buttonVariants }; 27 | -------------------------------------------------------------------------------- /src/components/ui/Grid/utils/style-object.ts: -------------------------------------------------------------------------------- 1 | export const gridColumnsObj = { 2 | "1": "grid-cols-1", 3 | "2": "grid-cols-2", 4 | "3": "grid-cols-3", 5 | "4": "grid-cols-4", 6 | "5": "grid-cols-5", 7 | "6": "grid-cols-6", 8 | "7": "grid-cols-7", 9 | "8": "grid-cols-8", 10 | "9": "grid-cols-9", 11 | "10": "grid-cols-10", 12 | "11": "grid-cols-11", 13 | "12": "grid-cols-12", 14 | }; 15 | 16 | export const gapObj = { 17 | "0": "gap-0", 18 | "1": "gap-1", 19 | "2": "gap-2", 20 | "3": "gap-3", 21 | "4": "gap-4", 22 | "5": "gap-5", 23 | "6": "gap-6", 24 | "8": "gap-8", 25 | "10": "gap-10", 26 | "12": "gap-12", 27 | "16": "gap-16", 28 | }; 29 | 30 | export type GridColumnsType = keyof typeof gridColumnsObj; 31 | export type GapType = keyof typeof gapObj; 32 | -------------------------------------------------------------------------------- /src/components/ui/Badge/Badge.tsx: -------------------------------------------------------------------------------- 1 | import { cva, type VariantProps } from "class-variance-authority"; 2 | import { cn } from "@Utils/className"; 3 | 4 | const badgeVariants = cva("base-badge", { 5 | variants: { 6 | variant: { 7 | default: "default-badge", 8 | secondary: "secondary-badge", 9 | destructive: "destructive-badge", 10 | outline: "outline-badge", 11 | }, 12 | }, 13 | defaultVariants: { 14 | variant: "default", 15 | }, 16 | }); 17 | 18 | export interface BadgeProps 19 | extends React.HTMLAttributes, 20 | VariantProps {} 21 | 22 | const Badge = ({ className, variant, ...props }: BadgeProps) => ( 23 |
24 | ); 25 | 26 | export { Badge }; 27 | -------------------------------------------------------------------------------- /src/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | export { Block } from "./Block"; 2 | export { Container } from "./Container"; 3 | export { Flex } from "./Flex"; 4 | export { Grid, GridItem } from "./Grid"; 5 | export { Typography } from "./Typography"; 6 | export { Model } from "./Model"; 7 | export { Button } from "./Button"; 8 | export { Accordion } from "./Accordion"; 9 | export { ConfirmationDialog } from "./ConfirmationDialog"; 10 | export { Avatar } from "./Avatar"; 11 | export { Badge } from "./Badge"; 12 | export { Breadcrumb } from "./Breadcrumb"; 13 | export { Checkbox } from "./CheckBox"; 14 | export { ContextMenu } from "./ContextMenu"; 15 | export { Tooltip } from "./ToolTip"; 16 | export { HoverCard } from "./HoverCard"; 17 | export { Skeleton } from "./Skeleton"; 18 | export { Separator } from "./Separator"; 19 | export { DropdownMenu } from "./DropDownMenu"; 20 | -------------------------------------------------------------------------------- /src/components/ui/CheckBox/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; 2 | import { Check } from "lucide-react"; 3 | import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; 4 | import { cn } from "@Utils/className"; 5 | 6 | const Checkbox = forwardRef< 7 | ElementRef, 8 | ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 15 | 16 | 17 | 18 | 19 | )); 20 | Checkbox.displayName = CheckboxPrimitive.Root.displayName; 21 | 22 | export { Checkbox }; 23 | -------------------------------------------------------------------------------- /src/components/shared/Label/Label.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as LabelPrimitive from "@radix-ui/react-label"; 4 | import { cva, type VariantProps } from "class-variance-authority"; 5 | import * as React from "react"; 6 | import { cn } from "@Utils/className"; 7 | 8 | const labelVariants = cva( 9 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 10 | ); 11 | 12 | const Label = React.forwardRef< 13 | React.ElementRef, 14 | React.ComponentPropsWithoutRef & 15 | VariantProps 16 | >(({ className, ...props }, ref) => ( 17 | 22 | )); 23 | Label.displayName = LabelPrimitive.Root.displayName; 24 | 25 | export { Label }; 26 | -------------------------------------------------------------------------------- /src/components/ui/Separator/Separator.tsx: -------------------------------------------------------------------------------- 1 | import * as SeparatorPrimitive from "@radix-ui/react-separator"; 2 | import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; 3 | import { cn } from "@Utils/className"; 4 | 5 | const Separator = forwardRef< 6 | ElementRef, 7 | ComponentPropsWithoutRef 8 | >( 9 | ( 10 | { className, orientation = "horizontal", decorative = true, ...props }, 11 | ref 12 | ) => ( 13 | 26 | ) 27 | ); 28 | Separator.displayName = SeparatorPrimitive.Root.displayName; 29 | 30 | export { Separator }; 31 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react-swc"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), tsconfigPaths()], 8 | resolve: { 9 | alias: { 10 | // assets 11 | "@Fonts/*": "./src/assets/fonts/*", 12 | "@Styles/*": "./src/assets/styles/*", 13 | "@Svg/*": "./src/assets/svg/*", 14 | 15 | // components 16 | "@Hooks/*": "./src/components/hooks/*", 17 | "@Shared/*": "./src/components/shared/*", 18 | "@UI/*": "./src/components/ui/**", 19 | "@config/*": "./src/components/config/*", 20 | 21 | "@Components/*": "./src/components/*", 22 | 23 | // Higher order components 24 | "@HOC/*": "./src/hoc/*", 25 | 26 | // utils 27 | "@Utils/*": "./src/utils/*", 28 | 29 | // types 30 | "@AppTypes/*": "./src/@types/*", 31 | }, 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /src/components/config/ui/asElement/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Layout component types 4 | * 5 | */ 6 | 7 | import { AriaRole, HtmlHTMLAttributes, ReactNode } from "react"; 8 | import { type ColorVariantsType } from "@Components/config"; 9 | import { ClassType } from "@Utils/className"; 10 | import { type AsElementType, type ElementTypeMap } from "./asElement"; 11 | 12 | interface P { 13 | children: ReactNode; 14 | className?: ClassType; 15 | asElement?: AsElementType; 16 | id?: string; 17 | ariaLabel?: string; 18 | ariaDescribedBy?: string; 19 | ariaLive?: "off" | "polite" | "assertive"; 20 | role?: AriaRole; 21 | border?: boolean; 22 | BackgroundColor?: ColorVariantsType; 23 | } 24 | 25 | type CommonProps = P; 26 | 27 | type CommonPropsExtendedHtmlAttribute = P & 28 | HtmlHTMLAttributes; 29 | 30 | export * from "./asElement"; 31 | export { type CommonProps, type CommonPropsExtendedHtmlAttribute }; 32 | -------------------------------------------------------------------------------- /src/components/ui/Block/Block.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react"; 2 | import { AnyType } from "@AppTypes/commonTypes"; 3 | import { CommonProps } from "@Components/config"; 4 | import { cn } from "@Utils/className"; 5 | 6 | type BlockProps = CommonProps<"block"> & object; 7 | 8 | const Block = forwardRef( 9 | ( 10 | { 11 | children, 12 | className, 13 | id, 14 | ariaLabel, 15 | ariaDescribedBy, 16 | ariaLive, 17 | role, 18 | asElement: Element = "div", 19 | border, 20 | ...rest 21 | }: BlockProps, 22 | ref 23 | ): JSX.Element => ( 24 | 34 | {children} 35 | 36 | ) 37 | ); 38 | 39 | Block.displayName = "Block"; 40 | export { type BlockProps, Block }; 41 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ```mermaid 2 | graph TD 3 | A[Types] 4 | A1[asContainerType] 5 | A2[asFlexType] 6 | A3[asBlockType] 7 | A4[asGridType] 8 | A5[asGridItemType] 9 | A6[asHeadingType] 10 | A7[asTextType] 11 | A8[asTypographyType] 12 | B[ElementTypeMap] 13 | B1[container: asContainerType] 14 | B2[flex: asFlexType] 15 | B3[block: asBlockType] 16 | B4[Grid: asGridType] 17 | B5[Typography: asTypographyType] 18 | B6[GridItem: asGridItemType] 19 | C[Type Utilities] 20 | C1[AsElementType] 21 | C2[ElementTypeMapKeys] 22 | C3[ElementKeysTypeUnion] 23 | C4[AllElementTypes] 24 | 25 | A --> A1 26 | A --> A2 27 | A --> A3 28 | A --> A4 29 | A --> A5 30 | A --> A6 31 | A --> A7 32 | A --> A8 33 | 34 | B --> B1 35 | B --> B2 36 | B --> B3 37 | B --> B4 38 | B --> B5 39 | B --> B6 40 | 41 | C --> C1 42 | C --> C2 43 | C --> C3 44 | C --> C4 45 | 46 | A --> B 47 | B --> C1 48 | C1 --> C2 49 | C2 --> C3 50 | C3 --> C4 51 | ``` 52 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Deepak Mandal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/ui/Container/Container.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react"; 2 | import { AnyType } from "@AppTypes/commonTypes"; 3 | import { CommonProps } from "@Components/config"; 4 | import { cn } from "@Utils/className"; 5 | 6 | type ContainerProps = Omit, "BackgroundColor"> & { 7 | ScreenType: "container" | "full-screen"; 8 | fullHeight?: boolean; 9 | }; 10 | 11 | const Container = forwardRef( 12 | ( 13 | { 14 | children, 15 | asElement: Element = "main", 16 | className, 17 | role, 18 | ScreenType = "container", 19 | border, 20 | fullHeight, 21 | ...rest 22 | }: ContainerProps, 23 | ref 24 | ): JSX.Element => ( 25 | 37 | {children} 38 | 39 | ) 40 | ); 41 | 42 | Container.displayName = "Container"; 43 | 44 | export { type ContainerProps, Container }; 45 | -------------------------------------------------------------------------------- /src/assets/styles/Button/index.css: -------------------------------------------------------------------------------- 1 | .base-button { 2 | @apply inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50; 3 | } 4 | 5 | .default-button { 6 | @apply text-heading-dark bg-primary hover:bg-primary/80; 7 | } 8 | 9 | .destructive-button { 10 | @apply bg-destructive text-heading-dark hover:bg-destructive/80; 11 | } 12 | 13 | .outline-button { 14 | @apply border border-input text-heading bg-transparent hover:bg-secondary; 15 | } 16 | 17 | .ghost-button { 18 | @apply bg-transparent text-heading hover:bg-secondary/55 dark:hover:bg-secondary-dark/55; 19 | } 20 | 21 | .secondary-button { 22 | @apply bg-secondary text-heading hover:bg-secondary/80; 23 | } 24 | 25 | .button-link { 26 | @apply text-primary underline-offset-4 hover:underline; 27 | } 28 | 29 | .button-default-size { 30 | @apply h-10 px-5 py-2; 31 | } 32 | .button-small-size { 33 | @apply h-9 rounded-md px-2; 34 | } 35 | 36 | .button-large-size { 37 | @apply h-11 rounded-md px-7; 38 | } 39 | 40 | .button-icon { 41 | @apply h-10 w-10; 42 | } 43 | -------------------------------------------------------------------------------- /src/components/ui/HoverCard/HoverCard.tsx: -------------------------------------------------------------------------------- 1 | import * as HoverCardPrimitive from "@radix-ui/react-hover-card"; 2 | import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; 3 | import { cn } from "@Utils/className"; 4 | 5 | interface HoverCardProps extends HoverCardPrimitive.HoverCardProps { 6 | Trigger?: typeof HoverCardPrimitive.Trigger; 7 | Content?: typeof HoverCardPrimitive.Content; 8 | } 9 | 10 | const HoverCard = ({ children }: HoverCardProps) => ( 11 | {children} 12 | ); 13 | 14 | const HoverCardTrigger = HoverCardPrimitive.Trigger; 15 | 16 | const HoverCardContent = forwardRef< 17 | ElementRef, 18 | ComponentPropsWithoutRef 19 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 20 | 27 | )); 28 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName; 29 | 30 | HoverCard.Trigger = HoverCardTrigger; 31 | HoverCard.Content = HoverCardContent; 32 | 33 | export { HoverCard }; 34 | -------------------------------------------------------------------------------- /src/components/ui/ToolTip/ToolTip.tsx: -------------------------------------------------------------------------------- 1 | import * as TooltipPrimitive from "@radix-ui/react-tooltip"; 2 | import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; 3 | import { cn } from "@Utils/className"; 4 | 5 | interface TooltipProps extends TooltipPrimitive.TooltipProps { 6 | Trigger?: typeof TooltipTrigger; 7 | Content?: typeof TooltipContent; 8 | Provider?: typeof TooltipProvider; 9 | } 10 | 11 | const Tooltip = ({ children, ...rest }: TooltipProps) => ( 12 | {children} 13 | ); 14 | 15 | const TooltipProvider = TooltipPrimitive.Provider; 16 | const TooltipTrigger = TooltipPrimitive.Trigger; 17 | 18 | const TooltipContent = forwardRef< 19 | ElementRef, 20 | ComponentPropsWithoutRef 21 | >(({ className, sideOffset = 4, ...props }, ref) => ( 22 | 28 | )); 29 | TooltipContent.displayName = TooltipPrimitive.Content.displayName; 30 | 31 | Tooltip.Trigger = TooltipTrigger; 32 | Tooltip.Content = TooltipContent; 33 | Tooltip.Provider = TooltipProvider; 34 | 35 | export { Tooltip }; 36 | -------------------------------------------------------------------------------- /src/components/config/ui/asElement/asElement.ts: -------------------------------------------------------------------------------- 1 | type asContainerType = "header" | "footer" | "nav" | "main"; 2 | type asFlexType = "div" | "section" | "article" | "aside"; 3 | type asBlockType = "div" | "section" | "article" | "aside"; 4 | type asGridType = "div" | "section" | "article" | "aside"; 5 | type asGridItemType = "div"; 6 | type asHeadingType = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; 7 | 8 | type asTextType = "p" | "span" | "strong"; 9 | 10 | type asTypographyType = asHeadingType | asTextType; 11 | 12 | type ElementTypeMap = { 13 | container: asContainerType; 14 | flex: asFlexType; 15 | block: asBlockType; 16 | Grid: asGridType; 17 | Typography: asTypographyType; 18 | GridItem: asGridItemType; 19 | }; 20 | type AsElementType = ElementTypeMap[T]; 21 | type ElementTypeMapKeys = keyof ElementTypeMap; 22 | type ElementKeysTypeUnion = ElementTypeMap[ElementTypeMapKeys]; 23 | type AllElementTypes = AsElementType; 24 | 25 | export { 26 | type asContainerType, 27 | type asFlexType, 28 | type asBlockType, 29 | type asGridType, 30 | type asGridItemType, 31 | type asTypographyType, 32 | type asHeadingType, 33 | type asTextType, 34 | 35 | // Element type map 36 | type ElementTypeMap, 37 | type AsElementType, 38 | type ElementKeysTypeUnion, 39 | type AllElementTypes, 40 | }; 41 | -------------------------------------------------------------------------------- /src/assets/styles/model/index.css: -------------------------------------------------------------------------------- 1 | @layer utilities { 2 | .model-overlay { 3 | @apply bg-model-overlay/75; 4 | position: fixed; 5 | width: 100vw; 6 | height: 100vh; 7 | inset: 0; 8 | animation: overlayShow 150ms cubic-bezier(0.16, 1, 0.3, 1); 9 | } 10 | 11 | .model-content { 12 | border-radius: 6px; 13 | box-shadow: 14 | hsl(206 22% 7% / 35%) 0px 10px 38px -10px, 15 | hsl(206 22% 7% / 20%) 0px 10px 20px -15px; 16 | position: fixed; 17 | top: 50%; 18 | left: 50%; 19 | transform: translate(-50%, -50%); 20 | width: 90vw; 21 | max-width: 450px; 22 | max-height: 85vh; 23 | padding: 25px; 24 | animation: contentShow 150ms cubic-bezier(0.16, 1, 0.3, 1); 25 | outline: none; 26 | } 27 | 28 | .model-title { 29 | margin: 0; 30 | font-weight: 500; 31 | font-size: 17px; 32 | } 33 | 34 | .model-description { 35 | margin: 10px 0 20px; 36 | font-size: 15px; 37 | line-height: 1.5; 38 | } 39 | 40 | @keyframes overlayShow { 41 | from { 42 | opacity: 0; 43 | } 44 | to { 45 | opacity: 1; 46 | } 47 | } 48 | 49 | @keyframes contentShow { 50 | from { 51 | opacity: 0; 52 | transform: translate(-50%, -45%) scale(0.9); 53 | } 54 | to { 55 | opacity: 1; 56 | transform: translate(-50%, -50%) scale(1); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/components/ui/Typography/utils/TypographyClasses.ts: -------------------------------------------------------------------------------- 1 | import { ColorVariantsType, asTypographyType } from "@Components/config"; 2 | import { ClassType } from "@Utils/className"; 3 | 4 | type asElementObjectType = { 5 | // eslint-disable-next-line no-unused-vars 6 | [key in asTypographyType]: ClassType; 7 | }; 8 | 9 | const asElementObject: asElementObjectType = { 10 | h1: "h1", 11 | h2: "h2", 12 | h3: "h3", 13 | h4: "h4", 14 | h5: "h5", 15 | h6: "h6", 16 | p: "p", 17 | span: "span", 18 | strong: "strong", 19 | } as const; 20 | 21 | type Variants = Exclude; 22 | 23 | const HeadingVariants: Record = { 24 | default: "header-default-variant", 25 | accent: "header-accent-variant", 26 | destructive: "header-destructive-variant", 27 | muted: "header-muted-variant", 28 | primary: "header-primary-variant", 29 | secondary: "header-secondary-variant", 30 | } as const; 31 | 32 | const TextVariants: Record = { 33 | default: "text-default-variant", 34 | accent: "text-accent-variant", 35 | destructive: "text-destructive-variant", 36 | muted: "text-muted-variant", 37 | primary: "text-primary-variant", 38 | secondary: "text-secondary-variant", 39 | } as const; 40 | 41 | export { 42 | type asElementObjectType, 43 | asElementObject, 44 | HeadingVariants, 45 | TextVariants, 46 | }; 47 | -------------------------------------------------------------------------------- /src/components/ui/Typography/Typography.tsx: -------------------------------------------------------------------------------- 1 | import { ColorVariantsType, CommonProps } from "@Components/config"; 2 | import { cn } from "@Utils/className"; 3 | import { 4 | HeadingVariants, 5 | TextVariants, 6 | asElementObject, 7 | } from "./utils/TypographyClasses"; 8 | 9 | type variantsType = ColorVariantsType; 10 | 11 | type TypographyProps = Omit, "BackgroundColor"> & { 12 | variants?: variantsType; 13 | }; 14 | 15 | const isHeading = (T: string) => 16 | ["h1", "h2", "h3", "h4", "h5", "h6"].includes(T); 17 | 18 | const Typography = ({ 19 | children, 20 | className, 21 | id, 22 | ariaLabel, 23 | ariaDescribedBy, 24 | ariaLive, 25 | role, 26 | asElement: Element = "span", 27 | border, 28 | variants = "default", 29 | ...rest 30 | }: TypographyProps): JSX.Element => ( 31 | 48 | {children} 49 | 50 | ); 51 | 52 | export { type TypographyProps, Typography }; 53 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/className/index.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | /** 5 | * Combines multiple class names into a single string, merging Tailwind CSS 6 | * classes intelligently to avoid conflicts and redundant styles. 7 | * 8 | * This utility function leverages `clsx` to conditionally combine class names 9 | * and `tailwind-merge` to merge Tailwind CSS classes correctly. It is particularly 10 | * useful in React components where class names need to be dynamically generated 11 | * based on props or state. 12 | * 13 | * @param {...ClassValue[]} inputs - An array of class values which can be strings, 14 | * arrays, or objects with boolean keys indicating whether a class should be included. 15 | * 16 | * @returns {string} A single string of merged class names. 17 | * 18 | * @example 19 | * // Basic usage with string literals 20 | * const className = cn('bg-red-500', 'text-white'); 21 | * 22 | * @example 23 | * // Conditional class names 24 | * const isActive = true; 25 | * const className = cn('bg-red-500', { 'text-white': isActive }); 26 | * 27 | * @example 28 | * // Combining arrays of class names 29 | * const baseClasses = ['p-4', 'rounded']; 30 | * const additionalClasses = ['hover:bg-red-700', 'focus:outline-none']; 31 | * const className = cn(baseClasses, additionalClasses); 32 | */ 33 | const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); 34 | 35 | export { type ClassValue as ClassType, cn }; 36 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | If you discover a security vulnerability within this repository, we encourage you to report it as soon as possible to help us address the issue promptly. 6 | 7 | ### How to Report 8 | 9 | 1. **Raise an Issue**: Go to the [Issues](https://github.com/your-repo/issues) section of this repository. 10 | 2. **Title**: Use a clear and descriptive title such as "Security Vulnerability Report". 11 | 3. **Description**: Provide a detailed description of the vulnerability including: 12 | - Steps to reproduce the issue. 13 | - The potential impact of the vulnerability. 14 | - Any relevant details or context that can help us understand the issue better. 15 | 16 | ### What to Expect 17 | 18 | - **Acknowledgment**: We will acknowledge receipt of your vulnerability report within 48 hours. 19 | - **Assessment**: We will assess the report and determine the severity and impact. 20 | - **Resolution**: We will work on fixing the vulnerability as soon as possible. Depending on the complexity, this might take some time. 21 | - **Notification**: We will notify you once the vulnerability has been resolved. 22 | 23 | ## Responsible Disclosure Policy 24 | 25 | To ensure the protection of our users, we kindly request that you: 26 | 27 | - Allow us a reasonable time to fix the vulnerability before making any details public. 28 | - Avoid exploiting the vulnerability in any way. 29 | - Provide us with sufficient details to understand and resolve the issue effectively. 30 | 31 | Thank you for helping us keep our project secure! 32 | -------------------------------------------------------------------------------- /src/assets/styles/Typography/index.css: -------------------------------------------------------------------------------- 1 | .h1 { 2 | @apply text-4xl font-extrabold leading-tight tracking-tight; 3 | } 4 | 5 | .h2 { 6 | @apply text-3xl font-bold leading-snug tracking-tight; 7 | } 8 | 9 | .h3 { 10 | @apply text-2xl font-semibold leading-normal tracking-tight; 11 | } 12 | .h4 { 13 | @apply text-xl font-medium leading-normal tracking-tight; 14 | } 15 | .h5 { 16 | @apply text-lg font-medium leading-snug tracking-tight; 17 | } 18 | .h6 { 19 | @apply text-base font-medium leading-snug tracking-tight; 20 | } 21 | 22 | .p { 23 | @apply text-base font-normal leading-normal tracking-normal; 24 | } 25 | 26 | .span { 27 | @apply text-base font-normal leading-normal tracking-normal; 28 | } 29 | 30 | .strong { 31 | @apply text-base font-semibold leading-normal tracking-normal; 32 | } 33 | 34 | .header-default-variant { 35 | @apply text-heading; 36 | } 37 | .header-accent-variant { 38 | @apply text-accent; 39 | } 40 | .header-destructive-variant { 41 | @apply text-destructive; 42 | } 43 | .header-muted-variant { 44 | @apply text-muted; 45 | } 46 | .header-primary-variant { 47 | @apply text-primary; 48 | } 49 | .header-secondary-variant { 50 | @apply text-secondary; 51 | } 52 | 53 | .text-default-variant { 54 | @apply text-text; 55 | } 56 | .text-accent-variant { 57 | @apply text-accent; 58 | } 59 | .text-destructive-variant { 60 | @apply text-destructive; 61 | } 62 | .text-muted-variant { 63 | @apply text-muted; 64 | } 65 | .text-primary-variant { 66 | @apply text-primary; 67 | } 68 | .text-secondary-variant { 69 | @apply text-secondary; 70 | } 71 | -------------------------------------------------------------------------------- /src/assets/styles/context-menu/index.css: -------------------------------------------------------------------------------- 1 | /* .context-menu-content { 2 | @apply min-w-[220px] 3 | bg-white 4 | rounded-md 5 | overflow-hidden 6 | p-[5px] 7 | shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)]; 8 | } 9 | 10 | .context-menu-item { 11 | @apply group 12 | text-[13px] 13 | leading-none 14 | text-violet11 15 | rounded-[3px] 16 | flex 17 | items-center 18 | h-[25px] 19 | px-[5px] 20 | relative 21 | pl-[25px] 22 | select-none 23 | outline-none 24 | data-[disabled]:text-mauve8 25 | data-[disabled]:pointer-events-none 26 | data-[highlighted]:bg-violet9 27 | data-[highlighted]:text-violet1; 28 | } 29 | 30 | .context-menu-subTrigger { 31 | @apply group 32 | text-[13px] 33 | leading-none 34 | text-violet11 35 | rounded-[3px] 36 | flex 37 | items-center 38 | h-[25px] 39 | px-[5px] 40 | relative 41 | pl-[25px] 42 | select-none 43 | outline-none 44 | data-[state=open]:bg-violet4 45 | data-[state=open]:text-violet11 46 | data-[disabled]:text-mauve8 47 | data-[disabled]:pointer-events-none 48 | data-[highlighted]:bg-violet9 49 | data-[highlighted]:text-violet1 50 | data-[highlighted]:data-[state=open]:bg-violet9 51 | data-[highlighted]:data-[state=open]:text-violet1; 52 | } 53 | 54 | .context-menu-subContent { 55 | @apply min-w-[220px] 56 | bg-white 57 | rounded-md 58 | overflow-hidden 59 | p-[5px] 60 | shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)]; 61 | } 62 | 63 | .context-menu-separator { 64 | @apply h-[1px] bg-violet6 m-[5px]; 65 | } */ 66 | -------------------------------------------------------------------------------- /src/components/ui/Grid/Grid.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react"; 2 | import { AnyType } from "@AppTypes/commonTypes"; 3 | import { CommonProps } from "@Components/config"; 4 | import { ClassType, cn } from "@Utils/className"; 5 | import { 6 | gridColumnsObj, 7 | gapObj, 8 | GridColumnsType, 9 | GapType, 10 | } from "./utils/style-object"; 11 | import { color } from "../Common/colors-blocks"; 12 | 13 | type GridProps = CommonProps<"Grid"> & { 14 | columns: GridColumnsType; 15 | gap?: GapType; 16 | gridLines?: boolean; 17 | // aspectRatio 18 | }; 19 | 20 | const Grid = forwardRef( 21 | ( 22 | { 23 | children, 24 | className, 25 | id, 26 | ariaLabel, 27 | ariaDescribedBy, 28 | ariaLive, 29 | role, 30 | asElement: Element = "div", 31 | columns, 32 | gap = "0", 33 | border, 34 | gridLines, 35 | BackgroundColor = "default", 36 | ...rest 37 | }: GridProps, 38 | ref 39 | ): JSX.Element => ( 40 | 58 | {children} 59 | 60 | ) 61 | ); 62 | 63 | Grid.displayName = "Grid"; 64 | export { type GridProps, Grid }; 65 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 8 | "module": "ESNext", 9 | "skipLibCheck": true, 10 | 11 | /* Bundler mode */ 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "moduleDetection": "force", 17 | "noEmit": true, 18 | "jsx": "react-jsx", 19 | 20 | /* Linting */ 21 | "strict": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true, 25 | 26 | // paths 27 | "paths": { 28 | // "@/*": ["./src/*"], 29 | // assets 30 | "@Fonts/*": ["./src/assets/fonts/*"], 31 | "@Styles/*": ["./src/assets/styles/*"], 32 | "@Svg/*": ["./src/assets/svg/*"], 33 | 34 | // components 35 | // "@Hooks/*": ["./src/components/hooks/*"], 36 | // "@Shared/*": ["./src/components/shared/*"], 37 | // "@UI/*": ["./src/components/ui/*"], 38 | // "@Config/*": ["./src/components/config/*"], 39 | 40 | "@Components/*": ["./src/components/*"], 41 | 42 | // Higher order components 43 | "@HOC/*": ["./src/hoc/*"], 44 | 45 | // utils 46 | "@Utils/*": ["./src/utils/*"], 47 | 48 | // types 49 | "@AppTypes/*": ["./src/@types/*"] 50 | } 51 | }, 52 | "include": ["src", "tailwind.config.js", "postcss.config.js"], 53 | "exclude": ["node_modules"], 54 | "files": [], 55 | "references": [ 56 | { 57 | "path": "./tsconfig.node.json" 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /src/components/ui/Grid/GridItem/index.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react"; 2 | import { AnyType } from "@AppTypes/commonTypes"; 3 | import { CommonProps } from "@Components/config"; 4 | import { color } from "@Components/ui/Common/colors-blocks"; 5 | import { type ClassType, cn } from "@Utils/className"; 6 | 7 | // type GridItemProps = { 8 | // children: ReactNode; 9 | // className?: ClassType; 10 | // id?: string; 11 | // ariaLabel?: string; 12 | // ariaDescribedBy?: string; 13 | // ariaLive?: "off" | "polite" | "assertive"; 14 | // role?: AriaRole; 15 | // border?: boolean; 16 | // }; 17 | type GridItemProps = CommonProps<"GridItem"> & object; 18 | 19 | /** 20 | * GridItem component for individual grid items. 21 | * 22 | * @param {GridItemProps} props - The props for the GridItem component. 23 | * @returns {JSX.Element} The rendered grid item component. 24 | */ 25 | const GridItem = forwardRef( 26 | ( 27 | { 28 | children, 29 | className, 30 | id, 31 | ariaLabel, 32 | ariaDescribedBy, 33 | ariaLive, 34 | role = "region", 35 | BackgroundColor = "default", 36 | border, 37 | ...rest 38 | }: GridItemProps, 39 | ref 40 | ): JSX.Element => ( 41 |
55 | {children} 56 |
57 | ) 58 | ); 59 | 60 | GridItem.displayName = "GridItem"; 61 | 62 | export { type GridItemProps, GridItem }; 63 | -------------------------------------------------------------------------------- /src/components/ui/Button/button.tsx: -------------------------------------------------------------------------------- 1 | import { Slot } from "@radix-ui/react-slot"; 2 | import { type VariantProps } from "class-variance-authority"; 3 | import { Loader } from "lucide-react"; 4 | import { forwardRef, ReactNode } from "react"; 5 | import { cn } from "@Utils/className"; 6 | import { buttonVariants } from "./utils/ButtonVariants"; 7 | 8 | type Direction = "ltr" | "rtl"; 9 | 10 | interface ButtonProps 11 | extends React.ButtonHTMLAttributes, 12 | VariantProps { 13 | asChild?: boolean; 14 | loading?: boolean; 15 | withIcon?: ReactNode | string | undefined; 16 | dir?: Direction; 17 | } 18 | 19 | const Button = forwardRef( 20 | ( 21 | { 22 | children, 23 | loading = false, 24 | dir = "ltr", 25 | withIcon, 26 | className, 27 | variant, 28 | size, 29 | asChild = false, 30 | ...props 31 | }, 32 | ref 33 | ) => { 34 | const Comp = asChild ? Slot : "button"; 35 | 36 | return ( 37 | 42 | {dir == "ltr" ? ( 43 | withIcon ? ( 44 | withIcon 45 | ) : loading ? ( 46 | 47 | ) : null 48 | ) : null} 49 | 50 | {children} 51 | 52 | {dir == "rtl" ? ( 53 | withIcon ? ( 54 | withIcon 55 | ) : loading ? ( 56 | 57 | ) : null 58 | ) : null} 59 | 60 | ); 61 | } 62 | ); 63 | Button.displayName = "Button"; 64 | 65 | export { Button, type ButtonProps }; 66 | -------------------------------------------------------------------------------- /src/components/ui/Avatar/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import * as RadixAvatar from "@radix-ui/react-avatar"; 2 | import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; 3 | import { cn } from "@Utils/className"; 4 | 5 | const Avatar = forwardRef< 6 | ElementRef, 7 | ComponentPropsWithoutRef 8 | >(({ className, ...props }, ref) => ( 9 | 10 | )); 11 | Avatar.displayName = RadixAvatar.Root.displayName; 12 | 13 | const AvatarImage = forwardRef< 14 | ElementRef, 15 | ComponentPropsWithoutRef 16 | >(({ className, ...props }, ref) => ( 17 | 22 | )); 23 | AvatarImage.displayName = RadixAvatar.Image.displayName; 24 | 25 | const AvatarFallback = forwardRef< 26 | ElementRef, 27 | ComponentPropsWithoutRef 28 | >(({ className, ...props }, ref) => ( 29 | 34 | )); 35 | AvatarFallback.displayName = RadixAvatar.Fallback.displayName; 36 | 37 | interface AvatarComponent 38 | extends React.ForwardRefExoticComponent< 39 | ComponentPropsWithoutRef & 40 | React.RefAttributes> 41 | > { 42 | Image: typeof AvatarImage; 43 | Fallback: typeof AvatarFallback; 44 | } 45 | 46 | const AvatarWithComponents = Avatar as AvatarComponent; 47 | AvatarWithComponents.Image = AvatarImage; 48 | AvatarWithComponents.Fallback = AvatarFallback; 49 | 50 | export { AvatarWithComponents as Avatar }; 51 | -------------------------------------------------------------------------------- /src/components/HOC/theme/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useEffect, useState } from "react"; 2 | 3 | type Theme = "dark" | "light" | "system"; 4 | 5 | type ThemeProviderProps = { 6 | children: React.ReactNode; 7 | defaultTheme?: Theme; 8 | storageKey?: string; 9 | }; 10 | 11 | type ThemeProviderState = { 12 | theme: Theme; 13 | // eslint-disable-next-line no-unused-vars 14 | setTheme: (theme: Theme) => void; 15 | }; 16 | 17 | const initialState: ThemeProviderState = { 18 | theme: "system", 19 | setTheme: () => null, 20 | }; 21 | 22 | const ThemeProviderContext = createContext(initialState); 23 | 24 | const ThemeProvider = ({ 25 | children, 26 | defaultTheme = "system", 27 | storageKey = "vite-ui-theme", 28 | ...props 29 | }: ThemeProviderProps) => { 30 | const [theme, setTheme] = useState( 31 | // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition 32 | () => (localStorage.getItem(storageKey) as Theme) || defaultTheme 33 | ); 34 | 35 | useEffect(() => { 36 | const root = window.document.documentElement; 37 | 38 | root.classList.remove("light", "dark"); 39 | 40 | if (theme === "system") { 41 | const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") 42 | .matches 43 | ? "dark" 44 | : "light"; 45 | 46 | root.classList.add(systemTheme); 47 | return; 48 | } 49 | 50 | root.classList.add(theme); 51 | }, [theme]); 52 | 53 | const value = { 54 | theme, 55 | setTheme: (data: Theme) => { 56 | localStorage.setItem(storageKey, data); 57 | setTheme(data); 58 | }, 59 | }; 60 | 61 | return ( 62 | 63 | {children} 64 | 65 | ); 66 | }; 67 | 68 | export { ThemeProvider, ThemeProviderContext }; 69 | -------------------------------------------------------------------------------- /src/components/ui/ConfirmationDialog/ConfirmationDialog.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "../Button"; 2 | import { Model } from "../Model"; 3 | import { Typography } from "../Typography"; 4 | 5 | interface ConfirmationDialogProps { 6 | title?: string; 7 | body?: string; 8 | model?: boolean; 9 | open?: boolean; 10 | onOpenChange?: () => void; 11 | handleConfirm: () => void; 12 | handleCancel: () => void; 13 | } 14 | 15 | const ConfirmationDialog = ({ 16 | title, 17 | body, 18 | model, 19 | open, 20 | onOpenChange, 21 | handleCancel, 22 | handleConfirm, 23 | }: ConfirmationDialogProps) => ( 24 | 25 | 26 | 27 | 28 | 29 | {title ?? "Delete Item"} 30 | 31 | 32 | 33 | 34 | 35 | {body ?? "Are you sure you want to delete this item?"} 36 | 37 | 38 | 39 | 40 | 41 | 48 | 49 | 50 | 57 | 58 | 59 | 60 | 61 | ); 62 | export { ConfirmationDialog }; 63 | -------------------------------------------------------------------------------- /src/components/ui/Flex/Flex.tsx: -------------------------------------------------------------------------------- 1 | import { AriaRole, forwardRef } from "react"; 2 | import { AnyType } from "@AppTypes/commonTypes"; 3 | import { CommonProps } from "@Components/config"; 4 | import { type ClassType, cn } from "@Utils/className"; 5 | import { 6 | FlexDirectionType, 7 | FlexElementType, 8 | AlignContentType, 9 | AlignItemsType, 10 | JustifyContentType, 11 | alignContentObj, 12 | alignItemsObj, 13 | directionObj, 14 | justifyObj, 15 | } from "./utils/style-object"; 16 | import { color } from "../Common/colors-blocks"; 17 | 18 | type FlexProps = CommonProps<"flex"> & { 19 | flexDirection?: FlexDirectionType; 20 | justifyContent?: JustifyContentType; 21 | alignItems?: AlignItemsType; 22 | alignContent?: AlignContentType; 23 | }; 24 | 25 | const Flex = forwardRef( 26 | ( 27 | { 28 | children, 29 | className, 30 | id, 31 | ariaLabel, 32 | ariaDescribedBy, 33 | ariaLive, 34 | role, 35 | asElement: Element = "div", 36 | flexDirection = "row", 37 | justifyContent = "flex-start", 38 | alignItems = "flex-start", 39 | alignContent = "flex-start", 40 | BackgroundColor = "default", 41 | border, 42 | ...rest 43 | }: FlexProps, 44 | ref 45 | ): JSX.Element => ( 46 | 67 | {children} 68 | 69 | ) 70 | ); 71 | 72 | Flex.displayName = "Flex"; 73 | 74 | export { 75 | Flex, 76 | type FlexProps, 77 | type AlignContentType, 78 | type AlignItemsType, 79 | type AriaRole, 80 | type FlexDirectionType, 81 | type FlexElementType, 82 | type JustifyContentType, 83 | }; 84 | -------------------------------------------------------------------------------- /src/components/ui/Flex/utils/style-object.ts: -------------------------------------------------------------------------------- 1 | type FlexElementType = "div" | "section" | "article" | "aside"; 2 | type JustifyContentType = 3 | | "flex-start" 4 | | "flex-end" 5 | | "center" 6 | | "space-between" 7 | | "space-around" 8 | | "space-evenly"; 9 | type FlexDirectionType = "row" | "row-reverse" | "column" | "column-reverse"; 10 | type AlignItemsType = 11 | | "flex-start" 12 | | "flex-end" 13 | | "center" 14 | | "baseline" 15 | | "stretch"; 16 | 17 | type AlignContentType = 18 | | "flex-start" 19 | | "flex-end" 20 | | "center" 21 | | "space-between" 22 | | "space-around" 23 | | "stretch"; 24 | 25 | type justifyProps = { 26 | // eslint-disable-next-line no-unused-vars 27 | [key in JustifyContentType]: string; 28 | }; 29 | 30 | type directionProps = { 31 | // eslint-disable-next-line no-unused-vars 32 | [key in FlexDirectionType]: string; 33 | }; 34 | type alignItemsProps = { 35 | // eslint-disable-next-line no-unused-vars 36 | [key in AlignItemsType]: string; 37 | }; 38 | type AlignContentProps = { 39 | // eslint-disable-next-line no-unused-vars 40 | [key in AlignContentType]: string; 41 | }; 42 | 43 | const justifyObj: justifyProps = { 44 | center: "justify-center", 45 | "flex-end": "justify-end", 46 | "flex-start": "justify-start", 47 | "space-around": "justify-around", 48 | "space-between": "justify-between", 49 | "space-evenly": "justify-evenly", 50 | }; 51 | 52 | const directionObj: directionProps = { 53 | row: "flex-row", 54 | "row-reverse": "flex-row-reverse", 55 | "column-reverse": "flex-col-reverse", 56 | column: "flex-col", 57 | }; 58 | const alignItemsObj: alignItemsProps = { 59 | "flex-end": "items-end", 60 | "flex-start": "items-start", 61 | baseline: "items-baseline", 62 | center: "items-center", 63 | stretch: "items-stretch", 64 | }; 65 | 66 | const alignContentObj: AlignContentProps = { 67 | "flex-end": "content-center", 68 | "flex-start": "content-start", 69 | "space-around": "content-around", 70 | "space-between": "content-between", 71 | center: "content-center", 72 | stretch: "content-stretch", 73 | }; 74 | 75 | export { 76 | justifyObj, 77 | alignContentObj, 78 | type AlignContentType, 79 | type AlignItemsType, 80 | type FlexDirectionType, 81 | type FlexElementType, 82 | type JustifyContentType, 83 | alignItemsObj, 84 | directionObj, 85 | }; 86 | -------------------------------------------------------------------------------- /src/assets/styles/drop-down-menu/index.css: -------------------------------------------------------------------------------- 1 | /* .drop-down-sub-trigger { 2 | @apply flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-secondary/50 data-[state=open]:bg-secondary/50focus:bg-secondary/50; 3 | } 4 | 5 | .drop-down-sub-trigger-icon { 6 | @apply ml-auto h-4 w-4; 7 | } 8 | 9 | .drop-down-sub-content { 10 | @apply z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 text-text shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2; 11 | } 12 | 13 | .drop-down-content { 14 | @apply z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 text-text shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2; 15 | } 16 | 17 | .drop-down-menu-item { 18 | @apply relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-secondary/50 focus:text-text data-[disabled]:pointer-events-none data-[disabled]:opacity-50; 19 | } 20 | 21 | .drop-down-checkbox-item { 22 | @apply relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-secondary/50 focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50; 23 | } 24 | 25 | .drop-down-checkbox-item-span { 26 | @apply absolute left-2 flex h-3.5 w-3.5 items-center justify-center; 27 | } 28 | 29 | .drop-down-checkbox-item-span-icon { 30 | @apply h-4 w-4; 31 | } 32 | 33 | .drop-down-menu-radio-item { 34 | @apply relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-secondary/50 focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50; 35 | } 36 | .drop-down-menu-radio-item-span { 37 | @apply absolute left-2 flex h-3.5 w-3.5 items-center justify-center; 38 | } 39 | .drop-down-menu-radio-item-span-icon { 40 | @apply h-2 w-2 fill-current; 41 | } 42 | 43 | .drop-down-menu-label { 44 | @apply px-2 py-1.5 text-sm font-semibold; 45 | } 46 | 47 | .drop-down-separator { 48 | @apply-mx-1 my-1 h-px bg-muted; 49 | } 50 | 51 | .drop-down-checkbox-shortcut { 52 | @apply ml-auto text-xs tracking-widest opacity-60; 53 | } */ 54 | -------------------------------------------------------------------------------- /src/tailwind.css: -------------------------------------------------------------------------------- 1 | @import "assets/styles/index.css"; /* will look here later */ 2 | 3 | @tailwind base; 4 | @tailwind components; 5 | @tailwind utilities; 6 | 7 | @layer base { 8 | :root { 9 | /* Light theme colors */ 10 | --background-light: 204, 93.8%, 93.7%; 11 | --heading-light: 220.9, 39.3%, 11%; 12 | --text-light: 220.9, 39.3%, 11%; 13 | --accent-light: 0, 62.8%, 30.6%; 14 | --muted-light: 215.3, 19.3%, 34.5%; 15 | --primary-light: 213.1, 93.9%, 67.8%; 16 | --secondary-light: 240, 13%, 91%; 17 | --destructive-light: 0, 84.2%, 60.2%; 18 | --input-light: 216, 12.2%, 83.9%; 19 | --model-overlay-light: 0, 0%, 0%; 20 | --border-light: 240, 5.9%, 90%; 21 | 22 | /* Dark theme colors */ 23 | --background-dark: 222.2, 84%, 4.9%; 24 | --heading-dark: 210, 20%, 98%; 25 | --text-dark: 220, 14.3%, 95.9%; 26 | --accent-dark: 0, 84.2%, 60.2%; 27 | --muted-dark: 215.3, 25%, 26.7%; 28 | --primary-dark: 213.1, 93.9%, 67.8%; 29 | --secondary-dark: 215, 13.8%, 34.1%; 30 | --destructive-dark: 346.8, 77.2%, 49.8%; 31 | --input-dark: 215.3, 25%, 26.7%; 32 | --model-overlay-dark: 0, 0%, 0%; 33 | --border-dark: 240, 3.7%, 15.9%; 34 | 35 | /* Default to light theme values */ 36 | --background: var(--background-light); 37 | --heading: var(--heading-light); 38 | --text: var(--text-light); 39 | --accent: var(--accent-light); 40 | --muted: var(--muted-light); 41 | --primary: var(--primary-light); 42 | --secondary: var(--secondary-light); 43 | --destructive: var(--destructive-light); 44 | --input: var(--input-light); 45 | --model-overlay: var(--model-overlay-light); 46 | --border: var(--border-light); 47 | } 48 | 49 | /* Dark theme overrides */ 50 | .dark { 51 | --background: var(--background-dark); 52 | --heading: var(--heading-dark); 53 | --text: var(--text-dark); 54 | --accent: var(--accent-dark); 55 | --muted: var(--muted-dark); 56 | --primary: var(--primary-dark); 57 | --secondary: var(--secondary-dark); 58 | --destructive: var(--destructive-dark); 59 | --input: var(--input-dark); 60 | --model-overlay: var(--model-overlay-dark); 61 | --border: var(--border-dark); 62 | } 63 | } 64 | 65 | /* 66 | * - notification colors 67 | * - input box colors 68 | * - border 69 | */ 70 | 71 | @layer base { 72 | body { 73 | @apply bg-background; 74 | } 75 | .app-border { 76 | @apply border border-border-red; 77 | } 78 | } 79 | 80 | /* Additional custom styles */ 81 | @layer utilities { 82 | .Hide-Scroll-Track::-webkit-scrollbar { 83 | display: none; 84 | } 85 | .Hide-Scroll-Track { 86 | -ms-overflow-style: none; 87 | } 88 | .gridLines > *, 89 | .gridLines { 90 | @apply border border-dashed border-border-red; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/components/ui/Accordion/Accordion.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | AccordionMultipleProps as _AccordionMultipleProps, 3 | AccordionSingleProps as _AccordionSingleProps, 4 | Content, 5 | Header, 6 | Item, 7 | Root, 8 | Trigger, 9 | } from "@radix-ui/react-accordion"; 10 | import { ChevronDown } from "lucide-react"; 11 | import { 12 | ComponentPropsWithoutRef, 13 | ElementRef, 14 | forwardRef, 15 | ReactNode, 16 | } from "react"; 17 | import { cn } from "@Utils/className"; 18 | 19 | interface AccordionMultipleProps extends _AccordionMultipleProps {} 20 | interface AccordionSingleProps extends _AccordionSingleProps {} 21 | 22 | type AccordionProps = AccordionMultipleProps | AccordionSingleProps; 23 | 24 | const Accordion = ({ children, className, ...rest }: AccordionProps) => ( 25 | 26 | {children} 27 | 28 | ); 29 | 30 | const AccordionItem = forwardRef< 31 | ElementRef, 32 | ComponentPropsWithoutRef 33 | >(({ className, ...props }, ref) => ( 34 | 35 | )); 36 | AccordionItem.displayName = "AccordionItem"; 37 | 38 | interface AccordionTriggerProps 39 | extends ComponentPropsWithoutRef { 40 | icon?: ReactNode; 41 | rotate?: boolean | string; 42 | } 43 | 44 | const AccordionTrigger = forwardRef< 45 | ElementRef, 46 | AccordionTriggerProps 47 | >(({ className, children, icon, rotate = true, ...props }, ref) => ( 48 |
49 | svg]:rotate-180" 56 | : "" 57 | : rotate, 58 | className 59 | )} 60 | {...props} 61 | > 62 | {children} 63 | 64 | {icon || ( 65 | 66 | )} 67 | 68 |
69 | )); 70 | AccordionTrigger.displayName = Trigger.displayName; 71 | 72 | const AccordionContent = forwardRef< 73 | ElementRef, 74 | ComponentPropsWithoutRef 75 | >(({ className, children, ...props }, ref) => ( 76 | 81 |
{children}
82 |
83 | )); 84 | 85 | AccordionContent.displayName = Content.displayName; 86 | 87 | Accordion.Item = AccordionItem; 88 | Accordion.Trigger = AccordionTrigger; 89 | Accordion.Content = AccordionContent; 90 | export { Accordion, type AccordionProps }; 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-template", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview", 11 | "prettier:write": "pnpm exec prettier . --write", 12 | "Prettier:preview": "npx prettier . --check", 13 | "lint-staged": "lint-staged", 14 | "prepare": "husky", 15 | "spellcheck": "cspell src/**/*.{ts,tsx,css} --show-suggestions", 16 | "check-types": "npx tsc --noEmit " 17 | }, 18 | "dependencies": { 19 | "@hookform/resolvers": "^3.9.0", 20 | "@radix-ui/colors": "^3.0.0", 21 | "@radix-ui/react-accordion": "^1.2.0", 22 | "@radix-ui/react-avatar": "^1.1.0", 23 | "@radix-ui/react-checkbox": "^1.1.1", 24 | "@radix-ui/react-context-menu": "^2.2.1", 25 | "@radix-ui/react-dialog": "^1.1.1", 26 | "@radix-ui/react-dropdown-menu": "^2.1.1", 27 | "@radix-ui/react-hover-card": "^1.1.1", 28 | "@radix-ui/react-icons": "^1.3.0", 29 | "@radix-ui/react-label": "^2.1.0", 30 | "@radix-ui/react-separator": "^1.1.0", 31 | "@radix-ui/react-slot": "^1.1.0", 32 | "@radix-ui/react-tooltip": "^1.1.2", 33 | "class-variance-authority": "^0.7.0", 34 | "clsx": "^2.1.1", 35 | "lucide-react": "^0.417.0", 36 | "postcss-import": "^16.1.0", 37 | "prettier": "3.3.3", 38 | "react": "^18.3.1", 39 | "react-dom": "^18.3.1", 40 | "react-hook-form": "^7.52.2", 41 | "tailwind-merge": "^2.4.0", 42 | "tailwindcss-animate": "^1.0.7", 43 | "vite-tsconfig-paths": "^4.3.2", 44 | "zod": "^3.23.8" 45 | }, 46 | "devDependencies": { 47 | "@cspell/eslint-plugin": "^8.11.0", 48 | "@types/react": "^18.3.3", 49 | "@types/react-dom": "^18.3.0", 50 | "@typescript-eslint/eslint-plugin": "^7.16.1", 51 | "@typescript-eslint/parser": "^7.16.1", 52 | "@vitejs/plugin-react-swc": "^3.5.0", 53 | "autoprefixer": "^10.4.19", 54 | "cspell": "^8.11.0", 55 | "eslint": "^8.57.0", 56 | "eslint-config-prettier": "^9.1.0", 57 | "eslint-import-resolver-typescript": "^3.6.1", 58 | "eslint-plugin-import": "^2.29.1", 59 | "eslint-plugin-jsx-a11y": "^6.9.0", 60 | "eslint-plugin-prettier": "^5.2.1", 61 | "eslint-plugin-react": "^7.34.4", 62 | "eslint-plugin-react-hooks": "^4.6.2", 63 | "eslint-plugin-react-refresh": "^0.4.7", 64 | "eslint-plugin-readable-tailwind": "^1.5.2", 65 | "husky": "^9.1.1", 66 | "lint-staged": "^15.2.7", 67 | "postcss": "^8.4.39", 68 | "prettier-plugin-tailwindcss": "^0.6.5", 69 | "tailwindcss": "^3.4.6", 70 | "ts-node": "^10.9.2", 71 | "typescript": "^5.2.2", 72 | "vite": "^5.3.4" 73 | }, 74 | "lint-staged": { 75 | "src/**/*.{ts,tsx}": [ 76 | "prettier --write", 77 | "eslint --fix", 78 | "pnpm spellcheck" 79 | ], 80 | "src/**/*.css": [ 81 | "prettier --write", 82 | "pnpm spellcheck" 83 | ], 84 | "./**/*.md": [ 85 | "pnpm spellcheck" 86 | ] 87 | }, 88 | "engines": { 89 | "node": ">=20", 90 | "pnpm": ">=6" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/components/ui/Breadcrumb/Breadcrumb.tsx: -------------------------------------------------------------------------------- 1 | import { Slot } from "@radix-ui/react-slot"; 2 | import { ChevronRight, MoreHorizontal } from "lucide-react"; 3 | import { 4 | ComponentProps, 5 | ComponentPropsWithoutRef, 6 | forwardRef, 7 | ReactNode, 8 | } from "react"; 9 | import { cn } from "@Utils/className"; 10 | 11 | interface BreadcrumbComponent 12 | extends React.ForwardRefExoticComponent< 13 | ComponentPropsWithoutRef<"nav"> & { 14 | separator?: ReactNode; 15 | } 16 | > { 17 | List: typeof BreadcrumbList; 18 | Item: typeof BreadcrumbItem; 19 | Link: typeof BreadcrumbLink; 20 | Page: typeof BreadcrumbPage; 21 | Separator: typeof BreadcrumbSeparator; 22 | Ellipsis: typeof BreadcrumbEllipsis; 23 | } 24 | 25 | const Breadcrumb = forwardRef< 26 | HTMLElement, 27 | ComponentPropsWithoutRef<"nav"> & { 28 | separator?: ReactNode; 29 | } 30 | >(({ ...props }, ref) => ( 31 |