From 1c4ccb367d8f97d150453e1982b897045f3c9aa1 Mon Sep 17 00:00:00 2001 From: Joe Muller <47997351+jtmuller5@users.noreply.github.com> Date: Sun, 17 Nov 2024 09:51:59 -0500 Subject: [PATCH] Initial commit --- .gitignore | 23 + README.md | 7 + dist/index.html | 1 + dist/js/background.js | 1 + dist/js/index.js | 2 + dist/js/index.js.LICENSE.txt | 39 + dist/js/options.js | 2 + dist/js/options.js.LICENSE.txt | 39 + dist/js/popup.js | 2 + dist/js/popup.js.LICENSE.txt | 39 + dist/js/sidepanel.js | 2 + dist/js/sidepanel.js.LICENSE.txt | 39 + dist/manifest.json | 17 + dist/options.html | 1 + dist/popup.html | 1 + dist/sidepanel.html | 1 + manifest.json | 17 + package-lock.json | 16682 ++++++++++++++++++++++++ package.json | 55 + postcss.config.js | 6 + public/favicon.ico | Bin 0 -> 3870 bytes public/index.html | 43 + public/logo192.png | Bin 0 -> 5347 bytes public/logo512.png | Bin 0 -> 9664 bytes public/manifest.json | 25 + public/robots.txt | 3 + src/App.css | 3 + src/App.test.tsx | 9 + src/App.tsx | 5 + src/app/background.ts | 5 + src/features/options/Options.tsx | 19 + src/features/options/index.tsx | 14 + src/features/popup/PopUp.tsx | 6 + src/features/popup/index.tsx | 14 + src/features/side_panel/SidePanel.tsx | 17 + src/features/side_panel/index.tsx | 14 + src/index.tsx | 14 + src/setupTests.ts | 5 + tailwind.config.js | 10 + tsconfig.json | 26 + webpack.config.js | 60 + 41 files changed, 17268 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 dist/index.html create mode 100644 dist/js/background.js create mode 100644 dist/js/index.js create mode 100644 dist/js/index.js.LICENSE.txt create mode 100644 dist/js/options.js create mode 100644 dist/js/options.js.LICENSE.txt create mode 100644 dist/js/popup.js create mode 100644 dist/js/popup.js.LICENSE.txt create mode 100644 dist/js/sidepanel.js create mode 100644 dist/js/sidepanel.js.LICENSE.txt create mode 100644 dist/manifest.json create mode 100644 dist/options.html create mode 100644 dist/popup.html create mode 100644 dist/sidepanel.html create mode 100644 manifest.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 public/favicon.ico create mode 100644 public/index.html create mode 100644 public/logo192.png create mode 100644 public/logo512.png create mode 100644 public/manifest.json create mode 100644 public/robots.txt create mode 100644 src/App.css create mode 100644 src/App.test.tsx create mode 100644 src/App.tsx create mode 100644 src/app/background.ts create mode 100644 src/features/options/Options.tsx create mode 100644 src/features/options/index.tsx create mode 100644 src/features/popup/PopUp.tsx create mode 100644 src/features/popup/index.tsx create mode 100644 src/features/side_panel/SidePanel.tsx create mode 100644 src/features/side_panel/index.tsx create mode 100644 src/index.tsx create mode 100644 src/setupTests.ts create mode 100644 tailwind.config.js create mode 100644 tsconfig.json create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d29575 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/README.md b/README.md new file mode 100644 index 0000000..81d63e5 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Build a Chrome Extension With React, TypeScript, and Tailwind + +This repository demonstrates how to create a Chrome extension using React, TypeScript, TailwindCSS, and Webpack. + +More details can be found in this blog post: + +https://joemuller.com/posts/create-a-chrome-extension-with-react-typescript-and-tailwindcss/ \ No newline at end of file diff --git a/dist/index.html b/dist/index.html new file mode 100644 index 0000000..75f7246 --- /dev/null +++ b/dist/index.html @@ -0,0 +1 @@ +
&*j;=u%25ay-%>3@81tGe^_z*C7pb9y*Ed^H3t$BIKH2o+olp#$q;)_ zfpjCb_^VFg5fU~K)nf*d*r@BCC>UZ!0&b?AGk_jTPXaSnCuW110wjHPPe^9R^;jo3 zwvzTl)C`Zl5}O2}3lec=hZ*$JnkW#7enKKc)(pM${_$9Hc=Sr_A9Biwe*Y=T?~1CK z6eZ9uPICjy-sMGbZl$yQmpB&`ouS8v{58__t0$JP%i3R&%QR3ianbZqDs<2#5FdN@n5bCn^ZtH992~5k(eA|8|@G9u`wdn7bnpg|@{m z^d6Y`*$Zf2Xr&|g%sai#5}Syvv(>Jnx&EM7-|Jr7!M~zdAyjt*xl;OLhvW-a%H1m0 z*x5*nb=R5u><7lyVpN AR?q@1U59 zO+)QW wL8t zyip?u_nI+K$uh{ y)~}qj?(w0&=SE^8`_WMM zTybjG=999h38Yes7}-4*LJ7H)UE8{mE(6;8voE+TYY%33A>S6`G_95^5QHNTo_;Ao ztIQIZ_}49%{8|=O;isBZ?=7kfdF8_@azfoTd+hEJKWE!)$)N%HIe2cplaK`ry#=pV z0q{9w-`i0h@!R8K3GC{ivt{70IWG`EP |(1g7i_Q<>aEAT{5( yD z=!O?kq61VegV+st@XCw475j6vS)_z@efuqQgHQR1T4;|-#OLZNQJPV4k$AX1Uk8Lm z{N*b*ia=I+MB}kWpupJ~>!C@xEN#Wa7V+7{m4j8c?)ChV=D?o~sjT?0C_AQ 7B-vxqX30s0I_`2$in86#`mAsT-w?j{&AL@B3$;P z31G4(lV|b}uSD CIrjk+M1R!X7s 4Aabn<)zpgT}#gE|mIvV38^ODy@<&yflpCwS#fRf9ZX3lPV_?8@C5)A;T zqmouFLFk;qIs4rA=hh=GL~sCFsXHsqO6_y~*AFt93 9UYVBSx1s(=Kb&5;j7cSowdE;7()CC2|-i9Zz+_BIw8#ll~-tyH?F3{%`QCsYa*b#s*9iCc`1P1oC26?`g<9))EJ3%xz+O!B3 zZ7$j~To)C@PquR>a1+Dh>-a%IvH_Y7^ys|4o?E%3`I&ADXfC8++hAdZfzIT#%C+Jz z1lU~K_vAm0m8Qk}K$F>| >RPK%<1SI0(G+8q~H zAsjezyP+u!Se4q3GW)`h`NPSRlMoBjCzNPesWJwVTY!o@G8=(6I%4XHGaSiS3MEBK zhgGFv6Jc>L$4jVE!I?TQuwvz_%CyO!bLh94nqK11C2W$*aa2ueGopG8DnBICVUORP zgytv#)49fVXDaR$SukloYC3u7#5H)}1K21=?DKj^U)8G;MS)&Op)g^zR2($<>C*zW z;X7`hLxiIO#J`ANdyAOJle4V%ppa*(+0i3w;8i*BA_;u8gOO6)MY`ueq7stBMJTB; z-a0R>hT*}>z|Gg}@^zDL1MrH+2hsR8 zHc}*9IvuQC^Ju)^#Y{fOr(96rQNPNhxc;mH@W*m206>Lo<*SaaH?~8zg&f&%YiOEG zGiz?*CP>Bci}!WiS=zj#K5I}>DtpregpP_tfZtPa(N<%vo^#WCQ5BTv0vr%Z{)0q+ z)RbfHktUm|lg&U3YM%lMUM(f u}i#kjX9h>GYctkx9Mt_8{@s%!K_EI zScgwy6%_fR?CG JQtmgNAj^h9B#zma MDWgH55pGuY1Gv7D z;8Psm(vEPiwn#MgJYu4Ty9D|h!?Rj0ddE|&L3S{IP%H4^N!m`60ZwZw^;eg4sk6K{ ziA^`Sbl_4~f&Oo%n;8Ye(tiAdlZKI!Z=|j$5hS|D$bDJ}p{gh$KN&JZYLUjv4h{NY zBJ>X9z !xfDGY z+oh_Z&_e#Q(-}>ssZfm=j$D&4W4FNy&-kAO1~#3Im;F)Nwe{(*75(p=P^VI?X 0GFakfh+X-px4a%Uw@fSbmp9hM1_~R>?Z8+ ziy|e9>8V*`OP}4x5JjdWp}7eX;lVxp5qS} 0YZek;SNmm7tEeSF*-dI)6U-A%m6YvCgM(}_=k#a6o^%-K4{`B1+}O4x zztDT%hVb;v#?j`lTvlFQ3aV#zkX=7 ;YFLS$uIzb0E3lozs5`Xy zi~vF+%{z9uLjKvKPhP%x5f ~7-Gj+%5N`%^=yk*Qn{`> z;xj&ROY6g`iy2a@{O)V(jk&8#hHACVDXey5a+KDod_Z&}kHM}xt7}Md@pil{2x7E~ zL$k^d2@Ec2XskjrN+IILw;#7((abu;OJii&v3?60x>d_Ma(onIPtcVnX@ELF0aL?T zSmWiL3(dOFkt!x=1O!_0n(cAzZW+3nHJ{2S>tgSK?~cF ha^y(l@-Mr2W$%MN{#af8J;V*>hdq!gx=d0h$T7l}>91Wh07)9CTX zh2_ZdQCyFOQ)l(}gft0UZ G`Sh2`x-w`5vC2UD}lZs*5 zG76$akzn}Xi))L3oGJ75#pcN=cX3!=57$Ha=hQ2^lwdyU#a}4JJOz6ddR%zae%#4& za)bFj)z=YQela(F#Y|Q#dp}PJghITwXouVaMq$BM?K%cXn9^Y@g43$=O)F&ZlOUom zJiad#dea;-eywBA@e&D6Pdso1?2^(pXiN91?jvcaUyYoKUmvl5G9e$W!okWe*@a<^ z8cQQ6cNSf+UPDx%?_G4a IiybZHHagF{ ;IcD(dPO!#=u zWfqLcPc^+7Uu#l(B pxft{*4lv#*u7X9AOzDO z1D9?^jIo}?%iz(_dwLa{ex#T}76ZfN_Z-hwpus9y+4xaUu9cX}&P{XrZVWE{1^0yw zO;YhLEW!pJcbCt3L8~a7>jsaN{V3>tz6_7`&pi%GxZ=V3?3K^ U+*ryLSb)8^IblJ0 zSRLNDvIxt)S}g30?s_3NX>F?NKIGrG_zB9@Z>uSW3k2es_H2kU;Rnn%j5qP)!XHKE zPB2mHP~tLCg4K_vH$xv`HbRsJwbZMUV(t=ez;Ec(vyHH)FbfLg`c61I$W_uBB>i^r z&{_P;369-&>23R%qNIULe=1~T$(DA`ev*EWZ6j(B$(te}x1WvmIll21zvygkS%vwG zzkR6Z#RKA2!z!C%M!O>!=Gr0(J0FP=-MN=5t-Ir)of50y10W}j`GtRCsXBakrKtG& zazmITDJMA0C51&BnLY)SY9r)NVTMs);1<=oosS9g31l{4ztjD3#+2H7u_|66b|_*O z;Qk6nalpqdHOjx|K&vUS_6ITgGll;TdaN*ta=M_YtyC)I9Tmr~VaPrH2q b6sd~=AcIxV+%z{E&0@y=DPArw zdV7z(G1hBx7hd{>(cr43^WF%4Y@PXZ?wPpj{OQ#tvc$pABJbvPGvdR`cAtHn)cSEV zrpu}1tJwQ3y!mSmH*uz*x0o|CS<^w%&KJzsj~DU0cLQUxk5B!hWE>aBkjJle8z~;s z-!A=($+}Jq_BTK5^B!`R>!MulZN)F=iXXeUd0w5lUsE5VP*H*oCy( ;?S$p*TVvTxwAeWFB$jHyb0593)$zqalVlDX=GcCN1gU0 zlgU)I$LcXZ8Oyc2TZYTPu@-;7<4YYB-``Qa;IDcvydIA$%kHhJKV^m*- zxcvU4viy &Kr5GVM{IT>WRywKQ9;>SEiQD*NqplK-KK4YR`p0@JW)n_{TU3bt0 zim%;(m1=#v2}zTps=?fU5w^(*y)xT%1vtQH&}50ZF!9YxW=&7*W($2kgKyz1mUgfs zfV<*XVVIFnohW=|j+@Kfo!#liQR^x>2yQdrG;2o8WZR+XzU_nG=Ed2rK?ntA;K5B{ z>M8+*A4 !Jm^Bg}aW?R?6;@QG@uQ8&oJ{hFixcfEnJ4QH?A4>P=q29oDGW;L;= z9-a0;g%c`C+Ai!UmK$NC*4#;Jp<1=TioL=t^YM)<<%u#hnnfSS`nq63QKGO1L8RzX z@MFDq s1z ztYmxDl@LU)5acvHk)~Z`RW7=aJ_nGD!mOSYD>5Odjn@TK#LY{jf?+piB5AM-CAoT_ z?S-*q7}wyLJzK>N%eMPuFgN)Q_otKP;aqy=D5f! 7<=n(lNkYRXVpkB{TAYLYg{|(jtRqYmg$xH zjmq ?B(RE4 zQx^~Pt}gxC2~l=K$$-sYy_r$CO(d=+b3H1MB*y_5g6WLaWTXn+TKQ|hNY^>Mp6k*$ zwkovomhu776vQATqT4blf~g;TY(MWCrf^^yfWJvSAB$p5l;jm@o#=!lqw+Lqfq>X= z$6~kxfm7`3q4zUEB;u4qa#BdJxO!;xGm)wwuisj{0y2x{R(IGMrsIzDY9LW>m!Y`= z04sx3IjnYvL<4JqxQ8f7qYd0s2Ig%`ytYPEMKI)s(LD}D@EY>x`VFtqvnADNBdeao zC96X+MxnwKmjpg{U&gP3HE}1=s!lv&D{6(g_lzyF3A`7Jn*&d_kL<;dAFx!UZ>hB8 z5A*%LsAn;VLp>3${0>M?PSQ)9s3}|h2e?TG4_F{}{Cs>#3Q*t$(CUc}M)I}8cPF6% z=+h(Kh^8)}gj(0}#e7O^FQ6`~fd1#8#!}LMuo3A0bN`o}PYsm!Y}sdOz$+Tegc=qT z8x`PH$7lvnhJp{kHWb22l;@7B7|4yL4UOOVM0MP_>P%S1Lnid)+k9{+3D+JFa#Pyf zhVc#&df87APl4W9X)F3pGS>@etfl=_E5tBcVoOfrD4hmVeTY-cj((pkn%n@EgN{0f zwb_^Rk0I#i ZuHK!l*lN`ceJn(sI{$Fq6nN& zE<-=0_2WN}m+*ivmIOxB@#~Q-cZ>l136w{#TIJe478`KE7@=a{>SzPHsKLzYAyBQO zAtuuF$-JSDy_S@6GW0MOE~R)b;+0f%_NMrW(+V#c_d&U8Z9+ec4=HmOHw?gdjF(Lu zzra 83M_BoO-1b3;9`%&DHfuUY)6YDV21P$C!Rc?mv&{lx#f8oc6?0?x zK08{WP65?#>(vPfA-c=MCY| %*1_<3D4NX zeVTi-JGl2uP_2@0F{G({pxQOXt_d{g_CV6b?jNpfUG9;8yle-^4KHRvZs-_2siata zt+d_T@U$&t*xaD22(fH(W1r$Mo?3dc%Tncm=C6{V9y{v&VT#^1L04vDrLM9qBoZ4@ z6DBN#m57hX7$C(=#$Y5$bJmwA$T8jKD8+6A!-IJwA{WOfs%s}yxUw^?MRZjF$n_KN z6`_bGXcmE#5e4Ym)aQJ)xg3Pg0@k`iGuHe?f(5LtuzSq=nS^5z>vqU0EuZ&75V%Z{ zYyhRLN^)$c6Ds{f7*FBpE;n5iglx5PkHfWrj3`x^j^t z7ntuV`g!9Xg#^3!x)l*}IW=(Tz3>Y5l4uGaB&lz{GDjm2D5S$CExLT`I1#n^lBH7Y zDgpMag@`iETKAI=p<5E#LTkw zVR@=yY|uBVI1HG|8h+d;G-qfuj}-ZR6fN>EfCCW z9~wRQoAPEa#aO?3h?x{YvV*d+NtPkf&4V0k4|L=uj!U{L+oLa(z#&iuhJr3-PjO3R z5s?=nn_5^*^Rawr>>Nr@K(jwkB#JK-=+HqwfdO<+P5byeim)wvqGlP-P|~Nse8=XF zz`?RYB|D6SwS}C+YQv+;}k6$-%D(@+t14BL@vM z2q%q?f6D-A5s$_WY3{^G0F131bbh|g!}#BKw=HQ7mx;Dzg4Z*bTLQSfo{ed{4}NZW zfrRm^Ca$rlE{Ue~uYv>R9{3s mwATcdM_6+yWIO z*ZRH~uXE@#p$XTbCt5j7j2=86e{9>HIB6xDzV+vAo&B?KUiMP|ttOElepnl%|DPqL b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN literal 0 HcmV?d00001 diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/src/App.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/src/App.test.tsx b/src/App.test.tsx new file mode 100644 index 0000000..2a68616 --- /dev/null +++ b/src/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render( ); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..2f349fd --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,5 @@ +function App() { + return Hello World; +} + +export default App; diff --git a/src/app/background.ts b/src/app/background.ts new file mode 100644 index 0000000..6263e18 --- /dev/null +++ b/src/app/background.ts @@ -0,0 +1,5 @@ +chrome.runtime.onInstalled.addListener(() => { + chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }); +}); + +export {} \ No newline at end of file diff --git a/src/features/options/Options.tsx b/src/features/options/Options.tsx new file mode 100644 index 0000000..07557d1 --- /dev/null +++ b/src/features/options/Options.tsx @@ -0,0 +1,19 @@ +function Options() { + const sendMessage = () => { + chrome.runtime.sendMessage( + { type: "UPDATE_FROM_OPTIONS", payload: "Hello SidePanel" }, + (response) => { + console.log("Response from SidePanel:", response); + } + ); + }; + + return ( ++ Options + ++ ); +} + +export default Options; diff --git a/src/features/options/index.tsx b/src/features/options/index.tsx new file mode 100644 index 0000000..e521ab4 --- /dev/null +++ b/src/features/options/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import "../../App.css"; +import Options from './Options'; + +const root = document.createElement("div") +root.className = "container" +document.body.appendChild(root) +const rootDiv = ReactDOM.createRoot(root); +rootDiv.render( ++ +); diff --git a/src/features/popup/PopUp.tsx b/src/features/popup/PopUp.tsx new file mode 100644 index 0000000..1842204 --- /dev/null +++ b/src/features/popup/PopUp.tsx @@ -0,0 +1,6 @@ +function PopUp() { + return+ Pop Up; + } + + export default PopUp; + \ No newline at end of file diff --git a/src/features/popup/index.tsx b/src/features/popup/index.tsx new file mode 100644 index 0000000..a388e6d --- /dev/null +++ b/src/features/popup/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import "../../App.css"; +import PopUp from './PopUp'; + +const root = document.createElement("div") +root.className = "container" +document.body.appendChild(root) +const rootDiv = ReactDOM.createRoot(root); +rootDiv.render( ++ +); diff --git a/src/features/side_panel/SidePanel.tsx b/src/features/side_panel/SidePanel.tsx new file mode 100644 index 0000000..4bfe3f0 --- /dev/null +++ b/src/features/side_panel/SidePanel.tsx @@ -0,0 +1,17 @@ +import { useEffect } from "react"; + +function SidePanel() { + useEffect(() => { + chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.type === "UPDATE_FROM_OPTIONS") { + // Handle the message + console.log("Received message in SidePanel:", message.payload); + sendResponse({ status: "Received by SidePanel" }); + } + }); + }, []); + + return+ Side Panel; +} + +export default SidePanel; diff --git a/src/features/side_panel/index.tsx b/src/features/side_panel/index.tsx new file mode 100644 index 0000000..8d6daf5 --- /dev/null +++ b/src/features/side_panel/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import SidePanel from './SidePanel'; +import "../../App.css"; + +const root = document.createElement("div") +root.className = "container" +document.body.appendChild(root) +const rootDiv = ReactDOM.createRoot(root); +rootDiv.render( ++ +); diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..30b24df --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import "./App.css"; + +const root = document.createElement("div") +root.className = "container" +document.body.appendChild(root) +const rootDiv = ReactDOM.createRoot(root); +rootDiv.render( ++ + +); \ No newline at end of file diff --git a/src/setupTests.ts b/src/setupTests.ts new file mode 100644 index 0000000..8f2609b --- /dev/null +++ b/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..9b5bf07 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,10 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./src/**/*.{js,jsx,ts,tsx,html}", // Adjust this path based on your project structure + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a273b0c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..a58bc05 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,60 @@ +const path = require("path"); +const HTMLPlugin = require("html-webpack-plugin"); +const CopyPlugin = require("copy-webpack-plugin"); + +module.exports = { + entry: { + index: "./src/index.tsx", + background: "./src/app/background.ts", + sidepanel: "./src/features/side_panel/index.tsx", + options: "./src/features/options/index.tsx", + popup: "./src/features/popup/index.tsx", + }, + mode: "production", + module: { + rules: [ + { + test: /\.tsx?$/, + use: [ + { + loader: "ts-loader", + options: { + compilerOptions: { noEmit: false }, + }, + }, + ], + exclude: /node_modules/, + }, + { + exclude: /node_modules/, + test: /\.css$/i, + use: ["style-loader", "css-loader", "postcss-loader"], + }, + ], + }, + plugins: [ + new CopyPlugin({ + patterns: [{ from: "manifest.json", to: "manifest.json" }], // Adjusted path + }), + ...getHtmlPlugins(["index", "sidepanel", "options", "popup"]), + ], + resolve: { + extensions: [".tsx", ".ts", ".js"], + }, + output: { + path: path.join(__dirname, "dist"), + filename: "js/[name].js", + publicPath: "/", + }, +}; + +function getHtmlPlugins(chunks) { + return chunks.map( + (chunk) => + new HTMLPlugin({ + title: "React extension", + filename: `${chunk}.html`, + chunks: [chunk], + }) + ); +}+