init
This commit is contained in:
		
							
								
								
									
										167
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										167
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -8,14 +8,24 @@
 | 
				
			|||||||
      "name": "msa-fe",
 | 
					      "name": "msa-fe",
 | 
				
			||||||
      "version": "0.1.0",
 | 
					      "version": "0.1.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-free": "^6.7.2",
 | 
				
			||||||
        "@testing-library/dom": "^10.4.0",
 | 
					        "@testing-library/dom": "^10.4.0",
 | 
				
			||||||
        "@testing-library/jest-dom": "^6.6.3",
 | 
					        "@testing-library/jest-dom": "^6.6.3",
 | 
				
			||||||
        "@testing-library/react": "^16.3.0",
 | 
					        "@testing-library/react": "^16.3.0",
 | 
				
			||||||
        "@testing-library/user-event": "^13.5.0",
 | 
					        "@testing-library/user-event": "^13.5.0",
 | 
				
			||||||
 | 
					        "echarts": "^5.6.0",
 | 
				
			||||||
        "react": "^19.1.0",
 | 
					        "react": "^19.1.0",
 | 
				
			||||||
        "react-dom": "^19.1.0",
 | 
					        "react-dom": "^19.1.0",
 | 
				
			||||||
        "react-scripts": "5.0.1",
 | 
					        "react-router-dom": "^7.5.1",
 | 
				
			||||||
 | 
					        "react-scripts": "^5.0.1",
 | 
				
			||||||
 | 
					        "swiper": "^11.2.6",
 | 
				
			||||||
        "web-vitals": "^2.1.4"
 | 
					        "web-vitals": "^2.1.4"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "devDependencies": {
 | 
				
			||||||
 | 
					        "autoprefixer": "^10.4.21",
 | 
				
			||||||
 | 
					        "postcss": "^8.5.3",
 | 
				
			||||||
 | 
					        "tailwindcss": "^3.4.17",
 | 
				
			||||||
 | 
					        "with": "^7.0.2"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@adobe/css-tools": {
 | 
					    "node_modules/@adobe/css-tools": {
 | 
				
			||||||
@ -2458,6 +2468,15 @@
 | 
				
			|||||||
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 | 
					        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fortawesome/fontawesome-free": {
 | 
				
			||||||
 | 
					      "version": "6.7.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==",
 | 
				
			||||||
 | 
					      "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@humanwhocodes/config-array": {
 | 
					    "node_modules/@humanwhocodes/config-array": {
 | 
				
			||||||
      "version": "0.13.0",
 | 
					      "version": "0.13.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
 | 
				
			||||||
@ -4800,6 +4819,13 @@
 | 
				
			|||||||
      "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
 | 
					      "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/assert-never": {
 | 
				
			||||||
 | 
					      "version": "1.4.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "license": "MIT"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/ast-types-flow": {
 | 
					    "node_modules/ast-types-flow": {
 | 
				
			||||||
      "version": "0.0.8",
 | 
					      "version": "0.0.8",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
 | 
				
			||||||
@ -5160,6 +5186,19 @@
 | 
				
			|||||||
        "@babel/core": "^7.0.0-0"
 | 
					        "@babel/core": "^7.0.0-0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/babel-walk": {
 | 
				
			||||||
 | 
					      "version": "3.0.0-canary-5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@babel/types": "^7.9.6"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 10.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/balanced-match": {
 | 
					    "node_modules/balanced-match": {
 | 
				
			||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 | 
				
			||||||
@ -6819,6 +6858,22 @@
 | 
				
			|||||||
      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
 | 
					      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/echarts": {
 | 
				
			||||||
 | 
					      "version": "5.6.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
 | 
				
			||||||
 | 
					      "license": "Apache-2.0",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "tslib": "2.3.0",
 | 
				
			||||||
 | 
					        "zrender": "5.6.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/echarts/node_modules/tslib": {
 | 
				
			||||||
 | 
					      "version": "2.3.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
 | 
				
			||||||
 | 
					      "license": "0BSD"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/ee-first": {
 | 
					    "node_modules/ee-first": {
 | 
				
			||||||
      "version": "1.1.1",
 | 
					      "version": "1.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
 | 
				
			||||||
@ -13926,6 +13981,54 @@
 | 
				
			|||||||
        "node": ">=0.10.0"
 | 
					        "node": ">=0.10.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/react-router": {
 | 
				
			||||||
 | 
					      "version": "7.5.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-/jjU3fcYNd2bwz9Q0xt5TwyiyoO8XjSEFXJY4O/lMAlkGTHWuHRAbR9Etik+lSDqMC7A7mz3UlXzgYT6Vl58sA==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "cookie": "^1.0.1",
 | 
				
			||||||
 | 
					        "set-cookie-parser": "^2.6.0",
 | 
				
			||||||
 | 
					        "turbo-stream": "2.4.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=20.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": ">=18",
 | 
				
			||||||
 | 
					        "react-dom": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "react-dom": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/react-router-dom": {
 | 
				
			||||||
 | 
					      "version": "7.5.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-5DPSPc7ENrt2tlKPq0FtpG80ZbqA9aIKEyqX6hSNJDlol/tr6iqCK4crqdsusmOSSotq6zDsn0y3urX9TuTNmA==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "react-router": "7.5.1"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=20.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": ">=18",
 | 
				
			||||||
 | 
					        "react-dom": ">=18"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/react-router/node_modules/cookie": {
 | 
				
			||||||
 | 
					      "version": "1.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/react-scripts": {
 | 
					    "node_modules/react-scripts": {
 | 
				
			||||||
      "version": "5.0.1",
 | 
					      "version": "5.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
 | 
				
			||||||
@ -14841,6 +14944,12 @@
 | 
				
			|||||||
        "node": ">= 0.8.0"
 | 
					        "node": ">= 0.8.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/set-cookie-parser": {
 | 
				
			||||||
 | 
					      "version": "2.7.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
 | 
				
			||||||
 | 
					      "license": "MIT"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/set-function-length": {
 | 
					    "node_modules/set-function-length": {
 | 
				
			||||||
      "version": "1.2.2",
 | 
					      "version": "1.2.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
 | 
				
			||||||
@ -15854,6 +15963,25 @@
 | 
				
			|||||||
        "node": ">=4"
 | 
					        "node": ">=4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/swiper": {
 | 
				
			||||||
 | 
					      "version": "11.2.6",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.6.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-8aXpYKtjy3DjcbzZfz+/OX/GhcU5h+looA6PbAzHMZT6ESSycSp9nAjPCenczgJyslV+rUGse64LMGpWE3PX9Q==",
 | 
				
			||||||
 | 
					      "funding": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "type": "patreon",
 | 
				
			||||||
 | 
					          "url": "https://www.patreon.com/swiperjs"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "type": "open_collective",
 | 
				
			||||||
 | 
					          "url": "http://opencollective.com/swiper"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 4.7.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/symbol-tree": {
 | 
					    "node_modules/symbol-tree": {
 | 
				
			||||||
      "version": "3.2.4",
 | 
					      "version": "3.2.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
 | 
				
			||||||
@ -16219,6 +16347,12 @@
 | 
				
			|||||||
      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
 | 
					      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
 | 
				
			||||||
      "license": "0BSD"
 | 
					      "license": "0BSD"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/turbo-stream": {
 | 
				
			||||||
 | 
					      "version": "2.4.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
 | 
				
			||||||
 | 
					      "license": "ISC"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/type-check": {
 | 
					    "node_modules/type-check": {
 | 
				
			||||||
      "version": "0.4.0",
 | 
					      "version": "0.4.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
 | 
				
			||||||
@ -17057,6 +17191,22 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/with": {
 | 
				
			||||||
 | 
					      "version": "7.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@babel/parser": "^7.9.6",
 | 
				
			||||||
 | 
					        "@babel/types": "^7.9.6",
 | 
				
			||||||
 | 
					        "assert-never": "^1.2.1",
 | 
				
			||||||
 | 
					        "babel-walk": "3.0.0-canary-5"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 10.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/word-wrap": {
 | 
					    "node_modules/word-wrap": {
 | 
				
			||||||
      "version": "1.2.5",
 | 
					      "version": "1.2.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
 | 
				
			||||||
@ -17537,6 +17687,21 @@
 | 
				
			|||||||
      "funding": {
 | 
					      "funding": {
 | 
				
			||||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
					        "url": "https://github.com/sponsors/sindresorhus"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/zrender": {
 | 
				
			||||||
 | 
					      "version": "5.6.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==",
 | 
				
			||||||
 | 
					      "license": "BSD-3-Clause",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "tslib": "2.3.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/zrender/node_modules/tslib": {
 | 
				
			||||||
 | 
					      "version": "2.3.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
 | 
				
			||||||
 | 
					      "license": "0BSD"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							@ -3,13 +3,17 @@
 | 
				
			|||||||
  "version": "0.1.0",
 | 
					  "version": "0.1.0",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@fortawesome/fontawesome-free": "^6.7.2",
 | 
				
			||||||
    "@testing-library/dom": "^10.4.0",
 | 
					    "@testing-library/dom": "^10.4.0",
 | 
				
			||||||
    "@testing-library/jest-dom": "^6.6.3",
 | 
					    "@testing-library/jest-dom": "^6.6.3",
 | 
				
			||||||
    "@testing-library/react": "^16.3.0",
 | 
					    "@testing-library/react": "^16.3.0",
 | 
				
			||||||
    "@testing-library/user-event": "^13.5.0",
 | 
					    "@testing-library/user-event": "^13.5.0",
 | 
				
			||||||
 | 
					    "echarts": "^5.6.0",
 | 
				
			||||||
    "react": "^19.1.0",
 | 
					    "react": "^19.1.0",
 | 
				
			||||||
    "react-dom": "^19.1.0",
 | 
					    "react-dom": "^19.1.0",
 | 
				
			||||||
    "react-scripts": "5.0.1",
 | 
					    "react-router-dom": "^7.5.1",
 | 
				
			||||||
 | 
					    "react-scripts": "^5.0.1",
 | 
				
			||||||
 | 
					    "swiper": "^11.2.6",
 | 
				
			||||||
    "web-vitals": "^2.1.4"
 | 
					    "web-vitals": "^2.1.4"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
@ -35,5 +39,11 @@
 | 
				
			|||||||
      "last 1 firefox version",
 | 
					      "last 1 firefox version",
 | 
				
			||||||
      "last 1 safari version"
 | 
					      "last 1 safari version"
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "autoprefixer": "^10.4.21",
 | 
				
			||||||
 | 
					    "postcss": "^8.5.3",
 | 
				
			||||||
 | 
					    "tailwindcss": "^3.4.17",
 | 
				
			||||||
 | 
					    "with": "^7.0.2"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								postcss.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								postcss.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  plugins: {
 | 
				
			||||||
 | 
					    tailwindcss: {},
 | 
				
			||||||
 | 
					    autoprefixer: {},
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/App.js
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								src/App.js
									
									
									
									
									
								
							@ -1,24 +1,30 @@
 | 
				
			|||||||
import logo from './logo.svg';
 | 
					import React from 'react';
 | 
				
			||||||
import './App.css';
 | 
					import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
 | 
				
			||||||
 | 
					import Navbar from './components/Navbar';
 | 
				
			||||||
 | 
					import Footer from './components/Footer';
 | 
				
			||||||
 | 
					import Home from './pages/Home';
 | 
				
			||||||
 | 
					import About from './pages/About';
 | 
				
			||||||
 | 
					import Board from './pages/Board';
 | 
				
			||||||
 | 
					import PostCategory from './pages/PostCategory';
 | 
				
			||||||
 | 
					import Login from './pages/Login';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function App() {
 | 
					function App() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="App">
 | 
					    <Router>
 | 
				
			||||||
      <header className="App-header">
 | 
					      <div className="flex flex-col min-h-screen">
 | 
				
			||||||
        <img src={logo} className="App-logo" alt="logo" />
 | 
					        <Navbar />
 | 
				
			||||||
        <p>
 | 
					        <main className="flex-grow pt-16">
 | 
				
			||||||
          Edit <code>src/App.js</code> and save to reload.
 | 
					          <Routes>
 | 
				
			||||||
        </p>
 | 
					            <Route path="/" element={<Home />} />
 | 
				
			||||||
        <a
 | 
					            <Route path="/about" element={<About />} />
 | 
				
			||||||
          className="App-link"
 | 
					            <Route path="/board" element={<Board />} />
 | 
				
			||||||
          href="https://reactjs.org"
 | 
					            <Route path="/post/:category" element={<PostCategory />} />
 | 
				
			||||||
          target="_blank"
 | 
					            <Route path="/login" element={<Login />} />
 | 
				
			||||||
          rel="noopener noreferrer"
 | 
					          </Routes>
 | 
				
			||||||
        >
 | 
					        </main>
 | 
				
			||||||
          Learn React
 | 
					        <Footer />
 | 
				
			||||||
        </a>
 | 
					 | 
				
			||||||
      </header>
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					    </Router>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								src/components/Footer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/components/Footer.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useNavigate } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Footer = () => {
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <footer className="bg-gray-900 text-white mt-auto">
 | 
				
			||||||
 | 
					      <div className="container mx-auto px-4 py-12">
 | 
				
			||||||
 | 
					        <div className="grid grid-cols-1 md:grid-cols-4 gap-8">
 | 
				
			||||||
 | 
					          <div>
 | 
				
			||||||
 | 
					            <h3 className="text-xl font-bold mb-4">TechEdu</h3>
 | 
				
			||||||
 | 
					            <p className="text-gray-400">최고의 IT 교육 플랫폼으로 당신의 커리어를 성장시키세요.</p>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div>
 | 
				
			||||||
 | 
					            <h4 className="text-lg font-semibold mb-4">Quick Links</h4>
 | 
				
			||||||
 | 
					            <ul className="space-y-2">
 | 
				
			||||||
 | 
					              <li><button onClick={() => navigate('/')} className="text-gray-400 hover:text-white">Home</button></li>
 | 
				
			||||||
 | 
					              <li><button onClick={() => navigate('/about')} className="text-gray-400 hover:text-white">About</button></li>
 | 
				
			||||||
 | 
					              <li><button onClick={() => navigate('/board')} className="text-gray-400 hover:text-white">Board</button></li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div>
 | 
				
			||||||
 | 
					            <h4 className="text-lg font-semibold mb-4">Categories</h4>
 | 
				
			||||||
 | 
					            <ul className="space-y-2">
 | 
				
			||||||
 | 
					              <li><button onClick={() => navigate('/post/developer')} className="text-gray-400 hover:text-white">Developer</button></li>
 | 
				
			||||||
 | 
					              <li><button onClick={() => navigate('/post/systemengineer')} className="text-gray-400 hover:text-white">System Engineer</button></li>
 | 
				
			||||||
 | 
					              <li><button onClick={() => navigate('/post/etc')} className="text-gray-400 hover:text-white">Other Posts</button></li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div>
 | 
				
			||||||
 | 
					            <h4 className="text-lg font-semibold mb-4">Contact</h4>
 | 
				
			||||||
 | 
					            <ul className="space-y-2 text-gray-400">
 | 
				
			||||||
 | 
					              <li className="flex items-center"><i className="fas fa-envelope mr-2"></i> contact@techedu.com</li>
 | 
				
			||||||
 | 
					              <li className="flex items-center"><i className="fas fa-phone mr-2"></i> 02-1234-5678</li>
 | 
				
			||||||
 | 
					              <li className="flex items-center"><i className="fas fa-map-marker-alt mr-2"></i> 서울특별시 강남구 테헤란로 123</li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="border-t border-gray-800 mt-8 pt-8 text-center text-gray-400">
 | 
				
			||||||
 | 
					          <p>© 2025 TechEdu. All rights reserved.</p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </footer>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Footer;
 | 
				
			||||||
							
								
								
									
										57
									
								
								src/components/Navbar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/components/Navbar.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { Link, useNavigate } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Navbar = () => {
 | 
				
			||||||
 | 
					  const menuItems = ['home', 'about', 'board', 'etc'];
 | 
				
			||||||
 | 
					  const postCategories = ['developer', 'systemengineer', 'etc'];
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <nav className="fixed w-full z-50 bg-white/90 backdrop-blur-md shadow-sm">
 | 
				
			||||||
 | 
					      <div className="container mx-auto px-4">
 | 
				
			||||||
 | 
					        <div className="flex justify-between items-center h-16">
 | 
				
			||||||
 | 
					          <Link to="/" className="text-2xl font-bold text-[#3B82F6]">TechEdu</Link>
 | 
				
			||||||
 | 
					          <div className="hidden md:flex items-center space-x-8">
 | 
				
			||||||
 | 
					            {menuItems.map((item) => (
 | 
				
			||||||
 | 
					              <Link
 | 
				
			||||||
 | 
					                key={item}
 | 
				
			||||||
 | 
					                to={item === 'home' ? '/' : `/${item}`}
 | 
				
			||||||
 | 
					                className="text-gray-600 hover:text-[#D4AF37]"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                {item.charAt(0).toUpperCase() + item.slice(1)}
 | 
				
			||||||
 | 
					              </Link>
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {/* ▼ Post Dropdown */}
 | 
				
			||||||
 | 
					            <div className="relative group">
 | 
				
			||||||
 | 
					              <button className="text-gray-600 hover:text-[#D4AF37] flex items-center">
 | 
				
			||||||
 | 
					                Post <i className="fas fa-chevron-down ml-1 text-xs"></i>
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
 | 
					              <div className="absolute hidden group-hover:block bg-white shadow-md mt-2 rounded-md py-2">
 | 
				
			||||||
 | 
					                {postCategories.map(category => (
 | 
				
			||||||
 | 
					                  <button
 | 
				
			||||||
 | 
					                    key={category}
 | 
				
			||||||
 | 
					                    onClick={() => navigate(`/post/${category.toLowerCase()}`)}
 | 
				
			||||||
 | 
					                    className="block px-4 py-2 text-gray-600 hover:bg-gray-50 hover:text-[#D4AF37] w-full text-left"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    {category.charAt(0).toUpperCase() + category.slice(1)}
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
 | 
					                ))}
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {/* ✅ 로그인 버튼 */}
 | 
				
			||||||
 | 
					            <Link
 | 
				
			||||||
 | 
					              to="/login"
 | 
				
			||||||
 | 
					              className="bg-[#3B82F6] text-white px-4 py-2 rounded hover:bg-blue-700 transition"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              로그인
 | 
				
			||||||
 | 
					            </Link>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </nav>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Navbar;
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/components/PostCard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/components/PostCard.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PostCard = ({ post }) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="bg-white shadow-lg rounded-lg overflow-hidden transition-transform duration-300 hover:-translate-y-2">
 | 
				
			||||||
 | 
					      <img src={post.image} alt={post.title} className="w-full h-48 object-cover" />
 | 
				
			||||||
 | 
					      <div className="p-6">
 | 
				
			||||||
 | 
					        <h3 className="text-xl font-semibold mb-2">{post.title}</h3>
 | 
				
			||||||
 | 
					        <p className="text-gray-600 mb-4">{post.content}</p>
 | 
				
			||||||
 | 
					        <div className="flex justify-between items-center">
 | 
				
			||||||
 | 
					          <span className="text-sm text-gray-500">{post.date}</span>
 | 
				
			||||||
 | 
					          <button className="text-[#D4AF37] hover:text-[#000080]">더 보기</button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PostCard;
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/data/sampleData.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/data/sampleData.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					export const posts = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      id: 1,
 | 
				
			||||||
 | 
					      title: '인공지능 기초 학습 가이드',
 | 
				
			||||||
 | 
					      content: '인공지능 학습을 시작하는 분들을 위한 완벽 가이드...',
 | 
				
			||||||
 | 
					      date: '2025-02-19',
 | 
				
			||||||
 | 
					      image: 'https://public.readdy.ai/ai/img_res/c22ebfe39e631e808ad948c508839779.jpg'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  export const boardItems = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      id: 1,
 | 
				
			||||||
 | 
					      title: '신규 프로젝트 진행 현황 보고',
 | 
				
			||||||
 | 
					      content: '2025년 1분기 신규 프로젝트의 진행 상황...',
 | 
				
			||||||
 | 
					      author: '김지원',
 | 
				
			||||||
 | 
					      updatedAt: '2025-02-19'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
@ -11,3 +11,10 @@ code {
 | 
				
			|||||||
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
 | 
					  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
 | 
				
			||||||
    monospace;
 | 
					    monospace;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@tailwind base;
 | 
				
			||||||
 | 
					@tailwind components;
 | 
				
			||||||
 | 
					@tailwind utilities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 추가로 FontAwesome을 위한 CSS */
 | 
				
			||||||
 | 
					@import '@fortawesome/fontawesome-free/css/all.min.css';
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,6 @@ import React from 'react';
 | 
				
			|||||||
import ReactDOM from 'react-dom/client';
 | 
					import ReactDOM from 'react-dom/client';
 | 
				
			||||||
import './index.css';
 | 
					import './index.css';
 | 
				
			||||||
import App from './App';
 | 
					import App from './App';
 | 
				
			||||||
import reportWebVitals from './reportWebVitals';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const root = ReactDOM.createRoot(document.getElementById('root'));
 | 
					const root = ReactDOM.createRoot(document.getElementById('root'));
 | 
				
			||||||
root.render(
 | 
					root.render(
 | 
				
			||||||
@ -10,8 +9,3 @@ root.render(
 | 
				
			|||||||
    <App />
 | 
					    <App />
 | 
				
			||||||
  </React.StrictMode>
 | 
					  </React.StrictMode>
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					 | 
				
			||||||
// If you want to start measuring performance in your app, pass a function
 | 
					 | 
				
			||||||
// to log results (for example: reportWebVitals(console.log))
 | 
					 | 
				
			||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
 | 
					 | 
				
			||||||
reportWebVitals();
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										81
									
								
								src/pages/About.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/pages/About.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					import React, { useEffect, useRef } from 'react';
 | 
				
			||||||
 | 
					import * as echarts from 'echarts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const About = () => {
 | 
				
			||||||
 | 
					  const chartRef = useRef(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    const chart = echarts.init(chartRef.current);
 | 
				
			||||||
 | 
					    chart.setOption({
 | 
				
			||||||
 | 
					      animation: false,
 | 
				
			||||||
 | 
					      radar: {
 | 
				
			||||||
 | 
					        indicator: [
 | 
				
			||||||
 | 
					          { name: '프로그래밍', max: 100 },
 | 
				
			||||||
 | 
					          { name: '클라우드', max: 100 },
 | 
				
			||||||
 | 
					          { name: '인공지능', max: 100 },
 | 
				
			||||||
 | 
					          { name: '데이터 분석', max: 100 },
 | 
				
			||||||
 | 
					          { name: '보안', max: 100 }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      series: [{
 | 
				
			||||||
 | 
					        type: 'radar',
 | 
				
			||||||
 | 
					        data: [{
 | 
				
			||||||
 | 
					          value: [95, 90, 85, 88, 92],
 | 
				
			||||||
 | 
					          name: '교육 역량',
 | 
				
			||||||
 | 
					          areaStyle: { color: 'rgba(59, 130, 246, 0.2)' },
 | 
				
			||||||
 | 
					          lineStyle: { color: '#3B82F6' }
 | 
				
			||||||
 | 
					        }]
 | 
				
			||||||
 | 
					      }]
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="min-h-screen bg-white">
 | 
				
			||||||
 | 
					      <div className="container mx-auto px-4 py-20">
 | 
				
			||||||
 | 
					        <div className="max-w-4xl mx-auto">
 | 
				
			||||||
 | 
					          <div className="text-center mb-16">
 | 
				
			||||||
 | 
					            <h2 className="text-4xl font-bold mb-6">About Us</h2>
 | 
				
			||||||
 | 
					            <p className="text-xl text-gray-600">최고의 IT 교육 플랫폼을 만들어갑니다</p>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="grid grid-cols-1 md:grid-cols-2 gap-12 mb-20">
 | 
				
			||||||
 | 
					            <div>
 | 
				
			||||||
 | 
					              <h3 className="text-2xl font-bold mb-6">우리의 비전</h3>
 | 
				
			||||||
 | 
					              <p className="text-gray-600 leading-relaxed">
 | 
				
			||||||
 | 
					                실무 중심의 IT 교육을 통해 더 많은 사람들이 디지털 시대의 전문가로
 | 
				
			||||||
 | 
					                성장할 수 있도록 돕고, 글로벌 IT 인재 양성의 허브가 되고자 합니다.
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div>
 | 
				
			||||||
 | 
					              <h3 className="text-2xl font-bold mb-6">핵심 가치</h3>
 | 
				
			||||||
 | 
					              <ul className="space-y-4">
 | 
				
			||||||
 | 
					                <li className="flex items-center">
 | 
				
			||||||
 | 
					                  <i className="fas fa-check text-[#3B82F6] mr-3"></i><span>실무 중심 교육</span>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li className="flex items-center">
 | 
				
			||||||
 | 
					                  <i className="fas fa-check text-[#3B82F6] mr-3"></i><span>최신 기술 트렌드</span>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li className="flex items-center">
 | 
				
			||||||
 | 
					                  <i className="fas fa-check text-[#3B82F6] mr-3"></i><span>커뮤니티 중심</span>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					              </ul>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="mb-20">
 | 
				
			||||||
 | 
					            <h3 className="text-2xl font-bold mb-8 text-center">전문 역량</h3>
 | 
				
			||||||
 | 
					            <div ref={chartRef} className="w-full h-[400px]"></div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="text-center">
 | 
				
			||||||
 | 
					            <h3 className="text-2xl font-bold mb-6">Contact Us</h3>
 | 
				
			||||||
 | 
					            <div className="space-y-4">
 | 
				
			||||||
 | 
					              <p><i className="fas fa-envelope mr-2"></i> contact@example.com</p>
 | 
				
			||||||
 | 
					              <p><i className="fas fa-phone mr-2"></i> 02-1234-5678</p>
 | 
				
			||||||
 | 
					              <p><i className="fas fa-map-marker-alt mr-2"></i> 서울특별시 강남구 테헤란로 123</p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default About;
 | 
				
			||||||
							
								
								
									
										80
									
								
								src/pages/Board.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/pages/Board.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { boardItems } from '../data/sampleData';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Board = () => {
 | 
				
			||||||
 | 
					  const [searchTerm, setSearchTerm] = useState('');
 | 
				
			||||||
 | 
					  const [currentPage, setCurrentPage] = useState(1);
 | 
				
			||||||
 | 
					  const itemsPerPage = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const filteredItems = boardItems.filter(item =>
 | 
				
			||||||
 | 
					    item.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
 | 
				
			||||||
 | 
					    item.content.toLowerCase().includes(searchTerm.toLowerCase()) ||
 | 
				
			||||||
 | 
					    item.author.toLowerCase().includes(searchTerm.toLowerCase())
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="min-h-screen bg-gray-50 py-20">
 | 
				
			||||||
 | 
					      <div className="container mx-auto px-4">
 | 
				
			||||||
 | 
					        <div className="max-w-6xl mx-auto">
 | 
				
			||||||
 | 
					          <div className="mb-8">
 | 
				
			||||||
 | 
					            <div className="relative">
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                type="text"
 | 
				
			||||||
 | 
					                placeholder="검색어를 입력하세요"
 | 
				
			||||||
 | 
					                className="w-full px-4 py-3 pl-12 border-none rounded-lg bg-white shadow-md text-sm"
 | 
				
			||||||
 | 
					                value={searchTerm}
 | 
				
			||||||
 | 
					                onChange={(e) => setSearchTerm(e.target.value)}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              <i className="fas fa-search absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="bg-white rounded-lg shadow-md overflow-hidden">
 | 
				
			||||||
 | 
					            <table className="w-full">
 | 
				
			||||||
 | 
					              <thead className="bg-[#3B82F6] text-white">
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <th className="px-6 py-4 text-left w-20">번호</th>
 | 
				
			||||||
 | 
					                  <th className="px-6 py-4 text-left">제목</th>
 | 
				
			||||||
 | 
					                  <th className="px-6 py-4 text-left">내용</th>
 | 
				
			||||||
 | 
					                  <th className="px-6 py-4 text-left w-32">작성자</th>
 | 
				
			||||||
 | 
					                  <th className="px-6 py-4 text-left w-32">수정일</th>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					              </thead>
 | 
				
			||||||
 | 
					              <tbody>
 | 
				
			||||||
 | 
					                {filteredItems
 | 
				
			||||||
 | 
					                  .slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage)
 | 
				
			||||||
 | 
					                  .map(item => (
 | 
				
			||||||
 | 
					                    <tr key={item.id} className="border-b border-gray-100 hover:bg-gray-50">
 | 
				
			||||||
 | 
					                      <td className="px-6 py-4">{item.id}</td>
 | 
				
			||||||
 | 
					                      <td className="px-6 py-4 font-medium">{item.title}</td>
 | 
				
			||||||
 | 
					                      <td className="px-6 py-4 text-gray-600">{item.content.substring(0, 30)}...</td>
 | 
				
			||||||
 | 
					                      <td className="px-6 py-4">{item.author}</td>
 | 
				
			||||||
 | 
					                      <td className="px-6 py-4 text-gray-500">{item.updatedAt}</td>
 | 
				
			||||||
 | 
					                    </tr>
 | 
				
			||||||
 | 
					                  ))}
 | 
				
			||||||
 | 
					              </tbody>
 | 
				
			||||||
 | 
					            </table>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="mt-6 flex justify-center">
 | 
				
			||||||
 | 
					            <div className="flex space-x-2">
 | 
				
			||||||
 | 
					              {Array.from({ length: Math.ceil(filteredItems.length / itemsPerPage) }, (_, i) => (
 | 
				
			||||||
 | 
					                <button
 | 
				
			||||||
 | 
					                  key={i + 1}
 | 
				
			||||||
 | 
					                  onClick={() => setCurrentPage(i + 1)}
 | 
				
			||||||
 | 
					                  className={`px-4 py-2 rounded ${
 | 
				
			||||||
 | 
					                    currentPage === i + 1
 | 
				
			||||||
 | 
					                      ? 'bg-[#3B82F6] text-white'
 | 
				
			||||||
 | 
					                      : 'bg-white text-gray-600 hover:bg-gray-100'
 | 
				
			||||||
 | 
					                  }`}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  {i + 1}
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					              ))}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Board;
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/pages/Home.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/pages/Home.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { posts } from '../data/sampleData';
 | 
				
			||||||
 | 
					import PostCard from '../components/PostCard';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Home = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="min-h-screen">
 | 
				
			||||||
 | 
					      <div className="relative h-screen">
 | 
				
			||||||
 | 
					        <div className="absolute inset-0">
 | 
				
			||||||
 | 
					          <img
 | 
				
			||||||
 | 
					            src="https://public.readdy.ai/ai/img_res/41c06ed594c02f95a02361b098edd073.jpg"
 | 
				
			||||||
 | 
					            className="w-full h-full object-cover"
 | 
				
			||||||
 | 
					            alt="Hero Background"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="absolute inset-0 bg-gradient-to-r from-black/70 to-transparent">
 | 
				
			||||||
 | 
					          <div className="container mx-auto px-4 h-full flex items-center">
 | 
				
			||||||
 | 
					            <div className="max-w-2xl text-white">
 | 
				
			||||||
 | 
					              <h1 className="text-5xl font-bold mb-6">IT 교육의 새로운 기준</h1>
 | 
				
			||||||
 | 
					              <p className="text-xl mb-8">실무 중심의 IT 교육 콘텐츠로 당신의 커리어를 성장시키세요</p>
 | 
				
			||||||
 | 
					              <button className="bg-[#3B82F6] text-white px-8 py-3 rounded-lg">학습 시작하기</button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="container mx-auto px-4 py-20">
 | 
				
			||||||
 | 
					        <h2 className="text-3xl font-bold mb-12 text-center">최신 포스트</h2>
 | 
				
			||||||
 | 
					        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
 | 
				
			||||||
 | 
					          {posts.map(post => (
 | 
				
			||||||
 | 
					            <PostCard key={post.id} post={post} />
 | 
				
			||||||
 | 
					          ))}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Home;
 | 
				
			||||||
							
								
								
									
										58
									
								
								src/pages/Login.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/pages/Login.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { useNavigate } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Login = () => {
 | 
				
			||||||
 | 
					  const [username, setUsername] = useState('');
 | 
				
			||||||
 | 
					  const [password, setPassword] = useState('');
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleLogin = async () => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const response = await fetch(`${process.env.REACT_APP_API_URL}/api/auth/login/`, {
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        headers: { 'Content-Type': 'application/json' },
 | 
				
			||||||
 | 
					        body: JSON.stringify({ username, password })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!response.ok) throw new Error('로그인 실패');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const data = await response.json();
 | 
				
			||||||
 | 
					      localStorage.setItem('access', data.access);
 | 
				
			||||||
 | 
					      localStorage.setItem('refresh', data.refresh);
 | 
				
			||||||
 | 
					      alert('로그인 성공!');
 | 
				
			||||||
 | 
					      navigate('/');
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      alert('로그인 실패: ' + error.message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="min-h-screen bg-gray-50 flex items-center justify-center px-4">
 | 
				
			||||||
 | 
					      <div className="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
 | 
				
			||||||
 | 
					        <h2 className="text-2xl font-bold mb-6 text-center text-[#3B82F6]">로그인</h2>
 | 
				
			||||||
 | 
					        <input
 | 
				
			||||||
 | 
					          type="text"
 | 
				
			||||||
 | 
					          placeholder="Username"
 | 
				
			||||||
 | 
					          value={username}
 | 
				
			||||||
 | 
					          onChange={(e) => setUsername(e.target.value)}
 | 
				
			||||||
 | 
					          className="w-full px-4 py-2 border rounded mb-4"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <input
 | 
				
			||||||
 | 
					          type="password"
 | 
				
			||||||
 | 
					          placeholder="Password"
 | 
				
			||||||
 | 
					          value={password}
 | 
				
			||||||
 | 
					          onChange={(e) => setPassword(e.target.value)}
 | 
				
			||||||
 | 
					          className="w-full px-4 py-2 border rounded mb-6"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          onClick={handleLogin}
 | 
				
			||||||
 | 
					          className="w-full bg-[#3B82F6] text-white py-2 rounded hover:bg-blue-700"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          로그인
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Login;
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/pages/PostCategory.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/pages/PostCategory.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useParams } from 'react-router-dom';
 | 
				
			||||||
 | 
					import { posts } from '../data/sampleData';
 | 
				
			||||||
 | 
					import PostCard from '../components/PostCard';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PostCategory = () => {
 | 
				
			||||||
 | 
					  const { category } = useParams();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="min-h-screen bg-gray-50 py-20">
 | 
				
			||||||
 | 
					      <div className="container mx-auto px-4">
 | 
				
			||||||
 | 
					        <h2 className="text-3xl font-bold mb-12 text-center">
 | 
				
			||||||
 | 
					          {category.charAt(0).toUpperCase() + category.slice(1)} 관련 포스트
 | 
				
			||||||
 | 
					        </h2>
 | 
				
			||||||
 | 
					        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
 | 
				
			||||||
 | 
					          {posts.map(post => (
 | 
				
			||||||
 | 
					            <PostCard key={post.id} post={post} />
 | 
				
			||||||
 | 
					          ))}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PostCategory;
 | 
				
			||||||
							
								
								
									
										11
									
								
								tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					/** @type {import('tailwindcss').Config} */
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  content: [
 | 
				
			||||||
 | 
					    "./src/**/*.{js,jsx,ts,tsx}"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  theme: {
 | 
				
			||||||
 | 
					    extend: {},
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  plugins: [],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user