diff --git a/projects/web-filter/public/sample-image.png b/projects/web-filter/public/sample-image.png new file mode 100644 index 0000000..3e102a8 Binary files /dev/null and b/projects/web-filter/public/sample-image.png differ diff --git a/projects/web-filter/src/assets/sample-image.png b/projects/web-filter/src/assets/sample-image.png new file mode 100644 index 0000000..3e102a8 Binary files /dev/null and b/projects/web-filter/src/assets/sample-image.png differ diff --git a/projects/web-filter/src/components/Button/Button.module.css b/projects/web-filter/src/components/Button/Button.module.css new file mode 100644 index 0000000..d6498f2 --- /dev/null +++ b/projects/web-filter/src/components/Button/Button.module.css @@ -0,0 +1,26 @@ +.Button { + padding: 7px 18px; + font-size: 11px; + line-height: 120%; + border-radius: 100px; + transition: 0.1s ease; + cursor: pointer; +} + +/* theme */ +.Button.blue { + color: white; + background-color: rgba(11, 153, 255, 1); +} +.Button.gray { + color: rgba(78, 78, 78, 1); + background-color: rgba(180, 180, 180, 1); +} + +/* interaction */ +.Button:hover { + opacity: 0.7; +} +.Button:active { + opacity: 0.5; +} diff --git a/projects/web-filter/src/components/Button/Button.tsx b/projects/web-filter/src/components/Button/Button.tsx new file mode 100644 index 0000000..3e7eeca --- /dev/null +++ b/projects/web-filter/src/components/Button/Button.tsx @@ -0,0 +1,13 @@ +import { PropsWithChildren } from 'react'; + +import styles from './Button.module.css'; + +type ButtonProps = PropsWithChildren<{ + theme?: 'blue' | 'gray'; +}>; + +export const Button = ({ children, theme = 'blue' }: ButtonProps) => { + return ( + + ); +}; diff --git a/projects/web-filter/src/components/Header/Header.module.css b/projects/web-filter/src/components/Header/Header.module.css new file mode 100644 index 0000000..3d6ebc2 --- /dev/null +++ b/projects/web-filter/src/components/Header/Header.module.css @@ -0,0 +1,15 @@ +.Header { + padding-left: 21px; + padding-right: 14px; + flex: 0 0 51px; + display: flex; + align-items: center; +} + +.title { + flex: 1 1 auto; + font-size: 17px; + font-weight: 400; + line-height: 20px; + color: white; +} diff --git a/projects/web-filter/src/components/Header/Header.tsx b/projects/web-filter/src/components/Header/Header.tsx new file mode 100644 index 0000000..d1825d6 --- /dev/null +++ b/projects/web-filter/src/components/Header/Header.tsx @@ -0,0 +1,9 @@ +import styles from './Header.module.css'; + +export const Header = () => { + return ( +
+

SVG filter for Web

+
+ ); +}; diff --git a/projects/web-filter/src/content-old.tsx b/projects/web-filter/src/content-old.tsx new file mode 100644 index 0000000..0fae40c --- /dev/null +++ b/projects/web-filter/src/content-old.tsx @@ -0,0 +1,20 @@ +import { createRoot } from 'react-dom/client'; + +import { WaveFilter } from './filters/WaveFilter'; + +const app = document.createElement('div'); + +app.id = 'web-filter-app'; +app.style.display = 'none'; + +document.body.appendChild(app); + +createRoot(app).render( + + + + + , +); + +document.body.style.filter = 'url(#filter)'; diff --git a/projects/web-filter/src/content.tsx b/projects/web-filter/src/content.tsx index 0fae40c..b1b6ea9 100644 --- a/projects/web-filter/src/content.tsx +++ b/projects/web-filter/src/content.tsx @@ -1,20 +1,3 @@ -import { createRoot } from 'react-dom/client'; +import { popup } from './functions/popup'; -import { WaveFilter } from './filters/WaveFilter'; - -const app = document.createElement('div'); - -app.id = 'web-filter-app'; -app.style.display = 'none'; - -document.body.appendChild(app); - -createRoot(app).render( - - - - - , -); - -document.body.style.filter = 'url(#filter)'; +popup.open(); diff --git a/projects/web-filter/src/functions/constant.ts b/projects/web-filter/src/functions/constant.ts new file mode 100644 index 0000000..01f3116 --- /dev/null +++ b/projects/web-filter/src/functions/constant.ts @@ -0,0 +1 @@ +export const POPUP_ID = 'web-filter-popup'; diff --git a/projects/web-filter/src/functions/popup.tsx b/projects/web-filter/src/functions/popup.tsx new file mode 100644 index 0000000..a165fba --- /dev/null +++ b/projects/web-filter/src/functions/popup.tsx @@ -0,0 +1,17 @@ +import { createRoot } from 'react-dom/client'; + +import { Popup } from '../pages/Popup/Popup'; +import { POPUP_ID } from './constant'; + +// open & close + +const open = () => { + if (document.querySelector(`#${POPUP_ID}`) !== null) return; + const app = document.createElement('div'); + app.id = POPUP_ID; + document.body.appendChild(app); + createRoot(app).render(); +}; +const close = () => document.querySelector(`#${POPUP_ID}`)?.remove(); + +export const popup = { open, close }; diff --git a/projects/web-filter/src/functions/popupNative.tsx b/projects/web-filter/src/functions/popupNative.tsx new file mode 100644 index 0000000..a0f0aaf --- /dev/null +++ b/projects/web-filter/src/functions/popupNative.tsx @@ -0,0 +1,5 @@ +import { createRoot } from 'react-dom/client'; + +import { PopupNative } from '../pages/PopupNative/PopupNative'; + +createRoot(document.body).render(); diff --git a/projects/web-filter/src/manifest-content.json b/projects/web-filter/src/manifest-content.json new file mode 100644 index 0000000..ba2c6ab --- /dev/null +++ b/projects/web-filter/src/manifest-content.json @@ -0,0 +1,21 @@ +{ + "{{chrome}}.manifest_version": 3, + "{{firefox}}.manifest_version": 2, + "icons": { + "16": "icon/16.png", + "32": "icon/32.png", + "48": "icon/48.png", + "96": "icon/96.png", + "128": "icon/128.png" + }, + "background": { + "{{chrome}}.service_worker": "src/background.ts", + "{{firefox}}.scripts": ["src/background.ts"] + }, + "content_scripts": [ + { + "matches": [""], + "js": ["src/content.tsx"] + } + ] +} diff --git a/projects/web-filter/src/manifest-native.json b/projects/web-filter/src/manifest-native.json new file mode 100644 index 0000000..40e518a --- /dev/null +++ b/projects/web-filter/src/manifest-native.json @@ -0,0 +1,21 @@ +{ + "{{chrome}}.manifest_version": 3, + "{{firefox}}.manifest_version": 2, + "icons": { + "16": "icon/16.png", + "32": "icon/32.png", + "48": "icon/48.png", + "96": "icon/96.png", + "128": "icon/128.png" + }, + "{{chrome}}.action": { + "default_popup": "src/popup.html" + }, + "{{firefox}}.browser_action": { + "default_popup": "src/popup.html" + }, + "background": { + "{{chrome}}.service_worker": "src/background.ts", + "{{firefox}}.scripts": ["src/background.ts"] + } +} diff --git a/projects/web-filter/src/pages/Popup.css b/projects/web-filter/src/pages/Popup.css deleted file mode 100644 index 1665040..0000000 --- a/projects/web-filter/src/pages/Popup.css +++ /dev/null @@ -1,33 +0,0 @@ -div { - height: 100%; - display: flex; - flex-direction: column; - gap: 16px; - align-items: center; - justify-content: center; -} - -img { - width: 200px; - height: 200px; -} - -h1 { - font-size: 18px; - color: white; - font-weight: bold; - margin: 0; -} - -p { - color: white; - opacity: 0.7; - margin: 0; -} - -code { - font-size: 12px; - padding: 2px 4px; - background-color: #ffffff24; - border-radius: 2px; -} diff --git a/projects/web-filter/src/pages/Popup/Popup.module.css b/projects/web-filter/src/pages/Popup/Popup.module.css new file mode 100644 index 0000000..b893ae9 --- /dev/null +++ b/projects/web-filter/src/pages/Popup/Popup.module.css @@ -0,0 +1,71 @@ +.Popup { + position: fixed; + top: 4px; + right: 8px; + width: 355px; + height: 451px; + background-color: rgba(17, 17, 17, 1); + border-radius: 16px; + z-index: 99999; + box-shadow: 3px 3px 11px rgba(0, 0, 0, 0.3); + display: flex; + flex-direction: column; + animation: open 0.3s ease; +} + +.Popup .slider { + display: flex; + overflow-x: auto; + overflow-y: hidden; +} +.Popup .filterList { + display: flex; + padding: 12px 16px; + gap: 9px; +} +.Popup .filterItem { + display: flex; + flex-direction: column; + align-items: center; + width: 73px; + gap: 6px; + transition: 0.1s ease; + cursor: pointer; +} +.Popup .filterItem:hover { + opacity: 0.7; +} +.Popup .filterItem:active { + opacity: 0.5; +} +.Popup .filterItem img { + width: 100%; +} +.Popup .filterName { + font-size: 10px; + color: white; + font-weight: 400; +} + +.Popup .divider { + background-color: rgba(51, 51, 51, 1); + height: 1px; + margin: 0 10px; +} +.Popup .footer { + padding: 17px 22px 22px 22px; + display: flex; + justify-content: flex-end; + gap: 9px; +} + +@keyframes open { + 0% { + opacity: 0; + transform: translateY(-10px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} diff --git a/projects/web-filter/src/pages/Popup/Popup.tsx b/projects/web-filter/src/pages/Popup/Popup.tsx new file mode 100644 index 0000000..e3eed38 --- /dev/null +++ b/projects/web-filter/src/pages/Popup/Popup.tsx @@ -0,0 +1,31 @@ +import sampleSrc from '../../assets/sample-image.png'; +// static folder 사용 불가능 +import { Button } from '../../components/Button/Button'; +import { Header } from '../../components/Header/Header'; +import styles from './Popup.module.css'; + +export const Popup = () => { + return ( +
+
+ +
+
+ {['적록색맹', '필름카메라', '유리창', '빛 번짐', '기타'].map( + (filterName) => ( +
+ +

{filterName}

+
+ ), + )} +
+
+
+
+ + +
+
+ ); +}; diff --git a/projects/web-filter/src/pages/PopupNative/PopupNative.module.css b/projects/web-filter/src/pages/PopupNative/PopupNative.module.css new file mode 100644 index 0000000..f57cd6d --- /dev/null +++ b/projects/web-filter/src/pages/PopupNative/PopupNative.module.css @@ -0,0 +1,62 @@ +.PopupNative { + display: flex; + flex-direction: column; + animation: open 0.3s ease; +} + +.PopupNative .slider { + display: flex; + overflow-x: auto; + overflow-y: hidden; +} +.PopupNative .filterList { + display: flex; + padding: 12px 16px; + gap: 9px; +} +.PopupNative .filterItem { + display: flex; + flex-direction: column; + align-items: center; + width: 73px; + gap: 6px; + transition: 0.1s ease; + cursor: pointer; +} +.PopupNative .filterItem:hover { + opacity: 0.7; +} +.PopupNative .filterItem:active { + opacity: 0.5; +} +.PopupNative .filterItem img { + width: 100%; +} +.PopupNative .filterName { + font-size: 10px; + color: white; + font-weight: 400; +} + +.PopupNative .divider { + background-color: rgba(51, 51, 51, 1); + height: 1px; + margin: 0 10px; +} +.PopupNative .footer { + padding: 17px 22px 22px 22px; + display: flex; + justify-content: flex-end; + gap: 9px; +} + +@keyframes open { + 0% { + opacity: 0; + transform: translateY(-10px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} diff --git a/projects/web-filter/src/pages/PopupNative/PopupNative.tsx b/projects/web-filter/src/pages/PopupNative/PopupNative.tsx new file mode 100644 index 0000000..27b4bfa --- /dev/null +++ b/projects/web-filter/src/pages/PopupNative/PopupNative.tsx @@ -0,0 +1,29 @@ +import { Button } from '../../components/Button/Button'; +import { Header } from '../../components/Header/Header'; +import styles from './PopupNative.module.css'; + +export const PopupNative = () => { + return ( +
+
+ +
+
+ {['적록색맹', '필름카메라', '유리창', '빛 번짐', '기타'].map( + (filterName) => ( +
+ +

{filterName}

+
+ ), + )} +
+
+
+
+ + +
+
+ ); +}; diff --git a/projects/web-filter/src/pages/PopupOld/Popup.css b/projects/web-filter/src/pages/PopupOld/Popup.css new file mode 100644 index 0000000..7e83038 --- /dev/null +++ b/projects/web-filter/src/pages/PopupOld/Popup.css @@ -0,0 +1,61 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} +html { + width: 460px; + height: 55px; + overflow: visible; +} +body { + position: relative; + width: 100%; + height: 100%; + background-color: transparent; +} +.container { + width: 100%; + height: 200px; + display: flex; + flex-direction: column; + background-color: rgba(17, 17, 17); + border-radius: 64px; +} + +.header { + flex: 0 0 66px; + background-color: blue; +} + +.page { + flex: 1 1 auto; + display: flex; + border-radius: 8px; + background-color: black; +} + +img { + width: 200px; + height: 200px; +} + +h1 { + font-size: 18px; + color: white; + font-weight: bold; + margin: 0; +} + +p { + color: white; + opacity: 0.7; + margin: 0; +} + +code { + font-size: 12px; + padding: 2px 4px; + /* background-color: #ffffff24; */ + border-radius: 2px; +} diff --git a/projects/web-filter/src/pages/Popup.tsx b/projects/web-filter/src/pages/PopupOld/Popup.tsx similarity index 81% rename from projects/web-filter/src/pages/Popup.tsx rename to projects/web-filter/src/pages/PopupOld/Popup.tsx index 09f3b72..e1fb377 100644 --- a/projects/web-filter/src/pages/Popup.tsx +++ b/projects/web-filter/src/pages/PopupOld/Popup.tsx @@ -8,7 +8,8 @@ export default function () { }, []); return ( -
+
+

Web Filter

by. Team Seoee - Interactive Study

diff --git a/projects/web-filter/src/popup.css b/projects/web-filter/src/popup.css index 37bcf5f..b4f047f 100644 --- a/projects/web-filter/src/popup.css +++ b/projects/web-filter/src/popup.css @@ -1,11 +1,20 @@ -html, -body { - width: 300px; - height: 400px; - padding: 0; +* { margin: 0; + padding: 0; + box-sizing: border-box; +} +button { + border: none; +} +html { + position: relative; + width: 355px; + height: 451px; } - body { - background-color: rgb(36, 36, 36); + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background-color: rgba(17, 17, 17, 1); } diff --git a/projects/web-filter/src/popup.html b/projects/web-filter/src/popup.html index 985fb72..2786c53 100644 --- a/projects/web-filter/src/popup.html +++ b/projects/web-filter/src/popup.html @@ -1,4 +1,4 @@ - + @@ -10,5 +10,5 @@ - + diff --git a/projects/web-filter/src/popup.tsx b/projects/web-filter/src/popup.tsx deleted file mode 100644 index 04d71f0..0000000 --- a/projects/web-filter/src/popup.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; - -import Popup from './pages/Popup'; - -createRoot(document.body).render( - - - , -); diff --git a/projects/web-filter/vite.config.ts b/projects/web-filter/vite.config.ts index c5cb244..641006a 100644 --- a/projects/web-filter/vite.config.ts +++ b/projects/web-filter/vite.config.ts @@ -3,7 +3,7 @@ import { defineConfig } from 'vite'; import webExtension, { readJsonFile } from 'vite-plugin-web-extension'; function generateManifest() { - const manifest = readJsonFile('src/manifest.json'); + const manifest = readJsonFile('src/manifest-native.json'); // "src/manifest-content.json"로 바꾸면 자체 팝업 사용 const pkg = readJsonFile('package.json'); return { name: pkg.name,