diff --git a/.env b/.env new file mode 100644 index 000000000..02320bbaa --- /dev/null +++ b/.env @@ -0,0 +1 @@ +$ PORT=6002 npm run start diff --git a/README.md b/README.md index 4d5ac098c..8b3ee81a8 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + # Chrome Extension (MV3) Boilerplate with React 18 and Webpack 5 diff --git a/package-lock.json b/package-lock.json index 020089ad5..aef02cef4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { - "name": "chrome-extension-boilerplate-react", + "name": "newscopev2", "version": "5.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "chrome-extension-boilerplate-react", + "name": "newscopev2", "version": "5.0.4", "license": "MIT", "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-rnd": "^10.4.14" }, "devDependencies": { "@babel/core": "^7.20.12", @@ -2364,6 +2365,7 @@ "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.202.tgz", "integrity": "sha512-Oc4daL9sFS+9MToVZPLMBxR7PxsEdod0b8wOY11lRr06GJp43MORvHeDyMD8QzeRGT6HI13oaYAe2PBgvALc4w==", "dev": true, + "license": "MIT", "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" @@ -4248,6 +4250,15 @@ "node": ">=6" } }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -8967,7 +8978,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9658,7 +9668,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -9796,6 +9805,16 @@ "node": ">=0.10.0" } }, + "node_modules/re-resizable": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.3.tgz", + "integrity": "sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -9819,11 +9838,24 @@ "react": "^18.2.0" } }, + "node_modules/react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "license": "MIT", + "dependencies": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-refresh": { "version": "0.14.0", @@ -9844,6 +9876,21 @@ "typescript": "^4" } }, + "node_modules/react-rnd": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.14.tgz", + "integrity": "sha512-NLGc3IymymumPfHy3DXiHNIMOiTlj6xBNb2boHqrtwCgYDasNarpg8tdUY36JlJbrs0E4BvjYBkfEGqUPBsukg==", + "license": "MIT", + "dependencies": { + "re-resizable": "6.10.3", + "react-draggable": "4.4.6", + "tslib": "2.6.2" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -11540,10 +11587,10 @@ } }, "node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", @@ -15501,6 +15548,11 @@ "shallow-clone": "^3.0.0" } }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -19104,8 +19156,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { "version": "1.12.3", @@ -19598,7 +19649,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -19696,6 +19746,12 @@ } } }, + "re-resizable": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.3.tgz", + "integrity": "sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw==", + "requires": {} + }, "react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -19713,11 +19769,19 @@ "scheduler": "^0.23.0" } }, + "react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "requires": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-refresh": { "version": "0.14.0", @@ -19732,6 +19796,16 @@ "dev": true, "requires": {} }, + "react-rnd": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.14.tgz", + "integrity": "sha512-NLGc3IymymumPfHy3DXiHNIMOiTlj6xBNb2boHqrtwCgYDasNarpg8tdUY36JlJbrs0E4BvjYBkfEGqUPBsukg==", + "requires": { + "re-resizable": "6.10.3", + "react-draggable": "4.4.6", + "tslib": "2.6.2" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -21048,10 +21122,9 @@ } }, "tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "tsutils": { "version": "3.21.0", diff --git a/package.json b/package.json index 4c83f2b9d..2eb9140a6 100755 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { - "name": "chrome-extension-boilerplate-react", + "name": "newscopev2", "version": "5.0.4", "description": "A chrome extension boilerplate built with React 18, Webpack 5, and Webpack Dev Server 4", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/lxieyang/chrome-extension-boilerplate-react.git" + "url": "https://github.com/NewScopeExtension/NewScopeV2.git" }, "scripts": { "build": "node utils/build.js", @@ -14,7 +14,8 @@ }, "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-rnd": "^10.4.14" }, "devDependencies": { "@babel/core": "^7.20.12", diff --git a/src/assets/img/icon-128.png b/src/assets/img/icon-128.png deleted file mode 100644 index 13996e60b..000000000 Binary files a/src/assets/img/icon-128.png and /dev/null differ diff --git a/src/assets/img/icon-34.png b/src/assets/img/icon-34.png deleted file mode 100644 index 96aba0bc2..000000000 Binary files a/src/assets/img/icon-34.png and /dev/null differ diff --git a/src/assets/img/icon.png b/src/assets/img/icon.png new file mode 100644 index 000000000..3e45ad8e6 Binary files /dev/null and b/src/assets/img/icon.png differ diff --git a/src/containers/Greetings/Greetings.jsx b/src/containers/Greetings/Greetings.jsx index b0404c860..d6b3fdeea 100644 --- a/src/containers/Greetings/Greetings.jsx +++ b/src/containers/Greetings/Greetings.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import icon from '../../assets/img/icon-128.png'; +import icon from '../../assets/img/icon.png'; class GreetingComponent extends Component { state = { diff --git a/src/manifest.json b/src/manifest.json index 9a7ba9080..a4c9deb81 100755 --- a/src/manifest.json +++ b/src/manifest.json @@ -3,16 +3,18 @@ "name": "Chrome Extension with React & Webpack", "description": "A chrome extension boilerplate built with React 17, Webpack 5, and Webpack Dev Server 4", "options_page": "options.html", - "background": { "service_worker": "background.bundle.js" }, + "background": { + "service_worker": "background.bundle.js" + }, "action": { "default_popup": "popup.html", - "default_icon": "icon-34.png" + "default_icon": "icon.png" }, "chrome_url_overrides": { "newtab": "newtab.html" }, "icons": { - "128": "icon-128.png" + "128": "icon.png" }, "content_scripts": [ { @@ -24,7 +26,7 @@ "devtools_page": "devtools.html", "web_accessible_resources": [ { - "resources": ["content.styles.css", "icon-128.png", "icon-34.png"], + "resources": ["content.styles.css", "icon.png"], "matches": [] } ] diff --git a/src/pages/Background/background.bundle.js b/src/pages/Background/background.bundle.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/pages/Devtools/index.js b/src/pages/Devtools/index.js index 647319a1f..0baccc6c2 100644 --- a/src/pages/Devtools/index.js +++ b/src/pages/Devtools/index.js @@ -1,5 +1,5 @@ chrome.devtools.panels.create( 'Dev Tools from chrome-extension-boilerplate-react', - 'icon-34.png', + 'icon.png', 'panel.html' ); diff --git a/src/pages/Popup/Modal.css b/src/pages/Popup/Modal.css new file mode 100644 index 000000000..a116d6a07 --- /dev/null +++ b/src/pages/Popup/Modal.css @@ -0,0 +1,46 @@ +/* Modal.css */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.5); /* 반투명 배경 */ + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 4px; + display: flex; + flex-direction: column; + width: 80%; /* 모달 너비 */ + max-width: 600px; /* 최대 너비 */ +} + +.modal-header { + background-color: #f1f1f1; + padding: 8px; + text-align: right; +} + +.close-button { + background: none; + border: none; + font-size: 18px; + cursor: pointer; +} + +.modal-body { + padding: 16px; + flex-grow: 1; + overflow: auto; +} + +.search-popup-container { + margin-top: 10px; /* SearchPopup과 다른 내용 사이에 공간을 추가 */ +} diff --git a/src/pages/Popup/Modal.jsx b/src/pages/Popup/Modal.jsx new file mode 100644 index 000000000..199c47a41 --- /dev/null +++ b/src/pages/Popup/Modal.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { Rnd } from 'react-rnd'; +import './Modal.css'; + +const Modal = ({ + isOpen, + onClose, + children, + initialWidth = 400, + initialHeight = 300, + initialX = 50, + initialY = 50, +}) => { + if (!isOpen) return null; + + return ( +
+ +
+
+ +
+
+ {children} {/* children에 SearchPopup 포함 */} +
+
+
+
+ ); +}; + +export default Modal; diff --git a/src/pages/Popup/Popup.jsx b/src/pages/Popup/Popup.jsx index d0dff8efc..0d4eb3764 100644 --- a/src/pages/Popup/Popup.jsx +++ b/src/pages/Popup/Popup.jsx @@ -1,9 +1,12 @@ -import React from 'react'; +import React, { useState } from 'react'; import logo from '../../assets/img/logo.svg'; -import Greetings from '../../containers/Greetings/Greetings'; +import Modal from './Modal'; +import SearchPopup from './SearchPopup'; // SearchPopup 컴포넌트 import import './Popup.css'; const Popup = () => { + const [isModalOpen, setIsModalOpen] = useState(false); + return (
@@ -19,7 +22,22 @@ const Popup = () => { > Learn React! +
+ + {/* Modal이 열릴 때만 렌더링 */} + setIsModalOpen(false)}> +

Resizable & Draggable Modal

+

+ 이 모달은 크기와 위치를 조정할 수 있습니다. 원하는 대로 드래그하거나 + 모서리를 잡고 크기를 조절하세요. +

+ + {/* 여기에서 SearchPopup을 추가 */} +
+ +
+
); }; diff --git a/src/pages/Popup/SearchPopup.css b/src/pages/Popup/SearchPopup.css new file mode 100644 index 000000000..8d9dc6522 --- /dev/null +++ b/src/pages/Popup/SearchPopup.css @@ -0,0 +1,39 @@ +.search-popup { + width: 300px; + padding: 10px; + display: flex; + flex-direction: column; + gap: 8px; + } + + .search-popup input { + padding: 8px; + font-size: 14px; + } + + .search-popup button { + padding: 8px; + background-color: #007bff; + color: white; + border: none; + cursor: pointer; + } + + .search-popup button:hover { + background-color: #0056b3; + } + + .search-result { + margin-top: 10px; + } + + .search-result ul { + list-style: none; + padding: 0; + } + + .search-result li { + padding: 5px; + border-bottom: 1px solid #ddd; + } + \ No newline at end of file diff --git a/src/pages/Popup/SearchPopup.jsx b/src/pages/Popup/SearchPopup.jsx new file mode 100644 index 000000000..5ac98ca5c --- /dev/null +++ b/src/pages/Popup/SearchPopup.jsx @@ -0,0 +1,61 @@ +import React, { useState } from "react"; +import "./SearchPopup.css"; // 스타일 적용 + +const SearchPopup = () => { + const [query, setQuery] = useState(""); + const [results, setResults] = useState([]); + const [loading, setLoading] = useState(false); + + const handleSearch = async () => { + if (!query.trim()) return; // 빈 입력 방지 + setLoading(true); + + try { + const response = await fetch( + `https://stdict.korean.go.kr/api/search.do?key=714604C8E02994906103C78E5E65B254&q=${query}&req_type=json` + ); + const data = await response.json(); + + if (data.channel && data.channel.item) { + setResults(data.channel.item); + } else { + setResults([]); + } + } catch (error) { + console.error("API 요청 중 오류 발생:", error); + setResults([]); + } finally { + setLoading(false); + } + }; + + return ( +
+ setQuery(e.target.value)} + /> + + + {loading &&

검색 중...

} + +
+ {results.length > 0 ? ( + + ) : ( + !loading &&

검색 결과가 없습니다.

+ )} +
+
+ ); +}; + +export default SearchPopup; diff --git a/src/pages/Popup/index.css b/src/pages/Popup/index.css index 800a9cb82..29904bf4b 100644 --- a/src/pages/Popup/index.css +++ b/src/pages/Popup/index.css @@ -1,6 +1,6 @@ body { - width: 300px; - height: 260px; + width: 500px; + height: 900px; margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', diff --git a/webpack.config.js b/webpack.config.js index c8a142da0..0f007830f 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -169,7 +169,7 @@ var options = { new CopyWebpackPlugin({ patterns: [ { - from: 'src/assets/img/icon-128.png', + from: 'src/assets/img/icon.png', to: path.join(__dirname, 'build'), force: true, }, @@ -178,7 +178,7 @@ var options = { new CopyWebpackPlugin({ patterns: [ { - from: 'src/assets/img/icon-34.png', + from: 'src/assets/img/icon.png', to: path.join(__dirname, 'build'), force: true, },