├── .eslintignore ├── .prettierignore ├── src ├── vite-env.d.ts ├── utils │ ├── logging.ts │ ├── enums.ts │ ├── models.ts │ └── helpers.ts ├── config │ └── theme.ts ├── main.tsx ├── components │ ├── AutoResizeTextArea.tsx │ ├── DarkModeIconButton.tsx │ ├── Column.tsx │ └── Task.tsx ├── hooks │ ├── useColumnDrop.ts │ ├── useTaskCollection.ts │ ├── useTaskDragAndDrop.ts │ └── useColumnTasks.ts └── App.tsx ├── .prettierrc ├── tsconfig.node.json ├── vite.config.ts ├── .gitignore ├── index.html ├── README.md ├── tsconfig.json ├── .eslintrc.json ├── LICENSE ├── package.json └── public └── vite.svg /.eslintignore: -------------------------------------------------------------------------------- 1 | public 2 | node_modules 3 | src/assets -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src/assets 3 | public -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "printWidth": 80 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/logging.ts: -------------------------------------------------------------------------------- 1 | export const debug = (msg: string) => { 2 | // if (process.env.NODE_ENV !== 'development') { 3 | // return; 4 | // } 5 | 6 | console.log(msg); 7 | }; 8 | -------------------------------------------------------------------------------- /src/utils/enums.ts: -------------------------------------------------------------------------------- 1 | export enum ColumnType { 2 | TO_DO = 'Todo', 3 | IN_PROGRESS = 'In Progress', 4 | BLOCKED = 'Blocked', 5 | COMPLETED = 'Completed', 6 | } 7 | 8 | export enum ItemType { 9 | TASK = 'Task', 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | port: 3000, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /src/utils/models.ts: -------------------------------------------------------------------------------- 1 | import { ColumnType } from './enums'; 2 | 3 | export interface TaskModel { 4 | id: string; 5 | title: string; 6 | column: ColumnType; 7 | color: string; 8 | } 9 | 10 | export interface DragItem { 11 | index: number; 12 | id: TaskModel['id']; 13 | from: ColumnType; 14 | } 15 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | // 2. Extend the theme to include custom colors, fonts, etc 4 | const theme = extendTheme({ 5 | styles: { 6 | global: (props: { colorMode: string }) => ({ 7 | body: { 8 | bg: props.colorMode === 'dark' ? 'gray.800' : 'white', 9 | }, 10 | }), 11 | }, 12 | }); 13 | 14 | export default theme; 15 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DnD Kanban 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProvider } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom/client'; 4 | import App from './App'; 5 | import theme from './config/theme'; 6 | 7 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 8 | 9 | 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /src/components/AutoResizeTextArea.tsx: -------------------------------------------------------------------------------- 1 | import { Textarea, TextareaProps } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import ResizeTextarea from 'react-textarea-autosize'; 4 | 5 | // eslint-disable-next-line react/display-name 6 | export const AutoResizeTextarea = React.forwardRef< 7 | HTMLTextAreaElement, 8 | TextareaProps 9 | >((props, ref) => { 10 | return