From d20cb3189d2169ecc7b52c078bfe813da4de96c1 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Wed, 13 Aug 2025 14:35:35 +0200 Subject: [PATCH 01/13] init preview example --- examples/nextjs/previews/.gitignore | 43 + examples/nextjs/previews/eslint.config.mjs | 20 + examples/nextjs/previews/jsconfig.json | 7 + examples/nextjs/previews/next.config.mjs | 6 + examples/nextjs/previews/package.json | 27 + examples/nextjs/previews/postcss.config.mjs | 5 + examples/nextjs/previews/public/favicon.ico | Bin 0 -> 25931 bytes .../previews/src/components/BlogPostItem.js | 32 + .../nextjs/previews/src/components/Header.js | 20 + .../nextjs/previews/src/components/Layout.js | 18 + .../previews/src/components/PreviewButton.js | 17 + .../previews/src/pages/[...identifier].js | 79 + examples/nextjs/previews/src/pages/_app.js | 10 + .../nextjs/previews/src/pages/_document.js | 13 + .../previews/src/pages/api/disable-preview.js | 7 + .../nextjs/previews/src/pages/api/preview.js | 53 + examples/nextjs/previews/src/pages/index.js | 111 ++ .../nextjs/previews/src/styles/globals.css | 137 ++ .../previews/src/utils/getAuthString.js | 5 + .../previews/src/wp-templates/archive.js | 38 + .../src/wp-templates/index-template.js | 33 + .../nextjs/previews/src/wp-templates/index.js | 19 + .../nextjs/previews/src/wp-templates/page.js | 24 + .../previews/src/wp-templates/single.js | 36 + pnpm-lock.yaml | 1330 ++++++++++++++++- 25 files changed, 2070 insertions(+), 20 deletions(-) create mode 100644 examples/nextjs/previews/.gitignore create mode 100644 examples/nextjs/previews/eslint.config.mjs create mode 100644 examples/nextjs/previews/jsconfig.json create mode 100644 examples/nextjs/previews/next.config.mjs create mode 100644 examples/nextjs/previews/package.json create mode 100644 examples/nextjs/previews/postcss.config.mjs create mode 100644 examples/nextjs/previews/public/favicon.ico create mode 100644 examples/nextjs/previews/src/components/BlogPostItem.js create mode 100644 examples/nextjs/previews/src/components/Header.js create mode 100644 examples/nextjs/previews/src/components/Layout.js create mode 100644 examples/nextjs/previews/src/components/PreviewButton.js create mode 100644 examples/nextjs/previews/src/pages/[...identifier].js create mode 100644 examples/nextjs/previews/src/pages/_app.js create mode 100644 examples/nextjs/previews/src/pages/_document.js create mode 100644 examples/nextjs/previews/src/pages/api/disable-preview.js create mode 100644 examples/nextjs/previews/src/pages/api/preview.js create mode 100644 examples/nextjs/previews/src/pages/index.js create mode 100644 examples/nextjs/previews/src/styles/globals.css create mode 100644 examples/nextjs/previews/src/utils/getAuthString.js create mode 100644 examples/nextjs/previews/src/wp-templates/archive.js create mode 100644 examples/nextjs/previews/src/wp-templates/index-template.js create mode 100644 examples/nextjs/previews/src/wp-templates/index.js create mode 100644 examples/nextjs/previews/src/wp-templates/page.js create mode 100644 examples/nextjs/previews/src/wp-templates/single.js diff --git a/examples/nextjs/previews/.gitignore b/examples/nextjs/previews/.gitignore new file mode 100644 index 000000000..f64000977 --- /dev/null +++ b/examples/nextjs/previews/.gitignore @@ -0,0 +1,43 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +package-lock.json \ No newline at end of file diff --git a/examples/nextjs/previews/eslint.config.mjs b/examples/nextjs/previews/eslint.config.mjs new file mode 100644 index 000000000..5165cec43 --- /dev/null +++ b/examples/nextjs/previews/eslint.config.mjs @@ -0,0 +1,20 @@ +import { FlatCompat } from "@eslint/eslintrc"; +import js from "@eslint/js"; +import { dirname } from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); + +const eslintConfig = [ + ...compat.config({ + extends: ["eslint:recommended", "next/core-web-vitals"], + }), +]; + +export default eslintConfig; diff --git a/examples/nextjs/previews/jsconfig.json b/examples/nextjs/previews/jsconfig.json new file mode 100644 index 000000000..b8d6842d7 --- /dev/null +++ b/examples/nextjs/previews/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/nextjs/previews/next.config.mjs b/examples/nextjs/previews/next.config.mjs new file mode 100644 index 000000000..d5456a15d --- /dev/null +++ b/examples/nextjs/previews/next.config.mjs @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +}; + +export default nextConfig; diff --git a/examples/nextjs/previews/package.json b/examples/nextjs/previews/package.json new file mode 100644 index 000000000..ea7058a46 --- /dev/null +++ b/examples/nextjs/previews/package.json @@ -0,0 +1,27 @@ +{ + "name": "@faustjs/nextjs-preview-example", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@faustjs/nextjs": "workspace:*", + "@faustjs/template-hierarchy": "workspace:*", + "graphql": "^16.11.0", + "graphql-tag": "^2.12.6", + "next": "15.2.4", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", + "eslint": "^9", + "eslint-config-next": "15.2.4", + "tailwindcss": "^4" + } +} diff --git a/examples/nextjs/previews/postcss.config.mjs b/examples/nextjs/previews/postcss.config.mjs new file mode 100644 index 000000000..c7bcb4b1e --- /dev/null +++ b/examples/nextjs/previews/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/examples/nextjs/previews/public/favicon.ico b/examples/nextjs/previews/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/examples/nextjs/previews/src/components/BlogPostItem.js b/examples/nextjs/previews/src/components/BlogPostItem.js new file mode 100644 index 000000000..58740f7f0 --- /dev/null +++ b/examples/nextjs/previews/src/components/BlogPostItem.js @@ -0,0 +1,32 @@ +import Link from "next/link"; + +export function BlogPostItem({ post }) { + const { title, date, excerpt, uri, featuredImage } = post ?? {}; + + return ( +
+ + + {featuredImage && ( + + )} + +

+ + {title} + +

+ +
+ + + Read more + +
+ ); +} diff --git a/examples/nextjs/previews/src/components/Header.js b/examples/nextjs/previews/src/components/Header.js new file mode 100644 index 000000000..d811ca3eb --- /dev/null +++ b/examples/nextjs/previews/src/components/Header.js @@ -0,0 +1,20 @@ +/* eslint-disable @next/next/no-html-link-for-pages */ +import Link from 'next/link'; + +export default function Header() { + return ( +
+
+
+ Headless +
+ + +
+
+ ); +} diff --git a/examples/nextjs/previews/src/components/Layout.js b/examples/nextjs/previews/src/components/Layout.js new file mode 100644 index 000000000..86172c15b --- /dev/null +++ b/examples/nextjs/previews/src/components/Layout.js @@ -0,0 +1,18 @@ +import { useRouter } from 'next/router'; +import Header from './Header'; +import PreviewButton from './PreviewButton'; + +export default function Layout({ children }) { + const router = useRouter(); + + return ( + <> +
+
+ {children} + + {router.isPreview && } +
+ + ); +} diff --git a/examples/nextjs/previews/src/components/PreviewButton.js b/examples/nextjs/previews/src/components/PreviewButton.js new file mode 100644 index 000000000..3c8a2122f --- /dev/null +++ b/examples/nextjs/previews/src/components/PreviewButton.js @@ -0,0 +1,17 @@ +import { useRouter } from "next/router"; + +export default function PreviewButton() { + const router = useRouter(); + + return ( +
+ Preview mode is on + + +
+ ); +} diff --git a/examples/nextjs/previews/src/pages/[...identifier].js b/examples/nextjs/previews/src/pages/[...identifier].js new file mode 100644 index 000000000..76dd4e5a4 --- /dev/null +++ b/examples/nextjs/previews/src/pages/[...identifier].js @@ -0,0 +1,79 @@ +import { getAuthString } from '@/utils/getAuthString'; +import availableTemplates from '@/wp-templates'; +import { + createDefaultClient, + setGraphQLClient, + uriToTemplate, +} from '@faustjs/nextjs/pages'; + +export default function Page(props) { + const { templateData } = props; + + const PageTemplate = availableTemplates[templateData?.template?.id]; + + return ; +} + +// Statically generate the pages, except for draft mode +// More info: https://nextjs.org/docs/pages/guides/draft-mode +export async function getStaticProps({ + params, + draftMode: isDraftModeEnabled, +}) { + // Send the authentication string only if draft mode is enabled + const headers = isDraftModeEnabled + ? { + Authorization: getAuthString(), + } + : null; + + const client = createDefaultClient( + process.env.NEXT_PUBLIC_WORDPRESS_URL, + headers, + ); + + setGraphQLClient(client); + + const uri = Array.isArray(params?.identifier) + ? '/' + params.identifier.join('/') + '/' + : '/'; + + const variables = isDraftModeEnabled + ? { + id: params.identifier?.[0], + isPreview: true, + } + : { uri }; + + try { + const templateData = await uriToTemplate({ + ...variables, + availableTemplates: Object.keys(availableTemplates), + wordpressUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL, + }); + + if ( + !templateData?.template?.id || + templateData?.template?.id === '404 Not Found' + ) { + return { notFound: true }; + } + + return { + props: { + uri, + templateData: JSON.parse(JSON.stringify(templateData)), + }, + }; + } catch (error) { + console.error('Error resolving template:', error); + return { notFound: true }; + } +} + +export async function getStaticPaths() { + return { + paths: [], + fallback: 'blocking', + }; +} diff --git a/examples/nextjs/previews/src/pages/_app.js b/examples/nextjs/previews/src/pages/_app.js new file mode 100644 index 000000000..af8ade7e2 --- /dev/null +++ b/examples/nextjs/previews/src/pages/_app.js @@ -0,0 +1,10 @@ +import Layout from '@/components/Layout'; +import '@/styles/globals.css'; + +export default function App({ Component, pageProps }) { + return ( + + + + ); +} diff --git a/examples/nextjs/previews/src/pages/_document.js b/examples/nextjs/previews/src/pages/_document.js new file mode 100644 index 000000000..628a7334c --- /dev/null +++ b/examples/nextjs/previews/src/pages/_document.js @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from "next/document"; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/examples/nextjs/previews/src/pages/api/disable-preview.js b/examples/nextjs/previews/src/pages/api/disable-preview.js new file mode 100644 index 000000000..fbaba41f5 --- /dev/null +++ b/examples/nextjs/previews/src/pages/api/disable-preview.js @@ -0,0 +1,7 @@ +export default async function handler(_, res) { + // This removes __prerender_bypass cookie + // More info: https://nextjs.org/docs/pages/guides/draft-mode#clear-the-draft-mode-cookie + res.setDraftMode({ enable: false }); + + return res.redirect("/"); +} diff --git a/examples/nextjs/previews/src/pages/api/preview.js b/examples/nextjs/previews/src/pages/api/preview.js new file mode 100644 index 000000000..f6dfd1f09 --- /dev/null +++ b/examples/nextjs/previews/src/pages/api/preview.js @@ -0,0 +1,53 @@ +import { getAuthString } from '@/utils/getAuthString'; +import { createDefaultClient, setGraphQLClient } from '@faustjs/nextjs/pages'; +import { gql } from 'graphql-tag'; +import { print } from 'graphql'; + +const GET_CONTENT = gql` + query GetNode($id: ID! = 0) { + contentNode(id: $id, idType: DATABASE_ID, asPreview: true) { + databaseId + } + } +`; + +export default async function handler(req, res) { + const { secret, id } = req.query; + + if (!id) { + return res.status(400).json({ message: 'No ID provided.' }); + } + + // Check if preview secret token exists and matches environment variable + if (secret !== process.env.WP_PREVIEW_SECRET) { + return res.status(401).json({ message: 'Secret token is invalid.' }); + } + + const client = createDefaultClient(process.env.NEXT_PUBLIC_WORDPRESS_URL, { + Authorization: getAuthString(), + }); + setGraphQLClient(client); + + const { data, error } = await client.request(print(GET_CONTENT), { + id, + }); + + if (error) { + console.error('Error fetching content:', error); + return res.status(500).json({ message: 'Error fetching content.' }); + } + + if (!data?.contentNode) { + return res.status(404).json({ + message: 'Content could not be found. Verify your authentication method.', + }); + } + + // Enable draft mode + // More info: https://nextjs.org/docs/pages/guides/draft-mode#step-1-create-and-access-the-api-route + res.setDraftMode({ enable: true }); + + // Redirect with the databaseId retrieved from the query to prevent redirect at + // More info: https://developers.google.com/search/blog/2009/01/open-redirect-urls-is-your-site-being + res.redirect('/' + data?.contentNode?.databaseId); +} diff --git a/examples/nextjs/previews/src/pages/index.js b/examples/nextjs/previews/src/pages/index.js new file mode 100644 index 000000000..98bc6ad75 --- /dev/null +++ b/examples/nextjs/previews/src/pages/index.js @@ -0,0 +1,111 @@ +import Head from 'next/head'; + +export default function Home() { + // Simple hardcoded template data like in the Astro example + const templates = [ + { + data: { + name: 'Single', + type: 'single', + path: 'src/wp-templates/single.js', + description: 'Displays individual blog posts with full content', + }, + }, + { + data: { + name: 'Page', + type: 'page', + path: 'src/wp-templates/page.js', + description: 'Displays individual WordPress pages', + }, + }, + { + data: { + name: 'Archive', + type: 'archive', + path: 'src/wp-templates/archive.js', + description: 'Displays category, tag, and other archive pages', + }, + }, + { + data: { + name: 'Index', + type: 'index', + path: 'src/wp-templates/index-template.js', + description: + "Fallback template for any content that doesn't have a specific template", + }, + }, + ]; + + return ( + <> + + @faustjs/nextjs Example + + +
+

@faustjs/nextjs Template Hierarchy Example

+

+ This example demonstrates how the @faustjs/nextjs package discovers + WordPress templates in your Next.js project using the WordPress + template hierarchy. +

+ +

Discovered Templates

+

+ The following templates were automatically discovered from the{' '} + wp-templates directory: +

+ +
+ {templates.map((template) => ( +
+

{template.data.name}

+

+ Type: {template.data.type} +

+

+ Path: {template.data.path} +

+

+ Description: {template.data.description} +

+
+ ))} +
+ +

How It Works

+
+
    +
  1. + Templates are placed in the src/wp-templates/{' '} + directory +
  2. +
  3. + The index.js file exports all templates with dynamic + imports +
  4. +
  5. + Templates are organized by WordPress template hierarchy rules +
  6. +
  7. Each template gets metadata like type and path
  8. +
  9. You can query templates using the template registry
  10. +
+
+ +

Live Template Router Demo

+

+ See the template hierarchy in action with our catch-all route that + resolves WordPress URLs to templates: +

+ +
+ + ); +} diff --git a/examples/nextjs/previews/src/styles/globals.css b/examples/nextjs/previews/src/styles/globals.css new file mode 100644 index 000000000..af80a2233 --- /dev/null +++ b/examples/nextjs/previews/src/styles/globals.css @@ -0,0 +1,137 @@ +@import 'tailwindcss'; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +.main { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} + +.main { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + max-width: 900px; + margin: 0 auto; + padding: 20px; + line-height: 1.6; + background: #f9f9f9; +} + +h1 { + color: #2563eb; + border-bottom: 2px solid #e5e7eb; + padding-bottom: 10px; +} + +h2 { + color: #374151; + margin-top: 30px; +} + +code { + background: #f3f4f6; + padding: 2px 6px; + border-radius: 4px; + font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; + font-size: 0.9em; +} + +main { + background: white; + padding: 20px; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.templates-list { + display: grid; + gap: 15px; + margin: 20px 0; +} + +.template-card { + background: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 8px; + padding: 20px; + border-left: 4px solid #3b82f6; +} + +.template-card h3 { + margin-top: 0; + color: #1e40af; +} + +.template-card p { + margin: 8px 0; +} + +.how-it-works { + background: #ecfdf5; + border: 1px solid #d1fae5; + border-radius: 8px; + padding: 20px; + margin: 20px 0; +} + +.how-it-works ol { + margin: 0; + padding-left: 20px; +} + +.how-it-works li { + margin-bottom: 8px; +} + +.router-links { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 15px; +} + +.router-links a { + display: inline-block; + background: #10b981; + color: white; + text-decoration: none; + padding: 10px 15px; + border-radius: 6px; + transition: background-color 0.2s; +} + +.router-links a:hover { + background: #059669; +} + +/* WordPress template styles */ +.content-area { + background: #e8f4f8; + padding: 20px; + border-radius: 8px; + margin-top: 20px; +} + +.post-preview { + background: #f0f8ff; + padding: 15px; + border-radius: 5px; + margin-bottom: 15px; + border-left: 4px solid #0066cc; +} + +.post-preview h3, +.post-preview h4 { + margin-top: 0; + color: #0066cc; +} diff --git a/examples/nextjs/previews/src/utils/getAuthString.js b/examples/nextjs/previews/src/utils/getAuthString.js new file mode 100644 index 000000000..a27e470be --- /dev/null +++ b/examples/nextjs/previews/src/utils/getAuthString.js @@ -0,0 +1,5 @@ +// Forming the authentication string for WordPress App Password +// More info: https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/ + +export const getAuthString = () => + "Basic " + Buffer.from(process.env.WP_USERNAME + ":" + process.env.WP_APP_PASSWORD).toString("base64"); diff --git a/examples/nextjs/previews/src/wp-templates/archive.js b/examples/nextjs/previews/src/wp-templates/archive.js new file mode 100644 index 000000000..1ce8e4951 --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/archive.js @@ -0,0 +1,38 @@ +export default function ArchiveTemplate({ templateData }) { + const { seedQuery } = templateData || {}; + const posts = seedQuery?.data?.posts?.nodes || []; + const archiveInfo = seedQuery?.data?.category || seedQuery?.data?.tag || {}; + + return ( + <> +

WordPress Archive Template

+

This template would render category, tag, or other archive pages.

+
+ {archiveInfo.name ? ( +

Archive: {archiveInfo.name}

+ ) : ( +

Archive Page

+ )} + {archiveInfo.description &&

{archiveInfo.description}

} + +

Posts in this archive:

+ {posts.length > 0 ? ( + posts.map((post) => ( +
+

{post.title}

+

{post.excerpt || 'Post excerpt would appear here...'}

+
+ )) + ) : ( +
+

Sample Archive Post

+

+ Posts from this category, tag, or archive would be displayed here + using data from the WordPress GraphQL API. +

+
+ )} +
+ + ); +} diff --git a/examples/nextjs/previews/src/wp-templates/index-template.js b/examples/nextjs/previews/src/wp-templates/index-template.js new file mode 100644 index 000000000..b50380764 --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/index-template.js @@ -0,0 +1,33 @@ +export default function IndexTemplate({ templateData }) { + const { seedQuery } = templateData || {}; + const posts = seedQuery?.data?.posts?.nodes || []; + + return ( + <> +

WordPress Index Template

+

This is the fallback template for all WordPress content.

+
+

+ Any WordPress content that doesn't have a specific template would use + this one: +

+ {posts.length > 0 ? ( + posts.map((post) => ( +
+

{post.title}

+

{post.excerpt || 'Content would appear here...'}

+
+ )) + ) : ( +
+

Sample Content

+

+ This is the default template that would render any WordPress + content using data from the WordPress GraphQL API. +

+
+ )} +
+ + ); +} diff --git a/examples/nextjs/previews/src/wp-templates/index.js b/examples/nextjs/previews/src/wp-templates/index.js new file mode 100644 index 000000000..c4b921aaf --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/index.js @@ -0,0 +1,19 @@ +import dynamic from 'next/dynamic'; + +const single = dynamic(() => import('./single.js'), { + loading: () =>

Loading Single Template...

, +}); + +const page = dynamic(() => import('./page.js'), { + loading: () =>

Loading Page Template...

, +}); + +const archive = dynamic(() => import('./archive.js'), { + loading: () =>

Loading Archive Template...

, +}); + +const index = dynamic(() => import('./index-template.js'), { + loading: () =>

Loading Index Template...

, +}); + +export default { single, page, archive, index }; diff --git a/examples/nextjs/previews/src/wp-templates/page.js b/examples/nextjs/previews/src/wp-templates/page.js new file mode 100644 index 000000000..f604fc64c --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/page.js @@ -0,0 +1,24 @@ +export default function PageTemplate({ templateData }) { + const { seedQuery } = templateData || {}; + const page = seedQuery?.data?.page; + + return ( + <> +

WordPress Page Template

+

This template would render individual WordPress pages.

+
+ {page ? ( + <> +

{page.title}

+
+ + ) : ( +

+ Page title, content, and metadata would be displayed here using data + from the WordPress GraphQL API. +

+ )} +
+ + ); +} diff --git a/examples/nextjs/previews/src/wp-templates/single.js b/examples/nextjs/previews/src/wp-templates/single.js new file mode 100644 index 000000000..d1f53a512 --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/single.js @@ -0,0 +1,36 @@ +export default function SingleTemplate({ templateData }) { + const { seedQuery } = templateData || {}; + const post = seedQuery?.data?.post; + + return ( + <> +

WordPress Single Post Template

+

This template would render individual blog posts.

+
+ {post ? ( +
+

{post.title}

+
+ {post.categories?.nodes && ( +
+ Categories: + {post.categories.nodes.map((cat) => cat.name).join(', ')} +
+ )} + {post.tags?.nodes && ( +
+ Tags: + {post.tags.nodes.map((tag) => tag.name).join(', ')} +
+ )} +
+ ) : ( +

+ Blog post title, content, categories, tags, and other metadata would + be displayed here using data from the WordPress GraphQL API. +

+ )} +
+ + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a319e165c..22b1a97fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,7 +76,7 @@ importers: version: link:../../../packages/template-hierarchy astro: specifier: ^5.1.1 - version: 5.12.8(rollup@4.46.2)(typescript@5.8.3) + version: 5.12.8(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.8.3) graphql: specifier: ^16.9.0 version: 16.11.0 @@ -88,6 +88,46 @@ importers: specifier: ^5.6.3 version: 5.8.3 + examples/nextjs/previews: + dependencies: + '@faustjs/nextjs': + specifier: workspace:* + version: link:../../../packages/nextjs + '@faustjs/template-hierarchy': + specifier: workspace:* + version: link:../../../packages/template-hierarchy + graphql: + specifier: ^16.11.0 + version: 16.11.0 + graphql-tag: + specifier: ^2.12.6 + version: 2.12.6(graphql@16.11.0) + next: + specifier: 15.2.4 + version: 15.2.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: + specifier: ^19.0.0 + version: 19.1.1 + react-dom: + specifier: ^19.0.0 + version: 19.1.1(react@19.1.1) + devDependencies: + '@eslint/eslintrc': + specifier: ^3 + version: 3.3.1 + '@tailwindcss/postcss': + specifier: ^4 + version: 4.1.11 + eslint: + specifier: ^9 + version: 9.33.0(jiti@2.5.1) + eslint-config-next: + specifier: 15.2.4 + version: 15.2.4(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + tailwindcss: + specifier: ^4 + version: 4.1.11 + examples/nextjs/template-hierarchy: dependencies: '@faustjs/nextjs': @@ -119,6 +159,46 @@ importers: specifier: ^15.1.3 version: 15.4.5(eslint@8.57.1)(typescript@5.8.3) + examples/sveltekit/template-hierarchy: + dependencies: + '@urql/core': + specifier: ^5.1.1 + version: 5.2.0(graphql@16.11.0) + '@urql/exchange-persisted': + specifier: ^4.3.1 + version: 4.3.1(@urql/core@5.2.0(graphql@16.11.0)) + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 + graphql: + specifier: ^16.11.0 + version: 16.11.0 + devDependencies: + '@faustjs/sveltekit': + specifier: workspace:* + version: link:../../../packages/sveltekit + '@faustjs/template-hierarchy': + specifier: workspace:* + version: link:../../../packages/template-hierarchy + '@sveltejs/adapter-auto': + specifier: ^6.0.0 + version: 6.1.0(@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1))) + '@sveltejs/kit': + specifier: ^2.16.0 + version: 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + '@sveltejs/vite-plugin-svelte': + specifier: ^5.0.0 + version: 5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + svelte: + specifier: ^5.0.0 + version: 5.38.1 + svelte-check: + specifier: ^4.0.0 + version: 4.3.1(picomatch@4.0.3)(svelte@5.38.1)(typescript@5.8.3) + vite: + specifier: ^6.2.6 + version: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) + packages/astro: dependencies: '@faustjs/graphql': @@ -129,7 +209,7 @@ importers: version: link:../template-hierarchy astro: specifier: ^5.0.0 - version: 5.12.8(rollup@4.46.2)(typescript@5.8.3) + version: 5.12.8(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.8.3) graphql: specifier: ^16.8.1 version: 16.11.0 @@ -149,11 +229,29 @@ importers: version: 16.11.0 next: specifier: ^13.0.0 || ^14.0.0 || ^15.0.0 - version: 14.2.31(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.31(react-dom@19.1.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.0.0 || ^19.0.0 version: 18.3.1 + packages/sveltekit: + dependencies: + '@faustjs/graphql': + specifier: workspace:* + version: link:../graphql + '@faustjs/template-hierarchy': + specifier: workspace:* + version: link:../template-hierarchy + '@sveltejs/kit': + specifier: ^2.0.0 + version: 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + graphql: + specifier: ^16.8.1 + version: 16.11.0 + svelte: + specifier: ^4.0.0 || ^5.0.0 + version: 5.38.1 + packages/template-hierarchy: dependencies: graphql: @@ -165,6 +263,22 @@ importers: packages: + '@0no-co/graphql.web@1.2.0': + resolution: {integrity: sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + graphql: + optional: true + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@astrojs/compiler@2.12.2': resolution: {integrity: sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==} @@ -448,14 +562,50 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.1': resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@9.33.0': + resolution: {integrity: sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -469,6 +619,14 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -696,9 +854,26 @@ packages: cpu: [x64] os: [win32] + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -714,9 +889,15 @@ packages: '@next/env@14.2.31': resolution: {integrity: sha512-X8VxxYL6VuezrG82h0pUA1V+DuTSJp7Nv15bxq3ivrFqZLjx81rfeHMWOE9T0jm1n3DtHGv8gdn6B0T0kr0D3Q==} + '@next/env@15.2.4': + resolution: {integrity: sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==} + '@next/env@15.4.5': resolution: {integrity: sha512-ruM+q2SCOVCepUiERoxOmZY9ZVoecR3gcXNwCYZRvQQWRjhOiPJGmQ2fAiLR6YKWXcSAh7G79KEFxN3rwhs4LQ==} + '@next/eslint-plugin-next@15.2.4': + resolution: {integrity: sha512-O8ScvKtnxkp8kL9TpJTTKnMqlkZnS+QxwoQnJwPGBxjBbzd6OVVPEJ5/pMNrktSyXQD/chEfzfFzYLM6JANOOQ==} + '@next/eslint-plugin-next@15.4.5': resolution: {integrity: sha512-YhbrlbEt0m4jJnXHMY/cCUDBAWgd5SaTa5mJjzOt82QwflAFfW/h3+COp2TfVSzhmscIZ5sg2WXt3MLziqCSCw==} @@ -726,6 +907,12 @@ packages: cpu: [arm64] os: [darwin] + '@next/swc-darwin-arm64@15.2.4': + resolution: {integrity: sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@next/swc-darwin-arm64@15.4.5': resolution: {integrity: sha512-84dAN4fkfdC7nX6udDLz9GzQlMUwEMKD7zsseXrl7FTeIItF8vpk1lhLEnsotiiDt+QFu3O1FVWnqwcRD2U3KA==} engines: {node: '>= 10'} @@ -738,6 +925,12 @@ packages: cpu: [x64] os: [darwin] + '@next/swc-darwin-x64@15.2.4': + resolution: {integrity: sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@next/swc-darwin-x64@15.4.5': resolution: {integrity: sha512-CL6mfGsKuFSyQjx36p2ftwMNSb8PQog8y0HO/ONLdQqDql7x3aJb/wB+LA651r4we2pp/Ck+qoRVUeZZEvSurA==} engines: {node: '>= 10'} @@ -750,6 +943,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-gnu@15.2.4': + resolution: {integrity: sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-gnu@15.4.5': resolution: {integrity: sha512-1hTVd9n6jpM/thnDc5kYHD1OjjWYpUJrJxY4DlEacT7L5SEOXIifIdTye6SQNNn8JDZrcN+n8AWOmeJ8u3KlvQ==} engines: {node: '>= 10'} @@ -762,6 +961,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-musl@15.2.4': + resolution: {integrity: sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-musl@15.4.5': resolution: {integrity: sha512-4W+D/nw3RpIwGrqpFi7greZ0hjrCaioGErI7XHgkcTeWdZd146NNu1s4HnaHonLeNTguKnL2Urqvj28UJj6Gqw==} engines: {node: '>= 10'} @@ -774,6 +979,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-gnu@15.2.4': + resolution: {integrity: sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-gnu@15.4.5': resolution: {integrity: sha512-N6Mgdxe/Cn2K1yMHge6pclffkxzbSGOydXVKYOjYqQXZYjLCfN/CuFkaYDeDHY2VBwSHyM2fUjYBiQCIlxIKDA==} engines: {node: '>= 10'} @@ -786,6 +997,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-musl@15.2.4': + resolution: {integrity: sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-musl@15.4.5': resolution: {integrity: sha512-YZ3bNDrS8v5KiqgWE0xZQgtXgCTUacgFtnEgI4ccotAASwSvcMPDLua7BWLuTfucoRv6mPidXkITJLd8IdJplQ==} engines: {node: '>= 10'} @@ -798,6 +1015,12 @@ packages: cpu: [arm64] os: [win32] + '@next/swc-win32-arm64-msvc@15.2.4': + resolution: {integrity: sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@next/swc-win32-arm64-msvc@15.4.5': resolution: {integrity: sha512-9Wr4t9GkZmMNcTVvSloFtjzbH4vtT4a8+UHqDoVnxA5QyfWe6c5flTH1BIWPGNWSUlofc8dVJAE7j84FQgskvQ==} engines: {node: '>= 10'} @@ -816,6 +1039,12 @@ packages: cpu: [x64] os: [win32] + '@next/swc-win32-x64-msvc@15.2.4': + resolution: {integrity: sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@next/swc-win32-x64-msvc@15.4.5': resolution: {integrity: sha512-voWk7XtGvlsP+w8VBz7lqp8Y+dYw/MTI4KeS0gTVtfdhdJ5QwhXLmNrndFOin/MDoCvUaLWMkYKATaCoUkt2/A==} engines: {node: '>= 10'} @@ -980,6 +1209,43 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@sveltejs/acorn-typescript@1.0.5': + resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} + peerDependencies: + acorn: ^8.9.0 + + '@sveltejs/adapter-auto@6.1.0': + resolution: {integrity: sha512-shOuLI5D2s+0zTv2ab5M5PqfknXqWbKi+0UwB9yLTRIdzsK1R93JOO8jNhIYSHdW+IYXIYnLniu+JZqXs7h9Wg==} + peerDependencies: + '@sveltejs/kit': ^2.0.0 + + '@sveltejs/kit@2.28.0': + resolution: {integrity: sha512-qrhygwHV5r6JrvCw4gwNqqxYGDi5YbajocxfKgFXmSFpFo8wQobUvsM0OfakN4h+0LEmXtqHRrC6BcyAkOwyoQ==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1': + resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^5.0.0 + svelte: ^5.0.0 + vite: ^6.0.0 + + '@sveltejs/vite-plugin-svelte@5.1.1': + resolution: {integrity: sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.0.0 + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -992,9 +1258,100 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@tailwindcss/node@4.1.11': + resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} + + '@tailwindcss/oxide-android-arm64@4.1.11': + resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.11': + resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.11': + resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.11': + resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.11': + resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.11': + resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.11': + resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.11': + resolution: {integrity: sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==} + '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1187,6 +1544,14 @@ packages: cpu: [x64] os: [win32] + '@urql/core@5.2.0': + resolution: {integrity: sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==} + + '@urql/exchange-persisted@4.3.1': + resolution: {integrity: sha512-VRGYFNW0gaT7+VCR/1rCMWEP9gvnDnlAolKisysLYkv8Zeysbqx+Omw4IgIRCLjI6oHWPkH8zOhFbqA3GRQ9HQ==} + peerDependencies: + '@urql/core': ^5.0.0 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1201,6 +1566,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -1391,6 +1761,10 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -1447,6 +1821,10 @@ packages: cookie-es@1.2.2: resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + cookie@1.0.2: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} @@ -1508,6 +1886,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -1586,6 +1968,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -1667,6 +2053,15 @@ packages: eslint-plugin-react: ^7.28.0 eslint-plugin-react-hooks: ^4.3.0 + eslint-config-next@15.2.4: + resolution: {integrity: sha512-v4gYjd4eYIme8qzaJItpR5MMBXJ0/YV07u7eb50kEnlEmX7yhOjdUdzz70v4fiINYRjLf8X8TbogF0k7wlz6sA==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + eslint-config-next@15.4.5: resolution: {integrity: sha512-IMijiXaZ43qFB+Gcpnb374ipTKD8JIyVNR+6VsifFQ/LHyx+A9wgcgSIhCX5PYSjwOoSYD5LtNHKlM5uc23eww==} peerDependencies: @@ -1766,16 +2161,41 @@ packages: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true + eslint@9.33.0: + resolution: {integrity: sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1789,6 +2209,9 @@ packages: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} + esrap@2.1.0: + resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -1859,6 +2282,10 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1875,6 +2302,10 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} @@ -1956,6 +2387,10 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -2182,6 +2617,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -2240,6 +2678,10 @@ packages: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2293,6 +2735,73 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2473,6 +2982,19 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -2526,6 +3048,27 @@ packages: sass: optional: true + next@15.2.4: + resolution: {integrity: sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + next@15.4.5: resolution: {integrity: sha512-nJ4v+IO9CPmbmcvsPebIoX3Q+S7f6Fu08/dEWu0Ttfa+wVwQRh9epcmsyCPjmL2b8MxC+CkBR97jgDhUUztI3g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} @@ -2788,6 +3331,11 @@ packages: peerDependencies: react: ^18.3.1 + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + peerDependencies: + react: ^19.1.1 + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -2799,6 +3347,10 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + engines: {node: '>=0.10.0'} + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} @@ -2907,6 +3459,10 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -2925,6 +3481,9 @@ packages: scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2934,6 +3493,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2992,6 +3554,10 @@ packages: resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==} engines: {node: '>= 10'} + sirv@3.0.1: + resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} + engines: {node: '>=18'} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -3107,6 +3673,29 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svelte-check@4.3.1: + resolution: {integrity: sha512-lkh8gff5gpHLjxIV+IaApMxQhTGnir2pNUAqcNgeKkvK5bT/30Ey/nzBxNLDlkztCH4dP7PixkMt9SWEKFPBWg==} + engines: {node: '>= 18.0.0'} + hasBin: true + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: '>=5.0.0' + + svelte@5.38.1: + resolution: {integrity: sha512-fO6CLDfJYWHgfo6lQwkQU2vhCiHc2MBl6s3vEhK+sSZru17YL4R5s1v14ndRpqKAIkq8nCz6MTk1yZbESZWeyQ==} + engines: {node: '>=18'} + + tailwindcss@4.1.11: + resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} + + tapable@2.2.2: + resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + engines: {node: '>=6'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -3136,6 +3725,10 @@ packages: resolution: {integrity: sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==} engines: {node: '>=6'} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -3424,6 +4017,9 @@ packages: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} + wonka@6.3.5: + resolution: {integrity: sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -3450,6 +4046,10 @@ packages: xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -3470,6 +4070,9 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} + zimmerframe@1.1.2: + resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + zod-to-json-schema@3.24.6: resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} peerDependencies: @@ -3489,6 +4092,17 @@ packages: snapshots: + '@0no-co/graphql.web@1.2.0(graphql@16.11.0)': + optionalDependencies: + graphql: 16.11.0 + + '@alloc/quick-lru@5.2.0': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + '@astrojs/compiler@2.12.2': {} '@astrojs/internal-helpers@0.7.1': {} @@ -3818,8 +4432,27 @@ snapshots: eslint: 8.57.1 eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.7.0(eslint@9.33.0(jiti@2.5.1))': + dependencies: + eslint: 9.33.0(jiti@2.5.1) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.1': {} + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.1 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.3.1': {} + + '@eslint/core@0.15.2': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 @@ -3834,8 +4467,38 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.1 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + '@eslint/js@8.57.1': {} + '@eslint/js@9.33.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.3.5': + dependencies: + '@eslint/core': 0.15.2 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -3848,6 +4511,10 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -4009,8 +4676,29 @@ snapshots: '@img/sharp-win32-x64@0.34.3': optional: true + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/sourcemap-codec@1.5.4': {} + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.4 + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.27.0 @@ -4043,8 +4731,14 @@ snapshots: '@next/env@14.2.31': {} + '@next/env@15.2.4': {} + '@next/env@15.4.5': {} + '@next/eslint-plugin-next@15.2.4': + dependencies: + fast-glob: 3.3.1 + '@next/eslint-plugin-next@15.4.5': dependencies: fast-glob: 3.3.1 @@ -4052,42 +4746,63 @@ snapshots: '@next/swc-darwin-arm64@14.2.31': optional: true + '@next/swc-darwin-arm64@15.2.4': + optional: true + '@next/swc-darwin-arm64@15.4.5': optional: true '@next/swc-darwin-x64@14.2.31': optional: true + '@next/swc-darwin-x64@15.2.4': + optional: true + '@next/swc-darwin-x64@15.4.5': optional: true '@next/swc-linux-arm64-gnu@14.2.31': optional: true + '@next/swc-linux-arm64-gnu@15.2.4': + optional: true + '@next/swc-linux-arm64-gnu@15.4.5': optional: true '@next/swc-linux-arm64-musl@14.2.31': optional: true + '@next/swc-linux-arm64-musl@15.2.4': + optional: true + '@next/swc-linux-arm64-musl@15.4.5': optional: true '@next/swc-linux-x64-gnu@14.2.31': optional: true + '@next/swc-linux-x64-gnu@15.2.4': + optional: true + '@next/swc-linux-x64-gnu@15.4.5': optional: true '@next/swc-linux-x64-musl@14.2.31': optional: true + '@next/swc-linux-x64-musl@15.2.4': + optional: true + '@next/swc-linux-x64-musl@15.4.5': optional: true '@next/swc-win32-arm64-msvc@14.2.31': optional: true + '@next/swc-win32-arm64-msvc@15.2.4': + optional: true + '@next/swc-win32-arm64-msvc@15.4.5': optional: true @@ -4097,6 +4812,9 @@ snapshots: '@next/swc-win32-x64-msvc@14.2.31': optional: true + '@next/swc-win32-x64-msvc@15.2.4': + optional: true + '@next/swc-win32-x64-msvc@15.4.5': optional: true @@ -4223,6 +4941,57 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@standard-schema/spec@1.0.0': {} + + '@sveltejs/acorn-typescript@1.0.5(acorn@8.14.1)': + dependencies: + acorn: 8.14.1 + + '@sveltejs/adapter-auto@6.1.0(@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))': + dependencies: + '@sveltejs/kit': 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + + '@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1))': + dependencies: + '@standard-schema/spec': 1.0.0 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1) + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + '@types/cookie': 0.6.0 + acorn: 8.14.1 + cookie: 0.6.0 + devalue: 5.1.1 + esm-env: 1.2.2 + kleur: 4.1.5 + magic-string: 0.30.17 + mrmime: 2.0.1 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.1 + svelte: 5.38.1 + vite: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1))': + dependencies: + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + debug: 4.4.1 + svelte: 5.38.1 + vite: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.1)(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + debug: 4.4.1 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.17 + svelte: 5.38.1 + vite: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) + vitefu: 1.1.1(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) + transitivePeerDependencies: + - supports-color + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -4238,11 +5007,85 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.8.1 + '@tailwindcss/node@4.1.11': + dependencies: + '@ampproject/remapping': 2.3.0 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + magic-string: 0.30.17 + source-map-js: 1.2.1 + tailwindcss: 4.1.11 + + '@tailwindcss/oxide-android-arm64@4.1.11': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.11': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.11': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.11': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.11': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + optional: true + + '@tailwindcss/oxide@4.1.11': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.11 + '@tailwindcss/oxide-darwin-arm64': 4.1.11 + '@tailwindcss/oxide-darwin-x64': 4.1.11 + '@tailwindcss/oxide-freebsd-x64': 4.1.11 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.11 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.11 + '@tailwindcss/oxide-linux-x64-musl': 4.1.11 + '@tailwindcss/oxide-wasm32-wasi': 4.1.11 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.11 + + '@tailwindcss/postcss@4.1.11': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.11 + '@tailwindcss/oxide': 4.1.11 + postcss: 8.5.6 + tailwindcss: 4.1.11 + '@tybys/wasm-util@0.10.0': dependencies: tslib: 2.8.1 optional: true + '@types/cookie@0.6.0': {} + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -4296,6 +5139,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + debug: 4.4.1 + eslint: 9.33.0(jiti@2.5.1) + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare-lite: 1.4.0 + semver: 7.7.2 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 5.62.0 @@ -4308,6 +5170,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + debug: 4.4.1 + eslint: 9.33.0(jiti@2.5.1) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 @@ -4316,9 +5190,21 @@ snapshots: '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + debug: 4.4.1 + eslint: 8.57.1 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/type-utils@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) debug: 4.4.1 - eslint: 8.57.1 + eslint: 9.33.0(jiti@2.5.1) tsutils: 3.21.0(typescript@5.8.3) optionalDependencies: typescript: 5.8.3 @@ -4356,6 +5242,21 @@ snapshots: - supports-color - typescript + '@typescript-eslint/utils@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + eslint: 9.33.0(jiti@2.5.1) + eslint-scope: 5.1.1 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/visitor-keys@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 @@ -4422,16 +5323,34 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@urql/core@5.2.0(graphql@16.11.0)': + dependencies: + '@0no-co/graphql.web': 1.2.0(graphql@16.11.0) + wonka: 6.3.5 + transitivePeerDependencies: + - graphql + + '@urql/exchange-persisted@4.3.1(@urql/core@5.2.0(graphql@16.11.0))': + dependencies: + '@urql/core': 5.2.0(graphql@16.11.0) + wonka: 6.3.5 + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-walk@8.3.4: dependencies: acorn: 8.14.1 acorn@8.14.1: {} + acorn@8.15.0: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -4539,7 +5458,7 @@ snapshots: ast-types-flow@0.0.8: {} - astro@5.12.8(rollup@4.46.2)(typescript@5.8.3): + astro@5.12.8(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.8.3): dependencies: '@astrojs/compiler': 2.12.2 '@astrojs/internal-helpers': 0.7.1 @@ -4595,8 +5514,8 @@ snapshots: unist-util-visit: 5.0.0 unstorage: 1.16.1 vfile: 6.0.3 - vite: 6.3.5 - vitefu: 1.1.1(vite@6.3.5) + vite: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) + vitefu: 1.1.1(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.3 @@ -4736,6 +5655,8 @@ snapshots: dependencies: readdirp: 4.1.2 + chownr@3.0.0: {} + ci-info@3.9.0: {} ci-info@4.3.0: {} @@ -4778,6 +5699,8 @@ snapshots: cookie-es@1.2.2: {} + cookie@0.6.0: {} + cookie@1.0.2: {} cross-fetch@3.2.0: @@ -4837,6 +5760,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge@4.3.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -4857,8 +5782,7 @@ snapshots: detect-indent@6.1.0: {} - detect-libc@2.0.4: - optional: true + detect-libc@2.0.4: {} deterministic-object-hash@2.0.2: dependencies: @@ -4904,6 +5828,11 @@ snapshots: emoji-regex@9.2.2: {} + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.2 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -5072,6 +6001,26 @@ snapshots: object.assign: 4.1.7 object.entries: 1.1.9 + eslint-config-next@15.2.4(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3): + dependencies: + '@next/eslint-plugin-next': 15.2.4 + '@rushstack/eslint-patch': 1.12.0 + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + eslint: 9.33.0(jiti@2.5.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.33.0(jiti@2.5.1)) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + eslint-config-next@15.4.5(eslint@8.57.1)(typescript@5.8.3): dependencies: '@next/eslint-plugin-next': 15.4.5 @@ -5080,7 +6029,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) @@ -5104,7 +6053,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -5119,14 +6068,40 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.1 + eslint: 9.33.0(jiti@2.5.1) + get-tsconfig: 4.10.1 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.14 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + eslint: 9.33.0(jiti@2.5.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color @@ -5141,7 +6116,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -5159,6 +6134,35 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.33.0(jiti@2.5.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): dependencies: aria-query: 5.3.2 @@ -5178,6 +6182,25 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 + eslint-plugin-jsx-a11y@6.10.2(eslint@9.33.0(jiti@2.5.1)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.10.3 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.33.0(jiti@2.5.1) + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -5186,6 +6209,10 @@ snapshots: dependencies: eslint: 8.57.1 + eslint-plugin-react-hooks@5.2.0(eslint@9.33.0(jiti@2.5.1)): + dependencies: + eslint: 9.33.0(jiti@2.5.1) + eslint-plugin-react@7.37.5(eslint@8.57.1): dependencies: array-includes: 3.1.8 @@ -5208,6 +6235,28 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 + eslint-plugin-react@7.37.5(eslint@9.33.0(jiti@2.5.1)): + dependencies: + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.33.0(jiti@2.5.1) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + eslint-plugin-simple-import-sort@7.0.0(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -5222,8 +6271,15 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-visitor-keys@3.4.3: {} + eslint-visitor-keys@4.2.1: {} + eslint@8.57.1: dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) @@ -5267,6 +6323,56 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@9.33.0(jiti@2.5.1): + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.1 + '@eslint/core': 0.15.2 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.33.0 + '@eslint/plugin-kit': 0.3.5 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.5.1 + transitivePeerDependencies: + - supports-color + + esm-env@1.2.2: {} + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + espree@9.6.1: dependencies: acorn: 8.14.1 @@ -5279,6 +6385,10 @@ snapshots: dependencies: estraverse: 5.3.0 + esrap@2.1.0: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -5343,6 +6453,10 @@ snapshots: dependencies: flat-cache: 3.2.0 + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -5363,6 +6477,11 @@ snapshots: keyv: 4.5.4 rimraf: 3.0.2 + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + flatted@3.3.3: {} flattie@1.1.1: {} @@ -5471,6 +6590,8 @@ snapshots: dependencies: type-fest: 0.20.2 + globals@14.0.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -5746,6 +6867,10 @@ snapshots: is-plain-obj@4.1.0: {} + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -5808,6 +6933,8 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 + jiti@2.5.1: {} + js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -5859,6 +6986,53 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + locate-character@3.0.0: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -6221,6 +7395,14 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.2: {} + + minizlib@3.0.2: + dependencies: + minipass: 7.1.2 + + mkdirp@3.0.1: {} + mri@1.2.0: {} mrmime@1.0.1: {} @@ -6239,7 +7421,7 @@ snapshots: neotraverse@0.6.18: {} - next@14.2.31(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.31(react-dom@19.1.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 14.2.31 '@swc/helpers': 0.5.5 @@ -6248,7 +7430,7 @@ snapshots: graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.1.1(react@18.3.1) styled-jsx: 5.1.1(react@18.3.1) optionalDependencies: '@next/swc-darwin-arm64': 14.2.31 @@ -6264,6 +7446,31 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@15.2.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + '@next/env': 15.2.4 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001731 + postcss: 8.4.31 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + styled-jsx: 5.1.6(react@19.1.1) + optionalDependencies: + '@next/swc-darwin-arm64': 15.2.4 + '@next/swc-darwin-x64': 15.2.4 + '@next/swc-linux-arm64-gnu': 15.2.4 + '@next/swc-linux-arm64-musl': 15.2.4 + '@next/swc-linux-x64-gnu': 15.2.4 + '@next/swc-linux-x64-musl': 15.2.4 + '@next/swc-win32-arm64-msvc': 15.2.4 + '@next/swc-win32-x64-msvc': 15.2.4 + sharp: 0.33.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + next@15.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 15.4.5 @@ -6515,6 +7722,16 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-dom@19.1.1(react@18.3.1): + dependencies: + react: 18.3.1 + scheduler: 0.26.0 + + react-dom@19.1.1(react@19.1.1): + dependencies: + react: 19.1.1 + scheduler: 0.26.0 + react-is@16.13.1: {} react-refresh@0.14.2: {} @@ -6523,6 +7740,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + react@19.1.1: {} + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -6711,6 +7930,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -6736,10 +7959,14 @@ snapshots: dependencies: loose-envify: 1.4.0 + scheduler@0.26.0: {} + semver@6.3.1: {} semver@7.7.2: {} + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -6877,6 +8104,12 @@ snapshots: mrmime: 1.0.1 totalist: 1.1.0 + sirv@3.0.1: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + sisteransi@1.0.5: {} slash@3.0.0: {} @@ -6987,12 +8220,59 @@ snapshots: client-only: 0.0.1 react: 18.3.1 + styled-jsx@5.1.6(react@19.1.1): + dependencies: + client-only: 0.0.1 + react: 19.1.1 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} + svelte-check@4.3.1(picomatch@4.0.3)(svelte@5.38.1)(typescript@5.8.3): + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + chokidar: 4.0.3 + fdir: 6.4.6(picomatch@4.0.3) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.38.1 + typescript: 5.8.3 + transitivePeerDependencies: + - picomatch + + svelte@5.38.1: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.4 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1) + '@types/estree': 1.0.8 + acorn: 8.14.1 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + esm-env: 1.2.2 + esrap: 2.1.0 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.17 + zimmerframe: 1.1.2 + + tailwindcss@4.1.11: {} + + tapable@2.2.2: {} + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + term-size@2.2.1: {} text-table@0.2.0: {} @@ -7016,6 +8296,8 @@ snapshots: totalist@1.1.0: {} + totalist@3.0.1: {} + tr46@0.0.3: {} trim-lines@3.0.1: {} @@ -7222,7 +8504,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@6.3.5: + vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1): dependencies: esbuild: 0.25.8 fdir: 6.4.6(picomatch@4.0.3) @@ -7232,10 +8514,12 @@ snapshots: tinyglobby: 0.2.14 optionalDependencies: fsevents: 2.3.3 + jiti: 2.5.1 + lightningcss: 1.30.1 - vitefu@1.1.1(vite@6.3.5): + vitefu@1.1.1(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)): optionalDependencies: - vite: 6.3.5 + vite: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) web-namespaces@2.0.1: {} @@ -7312,6 +8596,8 @@ snapshots: dependencies: string-width: 7.2.0 + wonka@6.3.5: {} + word-wrap@1.2.5: {} wrap-ansi@9.0.0: @@ -7326,6 +8612,8 @@ snapshots: xxhash-wasm@1.1.0: {} + yallist@5.0.0: {} + yargs-parser@21.1.1: {} yocto-queue@0.1.0: {} @@ -7338,6 +8626,8 @@ snapshots: yoctocolors@2.1.1: {} + zimmerframe@1.1.2: {} + zod-to-json-schema@3.24.6(zod@3.25.76): dependencies: zod: 3.25.76 From 404576da0312b8fdf357a4a7cf3f8a4ff23b2ae5 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Wed, 13 Aug 2025 14:36:10 +0200 Subject: [PATCH 02/13] update gql client, add headers param --- packages/graphql/client.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/graphql/client.js b/packages/graphql/client.js index 6a80e8672..2ad3cfeca 100644 --- a/packages/graphql/client.js +++ b/packages/graphql/client.js @@ -38,7 +38,7 @@ export function buildGraphQLEndpoint(wordpressUrl) { * @returns {import('./types.js').GraphQLClient} A basic GraphQL client * @throws {Error} If no WordPress URL is provided */ -export function createDefaultGraphQLClient(wordpressUrl) { +export function createDefaultGraphQLClient(wordpressUrl, headers = {}) { if (!wordpressUrl) { throw new Error( 'WordPress URL is required to create a default GraphQL client.', @@ -54,6 +54,7 @@ export function createDefaultGraphQLClient(wordpressUrl) { method: 'POST', headers: { 'Content-Type': 'application/json', + ...headers, }, body: JSON.stringify({ query, variables }), }); From 2437c6aee416b8733f83c253d2b7c747e5741136 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Wed, 13 Aug 2025 14:36:38 +0200 Subject: [PATCH 03/13] update template-hierarchy, add id and asPreview --- packages/nextjs/pages/templateHierarchy.js | 10 ++++++++-- packages/template-hierarchy/seedQueryExecutor.js | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/nextjs/pages/templateHierarchy.js b/packages/nextjs/pages/templateHierarchy.js index 2e91c685c..3014cc904 100644 --- a/packages/nextjs/pages/templateHierarchy.js +++ b/packages/nextjs/pages/templateHierarchy.js @@ -20,6 +20,8 @@ import { getGraphQLClient } from '@faustjs/graphql'; */ export async function uriToTemplate({ uri, + id, + asPreview, availableTemplates, graphqlClient, wordpressUrl, @@ -37,17 +39,21 @@ export async function uriToTemplate({ const client = getGraphQLClient(graphqlClient); const { data, error } = await getSeedQuery({ uri, + id, + asPreview, graphqlClient: client, }); returnData.seedQuery = { data, error }; + const seedNode = data?.nodeByUri || data?.contentNode; + if (error) { console.error('Error fetching seedQuery:', error); return returnData; } - if (!data?.nodeByUri) { + if (!seedNode) { console.error('HTTP/404 - Not Found in WordPress:', uri); return returnData; // Let Next.js handle 404s } @@ -59,7 +65,7 @@ export async function uriToTemplate({ return returnData; } - const possibleTemplates = getPossibleTemplates(data.nodeByUri); + const possibleTemplates = getPossibleTemplates(seedNode); returnData.possibleTemplates = possibleTemplates; diff --git a/packages/template-hierarchy/seedQueryExecutor.js b/packages/template-hierarchy/seedQueryExecutor.js index 16181e737..15a4a4dd5 100644 --- a/packages/template-hierarchy/seedQueryExecutor.js +++ b/packages/template-hierarchy/seedQueryExecutor.js @@ -10,13 +10,20 @@ import { print } from 'graphql'; * @param {import('./types.js').SeedQueryOptions} options - Query options * @returns {Promise} Query result */ -export async function getSeedQuery({ uri, graphqlClient }) { +export async function getSeedQuery({ uri, id, asPreview, graphqlClient }) { if (!graphqlClient) { throw new Error('GraphQL client is required for getSeedQuery'); } try { - const result = await graphqlClient.request(print(SEED_QUERY), { uri }); + const result = await graphqlClient.request(print(SEED_QUERY), { + uri, + id, + asPreview, + }); + + console.log('Seed query result:', uri, id, asPreview, result); + return { data: result.data || result, error: result.error || null, From f66dcc03ba66c827e2ccf03f87612e395917092d Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Wed, 13 Aug 2025 15:15:45 +0200 Subject: [PATCH 04/13] add preview utility to @faustjs/nextjs package --- .../previews/src/pages/[...identifier].js | 2 +- .../nextjs/previews/src/pages/api/preview.js | 60 ++------------- packages/nextjs/pages/enablePreview.js | 73 +++++++++++++++++++ packages/nextjs/pages/index.js | 3 + 4 files changed, 85 insertions(+), 53 deletions(-) create mode 100644 packages/nextjs/pages/enablePreview.js diff --git a/examples/nextjs/previews/src/pages/[...identifier].js b/examples/nextjs/previews/src/pages/[...identifier].js index 76dd4e5a4..59f5a86cb 100644 --- a/examples/nextjs/previews/src/pages/[...identifier].js +++ b/examples/nextjs/previews/src/pages/[...identifier].js @@ -41,7 +41,7 @@ export async function getStaticProps({ const variables = isDraftModeEnabled ? { id: params.identifier?.[0], - isPreview: true, + asPreview: true, } : { uri }; diff --git a/examples/nextjs/previews/src/pages/api/preview.js b/examples/nextjs/previews/src/pages/api/preview.js index f6dfd1f09..7cbca238b 100644 --- a/examples/nextjs/previews/src/pages/api/preview.js +++ b/examples/nextjs/previews/src/pages/api/preview.js @@ -1,53 +1,9 @@ import { getAuthString } from '@/utils/getAuthString'; -import { createDefaultClient, setGraphQLClient } from '@faustjs/nextjs/pages'; -import { gql } from 'graphql-tag'; -import { print } from 'graphql'; - -const GET_CONTENT = gql` - query GetNode($id: ID! = 0) { - contentNode(id: $id, idType: DATABASE_ID, asPreview: true) { - databaseId - } - } -`; - -export default async function handler(req, res) { - const { secret, id } = req.query; - - if (!id) { - return res.status(400).json({ message: 'No ID provided.' }); - } - - // Check if preview secret token exists and matches environment variable - if (secret !== process.env.WP_PREVIEW_SECRET) { - return res.status(401).json({ message: 'Secret token is invalid.' }); - } - - const client = createDefaultClient(process.env.NEXT_PUBLIC_WORDPRESS_URL, { - Authorization: getAuthString(), - }); - setGraphQLClient(client); - - const { data, error } = await client.request(print(GET_CONTENT), { - id, - }); - - if (error) { - console.error('Error fetching content:', error); - return res.status(500).json({ message: 'Error fetching content.' }); - } - - if (!data?.contentNode) { - return res.status(404).json({ - message: 'Content could not be found. Verify your authentication method.', - }); - } - - // Enable draft mode - // More info: https://nextjs.org/docs/pages/guides/draft-mode#step-1-create-and-access-the-api-route - res.setDraftMode({ enable: true }); - - // Redirect with the databaseId retrieved from the query to prevent redirect at - // More info: https://developers.google.com/search/blog/2009/01/open-redirect-urls-is-your-site-being - res.redirect('/' + data?.contentNode?.databaseId); -} +import { enablePreview } from '@faustjs/nextjs/pages'; + +export default enablePreview({ + wordpressUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL, + expectedSecret: process.env.WP_PREVIEW_SECRET, + // graphqlClient: client, + bearerToken: getAuthString(), +}); diff --git a/packages/nextjs/pages/enablePreview.js b/packages/nextjs/pages/enablePreview.js new file mode 100644 index 000000000..0ef10afdf --- /dev/null +++ b/packages/nextjs/pages/enablePreview.js @@ -0,0 +1,73 @@ +import { createDefaultClient, setGraphQLClient } from '@faustjs/nextjs/pages'; +import { print } from 'graphql'; +import { gql } from 'graphql-tag'; + +const VERIFY_NODE = gql` + query GetNode($id: ID! = 0) { + contentNode(id: $id, idType: DATABASE_ID, asPreview: true) { + databaseId + } + } +`; + +export function enablePreview({ + wordpressUrl, + expectedSecret, + secretParamName = 'secret', + idParamName = 'id', + graphqlClient, + bearerToken, +}) { + return async function handler(req, res) { + const id = req.query[idParamName]; + const secret = req.query[secretParamName]; + + if (!id) { + return res.status(400).json({ message: 'No ID received.' }); + } + + // Check if preview secret token exists and matches environment variable + if (secret !== expectedSecret) { + return res.status(401).json({ message: 'Secret token is invalid.' }); + } + + if (!wordpressUrl) { + return res + .status(500) + .json({ message: 'WordPress URL is not configured.' }); + } + + let client; + + if (graphqlClient) { + client = graphqlClient; + } else { + client = createDefaultClient(wordpressUrl, { + Authorization: bearerToken, + }); + setGraphQLClient(client); + } + + const { data, error } = await client.request(print(VERIFY_NODE), { + id, + }); + + if (error) { + console.error('Error fetching content:', error); + return res.status(500).json({ message: 'Error fetching content.' }); + } + + if (!data?.contentNode) { + return res.status(404).json({ + message: + 'Content could not be found. Verify your authentication method.', + }); + } + + // Enable draft mode + res.setDraftMode({ enable: true }); + + // Redirect with the databaseId retrieved from the query + res.redirect('/' + data?.contentNode?.databaseId); + }; +} diff --git a/packages/nextjs/pages/index.js b/packages/nextjs/pages/index.js index a4dababf2..12278c47f 100644 --- a/packages/nextjs/pages/index.js +++ b/packages/nextjs/pages/index.js @@ -8,6 +8,9 @@ import './types.js'; // Export template hierarchy utilities export { uriToTemplate } from './templateHierarchy.js'; +// Export Next.js preview enabling api handler +export { enablePreview } from './enablePreview.js'; + // Export GraphQL client configuration // Export GraphQL client configuration export { From ebe7a5dce675f0d44e287b646521d9b25963cf02 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Tue, 19 Aug 2025 14:04:05 +0200 Subject: [PATCH 05/13] initial --- examples/nextjs/previews/package.json | 1 + .../previews/src/pages/[...identifier].js | 12 ++++- .../nextjs/previews/src/queries/getLayout.js | 10 ++++ .../nextjs/previews/src/queries/getPost.js | 27 ++++++++++ .../nextjs/previews/src/wp-templates/page.js | 2 +- .../previews/src/wp-templates/single.js | 16 ++++++ .../src/wp-templates/templateQueries.js | 3 ++ packages/data-fetching/README.md | 1 + .../data-fetching/fetchTemplateQueries.js | 49 +++++++++++++++++++ packages/data-fetching/index.js | 6 +++ packages/data-fetching/package.json | 23 +++++++++ packages/nextjs/pages/templateHierarchy.js | 5 +- pnpm-lock.yaml | 22 +++++++-- 13 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 examples/nextjs/previews/src/queries/getLayout.js create mode 100644 examples/nextjs/previews/src/queries/getPost.js create mode 100644 examples/nextjs/previews/src/wp-templates/templateQueries.js create mode 100644 packages/data-fetching/README.md create mode 100644 packages/data-fetching/fetchTemplateQueries.js create mode 100644 packages/data-fetching/index.js create mode 100644 packages/data-fetching/package.json diff --git a/examples/nextjs/previews/package.json b/examples/nextjs/previews/package.json index ea7058a46..e2fb03d82 100644 --- a/examples/nextjs/previews/package.json +++ b/examples/nextjs/previews/package.json @@ -11,6 +11,7 @@ "dependencies": { "@faustjs/nextjs": "workspace:*", "@faustjs/template-hierarchy": "workspace:*", + "@faustjs/data-fetching": "workspace:*", "graphql": "^16.11.0", "graphql-tag": "^2.12.6", "next": "15.2.4", diff --git a/examples/nextjs/previews/src/pages/[...identifier].js b/examples/nextjs/previews/src/pages/[...identifier].js index 59f5a86cb..5917c95ed 100644 --- a/examples/nextjs/previews/src/pages/[...identifier].js +++ b/examples/nextjs/previews/src/pages/[...identifier].js @@ -1,13 +1,15 @@ import { getAuthString } from '@/utils/getAuthString'; import availableTemplates from '@/wp-templates'; +import availableQueries from '@/wp-templates/templateQueries'; import { createDefaultClient, setGraphQLClient, uriToTemplate, } from '@faustjs/nextjs/pages'; +import { fetchTemplateQueries } from '@faustjs/data-fetching'; export default function Page(props) { - const { templateData } = props; + const { templateData, queriesData } = props; const PageTemplate = availableTemplates[templateData?.template?.id]; @@ -59,10 +61,18 @@ export async function getStaticProps({ return { notFound: true }; } + const queriesData = await fetchTemplateQueries({ + availableQueries, + templateData, + client, + locale: templateData?.seedNode?.locale, + }); + return { props: { uri, templateData: JSON.parse(JSON.stringify(templateData)), + queriesData, }, }; } catch (error) { diff --git a/examples/nextjs/previews/src/queries/getLayout.js b/examples/nextjs/previews/src/queries/getLayout.js new file mode 100644 index 000000000..7f1b7f012 --- /dev/null +++ b/examples/nextjs/previews/src/queries/getLayout.js @@ -0,0 +1,10 @@ +const { default: gql } = require('graphql-tag'); + +export const GET_LAYOUT = gql` + query GetLayout { + generalSettings { + title + description + } + } +`; diff --git a/examples/nextjs/previews/src/queries/getPost.js b/examples/nextjs/previews/src/queries/getPost.js new file mode 100644 index 000000000..30ba7b8d7 --- /dev/null +++ b/examples/nextjs/previews/src/queries/getPost.js @@ -0,0 +1,27 @@ +import gql from 'graphql-tag'; + +export const GET_POST = gql` + query GetPost($databaseId: ID!, $asPreview: Boolean = false) { + post(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) { + title + content + date + author { + node { + name + } + } + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + } + } +`; diff --git a/examples/nextjs/previews/src/wp-templates/page.js b/examples/nextjs/previews/src/wp-templates/page.js index f604fc64c..334e5de77 100644 --- a/examples/nextjs/previews/src/wp-templates/page.js +++ b/examples/nextjs/previews/src/wp-templates/page.js @@ -1,4 +1,4 @@ -export default function PageTemplate({ templateData }) { +export default function Component({ templateData }) { const { seedQuery } = templateData || {}; const page = seedQuery?.data?.page; diff --git a/examples/nextjs/previews/src/wp-templates/single.js b/examples/nextjs/previews/src/wp-templates/single.js index d1f53a512..36b82be56 100644 --- a/examples/nextjs/previews/src/wp-templates/single.js +++ b/examples/nextjs/previews/src/wp-templates/single.js @@ -1,3 +1,6 @@ +import { GET_LAYOUT } from '@/queries/getLayout'; +import { GET_POST } from '@/queries/getPost'; + export default function SingleTemplate({ templateData }) { const { seedQuery } = templateData || {}; const post = seedQuery?.data?.post; @@ -34,3 +37,16 @@ export default function SingleTemplate({ templateData }) { ); } + +export const queries = [ + { + query: GET_LAYOUT, + }, + { + query: GET_POST, + variables: ({ databaseId }, ctx) => ({ + databaseId, + asPreview: ctx?.asPreview, + }), + }, +]; diff --git a/examples/nextjs/previews/src/wp-templates/templateQueries.js b/examples/nextjs/previews/src/wp-templates/templateQueries.js new file mode 100644 index 000000000..ac3c0b582 --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/templateQueries.js @@ -0,0 +1,3 @@ +import { queries as single } from './single'; + +export default { single }; diff --git a/packages/data-fetching/README.md b/packages/data-fetching/README.md new file mode 100644 index 000000000..14294dfc8 --- /dev/null +++ b/packages/data-fetching/README.md @@ -0,0 +1 @@ +# @faustjs/data-fetching diff --git a/packages/data-fetching/fetchTemplateQueries.js b/packages/data-fetching/fetchTemplateQueries.js new file mode 100644 index 000000000..be82acda3 --- /dev/null +++ b/packages/data-fetching/fetchTemplateQueries.js @@ -0,0 +1,49 @@ +/** + * @file Fetches template-specific GraphQL queries for FaustJS templates + */ + +/** + * @param {Object} params + * @param {Object.} params.availableQueries - Map of template IDs to their queries + * @param {Object} params.templateData - Template data with seedNode and template info + * @param {Object} params.client - GraphQL client with request method + * @param {Object} [params.extraVariables={}] - Additional variables for queries + * @param {string} [params.locale] - Locale for internationalization + * @returns {Promise} Array of query results or undefined + */ +export async function fetchTemplateQueries({ + availableQueries, + templateData, + client, + extraVariables = {}, + locale, +}) { + if (!client) { + throw new Error('GraphQL client is required to fetch template queries'); + } + + // Get the template queries for the current template + const templateQueries = availableQueries[templateData?.template?.id]; + + if (templateQueries) { + const queryCalls = templateQueries.map(({ query, variables }) => { + const queryVariables = variables + ? variables( + templateData.seedNode, + { + asPreview: false, + locale, + }, + extraVariables, + ) + : undefined; + + return client.request({ + query, + variables: queryVariables, + }); + }); + + return await Promise.all(queryCalls); + } +} diff --git a/packages/data-fetching/index.js b/packages/data-fetching/index.js new file mode 100644 index 000000000..748305b01 --- /dev/null +++ b/packages/data-fetching/index.js @@ -0,0 +1,6 @@ +/** + * @file Main entry point for the data-fetching package + */ + +// Export data fetching utilities +export { fetchTemplateQueries } from './fetchTemplateQueries.js'; diff --git a/packages/data-fetching/package.json b/packages/data-fetching/package.json new file mode 100644 index 000000000..13e94bacc --- /dev/null +++ b/packages/data-fetching/package.json @@ -0,0 +1,23 @@ +{ + "name": "@faustjs/data-fetching", + "version": "0.0.1-alpha.0", + "description": "Data fetching utilities for FaustJS", + "type": "module", + "exports": { + ".": "./index.js" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "MIT", + "packageManager": "pnpm@10.14.0", + "engines": { + "node": ">=24" + }, + "peerDependencies": { + "graphql": "^16.0.0", + "graphql-tag": "^2.12.0" + } +} diff --git a/packages/nextjs/pages/templateHierarchy.js b/packages/nextjs/pages/templateHierarchy.js index 3014cc904..e9afbc41b 100644 --- a/packages/nextjs/pages/templateHierarchy.js +++ b/packages/nextjs/pages/templateHierarchy.js @@ -29,10 +29,11 @@ export async function uriToTemplate({ /** @type {import('../types.js').NextJSTemplateData} */ const returnData = { uri, - seedQuery: undefined, + seedQuery: undefined, // TODO remove in favor of seedNode availableTemplates: undefined, possibleTemplates: undefined, template: undefined, + seedNode: undefined, }; // Get the GraphQL client - use provided one or get configured one @@ -48,6 +49,8 @@ export async function uriToTemplate({ const seedNode = data?.nodeByUri || data?.contentNode; + returnData.seedNode = seedNode ?? error; + if (error) { console.error('Error fetching seedQuery:', error); return returnData; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22b1a97fa..dad6121ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,6 +90,9 @@ importers: examples/nextjs/previews: dependencies: + '@faustjs/data-fetching': + specifier: workspace:* + version: link:../../../packages/data-fetching '@faustjs/nextjs': specifier: workspace:* version: link:../../../packages/nextjs @@ -214,6 +217,15 @@ importers: specifier: ^16.8.1 version: 16.11.0 + packages/data-fetching: + dependencies: + graphql: + specifier: ^16.0.0 + version: 16.11.0 + graphql-tag: + specifier: ^2.12.0 + version: 2.12.6(graphql@16.11.0) + packages/graphql: {} packages/nextjs: @@ -6009,7 +6021,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.5.1)) @@ -6068,7 +6080,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -6094,14 +6106,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color @@ -6145,7 +6157,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 01c7132072f12f350d43d5655a3b9bb8fbe9ac48 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Tue, 19 Aug 2025 15:37:13 +0200 Subject: [PATCH 06/13] new templates --- .../previews/src/pages/[...identifier].js | 2 +- .../nextjs/previews/src/queries/getArchive.js | 68 ++++++++++++++ .../nextjs/previews/src/queries/getPage.js | 27 ++++++ examples/nextjs/previews/src/queries/index.js | 5 + .../previews/src/wp-templates/archive.js | 93 ++++++++++++------- .../nextjs/previews/src/wp-templates/page.js | 62 +++++++++---- .../previews/src/wp-templates/single.js | 58 ++++++------ .../src/wp-templates/templateQueries.js | 3 - .../data-fetching/fetchTemplateQueries.js | 22 +++-- packages/graphql/client.js | 12 ++- 10 files changed, 261 insertions(+), 91 deletions(-) create mode 100644 examples/nextjs/previews/src/queries/getArchive.js create mode 100644 examples/nextjs/previews/src/queries/getPage.js create mode 100644 examples/nextjs/previews/src/queries/index.js delete mode 100644 examples/nextjs/previews/src/wp-templates/templateQueries.js diff --git a/examples/nextjs/previews/src/pages/[...identifier].js b/examples/nextjs/previews/src/pages/[...identifier].js index 5917c95ed..49682e944 100644 --- a/examples/nextjs/previews/src/pages/[...identifier].js +++ b/examples/nextjs/previews/src/pages/[...identifier].js @@ -1,6 +1,6 @@ import { getAuthString } from '@/utils/getAuthString'; import availableTemplates from '@/wp-templates'; -import availableQueries from '@/wp-templates/templateQueries'; +import availableQueries from '@/queries'; import { createDefaultClient, setGraphQLClient, diff --git a/examples/nextjs/previews/src/queries/getArchive.js b/examples/nextjs/previews/src/queries/getArchive.js new file mode 100644 index 000000000..fc59b7f14 --- /dev/null +++ b/examples/nextjs/previews/src/queries/getArchive.js @@ -0,0 +1,68 @@ +import gql from 'graphql-tag'; + +export const GET_ARCHIVE = gql` + query GetArchivePage($uri: String!) { + nodeByUri(uri: $uri) { + ... on Category { + name + posts { + edges { + node { + id + title + content + date + uri + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + author { + node { + name + } + } + } + } + } + } + ... on Tag { + name + posts { + edges { + node { + id + title + content + date + uri + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + author { + node { + name + } + } + } + } + } + } + } + } +`; diff --git a/examples/nextjs/previews/src/queries/getPage.js b/examples/nextjs/previews/src/queries/getPage.js new file mode 100644 index 000000000..76646f1a5 --- /dev/null +++ b/examples/nextjs/previews/src/queries/getPage.js @@ -0,0 +1,27 @@ +import gql from 'graphql-tag'; + +export const GET_PAGE = gql` + query GetPage($databaseId: ID!, $asPreview: Boolean = false) { + page(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) { + title + content + date + author { + node { + name + } + } + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + } + } +`; diff --git a/examples/nextjs/previews/src/queries/index.js b/examples/nextjs/previews/src/queries/index.js new file mode 100644 index 000000000..5b677233e --- /dev/null +++ b/examples/nextjs/previews/src/queries/index.js @@ -0,0 +1,5 @@ +import { queries as single } from '../wp-templates/single'; +import { queries as page } from '../wp-templates/page'; +import { queries as archive } from '../wp-templates/archive'; + +export default { single, page, archive }; diff --git a/examples/nextjs/previews/src/wp-templates/archive.js b/examples/nextjs/previews/src/wp-templates/archive.js index 1ce8e4951..6417d07a2 100644 --- a/examples/nextjs/previews/src/wp-templates/archive.js +++ b/examples/nextjs/previews/src/wp-templates/archive.js @@ -1,38 +1,69 @@ -export default function ArchiveTemplate({ templateData }) { - const { seedQuery } = templateData || {}; - const posts = seedQuery?.data?.posts?.nodes || []; - const archiveInfo = seedQuery?.data?.category || seedQuery?.data?.tag || {}; +import { GET_LAYOUT } from '@/queries/getLayout'; +import { GET_ARCHIVE } from '@/queries/getArchive'; +import Head from 'next/head'; + +export default function CategoryTemplate({ queriesData }) { + const { getCategory } = queriesData || {}; + const categoryData = getCategory?.data?.nodeByUri; + const { posts, name } = categoryData || {}; return ( <> -

WordPress Archive Template

-

This template would render category, tag, or other archive pages.

-
- {archiveInfo.name ? ( -

Archive: {archiveInfo.name}

- ) : ( -

Archive Page

- )} - {archiveInfo.description &&

{archiveInfo.description}

} - -

Posts in this archive:

- {posts.length > 0 ? ( - posts.map((post) => ( -
-

{post.title}

-

{post.excerpt || 'Post excerpt would appear here...'}

-
- )) - ) : ( -
-

Sample Archive Post

-

- Posts from this category, tag, or archive would be displayed here - using data from the WordPress GraphQL API. -

-
- )} + + {name} + + +
+

{name}

+ + {posts?.edges?.map((item) => { + const post = item.node; + + return ( +
+

+ + {post.title} + +

+ + {post.featuredImage && ( + {post.featuredImage.node.altText + )} + +
+ By {post.author.node.name} on{' '} + {new Date(post.date).toLocaleDateString()} +
+ +
+
+ ); + })}
); } + +export const queries = [ + { + name: 'getLayout', + query: GET_LAYOUT, + }, + { + name: 'getCategory', + query: GET_ARCHIVE, + variables: ({ uri }) => ({ + uri, + }), + }, +]; diff --git a/examples/nextjs/previews/src/wp-templates/page.js b/examples/nextjs/previews/src/wp-templates/page.js index 334e5de77..876cea1b7 100644 --- a/examples/nextjs/previews/src/wp-templates/page.js +++ b/examples/nextjs/previews/src/wp-templates/page.js @@ -1,24 +1,52 @@ -export default function Component({ templateData }) { - const { seedQuery } = templateData || {}; - const page = seedQuery?.data?.page; +import { GET_LAYOUT } from '@/queries/getLayout'; +import { GET_PAGE } from '@/queries/getPage'; +import Head from 'next/head'; + +export default function PageTemplate({ queriesData }) { + const { getPage } = queriesData || {}; + const { title, content, featuredImage } = getPage?.data?.page || {}; return ( <> -

WordPress Page Template

-

This template would render individual WordPress pages.

-
- {page ? ( - <> -

{page.title}

-
- - ) : ( -

- Page title, content, and metadata would be displayed here using data - from the WordPress GraphQL API. -

+ + {title} + + +
+
+

+ {title} +

+
+ + {featuredImage && ( + )} -
+ +
+ ); } + +export const queries = [ + { + name: 'getLayout', + query: GET_LAYOUT, + }, + { + name: 'getPage', + query: GET_PAGE, + variables: ({ databaseId }, ctx) => ({ + databaseId, + asPreview: ctx?.asPreview, + }), + }, +]; diff --git a/examples/nextjs/previews/src/wp-templates/single.js b/examples/nextjs/previews/src/wp-templates/single.js index 36b82be56..ef7479c3e 100644 --- a/examples/nextjs/previews/src/wp-templates/single.js +++ b/examples/nextjs/previews/src/wp-templates/single.js @@ -1,48 +1,48 @@ import { GET_LAYOUT } from '@/queries/getLayout'; import { GET_POST } from '@/queries/getPost'; +import Head from 'next/head'; -export default function SingleTemplate({ templateData }) { - const { seedQuery } = templateData || {}; - const post = seedQuery?.data?.post; +export default function SingleTemplate({ queriesData }) { + const { getPost } = queriesData || {}; + const { title, content, featuredImage } = getPost?.data?.post || {}; return ( <> -

WordPress Single Post Template

-

This template would render individual blog posts.

-
- {post ? ( -
-

{post.title}

-
- {post.categories?.nodes && ( -
- Categories: - {post.categories.nodes.map((cat) => cat.name).join(', ')} -
- )} - {post.tags?.nodes && ( -
- Tags: - {post.tags.nodes.map((tag) => tag.name).join(', ')} -
- )} -
- ) : ( -

- Blog post title, content, categories, tags, and other metadata would - be displayed here using data from the WordPress GraphQL API. -

+ + {title} + + +
+
+

+ {title} +

+
+ + {featuredImage && ( + )} -
+ +
+ ); } export const queries = [ { + name: 'getLayout', query: GET_LAYOUT, }, { + name: 'getPost', query: GET_POST, variables: ({ databaseId }, ctx) => ({ databaseId, diff --git a/examples/nextjs/previews/src/wp-templates/templateQueries.js b/examples/nextjs/previews/src/wp-templates/templateQueries.js deleted file mode 100644 index ac3c0b582..000000000 --- a/examples/nextjs/previews/src/wp-templates/templateQueries.js +++ /dev/null @@ -1,3 +0,0 @@ -import { queries as single } from './single'; - -export default { single }; diff --git a/packages/data-fetching/fetchTemplateQueries.js b/packages/data-fetching/fetchTemplateQueries.js index be82acda3..9db1ddb98 100644 --- a/packages/data-fetching/fetchTemplateQueries.js +++ b/packages/data-fetching/fetchTemplateQueries.js @@ -2,6 +2,8 @@ * @file Fetches template-specific GraphQL queries for FaustJS templates */ +import { print } from 'graphql'; + /** * @param {Object} params * @param {Object.} params.availableQueries - Map of template IDs to their queries @@ -15,7 +17,7 @@ export async function fetchTemplateQueries({ availableQueries, templateData, client, - extraVariables = {}, + extraVariables, locale, }) { if (!client) { @@ -38,12 +40,20 @@ export async function fetchTemplateQueries({ ) : undefined; - return client.request({ - query, - variables: queryVariables, - }); + return client.request(print(query), queryVariables); }); - return await Promise.all(queryCalls); + const results = await Promise.all(queryCalls); + + return results.reduce((acc, result, index) => { + const queryName = templateQueries[index].name ?? `query${index + 1}`; + + return { + ...acc, + [queryName]: result, + }; + }, {}); } + + return null; } diff --git a/packages/graphql/client.js b/packages/graphql/client.js index 2ad3cfeca..87552e174 100644 --- a/packages/graphql/client.js +++ b/packages/graphql/client.js @@ -60,15 +60,19 @@ export function createDefaultGraphQLClient(wordpressUrl, headers = {}) { }); if (!response.ok) { - console.error(); + const message = await response.json(); + return { - error: `GraphQL request failed: ${response.status}`, - message: await response.body.text(), + error: `GraphQL request failed: ${response.statusText}`, + message: message.errors[0]?.message || 'Unknown error', }; } const result = await response.json(); - return { data: result.data, error: result.errors?.[0]?.message }; + return { + data: result.data, + error: result.errors?.[0]?.message ?? null, + }; } catch (error) { return { error: error.message }; } From b5bf801d65408935e40425bb6d28bc7b13d5b3be Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Tue, 19 Aug 2025 16:37:26 +0200 Subject: [PATCH 07/13] add homepage --- ......identifier].js => [[...identifier]].js} | 6 +- examples/nextjs/previews/src/pages/index.js | 111 ------------------ .../nextjs/previews/src/queries/getPosts.js | 33 ++++++ examples/nextjs/previews/src/queries/index.js | 5 - .../nextjs/previews/src/wp-templates/home.js | 29 +++++ .../src/wp-templates/index-template.js | 33 ------ .../nextjs/previews/src/wp-templates/index.js | 4 +- .../src/wp-templates/templateQueries.js | 6 + packages/nextjs/pages/templateHierarchy.js | 2 + 9 files changed, 74 insertions(+), 155 deletions(-) rename examples/nextjs/previews/src/pages/{[...identifier].js => [[...identifier]].js} (89%) delete mode 100644 examples/nextjs/previews/src/pages/index.js create mode 100644 examples/nextjs/previews/src/queries/getPosts.js delete mode 100644 examples/nextjs/previews/src/queries/index.js create mode 100644 examples/nextjs/previews/src/wp-templates/home.js delete mode 100644 examples/nextjs/previews/src/wp-templates/index-template.js create mode 100644 examples/nextjs/previews/src/wp-templates/templateQueries.js diff --git a/examples/nextjs/previews/src/pages/[...identifier].js b/examples/nextjs/previews/src/pages/[[...identifier]].js similarity index 89% rename from examples/nextjs/previews/src/pages/[...identifier].js rename to examples/nextjs/previews/src/pages/[[...identifier]].js index 49682e944..f83d2582e 100644 --- a/examples/nextjs/previews/src/pages/[...identifier].js +++ b/examples/nextjs/previews/src/pages/[[...identifier]].js @@ -1,6 +1,6 @@ import { getAuthString } from '@/utils/getAuthString'; import availableTemplates from '@/wp-templates'; -import availableQueries from '@/queries'; +import availableQueries from '@/wp-templates/templateQueries'; import { createDefaultClient, setGraphQLClient, @@ -9,15 +9,13 @@ import { import { fetchTemplateQueries } from '@faustjs/data-fetching'; export default function Page(props) { - const { templateData, queriesData } = props; + const { templateData } = props; const PageTemplate = availableTemplates[templateData?.template?.id]; return ; } -// Statically generate the pages, except for draft mode -// More info: https://nextjs.org/docs/pages/guides/draft-mode export async function getStaticProps({ params, draftMode: isDraftModeEnabled, diff --git a/examples/nextjs/previews/src/pages/index.js b/examples/nextjs/previews/src/pages/index.js deleted file mode 100644 index 98bc6ad75..000000000 --- a/examples/nextjs/previews/src/pages/index.js +++ /dev/null @@ -1,111 +0,0 @@ -import Head from 'next/head'; - -export default function Home() { - // Simple hardcoded template data like in the Astro example - const templates = [ - { - data: { - name: 'Single', - type: 'single', - path: 'src/wp-templates/single.js', - description: 'Displays individual blog posts with full content', - }, - }, - { - data: { - name: 'Page', - type: 'page', - path: 'src/wp-templates/page.js', - description: 'Displays individual WordPress pages', - }, - }, - { - data: { - name: 'Archive', - type: 'archive', - path: 'src/wp-templates/archive.js', - description: 'Displays category, tag, and other archive pages', - }, - }, - { - data: { - name: 'Index', - type: 'index', - path: 'src/wp-templates/index-template.js', - description: - "Fallback template for any content that doesn't have a specific template", - }, - }, - ]; - - return ( - <> - - @faustjs/nextjs Example - - -
-

@faustjs/nextjs Template Hierarchy Example

-

- This example demonstrates how the @faustjs/nextjs package discovers - WordPress templates in your Next.js project using the WordPress - template hierarchy. -

- -

Discovered Templates

-

- The following templates were automatically discovered from the{' '} - wp-templates directory: -

- -
- {templates.map((template) => ( -
-

{template.data.name}

-

- Type: {template.data.type} -

-

- Path: {template.data.path} -

-

- Description: {template.data.description} -

-
- ))} -
- -

How It Works

-
-
    -
  1. - Templates are placed in the src/wp-templates/{' '} - directory -
  2. -
  3. - The index.js file exports all templates with dynamic - imports -
  4. -
  5. - Templates are organized by WordPress template hierarchy rules -
  6. -
  7. Each template gets metadata like type and path
  8. -
  9. You can query templates using the template registry
  10. -
-
- -

Live Template Router Demo

-

- See the template hierarchy in action with our catch-all route that - resolves WordPress URLs to templates: -

- -
- - ); -} diff --git a/examples/nextjs/previews/src/queries/getPosts.js b/examples/nextjs/previews/src/queries/getPosts.js new file mode 100644 index 000000000..9cfcdd4e1 --- /dev/null +++ b/examples/nextjs/previews/src/queries/getPosts.js @@ -0,0 +1,33 @@ +import gql from 'graphql-tag'; + +export const GET_POSTS = gql` + query GetPosts { + posts { + edges { + node { + id + title + content + date + uri + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + author { + node { + name + } + } + } + } + } + } +`; diff --git a/examples/nextjs/previews/src/queries/index.js b/examples/nextjs/previews/src/queries/index.js deleted file mode 100644 index 5b677233e..000000000 --- a/examples/nextjs/previews/src/queries/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import { queries as single } from '../wp-templates/single'; -import { queries as page } from '../wp-templates/page'; -import { queries as archive } from '../wp-templates/archive'; - -export default { single, page, archive }; diff --git a/examples/nextjs/previews/src/wp-templates/home.js b/examples/nextjs/previews/src/wp-templates/home.js new file mode 100644 index 000000000..2fc1c310d --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/home.js @@ -0,0 +1,29 @@ +import { BlogPostItem } from '@/components/BlogPostItem'; +import { GET_POSTS } from '@/queries/getPosts'; +import Head from 'next/head'; + +export default function HomeTemplate({ queriesData }) { + const { getPosts } = queriesData || {}; + const posts = getPosts?.data?.posts; + + return ( + <> + + {'Home'} + + + {posts?.edges?.map((item) => { + const post = item.node; + + return ; + })} + + ); +} + +export const queries = [ + { + name: 'getPosts', + query: GET_POSTS, + }, +]; diff --git a/examples/nextjs/previews/src/wp-templates/index-template.js b/examples/nextjs/previews/src/wp-templates/index-template.js deleted file mode 100644 index b50380764..000000000 --- a/examples/nextjs/previews/src/wp-templates/index-template.js +++ /dev/null @@ -1,33 +0,0 @@ -export default function IndexTemplate({ templateData }) { - const { seedQuery } = templateData || {}; - const posts = seedQuery?.data?.posts?.nodes || []; - - return ( - <> -

WordPress Index Template

-

This is the fallback template for all WordPress content.

-
-

- Any WordPress content that doesn't have a specific template would use - this one: -

- {posts.length > 0 ? ( - posts.map((post) => ( -
-

{post.title}

-

{post.excerpt || 'Content would appear here...'}

-
- )) - ) : ( -
-

Sample Content

-

- This is the default template that would render any WordPress - content using data from the WordPress GraphQL API. -

-
- )} -
- - ); -} diff --git a/examples/nextjs/previews/src/wp-templates/index.js b/examples/nextjs/previews/src/wp-templates/index.js index c4b921aaf..119695774 100644 --- a/examples/nextjs/previews/src/wp-templates/index.js +++ b/examples/nextjs/previews/src/wp-templates/index.js @@ -12,8 +12,8 @@ const archive = dynamic(() => import('./archive.js'), { loading: () =>

Loading Archive Template...

, }); -const index = dynamic(() => import('./index-template.js'), { +const home = dynamic(() => import('./home.js'), { loading: () =>

Loading Index Template...

, }); -export default { single, page, archive, index }; +export default { single, page, archive, home }; diff --git a/examples/nextjs/previews/src/wp-templates/templateQueries.js b/examples/nextjs/previews/src/wp-templates/templateQueries.js new file mode 100644 index 000000000..10cc13425 --- /dev/null +++ b/examples/nextjs/previews/src/wp-templates/templateQueries.js @@ -0,0 +1,6 @@ +import { queries as single } from './single'; +import { queries as page } from './page'; +import { queries as archive } from './archive'; +import { queries as home } from './home'; + +export default { single, page, archive, home }; diff --git a/packages/nextjs/pages/templateHierarchy.js b/packages/nextjs/pages/templateHierarchy.js index e9afbc41b..43e365e3f 100644 --- a/packages/nextjs/pages/templateHierarchy.js +++ b/packages/nextjs/pages/templateHierarchy.js @@ -70,6 +70,8 @@ export async function uriToTemplate({ const possibleTemplates = getPossibleTemplates(seedNode); + console.log(possibleTemplates); + returnData.possibleTemplates = possibleTemplates; if (!possibleTemplates || possibleTemplates.length === 0) { From fdb6f0c93cc28cf4c62d04487fa2f44c4884efef Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Tue, 19 Aug 2025 17:18:43 +0200 Subject: [PATCH 08/13] style fixes --- .../nextjs/previews/src/components/Header.js | 2 +- .../nextjs/previews/src/components/Layout.js | 2 +- .../nextjs/previews/src/styles/globals.css | 120 +----------------- 3 files changed, 3 insertions(+), 121 deletions(-) diff --git a/examples/nextjs/previews/src/components/Header.js b/examples/nextjs/previews/src/components/Header.js index d811ca3eb..2d6ad7137 100644 --- a/examples/nextjs/previews/src/components/Header.js +++ b/examples/nextjs/previews/src/components/Header.js @@ -3,7 +3,7 @@ import Link from 'next/link'; export default function Header() { return ( -
+
Headless diff --git a/examples/nextjs/previews/src/components/Layout.js b/examples/nextjs/previews/src/components/Layout.js index 86172c15b..773b4f45c 100644 --- a/examples/nextjs/previews/src/components/Layout.js +++ b/examples/nextjs/previews/src/components/Layout.js @@ -8,7 +8,7 @@ export default function Layout({ children }) { return ( <>
-
+
{children} {router.isPreview && } diff --git a/examples/nextjs/previews/src/styles/globals.css b/examples/nextjs/previews/src/styles/globals.css index af80a2233..5a142e3ec 100644 --- a/examples/nextjs/previews/src/styles/globals.css +++ b/examples/nextjs/previews/src/styles/globals.css @@ -12,126 +12,8 @@ --font-mono: var(--font-geist-mono); } -.main { +body { background: var(--background); color: var(--foreground); font-family: Arial, Helvetica, sans-serif; } - -.main { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - max-width: 900px; - margin: 0 auto; - padding: 20px; - line-height: 1.6; - background: #f9f9f9; -} - -h1 { - color: #2563eb; - border-bottom: 2px solid #e5e7eb; - padding-bottom: 10px; -} - -h2 { - color: #374151; - margin-top: 30px; -} - -code { - background: #f3f4f6; - padding: 2px 6px; - border-radius: 4px; - font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; - font-size: 0.9em; -} - -main { - background: white; - padding: 20px; - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.templates-list { - display: grid; - gap: 15px; - margin: 20px 0; -} - -.template-card { - background: #f8fafc; - border: 1px solid #e2e8f0; - border-radius: 8px; - padding: 20px; - border-left: 4px solid #3b82f6; -} - -.template-card h3 { - margin-top: 0; - color: #1e40af; -} - -.template-card p { - margin: 8px 0; -} - -.how-it-works { - background: #ecfdf5; - border: 1px solid #d1fae5; - border-radius: 8px; - padding: 20px; - margin: 20px 0; -} - -.how-it-works ol { - margin: 0; - padding-left: 20px; -} - -.how-it-works li { - margin-bottom: 8px; -} - -.router-links { - display: flex; - flex-direction: column; - gap: 10px; - margin-top: 15px; -} - -.router-links a { - display: inline-block; - background: #10b981; - color: white; - text-decoration: none; - padding: 10px 15px; - border-radius: 6px; - transition: background-color 0.2s; -} - -.router-links a:hover { - background: #059669; -} - -/* WordPress template styles */ -.content-area { - background: #e8f4f8; - padding: 20px; - border-radius: 8px; - margin-top: 20px; -} - -.post-preview { - background: #f0f8ff; - padding: 15px; - border-radius: 5px; - margin-bottom: 15px; - border-left: 4px solid #0066cc; -} - -.post-preview h3, -.post-preview h4 { - margin-top: 0; - color: #0066cc; -} From 79e2a37261321cdf8ffa10ef8a0d451a7ac33d53 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Wed, 20 Aug 2025 13:03:40 +0200 Subject: [PATCH 09/13] update uri expression --- examples/nextjs/previews/src/pages/[[...identifier]].js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/nextjs/previews/src/pages/[[...identifier]].js b/examples/nextjs/previews/src/pages/[[...identifier]].js index f83d2582e..3eea8f967 100644 --- a/examples/nextjs/previews/src/pages/[[...identifier]].js +++ b/examples/nextjs/previews/src/pages/[[...identifier]].js @@ -34,9 +34,7 @@ export async function getStaticProps({ setGraphQLClient(client); - const uri = Array.isArray(params?.identifier) - ? '/' + params.identifier.join('/') + '/' - : '/'; + const uri = params?.identifier ? `/${params.identifier.join('/')}/` : '/'; const variables = isDraftModeEnabled ? { From 14be433d91f7edcc7f62e74ccd5085cb276582dd Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Wed, 20 Aug 2025 13:12:40 +0200 Subject: [PATCH 10/13] rename example name, add readme --- .../{previews => kitchen-sink}/.gitignore | 0 examples/nextjs/kitchen-sink/README.md | 40 ++++++++++++++++++ .../eslint.config.mjs | 0 .../{previews => kitchen-sink}/jsconfig.json | 0 .../next.config.mjs | 0 .../{previews => kitchen-sink}/package.json | 2 +- .../postcss.config.mjs | 0 .../public/favicon.ico | Bin .../src/components/BlogPostItem.js | 0 .../src/components/Header.js | 0 .../src/components/Layout.js | 0 .../src/components/PreviewButton.js | 0 .../src/pages/[[...identifier]].js | 0 .../src/pages/_app.js | 0 .../src/pages/_document.js | 0 .../src/pages/api/disable-preview.js | 0 .../src/pages/api/preview.js | 0 .../src/queries/getArchive.js | 0 .../src/queries/getLayout.js | 0 .../src/queries/getPage.js | 0 .../src/queries/getPost.js | 0 .../src/queries/getPosts.js | 0 .../src/styles/globals.css | 0 .../src/utils/getAuthString.js | 0 .../src/wp-templates/archive.js | 0 .../src/wp-templates/home.js | 0 .../src/wp-templates/index.js | 2 +- .../src/wp-templates/page.js | 0 .../src/wp-templates/single.js | 0 .../src/wp-templates/templateQueries.js | 0 30 files changed, 42 insertions(+), 2 deletions(-) rename examples/nextjs/{previews => kitchen-sink}/.gitignore (100%) create mode 100644 examples/nextjs/kitchen-sink/README.md rename examples/nextjs/{previews => kitchen-sink}/eslint.config.mjs (100%) rename examples/nextjs/{previews => kitchen-sink}/jsconfig.json (100%) rename examples/nextjs/{previews => kitchen-sink}/next.config.mjs (100%) rename examples/nextjs/{previews => kitchen-sink}/package.json (92%) rename examples/nextjs/{previews => kitchen-sink}/postcss.config.mjs (100%) rename examples/nextjs/{previews => kitchen-sink}/public/favicon.ico (100%) rename examples/nextjs/{previews => kitchen-sink}/src/components/BlogPostItem.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/components/Header.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/components/Layout.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/components/PreviewButton.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/pages/[[...identifier]].js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/pages/_app.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/pages/_document.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/pages/api/disable-preview.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/pages/api/preview.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/queries/getArchive.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/queries/getLayout.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/queries/getPage.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/queries/getPost.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/queries/getPosts.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/styles/globals.css (100%) rename examples/nextjs/{previews => kitchen-sink}/src/utils/getAuthString.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/wp-templates/archive.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/wp-templates/home.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/wp-templates/index.js (92%) rename examples/nextjs/{previews => kitchen-sink}/src/wp-templates/page.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/wp-templates/single.js (100%) rename examples/nextjs/{previews => kitchen-sink}/src/wp-templates/templateQueries.js (100%) diff --git a/examples/nextjs/previews/.gitignore b/examples/nextjs/kitchen-sink/.gitignore similarity index 100% rename from examples/nextjs/previews/.gitignore rename to examples/nextjs/kitchen-sink/.gitignore diff --git a/examples/nextjs/kitchen-sink/README.md b/examples/nextjs/kitchen-sink/README.md new file mode 100644 index 000000000..a8b986645 --- /dev/null +++ b/examples/nextjs/kitchen-sink/README.md @@ -0,0 +1,40 @@ +# Kitchen Sink Example + +A comprehensive Next.js example showcasing FaustJS features including template hierarchy, data fetching, and WordPress integration. + +## Features + +- **Template Hierarchy**: Dynamic WordPress template mapping (single, page, archive, home) +- **Data Fetching**: Server-side rendering with WordPress GraphQL data +- **Preview Mode**: WordPress post/page previews with authentication +- **Fallback Routing**: Catch-all routing with blocking fallback strategy +- **Dynamic Loading**: Code-split templates for optimal performance + +## Quick Start + +1. Install dependencies: + + ```bash + npm install + ``` + +2. Configure environment variables: + + ```bash + cp .env.example .env.local + # Add your NEXT_PUBLIC_WORDPRESS_URL + ``` + +3. Run development server: + ```bash + npm run dev + ``` + +## Architecture + +- Uses `[[...identifier]].js` for dynamic WordPress routing +- Template queries are fetched server-side using `@faustjs/data-fetching` +- WordPress templates are dynamically loaded based on content type +- Supports both static generation and draft previews + +Perfect for testing FaustJS capabilities and as a reference implementation. diff --git a/examples/nextjs/previews/eslint.config.mjs b/examples/nextjs/kitchen-sink/eslint.config.mjs similarity index 100% rename from examples/nextjs/previews/eslint.config.mjs rename to examples/nextjs/kitchen-sink/eslint.config.mjs diff --git a/examples/nextjs/previews/jsconfig.json b/examples/nextjs/kitchen-sink/jsconfig.json similarity index 100% rename from examples/nextjs/previews/jsconfig.json rename to examples/nextjs/kitchen-sink/jsconfig.json diff --git a/examples/nextjs/previews/next.config.mjs b/examples/nextjs/kitchen-sink/next.config.mjs similarity index 100% rename from examples/nextjs/previews/next.config.mjs rename to examples/nextjs/kitchen-sink/next.config.mjs diff --git a/examples/nextjs/previews/package.json b/examples/nextjs/kitchen-sink/package.json similarity index 92% rename from examples/nextjs/previews/package.json rename to examples/nextjs/kitchen-sink/package.json index e2fb03d82..3faedb491 100644 --- a/examples/nextjs/previews/package.json +++ b/examples/nextjs/kitchen-sink/package.json @@ -1,5 +1,5 @@ { - "name": "@faustjs/nextjs-preview-example", + "name": "@faustjs/kitchen-sink-example", "version": "0.1.0", "private": true, "scripts": { diff --git a/examples/nextjs/previews/postcss.config.mjs b/examples/nextjs/kitchen-sink/postcss.config.mjs similarity index 100% rename from examples/nextjs/previews/postcss.config.mjs rename to examples/nextjs/kitchen-sink/postcss.config.mjs diff --git a/examples/nextjs/previews/public/favicon.ico b/examples/nextjs/kitchen-sink/public/favicon.ico similarity index 100% rename from examples/nextjs/previews/public/favicon.ico rename to examples/nextjs/kitchen-sink/public/favicon.ico diff --git a/examples/nextjs/previews/src/components/BlogPostItem.js b/examples/nextjs/kitchen-sink/src/components/BlogPostItem.js similarity index 100% rename from examples/nextjs/previews/src/components/BlogPostItem.js rename to examples/nextjs/kitchen-sink/src/components/BlogPostItem.js diff --git a/examples/nextjs/previews/src/components/Header.js b/examples/nextjs/kitchen-sink/src/components/Header.js similarity index 100% rename from examples/nextjs/previews/src/components/Header.js rename to examples/nextjs/kitchen-sink/src/components/Header.js diff --git a/examples/nextjs/previews/src/components/Layout.js b/examples/nextjs/kitchen-sink/src/components/Layout.js similarity index 100% rename from examples/nextjs/previews/src/components/Layout.js rename to examples/nextjs/kitchen-sink/src/components/Layout.js diff --git a/examples/nextjs/previews/src/components/PreviewButton.js b/examples/nextjs/kitchen-sink/src/components/PreviewButton.js similarity index 100% rename from examples/nextjs/previews/src/components/PreviewButton.js rename to examples/nextjs/kitchen-sink/src/components/PreviewButton.js diff --git a/examples/nextjs/previews/src/pages/[[...identifier]].js b/examples/nextjs/kitchen-sink/src/pages/[[...identifier]].js similarity index 100% rename from examples/nextjs/previews/src/pages/[[...identifier]].js rename to examples/nextjs/kitchen-sink/src/pages/[[...identifier]].js diff --git a/examples/nextjs/previews/src/pages/_app.js b/examples/nextjs/kitchen-sink/src/pages/_app.js similarity index 100% rename from examples/nextjs/previews/src/pages/_app.js rename to examples/nextjs/kitchen-sink/src/pages/_app.js diff --git a/examples/nextjs/previews/src/pages/_document.js b/examples/nextjs/kitchen-sink/src/pages/_document.js similarity index 100% rename from examples/nextjs/previews/src/pages/_document.js rename to examples/nextjs/kitchen-sink/src/pages/_document.js diff --git a/examples/nextjs/previews/src/pages/api/disable-preview.js b/examples/nextjs/kitchen-sink/src/pages/api/disable-preview.js similarity index 100% rename from examples/nextjs/previews/src/pages/api/disable-preview.js rename to examples/nextjs/kitchen-sink/src/pages/api/disable-preview.js diff --git a/examples/nextjs/previews/src/pages/api/preview.js b/examples/nextjs/kitchen-sink/src/pages/api/preview.js similarity index 100% rename from examples/nextjs/previews/src/pages/api/preview.js rename to examples/nextjs/kitchen-sink/src/pages/api/preview.js diff --git a/examples/nextjs/previews/src/queries/getArchive.js b/examples/nextjs/kitchen-sink/src/queries/getArchive.js similarity index 100% rename from examples/nextjs/previews/src/queries/getArchive.js rename to examples/nextjs/kitchen-sink/src/queries/getArchive.js diff --git a/examples/nextjs/previews/src/queries/getLayout.js b/examples/nextjs/kitchen-sink/src/queries/getLayout.js similarity index 100% rename from examples/nextjs/previews/src/queries/getLayout.js rename to examples/nextjs/kitchen-sink/src/queries/getLayout.js diff --git a/examples/nextjs/previews/src/queries/getPage.js b/examples/nextjs/kitchen-sink/src/queries/getPage.js similarity index 100% rename from examples/nextjs/previews/src/queries/getPage.js rename to examples/nextjs/kitchen-sink/src/queries/getPage.js diff --git a/examples/nextjs/previews/src/queries/getPost.js b/examples/nextjs/kitchen-sink/src/queries/getPost.js similarity index 100% rename from examples/nextjs/previews/src/queries/getPost.js rename to examples/nextjs/kitchen-sink/src/queries/getPost.js diff --git a/examples/nextjs/previews/src/queries/getPosts.js b/examples/nextjs/kitchen-sink/src/queries/getPosts.js similarity index 100% rename from examples/nextjs/previews/src/queries/getPosts.js rename to examples/nextjs/kitchen-sink/src/queries/getPosts.js diff --git a/examples/nextjs/previews/src/styles/globals.css b/examples/nextjs/kitchen-sink/src/styles/globals.css similarity index 100% rename from examples/nextjs/previews/src/styles/globals.css rename to examples/nextjs/kitchen-sink/src/styles/globals.css diff --git a/examples/nextjs/previews/src/utils/getAuthString.js b/examples/nextjs/kitchen-sink/src/utils/getAuthString.js similarity index 100% rename from examples/nextjs/previews/src/utils/getAuthString.js rename to examples/nextjs/kitchen-sink/src/utils/getAuthString.js diff --git a/examples/nextjs/previews/src/wp-templates/archive.js b/examples/nextjs/kitchen-sink/src/wp-templates/archive.js similarity index 100% rename from examples/nextjs/previews/src/wp-templates/archive.js rename to examples/nextjs/kitchen-sink/src/wp-templates/archive.js diff --git a/examples/nextjs/previews/src/wp-templates/home.js b/examples/nextjs/kitchen-sink/src/wp-templates/home.js similarity index 100% rename from examples/nextjs/previews/src/wp-templates/home.js rename to examples/nextjs/kitchen-sink/src/wp-templates/home.js diff --git a/examples/nextjs/previews/src/wp-templates/index.js b/examples/nextjs/kitchen-sink/src/wp-templates/index.js similarity index 92% rename from examples/nextjs/previews/src/wp-templates/index.js rename to examples/nextjs/kitchen-sink/src/wp-templates/index.js index 119695774..7b8c16ce4 100644 --- a/examples/nextjs/previews/src/wp-templates/index.js +++ b/examples/nextjs/kitchen-sink/src/wp-templates/index.js @@ -1,4 +1,4 @@ -import dynamic from 'next/dynamic'; +import dynamic from 'next/dynamic.js'; const single = dynamic(() => import('./single.js'), { loading: () =>

Loading Single Template...

, diff --git a/examples/nextjs/previews/src/wp-templates/page.js b/examples/nextjs/kitchen-sink/src/wp-templates/page.js similarity index 100% rename from examples/nextjs/previews/src/wp-templates/page.js rename to examples/nextjs/kitchen-sink/src/wp-templates/page.js diff --git a/examples/nextjs/previews/src/wp-templates/single.js b/examples/nextjs/kitchen-sink/src/wp-templates/single.js similarity index 100% rename from examples/nextjs/previews/src/wp-templates/single.js rename to examples/nextjs/kitchen-sink/src/wp-templates/single.js diff --git a/examples/nextjs/previews/src/wp-templates/templateQueries.js b/examples/nextjs/kitchen-sink/src/wp-templates/templateQueries.js similarity index 100% rename from examples/nextjs/previews/src/wp-templates/templateQueries.js rename to examples/nextjs/kitchen-sink/src/wp-templates/templateQueries.js From d3003d4bd286786a0916c08b3d585d1916b47ad9 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Thu, 21 Aug 2025 14:36:01 +0200 Subject: [PATCH 11/13] init project --- examples/astro/kitchen-sink/.gitignore | 22 ++ examples/astro/kitchen-sink/README.md | 138 ++++++++++++ examples/astro/kitchen-sink/astro.config.mjs | 31 +++ examples/astro/kitchen-sink/package.json | 28 +++ .../kitchen-sink/src/components/Nav.astro | 50 +++++ .../components/TemplateHierarchyInfo.astro | 52 +++++ .../astro/kitchen-sink/src/content.config.js | 7 + examples/astro/kitchen-sink/src/env.d.ts | 7 + .../kitchen-sink/src/layouts/Layout.astro | 36 ++++ .../src/layouts/WordPressLayout.astro | 66 ++++++ .../astro/kitchen-sink/src/pages/404.astro | 24 +++ .../src/pages/[...identifier].astro | 56 +++++ .../astro/kitchen-sink/src/pages/index.astro | 198 ++++++++++++++++++ .../src/pages/wp-templates/archive.astro | 86 ++++++++ .../src/pages/wp-templates/home.astro | 88 ++++++++ .../src/pages/wp-templates/index.astro | 80 +++++++ .../src/pages/wp-templates/single.astro | 73 +++++++ .../kitchen-sink/src/queries/getArchive.js | 68 ++++++ .../kitchen-sink/src/queries/getLayout.js | 10 + .../astro/kitchen-sink/src/queries/getPage.js | 27 +++ .../astro/kitchen-sink/src/queries/getPost.js | 27 +++ .../kitchen-sink/src/queries/getPosts.js | 33 +++ .../kitchen-sink/src/utils/getAuthString.js | 8 + examples/astro/kitchen-sink/tsconfig.json | 9 + packages/astro/templateHierarchy.js | 18 +- packages/graphql/client.js | 2 + pnpm-lock.yaml | 37 +++- 27 files changed, 1271 insertions(+), 10 deletions(-) create mode 100644 examples/astro/kitchen-sink/.gitignore create mode 100644 examples/astro/kitchen-sink/README.md create mode 100644 examples/astro/kitchen-sink/astro.config.mjs create mode 100644 examples/astro/kitchen-sink/package.json create mode 100644 examples/astro/kitchen-sink/src/components/Nav.astro create mode 100644 examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro create mode 100644 examples/astro/kitchen-sink/src/content.config.js create mode 100644 examples/astro/kitchen-sink/src/env.d.ts create mode 100644 examples/astro/kitchen-sink/src/layouts/Layout.astro create mode 100644 examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro create mode 100644 examples/astro/kitchen-sink/src/pages/404.astro create mode 100644 examples/astro/kitchen-sink/src/pages/[...identifier].astro create mode 100644 examples/astro/kitchen-sink/src/pages/index.astro create mode 100644 examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro create mode 100644 examples/astro/kitchen-sink/src/pages/wp-templates/home.astro create mode 100644 examples/astro/kitchen-sink/src/pages/wp-templates/index.astro create mode 100644 examples/astro/kitchen-sink/src/pages/wp-templates/single.astro create mode 100644 examples/astro/kitchen-sink/src/queries/getArchive.js create mode 100644 examples/astro/kitchen-sink/src/queries/getLayout.js create mode 100644 examples/astro/kitchen-sink/src/queries/getPage.js create mode 100644 examples/astro/kitchen-sink/src/queries/getPost.js create mode 100644 examples/astro/kitchen-sink/src/queries/getPosts.js create mode 100644 examples/astro/kitchen-sink/src/utils/getAuthString.js create mode 100644 examples/astro/kitchen-sink/tsconfig.json diff --git a/examples/astro/kitchen-sink/.gitignore b/examples/astro/kitchen-sink/.gitignore new file mode 100644 index 000000000..f26f0594a --- /dev/null +++ b/examples/astro/kitchen-sink/.gitignore @@ -0,0 +1,22 @@ +# Local environment variables +.env +.env.local +.env.production + +# Build output +dist/ +.astro/ + +# Dependencies +node_modules/ + +# Logs +*.log + +# Editor +.vscode/ +.idea/ + +# OS +.DS_Store +Thumbs.db diff --git a/examples/astro/kitchen-sink/README.md b/examples/astro/kitchen-sink/README.md new file mode 100644 index 000000000..433c933ee --- /dev/null +++ b/examples/astro/kitchen-sink/README.md @@ -0,0 +1,138 @@ +# @faustjs/astro Template Hierarchy Example + +This example demonstrates how to use the `@faustjs/astro` package to automatically discover WordPress templates in an Astro project using the WordPress template hierarchy. + +## What This Example Shows + +- **Template Discovery**: Automatically finds WordPress template files in your `wp-templates` directory +- **Content Collections**: Uses Astro's content collections to organize and query templates +- **Template Hierarchy**: Follows WordPress template hierarchy rules for organizing templates +- **Template Resolution**: SSR catch-all route that dynamically resolves WordPress URLs to templates + +## Project Structure + +``` +src/ +├── layouts/ +│ └── WordPressLayout.astro # Shared layout for all templates +├── content.config.js # Content collection configuration +└── pages/ + ├── index.astro # Demo page showing discovered templates + ├── 404.astro # Custom 404 page + ├── [...uri].astro # Catch-all route implementing template resolution + └── wp-templates/ # WordPress template files (protected from direct access) + ├── index.astro # Home/blog template + ├── page.astro # Page template + ├── single-post.astro # Single post template + └── archive.astro # Archive template +``` + +## How It Works + +1. **Template Files**: Place your WordPress templates in `src/pages/wp-templates/` +2. **Auto-Discovery**: The `createTemplateCollection()` function finds all template files +3. **Content Collections**: Templates are available as an Astro content collection with `id` and `path` +4. **SSR Resolution**: The `[...uri].astro` route dynamically fetches content and resolves templates +5. **Shared Layout**: All templates use `WordPressLayout.astro` for consistent styling +6. **Template Protection**: Templates can't be accessed directly (e.g., `/wp-templates/page` returns 404) + +## Running the Example + +```bash +# Install dependencies (includes GraphQL requirements) +pnpm install + +# Copy environment configuration +cp .env.example .env + +# Edit .env to set your WordPress URL +# WORDPRESS_URL=https://your-wordpress-site.com + +# Start development server (SSR mode) +pnpm dev + +# Build for production (outputs server bundle) +pnpm build +``` + +## Dependencies + +This example requires the following dependencies (automatically installed): + +- `@faustjs/astro` - Astro integration with WordPress template hierarchy +- `@faustjs/template-hierarchy` - Core template hierarchy logic +- `astro` - Astro framework (peer dependency) +- `graphql` - GraphQL core library (peer dependency) +- `graphql-tag` - GraphQL query parsing (peer dependency) + +## WordPress Setup + +This example requires a WordPress site with WPGraphQL plugin installed: + +1. **Install WPGraphQL**: Install the [WPGraphQL plugin](https://www.wpgraphql.com/) on your WordPress site +2. **Set Environment Variable**: Copy `.env.example` to `.env` and set your WordPress URL +3. **GraphQL Endpoint**: The endpoint should be `https://your-site.com/graphql` + +### Supported WordPress Content + +The example automatically discovers and creates routes for: + +- **Posts**: Individual blog posts with categories and tags +- **Pages**: Static pages like About, Contact, etc. +- **Category Archives**: Archive pages for each category +- **Tag Archives**: Archive pages for each tag +- **Home Page**: Main blog index + +## Template Discovery + +The `@faustjs/astro` package automatically discovers templates in your `wp-templates` directory: + +- **index.astro** → Home template +- **page.astro** → Page template +- **single-post.astro** → Single post template +- **archive.astro** → Archive template + +Each template is automatically added to the content collection with an `id` and `path`. + +## Template Resolution Demo + +The catch-all route (`[...uri].astro`) fetches real WordPress content and demonstrates URL resolution: + +- `/` → `index.astro` (home page) +- `/about` → `page.astro` (WordPress page) +- `/hello-world` → `single-post.astro` (WordPress post) +- `/category/uncategorized` → `archive.astro` (category archive) +- `/tag/fun` → `archive.astro` (tag archive) + +_Note: Actual URLs depend on your WordPress content_ + +## Content Collection Usage + +```js +// Get all templates +import { getCollection } from 'astro:content'; +const templates = await getCollection('templates'); + +// Find a specific template by id +const pageTemplate = templates.find((t) => t.id === 'page'); + +// Each template has: { id: string, path: string } +console.log(pageTemplate); // { id: 'page', path: 'wp-templates/page' } +``` + +## Real-World Usage + +This example shows how a real WordPress headless site works with SSR: + +1. **WordPress GraphQL API**: Dynamically fetches content from WordPress on each request +2. **Server-Side Rendering**: Renders pages on-demand with fresh WordPress content +3. **Template Resolution**: Uses WordPress template hierarchy to render content +4. **Content Types**: Handles posts, pages, categories, and tags dynamically +5. **SEO Ready**: Generates proper HTML with fresh WordPress content +6. **404 Handling**: Automatically redirects to 404 for non-existent content + +## Learn More + +- [WordPress Template Hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/) +- [Astro Content Collections](https://docs.astro.build/en/guides/content-collections/) +- [@faustjs/template-hierarchy](../packages/template-hierarchy/) diff --git a/examples/astro/kitchen-sink/astro.config.mjs b/examples/astro/kitchen-sink/astro.config.mjs new file mode 100644 index 000000000..b1ccfb253 --- /dev/null +++ b/examples/astro/kitchen-sink/astro.config.mjs @@ -0,0 +1,31 @@ +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + output: 'server', + // Enable SSR for dynamic WordPress content + vite: { + resolve: { + alias: { + '@': '/src', + }, + }, + server: { + watch: { + // Explicitly watch the packages directories + ignored: [ + '**/node_modules/**', + '!**/node_modules/@faustjs/**', // Watch @faustjs packages + ], + followSymlinks: true, + }, + }, + optimizeDeps: { + // Don't pre-bundle workspace packages so changes are picked up immediately + exclude: [ + '@faustjs/astro', + '@faustjs/template-hierarchy', + '@faustjs/graphql', + ], + }, + }, +}); diff --git a/examples/astro/kitchen-sink/package.json b/examples/astro/kitchen-sink/package.json new file mode 100644 index 000000000..7f52963b1 --- /dev/null +++ b/examples/astro/kitchen-sink/package.json @@ -0,0 +1,28 @@ +{ + "name": "@faustjs/astro-kitchen-sink-example", + "private": true, + "version": "0.1.0", + "license": "0BSD", + "type": "module", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro check && astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@faustjs/astro": "workspace:*", + "@faustjs/template-hierarchy": "workspace:*", + "@faustjs/data-fetching": "workspace:*", + "astro": "^5.1.1", + "graphql": "^16.9.0", + "graphql-tag": "^2.12.6" + }, + "devDependencies": { + "typescript": "^5.6.3" + }, + "engines": { + "node": ">=24" + } +} diff --git a/examples/astro/kitchen-sink/src/components/Nav.astro b/examples/astro/kitchen-sink/src/components/Nav.astro new file mode 100644 index 000000000..d35cab7de --- /dev/null +++ b/examples/astro/kitchen-sink/src/components/Nav.astro @@ -0,0 +1,50 @@ +--- +/** + * We've hard coded this but you can use the client to fetch this data from WP Menus! + * import { client, gql } from "../lib/client"; + */ +--- + + + diff --git a/examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro b/examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro new file mode 100644 index 000000000..3bbaafe89 --- /dev/null +++ b/examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro @@ -0,0 +1,52 @@ +--- +const template = Astro.locals.templateData; + +if (!template) { + return null; +} +--- + + diff --git a/examples/astro/kitchen-sink/src/content.config.js b/examples/astro/kitchen-sink/src/content.config.js new file mode 100644 index 000000000..e8c52b83b --- /dev/null +++ b/examples/astro/kitchen-sink/src/content.config.js @@ -0,0 +1,7 @@ +import { defineCollection } from "astro:content"; +import { createTemplateCollection } from "@faustjs/astro"; + +// Set up WordPress template collection +const templates = defineCollection(createTemplateCollection()); + +export const collections = { templates }; diff --git a/examples/astro/kitchen-sink/src/env.d.ts b/examples/astro/kitchen-sink/src/env.d.ts new file mode 100644 index 000000000..7b59111d0 --- /dev/null +++ b/examples/astro/kitchen-sink/src/env.d.ts @@ -0,0 +1,7 @@ +declare namespace App { + interface Locals { + templateData?: import('./lib/templateHierarchy').TemplateData; + isPreview?: boolean; + client?: import('./lib/types').GraphQLClient; + } +} diff --git a/examples/astro/kitchen-sink/src/layouts/Layout.astro b/examples/astro/kitchen-sink/src/layouts/Layout.astro new file mode 100644 index 000000000..f078b89be --- /dev/null +++ b/examples/astro/kitchen-sink/src/layouts/Layout.astro @@ -0,0 +1,36 @@ +--- +// import Nav from '../components/Nav.astro'; +// import TemplateHierarchyInfo from "../components/TemplateHierarchyInfo.astro"; +--- + + + + + + + + + Astro Basics + + + + +
+ +
+ + + + diff --git a/examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro b/examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro new file mode 100644 index 000000000..2c95b429f --- /dev/null +++ b/examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro @@ -0,0 +1,66 @@ +--- +export interface Props { + title: string; +} + +const { title } = Astro.props; +--- + + + + + + + + {title} + + +
+ +
+ + + + diff --git a/examples/astro/kitchen-sink/src/pages/404.astro b/examples/astro/kitchen-sink/src/pages/404.astro new file mode 100644 index 000000000..b220b4f32 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/404.astro @@ -0,0 +1,24 @@ +--- +import WordPressLayout from '@/layouts/WordPressLayout.astro'; + +// Set the response status to 404 +Astro.response.status = 404; +--- + + +

404 - Page Not Found

+

Sorry, the page you're looking for doesn't exist.

+
+

This could happen if:

+
    +
  • The page has been moved or deleted
  • +
  • You typed the URL incorrectly
  • +
  • The WordPress content couldn't be found
  • +
+

+ + ← Go back to the homepage + +

+
+
diff --git a/examples/astro/kitchen-sink/src/pages/[...identifier].astro b/examples/astro/kitchen-sink/src/pages/[...identifier].astro new file mode 100644 index 000000000..6d7384cc2 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/[...identifier].astro @@ -0,0 +1,56 @@ +--- +import { + uriToTemplate, + createDefaultClient, + setGraphQLClient, +} from '@faustjs/astro'; +import { getAuthString } from '../utils/getAuthString.js'; + +const isPreview = Astro.url.searchParams.get('preview') === 'true'; + +const headers = isPreview + ? { + Authorization: getAuthString(), + } + : null; + +// Set up GraphQL client using environment variable +const client = createDefaultClient(import.meta.env.WORDPRESS_URL, headers); + +setGraphQLClient(client); + +// URI comes as a string from Astro params, ensure it starts with / +const { identifier = '/' } = Astro.params; + +const variables = isPreview + ? { + id: identifier, + asPreview: true, + } + : { uri: identifier }; + +console.log('VVV', variables); + +const results = await uriToTemplate(variables); + +console.log(results); + +Astro.locals.templateData = results; +Astro.locals.isPreview = isPreview || false; +Astro.locals.client = client; + +if (results.template) { + return Astro.rewrite(results.template.path); +} +--- + +

Oops! You shouldn't be here, something went wrong!

+
+	
+	  {JSON.stringify(
+		results,
+		null,
+		2
+	  )}
+	
+  
diff --git a/examples/astro/kitchen-sink/src/pages/index.astro b/examples/astro/kitchen-sink/src/pages/index.astro new file mode 100644 index 000000000..9859cf006 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/index.astro @@ -0,0 +1,198 @@ +--- +// Demo page showing template discovery +import { getCollection } from 'astro:content'; + +// Get all templates from our content collection +const templates = await getCollection('templates'); +--- + + + + + + + + @faustjs/astro Example + + +
+

@faustjs/astro Template Hierarchy Example

+

+ This example demonstrates how the @faustjs/astro package discovers + WordPress templates in your Astro project using the WordPress template + hierarchy. +

+ +

Discovered Templates

+

+ The following templates were automatically discovered from the wp-templates directory: +

+ +
+ { + templates.map((template) => ( +
+

{template.data.name}

+

+ Type: {template.data.type} +

+

+ Priority: {template.data.priority} +

+

+ Path: {template.data.path} +

+ {template.data.description && ( +

+ Description: {template.data.description} +

+ )} +
+ )) + } +
+ +

How It Works

+
+
    +
  1. + Templates are placed in the src/pages/wp-templates/ directory +
  2. +
  3. + The createTemplateCollection() function automatically discovers + them +
  4. +
  5. Templates are organized by WordPress template hierarchy rules
  6. +
  7. Each template gets metadata like type, priority, and path
  8. +
  9. You can query templates using Astro's content collections API
  10. +
+
+ +

Live Template Router Demo

+

+ See the template hierarchy in action with our catch-all route that + resolves WordPress URLs to templates: +

+ +
+ + + + diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro new file mode 100644 index 000000000..89eb63d38 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro @@ -0,0 +1,86 @@ +--- +import Layout from "../../layouts/Layout.astro"; +import { authHeaders, client, gql } from "../../lib/client"; +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ +if (Astro.url.pathname === Astro.originPathname) { + return Astro.rewrite("/404"); +} + +const isPreview = Astro.locals.isPreview; + +const { data, error } = await client.query( + gql` + query ArchiveTemplateNodeQuery($uri: String!) { + node: nodeByUri(uri: $uri) { + __typename + ... on TermNode { + name + description + } + ... on Tag { + contentNodes(where: { stati: [DRAFT, PUBLISH, FUTURE, PENDING] }) { + nodes { + ... on NodeWithTitle { + title + } + uri + } + } + } + ... on Category { + contentNodes(where: { stati: [DRAFT, PUBLISH, FUTURE, PENDING] }) { + nodes { + ... on NodeWithTitle { + title + } + uri + } + } + } + } + terms { + nodes { + uri + } + } + } + `, + { + uri: Astro.originPathname, + }, + { + fetchOptions: { + headers: { + ...authHeaders(isPreview), + }, + }, + } +); + +if (error) { + console.error("Error fetching data:", error); + return Astro.rewrite("/500"); +} +--- + + +
+

{data.node.name}

+

+

    + { + data.node.contentNodes.nodes.map((content) => ( +
  1. + +
  2. + )) + } +
+
+
diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro new file mode 100644 index 000000000..816aada23 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro @@ -0,0 +1,88 @@ +--- +import Layout from "../../layouts/Layout.astro"; +import { authHeaders, client, gql } from "../../lib/client"; + +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ +if (Astro.url.pathname === Astro.originPathname) { + return Astro.rewrite("/404"); +} + +const isPreview = Astro.locals.isPreview; + +const { data, error } = await client.query( + gql` + query homeTemplatePostQuery { + posts(first: 6, where: { stati: [DRAFT, PUBLISH, FUTURE, PENDING] }) { + nodes { + id + title + uri + excerpt + } + } + } + `, + {}, + { + fetchOptions: { + headers: { + ...authHeaders(isPreview), + }, + }, + } +); + +if (error) { + console.error("Error fetching data:", error); + return Astro.rewrite("/500"); +} +--- + + +
+

My WP + Astro Blog!

+ +

I like sharing my life!

+ +
+

Recent Posts

+
+ { + data.posts.nodes.map((post) => { + return ( +
+

{post.title}

+
+ + Read more... + +
+ ); + }) + } +
+
+
+ + + diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro new file mode 100644 index 000000000..2c0cca05d --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro @@ -0,0 +1,80 @@ +--- +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ +if (Astro.url.pathname === Astro.originPathname) { + return Astro.rewrite("/404"); +} + +import Layout from "../../layouts/Layout.astro"; +import { authHeaders, client, gql } from "../../lib/client"; + +const databaseId = Astro.locals.templateData?.databaseId; +const isPreview = Astro.locals.isPreview; + +const query = gql` + query indexTemplateNodeQuery($id: ID!, $isPreview: Boolean = false) { + node: contentNode(id: $id, idType: DATABASE_ID, asPreview: $isPreview) { + __typename + uri + id + ... on NodeWithTitle { + title + } + ... on NodeWithContentEditor { + content + } + } + } +`; + +const { data, error } = await client.query( + query, + { + id: databaseId, + isPreview, + }, + { + fetchOptions: { + headers: { + ...authHeaders(isPreview), + }, + }, + } +); + +if (error) { + console.error("Error fetching data:", error); + return Astro.rewrite("/500"); +} +--- + + +

+ This is the index template for the WordPress template hierarchy. + It will be used to render the WordPress content if no more appropriate template + is provided (e.g. front-page, single, singular, archive, etc). It should never + be used directly. +

+ + {data.node.title &&

} + {data.node.content &&
} + { + !data.node.content && !data.node.title && ( +
+        {JSON.stringify(data ?? {}, null, 2)}
+      
+ ) + } + + + diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro new file mode 100644 index 000000000..e9b772414 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro @@ -0,0 +1,73 @@ +--- +import Layout from '../../layouts/Layout.astro'; +import { GET_POST } from '../../queries/getPost.js'; +import { print } from 'graphql'; + +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ +if (Astro.url.pathname === Astro.originPathname) { + return Astro.rewrite('/404'); +} + +const isPreview = Astro.locals.isPreview; +const databaseId = Astro.locals.templateData?.seedNode?.databaseId; + +const { data, error } = await Astro.locals.client.request(print(GET_POST), { + databaseId, + asPreview: isPreview, +}); + +if (error) { + console.error('Error fetching data:', error); + return Astro.rewrite('/500'); +} + +if (!data.post) { + console.error('HTTP/404 - Not Found in WordPress:', databaseId); + return Astro.rewrite('/404'); +} + +const { title, content, featuredImage } = data?.post || {}; +--- + + +
+
+

+ {title} +

+
+ + { + featuredImage && ( + + ) + } + +
+
+
+ + diff --git a/examples/astro/kitchen-sink/src/queries/getArchive.js b/examples/astro/kitchen-sink/src/queries/getArchive.js new file mode 100644 index 000000000..fc59b7f14 --- /dev/null +++ b/examples/astro/kitchen-sink/src/queries/getArchive.js @@ -0,0 +1,68 @@ +import gql from 'graphql-tag'; + +export const GET_ARCHIVE = gql` + query GetArchivePage($uri: String!) { + nodeByUri(uri: $uri) { + ... on Category { + name + posts { + edges { + node { + id + title + content + date + uri + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + author { + node { + name + } + } + } + } + } + } + ... on Tag { + name + posts { + edges { + node { + id + title + content + date + uri + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + author { + node { + name + } + } + } + } + } + } + } + } +`; diff --git a/examples/astro/kitchen-sink/src/queries/getLayout.js b/examples/astro/kitchen-sink/src/queries/getLayout.js new file mode 100644 index 000000000..7f1b7f012 --- /dev/null +++ b/examples/astro/kitchen-sink/src/queries/getLayout.js @@ -0,0 +1,10 @@ +const { default: gql } = require('graphql-tag'); + +export const GET_LAYOUT = gql` + query GetLayout { + generalSettings { + title + description + } + } +`; diff --git a/examples/astro/kitchen-sink/src/queries/getPage.js b/examples/astro/kitchen-sink/src/queries/getPage.js new file mode 100644 index 000000000..76646f1a5 --- /dev/null +++ b/examples/astro/kitchen-sink/src/queries/getPage.js @@ -0,0 +1,27 @@ +import gql from 'graphql-tag'; + +export const GET_PAGE = gql` + query GetPage($databaseId: ID!, $asPreview: Boolean = false) { + page(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) { + title + content + date + author { + node { + name + } + } + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + } + } +`; diff --git a/examples/astro/kitchen-sink/src/queries/getPost.js b/examples/astro/kitchen-sink/src/queries/getPost.js new file mode 100644 index 000000000..30ba7b8d7 --- /dev/null +++ b/examples/astro/kitchen-sink/src/queries/getPost.js @@ -0,0 +1,27 @@ +import gql from 'graphql-tag'; + +export const GET_POST = gql` + query GetPost($databaseId: ID!, $asPreview: Boolean = false) { + post(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) { + title + content + date + author { + node { + name + } + } + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + } + } +`; diff --git a/examples/astro/kitchen-sink/src/queries/getPosts.js b/examples/astro/kitchen-sink/src/queries/getPosts.js new file mode 100644 index 000000000..9cfcdd4e1 --- /dev/null +++ b/examples/astro/kitchen-sink/src/queries/getPosts.js @@ -0,0 +1,33 @@ +import gql from 'graphql-tag'; + +export const GET_POSTS = gql` + query GetPosts { + posts { + edges { + node { + id + title + content + date + uri + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + author { + node { + name + } + } + } + } + } + } +`; diff --git a/examples/astro/kitchen-sink/src/utils/getAuthString.js b/examples/astro/kitchen-sink/src/utils/getAuthString.js new file mode 100644 index 000000000..666bc6721 --- /dev/null +++ b/examples/astro/kitchen-sink/src/utils/getAuthString.js @@ -0,0 +1,8 @@ +// Forming the authentication string for WordPress App Password +// More info: https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/ + +export const getAuthString = () => + 'Basic ' + + Buffer.from( + import.meta.env.WP_USERNAME + ':' + import.meta.env.WP_APP_PASSWORD, + ).toString('base64'); diff --git a/examples/astro/kitchen-sink/tsconfig.json b/examples/astro/kitchen-sink/tsconfig.json new file mode 100644 index 000000000..547e4a6ce --- /dev/null +++ b/examples/astro/kitchen-sink/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/packages/astro/templateHierarchy.js b/packages/astro/templateHierarchy.js index a0e471f20..5ef364d02 100644 --- a/packages/astro/templateHierarchy.js +++ b/packages/astro/templateHierarchy.js @@ -20,7 +20,7 @@ console.log( * @param {import('@faustjs/template-hierarchy').UriToTemplateBaseParams & { graphqlClient?: import('./types.js').GraphQLClient }} options - Resolution options * @returns {Promise} The resolved template data */ -export async function uriToTemplate({ uri, graphqlClient }) { +export async function uriToTemplate({ uri, graphqlClient, id, asPreview }) { /** @type {import('@faustjs/template-hierarchy').TemplateData} */ const returnData = { uri, @@ -28,20 +28,30 @@ export async function uriToTemplate({ uri, graphqlClient }) { availableTemplates: undefined, possibleTemplates: undefined, template: undefined, + seedNode: undefined, }; // Get the GraphQL client - use provided one or get configured one const client = getGraphQLClient(graphqlClient); - const { data, error } = await getSeedQuery({ uri, graphqlClient: client }); + const { data, error } = await getSeedQuery({ + uri, + graphqlClient: client, + id, + asPreview, + }); returnData.seedQuery = { data, error }; + const seedNode = data?.nodeByUri || data?.contentNode; + + returnData.seedNode = seedNode ?? error; + if (error) { console.error('Error fetching seedQuery:', error); return returnData; } - if (!data.nodeByUri) { + if (!seedNode) { console.error('HTTP/404 - Not Found in WordPress:', uri); returnData.template = { id: '404 Not Found', path: '/404' }; @@ -58,7 +68,7 @@ export async function uriToTemplate({ uri, graphqlClient }) { return returnData; } - const possibleTemplates = getPossibleTemplates(data.nodeByUri); + const possibleTemplates = getPossibleTemplates(seedNode); returnData.possibleTemplates = possibleTemplates; diff --git a/packages/graphql/client.js b/packages/graphql/client.js index 87552e174..e438e3b5f 100644 --- a/packages/graphql/client.js +++ b/packages/graphql/client.js @@ -59,6 +59,8 @@ export function createDefaultGraphQLClient(wordpressUrl, headers = {}) { body: JSON.stringify({ query, variables }), }); + console.log('RRR', response); + if (!response.ok) { const message = await response.json(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dad6121ba..bc0f0e950 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,6 +66,31 @@ importers: specifier: ^3.0.2 version: 3.0.2 + examples/astro/kitchen-sink: + dependencies: + '@faustjs/astro': + specifier: workspace:* + version: link:../../../packages/astro + '@faustjs/data-fetching': + specifier: workspace:* + version: link:../../../packages/data-fetching + '@faustjs/template-hierarchy': + specifier: workspace:* + version: link:../../../packages/template-hierarchy + astro: + specifier: ^5.1.1 + version: 5.12.8(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.8.3) + graphql: + specifier: ^16.9.0 + version: 16.11.0 + graphql-tag: + specifier: ^2.12.6 + version: 2.12.6(graphql@16.11.0) + devDependencies: + typescript: + specifier: ^5.6.3 + version: 5.8.3 + examples/astro/template-hierarchy: dependencies: '@faustjs/astro': @@ -88,7 +113,7 @@ importers: specifier: ^5.6.3 version: 5.8.3 - examples/nextjs/previews: + examples/nextjs/kitchen-sink: dependencies: '@faustjs/data-fetching': specifier: workspace:* @@ -6021,7 +6046,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.5.1)) @@ -6080,7 +6105,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -6106,14 +6131,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color @@ -6157,7 +6182,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From bb8966a22635e38e86993796813093ab17e20da9 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Fri, 22 Aug 2025 13:54:47 +0200 Subject: [PATCH 12/13] update templates, add data fetching --- examples/astro/kitchen-sink/astro.config.mjs | 2 + examples/astro/kitchen-sink/package.json | 6 +- .../src/components/BlogPostItem.astro | 35 ++++ .../kitchen-sink/src/components/Header.astro | 18 ++ .../kitchen-sink/src/components/Layout.astro | 23 ++ .../kitchen-sink/src/components/Nav.astro | 50 ----- .../components/TemplateHierarchyInfo.astro | 52 ----- .../kitchen-sink/src/layouts/Layout.astro | 36 ---- .../src/layouts/WordPressLayout.astro | 66 ------ .../astro/kitchen-sink/src/pages/404.astro | 32 +-- .../src/pages/[...identifier].astro | 18 +- .../astro/kitchen-sink/src/pages/index.astro | 198 ------------------ .../src/pages/wp-templates/archive.astro | 129 +++++------- .../src/pages/wp-templates/home.astro | 99 ++------- .../src/pages/wp-templates/index.astro | 115 ++++------ .../src/pages/wp-templates/page.astro | 51 +++++ .../src/pages/wp-templates/single.astro | 6 +- .../kitchen-sink/src/queries/getLayout.js | 2 +- .../astro/kitchen-sink/src/styles/globals.css | 1 + pnpm-lock.yaml | 182 +++++++++++++++- 20 files changed, 453 insertions(+), 668 deletions(-) create mode 100644 examples/astro/kitchen-sink/src/components/BlogPostItem.astro create mode 100644 examples/astro/kitchen-sink/src/components/Header.astro create mode 100644 examples/astro/kitchen-sink/src/components/Layout.astro delete mode 100644 examples/astro/kitchen-sink/src/components/Nav.astro delete mode 100644 examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro delete mode 100644 examples/astro/kitchen-sink/src/layouts/Layout.astro delete mode 100644 examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro delete mode 100644 examples/astro/kitchen-sink/src/pages/index.astro create mode 100644 examples/astro/kitchen-sink/src/pages/wp-templates/page.astro create mode 100644 examples/astro/kitchen-sink/src/styles/globals.css diff --git a/examples/astro/kitchen-sink/astro.config.mjs b/examples/astro/kitchen-sink/astro.config.mjs index b1ccfb253..2ec71dc14 100644 --- a/examples/astro/kitchen-sink/astro.config.mjs +++ b/examples/astro/kitchen-sink/astro.config.mjs @@ -1,4 +1,5 @@ import { defineConfig } from 'astro/config'; +import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ output: 'server', @@ -27,5 +28,6 @@ export default defineConfig({ '@faustjs/graphql', ], }, + plugins: [tailwindcss()], }, }); diff --git a/examples/astro/kitchen-sink/package.json b/examples/astro/kitchen-sink/package.json index 7f52963b1..664a4cec2 100644 --- a/examples/astro/kitchen-sink/package.json +++ b/examples/astro/kitchen-sink/package.json @@ -13,11 +13,13 @@ }, "dependencies": { "@faustjs/astro": "workspace:*", - "@faustjs/template-hierarchy": "workspace:*", "@faustjs/data-fetching": "workspace:*", + "@faustjs/template-hierarchy": "workspace:*", + "@tailwindcss/vite": "^4.1.12", "astro": "^5.1.1", "graphql": "^16.9.0", - "graphql-tag": "^2.12.6" + "graphql-tag": "^2.12.6", + "tailwindcss": "^4.1.11" }, "devDependencies": { "typescript": "^5.6.3" diff --git a/examples/astro/kitchen-sink/src/components/BlogPostItem.astro b/examples/astro/kitchen-sink/src/components/BlogPostItem.astro new file mode 100644 index 000000000..420595e43 --- /dev/null +++ b/examples/astro/kitchen-sink/src/components/BlogPostItem.astro @@ -0,0 +1,35 @@ +--- +const { title, date, excerpt, uri, featuredImage } = Astro.props?.post ?? {}; +--- + +
+ + + { + featuredImage && ( + + ) + } + +

+ + {title} + +

+ +
diff --git a/examples/astro/kitchen-sink/src/components/Header.astro b/examples/astro/kitchen-sink/src/components/Header.astro new file mode 100644 index 000000000..a22290c8b --- /dev/null +++ b/examples/astro/kitchen-sink/src/components/Header.astro @@ -0,0 +1,18 @@ +--- +import { GET_LAYOUT } from '@/queries/getLayout'; +import { print } from 'graphql'; + +const { data } = await Astro.locals.client?.request(print(GET_LAYOUT)); +--- + +
+ +
diff --git a/examples/astro/kitchen-sink/src/components/Layout.astro b/examples/astro/kitchen-sink/src/components/Layout.astro new file mode 100644 index 000000000..01f18537a --- /dev/null +++ b/examples/astro/kitchen-sink/src/components/Layout.astro @@ -0,0 +1,23 @@ +--- +import Header from './Header.astro'; +import '../styles/globals.css'; + +const pageTitle = Astro.props.pageTitle; +--- + + + + + + + + + {pageTitle} + + +
+
+ +
+ + diff --git a/examples/astro/kitchen-sink/src/components/Nav.astro b/examples/astro/kitchen-sink/src/components/Nav.astro deleted file mode 100644 index d35cab7de..000000000 --- a/examples/astro/kitchen-sink/src/components/Nav.astro +++ /dev/null @@ -1,50 +0,0 @@ ---- -/** - * We've hard coded this but you can use the client to fetch this data from WP Menus! - * import { client, gql } from "../lib/client"; - */ ---- - - - diff --git a/examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro b/examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro deleted file mode 100644 index 3bbaafe89..000000000 --- a/examples/astro/kitchen-sink/src/components/TemplateHierarchyInfo.astro +++ /dev/null @@ -1,52 +0,0 @@ ---- -const template = Astro.locals.templateData; - -if (!template) { - return null; -} ---- - - diff --git a/examples/astro/kitchen-sink/src/layouts/Layout.astro b/examples/astro/kitchen-sink/src/layouts/Layout.astro deleted file mode 100644 index f078b89be..000000000 --- a/examples/astro/kitchen-sink/src/layouts/Layout.astro +++ /dev/null @@ -1,36 +0,0 @@ ---- -// import Nav from '../components/Nav.astro'; -// import TemplateHierarchyInfo from "../components/TemplateHierarchyInfo.astro"; ---- - - - - - - - - - Astro Basics - - - - -
- -
- - - - diff --git a/examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro b/examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro deleted file mode 100644 index 2c95b429f..000000000 --- a/examples/astro/kitchen-sink/src/layouts/WordPressLayout.astro +++ /dev/null @@ -1,66 +0,0 @@ ---- -export interface Props { - title: string; -} - -const { title } = Astro.props; ---- - - - - - - - - {title} - - -
- -
- - - - diff --git a/examples/astro/kitchen-sink/src/pages/404.astro b/examples/astro/kitchen-sink/src/pages/404.astro index b220b4f32..048321584 100644 --- a/examples/astro/kitchen-sink/src/pages/404.astro +++ b/examples/astro/kitchen-sink/src/pages/404.astro @@ -1,24 +1,26 @@ --- -import WordPressLayout from '@/layouts/WordPressLayout.astro'; +import Layout from '@/components/Layout.astro'; // Set the response status to 404 Astro.response.status = 404; --- - -

404 - Page Not Found

-

Sorry, the page you're looking for doesn't exist.

-
-

This could happen if:

-
    -
  • The page has been moved or deleted
  • -
  • You typed the URL incorrectly
  • -
  • The WordPress content couldn't be found
  • -
-

- + +

- + diff --git a/examples/astro/kitchen-sink/src/pages/[...identifier].astro b/examples/astro/kitchen-sink/src/pages/[...identifier].astro index 6d7384cc2..8e8fd1a02 100644 --- a/examples/astro/kitchen-sink/src/pages/[...identifier].astro +++ b/examples/astro/kitchen-sink/src/pages/[...identifier].astro @@ -16,7 +16,6 @@ const headers = isPreview // Set up GraphQL client using environment variable const client = createDefaultClient(import.meta.env.WORDPRESS_URL, headers); - setGraphQLClient(client); // URI comes as a string from Astro params, ensure it starts with / @@ -29,12 +28,8 @@ const variables = isPreview } : { uri: identifier }; -console.log('VVV', variables); - const results = await uriToTemplate(variables); -console.log(results); - Astro.locals.templateData = results; Astro.locals.isPreview = isPreview || false; Astro.locals.client = client; @@ -42,15 +37,6 @@ Astro.locals.client = client; if (results.template) { return Astro.rewrite(results.template.path); } ---- -

Oops! You shouldn't be here, something went wrong!

-
-	
-	  {JSON.stringify(
-		results,
-		null,
-		2
-	  )}
-	
-  
+return Astro.rewrite('/404'); +--- diff --git a/examples/astro/kitchen-sink/src/pages/index.astro b/examples/astro/kitchen-sink/src/pages/index.astro deleted file mode 100644 index 9859cf006..000000000 --- a/examples/astro/kitchen-sink/src/pages/index.astro +++ /dev/null @@ -1,198 +0,0 @@ ---- -// Demo page showing template discovery -import { getCollection } from 'astro:content'; - -// Get all templates from our content collection -const templates = await getCollection('templates'); ---- - - - - - - - - @faustjs/astro Example - - -
-

@faustjs/astro Template Hierarchy Example

-

- This example demonstrates how the @faustjs/astro package discovers - WordPress templates in your Astro project using the WordPress template - hierarchy. -

- -

Discovered Templates

-

- The following templates were automatically discovered from the wp-templates directory: -

- -
- { - templates.map((template) => ( -
-

{template.data.name}

-

- Type: {template.data.type} -

-

- Priority: {template.data.priority} -

-

- Path: {template.data.path} -

- {template.data.description && ( -

- Description: {template.data.description} -

- )} -
- )) - } -
- -

How It Works

-
-
    -
  1. - Templates are placed in the src/pages/wp-templates/ directory -
  2. -
  3. - The createTemplateCollection() function automatically discovers - them -
  4. -
  5. Templates are organized by WordPress template hierarchy rules
  6. -
  7. Each template gets metadata like type, priority, and path
  8. -
  9. You can query templates using Astro's content collections API
  10. -
-
- -

Live Template Router Demo

-

- See the template hierarchy in action with our catch-all route that - resolves WordPress URLs to templates: -

- -
- - - - diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro index 89eb63d38..5603eebfe 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro @@ -1,86 +1,65 @@ --- -import Layout from "../../layouts/Layout.astro"; -import { authHeaders, client, gql } from "../../lib/client"; -/** - * This is a template for the WordPress template hierarchy. - * It will be used to render the WordPress templates. - * It should never be used directly. - * This check confirms that the template is being used in the correct context. - * If the template is being used directly, it will redirect to the 404 page. - */ +import Layout from '@/components/Layout.astro'; +import { GET_ARCHIVE } from '@/queries/getArchive'; +import { print } from 'graphql'; + if (Astro.url.pathname === Astro.originPathname) { - return Astro.rewrite("/404"); + return Astro.rewrite('/404'); } -const isPreview = Astro.locals.isPreview; +const uri = Astro.locals.templateData?.seedNode?.uri; -const { data, error } = await client.query( - gql` - query ArchiveTemplateNodeQuery($uri: String!) { - node: nodeByUri(uri: $uri) { - __typename - ... on TermNode { - name - description - } - ... on Tag { - contentNodes(where: { stati: [DRAFT, PUBLISH, FUTURE, PENDING] }) { - nodes { - ... on NodeWithTitle { - title - } - uri - } - } - } - ... on Category { - contentNodes(where: { stati: [DRAFT, PUBLISH, FUTURE, PENDING] }) { - nodes { - ... on NodeWithTitle { - title - } - uri - } - } - } - } - terms { - nodes { - uri - } - } - } - `, - { - uri: Astro.originPathname, - }, - { - fetchOptions: { - headers: { - ...authHeaders(isPreview), - }, - }, - } -); +const { data, error } = await Astro.locals.client.request(print(GET_ARCHIVE), { + uri, +}); if (error) { - console.error("Error fetching data:", error); - return Astro.rewrite("/500"); + console.error('Error fetching data:', error); + return Astro.rewrite('/500'); +} + +if (!data?.nodeByUri) { + console.error('HTTP/404 - Not Found in WordPress:', uri); + return Astro.rewrite('/404'); } + +const categoryData = data?.nodeByUri; +const { posts, name } = categoryData || {}; --- - -
-

{data.node.name}

-

-

    - { - data.node.contentNodes.nodes.map((content) => ( -
  1. - -
  2. - )) - } -
-
+ +
+

{name}

+ + { + posts?.edges?.map((item: any) => { + const post = item.node; + + return ( +
+

+ + {post.title} + +

+ + {post.featuredImage && ( + {post.featuredImage.node.altText + )} + +
+ By {post.author.node.name} on{' '} + {new Date(post.date).toLocaleDateString()} +
+ +
+
+ ); + }) + } +
diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro index 816aada23..a64c950c4 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro @@ -1,88 +1,31 @@ --- -import Layout from "../../layouts/Layout.astro"; -import { authHeaders, client, gql } from "../../lib/client"; +import Layout from '@/components/Layout.astro'; +import BlogPostItem from '@/components/BlogPostItem.astro'; +import { GET_POSTS } from '@/queries/getPosts'; +import { print } from 'graphql'; -/** - * This is a template for the WordPress template hierarchy. - * It will be used to render the WordPress templates. - * It should never be used directly. - * This check confirms that the template is being used in the correct context. - * If the template is being used directly, it will redirect to the 404 page. - */ -if (Astro.url.pathname === Astro.originPathname) { - return Astro.rewrite("/404"); -} - -const isPreview = Astro.locals.isPreview; +const databaseId = Astro.locals.templateData?.seedNode?.databaseId; -const { data, error } = await client.query( - gql` - query homeTemplatePostQuery { - posts(first: 6, where: { stati: [DRAFT, PUBLISH, FUTURE, PENDING] }) { - nodes { - id - title - uri - excerpt - } - } - } - `, - {}, - { - fetchOptions: { - headers: { - ...authHeaders(isPreview), - }, - }, - } -); +const { data, error } = await Astro.locals.client.request(print(GET_POSTS)); if (error) { - console.error("Error fetching data:", error); - return Astro.rewrite("/500"); + console.error('Error fetching data:', error); + return Astro.rewrite('/500'); } ---- - -
-

My WP + Astro Blog!

+if (!data.posts) { + console.error('HTTP/404 - Not Found in WordPress:', databaseId); + return Astro.rewrite('/404'); +} -

I like sharing my life!

+const posts = data?.posts; +--- -
-

Recent Posts

-
- { - data.posts.nodes.map((post) => { - return ( -
-

{post.title}

-
- - Read more... - -
- ); - }) - } -
-
-
+ + { + posts?.edges?.map((item: any) => { + const post = item.node; + return ; + }) + } - - diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro index 2c0cca05d..9bd4d8452 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/index.astro @@ -1,80 +1,53 @@ --- +import Layout from '@/components/Layout.astro'; + /** - * This is a template for the WordPress template hierarchy. - * It will be used to render the WordPress templates. - * It should never be used directly. - * This check confirms that the template is being used in the correct context. - * If the template is being used directly, it will redirect to the 404 page. + * This is the index template for the WordPress template hierarchy. + * It serves as the fallback template for any content that doesn't have + * a more specific template (like single, page, archive, etc.). + * This template should never be accessed directly. */ if (Astro.url.pathname === Astro.originPathname) { - return Astro.rewrite("/404"); + return Astro.rewrite('/404'); } -import Layout from "../../layouts/Layout.astro"; -import { authHeaders, client, gql } from "../../lib/client"; - -const databaseId = Astro.locals.templateData?.databaseId; -const isPreview = Astro.locals.isPreview; - -const query = gql` - query indexTemplateNodeQuery($id: ID!, $isPreview: Boolean = false) { - node: contentNode(id: $id, idType: DATABASE_ID, asPreview: $isPreview) { - __typename - uri - id - ... on NodeWithTitle { - title - } - ... on NodeWithContentEditor { - content - } - } - } -`; - -const { data, error } = await client.query( - query, - { - id: databaseId, - isPreview, - }, - { - fetchOptions: { - headers: { - ...authHeaders(isPreview), - }, - }, - } -); - -if (error) { - console.error("Error fetching data:", error); - return Astro.rewrite("/500"); -} +const templateData = Astro.locals.templateData; +const seedNode = templateData?.seedNode; +const contentType = seedNode?.__typename || 'content'; --- - -

- This is the index template for the WordPress template hierarchy. - It will be used to render the WordPress content if no more appropriate template - is provided (e.g. front-page, single, singular, archive, etc). It should never - be used directly. -

- - {data.node.title &&

} - {data.node.content &&
} - { - !data.node.content && !data.node.title && ( -
-        {JSON.stringify(data ?? {}, null, 2)}
-      
- ) - } + +
+
+

+ Template Not Found +

+

+ No specific template was found for the {contentType} type. + This content is being displayed using the default fallback template. +

+
+ + + +
+

+ Debug Information +

+
+
{JSON.stringify(
+					templateData,
+					null,
+					2
+				)}
+
+
+
- - diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro new file mode 100644 index 000000000..e26837114 --- /dev/null +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro @@ -0,0 +1,51 @@ +--- +import Layout from '@/components/Layout.astro'; +import { GET_PAGE } from '@/queries/getPage'; +import { print } from 'graphql'; + +if (Astro.url.pathname === Astro.originPathname) { + return Astro.rewrite('/404'); +} + +const isPreview = Astro.locals.isPreview; +const databaseId = Astro.locals.templateData?.seedNode?.databaseId; + +const { data, error } = await Astro.locals.client.request(print(GET_PAGE), { + databaseId, + asPreview: isPreview, +}); + +if (error) { + console.error('Error fetching data:', error); + return Astro.rewrite('/500'); +} + +if (!data.page) { + console.error('HTTP/404 - Not Found in WordPress:', databaseId); + return Astro.rewrite('/404'); +} + +const { title, content, featuredImage } = data?.page || {}; +--- + + +
+
+

+ {title} +

+
+ + { + featuredImage && ( + + ) + } + +
+
+
diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro index e9b772414..c00431300 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/single.astro @@ -1,6 +1,6 @@ --- -import Layout from '../../layouts/Layout.astro'; -import { GET_POST } from '../../queries/getPost.js'; +import Layout from '@/components/Layout.astro'; +import { GET_POST } from '@/queries/getPost.js'; import { print } from 'graphql'; /** @@ -35,7 +35,7 @@ if (!data.post) { const { title, content, featuredImage } = data?.post || {}; --- - +

diff --git a/examples/astro/kitchen-sink/src/queries/getLayout.js b/examples/astro/kitchen-sink/src/queries/getLayout.js index 7f1b7f012..f278ee1af 100644 --- a/examples/astro/kitchen-sink/src/queries/getLayout.js +++ b/examples/astro/kitchen-sink/src/queries/getLayout.js @@ -1,4 +1,4 @@ -const { default: gql } = require('graphql-tag'); +import { gql } from 'graphql-tag'; export const GET_LAYOUT = gql` query GetLayout { diff --git a/examples/astro/kitchen-sink/src/styles/globals.css b/examples/astro/kitchen-sink/src/styles/globals.css new file mode 100644 index 000000000..d4b507858 --- /dev/null +++ b/examples/astro/kitchen-sink/src/styles/globals.css @@ -0,0 +1 @@ +@import 'tailwindcss'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc0f0e950..7e18df114 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,6 +77,9 @@ importers: '@faustjs/template-hierarchy': specifier: workspace:* version: link:../../../packages/template-hierarchy + '@tailwindcss/vite': + specifier: ^4.1.12 + version: 4.1.12(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1)) astro: specifier: ^5.1.1 version: 5.12.8(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.8.3) @@ -86,6 +89,9 @@ importers: graphql-tag: specifier: ^2.12.6 version: 2.12.6(graphql@16.11.0) + tailwindcss: + specifier: ^4.1.11 + version: 4.1.11 devDependencies: typescript: specifier: ^5.6.3 @@ -1298,60 +1304,117 @@ packages: '@tailwindcss/node@4.1.11': resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} + '@tailwindcss/node@4.1.12': + resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==} + '@tailwindcss/oxide-android-arm64@4.1.11': resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} engines: {node: '>= 10'} cpu: [arm64] os: [android] + '@tailwindcss/oxide-android-arm64@4.1.12': + resolution: {integrity: sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + '@tailwindcss/oxide-darwin-arm64@4.1.11': resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] + '@tailwindcss/oxide-darwin-arm64@4.1.12': + resolution: {integrity: sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@tailwindcss/oxide-darwin-x64@4.1.11': resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] + '@tailwindcss/oxide-darwin-x64@4.1.12': + resolution: {integrity: sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@tailwindcss/oxide-freebsd-x64@4.1.11': resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] + '@tailwindcss/oxide-freebsd-x64@4.1.12': + resolution: {integrity: sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} engines: {node: '>= 10'} cpu: [arm] os: [linux] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + resolution: {integrity: sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + resolution: {integrity: sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@tailwindcss/oxide-linux-x64-musl@4.1.11': resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + '@tailwindcss/oxide-linux-x64-musl@4.1.12': + resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@tailwindcss/oxide-wasm32-wasi@4.1.11': resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} engines: {node: '>=14.0.0'} @@ -1364,25 +1427,58 @@ packages: - '@emnapi/wasi-threads' - tslib + '@tailwindcss/oxide-wasm32-wasi@4.1.12': + resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + resolution: {integrity: sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + resolution: {integrity: sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@tailwindcss/oxide@4.1.11': resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} engines: {node: '>= 10'} + '@tailwindcss/oxide@4.1.12': + resolution: {integrity: sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==} + engines: {node: '>= 10'} + '@tailwindcss/postcss@4.1.11': resolution: {integrity: sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==} + '@tailwindcss/vite@4.1.12': + resolution: {integrity: sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} @@ -3725,6 +3821,9 @@ packages: tailwindcss@4.1.11: resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} + tailwindcss@4.1.12: + resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} + tapable@2.2.2: resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} engines: {node: '>=6'} @@ -5054,42 +5153,88 @@ snapshots: source-map-js: 1.2.1 tailwindcss: 4.1.11 + '@tailwindcss/node@4.1.12': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + magic-string: 0.30.17 + source-map-js: 1.2.1 + tailwindcss: 4.1.12 + '@tailwindcss/oxide-android-arm64@4.1.11': optional: true + '@tailwindcss/oxide-android-arm64@4.1.12': + optional: true + '@tailwindcss/oxide-darwin-arm64@4.1.11': optional: true + '@tailwindcss/oxide-darwin-arm64@4.1.12': + optional: true + '@tailwindcss/oxide-darwin-x64@4.1.11': optional: true + '@tailwindcss/oxide-darwin-x64@4.1.12': + optional: true + '@tailwindcss/oxide-freebsd-x64@4.1.11': optional: true + '@tailwindcss/oxide-freebsd-x64@4.1.12': + optional: true + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': optional: true + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + optional: true + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': optional: true + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + optional: true + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': optional: true + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + optional: true + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': optional: true + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + optional: true + '@tailwindcss/oxide-linux-x64-musl@4.1.11': optional: true + '@tailwindcss/oxide-linux-x64-musl@4.1.12': + optional: true + '@tailwindcss/oxide-wasm32-wasi@4.1.11': optional: true + '@tailwindcss/oxide-wasm32-wasi@4.1.12': + optional: true + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': optional: true + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + optional: true + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': optional: true + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + optional: true + '@tailwindcss/oxide@4.1.11': dependencies: detect-libc: 2.0.4 @@ -5108,6 +5253,24 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 '@tailwindcss/oxide-win32-x64-msvc': 4.1.11 + '@tailwindcss/oxide@4.1.12': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-x64': 4.1.12 + '@tailwindcss/oxide-freebsd-x64': 4.1.12 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.12 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.12 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-x64-musl': 4.1.12 + '@tailwindcss/oxide-wasm32-wasi': 4.1.12 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.12 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.12 + '@tailwindcss/postcss@4.1.11': dependencies: '@alloc/quick-lru': 5.2.0 @@ -5116,6 +5279,13 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.11 + '@tailwindcss/vite@4.1.12(vite@6.3.5(jiti@2.5.1)(lightningcss@1.30.1))': + dependencies: + '@tailwindcss/node': 4.1.12 + '@tailwindcss/oxide': 4.1.12 + tailwindcss: 4.1.12 + vite: 6.3.5(jiti@2.5.1)(lightningcss@1.30.1) + '@tybys/wasm-util@0.10.0': dependencies: tslib: 2.8.1 @@ -6046,7 +6216,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.5.1)) @@ -6105,7 +6275,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -6131,14 +6301,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.33.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color @@ -6182,7 +6352,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.5.1)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -8299,6 +8469,8 @@ snapshots: tailwindcss@4.1.11: {} + tailwindcss@4.1.12: {} + tapable@2.2.2: {} tar@7.4.3: From 0dec604415bd76faeb5d7293e777c24c8186e968 Mon Sep 17 00:00:00 2001 From: ahuseyn Date: Thu, 28 Aug 2025 17:35:46 +0200 Subject: [PATCH 13/13] remove logs, add comments, minor fixes --- .../src/pages/[...identifier].astro | 42 ++++++++++--------- .../src/pages/wp-templates/archive.astro | 7 ++++ .../src/pages/wp-templates/home.astro | 11 +++++ .../src/pages/wp-templates/page.astro | 7 ++++ packages/graphql/client.js | 2 - packages/nextjs/pages/templateHierarchy.js | 2 - .../template-hierarchy/seedQueryExecutor.js | 2 - 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/examples/astro/kitchen-sink/src/pages/[...identifier].astro b/examples/astro/kitchen-sink/src/pages/[...identifier].astro index 8e8fd1a02..81882980d 100644 --- a/examples/astro/kitchen-sink/src/pages/[...identifier].astro +++ b/examples/astro/kitchen-sink/src/pages/[...identifier].astro @@ -4,39 +4,41 @@ import { createDefaultClient, setGraphQLClient, } from '@faustjs/astro'; -import { getAuthString } from '../utils/getAuthString.js'; +import { getAuthString } from '@/utils/getAuthString.js'; -const isPreview = Astro.url.searchParams.get('preview') === 'true'; +// Determine if we are in preview mode based on the URL parameter and the secret +const isPreview = + Astro.url.searchParams.get('preview') === 'true' && + import.meta.env.WP_PREVIEW_SECRET === Astro.url.searchParams.get('secret'); -const headers = isPreview - ? { - Authorization: getAuthString(), - } - : null; +const headers = isPreview ? { Authorization: getAuthString() } : undefined; // Set up GraphQL client using environment variable const client = createDefaultClient(import.meta.env.WORDPRESS_URL, headers); setGraphQLClient(client); -// URI comes as a string from Astro params, ensure it starts with / const { identifier = '/' } = Astro.params; -const variables = isPreview - ? { - id: identifier, - asPreview: true, - } - : { uri: identifier }; - -const results = await uriToTemplate(variables); - -Astro.locals.templateData = results; +// Fetch template data based on the URI and preview mode +const templateData = await uriToTemplate( + isPreview + ? { + id: identifier, + asPreview: true, + } + : { uri: identifier }, +); + +// Make data available to other templates and components +Astro.locals.templateData = templateData; Astro.locals.isPreview = isPreview || false; Astro.locals.client = client; -if (results.template) { - return Astro.rewrite(results.template.path); +// If a template was found, rewrite to that template's path +if (templateData.template) { + return Astro.rewrite(templateData.template.path); } +// If no template was found, redirect to 404 return Astro.rewrite('/404'); --- diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro index 5603eebfe..26ee4def3 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/archive.astro @@ -3,6 +3,13 @@ import Layout from '@/components/Layout.astro'; import { GET_ARCHIVE } from '@/queries/getArchive'; import { print } from 'graphql'; +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ if (Astro.url.pathname === Astro.originPathname) { return Astro.rewrite('/404'); } diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro index a64c950c4..ea5cdb354 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/home.astro @@ -4,6 +4,17 @@ import BlogPostItem from '@/components/BlogPostItem.astro'; import { GET_POSTS } from '@/queries/getPosts'; import { print } from 'graphql'; +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ +if (Astro.url.pathname === Astro.originPathname) { + return Astro.rewrite('/404'); +} + const databaseId = Astro.locals.templateData?.seedNode?.databaseId; const { data, error } = await Astro.locals.client.request(print(GET_POSTS)); diff --git a/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro b/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro index e26837114..1f59f8f05 100644 --- a/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro +++ b/examples/astro/kitchen-sink/src/pages/wp-templates/page.astro @@ -3,6 +3,13 @@ import Layout from '@/components/Layout.astro'; import { GET_PAGE } from '@/queries/getPage'; import { print } from 'graphql'; +/** + * This is a template for the WordPress template hierarchy. + * It will be used to render the WordPress templates. + * It should never be used directly. + * This check confirms that the template is being used in the correct context. + * If the template is being used directly, it will redirect to the 404 page. + */ if (Astro.url.pathname === Astro.originPathname) { return Astro.rewrite('/404'); } diff --git a/packages/graphql/client.js b/packages/graphql/client.js index e438e3b5f..87552e174 100644 --- a/packages/graphql/client.js +++ b/packages/graphql/client.js @@ -59,8 +59,6 @@ export function createDefaultGraphQLClient(wordpressUrl, headers = {}) { body: JSON.stringify({ query, variables }), }); - console.log('RRR', response); - if (!response.ok) { const message = await response.json(); diff --git a/packages/nextjs/pages/templateHierarchy.js b/packages/nextjs/pages/templateHierarchy.js index 43e365e3f..e9afbc41b 100644 --- a/packages/nextjs/pages/templateHierarchy.js +++ b/packages/nextjs/pages/templateHierarchy.js @@ -70,8 +70,6 @@ export async function uriToTemplate({ const possibleTemplates = getPossibleTemplates(seedNode); - console.log(possibleTemplates); - returnData.possibleTemplates = possibleTemplates; if (!possibleTemplates || possibleTemplates.length === 0) { diff --git a/packages/template-hierarchy/seedQueryExecutor.js b/packages/template-hierarchy/seedQueryExecutor.js index 15a4a4dd5..9eec53d08 100644 --- a/packages/template-hierarchy/seedQueryExecutor.js +++ b/packages/template-hierarchy/seedQueryExecutor.js @@ -22,8 +22,6 @@ export async function getSeedQuery({ uri, id, asPreview, graphqlClient }) { asPreview, }); - console.log('Seed query result:', uri, id, asPreview, result); - return { data: result.data || result, error: result.error || null,