From e9bc8eb2dae6314bf9847515d84288cf95c1db0f Mon Sep 17 00:00:00 2001
From: Archos
Date: Thu, 9 Oct 2025 15:50:02 +0200
Subject: [PATCH] aktualizace phanpy_cz
---
404.html | 2 +-
assets/ICONS-BLqAe1AS.js | 2 +
assets/ICONS-BLqAe1AS.js.map | 1 +
assets/ScheduledAtField-Bi22_aXV.css | 1 +
assets/ScheduledAtField-O5kh-u-d.js | 194 ++++++++++++++++++
assets/ScheduledAtField-O5kh-u-d.js.map | 1 +
assets/compose-DPEmvLj7.js | 31 +++
assets/compose-DPEmvLj7.js.map | 1 +
assets/compose-DoxvhBtV.css | 1 +
assets/compose-P9SlIbYO.js | 2 +
assets/compose-P9SlIbYO.js.map | 1 +
assets/icons/add-circle-line-VUOz5dLS.js | 1 -
assets/icons/alert-line-CcwmWSBO.js | 1 -
assets/icons/android-2-line-C7qVwx2U.js | 1 -
assets/icons/announcement-line-BdsFnqjO.js | 1 -
.../icons/arrow-down-circle-line-SfuiravZ.js | 1 -
assets/icons/arrow-down-line-RSwsrALM.js | 1 -
assets/icons/arrow-left-line-BGgZ0udH.js | 1 -
assets/icons/arrow-right-line-zKtS4vm5.js | 1 -
assets/icons/arrow-up-circle-line-SO68bPTf.js | 1 -
assets/icons/arrow-up-line-Bow_AQZ6.js | 1 -
assets/icons/arrows-right-line-B7gMPCMB.js | 1 -
assets/icons/at-line-C4-OGRKX.js | 1 -
assets/icons/attachment-line-C4ysC1zZ.js | 1 -
assets/icons/blockquote-line-Dcv4EJtN.js | 1 +
assets/icons/bookmark-line-BMGZc_Mc.js | 1 -
assets/icons/building-5-line-jPUf3HeC.js | 1 -
assets/icons/bus-2-line-CfBaNBAi.js | 1 -
assets/icons/calendar-day-line-zQlj2fPr.js | 1 -
assets/icons/calendar-month-line-DGpTEHfi.js | 1 -
.../icons/calendar-time-add-line-BwP_cVys.js | 1 -
assets/icons/camera-line-DK82q_yA.js | 1 -
assets/icons/celebrate-line-CwClz8eZ.js | 1 -
assets/icons/chart-bar-line-W9BuvVdR.js | 1 -
assets/icons/chart-line-line-noCpZUdN.js | 1 -
assets/icons/chat-3-line-C4e7R0Zy.js | 1 -
assets/icons/check-circle-line-CSlVj8QA.js | 1 -
assets/icons/clipboard-line-CIOFpSsX.js | 1 -
assets/icons/close-circle-line-DlCWcUwK.js | 1 -
assets/icons/close-line-Bfj902o4.js | 1 -
assets/icons/cloud-line-CCOdtB64.js | 1 -
assets/icons/code-line-_8nrb8Yp.js | 1 -
assets/icons/comment-2-line-DfD-95ou.js | 1 -
assets/icons/copy-2-line-SBRewLs-.js | 1 -
assets/icons/delete-2-line-C-lQIJNC.js | 1 -
assets/icons/document-line-ewA3UKpU.js | 1 -
assets/icons/down-line-PlS1iUy8.js | 1 -
assets/icons/edit-4-line-B3lvLrpT.js | 1 -
assets/icons/emoji-2-line-DODV8bnC.js | 1 -
assets/icons/exit-line-NjC63GxM.js | 1 -
assets/icons/external-link-line-BYXsdcMa.js | 1 -
assets/icons/eye-2-line-Dvog5oyl.js | 1 -
assets/icons/eye-close-line-DQnawnJE.js | 1 -
assets/icons/filter-2-line-DLBEPhKS.js | 1 -
assets/icons/filter-line-CuUlgBZU.js | 1 -
assets/icons/flag-1-line-sWzx_4o4.js | 1 -
assets/icons/forbid-circle-line-f_JQE7a8.js | 1 -
assets/icons/formula-line-DHbN6ztn.js | 1 -
assets/icons/group-line-Cw2Phg9p.js | 1 -
assets/icons/hand-finger-2-line-QNYxa4H_.js | 1 -
assets/icons/hashtag-line-Cml-0qv2.js | 1 -
assets/icons/heart-crack-line-BlrTdexG.js | 1 -
assets/icons/heart-line-vi3QqJTo.js | 1 -
assets/icons/history-2-line-C2uKqj-3.js | 1 -
assets/icons/history-line-Bi2So-je.js | 1 -
assets/icons/home-3-line-BLD1YYP8.js | 1 -
assets/icons/information-line-Dn255DD5.js | 1 -
assets/icons/keyboard-line-BRd9ohM1.js | 1 -
assets/icons/layout-4-line-BFFb1cPy.js | 1 -
assets/icons/layout-5-line-tauINoiF.js | 1 -
assets/icons/left-line-8vYaPuok.js | 1 -
assets/icons/lightning-line-cvW5NR-M.js | 1 -
assets/icons/link-2-line-SnIkQ_rZ.js | 1 -
assets/icons/list-check-line-BaMf8v8i.js | 1 -
assets/icons/lock-line-BbTC1fux.js | 1 -
assets/icons/mail-line-Cadg2cpP.js | 1 -
assets/icons/more-1-fill-Cnnj9cLP.js | 1 -
assets/icons/more-3-line-WfszpsFu.js | 1 -
assets/icons/notification-line-Cc2m6sh5.js | 1 -
assets/icons/pencil-line-BwUdLENj.js | 1 -
assets/icons/photo-album-line-DkklX4P5.js | 1 -
assets/icons/pin-line-BqseDe3t.js | 1 -
assets/icons/play-fill-D1o3ePO2.js | 1 -
assets/icons/quill-pen-line-oAx8SSeF.js | 1 -
assets/icons/quote-left-line-D0CgS7V6.js | 1 -
assets/icons/radar-line-Dch2zZ5p.js | 1 -
assets/icons/react-line-C6TecPWI.js | 1 -
assets/icons/refresh-2-line-B3CD5yz0.js | 1 -
assets/icons/right-line-E80CeS1Q.js | 1 -
assets/icons/rocket-line-B7gBxy4I.js | 1 -
assets/icons/round-fill-CaZIeOWe.js | 1 -
assets/icons/route-line-D10jSVCO.js | 1 -
assets/icons/rows-4-line-DIXu-DVG.js | 1 -
assets/icons/search-2-line-CoCbFBVR.js | 1 -
assets/icons/settings-3-line-BGrM7a5R.js | 1 -
assets/icons/settings-6-line-3dTfr4F6.js | 1 -
assets/icons/share-2-line-C2byQ30z.js | 1 -
assets/icons/share-forward-line-DX1QbiUu.js | 1 -
assets/icons/sparkles-2-line-H731KO3v.js | 1 -
assets/icons/sparkles-line-DWyRj8uB.js | 1 -
assets/icons/time-line-CHAmvUdg.js | 1 -
assets/icons/transfer-4-line-BHXBUumZ.js | 1 -
assets/icons/translate-line-cdOWN72F.js | 1 -
assets/icons/unlock-line-CGrzBxul.js | 1 -
assets/icons/upload-3-line-BB2RA_2Z.js | 1 -
assets/icons/user-4-line-C89P3h09.js | 1 -
assets/icons/user-add-2-line-BbaxtCjf.js | 1 -
assets/icons/user-add-line-DuegJyfy.js | 1 -
assets/icons/user-edit-line-CC6Y-fJT.js | 1 -
assets/icons/user-follow-line-CsL-DB1N.js | 1 -
assets/icons/user-star-line-jCNS7JD6.js | 1 -
assets/icons/user-warning-line-BLfdr8Bj.js | 1 -
assets/icons/user-x-line-Dahn1YZg.js | 1 -
assets/icons/volume-line-dtC5ZFr8.js | 1 -
assets/icons/volume-mute-line-BluUkhVT.js | 1 -
assets/icons/walk-line-BZwRwcxJ.js | 1 -
assets/icons/world-2-line-BqQ1RIgL.js | 1 -
assets/icons/zoom-in-line-a0TkUNno.js | 1 -
assets/icons/zoom-out-line-wfKlvfFM.js | 1 -
assets/locales/ar-SA-CDNdOtfs.js | 1 +
assets/locales/ca-ES-CxAoO_I3.js | 1 +
assets/locales/cs-CZ-CjIobYdO.js | 1 +
assets/locales/de-DE-dhPpog3t.js | 1 +
assets/locales/eo-UY-BrZQz0vH.js | 1 +
assets/locales/es-ES-BqeCFrKf.js | 1 +
assets/locales/eu-ES-DpPedTtb.js | 1 +
assets/locales/fa-IR-CSZBIA71.js | 1 +
assets/locales/fi-FI-ivGhXWUZ.js | 1 +
assets/locales/fr-FR-COHx1nPI.js | 1 +
assets/locales/gl-ES-CCDsjs9K.js | 1 +
assets/locales/he-IL-CDNdOtfs.js | 1 +
assets/locales/it-IT-C0_fpwIJ.js | 1 +
assets/locales/ja-JP-CDNdOtfs.js | 1 +
assets/locales/kab-pD_PUcxx.js | 1 +
assets/locales/ko-KR-CwqZ49z-.js | 1 +
assets/locales/lt-LT-CncvK9Qo.js | 1 +
assets/locales/nb-NO-CDNdOtfs.js | 1 +
assets/locales/nl-NL-Akym_zHM.js | 1 +
assets/locales/oc-FR-CDNdOtfs.js | 1 +
assets/locales/pl-PL-By6FX6b1.js | 1 +
assets/locales/pseudo-LOCALE-BwEJy58t.js | 1 +
assets/locales/pt-BR-Ds3-9-kj.js | 1 +
assets/locales/pt-PT-Vw7HPpab.js | 1 +
assets/locales/ru-RU-CijsJMoS.js | 1 +
assets/locales/th-TH-CDNdOtfs.js | 1 +
assets/locales/tok-CDNdOtfs.js | 1 +
assets/locales/tr-TR-CDNdOtfs.js | 1 +
assets/locales/uk-UA-DuCAvqrn.js | 1 +
assets/locales/zh-CN-BhVLBBpS.js | 1 +
assets/locales/zh-TW-CDNdOtfs.js | 1 +
assets/main-4pNIlcuh.css | 1 +
assets/main-sgpw-Fwy.js | 36 ++++
assets/main-sgpw-Fwy.js.map | 1 +
assets/polyfill-force-D2cMya_1.js | 9 +
assets/polyfill-force-D2cMya_1.js.map | 1 +
assets/pwa-viewport-BBUWca8r.css | 7 +
assets/pwa-viewport-cDxGxYgG.js | 45 ++++
assets/pwa-viewport-cDxGxYgG.js.map | 1 +
assets/temml-KWa8qPDv.js | 97 +++++++++
assets/temml-KWa8qPDv.js.map | 1 +
assets/tinyld.light.node-D9KYf3Y3.js.map | 2 +-
compose/index.html | 8 +-
index.html | 29 ++-
sw.js | 2 +-
sw.js.map | 2 +-
version.json | 2 +-
166 files changed, 497 insertions(+), 123 deletions(-)
create mode 100644 assets/ICONS-BLqAe1AS.js
create mode 100644 assets/ICONS-BLqAe1AS.js.map
create mode 100644 assets/ScheduledAtField-Bi22_aXV.css
create mode 100644 assets/ScheduledAtField-O5kh-u-d.js
create mode 100644 assets/ScheduledAtField-O5kh-u-d.js.map
create mode 100644 assets/compose-DPEmvLj7.js
create mode 100644 assets/compose-DPEmvLj7.js.map
create mode 100644 assets/compose-DoxvhBtV.css
create mode 100644 assets/compose-P9SlIbYO.js
create mode 100644 assets/compose-P9SlIbYO.js.map
create mode 100644 assets/icons/blockquote-line-Dcv4EJtN.js
create mode 100644 assets/locales/ar-SA-CDNdOtfs.js
create mode 100644 assets/locales/ca-ES-CxAoO_I3.js
create mode 100644 assets/locales/cs-CZ-CjIobYdO.js
create mode 100644 assets/locales/de-DE-dhPpog3t.js
create mode 100644 assets/locales/eo-UY-BrZQz0vH.js
create mode 100644 assets/locales/es-ES-BqeCFrKf.js
create mode 100644 assets/locales/eu-ES-DpPedTtb.js
create mode 100644 assets/locales/fa-IR-CSZBIA71.js
create mode 100644 assets/locales/fi-FI-ivGhXWUZ.js
create mode 100644 assets/locales/fr-FR-COHx1nPI.js
create mode 100644 assets/locales/gl-ES-CCDsjs9K.js
create mode 100644 assets/locales/he-IL-CDNdOtfs.js
create mode 100644 assets/locales/it-IT-C0_fpwIJ.js
create mode 100644 assets/locales/ja-JP-CDNdOtfs.js
create mode 100644 assets/locales/kab-pD_PUcxx.js
create mode 100644 assets/locales/ko-KR-CwqZ49z-.js
create mode 100644 assets/locales/lt-LT-CncvK9Qo.js
create mode 100644 assets/locales/nb-NO-CDNdOtfs.js
create mode 100644 assets/locales/nl-NL-Akym_zHM.js
create mode 100644 assets/locales/oc-FR-CDNdOtfs.js
create mode 100644 assets/locales/pl-PL-By6FX6b1.js
create mode 100644 assets/locales/pseudo-LOCALE-BwEJy58t.js
create mode 100644 assets/locales/pt-BR-Ds3-9-kj.js
create mode 100644 assets/locales/pt-PT-Vw7HPpab.js
create mode 100644 assets/locales/ru-RU-CijsJMoS.js
create mode 100644 assets/locales/th-TH-CDNdOtfs.js
create mode 100644 assets/locales/tok-CDNdOtfs.js
create mode 100644 assets/locales/tr-TR-CDNdOtfs.js
create mode 100644 assets/locales/uk-UA-DuCAvqrn.js
create mode 100644 assets/locales/zh-CN-BhVLBBpS.js
create mode 100644 assets/locales/zh-TW-CDNdOtfs.js
create mode 100644 assets/main-4pNIlcuh.css
create mode 100644 assets/main-sgpw-Fwy.js
create mode 100644 assets/main-sgpw-Fwy.js.map
create mode 100644 assets/polyfill-force-D2cMya_1.js
create mode 100644 assets/polyfill-force-D2cMya_1.js.map
create mode 100644 assets/pwa-viewport-BBUWca8r.css
create mode 100644 assets/pwa-viewport-cDxGxYgG.js
create mode 100644 assets/pwa-viewport-cDxGxYgG.js.map
create mode 100644 assets/temml-KWa8qPDv.js
create mode 100644 assets/temml-KWa8qPDv.js.map
diff --git a/404.html b/404.html
index 0fcb4e9..313e879 100644
--- a/404.html
+++ b/404.html
@@ -7,7 +7,7 @@
content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
Page not found
-
+
+
+
+
+
+
+
+
+
+
+
+ `,this.domRefFrame=e.querySelector("#frame"),this.domRefImg={fallback:e.querySelector("#fallbackPlaceholder"),webp:e.querySelector("#webpPlaceholder"),jpeg:e.querySelector("#jpegPlaceholder")},this.domRefPlayButton=e.querySelector("#playButton")}setupComponent(){this.shadowRoot.querySelector("slot[name=image]").assignedNodes().length===0&&this.initImagePlaceholder(),this.domRefPlayButton.setAttribute("aria-label",`${this.videoPlay}: ${this.videoTitle}`),this.setAttribute("title",`${this.videoPlay}: ${this.videoTitle}`),(this.autoLoad||this.isYouTubeShort()||this.autoPause)&&this.initIntersectionObserver(),this.disableNoscript||this.injectSearchNoScript()}attributeChangedCallback(e,n,i){n!==i&&(this.setupComponent(),this.domRefFrame.classList.contains("activated")&&(this.domRefFrame.classList.remove("activated"),this.shadowRoot.querySelector("iframe").remove(),this.isIframeLoaded=!1))}injectSearchNoScript(){const e=document.createElement("noscript");this.prepend(e),e.innerHTML=this.generateIframe()}generateIframe(e=!1){let n=e?0:1,i=this.autoPause?"&enablejsapi=1":"";const r=this.noCookie?"-nocookie":"";let a;return this.playlistId?a=`?listType=playlist&list=${this.playlistId}&`:a=`${this.videoId}?`,this.isYouTubeShort()&&(this.params=`loop=1&mute=1&modestbranding=1&playsinline=1&rel=0&enablejsapi=1&playlist=${this.videoId}`,n=1),`
+`}addIframe(e=!1){if(!this.isIframeLoaded){const n=this.generateIframe(e);this.domRefFrame.insertAdjacentHTML("beforeend",n),this.domRefFrame.classList.add("activated"),this.isIframeLoaded=!0,this.attemptShortAutoPlay(),this.dispatchEvent(new CustomEvent("liteYoutubeIframeLoaded",{detail:{videoId:this.videoId},bubbles:!0,cancelable:!0}))}}initImagePlaceholder(){this.testPosterImage(),this.domRefImg.fallback.setAttribute("aria-label",`${this.videoPlay}: ${this.videoTitle}`),this.domRefImg?.fallback?.setAttribute("alt",`${this.videoPlay}: ${this.videoTitle}`)}async testPosterImage(){setTimeout(()=>{const e=`https://i.ytimg.com/vi_webp/${this.videoId}/${this.posterQuality}.webp`,n=new Image;n.fetchPriority="low",n.referrerPolicy="origin",n.src=e,n.onload=async i=>{const r=i.target;r?.naturalHeight==90&&r?.naturalWidth==120&&(this.posterQuality="hqdefault");const s=`https://i.ytimg.com/vi_webp/${this.videoId}/${this.posterQuality}.webp`;this.domRefImg.webp.srcset=s;const c=`https://i.ytimg.com/vi/${this.videoId}/${this.posterQuality}.jpg`;this.domRefImg.fallback.loading=this.posterLoading,this.domRefImg.jpeg.srcset=c,this.domRefImg.fallback.src=c,this.domRefImg.fallback.loading=this.posterLoading}},100)}initIntersectionObserver(){const e={root:null,rootMargin:"0px",threshold:0};new IntersectionObserver((i,r)=>{i.forEach(a=>{a.isIntersecting&&!this.isIframeLoaded&&(Ut.warmConnections(this),this.addIframe(!0),r.unobserve(this))})},e).observe(this),this.autoPause&&new IntersectionObserver((r,a)=>{r.forEach(s=>{s.intersectionRatio!==1&&this.shadowRoot.querySelector("iframe")?.contentWindow?.postMessage('{"event":"command","func":"pauseVideo","args":""}',"*")})},{threshold:1}).observe(this)}attemptShortAutoPlay(){this.isYouTubeShort()&&setTimeout(()=>{this.shadowRoot.querySelector("iframe")?.contentWindow?.postMessage('{"event":"command","func":"playVideo","args":""}',"*")},2e3)}isYouTubeShort(){return this.getAttribute("short")===""&&window.matchMedia("(max-width: 40em)").matches}static addPrefetch(e,n){const i=document.createElement("link");i.rel=e,i.href=n,i.crossOrigin="true",document.head.append(i)}static warmConnections(e){Ut.isPreconnected||window.liteYouTubeIsPreconnected||(Ut.addPrefetch("preconnect","https://i.ytimg.com/"),Ut.addPrefetch("preconnect","https://s.ytimg.com"),e.noCookie?Ut.addPrefetch("preconnect","https://www.youtube-nocookie.com"):(Ut.addPrefetch("preconnect","https://www.youtube.com"),Ut.addPrefetch("preconnect","https://www.google.com"),Ut.addPrefetch("preconnect","https://googleads.g.doubleclick.net"),Ut.addPrefetch("preconnect","https://static.doubleclick.net")),Ut.isPreconnected=!0,window.liteYouTubeIsPreconnected=!0)}}Ut.isPreconnected=!1;customElements.define("lite-youtube",Ut);function Eg({authors:t,hidden:e,children:n}){if(e||!t?.[0]?.account?.id)return n;const i=t[0].account;return o("div",{class:"card-byline",children:[n,o("div",{class:"card-byline-author",children:[o(x,{icon:"link",size:"s"})," ",o("small",{children:o(I,{id:"4LHHK6",components:{0:o(Ce,{account:i,showAvatar:!0})}})})]})]})}function Qr(t){return["x.com","twitter.com","threads.net","bsky.app","bsky.brid.gy","fed.brid.gy"].includes(t)}function Cg({card:t,selfReferential:e,selfAuthor:n,instance:i}){const r=sn(B),{blurhash:a,title:s,description:c,html:l,providerName:d,providerUrl:h,authorName:u,authorUrl:f,width:p,height:m,image:g,imageDescription:v,url:T,type:_,embedUrl:k,language:S,publishedAt:b,authors:A}=t,C=s||d||u,L=p/m>=1.2?"large":"",[F,M]=z(null);if(W(()=>{C&&g&&!e&&oc(T)&&ic(i,T).then(R=>{if(!R)return;const{id:Q,url:et}=R;M("#"+et)})},[C,g,e]),r.unfurledLinks[T])return null;const E=/
\\n\\n')\n .replace(LIST_ITEM_END_RE, '\\n');\n\n const content = template.content;\n const brElements = content.querySelectorAll('br');\n for (let i = 0; i < brElements.length; i++) {\n brElements[i].replaceWith('\\n');\n }\n\n preProcess?.(content);\n\n if (truncateLinks) {\n // MASTODON-SPECIFIC classes\n // Remove .invisible\n const invisibleElements = content.querySelectorAll('.invisible');\n for (let i = 0; i < invisibleElements.length; i++) {\n invisibleElements[i].remove();\n }\n // Add … at end of .ellipsis\n const ellipsisElements = content.querySelectorAll('.ellipsis');\n for (let i = 0; i < ellipsisElements.length; i++) {\n ellipsisElements[i].append('…');\n }\n }\n\n // Collect innerText from all child nodes since DocumentFragment doesn't have innerText\n let textContent = '';\n for (let i = 0; i < content.childNodes.length; i++) {\n const n = content.childNodes[i];\n textContent += n.innerText || n.textContent || '';\n }\n\n return textContent.replace(MULTIPLE_LINE_BREAKS_RE, '\\n\\n').trim();\n}\n\nexport default mem(getHTMLText);\n","import getHTMLText from './getHTMLText';\n\nfunction statusPeek(status) {\n const { spoilerText, content, poll, mediaAttachments } = status;\n let text = '';\n if (spoilerText?.trim()) {\n text += spoilerText;\n } else {\n text += getHTMLText(content);\n }\n text = text.trim();\n if (poll?.options?.length) {\n text += `\\n\\n📊:\\n${poll.options\n .map((o) => `${poll.multiple ? '▪️' : '•'} ${o.title}`)\n .join('\\n')}`;\n }\n if (mediaAttachments?.length) {\n text +=\n ' ' +\n mediaAttachments\n .map(\n (m) =>\n ({\n image: '🖼️',\n gifv: '🎞️',\n video: '📹',\n audio: '🎵',\n unknown: '',\n })[m.type] || '',\n )\n .join('');\n }\n return text;\n}\n\nexport default statusPeek;\n","import { memo } from 'preact/compat';\nimport { useEffect } from 'preact/hooks';\n\nimport { ICONS } from './ICONS';\nimport { ICON_NAMESPACE, useIconSprite } from './icon-sprite-manager';\n\nconst SIZES = {\n xs: 8,\n s: 12,\n m: 16,\n l: 20,\n xl: 24,\n xxl: 32,\n};\n\nconst INVALID_ID_CHARS_REGEX = /[^a-zA-Z0-9]/g;\n\nfunction Icon({\n icon,\n size = 'm',\n alt,\n title,\n class: className = '',\n style = {},\n}) {\n title = title || alt;\n const { loadIcon, isIconLoaded } = useIconSprite();\n\n if (!icon) return null;\n\n const iconSize = SIZES[size];\n let iconBlock = ICONS[icon];\n if (!iconBlock) {\n console.warn(`Icon ${icon} not found`);\n return null;\n }\n\n let rotate,\n flip,\n rtl = false;\n if (Array.isArray(iconBlock)) {\n [iconBlock, rotate, flip] = iconBlock;\n } else if (typeof iconBlock === 'object') {\n ({ rotate, flip, rtl } = iconBlock);\n iconBlock = iconBlock.module;\n }\n\n const sanitizedTitle = title?.replace(INVALID_ID_CHARS_REGEX, '-');\n const titleID = `${ICON_NAMESPACE}-title-${icon}-${sanitizedTitle}`;\n\n useEffect(() => {\n if (!isIconLoaded(icon)) {\n loadIcon(icon);\n }\n }, [icon]);\n\n const loaded = isIconLoaded(icon);\n\n return (\n \n {loaded && (\n \n )}\n \n );\n}\n\nexport default memo(Icon, (prevProps, nextProps) => {\n return (\n prevProps.icon === nextProps.icon &&\n prevProps.title === nextProps.title &&\n prevProps.alt === nextProps.alt\n );\n});\n","import { forwardRef } from 'preact/compat';\nimport { useLocation } from 'react-router-dom';\n\nimport states from '../utils/states';\n\n/* NOTES\n =====\n Initially this uses from react-router-dom, but it doesn't work:\n 1. It interferes with nested inside and it's difficult to preventDefault/stopPropagation from the nested \n 2. isActive doesn't work properly with the weird routes that's set up in this app, due to the faux \"location\" to make the modals work and prevent unmounting\n 3. Not using because it modifies history.state that *persists* across page reloads. I don't need that, so using valtio's states instead.\n*/\n\nconst Link = forwardRef((props, ref) => {\n let routerLocation;\n try {\n routerLocation = useLocation();\n } catch (e) {}\n let hash = (location.hash || '').replace(/^#/, '').trim();\n if (hash === '') hash = '/';\n const { to, ...restProps } = props;\n\n // Handle encodeURIComponent of searchParams values\n if (!!hash && hash !== '/' && hash.includes('?')) {\n const parsedHash = URL.parse(hash, location.origin); // Fake base URL\n if (parsedHash?.searchParams?.size) {\n const searchParamsStr = Array.from(parsedHash.searchParams.entries())\n .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n .join('&');\n hash = parsedHash.pathname + '?' + searchParamsStr;\n }\n }\n\n const isActive = hash === to || decodeURIComponent(hash) === to;\n return (\n {\n if (e.currentTarget?.parentNode?.closest('a')) {\n // If this is nested inside another \n e.stopPropagation();\n }\n if (routerLocation) states.prevLocation = routerLocation;\n props.onClick?.(e);\n }}\n />\n );\n});\n\nexport default Link;\n","import { FocusableItem } from '@szhsin/react-menu';\n\nimport Link from './link';\n\nfunction MenuLink(props) {\n const { className, disabled, ...restProps } = props;\n return (\n \n {({ ref, closeMenu }) => (\n \n closeMenu(detail === 0 ? 'Enter' : undefined)\n }\n />\n )}\n \n );\n}\n\nexport default MenuLink;\n","import mem from './mem.js';\n\nexport default mem(\n (locale) => new Intl.RelativeTimeFormat(locale || undefined),\n);\n","import { i18n } from '@lingui/core';\nimport { t } from '@lingui/core/macro';\nimport { useEffect, useMemo, useReducer } from 'preact/hooks';\n\nimport DateTimeFormat from '../utils/date-time-format';\nimport RTF from '../utils/relative-time-format';\n\nfunction isValidDate(value) {\n if (value instanceof Date) {\n return !isNaN(value.getTime());\n } else {\n const date = new Date(value);\n return !isNaN(date.getTime());\n }\n}\n\nconst minute = 60;\nconst hour = 60 * minute;\nconst day = 24 * hour;\n\nconst rtfFromNow = (date) => {\n // date = Date object\n const rtf = RTF(i18n.locale);\n const seconds = (date.getTime() - Date.now()) / 1000;\n const absSeconds = Math.abs(seconds);\n if (absSeconds < minute) {\n return rtf.format(Math.floor(seconds), 'second');\n } else if (absSeconds < hour) {\n return rtf.format(Math.floor(seconds / minute), 'minute');\n } else if (absSeconds < day) {\n return rtf.format(Math.floor(seconds / hour), 'hour');\n } else if (absSeconds < 30 * day) {\n return rtf.format(Math.floor(seconds / day), 'day');\n } else if (absSeconds < 365 * day) {\n return rtf.format(Math.floor(seconds / day / 30), 'month');\n } else {\n return rtf.format(Math.floor(seconds / day / 365), 'year');\n }\n};\n\nconst twitterFromNow = (date) => {\n // date = Date object\n const seconds = (Date.now() - date.getTime()) / 1000;\n if (seconds < minute) {\n return t({\n comment: 'Relative time in seconds, as short as possible',\n message: `${seconds < 1 ? 1 : Math.floor(seconds)}s`,\n });\n } else if (seconds < hour) {\n return t({\n comment: 'Relative time in minutes, as short as possible',\n message: `${Math.floor(seconds / minute)}m`,\n });\n } else {\n return t({\n comment: 'Relative time in hours, as short as possible',\n message: `${Math.floor(seconds / hour)}h`,\n });\n }\n};\n\nexport default function RelativeTime({ datetime, format }) {\n if (!datetime) return null;\n const [renderCount, rerender] = useReducer((x) => x + 1, 0);\n const date = useMemo(() => new Date(datetime), [datetime]);\n const [dateStr, dt, title] = useMemo(() => {\n if (!isValidDate(date))\n return ['' + (typeof datetime === 'string' ? datetime : ''), '', ''];\n let str;\n if (format === 'micro') {\n // If date <= 1 day ago or day is within this year\n const now = new Date();\n const dayDiff = (now.getTime() - date.getTime()) / 1000 / day;\n if (dayDiff <= 1) {\n str = twitterFromNow(date);\n } else {\n const sameYear = now.getFullYear() === date.getFullYear();\n if (sameYear) {\n str = DateTimeFormat(i18n.locale, {\n year: undefined,\n month: 'short',\n day: 'numeric',\n }).format(date);\n } else {\n str = DateTimeFormat(i18n.locale, {\n dateStyle: 'short',\n }).format(date);\n }\n }\n }\n if (!str) str = rtfFromNow(date);\n return [str, date.toISOString(), date.toLocaleString()];\n }, [date, format, renderCount]);\n\n useEffect(() => {\n if (!isValidDate(date)) return;\n let timeout;\n let raf;\n function rafRerender() {\n raf = requestAnimationFrame(() => {\n rerender();\n scheduleRerender();\n });\n }\n function scheduleRerender() {\n // If less than 1 minute, rerender every 10s\n // If less than 1 hour rerender every 1m\n // Else, don't need to rerender\n const seconds = (Date.now() - date.getTime()) / 1000;\n if (seconds < minute) {\n timeout = setTimeout(rafRerender, 10_000);\n } else if (seconds < hour) {\n timeout = setTimeout(rafRerender, 60_000);\n }\n }\n scheduleRerender();\n return () => {\n clearTimeout(timeout);\n cancelAnimationFrame(raf);\n };\n }, []);\n\n return (\n \n );\n}\n","import { SubMenu } from '@szhsin/react-menu';\nimport { useRef } from 'preact/hooks';\n\nexport default function SubMenu2(props) {\n const menuRef = useRef();\n return (\n {\n if (e.pointerType === 'touch') {\n menuRef.current?.openMenu?.();\n }\n },\n onPointerLeave: (e) => {\n if (e.pointerType === 'touch') {\n menuRef.current?.openMenu?.();\n }\n },\n ...props.itemProps,\n }}\n />\n );\n}\n","import { useEffect } from 'preact/hooks';\n\n// NOTE: The order of initialized close watchers is important\n// Last one will intercept first if there are multiple/nested close watchers\n// So if this hook reruns, the previous close watcher will be destroyed, the new one will be created and the order will change\nfunction useCloseWatcher(fn, deps = []) {\n if (!fn || typeof fn !== 'function') return;\n useEffect(() => {\n console.log('useCloseWatcher');\n const watcher = new CloseWatcher();\n watcher.addEventListener('close', fn);\n return () => {\n watcher.destroy();\n };\n }, deps);\n}\n\nexport default window.CloseWatcher ? useCloseWatcher : () => {};\n","import './modal.css';\n\nimport { createPortal } from 'preact/compat';\nimport { useEffect, useLayoutEffect, useRef } from 'preact/hooks';\nimport { useHotkeys } from 'react-hotkeys-hook';\n\nimport store from '../utils/store';\nimport useCloseWatcher from '../utils/useCloseWatcher';\n\nconst $modalContainer = document.getElementById('modal-container');\n\nfunction getBackdropThemeColor() {\n return getComputedStyle(document.documentElement).getPropertyValue(\n '--backdrop-theme-color',\n );\n}\n\nfunction Modal({ children, onClose, onClick, class: className, minimized }) {\n if (!children) return null;\n\n const modalRef = useRef();\n useEffect(() => {\n let timer = setTimeout(() => {\n const focusElement = modalRef.current?.querySelector('[tabindex=\"-1\"]');\n if (focusElement) {\n focusElement.focus();\n }\n }, 100);\n return () => clearTimeout(timer);\n }, []);\n\n const supportsCloseWatcher = window.CloseWatcher;\n const escRef = useHotkeys(\n 'esc',\n () => {\n setTimeout(() => {\n onClose?.();\n }, 0);\n },\n {\n enabled: !supportsCloseWatcher && !!onClose,\n // Using keyup and setTimeout above\n // This will run \"later\" to prevent clash with esc handlers from other components\n keydown: false,\n keyup: true,\n useKey: true,\n ignoreEventWhen: (e) => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey,\n },\n [onClose],\n );\n useCloseWatcher(onClose, [onClose]);\n\n useEffect(() => {\n const $deckContainers = document.querySelectorAll('.deck-container');\n if (minimized) {\n // Similar to focusDeck in focus-deck.jsx\n // Focus last deck\n const page = $deckContainers[$deckContainers.length - 1]; // last one\n if (page && page.tabIndex === -1) {\n page.focus();\n }\n } else {\n if (children) {\n $deckContainers.forEach(($deckContainer) => {\n $deckContainer.setAttribute('inert', '');\n });\n } else {\n $deckContainers.forEach(($deckContainer) => {\n $deckContainer.removeAttribute('inert');\n });\n }\n }\n return () => {\n $deckContainers.forEach(($deckContainer) => {\n $deckContainer.removeAttribute('inert');\n });\n };\n }, [children, minimized]);\n\n const $meta = useRef();\n const metaColor = useRef();\n useLayoutEffect(() => {\n if (children && !minimized) {\n const theme = store.local.get('theme');\n if (theme) {\n const backdropColor = getBackdropThemeColor();\n console.log({ backdropColor });\n $meta.current = document.querySelector(\n `meta[name=\"theme-color\"][data-theme-setting=\"manual\"]`,\n );\n if ($meta.current) {\n metaColor.current = $meta.current.content;\n $meta.current.content = backdropColor;\n }\n } else {\n const colorScheme = window.matchMedia('(prefers-color-scheme: dark)')\n .matches\n ? 'dark'\n : 'light';\n const backdropColor = getBackdropThemeColor();\n console.log({ backdropColor });\n $meta.current = document.querySelector(\n `meta[name=\"theme-color\"][media*=\"${colorScheme}\"]`,\n );\n if ($meta.current) {\n metaColor.current = $meta.current.content;\n $meta.current.content = backdropColor;\n }\n }\n } else {\n // Reset meta color\n if ($meta.current && metaColor.current) {\n $meta.current.content = metaColor.current;\n }\n }\n return () => {\n // Reset meta color\n if ($meta.current && metaColor.current) {\n $meta.current.content = metaColor.current;\n }\n };\n }, [children, minimized]);\n\n const Modal = (\n {\n modalRef.current = node;\n escRef.current = node?.querySelector?.('[tabindex=\"-1\"]') || node;\n }}\n className={className}\n onClick={(e) => {\n onClick?.(e);\n if (e.target === e.currentTarget) {\n onClose?.(e);\n }\n }}\n tabIndex={minimized ? 0 : '-1'}\n inert={minimized}\n onFocus={(e) => {\n try {\n if (e.target === e.currentTarget) {\n const focusElement =\n modalRef.current?.querySelector('[tabindex=\"-1\"]');\n const isFocusable =\n !!focusElement &&\n getComputedStyle(focusElement)?.pointerEvents !== 'none';\n if (focusElement && isFocusable) {\n focusElement.focus();\n }\n }\n } catch (err) {\n console.error(err);\n }\n }}\n >\n {children}\n
\n );\n\n return createPortal(Modal, $modalContainer);\n\n // return createPortal(children, $modalContainer);\n}\n\nexport default Modal;\n","import './avatar.css';\n\nimport { useRef } from 'preact/hooks';\n\nimport mem from '../utils/mem';\n\nconst SIZES = {\n s: 16,\n m: 20,\n l: 24,\n xl: 32,\n xxl: 50,\n xxxl: 64,\n};\n\nconst alphaCache = {};\n\nconst canvas = window.OffscreenCanvas\n ? new OffscreenCanvas(1, 1)\n : document.createElement('canvas');\nconst ctx = canvas.getContext('2d', {\n willReadFrequently: true,\n});\nctx.imageSmoothingEnabled = false;\n\nconst MISSING_IMAGE_PATH_REGEX = /missing\\.png$/;\n\nfunction Avatar({ url, staticUrl, size, alt = '', squircle, ...props }) {\n size = SIZES[size] || size || SIZES.m;\n const avatarRef = useRef();\n const isMissing = MISSING_IMAGE_PATH_REGEX.test(url);\n return (\n \n {!!staticUrl && (\n \n )}\n {!!url && (\n
{\n if (e.target.crossOrigin) {\n e.target.crossOrigin = null;\n e.target.src = url;\n }\n }}\n onLoad={(e) => {\n if (avatarRef.current) avatarRef.current.dataset.loaded = true;\n if (alphaCache[url] !== undefined) return;\n if (isMissing) return;\n setTimeout(() => {\n try {\n // Check if image has alpha channel\n const { width, height } = e.target;\n if (canvas.width !== width) canvas.width = width;\n if (canvas.height !== height) canvas.height = height;\n ctx.drawImage(e.target, 0, 0);\n const allPixels = ctx.getImageData(0, 0, width, height);\n // At least 10% of pixels have alpha <= 128\n const hasAlpha =\n allPixels.data.filter(\n (pixel, i) => i % 4 === 3 && pixel <= 128,\n ).length /\n (allPixels.data.length / 4) >\n 0.1;\n if (hasAlpha) {\n // console.log('hasAlpha', hasAlpha, allPixels.data);\n avatarRef.current.classList.add('has-alpha');\n }\n alphaCache[url] = hasAlpha;\n ctx.clearRect(0, 0, width, height);\n } catch (e) {\n // Silent fail\n alphaCache[url] = false;\n }\n }, 1);\n }}\n />\n )}\n \n );\n}\n\nexport default mem(Avatar);\n","let IS_RTL = false;\n\n// Use MutationObserver to detect RTL\nconst observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if (mutation.type === 'attributes') {\n const { dir } = mutation.target;\n if (dir === 'rtl') {\n IS_RTL = true;\n } else {\n IS_RTL = false;\n }\n console.log({ IS_RTL });\n // Fire custom event 'dirchange' on document\n // document.dispatchEvent(new Event('dirchange'));\n }\n });\n});\nobserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['dir'],\n});\n\nexport default function isRTL() {\n return IS_RTL;\n // return document.documentElement.dir === 'rtl';\n}\n","import { useLayoutEffect, useState } from 'preact/hooks';\n\nexport default function useWindowSize() {\n const [size, setSize] = useState({\n width: null,\n height: null,\n });\n\n useLayoutEffect(() => {\n const handleResize = () => {\n setSize({\n width: window.innerWidth,\n height: window.innerHeight,\n });\n };\n\n handleResize();\n window.addEventListener('resize', handleResize, {\n passive: true,\n });\n\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, []);\n\n return size;\n}\n","import { Menu } from '@szhsin/react-menu';\nimport { useRef } from 'preact/hooks';\n\nimport isRTL from '../utils/is-rtl';\nimport safeBoundingBoxPadding from '../utils/safe-bounding-box-padding';\nimport useWindowSize from '../utils/useWindowSize';\n\n// It's like Menu but with sensible defaults, bug fixes and improvements.\nfunction Menu2(props) {\n const { containerProps, instanceRef: _instanceRef, align } = props;\n const size = useWindowSize();\n const instanceRef = _instanceRef?.current ? _instanceRef : useRef();\n\n // Values: start, end, center\n // Note: don't mess with 'center'\n const rtlAlign = isRTL()\n ? align === 'end'\n ? 'start'\n : align === 'start'\n ? 'end'\n : align\n : align;\n\n return (\n