From 6515bda7308ea6adee46768215fc34d597b36cbe Mon Sep 17 00:00:00 2001 From: mStar Date: Thu, 10 Jul 2025 20:23:59 +0200 Subject: [PATCH 1/2] Some progress on porting frontend --- frontend-vue/bun.lockb | Bin 195481 -> 229017 bytes frontend-vue/package.json | 5 + frontend-vue/src/App.vue | 15 +- frontend-vue/src/assets/base.css | 38 +- frontend-vue/src/assets/base.css.map | 1 + frontend-vue/src/assets/main.css | 12 +- frontend-vue/src/components/WelcomeItem.vue | 17 +- frontend-vue/src/components/global/Header.vue | 40 ++ frontend-vue/src/components/user/Header.vue | 0 .../src/components/user/PreviewHeader.vue | 30 ++ .../src/components/user/ProfilePicture.vue | 57 ++ .../src/components/util/FormattedText.vue | 5 +- frontend-vue/src/router/index.ts | 5 + frontend-vue/src/stores/media.ts | 10 + frontend-vue/src/stores/userdata.ts | 10 + frontend-vue/src/utils/identiheart.ts | 492 ++++++++++++++++++ frontend-vue/src/views/AboutView.vue | 1 + frontend-vue/src/views/NoteTestView.vue | 29 ++ 18 files changed, 728 insertions(+), 39 deletions(-) create mode 100644 frontend-vue/src/assets/base.css.map create mode 100644 frontend-vue/src/components/global/Header.vue delete mode 100644 frontend-vue/src/components/user/Header.vue create mode 100644 frontend-vue/src/components/user/PreviewHeader.vue create mode 100644 frontend-vue/src/components/user/ProfilePicture.vue create mode 100644 frontend-vue/src/stores/media.ts create mode 100644 frontend-vue/src/stores/userdata.ts create mode 100644 frontend-vue/src/utils/identiheart.ts create mode 100644 frontend-vue/src/views/NoteTestView.vue diff --git a/frontend-vue/bun.lockb b/frontend-vue/bun.lockb index 7999c8e98bf7d10514eb0376f3cff721adb21947..d136a17ec0f228b0f3230a84f144785ec34e704c 100755 GIT binary patch delta 57716 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 Ol&!0=FXAnhbKL_q;T z#eft+K>-V32L(Y?iioIN1vkR~_swEBZr$g<_qq4n=ef^b`sN+qJNh@u9CKxox%M~z zwZ9Zz*05gF50-6he%>`U$#3y(BWOUEHj8VFdEtd4UEA&Wq3tu__tQOp*ERWk>smgj zQr3ZMF4MAp6wx$a4Fo@UVn)0vN`lhZ9m!S#K7lR#C3Z>pS?t2_pnRI<4|laWJ~=%x zJuyDbYuh{XYnqhr@7A0ZP0J`?H6S@Ud3<7=riEfl#?}SN z0PiDxaab#4HROBrV%X$O&rFHe#yI6ACMQPI1;<|RvC@~NchaHMgt*vR(nWs+;(VXO z(u2gb29ridr)xU4^y~+Zu~4s+g+m&or^RYF$wG|p5{(iE94C*ISFNa3{tMWmzltrz zj<)=$ZAF)Mu7>&Fx4>o}Ea^h&l*DJlWc9s6`QqqG{Gh%p-^9f9__TCQOQiHNMC6C1 zeFNZ9@E(3hL1~Gj5|b0gYaP(VQ7O^sW*Z`~rQnZgtu&w(g-H5h=wc_0&%k|}R?kl7 zjAY-k5}&2{ZqpK}Fg-CjGc6@k3$hblwe>0G?2#B9ohXi#iYG=VX>sxKDGlN$Bo!=g z<-cpEyJzP+Z}rf31eOLR#3iOm{5l=Onl?JjmweFzK>^?;$f$ z5?qDFJ_*a@j8BWnNKA^;j?}g$!E>;Tje=#8%(eBgurz$2t+#=3v#%j6=>uRHA7<%~!%|N;EUSG*xYdsMwAkpR=(zZ~*fL2cz&J9?7f(PEHY9^g zn#|~=BS&lPt~-AR3IbtB@K`fYC{8Lc^z+VHRwBR=GX75pfBlVwcL-iIuO^w za_m>w<b0VwS^5WRRf@5wWneyge+-YgBx4T4r*rHYRO+GLoi|L58{)EORRm zW+C|Q;0dw!w5Cva9$XKu(pJ+RgMV$KX$+39GrG*tOW4wpQP`D-5jab(D)6(gBwPSj zg?;UuB8cRLZ*8$=c_} zr^F{~d}LcpOVYHvY;oK%SRCBDtL2Xlu~Od=97->w0o8|F{VxPd$G%~*NC)16 ztH960Qr>DfK=zbO0u>R4!;+yLEHkzNEK|Q4ERJ(3N=c1R=hB{fiAG3;ajc87@HMz1 z{4Okez#v%SyTg*dt<5Qkap|e?@!F)(iLs-NxkXB4)gNUwtt>2E+>&7VwCiYVNH@b$ zQhws4%Rdk=dbY1S#pSnXdg>m90-zVu18IG*{HoUUp8fi!79EPYCfpJ=Yf-L}5Y=54Sv z&Ai$&L4KQH_1))h>CXA$yNOnLok=e~sR1+XvgF(|DrtO-R&lbGAbL_!Dlq5njbed~%BrFwt1WV6lyrS`xQ*a9kEQ?+TmIhavZ%xl) z*s>z4;~{CN<3ZUR)Et(b`6O$T`GYdbF*I?1BEw&n35*7~>T#V}_<2X+3DbZ>VR2!^GMll*Q>U<{BS&B<@4ri*u)^x_kt{pI!$np>Jq@cuAGJ!) zJ75d{Xvfn|>4?^KrPTn)-2A+&tmS(Gu0r~qu(&=@Sx3&puv`Y#!*W^BVL1+DO3T@8(Znyp+@jlnfrx&Q9cv~I?*nvw27x~6q7 zLr?x5`k7ECQ;W~1Y0V|%+Gw1w)k?pT&j_sTbyYV8*KXxXG1k^@<=&rPl5D6Q>1t#I z)M@2j<<_)8M#Vaj?r#a1MY~!V=j*g`Wf=i=Te(gdgX^}^9~3Zh>Uv#6jPrF{xpx)R zw035FCAhn_S~HMPTeIf1#`$`!TxX1c`mNlh@nncGtZ}41&|?IKdi7l+OGOBhD_uRs2 zY-S)%4=Q5hH1+EJiWnE5)ldhoe!qwj*wO2bV1aZpE_R62Kk+wm5JH)a?Tif_BlSr| zjlfP`&q;*lR>`%)b-kF8gV>O{*TEE}@^ma|pJrSM4cA{TW<+)NdhQ`gK94lo-Iht* z!Khd}(zBXSJEuJN1+k<$Pn{B))&iYQwhGsiOBffrc-!yF_|wl+rXW(Yo2e z7%XNUR&tB{O0=s)X zjhM|=d+CxpQ7kihYZ>E0cdz?H1T($6L|Jo48%KIZ5{jfmmvN;LC1Qn{HJy_XdVaH} zf-E01r{{4(;plFoYLjr!0xTK8{AR09V#$!Xjm@3HJtbMHQi5&{ZYQh=Dum#!oZenf7NYdbtVll)U$ z5-;VKvGn9(J!X|&FWhq*OWIgaTC8`gVC3}m>P7|QLSL`DE?1@@#>Kvo?m2`8o1u$@ z`kSGU%1-QJLVZo`GNEB+sAUyyP|VQNgksH*hwU}m42>aV#lBC-%F(!*rj0UV6`^=D zbf3@&Gc=^S6MBV^m7`n@r&TG0taN97*Xq>Nw1JXWUs%%!9PD+Utu6Di;^0Vk={n}j zB@{)dlTmSKi~Izv$gc_YGcHE8$Y0ltBh@TI-OQZt5@OCv8TDiuOK3PDvJP$Gs%JzE zZIvI>N*q?-DPRVn9%kaV30bk_83e1S;e^=KsF47>4XrU1DLkZslYRyvEB$dotf0Xy z*f=i?X~oaLq4HBIZ)kTzZ`jDVFv6=3Yh(nD^tx3erkhc*Zlr#uk&!df>nX^f%WTYN zR2>=aZi&Ut7#ivJu+w*xkY@xTYZh+q65$FqE<}4hHJC1IY$g4bQIIn6gKpF^m%RPH`csGAw8$+~A8>qL4I2_ehs>K^Xiiq+O^Xqgs9;ApRB zDtlTNt7#$O`iT}s4q`w{Ymu3Iox3YmYhze!q-PN!%Z;+Fox|!zR&&eKD|(F!iC%q( z*9aWr)wg(!s4-sm2W$ib%x2VU#fl)Y=~(x2tUhMruM$cyoBTypdgTyTrfNQu?EwKJl|dEL9)Imv_CYg(LH!A3$>qKEB` zsAR9_8T!(PHgR2u4)@%{lFpesoIbpx5jfuKS<_L|@V>9GxshMTqLub$R;QCSss+p| z!pKfWV2anX5mEM_eCE!0%}!!jl{;JG$PS+p;p%JzPVjn`p)omqen#}#h(dM()9;?z zjEh`E%xk8523B*UV)sb*enPDC?vWm?tJCBwwZc8ISTY_=Ax8RnEUz)FRix*>or-Od zYj0bU$Oh^$t~3w#w6<7MqcvBSNt{{2yM$y8dCbkf5J_Yl#Yo{&nIUKXOUi;hotY?Cur^rCD%v-bkmM<3y6klGmXG z$+9p#?%9LI|Fm7M$XahBXOh>`y|*((X^y_Bw|VXS0?}H3^wQmgF%L1X^$8L(OOUp& z!IJWSc!N4;4=^2Kum}#)TPP_XdP^ z#>E+t`jw$ZRF>BrIb1GF!?GgXD+!G-Lq8IVHA4f~923pZtAwJBVZIjmN6M8{GE608 zCA&n(%Gxqou6GifLujCcJl_+trr?#xaJ^BC5jD%}nH}Sd*k<-&J=U6I%#g@%&lD`# zTdi@*A4gw*w-T`Eyd8HGOXenn!Ccbfe;UPH-9*TSV&>EPk2a#_c|E%jrAfN6 zIV9ZkE!OW#*3&G}vaE$V7fW_#YdN10%h)i9`8LK{AO(#pOxh7xok(S#c|6ZxNtKps zzQvNd*wNVA!^avIvc2x~v6|M>xR@R3-b=`99 zs?LkZkHMvvv*mksB0tk%#l~4n+j3ZEEScb((QxK!EXxgY@$)7dIg7mR%w)Q1T#StL zoFK%k!%LjQJypkZ{4%YoZNoi_u-amAc%-ZEV0FWy5{{VxDb{An`edi+jwMwxnp`61 zrWiSky`EPPWf-lk>6V=Y&(n??6O5=OUOjVyk+a0>*)f3|8&dk2U5-tC)VhGhm0xZY zvN$KC8yA*x*O6|yox&!Cdx~dRJ~D4GJgu>02g7O_?w%%=aj{mUzCXhVT<-P!fM8EG zI#p+)aT$9q_Iu}rn5ldQ4LZ*0bG8CW#ao`%=3!m!Nq zy{GnME1$W=yJNA~)R(s?L_iJ|=JCh#p~zUc3g4E>va|D*eS(9pmZCOtJ6f43k zMRw3qQ>=W}^{XG2J*!wLE3jmu7Ba6BUt&pTm?Cth%2X%c=Dy*c0a%T#ICkshSYBg8 zvljUYbTBT~i}aM4W+k`ol)8##Tx`zqgpd^KHmAg!SWU5*p==@U>CUB1mU~~U=4MJc z`|X)-M6L09t|H2EVV5DpV>6tqmCUaMtX{;KK5)N`6=G}%iS+zTs2zGibK*45awfib zBNfYQ=8+N(W7%_=9(#ONQyF$HQ|*1mg&ePE3*t~Rm=`q911zc1np8bzTEk`D_vo`` z8W+|v3lZCxNj5K{%vs#dV3~W7K75vuvz}Y@S;mF+UeD*mSt(^FtTNkbwPxUNJ#My< zv%%}xfGGYl=eg%SEO7>#7a4-*Sl%+bIFSb2H+&2?s|IAbMN zTc>fJ&#}b+)eJ^N zQJcMvDq_n(Z_dpXf8QjleBl&pyNfWG`T@tAGVo_gPo9!`-8>nwZC_b%dl! zYocGnk~UgLqpAz7o|=a-&tNRsBDt_o9-{z!q6>Ea}&lT1l*H%Y7_aDdu+RZo3T2xX7+PgOH3MJI9!C z_hl?j?;JG4mRnQVTD<94Qe7eQ61W>n%3>pCncuW6>xfosg;kz;1@fe0wId~i$ae_) zv1EC8%x@bC7*-qVCG~OqY!*=nBNBsU%}(#P(#UzvtM^}NTzHOC z!^+=RRhMwjt60NH$v05V!}aJ@M$S&J`^Qz%rww~sJTRTD@6Y3`+PyMx4W37cc7R&ZNtLe;I<3b~^UO2}HZ0yzB=NM6qX;_Zq zBl@GilVe;!3|wdBGl#_8537lBk(VVGiaZI@90ahzBm0V0)ZqUr53O-#Q?n%Lts{$!og}a}|!Vh%oJ|T{Sgt|Rx zch$3kkaUThY=v)Q$&@vZ!X9m-b;Po+l}oYu5yz#XX1HE`lM(o$SC89dM7`+sLsuHQ$$V#Ov0X9tZ8CiVf0N~jKFZSsKm| zoADe6w1S|AZTE!bBP{uQQNJ1JEh?XXg{30K()7Z<+4g*9u|#{a9Qxa7<~R0*czyRry^NZ-w*6-;1scRll9e{EveQ4xQm(Rf;VcQSu?68G*iYH^ zpRq)3v*U%Oz-Mgx|Ar;~4m&-ZWw!WPTM(9>?t(?yZR?M+NYC5)qg)F8HT2@}dv?6A z1mEX}lq(P7iv6+tFd6?#_!E9e%PzoTe=0xzH`w&QT~T59YrEqA4VFosb(;#M=XdOi z{}q-j-`n|w%U~Cf!fckPg4n`^Z1&jkHfL#%3X;%|1d^tRolsbUMQvMH(iOA0xUK&g zOH@faT`4==qpZswScV9RE5{GFaq(O^b4)5?$)c)i$5xjle1xU?8n*o?i(b>#g(XXNLW5_mYFdIK?;nuBmNmnx;WBF(gZvGpRuGHWyk*+OZ;e^ zH6dxn*a?LtVyw+cHjlI8g(W^27AeKng+-rW+keIqpK8Yo%OcIlvV{y-5=^vhVF^yQ z^-NnAmf%!dpJwaAl7G6*Gi+U0hIW>1KgyCmYqlNnXDm^3?f6Gor1|`i0@(_r8 zgeADi<}J1kXPKAcXAmUAc01xxmbtsz)`caw$L1GoU08xI*|xCcdj*z`9fqa+BX+#7 z=*MI#%IBCJAuJKcVaag9)`dksY1@yojP%>KE-d-pv29@qp0VvmSr+L>G8N@8@+mA= z#%r)d+=gYlz6VPMzrj-Q16V%7W{_5i?t-P90%gTYB*S`mM6e zaH;5DxkV(*KPQB(FFn}MxihLjriML zT@{VJw+Ff^8J_P3x+)vd{H$Ue;Ad5%#GQezYDOYIs~gAoS;GkUexR$SF@c}8j8puq zt?GJQ16_60Org5!yih$A><86X3m_x=hQIpO&(+n{Ks76j9dXlNZ77W0NZk`3J)j$PJW+c1v|Y?ETmkOJKKBi6yW{-|<)Ph}}j7l*BIoy}z1X68mv= zO6-%^4N76RSDB@-C;#BDE{fez)h&%(=SP3FxHNWWbzbaGuv?bF?y44)!Os30{TI8t zYE~9I;wSoF7Q3gqA@+6b?&Yw1tF`5@*ZfTX#qO&*m&fk(3;i#T-Cx}k`!4pd0PKNk zM*#NryYxR0d$1ZDh})yoUZEk%Qvn*PqJ@U3146@9i6Cf%N)#HYjtNDpfQnFznjjRb zP6@@Ss+FL4l_`{<&IyfDbt^-o)l8v8bzW$U3a$c;RSSfY)D@v|s##SiSuGbDuWmrA zuDj@IHCj4Bt*wTfs=gOWQ=O|r>1wl3hPo#-QT46?O;S6ACM#D>C{qme-G+iAKnxRV6hO$(mkWU>GnyCWnK(o{Yq1oz`&>U5@E;LtV3e8jJgyyTd^`LAu zQ)q!YFSJkv*M}CV1(3@2qZ{AWryGk^v&Rr33L|WI3}LCdA;NVLx;H>ruGTg{SW^Vy zHxUfgxgkO)e}r8P5mu>tBHR^WSR(|bb~HlRUKGKW=#c#qLeR*GCdS!tENtia#EBAO;EOJ zYDyE7$)!*(it>!6>NQ2FQyOJ)Q={BT)8gDklPEO*xd`M0rtDU7DeEDvz?O8OlCQ{VK{`QHC`~$<@@e z%~7@op!i3k9MDu$B+8&bl*6JN)RbQfltL9y#tf^N}^dp)o*%E#g?+72&)N8`W z@QoLKO;f4Duj3ivBRG;?n$9O^b z6HVzI;Pd!E_=2Wh5dIVobc8?CRE+RN`Y(Km{&#{ur~ks2>A&z5`rjG;g8mC%rT@ZT z(*G{-SM*=_Yx*yIjsACquhW0w8}wiJCjIXQe?$Lam0h0^__iA(@GTzbjuP=0%7*SJ z-{AvMu8Y#W2g>(&p$E#E1}MLY@*{reNqK+655hm;2Uy*0NQz;-Nbw7v=!LSq5sH6r zlzaH1H_D*KD2GM)JKpF+?)!K{_&2;E`~YwCg&*P#*rlmseOcr#70?gT)dZn@>XcA^ zRkc6lR+*5R+=Q|(_GjT0RCNa+)M<*acmRS&okwu_so;T7VYNW0h`J)=ubK^limK&8 z#ncU<;;PMHsDxT8R8oB}R7!P@qS#K&$g?YoV#}y|BHR^W*bszrYR3?S?adMVhav>1 z!9x)SMIsy)p@Q-ZLnzb&Vcal;it2y}`$ecY9HFvG9F8!$CBi!*R8;{Z5XyTIrjJ0V zu1<+?QiKL05o)T;kqDDpAzT!pwyGPAP^UG*;%J1r>bwY_h|n?yp}txWgOJ?@;ad?J zsAjPU5p5AR#3D3OH$=EDLiad?V6`?5Va?+Rzljj4I>#e)YKO2Z9-*naC&FD3h9w|` zs~rgl+uI}fk3wjs29H7*)B)kJ2$9M&8lg}}gmI%0TB-vg>=&V8A_B*OM1;|u5Z)1? zjS3ipP`)$5^f3sJt5YJJ6rsUbg!U?PEW+e22p2`@sAeW1)ai=wRT4sH6+8~%6A@O8 zL+Glmh>+b4p?xw!ceOkjA)-6NPa^bGZN?*97h&6Ygx>0V5!UoT=%0enS8YyVn)Flm zg!-%A6NtXsljwaDnDGN$M$R`Zie4^%(5@v7=Xik;k_V&_hz*iq`72z3S^G@XQy zsAf(=_(X)SL>Q}rCzCTtEf5-~t_UToW|`1O2+7 zP@5rjH;Q82(OBo%`w)bEB4jGpbc8`e5#pyKOjUbDC^QVA%nXF-DtZROei2TH zkflmwA&ef5kdcKjQymkb{0M}aK7`q7f)C-O2p@_tS5=*fFnJ`x+?fdT)j1LBL?bkv zg|I-)oQ3d-2w#b?NCnSE$c{l+H5*~Ex*|eEEJFJ^2us!SISAK9_(_E2s?A)4HE{^r z<{}vCdl5RtBlMq#uu5&7hj3Q}_k0AUde2ALo`A4Vgtf|*jWB2wLVPyDI<;4XLZcDN zEI`!CeE3Rz2Rn8{T-Ka6FVXkyZbj?^)vW$4JBMhP+v(2=kVuRlr>XOR;@*O zAAgF{X(~$l9F!07XAa6;QGOETWBj=eW&1RgZR=3Z<4;irO-Jd!9_3T~xgMp^3>5bU zl#BRt1Im6;_KEU2{(KT;bQVhdlPFj4rzqupC}lRHT*aRoQBI0-LX@xY=O&cNGf^@& zp=Zscg#g|ujIN6mnk0F=_=%z$M55L){B27a3!*l+OyTw$&Bl?%XP>dSAyq= zq>%ce=>tmUHs9?E)cu@4w|65z4d3JHpo|;J)=&J!2|Gn2$ z<&P=S674F#ROeX*pES$)%U^@~{+GT@mdeYd*njjYEyngN8F;8Y#`NwWNmAAMyH?XE zxu{*HQ~go2BI2(`)+h}<<|?E&7%Lq)Vl{M3VtS&qC~?B04fS{a4AeWR_$SZdPnaHY z{_@c?({sIVxPEZCv*y^7p`caGBd&D@TunQLYlrbLwmAu=s{E&2RotcdMRVcb-Q#cm zAt)Mi7`eFAnq@W8`Rh18udwxwdhXFfuJUHApYxYp8jMx+>t^oGGp>fi{jSTGvpllO zd~S1CFQv|S^=4Vl!-q_0^W)eu4*s?#4<<@p`7&1?V3f}XwkG+?nTn=;Xlrh4dFVnu z&clrI0LED5h2KjaIB?6L%nWB9!8lTH{LV5T&*;F*`iml0`o6KSJ z^M$RklI2hHn4hb*RuZcwVflP%YvR2@w)T~1^6TQ#prY+Ad7@I{q?1oGT%ERY9#hk&7A7#IOIfOTL!r~zb)C=QB(fL5ePy?m-BmWz&%tFN8>VcKvLUhoW@)nHMbI)%81hf%wAZnZgEzpN;3PN&PJ_3= z+u$AWE;s|uf^%RE$N}rXdawaJ2{wXFU^CbPwt^?XVz5NE+Drn|zzmQDd|)PcKw};P zjc|S-|6b)T=m9!{PM|C31~z~v!A7tNYzEJP=fO6x1FQ$~Z=@o@3LqQh9O~ERf*24B z;=lkf5JZ6%pe1MpWZww`4M0QCibg#SI)IL#HK+~hfV!X_7y+U|3@F8%`jKJ!8TohZc?7i^at{Y=VwG*0rGt5yWkXf3v35Fz;j?H*ae;eD}Vvy0pVF-8kh=pQDHJX z9*hBTARd$hSPoWz`5+rC0O_D7UU(mT06qjC zfser_;5@hhJ_VnFi{KLY99#xhz!$RquM+qYd0p0{B!6|SWyanC{?|^r~8E_Vy1Mh)hU^w;5Uq~|l$xsMAst+Cm4M0O655*P( z^3?4Mcg5w|*O@|XGv^)qPT|Tt6Xmi1AkO|~W;elU+Pk^6E`!tYa zKx0q~Z5a4L#=js1d`jZek`e4Cq5`}Po&%mB!$?pE)V0I%FtliUVYy1b3J!x;z(H`x zwjF)DT+R4wlB*OSzZMyxA>JxYs-&r3+v;U|-y-@Zkc-vVK=!0Bfoxt!fb1o*r*sA# zK?hJ3lmlgfv`wy4%Ro4&t=!%9*R!NDxuVnpHGv!^s)K5vGN=gTN>c??1xvG42T9Jfh^$RKvwinun;T& z**F}7A9N_NF6dT`@mD+B_MeVOV3{fPJz!6mI7V?d%-ra7D%QoU_Dp|a=>P= z32X!#z>}Z^kThF?G*BAi52OK7p=i<&vvN2~Dt0Q}PWV|Mg-E97fs=4I;hkU?C~ZS* zCte!uq!CTZ6>mw!!biYSa1gu#>;`3-Et1|z%U%VN@Gv+89!Y4%OThw3>!fii_$xk6 zTB-EW_;c7YX9mjnpCTYVJ_)LWH^Cb~#=HaYfWAP+_HFnraN360XTcfpF8Bz12;K+p z+57?g3HTVC2Y0|ta2BOOgM2^-E+A*UhtLD?8@Lbt4*mvy1V4d$;4b(X z{9@zRN5Z8kqZB9!N`T^^7$_>IU4H^aKw;nqDuYTu+FKD8=LErW!{OX~$Yr()XbV5&=sI(nSvzf3z|@IKX?$3 z0*8ZPU<4QmqCqT(2XP<)i~-4D91w3vI0c9<$N*^|9ZUq1z*Ha|nd02-G{u++d|)<^ z7CK%LZ-|Q*1L^GoFds-S=Yedn2rL9o0Lix;NIprk63DQu0Sc@G;uZO9l(Bdc90a*w zE7$@yfz99+ft2NxBbwNP zBr`4RUyKhi&VjSw3^)be0;j>-;2rQTkjg#+?*Ym4KKKB944jIkGHHl-;L!$4yaA+> zzw6X*-uPcal%AIbSHR~$+$kSNzl`<;5L*hjVy$?&o*e*g^wqFjuH;N}4ciIdAlw>U z2j76Rq$ofdEvUbGdWc>t_v{cof?tXa({HNQ!}UP5gdY`ZkkXHpF>pwQR- zJ;ce@QJsm_1JoNM^gu_lim)yHOICgMpBY1pe(e%^U!eyhfI3MR`5wLDc1&|mOZJ4vV?_g8z;Xyc_++E}fq`Zbjn zyjoN>MASoztJW{jRp-@W1ABkaeb^7DuGpo~l1e4iG*Slrb$wO^?c7`NVUT)$A9a;T z*T=bzsH}87AnZ+K9PGQhxa{Q8rzS;GbV$Qy(n;snimy$+eDJMqzh%g9;VPEN`4Z~g zbR6WoKWxyf-_Bn?-6Wa3O-aHAVQ&A12SKl9%^h2^Ew<*YcNCk7Y79tl6d) zE2*BCL_eHYlYM=s>lZ!h_D{^qSg)jdl8j-_+t6O#`ANi_X;qHrrRY%7JlOgAY&o54 zjO{!=FJ?eVbxSHuEU5}iWDd+ArF42^@rD__-)jC|X;(d2{(R<_RQ)FE^}NeTQHd1K z!$siRk4Jx8CjHgTrDf3vHw+HZ4idvXjITtE%BA|Pzkj{-@9sHWQXQI@*F|-EB15~U zl=7RzYPb7KONvfrC{iX7=XBnA!Q1ZFw_MuV>eg=j8OpR`ENYceN6GDYO*$gkEBv*e zt$NrXhD>G+nS)Pb`<7MDPS(5qTO((WnA2K)N;x%>5e#zP3YTw0z>gmk+u72bL9z_B zg5}l9Oxcu>Ru$By)q0Ljk6xLEeX@eOJx%6h1@m6kx9{PtAN&GO*Uax~(y&PrnUl_| z-+JfVzTJA$xd(YMm4Z}@>GZ^YTb!>z`g?In@BXOgr5F^XQb-Zzyk9Qj&eWboi_bro zm%@1i-J+$xtKUQx9sMcAy0)`abM>DA5i|28u)FU2Ne0vP*N1$!r? zW}k}7i#bqHEs?y=+xTX6-8lA}9e&;NQaJDHEB3{?;K%O2bw4krNG0`|wCq?->ydD~s%wmBnm3lw8SoYI~5;rW+qcjL+36Y+=>)3cV^N#3B?T2{*v5470c zq`9x2^< zonUtUoufyTXg)bFMVs1I%R)*_A8_TBJ~4SQ18b`XlGk}f;Vbb+8aAyw;8b1;=Ou>6 zzFNM$RJo47Pzi7S{jQa7=cPDOTlr?{-SkzB)w`q&bKV#D>)^vL zKKu3LBIe#7Dy#k&`xSemZ^dh)`m5*s7ZVfSkpF16bv@R(l84RG>lJ#RluQ(#YRm;% z&6=e*33Fac`1G?&_v~J?rklN)aMf{M1G;y1=~}Z=F3E)|uh?6&^mcyRsN73&GeTA$ z(o0ui>(rcA>#ZwTyl~@{zr1W_3Xzy+Lsar?`r*8c?{=?&ORkql>T9M5Zp?M=4tqv5 zio165((2UyRcl&#LpUmw3{{87%Mp)Dd1-ZHwqDuV*UPCYbM(@FwK)hxkn_t>bvBy> zDRcGwVRBCwh&cUFUti?0`4_F?!Z>$1FBbfz+tTlXzpOsmifP)g8SgAqn-);Ora5|k zy-gE!`3b$WJB$eHh}T?#e{o6)4%M6&7v8x#E!S1Ex1Xs0Utb*Id8<)0mY%`+6On-QXl zKfx97v$^_6PXxy=IZ!=vbme3^Vjc%*=k<&ozes9d?^x~ut0m#=FqU`9JC11{LEoIW zL4Gr4>O4>Lu#Hw~iTU#$$w@f2sk%Rp$?v=vQcE~;{M%&{IG=J93K54bY^oa1=Ze0g zsp>MHi%r8YH3K`$c}8mdnlr^_WOq~K;8G(#c3zA5Mo_5-8*UUU@3cBZ>mR1xCT~zY z3qnp7p(|pi9NVyIy6zf;B2JhPzB-!(b8R!X{E5%bo_+A8*&ME`&3Ft;HOb~IVI8_l z|FIRtUH8M)%51%g?U}OqL+w$Mf3hH_ejVrUSfbW`Ck0_do;|v z4GYyqwN}Gf24V9^!6DRF)N{FSrP~LGIVpm*J;bmT`L^AzdSl(fZQtd^*tPs|6hrKB zFRx!}qZ%^Ie_4I7_G=r}Z3zvo(pF8Al>fA{Kb{5NSygyl3yEXIL)EcDVmR)Y|k~*j@%k+BHXYy?!M+DB(){^xO*AIR0U7^oODK~;lIQwSW zy3114mg^<`T6MHu6nCzp@-Al=`K+UQVmaNmx#2nD<$g1w%jw%8>jJsxoA(-AA)Qyc zPFsE~s^HNo8+6y1PU^ko9EXo}Rz+9f66a;EQ(i57xpav#GQsRyhs&K++ZEjNIL}_&c;&C<;c+<8~+kv@s9>kr;vmRIW6-PC>Z>i4>-vMcp&LB1Z=hz>pR*!6(vwR@0K zHW^y@u&0`_lCJ)BJJ$D7FHnZ=?Y(*xMH;Ttp@z@?x*o;J^A;$9*S(CsA6khH9+YhS5Fn zIU~Vy{15Juk+2)$Oeg z4;R1t%5l!NW<7j)_xsy$e@R;ROW_XBcg)LVzcANVUP;S?X6{B z9(*k?#(C-PbBn%Ol>J@)UU@OjYk9{l__{~$^&gg&m;si{oHzGwxOJrTlI+8e6z9AP z_?0)iexk~KTP&|Q=WW4zcb;swb;n2C6*`_PIzWB4hVgdZ4}9t2@{6Nto~dUJTNBw0 zG6$&QYZ-;?0jl0w#(gIL>;ev|Hq2T`qwh`gtz8hv}ZHH~yG$t=5bC_zFLtg9kzq~QCK>fLeeP_7Cb@Dnd2;SW& z_Vo|5$MGvHC+4kTY8rWioL34r7+u>vc(MEAycC6ot39O9s}EPFbM$WZ-FQ&jSgR{N z8ojn9;PmUI=}H)9A{L#!u7jMH1p75Cozo1O z@5vcYws!inB|)*VvH?+se6MqB>r;(4bicnfuT4jZDNamCxt+D91W%h!jGUIaHlIyU z$&&X9DN2xHLi4^k%`5FZY?f~J)OqpoQ}r$_%II9Ti=CI2XRDYDZvw?lYZlT_FwDLYlj?JU36XZSrYWvEx-gHNIEk}_S+GXkiW7N?n^)hPn zlX^wl=%$YutBP)cR9 z#3jy)lxqwMe&KAnMV-yOjk#~poL4O`{<^KVc24K3b_};kwUgCjo9LkPa^^e7r>Cs{ z`0e*eA$MlXEmDjmMVRwi=I>%B_Ae2a|L>%b>A{dVFK+G>67lzC@Bdhr7^ba!eOV}3 z?Iy2om!bc`R;4%VO@ez*u)gdcowobouf?8AG{5&VztkE+Oi_A%wrS~pgFpLQ!O|{o zOX^f3=Idpvb6X-a-+Ak9)k;0z& zMN(I9k#(4=0=MY({Mw{iQ>ss@>am5>9zd$;JZ zzh|SEN?UQ1^CICZ*`KEG?Qy!0SzoX$WapK`m#PMo^lMpECk6+~Wxqw5N+NHN^OE9# z0t0JQs55b;nL@s5*M_I5O;Wn^UgWaw!4-Q{oPA1nHM1^kn)3$bv~FYjk9>TVT$0T* zJNHy+>bB%{-oe~FxNE<_nV;_@g`7+9mGc(nzg?(aX7i4#t<1dUS9yHt*WxLhbSh1G zpVLEB_EUU|>Krr0IUSU&IMcM>?ll3pM#( zv%B5L^r>JrhHaEt#IFmUrX%*W(EF#W6;D&t8%LZzDgocv{hN`iGNszB@BV?f2J^J1_P%Tg2p7Rrc!vm2sf+-thsw-|7)v z{G~TZ5Jp}`pkJm6+0KQu^AzRVj$1BFQ90N_)|+ z%6X;unw71Of3Sa$+;2DK*oKR(QLR^F@pS8wTYZLgMTvf`>WPkP0)8STJBrj!Sx++l zy3K!f?X%Cr*Jr3()T-~vQdOQM$HOeu{8{Yp(o`~bP`XbuU*ml~yVe8mkZcci$iBs# z&i1J-qzwAgxox&$%`A0C%IuS-{FvMJ9M929&QTY{cBV|FIjYW1?8v!l=uYZ%UNwH} zZp_6Ir3yL6WBT>cT(yi8c1h*+O7qom$?24Yhf40!>*?jQm3J548WdijM()xR!kl-4 zZ>==%c$Ksd`2L6q#JX>$Id2V5>-_n{h;v`b)l4QGb^W+V-QOi1S)|JDrjEi-s4lzp zgdpd&;70>%7C1O!a`cY{%JSW<9WSajZ#aj(f;#Gh+MliE>Y{HOy@=A+cO`G z58YIOBQ0YUEc;)?QgxOTSwoguSJk_}P96Q)pq1NnS38t)w8MFsdBtj1svq@Kv%Z@$ zC+0#@$WmLkS~pXOLFZ=sn$-u;IOCU*rjTdnPQoB;fivt|Fpv|8|4@w zS45_sm7AbFsT5L# z{dI~XG*a$#Z^cFRzu4kvJL+x5*2HW`SfP&WWqouotX29^(Pqgd%XIBb3NHQ9G-hoP z`JJfqp7*KsUOp6kwMn{cK;|V@vwv%tm%8K{@nPO;;ye&sUt74z&fv1m&p<2yfOaWGM(By z^|vwCsaB2&xZk-R*meBHtA~_7K}tU=_-5Skb%U<; zev6cH+K5n}#p^*~M@m?8x&O#p4}V=2{j*sPyB{}@Iaa=wKOWtCx_DFTn}2f>znY^O zCg|nMmsn@zt=Fj2{kua-|3F^z8+y5zhK0F#rnMCHzEh<82T}XJt1Hhk1k33_`^UCR z({rRtsi~j{&OnVZAkm@*UP2XWijyA{Uf75l!EAO)mN%H6yt}3h9EEzwt?GW%rqb zG1f2hx=x6@rXG|lEAeT>e>&ZBHRjC2weQ&RC!f9Z_v!xG%Ra}JoqbBf$X~xK@#3|c z*yXWba)s^e-1(JPE|FL2tJR}ozLAq#W!3&;g29Wd1Z!5Wc%o*ax?8&63 zA4^*`6I;;F24=o#sFGKv>0YA=v^?}x5{{WpP z@HFq=g>!cw(L1;bP0WaIkUBmiUG?sguVQYqqx#ncbBnyM56qYQ$#p%#?MX?D9X~EQ zJ$7_%@!R@jkJ@@tuamp=7yV$H!g2BG@v-R*k`iNLS9|l7%gtz(FT~?FX>@e@q)`nr zQj^p(ZS$p;oD?6E7?;!_c6{>0_|&w-@yThq0gvZ9>ZiOt^A%9HGxHV7t|RRaAkqdR29zcfO$9ZfEsQuH0Q2`L-5RzUz89 fm3mEoT)lf;_fruW`6{Sa)AJR`?KwSP7uWv*^S)u6 diff --git a/frontend-vue/package.json b/frontend-vue/package.json index fb4f9ca..367eef7 100644 --- a/frontend-vue/package.json +++ b/frontend-vue/package.json @@ -14,7 +14,11 @@ "format": "prettier --write src/" }, "dependencies": { + "jdenticon": "^3.3.0", + "node-vibrant": "^4.0.3", "pinia": "^3.0.3", + "sass": "^1.89.2", + "sass-loader": "^16.0.5", "vue": "^3.5.17", "vue-router": "^4.5.1" }, @@ -31,6 +35,7 @@ "@vue/tsconfig": "^0.7.0", "eslint": "^9.29.0", "eslint-plugin-vue": "~10.2.0", + "fibers": "^5.0.3", "jiti": "^2.4.2", "jsdom": "^26.1.0", "npm-run-all2": "^8.0.4", diff --git a/frontend-vue/src/App.vue b/frontend-vue/src/App.vue index 7905b05..e35255f 100644 --- a/frontend-vue/src/App.vue +++ b/frontend-vue/src/App.vue @@ -1,22 +1,11 @@ diff --git a/frontend-vue/src/assets/base.css b/frontend-vue/src/assets/base.css index 7e10f38..2e7efbc 100644 --- a/frontend-vue/src/assets/base.css +++ b/frontend-vue/src/assets/base.css @@ -1,18 +1,28 @@ @media (prefers-color-scheme: light) { - :root { - --text: #0d0f0b; - --background: #f6f7f3; - --primary: #4a5733; - --secondary: #b5c898; - --accent: #7c9b4b; - } + :root { + --text: #0d0f0b; + --background: #f6f7f3; + --primary: #4a5733; + --secondary: #b5c898; + --accent: #7c9b4b; + } } @media (prefers-color-scheme: dark) { - :root { - --text: #f2f4f0; - --background: #0b0c08; - --primary: #bfcca8; - --secondary: #546737; - --accent: #96b464; - } + :root { + --text: #f2f4f0; + --background: #0b0c08; + --primary: #bfcca8; + --secondary: #546737; + --accent: #96b464; + } } +:root { + --border: var(--text); +} + +svg.black-white { + fill: var(--text); + stroke: var(--text); +} + +/*# sourceMappingURL=base.css.map */ diff --git a/frontend-vue/src/assets/base.css.map b/frontend-vue/src/assets/base.css.map new file mode 100644 index 0000000..d9050d5 --- /dev/null +++ b/frontend-vue/src/assets/base.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["base.scss"],"names":[],"mappings":"AAGA;EACC;IACC;IACA;IACA;IACA;IACA;;;AAIF;EACC;IACC;IACA;IACA;IACA;IACA;;;AAKF;EACE;;;AAGF;EACI;EACA","file":"base.css"} \ No newline at end of file diff --git a/frontend-vue/src/assets/main.css b/frontend-vue/src/assets/main.css index 36fb845..c520204 100644 --- a/frontend-vue/src/assets/main.css +++ b/frontend-vue/src/assets/main.css @@ -1,4 +1,12 @@ -@import './base.css'; +@import 'base.scss'; + +body { + background-color: var(--background); +} + +p, h1, h2, h3, h4, h5, h6 { + color: var(--text); +} #app { max-width: 1280px; @@ -10,7 +18,7 @@ a, .green { text-decoration: none; - color: hsla(160, 100%, 37%, 1); + color: var(--accent); transition: 0.4s; padding: 3px; } diff --git a/frontend-vue/src/components/WelcomeItem.vue b/frontend-vue/src/components/WelcomeItem.vue index 6d7086a..df3e839 100644 --- a/frontend-vue/src/components/WelcomeItem.vue +++ b/frontend-vue/src/components/WelcomeItem.vue @@ -21,7 +21,8 @@ .details { flex: 1; - margin-left: 1rem; + margin-left: 2rem; + color: var(--text); } i { @@ -31,28 +32,28 @@ i { width: 32px; height: 32px; - color: var(--color-text); + color: var(--text); } h3 { font-size: 1.2rem; font-weight: 500; margin-bottom: 0.4rem; - color: var(--color-heading); + color: var(--text); } @media (min-width: 1024px) { .item { margin-top: 0; - padding: 0.4rem 0 1rem calc(var(--section-gap) / 2); + padding: 0.4rem 0 1rem; } i { top: calc(50% - 25px); left: -26px; position: absolute; - border: 1px solid var(--color-border); - background: var(--color-background); + border: 1px solid var(--text); + background: var(--background); border-radius: 8px; width: 50px; height: 50px; @@ -60,7 +61,7 @@ h3 { .item:before { content: ' '; - border-left: 1px solid var(--color-border); + border-left: 1px solid var(--text); position: absolute; left: 0; bottom: calc(50% + 25px); @@ -69,7 +70,7 @@ h3 { .item:after { content: ' '; - border-left: 1px solid var(--color-border); + border-left: 1px solid var(--text); position: absolute; left: 0; top: calc(50% + 25px); diff --git a/frontend-vue/src/components/global/Header.vue b/frontend-vue/src/components/global/Header.vue new file mode 100644 index 0000000..3af8548 --- /dev/null +++ b/frontend-vue/src/components/global/Header.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/frontend-vue/src/components/user/Header.vue b/frontend-vue/src/components/user/Header.vue deleted file mode 100644 index e69de29..0000000 diff --git a/frontend-vue/src/components/user/PreviewHeader.vue b/frontend-vue/src/components/user/PreviewHeader.vue new file mode 100644 index 0000000..2902884 --- /dev/null +++ b/frontend-vue/src/components/user/PreviewHeader.vue @@ -0,0 +1,30 @@ + + + + diff --git a/frontend-vue/src/components/user/ProfilePicture.vue b/frontend-vue/src/components/user/ProfilePicture.vue new file mode 100644 index 0000000..23188b6 --- /dev/null +++ b/frontend-vue/src/components/user/ProfilePicture.vue @@ -0,0 +1,57 @@ + + + diff --git a/frontend-vue/src/components/util/FormattedText.vue b/frontend-vue/src/components/util/FormattedText.vue index f6f73bb..04d40d4 100644 --- a/frontend-vue/src/components/util/FormattedText.vue +++ b/frontend-vue/src/components/util/FormattedText.vue @@ -1,5 +1,4 @@ -

{{props.rawText}}

+ diff --git a/frontend-vue/src/router/index.ts b/frontend-vue/src/router/index.ts index 3e49915..fa57489 100644 --- a/frontend-vue/src/router/index.ts +++ b/frontend-vue/src/router/index.ts @@ -17,6 +17,11 @@ const router = createRouter({ // which is lazy-loaded when the route is visited. component: () => import('../views/AboutView.vue'), }, + { + path: '/testing/note', + name: 'note-testing', + component: () => import('../views/NoteTestView.vue'), + }, ], }) diff --git a/frontend-vue/src/stores/media.ts b/frontend-vue/src/stores/media.ts new file mode 100644 index 0000000..5a78894 --- /dev/null +++ b/frontend-vue/src/stores/media.ts @@ -0,0 +1,10 @@ +export interface MediaMetadata { + id: string; + ownedBy: string; + remote: boolean; + url: string; + mediaType: string; + name: string; + alt: string; + blurred: boolean; +} diff --git a/frontend-vue/src/stores/userdata.ts b/frontend-vue/src/stores/userdata.ts new file mode 100644 index 0000000..95d0397 --- /dev/null +++ b/frontend-vue/src/stores/userdata.ts @@ -0,0 +1,10 @@ +import type { MediaMetadata } from '@/stores/media.ts' + +export interface User { + username: string + displayName: string + description: string + profilePicture?: MediaMetadata + bannerPicture?: MediaMetadata + backgroundPicture?: MediaMetadata +} diff --git a/frontend-vue/src/utils/identiheart.ts b/frontend-vue/src/utils/identiheart.ts new file mode 100644 index 0000000..9df1ec8 --- /dev/null +++ b/frontend-vue/src/utils/identiheart.ts @@ -0,0 +1,492 @@ +class Crusher { + hash(s: any): number { + return String(s).split("").reduce(function(a, b) { + a = ((a << 5) - a) + b.charCodeAt(0); + return a & a + }, 0); + } + isDOMElement(o:any): boolean { + return ( + typeof HTMLElement === "object" ? o instanceof HTMLElement : + o && typeof o === "object" && true && o.nodeType === 1 && typeof o.nodeName==="string" + ); + } +} + +enum BlockType { + ONE = 1, + TWO = 2, + THREE = 3, +} + +class Block { + canvas: HTMLCanvasElement; + context: CanvasRenderingContext2D; + type: BlockType; + primary: string; + accent: string; + cellSize: number; + margin: number; + scale: number; + pos: Position; + hash: number; + + constructor( + c: HTMLCanvasElement, + ctx: CanvasRenderingContext2D, + type: BlockType, + primary: string, + accent: string, + hash: number, + cellSize: number, + margin: number, + scale: number, + pos: Position, + ) { + this.canvas = c; + this.context = ctx; + this.type = type; + this.primary = primary; + this.accent = accent; + this.hash = hash; + this.cellSize = cellSize; + this.margin = margin; + this.scale = scale; + this.pos = pos; + } + + offset() { + this.context.save(); + this.context.translate(0.6 * this.scale, -0.6 * this.scale); + } + + resetOffset() { + this.context.restore(); + } + + makePath(hash: number, offset: number) { + const mod = Math.abs(hash + offset) % 4; + + switch(mod) { + case 0: + // top + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x + this.cellSize, this.pos.y); + this.context.lineTo(this.pos.x + this.cellSize, this.pos.y + this.cellSize); + this.context.closePath(); + break; + case 1: + // right + this.context.beginPath(); + this.context.moveTo(this.pos.x + this.cellSize, this.pos.y); + this.context.lineTo(this.pos.x + this.cellSize, this.pos.y + this.cellSize); + this.context.lineTo(this.pos.x, this.pos.y + this.cellSize); + this.context.closePath(); + break; + case 2: + // bottom + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x, this.pos.y + this.cellSize); + this.context.lineTo(this.pos.x + this.cellSize, this.pos.y + this.cellSize); + this.context.closePath(); + break; + case 3: + // left + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x + this.cellSize, this.pos.y); + this.context.lineTo(this.pos.x, this.pos.y + this.cellSize); + this.context.closePath(); + break; + default: + // top + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x + this.cellSize, this.pos.y); + this.context.lineTo(this.pos.x, this.pos.y + this.cellSize); + this.context.closePath(); + } + } + + draw() { + this.offset(); + + if (this.type === BlockType.ONE) { + this.makePath(this.hash, this.hash % 3); + this.context.fillStyle = this.primary; + this.context.fill(); + + this.makePath(this.hash, this.hash % 5); + this.context.fillStyle = this.accent; + this.context.fill(); + } else if (this.type === BlockType.TWO) { + this.makePath(this.hash, this.hash % 4); + this.context.fillStyle = this.accent; + this.context.fill(); + + this.makePath(this.hash, this.hash % 3); + this.context.fillStyle = this.primary; + this.context.fill(); + } else { + this.makePath(this.hash, this.hash % 7); + this.context.fillStyle = this.accent; + this.context.fill(); + + this.makePath(this.hash, this.hash % 8); + this.context.fillStyle = this.primary; + this.context.fill(); + } + + this.resetOffset(); + } +} + +class Position { + x: number; + y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } +} + +class Shape { + canvas: HTMLCanvasElement; + context: CanvasRenderingContext2D; + hash: number; + primary: string; + accent: string; + pos: Position; + scale: number; + cellSize: number; + strokeColor: string; + + constructor( + c: HTMLCanvasElement, + ctx: CanvasRenderingContext2D, + hash: number, + primary: string, + accent: string, + pos: Position, + scale: number, + cellSize: number, + strokeColor: string + ) { + this.canvas = c; + this.context = ctx; + this.hash = hash; + this.primary = primary; + this.accent = accent; + this.pos = pos; + this.scale = scale; + this.cellSize = cellSize; + this.strokeColor = strokeColor; + } + + getColor() { + return [this.primary, this.accent][Math.abs(this.hash % 2)]; + } + + makePath() { + const mod = Math.abs(this.hash + 1) % 4; + + switch(mod) { + case 0: + // square + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x + (this.cellSize / 2), this.pos.y); + this.context.lineTo(this.pos.x + (this.cellSize / 2), this.pos.y - (this.cellSize / 2)); + this.context.lineTo(this.pos.x, this.pos.y - (this.cellSize / 2)); + this.context.closePath(); + break; + case 1: + //circle + this.context.beginPath(); + this.context.arc( + this.pos.x + (this.cellSize / Math.PI) - 5, + this.pos.y - (this.cellSize / Math.PI) + 5, + this.cellSize / 3, + 0, + Math.PI * 2, + true + ); + break; + case 2: + // triangle + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x + (this.cellSize * 0.65), this.pos.y); + this.context.lineTo(this.pos.x, this.pos.y - (this.cellSize * 0.65)); + this.context.closePath(); + break; + case 3: + // oval + this.context.beginPath(); + this.context.moveTo(this.pos.x - (this.cellSize * 0.2), this.pos.y + (this.cellSize * 0.2)); + this.context.quadraticCurveTo(this.pos.x + (this.cellSize * 0.4), this.pos.y, this.pos.x + (this.cellSize * 0.5), this.pos.y - (this.cellSize * 0.5)); + this.context.moveTo(this.pos.x + (this.cellSize * 0.5), this.pos.y - (this.cellSize * 0.5)); + this.context.quadraticCurveTo(this.pos.x , this.pos.y - (this.cellSize * 0.4), this.pos.x - (this.cellSize * 0.2), this.pos.y + (this.cellSize * 0.2)); + break; + default: + //square + this.context.beginPath(); + this.context.moveTo(this.pos.x, this.pos.y); + this.context.lineTo(this.pos.x + (this.cellSize / 2), this.pos.y); + this.context.lineTo(this.pos.x + (this.cellSize / 2), this.pos.y - (this.cellSize / 2)); + this.context.lineTo(this.pos.x, this.pos.y - (this.cellSize / 2)); + this.context.closePath(); + } + } + + draw(hasStroke: boolean, strokeWeight: number) { + const color = this.getColor(); + this.context.globalCompositeOperation = "source-over"; + + this.makePath(); + this.context.fillStyle = color; + this.context.strokeStyle = this.strokeColor; + this.context.lineWidth = this.scale * ((4/5 * strokeWeight) / this.canvas.width); + this.context.lineJoin = "round"; + this.context.lineCap = "round"; + this.context.fill(); + + if (hasStroke) { + this.context.stroke(); + } + } +} + + +/** + * @name IdentiHeart + * @author Schlipak + * @copyright Apache license 2015 Guillaume de Matos + */ +export class Identiheart { + canvas: HTMLCanvasElement + context: CanvasRenderingContext2D + margin: number + crusher: Crusher + palette = [ + '#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', + '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39', + '#FFEB3B', '#FFC107', '#FF9800', '#FF5722', '#795548', '#607D8B' + ]; + + primary: string = "#F44336"; + accent: string = "#E91E63"; + scale: number; + cellSize: number; + hash: number = 0; + blocks: Block[] = []; + shape?: Shape; + hasStroke: boolean = true; + strokeWeight = 500; + strokeColor = "#000000"; + compositeOperation: GlobalCompositeOperation = 'multiply'; + + constructor(c: HTMLCanvasElement, margin?: number, scale?: number, ctx?: CanvasRenderingContext2D) { + this.canvas = c; + this.context = ctx ?? c.getContext("2d")!; + this.margin = margin || 5; + this.scale = scale || 20; + this.crusher = new Crusher(); + this.cellSize = (this.canvas.width / 2) - (this.margin * this.scale); + } + + setUsername(username: string) { + this.hash = this.crusher.hash(username); + return this; + } + + setPalette(palette:string[]) { + if (palette.length < 2) { + throw new Error('Palette must be more than two elements long'); + } + + this.palette = palette; + return this; + } + + setHasStroke(b: boolean) { + this.hasStroke = b; + return this; + } + + setStrokeWeight(weight: number) { + this.strokeWeight = weight; + return this; + } + + setStrokeColor(color: string) { + this.strokeColor = color; + return this; + } + + setCompositeOperation(operation: GlobalCompositeOperation) { + this.compositeOperation = operation; + return this; + } + + setCanvas(canvas: HTMLCanvasElement) { + this.canvas = canvas; + this.context = canvas.getContext('2d')!; + return this; + } + + init() { + // Purge the block array + this.blocks = new Array(); + // Purge the shape + this.shape = undefined; + + // Generate colors + const crusher = new Crusher(); + const subHash = crusher.hash(this.hash); + this.accent = this.palette[Math.abs(subHash % this.palette.length)]; + + // Clear the canvas + this.context.globalCompositeOperation = "source-over"; + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.context.globalCompositeOperation = this.compositeOperation; + + return this; + } + + draw() { + this.init(); + + // Rotate the canvas -45deg + this.context.save(); + this.context.translate(this.canvas.width/2, this.canvas.height/2); + this.context.rotate(- Math.PI / 4); + this.context.translate(-this.canvas.width/2, -this.canvas.height/2); + + this.generateBlocks(); + this.drawBlocks(); + + if (this.hasStroke) { + this.drawOutline(); + } + + this.shape = new Shape(this.canvas, this.context, this.hash, this.primary, this.accent, { + x: (this.margin * this.scale) + 1.5 * this.cellSize, + y: (this.margin * this.scale) + 0.5 * this.cellSize + }, this.scale, this.cellSize, this.strokeColor); + this.shape.draw(this.hasStroke, this.strokeWeight); + + // Restore the original matrix + this.context.restore(); + + return this; + } + + offset() { + this.context.save(); + this.context.translate(0.6 * this.scale, - 0.6 * this.scale); + } + + resetOffset() { + this.context.restore(); + } + + drawOutline() { + this.offset(); + this.context.globalCompositeOperation = "source-over"; + + // Outer lines + this.context.beginPath(); + this.context.moveTo(this.margin * this.scale, this.margin * this.scale); + this.context.lineTo(this.margin * this.scale, this.canvas.height - (this.margin * this.scale)); + this.context.lineTo(this.canvas.width - (this.margin * this.scale), this.canvas.height - (this.margin * this.scale)); + this.context.lineTo(this.canvas.width - (this.margin * this.scale), this.canvas.height / 2); + this.context.lineTo(this.canvas.width / 2, this.canvas.height / 2); + this.context.lineTo(this.canvas.width / 2, this.margin * this.scale); + this.context.closePath(); + + this.context.strokeStyle = this.strokeColor; + this.context.lineWidth = this.scale * (this.strokeWeight / this.canvas.width); + this.context.lineJoin = "round"; + this.context.lineCap = "round"; + this.context.stroke(); + + // Inner lines + this.context.beginPath(); + this.context.moveTo(this.canvas.width / 2, this.canvas.height / 2); + this.context.lineTo(this.margin * this.scale, this.canvas.height / 2); + this.context.moveTo(this.canvas.width / 2, this.canvas.height / 2); + this.context.lineTo(this.canvas.width / 2, this.canvas.height - (this.margin * this.scale)); + + this.context.stroke(); + + this.resetOffset(); + this.context.globalCompositeOperation = this.compositeOperation; + } + + generateBlocks() { + /* + c: HTMLCanvasElement, + ctx: CanvasRenderingContext2D, + type: BlockType, + primary: string, + accent: string, + hash: number, + cellSize: number, + margin: number, + scale: number, + pos: Position, + * */ + let b1 = new Block( + this.canvas, + this.context, + BlockType.ONE, + this.primary, + this.accent, + this.hash, + this.cellSize, + this.margin, + this.scale, + new Position(this.margin * this.scale,this.margin * this.scale)); + this.blocks.push(b1); + + let b2 = new Block( + this.canvas, + this.context, + BlockType.TWO, + this.primary, this.accent, + this.hash, + this.cellSize, + this.margin, + this.scale, + new Position(this.margin * this.scale,this.canvas.height / 2) + ); + this.blocks.push(b2); + + let b3 = new Block( + this.canvas, + this.context, + BlockType.THREE, + this.primary, + this.accent, + this.hash, + this.cellSize, + this.margin, + this.scale, + new Position(this.canvas.width / 2, this.canvas.height / 2) + ); + this.blocks.push(b3); + } + + drawBlocks() { + if (this.blocks.length == 0) { + return false; + } + + for (var i = 0; i < this.blocks.length; i++) { + this.blocks[i].draw(); + } + } +} diff --git a/frontend-vue/src/views/AboutView.vue b/frontend-vue/src/views/AboutView.vue index 756ad2a..2b3dbb0 100644 --- a/frontend-vue/src/views/AboutView.vue +++ b/frontend-vue/src/views/AboutView.vue @@ -10,6 +10,7 @@ min-height: 100vh; display: flex; align-items: center; + color: var(--text); } } diff --git a/frontend-vue/src/views/NoteTestView.vue b/frontend-vue/src/views/NoteTestView.vue new file mode 100644 index 0000000..60b0cbd --- /dev/null +++ b/frontend-vue/src/views/NoteTestView.vue @@ -0,0 +1,29 @@ + + + + + From ba11090007bd30499bf50c0904f9f5ed73d3ecfe Mon Sep 17 00:00:00 2001 From: mStar Date: Thu, 10 Jul 2025 20:25:07 +0200 Subject: [PATCH 2/2] Huw did this go missing? --- frontend-vue/src/assets/base.scss | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 frontend-vue/src/assets/base.scss diff --git a/frontend-vue/src/assets/base.scss b/frontend-vue/src/assets/base.scss new file mode 100644 index 0000000..4fd2864 --- /dev/null +++ b/frontend-vue/src/assets/base.scss @@ -0,0 +1,32 @@ +@use "sass:color"; + +// Base colors here +@media (prefers-color-scheme: light) { + :root { + --text: #0d0f0b; + --background: #f6f7f3; + --primary: #4a5733; + --secondary: #b5c898; + --accent: #7c9b4b; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --text: #f2f4f0; + --background: #0b0c08; + --primary: #bfcca8; + --secondary: #546737; + --accent: #96b464; + } +} + +// And calculate the rest here +:root { + --border: var(--text); +} + +svg.black-white { + fill: var(--text); + stroke: var(--text); +}