Table About Modal: Redesign (#6523)

This commit is contained in:
Alexander Zinchuk 2025-12-22 22:53:29 +01:00
parent 6a37bfbf43
commit 6fc1974145
93 changed files with 519 additions and 353 deletions

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 32 32"><path d="M18.5 4.1c1.9 0 3.5 1.6 3.5 3.5q0 .75-.3 1.5h2c.4 0 .9.1 1.3.3.7.3 1.3.9 1.7 1.7.2.4.3.8.3 1.3V15c0 .3-.1.6-.2.9-.2.5-.6.8-1 1.1v7.7c0 .5-.1.9-.3 1.4-.3.7-.9 1.2-1.5 1.5-.4.2-.9.3-1.4.3H9.7c-.5 0-.9-.1-1.4-.3-.8-.4-1.3-.9-1.7-1.6-.2-.4-.3-.9-.3-1.4v-7.7c-.4-.3-.8-.6-1-1.1-.2-.2-.3-.5-.3-.8v-2.6c0-.4.1-.9.3-1.3.4-.8 1-1.4 1.7-1.7.4-.2.8-.3 1.3-.3h2q-.3-.75-.3-1.5c0-1.9 1.6-3.5 3.5-3.5 1 0 1.9.4 2.5 1.1.6-.7 1.5-1.1 2.5-1.1m5.2 13.2H17v8.6h5.4c.4 0 .5-.1.6-.1.3-.1.5-.4.7-.7.1-.1.1-.3.1-.6v-1.6zM8.2 22.9v1.5c0 .4.1.5.1.6.1.3.4.5.7.7.1.1.3.1.6.1H15v-8.6H8.2zm8.8-7.6h7.7c.1 0 .2-.1.2-.2v-2.5c0-.3-.1-.5-.1-.6-.1-.3-.4-.6-.7-.7-.1 0-.3-.1-.6-.1H17zm-7.1-4.2H8.4c-.3 0-.5.1-.6.1-.3.1-.6.4-.7.7 0 .1-.1.3-.1.6V15c0 .1.1.2.2.2H15V11H9.9zm3.6-5c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5H15V7.6c0-.9-.7-1.5-1.5-1.5m5 0c-.8 0-1.5.7-1.5 1.5v1.5h1.5c.8 0 1.5-.7 1.5-1.5 0-.9-.7-1.5-1.5-1.5"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M19.4 0C21.9 0 24 2.1 24 4.7c0 .7-.2 1.4-.5 2h2.8c.6 0 1.2.1 1.7.4 1 .5 1.8 1.3 2.2 2.2.3.5.4 1.1.4 1.7v3.5q0 .6-.3 1.2c-.3.6-.8 1.1-1.4 1.5v10.3c-.1.6-.2 1.3-.5 1.8-.4.9-1.2 1.6-2 2-.6.3-1.2.4-1.8.5s-1.4 0-2.3 0h-15c-.6-.1-1.3-.2-1.8-.5-.9-.4-1.6-1.2-2-2-.4-.4-.5-1-.5-1.7V17.3c-.6-.3-1.1-.9-1.4-1.5q-.3-.6-.3-1.2v-3.5c0-.6.1-1.2.4-1.7.5-1 1.3-1.8 2.2-2.2.5-.3 1.1-.4 1.7-.4h2.8C8.1 6.1 8 5.4 8 4.7 8 2.1 10.1 0 12.6 0 14 0 15.1.5 16 1.4 16.9.5 18 0 19.4 0m6.9 17.8h-8.9v11.6h7.1c.5 0 .7-.1.8-.2q.6-.3.9-.9c.1-.1.1-.4.2-.8v-9.6zM5.6 25.3v2.1c0 .5.1.7.2.8q.3.6.9.9c.1.1.4.1.8.2h7.1V17.8h-9zm11.7-10.2h10.2c.1-.1.3-.2.3-.3v-3.3c0-.4-.1-.7-.2-.8-.2-.4-.5-.8-1-1-.1-.1-.3-.1-.8-.2H17v5.6zM7.8 9.4h-2c-.4 0-.7.1-.8.2-.4.2-.8.5-1 1 .1.1 0 .3 0 .7v3.3c.1.1.2.3.3.3h10.2V9.4zm4.8-6.7c-1.1 0-2 .9-2 2s.9 2 2 2h2v-2c.1-1.1-.8-2-2-2m6.8 0c-1.1 0-2 .9-2 2v2h2c1.1 0 2-.9 2-2s-.9-2-2-2"/></svg>

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 951 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="M19.58 16C23.868 14.353 27 10.153 27 5.294A3.306 3.306 0 0 0 23.703 2H7.297A3.305 3.305 0 0 0 4 5.294C4 10.153 7.05 14.353 11.42 16 7.132 17.647 4 21.847 4 26.706A3.306 3.306 0 0 0 7.297 30h16.406A3.306 3.306 0 0 0 27 26.706c0-4.859-3.133-9.059-7.42-10.706M5.65 5.294c0-.906.742-1.647 1.648-1.647h16.406c.906 0 1.648.741 1.648 1.647 0 5.435-4.451 9.8-9.81 9.8-5.358 0-9.892-4.365-9.892-9.8m18.054 23.059H7.297a1.653 1.653 0 0 1-1.648-1.647c0-5.435 4.451-9.8 9.81-9.8 5.358 0 9.892 4.365 9.892 9.8 0 .906-.742 1.647-1.648 1.647"/><path fill="#000" d="m9.688 24.235.824 1.4 4.947-3.13 5.029 3.13.824-1.4-5.853-3.623zM19.498 9l.99.741.989-1.317-.99-.742c-1.154-.906-2.802-.906-4.039 0-.577.494-1.401.494-2.06 0a3.47 3.47 0 0 0-4.123 0l-.824.742.99 1.317.906-.741a1.62 1.62 0 0 1 2.06 0c1.155.906 2.886.906 4.04 0 .66-.412 1.484-.412 2.061 0"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M21.525 15.999c4.1-2.084 6.721-6.484 6.721-11.361 0-2.42-1.846-4.388-4.115-4.388H7.865C5.595.25 3.75 2.219 3.75 4.638c0 4.88 2.623 9.28 6.725 11.363-4.1 2.084-6.72 6.484-6.72 11.362 0 2.42 1.845 4.387 4.114 4.387h16.267c2.268 0 4.114-1.968 4.114-4.387 0-4.88-2.623-9.282-6.725-11.364m-6.004 1.22h.962c5.213 0 9.453 4.547 9.453 10.137 0 1.073-.807 1.946-1.8 1.946H7.869c-.993 0-1.8-.873-1.8-1.946 0-5.59 4.24-10.137 9.452-10.137m.958-2.445h-.963c-5.212 0-9.453-4.547-9.453-10.136 0-1.074.809-1.947 1.802-1.947h16.266c.993 0 1.801.873 1.801 1.947 0 5.59-4.24 10.136-9.453 10.136" class="st0"/><path d="M8.044 27.952q.12.027.24.026c.219 0 .435-.066.623-.195l6.868-4.668a.39.39 0 0 1 .446 0l6.866 4.667c.516.358 1.275.182 1.607-.377.335-.562.177-1.313-.352-1.674l-6.868-4.669a2.62 2.62 0 0 0-2.954.001l-6.867 4.668c-.53.36-.687 1.112-.352 1.674.168.284.432.479.743.547M23.19 6.253c-1.675-1.57-3.924-1.57-5.598 0l-.326.305c-.802.75-1.722.751-2.528-.001l-.324-.303c-1.674-1.57-3.925-1.57-5.6 0l-.862.807a1.27 1.27 0 0 0-.108 1.71c.204.25.488.4.801.421.313.011.61-.088.842-.304l.863-.809c.803-.752 1.725-.752 2.528 0l.325.305c.818.766 1.787 1.172 2.8 1.172s1.98-.405 2.797-1.17l.328-.308c.802-.75 1.721-.754 2.525 0l.854.799c.231.219.528.333.838.306.313-.019.6-.17.806-.421a1.273 1.273 0 0 0-.108-1.71z"/></svg>

Before

Width:  |  Height:  |  Size: 942 B

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M17.75 4.875a2.833 2.833 0 0 1 3.933 2.612v7.304l.354-.713a2.637 2.637 0 0 1 3.542-1.179 2.714 2.714 0 0 1 1.267 3.533L23.7 23.507a8.962 8.962 0 0 1-8.183 5.321h-.742c-5.442-.004-9.858-4.421-9.858-9.867v-8.512A2.833 2.833 0 0 1 7.75 7.616c.3 0 .592.046.867.133v-.263a2.833 2.833 0 0 1 3.933-2.612 2.843 2.843 0 0 1 2.6-1.704 2.847 2.847 0 0 1 2.6 1.704zm.238 2.612v7.771c0 .542-.442.983-.983.983s-.983-.442-.983-.983v-9.25a.866.866 0 1 0-1.734 0v9.25c0 .542-.442.983-.983.983s-.983-.442-.983-.983V7.487a.866.866 0 1 0-1.734 0v8.512c0 .542-.442.983-.983.983s-.983-.442-.983-.983v-5.55a.866.866 0 1 0-1.734 0v8.512a7.896 7.896 0 0 0 7.896 7.896h.742a6.991 6.991 0 0 0 6.388-4.15l3.146-7.075a.745.745 0 0 0-.35-.971.668.668 0 0 0-.9.3l-2.225 4.438c-.462.929-1.867.6-1.867-.442V7.486a.866.866 0 1 0-1.73 0z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M29.414 12.344c-1.333-.661-3.035-.23-3.894 1.01l-1.098 2.142-.002-9.994a3.24 3.24 0 0 0-.847-2.357c-.61-.67-1.477-1.061-2.452-1.104-.529 0-1.044.125-1.51.363a3.307 3.307 0 0 0-6.212.046 3.3 3.3 0 0 0-1.494-.357A3.31 3.31 0 0 0 8.6 5.396v.656a3.308 3.308 0 0 0-4.61 3.035V19.69c0 6.65 5.41 12.06 12.06 12.06h.925c4.314 0 8.236-2.548 9.99-6.49l3.917-8.812a3.143 3.143 0 0 0-1.47-4.104M9.6 17.45c.8 0 1.451-.651 1.451-1.451V5.396a.854.854 0 0 1 1.707 0v9.681c0 .8.652 1.451 1.451 1.451s1.452-.651 1.452-1.45V3.553a.854.854 0 0 1 1.707 0v11.523c0 .8.65 1.451 1.45 1.451s1.451-.651 1.451-1.45c0-.097-.002-9.543.001-9.784.02-.443.383-.803.796-.804.281.013.528.12.695.304.152.166.222.38.21.65l.001 14.241c0 .42.16.791.468 1.079.268.239.634.377 1.002.377.556 0 1.036-.3 1.282-.801l2.809-5.592a.62.62 0 0 1 .788-.211.7.7 0 0 1 .324.915l-3.919 8.813a8.49 8.49 0 0 1-7.75 5.035h-.925c-5.299 0-9.61-4.31-9.61-9.61V9.087a.855.855 0 0 1 1.709 0V16c0 .8.65 1.451 1.45 1.451"/></svg>

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="m23.327 8.372.006.295v2.193c.403.087.741.211 1.088.388a5.331 5.331 0 0 1 2.394 2.458l.112.249c.137.331.229.665.29 1.1l.04.347.03.394.021.451.014.516.008.591.004 4.246-.004 1.046-.008.591-.014.516-.021.451-.03.394-.04.347c-.069.49-.176.852-.344 1.224l-.121.251a5.337 5.337 0 0 1-2.458 2.394l-.249.112a4.32 4.32 0 0 1-1.1.29l-.347.04-.394.03-.451.021-.516.014-9.883.008-.591-.008-.516-.014-.451-.021-.394-.03-.347-.04a4.248 4.248 0 0 1-1.224-.344l-.251-.121a5.331 5.331 0 0 1-2.331-2.331c-.338-.663-.485-1.296-.544-2.405l-.023-.597a31.653 31.653 0 0 1-.007-.333l-.007-.742v-4.695l.002-.384.011-.689.023-.596c.06-1.108.206-1.74.544-2.403a5.331 5.331 0 0 1 2.331-2.331 4.312 4.312 0 0 1 1.088-.388V8.664a7.333 7.333 0 0 1 14.66-.295zm-2.66 2.297V8.667a4.667 4.667 0 0 0-9.327-.256l-.007.256v2.004l.321-.003h8.695l.317.002zm-.014 2.667h-9.302l-.789.014-.425.018-.355.025-.295.034-.245.043c-.185.04-.328.091-.453.154-.502.256-.91.664-1.165 1.165a1.799 1.799 0 0 0-.154.453l-.043.244-.034.295-.014.169-.021.388-.014.462-.008.546v5.303l.014.789.018.425.025.355.034.295.043.245c.04.185.091.328.154.453.256.502.664.91 1.165 1.165l.128.059.141.051.161.043.188.036.222.029.413.033.339.016.398.011 1.002.011 8.974-.004.863-.019.339-.016.413-.033.222-.029.188-.036c.029-.007.057-.013.083-.021l.15-.047.068-.026.128-.059a2.66 2.66 0 0 0 1.195-1.228l.055-.133c.008-.023.017-.047.024-.072l.043-.161.036-.188.029-.222.033-.413.016-.339.011-.398.011-1.002.001-3.818-.005-1.156-.019-.863-.016-.339-.033-.413-.029-.222-.036-.188c-.007-.029-.013-.057-.021-.083l-.047-.15a1.368 1.368 0 0 0-.026-.068l-.059-.128a2.666 2.666 0 0 0-1.165-1.165l-.077-.037a1.91 1.91 0 0 0-.375-.118l-.244-.043-.295-.034-.169-.014-.388-.021-.462-.014-.546-.008z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M24.151 10.992V8.345C24.151 3.85 20.495.193 16 .193S7.849 3.85 7.849 8.345v2.647c-2.59.355-4.599 2.559-4.599 5.244v10.252a5.324 5.324 0 0 0 5.317 5.319h14.866a5.324 5.324 0 0 0 5.317-5.319V16.236c0-2.685-2.009-4.89-4.599-5.244M16 2.693a5.66 5.66 0 0 1 5.651 5.652v2.574H10.35V8.345A5.66 5.66 0 0 1 16 2.693m10.25 23.795a2.82 2.82 0 0 1-2.817 2.819H8.567a2.82 2.82 0 0 1-2.817-2.819V16.236a2.82 2.82 0 0 1 2.817-2.817h14.866a2.82 2.82 0 0 1 2.817 2.817z"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 530 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" x="0" y="0" version="1.1" viewBox="0 0 32 32"><path d="M12.5 27.1c-.5-.3-.6-.9-.2-1.4l2.7-3.9c.3-.5.9-.6 1.4-.2.5.3.6.9.2 1.4l-1.4 2c3.4.2 6.8-1.2 8.9-4.2 3.2-4.5 2.1-10.7-2.4-13.9C17.2 3.6 11 4.7 7.8 9.2s-2.1 10.7 2.4 13.9c.5.3.6.9.2 1.4-.3.5-.9.6-1.4.2-5.3-3.8-6.6-11.2-2.8-16.6s11.2-6.7 16.7-3c5.4 3.8 6.7 11.2 2.9 16.6-2.4 3.4-6.2 5.2-10.1 5.1l1.9 1.3c.5.3.6.9.2 1.4-.3.5-.9.6-1.4.2z" class="st3"/><path d="M19.1 21.5c-.5 0-.9-.1-1.3-.4l-1.8-1-1.7 1c-1.2.7-2.7.3-3.5-.8-.4-.6-.5-1.3-.3-2l.4-1.4c0-.1.1-.2.1-.4-.2-.1-.4-.2-.6-.4l-.9-.8c-.5-.4-.9-1.1-.9-1.7-.1-.7.2-1.4.6-1.9s1.1-.8 1.7-.9l2-.2.9-2c.6-1 1.8-1.5 2.9-1.2l.4.2c.5.2.9.6 1.1 1l.1.2.8 1.8 2 .2q1.05.15 1.8.9c.4.5.6 1.2.6 1.8-.1.7-.4 1.3-.9 1.7l-1.5 1.2.5 1.8c.2.7.1 1.3-.3 1.9s-.9 1-1.6 1.2c-.3.2-.5.2-.6.2M16 17.8l2.8 1.6c.1.1.3.1.4.1s.3-.1.3-.2c.1-.1.1-.2.1-.4l-.8-3 2.5-2c.1-.1.2-.2.2-.4 0-.1 0-.3-.1-.4s-.2-.2-.4-.2l-3.3-.2-1.3-3-.2-.2-.1-.1c-.2 0-.4 0-.6.2l-.1.1-1.2 2.8-3.2.3c-.1 0-.3.1-.4.2s-.1.3-.1.4.1.3.2.4l.9.8c.3.2.6.4 1 .4l4.1-.5-3.5 2.2c-.2.2-.3.5-.4.7l-.4 1.4c0 .1 0 .3.1.4.2.2.5.3.8.2z" class="st3"/><path d="m12.6 15 4.2-.7c.1 0 .2.1.1.2l-3.7 2.1"/></svg> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 32 32"><path d="M11.9 28.5c-.5-.4-.7-1.1-.3-1.6l3.3-4.6c.4-.5 1.1-.7 1.6-.3s.7 1.1.3 1.6l-1.6 2.3c4 .3 8-1.5 10.5-5 3.7-5.3 2.4-12.7-2.9-16.4C17.4.8 10.1 2.1 6.3 7.4c-3.7 5.3-2.4 12.7 2.9 16.4.5.4.7 1.1.3 1.6s-1.1.7-1.6.3C1.5 21.3-.1 12.4 4.4 6s13.3-8 19.7-3.5 8 13.3 3.5 19.7c-2.8 4-7.4 6.1-11.9 6l2.2 1.5c.5.4.7 1.1.3 1.6s-1.1.7-1.6.3z"/><path d="M19.6 21.9c-.5 0-1.1-.1-1.5-.4L16 20.2l-2.1 1.2c-1.4.8-3.2.4-4.1-1-.4-.7-.6-1.6-.4-2.4l.5-1.7c0-.1.1-.3.1-.4-.2-.1-.5-.3-.7-.5l-1.1-.9c-.6-.5-1-1.3-1.1-2.1s.2-1.6.7-2.2 1.3-1 2-1l2.4-.2 1-2.4c.7-1.2 2.1-1.8 3.5-1.4l.5.2c.6.3 1 .7 1.3 1.2l.2.4.9 2.2 2.4.2c.8.1 1.6.4 2.1 1.1.5.6.8 1.4.7 2.2s-.5 1.6-1.1 2.1L22 16.1l.5 2.1c.2.8.1 1.6-.3 2.3s-1.1 1.2-1.9 1.4zM16 17.5l3.3 1.9c.1.1.3.1.5.1s.3-.1.4-.3c.1-.1.1-.3.1-.5l-.9-3.6 2.9-2.4c.1-.1.2-.3.2-.4 0-.2 0-.3-.1-.4s-.3-.2-.5-.2l-3.9-.3-1.5-3.5c0-.1-.1-.1-.2-.2l-.2-.1c-.2-.1-.5 0-.7.3V8l-1.5 3.4-3.8.3c-.2 0-.3.1-.4.2-.1.2-.2.3-.1.4 0 .2.1.3.2.4l1.1.9c.3.3.7.4 1.2.5l4.8-.6-4.2 2.6c-.2.2-.4.6-.5.9l-.5 1.7c0 .2 0 .3.1.5.2.3.6.4.9.2z"/><path d="m12 14.2 5-.8c.1 0 .2.2.1.2l-4.4 2.5"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M13.867 3.198c0-.561.631-.89 1.091-.568l3.431 2.402a.694.694 0 0 1 0 1.136L14.958 8.57a.693.693 0 0 1-1.091-.568V6.679C9.614 7.648 6.44 11.454 6.44 16A9.56 9.56 0 0 0 16 25.56a9.56 9.56 0 0 0 5.355-17.481 1.107 1.107 0 1 1 1.242-1.832A11.762 11.762 0 0 1 27.774 16c0 6.502-5.271 11.773-11.773 11.773S4.228 22.502 4.228 16c0-5.774 4.156-10.577 9.64-11.581V3.198z"/><path d="M10.307 20c-.544 0-.814-.304-.814-.739 0-.327.126-.544.476-.865l2.464-2.355c1.02-.98 1.283-1.381 1.283-1.977 0-.682-.527-1.169-1.266-1.169-.665 0-1.123.332-1.421.997-.195.344-.395.504-.768.504-.464 0-.739-.275-.739-.705 0-.132.023-.252.063-.372.281-.917 1.318-1.77 2.882-1.77 1.753 0 2.933.985 2.933 2.406 0 1.008-.493 1.639-1.845 2.916l-1.787 1.719v.034h3.117c.447 0 .716.269.716.688 0 .407-.269.687-.716.687h-4.578zm9.197.183c-1.312 0-2.458-.613-2.87-1.49a1.291 1.291 0 0 1-.137-.567c0-.441.275-.705.722-.705.344 0 .561.12.756.43.298.596.785.957 1.53.957.899 0 1.547-.647 1.547-1.541 0-.871-.642-1.49-1.541-1.49a1.72 1.72 0 0 0-1.197.493c-.338.315-.51.401-.894.401-.567 0-.837-.395-.814-.859 0-.023 0-.04.006-.069l.241-3.031c.057-.699.418-.98 1.089-.98h3.627c.43 0 .71.269.71.688s-.275.688-.71.688h-3.266l-.195 2.297h.034c.338-.533 1.014-.865 1.856-.865 1.581 0 2.704 1.111 2.704 2.687 0 1.765-1.312 2.956-3.197 2.956z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M13.3.9c0-.7.8-1.1 1.4-.7l4.3 3c.4.3.5.8.2 1.2 0 0-.1.2-.2.2l-4.3 3c-.4.3-.9.2-1.2-.2-.1-.1-.2-.3-.2-.5V5.2c-5.4 1.2-9.4 6-9.4 11.8S9.3 29.1 16 29.1 28.1 23.7 28.1 17c0-4-2-7.8-5.3-10-.7-.4-.8-1.3-.4-1.9s1.3-.8 1.9-.4c4.1 2.8 6.6 7.4 6.6 12.4C30.9 25.3 24.2 32 16 32S1.1 25.3 1.1 17.1 6.4 3.7 13.3 2.4z"/><path d="M8.8 22.2c-.7 0-1-.4-1-.9s.2-.7.6-1.1l3.1-3c1.3-1.2 1.6-1.7 1.6-2.5s-.7-1.5-1.6-1.5-1.4.4-1.8 1.3c-.2.4-.5.6-1 .6s-.9-.3-.9-.9v-.5c.4-1.2 1.7-2.2 3.6-2.2s3.7 1.2 3.7 3-.6 2.1-2.3 3.7l-2.3 2.2h3.9q.9 0 .9.9c0 .9-.3.9-.9.9H8.6Zm11.6.2c-1.7 0-3.1-.8-3.6-1.9-.1-.2-.2-.5-.2-.7q0-.9.9-.9c.9 0 .7.2 1 .5.4.8 1 1.2 1.9 1.2s2-.8 2-2-.8-1.9-2-1.9q-.9 0-1.5.6c-.4.4-.6.5-1.1.5-.7 0-1.1-.5-1-1.1l.3-3.8c0-.9.5-1.2 1.4-1.2h4.6c.5 0 .9.3.9.9s-.3.9-.9.9H19l-.2 2.9c.4-.7 1.3-1.1 2.4-1.1 2 0 3.4 1.4 3.4 3.4s-1.7 3.7-4 3.7Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 900 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="33" height="32"><path d="M18.8 3.198a.693.693 0 0 0-1.091-.568l-3.431 2.402a.694.694 0 0 0 0 1.136l3.431 2.402a.693.693 0 0 0 1.091-.568V6.679c4.253.969 7.427 4.775 7.427 9.321a9.56 9.56 0 0 1-9.56 9.56 9.56 9.56 0 0 1-5.355-17.481 1.107 1.107 0 1 0-1.242-1.832A11.762 11.762 0 0 0 4.893 16c0 6.502 5.271 11.773 11.773 11.773S28.439 22.502 28.439 16c0-5.774-4.156-10.577-9.64-11.581V3.198z"/><path d="M17.025 20.183c-1.312 0-2.458-.613-2.87-1.49a1.292 1.292 0 0 1-.138-.567c0-.441.275-.705.722-.705.344 0 .561.12.756.43.298.596.785.957 1.53.957.899 0 1.547-.647 1.547-1.541 0-.871-.642-1.49-1.541-1.49a1.72 1.72 0 0 0-1.197.493c-.338.315-.51.401-.894.401-.567 0-.836-.395-.813-.859 0-.023 0-.04.006-.069l.241-3.031c.057-.699.418-.98 1.089-.98h3.627c.43 0 .71.269.71.688s-.275.688-.71.688h-3.266l-.195 2.297h.034c.338-.533 1.014-.865 1.856-.865 1.581 0 2.704 1.111 2.704 2.687 0 1.765-1.312 2.956-3.197 2.956z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 32"><path d="M19.4.9c0-.5-.4-.9-.9-.9-.2 0-.4 0-.5.2l-4.3 3c-.4.3-.5.8-.2 1.2 0 0 .1.2.2.2l4.3 3c.4.3.9.2 1.2-.2.1-.1.2-.3.2-.5V5.2c5.4 1.2 9.4 6 9.4 11.8s-5.4 12.1-12.1 12.1S4.6 23.7 4.6 17c0-4 2-7.8 5.3-10 .7-.4.8-1.3.4-1.9-.4-.7-1.3-.8-1.9-.4-4.2 2.8-6.6 7.4-6.6 12.4C1.8 25.3 8.5 32 16.7 32s14.9-6.7 14.9-14.9S26.3 3.7 19.4 2.4z"/><path d="M17.1 22.4c-1.7 0-3.1-.8-3.6-1.9-.1-.2-.2-.5-.2-.7q0-.9.9-.9c.9 0 .7.2 1 .5.4.8 1 1.2 1.9 1.2s2-.8 2-2-.8-1.9-2-1.9q-.9 0-1.5.6c-.4.4-.6.5-1.1.5-.7 0-1.1-.5-1-1.1l.3-3.8c0-.9.5-1.2 1.4-1.2h4.6c.5 0 .9.3.9.9s-.3.9-.9.9h-4.1l-.2 2.9c.4-.7 1.3-1.1 2.4-1.1 2 0 3.4 1.4 3.4 3.4s-1.7 3.7-4 3.7Z"/></svg>

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 697 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" x="0" y="0" version="1.1" viewBox="0 0 32 32"><path d="M11.9 17.7c-6.2 0-8.4 3.6-9.2 5.7-.3.8-.2 1.7.3 2.5.6.8 1.6 1.3 2.6 1.3h12.5c1.1 0 2.1-.5 2.6-1.3.5-.7.6-1.6.3-2.5-.7-2.1-2.9-5.7-9.1-5.7m7.2 7c-.2.3-.6.5-1 .5H5.6c-.4 0-.8-.2-1-.5-.1-.2-.2-.4-.1-.6.7-2 2.6-4.4 7.3-4.4s6.6 2.4 7.3 4.4q.3.3 0 .6M29.3 22.7c-.6-1.9-2.6-5.2-8.1-5.2h-.7c-.6 0-1 .5-1 1 0 .6.5 1 1 1h.6c4.1 0 5.6 2.1 6.2 3.8v.4c-.1.2-.4.3-.6.3h-3.6c-.6 0-1 .4-1 1s.4 1 1 1h3.6c.9 0 1.8-.4 2.3-1.1s.6-1.5.3-2.2M6.4 12l.8.6c.1.1.2.1.3.2L7.1 14c-.2.7-.1 1.3.3 1.9.7 1.1 2.2 1.5 3.3.8l1.2-.7 1.3.7q.6.3 1.2.3c.2 0 .4 0 .6-.1.6-.1 1.2-.6 1.5-1.1q.45-.9.3-1.8l-.3-1.3.6-.5c.1.3.4.6.6.9l.4.3-.1.4c-.2.6-.1 1.3.3 1.8.7 1 2 1.4 3.1.7l.5-.3.5.3q.6.3 1.2.3c.2 0 .3 0 .5-.1.6-.1 1.1-.5 1.4-1s.4-1.1.3-1.7l-.1-.4.4-.3c.5-.4.8-1 .8-1.6s-.1-1.2-.5-1.7-1-.8-1.6-.8h-.6l-.2-.6c-.3-.5-.7-.8-1.2-1-1.1-.4-2.3 0-2.9 1l-.3.6H19c-.3 0-.5.1-.8.2-.1-.3-.2-.5-.4-.8-.4-.5-1-.8-1.7-.9l-1.5-.1-.5-1.2c-.3-.6-.7-1.1-1.3-1.3-1.2-.5-2.6.1-3.2 1.3l-.4 1.3-1.5.1c-.6 0-1.1.3-1.5.7l-.1.2q-.75.75-.6 1.8c0 .6.4 1.2.9 1.7m12.6-.8c.1-.1.2-.1.2-.1L21 11l.7-1.6c.1-.1.2-.2.4-.1.1 0 .1.1.1.1l.7 1.6 1.8.1c.1 0 .2 0 .2.1s.1.1.1.2-.1.2-.1.2l-1.4 1.1.4 1.7v.2c0 .1-.1.1-.2.1h-.2l-1.5-.9-1.5.9c-.1.1-.3.1-.4-.1 0-.1-.1-.1 0-.2l.3-1.1h.1l1.8-1c.1 0 0-.2-.1-.2l-2.1.1H20c-.1 0-.1-.1-.2-.1l-.5-.4c-.3-.2-.3-.3-.3-.3zM7.5 9.8c.1-.1.2-.2.3-.2l2.6-.2 1-2.4c.1-.2.4-.3.6-.2.1 0 .2.1.2.2l1 2.4 2.8.2c.1 0 .2.1.3.2s.1.2.1.3-.1.2-.2.3l-2 1.7.6 2.5v.3c-.1.1-.2.2-.3.2s-.2 0-.3-.1l-2.3-1.3L9.7 15c-.2.1-.5.1-.6-.1-.1-.1-.1-.3-.1-.4l.3-1.2c0-.2.1-.3.2-.5l3.3-1.7c.1-.1.1-.2-.1-.2l-3.7.4-.6-.3-.8-.6c-.1-.1-.2-.2-.2-.3.1-.1.1-.2.1-.3"/></svg> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" x="0" y="0" version="1.1" viewBox="0 0 32 32"><style>.st3{fill:#4e8ee5}</style><path d="M11.1 18c-7.4 0-10 4.3-10.9 6.8-.4 1-.2 2.1.4 2.9.7 1 1.9 1.6 3.1 1.6h14.8c1.3 0 2.4-.6 3.1-1.6.6-.9.7-1.9.4-2.9-.9-2.5-3.5-6.8-10.9-6.8m8.6 8.4c-.2.3-.7.5-1.2.5H3.7c-.5 0-1-.2-1.2-.5-.2-.2-.2-.5-.1-.8.9-2.4 3.1-5.2 8.7-5.2s7.8 2.8 8.7 5.2c.1.3.1.5-.1.8M31.8 23.9c-.8-2.3-3-6.1-9.6-6.1h-.8c-.7 0-1.2.6-1.1 1.2 0 .7.6 1.2 1.2 1.1h.7c4.8 0 6.6 2.4 7.3 4.5.1.2 0 .3-.1.4-.1.2-.4.3-.8.3h-4.3c-.7 0-1.2.5-1.2 1.2s.5 1.2 1.2 1.2h4.3c1.1 0 2.1-.5 2.7-1.3.7-.7.8-1.6.5-2.5M4.6 11.2l.9.7c.1.1.2.2.3.2v.1l-.4 1.4c-.2.8-.1 1.6.4 2.3.8 1.3 2.6 1.7 3.9.9l1.5-.9 1.5.9c.5.3 1 .4 1.5.4.2 0 .4 0 .7-.1.8-.2 1.4-.7 1.8-1.3.4-.7.5-1.4.3-2.2l-.4-1.5.8-.6c.2.4.4.8.8 1l.4.3-.1.5c-.2.7-.1 1.5.3 2.1.8 1.2 2.4 1.6 3.7.9l.6-.3.6.4c.4.2.9.4 1.4.4.2 0 .4 0 .6-.1.7-.2 1.3-.6 1.7-1.2s.5-1.4.3-2.1l-.1-.5.4-.4c.6-.5.9-1.1 1-1.9.1-.7-.2-1.4-.6-2-.5-.6-1.2-.9-1.9-1l-.7-.1-.4-.8c-.3-.5-.8-1-1.4-1.2-1.3-.5-2.7 0-3.4 1.2l-.4.8h-.7c-.3 0-.6.1-.9.2-.1-.3-.3-.6-.5-.9-.5-.6-1.2-1-2-1l-1.6.2-.6-1.5c-.3-.7-.9-1.3-1.6-1.5-1.5-.7-3.2 0-3.8 1.5L7.9 6l-1.7.1c-.7 0-1.3.3-1.8.8l-.2.2c-.5.6-.8 1.3-.7 2.1s.5 1.5 1.1 2m14.9-.9c.1-.1.2-.2.3-.2l2.1-.2.8-1.9c.1-.2.3-.2.4-.1.2.1.2.1.3.1l.8 1.9 2.1.2c.1 0 .2.1.3.1.1.1.1.1.1.2s-.1.2-.1.2L25 11.9l.5 2v.2l-.2.2H25l-1.8-1.1-1.8 1c-.1.1-.4.1-.5-.1 0-.1-.1-.2 0-.3l.3-1.3.1-.1 2.1-1.2c.1-.1 0-.2-.1-.2l-2.5.1h-.1c-.1 0-.2-.1-.2-.2l-.6-.5c-.1-.1-.1-.2-.1-.2-.3.3-.3.2-.3.1M5.9 8.7c.2-.2.3-.2.4-.2l3.1-.2 1.2-2.8c.1-.3.5-.4.7-.3l.3.3 1.2 2.8 3.2.2c.1 0 .3.1.4.2s.1.2.1.4c0 .1-.1.3-.2.3l-2.4 2 .7 2.9c0 .1 0 .3-.1.4s-.2.2-.3.2-.3 0-.4-.1l-2.7-1.6-2.7 1.6c-.2.1-.6.1-.7-.2-.1-.1-.1-.3-.1-.4l.4-1.4c.1-.2.1-.4.3-.6l3.9-2c.1-.1.1-.3-.1-.2l-4.5.4c-.3-.1-.5-.2-.7-.4L6 9.3c-.1-.1-.1-.2-.1-.3z"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -2108,6 +2108,7 @@
"StarGiftPurchaseTransaction" = "Gift Sale"; "StarGiftPurchaseTransaction" = "Gift Sale";
"GiftBuyConfirmDescription" = "Do you want to buy **{gift}** for **{stars}**?"; "GiftBuyConfirmDescription" = "Do you want to buy **{gift}** for **{stars}**?";
"GiftBuyForPeerConfirmDescription" = "Do you want to buy **{gift}** for **{stars}** and gift it to **{peer}**?"; "GiftBuyForPeerConfirmDescription" = "Do you want to buy **{gift}** for **{stars}** and gift it to **{peer}**?";
"GiftBuyEqualsTo" = "Equals to {stars}";
"ComposerTitleForwardFrom" = "From: **{users}**"; "ComposerTitleForwardFrom" = "From: **{users}**";
"ContextMenuItemMention" = "Mention"; "ContextMenuItemMention" = "Mention";
"GiftRibbonResale" = "resale"; "GiftRibbonResale" = "resale";

View File

@ -8,7 +8,7 @@ import type { UiLoaderPage } from './common/UiLoader';
import { DARK_THEME_BG_COLOR, INACTIVE_MARKER, LIGHT_THEME_BG_COLOR, PAGE_TITLE, PAGE_TITLE_TAURI } from '../config'; import { DARK_THEME_BG_COLOR, INACTIVE_MARKER, LIGHT_THEME_BG_COLOR, PAGE_TITLE, PAGE_TITLE_TAURI } from '../config';
import { forceMutation } from '../lib/fasterdom/stricterdom.ts'; import { forceMutation } from '../lib/fasterdom/stricterdom.ts';
import { selectTabState, selectTheme } from '../global/selectors'; import { selectActionMessageBg, selectTabState, selectTheme } from '../global/selectors';
import { IS_TAURI } from '../util/browser/globalEnvironment'; import { IS_TAURI } from '../util/browser/globalEnvironment';
import { IS_INSTALL_PROMPT_SUPPORTED, PLATFORM_ENV } from '../util/browser/windowEnvironment'; import { IS_INSTALL_PROMPT_SUPPORTED, PLATFORM_ENV } from '../util/browser/windowEnvironment';
import buildClassName from '../util/buildClassName'; import buildClassName from '../util/buildClassName';
@ -43,6 +43,7 @@ type StateProps = {
hasWebAuthTokenFailed?: boolean; hasWebAuthTokenFailed?: boolean;
isTestServer?: boolean; isTestServer?: boolean;
theme: ThemeKey; theme: ThemeKey;
actionMessageBg?: string;
}; };
enum AppScreens { enum AppScreens {
@ -64,6 +65,7 @@ const App: FC<StateProps> = ({
hasWebAuthTokenFailed, hasWebAuthTokenFailed,
isTestServer, isTestServer,
theme, theme,
actionMessageBg,
}) => { }) => {
const { isMobile } = useAppLayout(); const { isMobile } = useAppLayout();
const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android'; const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android';
@ -226,6 +228,12 @@ const App: FC<StateProps> = ({
); );
}, [theme]); }, [theme]);
useLayoutEffect(() => {
if (actionMessageBg) {
document.body.style.setProperty('--action-message-bg', actionMessageBg);
}
}, [actionMessageBg]);
const getIsInBackgroundLocal = getIsInBackground; const getIsInBackgroundLocal = getIsInBackground;
useSignalEffect(() => { useSignalEffect(() => {
// Mutation forced to avoid RAF throttling in background // Mutation forced to avoid RAF throttling in background
@ -263,6 +271,7 @@ export default withGlobal(
hasWebAuthTokenFailed: global.hasWebAuthTokenFailed || global.hasWebAuthTokenPasswordRequired, hasWebAuthTokenFailed: global.hasWebAuthTokenFailed || global.hasWebAuthTokenPasswordRequired,
theme: selectTheme(global), theme: selectTheme(global),
isTestServer: global.config?.isTestServer, isTestServer: global.config?.isTestServer,
actionMessageBg: selectActionMessageBg(global),
}; };
}, },
)(App); )(App);

View File

@ -70,13 +70,17 @@
} }
} }
.container {
margin-top: 0.1875rem;
}
.month-selector { .month-selector {
display: flex; display: flex;
align-items: center; align-items: center;
h4 { h4 {
flex: 1; flex: 1;
margin: 0 0 0 1.25rem; margin: 0 0 0 2.25rem;
font-size: 1.25rem; font-size: 1.25rem;
& ~ .Button { & ~ .Button {

View File

@ -370,16 +370,10 @@ const CalendarModal: FC<OwnProps & StateProps> = ({
className="CalendarModal" className="CalendarModal"
onEnter={handleSubmit} onEnter={handleSubmit}
dialogRef={dialogRef} dialogRef={dialogRef}
hasAbsoluteCloseButton
> >
<div className="container"> <div className="container">
<div className="month-selector"> <div className="month-selector">
<Button
round
size="smaller"
color="translucent"
iconName="close"
onClick={onClose}
/>
<h4> <h4>
{oldLang(`lng_month${currentMonth + 1}`)} {oldLang(`lng_month${currentMonth + 1}`)}

View File

@ -9,8 +9,9 @@
.pickerTitle { .pickerTitle {
flex: 1; flex: 1;
margin: 0 0 0 1.25rem; margin: 0 0 0 2.25rem;
font-size: 1.25rem; font-size: 1.25rem;
line-height: 1.25;
@media (max-width: 600px) { @media (max-width: 600px) {
margin-left: 0.75rem; margin-left: 0.75rem;

View File

@ -76,16 +76,10 @@ const CountryPickerModal: FC<OwnProps> = ({
isOpen={isOpen} isOpen={isOpen}
onClose={onClose} onClose={onClose}
onEnter={handleSubmit} onEnter={handleSubmit}
hasAbsoluteCloseButton
> >
<div className={styles.container}> <div className={styles.container}>
<div className={styles.pickerSelector}> <div className={styles.pickerSelector}>
<Button
round
size="smaller"
color="translucent"
onClick={onClose}
iconName="close"
/>
<h4 className={styles.pickerTitle}> <h4 className={styles.pickerTitle}>
{lang('BoostingSelectCountry')} {lang('BoostingSelectCountry')}

View File

@ -38,6 +38,6 @@
.closeButton { .closeButton {
position: absolute; position: absolute;
top: 0.5rem; top: 0.875rem;
right: 0.5rem; right: 0.875rem;
} }

View File

@ -87,7 +87,7 @@ const PrivacySettingsNoticeModal = ({ isOpen, isReadDate, user }: OwnProps & Sta
className={styles.closeButton} className={styles.closeButton}
color="translucent" color="translucent"
round round
size="smaller" size="tiny"
onClick={handleClose} onClick={handleClose}
ariaLabel="Close" ariaLabel="Close"
iconName="close" iconName="close"

View File

@ -195,7 +195,7 @@ const StickerSetModal: FC<OwnProps & StateProps> = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
onClick={onClose} onClick={onClose}
iconName="close" iconName="close"

View File

@ -249,7 +249,7 @@ const ChatOrUserPicker: FC<OwnProps> = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={oldLang('Back')} ariaLabel={oldLang('Back')}
onClick={handleHeaderBackClick} onClick={handleHeaderBackClick}
iconName="arrow-left" iconName="arrow-left"
@ -301,7 +301,7 @@ const ChatOrUserPicker: FC<OwnProps> = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={oldLang('Close')} ariaLabel={oldLang('Close')}
onClick={onClose} onClick={onClose}
iconName="close" iconName="close"

View File

@ -22,5 +22,8 @@
} }
.buttonWrapper { .buttonWrapper {
padding: 0.25rem; position: relative;
padding-top: 0.25rem;
padding-bottom: 1rem;
padding-inline: 1rem;
} }

View File

@ -1,13 +1,15 @@
import { memo } from '../../../lib/teact/teact'; import { memo, useRef } from '../../../lib/teact/teact';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import useOldLang from '../../../hooks/useOldLang'; import useOldLang from '../../../hooks/useOldLang';
import useScrollNotch from '../../../hooks/useScrollNotch';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import Modal, { type OwnProps as ModalProps } from '../../ui/Modal'; import Modal, { type OwnProps as ModalProps } from '../../ui/Modal';
import styles from './PickerModal.module.scss'; import styles from './PickerModal.module.scss';
import pickerStyles from './PickerStyles.module.scss';
type OwnProps = { type OwnProps = {
confirmButtonText?: string; confirmButtonText?: string;
@ -15,9 +17,12 @@ type OwnProps = {
shouldAdaptToSearch?: boolean; shouldAdaptToSearch?: boolean;
withFixedHeight?: boolean; withFixedHeight?: boolean;
withPremiumGradient?: boolean; withPremiumGradient?: boolean;
itemsContainerSelector?: string;
onConfirm?: NoneToVoidFunction; onConfirm?: NoneToVoidFunction;
} & ModalProps; } & ModalProps;
const DEFAULT_ITEMS_CONTAINER_SELECTOR = `.${pickerStyles.pickerList}`;
const PickerModal = ({ const PickerModal = ({
confirmButtonText, confirmButtonText,
isConfirmDisabled, isConfirmDisabled,
@ -25,14 +30,24 @@ const PickerModal = ({
withFixedHeight, withFixedHeight,
onConfirm, onConfirm,
withPremiumGradient, withPremiumGradient,
itemsContainerSelector = DEFAULT_ITEMS_CONTAINER_SELECTOR,
...modalProps ...modalProps
}: OwnProps) => { }: OwnProps) => {
const lang = useOldLang(); const lang = useOldLang();
const hasButton = Boolean(confirmButtonText || onConfirm); const hasButton = Boolean(confirmButtonText || onConfirm);
const dialogRef = useRef<HTMLDivElement>();
useScrollNotch({
containerRef: dialogRef,
selector: `.modal-content ${itemsContainerSelector}`,
isBottomNotch: true,
}, [modalProps.isOpen]);
return ( return (
<Modal <Modal
{...modalProps} {...modalProps}
dialogRef={dialogRef}
isSlim isSlim
className={buildClassName( className={buildClassName(
shouldAdaptToSearch && styles.withSearch, shouldAdaptToSearch && styles.withSearch,

View File

@ -51,6 +51,7 @@
} }
.pickerList { .pickerList {
position: relative;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
flex-grow: 1; flex-grow: 1;

View File

@ -22,11 +22,13 @@ type OwnProps = {
patternIcon?: ApiSticker; patternIcon?: ApiSticker;
patternColor?: number; patternColor?: number;
patternSize?: number; patternSize?: number;
maxRadius?: number;
centerEmptiness?: number; centerEmptiness?: number;
ringsCount?: number; ringsCount?: number;
ovalFactor?: number; ovalFactor?: number;
withLinearGradient?: boolean; withLinearGradient?: boolean;
className?: string; className?: string;
canvasClassName?: string;
clearBottomSector?: boolean; clearBottomSector?: boolean;
yPosition?: number; yPosition?: number;
withAdaptiveHeight?: boolean; withAdaptiveHeight?: boolean;
@ -35,7 +37,7 @@ type OwnProps = {
const BASE_RING_ITEM_COUNT = 8; const BASE_RING_ITEM_COUNT = 8;
const RING_INCREMENT = 0.5; const RING_INCREMENT = 0.5;
const DEFAULT_CENTER_EMPTINESS = 0.1; const DEFAULT_CENTER_EMPTINESS = 0.1;
const MAX_RADIUS = 0.42; const DEFAULT_MAX_RADIUS = 0.42;
const MIN_SIZE = 4 * REM; const MIN_SIZE = 4 * REM;
const DARK_LUMA_THRESHOLD = 255 * 0.2; const DARK_LUMA_THRESHOLD = 255 * 0.2;
@ -50,9 +52,11 @@ const RadialPatternBackground = ({
centerEmptiness = DEFAULT_CENTER_EMPTINESS, centerEmptiness = DEFAULT_CENTER_EMPTINESS,
ringsCount = DEFAULT_RINGS_COUNT, ringsCount = DEFAULT_RINGS_COUNT,
ovalFactor = DEFAULT_OVAL_FACTOR, ovalFactor = DEFAULT_OVAL_FACTOR,
maxRadius = DEFAULT_MAX_RADIUS,
withLinearGradient, withLinearGradient,
clearBottomSector, clearBottomSector,
className, className,
canvasClassName,
yPosition, yPosition,
withAdaptiveHeight, withAdaptiveHeight,
}: OwnProps) => { }: OwnProps) => {
@ -78,7 +82,7 @@ const RadialPatternBackground = ({
for (let ring = 1; ring <= ringsCount; ring++) { for (let ring = 1; ring <= ringsCount; ring++) {
const ringItemCount = Math.floor(BASE_RING_ITEM_COUNT * (1 + (ring - 1) * RING_INCREMENT)); const ringItemCount = Math.floor(BASE_RING_ITEM_COUNT * (1 + (ring - 1) * RING_INCREMENT));
const ringProgress = ring / ringsCount; const ringProgress = ring / ringsCount;
const ringRadius = centerEmptiness + (MAX_RADIUS - centerEmptiness) * ringProgress; const ringRadius = centerEmptiness + (maxRadius - centerEmptiness) * ringProgress;
const angleShift = ring % 2 === 0 ? Math.PI / ringItemCount : 0; const angleShift = ring % 2 === 0 ? Math.PI / ringItemCount : 0;
for (let i = 0; i < ringItemCount; i++) { for (let i = 0; i < ringItemCount; i++) {
@ -100,7 +104,7 @@ const RadialPatternBackground = ({
} }
} }
return coordinates; return coordinates;
}, [centerEmptiness, clearBottomSector, ovalFactor, ringsCount]); }, [centerEmptiness, clearBottomSector, maxRadius, ovalFactor, ringsCount]);
useResizeObserver(containerRef, (entry) => { useResizeObserver(containerRef, (entry) => {
setContainerSize({ setContainerSize({
@ -148,7 +152,7 @@ const RadialPatternBackground = ({
ctx.globalCompositeOperation = 'source-in'; ctx.globalCompositeOperation = 'source-in';
ctx.fillRect(0, 0, width, height); ctx.fillRect(0, 0, width, height);
const radialGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, width / 2); const radialGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, width * maxRadius);
radialGradient.addColorStop(0, 'rgb(255 255 255 / 0.4)'); radialGradient.addColorStop(0, 'rgb(255 255 255 / 0.4)');
radialGradient.addColorStop(1, 'rgb(255 255 255 / 0.9)'); radialGradient.addColorStop(1, 'rgb(255 255 255 / 0.9)');
@ -200,7 +204,7 @@ const RadialPatternBackground = ({
> >
<canvas <canvas
ref={canvasRef} ref={canvasRef}
className={buildClassName(styles.canvas, emojiImage && styles.showing)} className={buildClassName(styles.canvas, emojiImage && styles.showing, canvasClassName)}
aria-hidden="true" aria-hidden="true"
/> />
</div> </div>

View File

@ -62,7 +62,14 @@ const SettingsActiveSession: FC<OwnProps & StateProps> = ({
function renderHeader() { function renderHeader() {
return ( return (
<div className="modal-header-condensed" dir={lang.isRtl ? 'rtl' : undefined}> <div className="modal-header-condensed" dir={lang.isRtl ? 'rtl' : undefined}>
<Button round color="translucent" size="smaller" ariaLabel={lang('Close')} onClick={onClose} iconName="close" /> <Button
round
color="translucent"
size="tiny"
ariaLabel={lang('Close')}
onClick={onClose}
iconName="close"
/>
<div className="modal-title">{lang('SessionPreviewTitle')}</div> <div className="modal-title">{lang('SessionPreviewTitle')}</div>
<Button <Button
color="danger" color="danger"

View File

@ -51,7 +51,14 @@ const SettingsActiveWebsite: FC<OwnProps & StateProps> = ({
function renderHeader() { function renderHeader() {
return ( return (
<div className="modal-header-condensed" dir={lang.isRtl ? 'rtl' : undefined}> <div className="modal-header-condensed" dir={lang.isRtl ? 'rtl' : undefined}>
<Button round color="translucent" size="smaller" ariaLabel={lang('Close')} onClick={onClose} iconName="close" /> <Button
round
color="translucent"
size="tiny"
ariaLabel={lang('Close')}
onClick={onClose}
iconName="close"
/>
<div className="modal-title">{lang('WebSessionsTitle')}</div> <div className="modal-title">{lang('WebSessionsTitle')}</div>
<Button <Button
color="danger" color="danger"

View File

@ -689,17 +689,9 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
isOpen={isOpen} isOpen={isOpen}
dialogRef={dialogRef} dialogRef={dialogRef}
onEnter={(dataPrepaidGiveaway || dataStarsPrepaidGiveaway) ? openConfirmModal : handleClick} onEnter={(dataPrepaidGiveaway || dataStarsPrepaidGiveaway) ? openConfirmModal : handleClick}
hasAbsoluteCloseButton
> >
<div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}> <div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
<Button
round
size="smaller"
className={styles.closeButton}
color="translucent"
onClick={handleClose}
ariaLabel={lang('Close')}
iconName="close"
/>
<img className={styles.logo} src={PremiumLogo} alt="" draggable={false} /> <img className={styles.logo} src={PremiumLogo} alt="" draggable={false} />
<h2 className={styles.headerText}> <h2 className={styles.headerText}>
{renderText(lang('BoostingBoostsViaGifts'))} {renderText(lang('BoostingBoostsViaGifts'))}

View File

@ -17,8 +17,9 @@
.back-button { .back-button {
position: absolute; position: absolute;
z-index: 2; z-index: 3;
margin: -0.5rem; top: 0.875rem;
left: 0.875rem;
} }
.white-back-button { .white-back-button {

View File

@ -227,7 +227,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
<div className={styles.root}> <div className={styles.root}>
<Button <Button
round round
size="smaller" size="tiny"
className={buildClassName(styles.backButton, hasHeaderBackdrop && styles.whiteBackButton)} className={buildClassName(styles.backButton, hasHeaderBackdrop && styles.whiteBackButton)}
color={hasHeaderBackdrop ? 'translucent-white' : 'translucent'} color={hasHeaderBackdrop ? 'translucent-white' : 'translucent'}
onClick={onBack} onClick={onBack}

View File

@ -103,8 +103,8 @@
.close-button { .close-button {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
top: 0.5rem; top: 0.875rem;
left: 0.5rem; left: 0.875rem;
} }
.premium-header-text { .premium-header-text {

View File

@ -428,19 +428,11 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
onClose={closePremiumModal} onClose={closePremiumModal}
isOpen={isOpen} isOpen={isOpen}
dialogRef={dialogRef} dialogRef={dialogRef}
hasAbsoluteCloseButton
> >
<Transition name="slide" activeKey={currentSection ? 1 : 0} className={styles.transition}> <Transition name="slide" activeKey={currentSection ? 1 : 0} className={styles.transition}>
{!currentSection ? ( {!currentSection ? (
<div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}> <div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
<Button
round
size="smaller"
className={styles.closeButton}
color="translucent"
onClick={() => closePremiumModal()}
ariaLabel={oldLang('Close')}
iconName="close"
/>
{renderHeader()} {renderHeader()}
{!isPremium && !isGift && renderSubscriptionOptions()} {!isPremium && !isGift && renderSubscriptionOptions()}
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}> <div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>

View File

@ -21,7 +21,7 @@
color: #fff; color: #fff;
background: var(--pattern-color); background: var(--action-message-bg);
} }
.explainer { .explainer {
@ -33,7 +33,7 @@
color: #fff; color: #fff;
text-wrap: balance; text-wrap: balance;
background: var(--pattern-color); background: var(--action-message-bg);
} }
.title { .title {

View File

@ -1,6 +1,4 @@
.MessageList { .MessageList {
--action-message-bg: var(--pattern-color);
overflow-x: hidden; overflow-x: hidden;
overflow-y: scroll; overflow-y: scroll;
flex: 1; flex: 1;

View File

@ -218,18 +218,11 @@
} }
&.with-notch::before { &.with-notch::before {
opacity: 1; opacity: 0.75;
} }
html.theme-dark &::before { html.theme-dark &::before {
background: background: var(--action-message-bg);
linear-gradient(
90deg,
rgba(127, 127, 127, 0) 0%,
rgba(127, 127, 127, 0.4) 2%,
rgba(127, 127, 127, 0.4) 98%,
rgba(127, 127, 127, 0) 100%
);
} }
@media (min-width: 1276px) { @media (min-width: 1276px) {

View File

@ -30,6 +30,7 @@ import {
isUserRightBanned, isUserRightBanned,
} from '../../global/helpers'; } from '../../global/helpers';
import { import {
selectActionMessageBg,
selectBot, selectBot,
selectCanAnimateInterface, selectCanAnimateRightColumn, selectCanAnimateInterface, selectCanAnimateRightColumn,
selectChat, selectChat,
@ -125,6 +126,7 @@ type StateProps = {
customBackground?: string; customBackground?: string;
backgroundColor?: string; backgroundColor?: string;
patternColor?: string; patternColor?: string;
actionMessageBg?: string;
isLeftColumnShown?: boolean; isLeftColumnShown?: boolean;
isRightColumnShown?: boolean; isRightColumnShown?: boolean;
isBackgroundBlurred?: boolean; isBackgroundBlurred?: boolean;
@ -191,6 +193,7 @@ function MiddleColumn({
theme, theme,
backgroundColor, backgroundColor,
patternColor, patternColor,
actionMessageBg,
isLeftColumnShown, isLeftColumnShown,
isRightColumnShown, isRightColumnShown,
isBackgroundBlurred, isBackgroundBlurred,
@ -486,7 +489,7 @@ function MiddleColumn({
}); });
// Prepare filter beforehand to avoid flickering // Prepare filter beforehand to avoid flickering
useFluidBackgroundFilter(patternColor); useFluidBackgroundFilter(actionMessageBg);
const isMessagingDisabled = Boolean( const isMessagingDisabled = Boolean(
!isPinnedMessageList && !isSavedDialog && !renderingCanPost && !renderingCanRestartBot && !renderingCanStartBot !isPinnedMessageList && !isSavedDialog && !renderingCanPost && !renderingCanRestartBot && !renderingCanStartBot
@ -760,6 +763,7 @@ export default memo(withGlobal<OwnProps>(
customBackground, customBackground,
backgroundColor, backgroundColor,
patternColor, patternColor,
actionMessageBg: selectActionMessageBg(global),
isLeftColumnShown, isLeftColumnShown,
isRightColumnShown: selectIsRightColumnShown(global, isMobile), isRightColumnShown: selectIsRightColumnShown(global, isMobile),
isBackgroundBlurred, isBackgroundBlurred,

View File

@ -29,7 +29,7 @@
color: #fff; color: #fff;
background: var(--pattern-color); background: var(--action-message-bg);
&[dir="rtl"] { &[dir="rtl"] {
text-align: right; text-align: right;

View File

@ -5,15 +5,6 @@
--hover-color-reaction: var(--color-message-reaction-hover); --hover-color-reaction: var(--color-message-reaction-hover);
--accent-color: var(--color-primary); --accent-color: var(--color-primary);
.modal-header {
padding-top: 0.5rem;
padding-inline: 0.5rem;
.modal-title {
margin-inline: 1.3125rem;
}
}
.modal-dialog { .modal-dialog {
overflow: clip; overflow: clip;
} }
@ -46,20 +37,27 @@
gap: 0.4375rem; gap: 0.4375rem;
width: auto; width: auto;
min-height: 2.25rem; min-height: 2rem;
padding-inline: 0.4375rem; margin-top: 0;
padding-inline: 0.75rem;
} }
.reaction-filter-emoji { .reaction-filter-emoji {
margin-inline-end: 0.25rem; margin-inline-end: 0.25rem;
} }
.not-chosen-button {
&:hover {
background-color: var(--hover-color-reaction) !important;
}
}
.reactor-list { .reactor-list {
overflow: auto; overflow: auto;
overflow-x: hidden; overflow-x: hidden;
max-height: 100%; max-height: 100%;
padding-top: 0.5rem; padding-top: 0.25rem;
padding-inline: 0.5rem; padding-inline: 0.5rem;
} }

View File

@ -7,6 +7,7 @@ import {
import { getActions, getGlobal, withGlobal } from '../../global'; import { getActions, getGlobal, withGlobal } from '../../global';
import type { ApiAvailableReaction, ApiMessage, ApiReaction } from '../../api/types'; import type { ApiAvailableReaction, ApiMessage, ApiReaction } from '../../api/types';
import type { AnimationLevel } from '../../types';
import { LoadMoreDirection } from '../../types'; import { LoadMoreDirection } from '../../types';
import { getReactionKey, isSameReaction } from '../../global/helpers'; import { getReactionKey, isSameReaction } from '../../global/helpers';
@ -14,9 +15,11 @@ import {
selectChatMessage, selectChatMessage,
selectTabState, selectTabState,
} from '../../global/selectors'; } from '../../global/selectors';
import { selectSharedSettings } from '../../global/selectors/sharedState';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { formatDateAtTime } from '../../util/dates/dateFormat'; import { formatDateAtTime } from '../../util/dates/dateFormat';
import { unique } from '../../util/iteratees'; import { unique } from '../../util/iteratees';
import { resolveTransitionName } from '../../util/resolveTransitionName';
import { formatIntegerCompact } from '../../util/textFormat'; import { formatIntegerCompact } from '../../util/textFormat';
import { REM } from '../common/helpers/mediaDimensions'; import { REM } from '../common/helpers/mediaDimensions';
@ -52,6 +55,7 @@ export type StateProps = Pick<ApiMessage, 'reactors' | 'reactions' | 'seenByDate
chatId?: string; chatId?: string;
messageId?: number; messageId?: number;
availableReactions?: ApiAvailableReaction[]; availableReactions?: ApiAvailableReaction[];
animationLevel: AnimationLevel;
}; };
const DEFAULT_REACTION_SIZE = 1.5 * REM; const DEFAULT_REACTION_SIZE = 1.5 * REM;
@ -64,6 +68,7 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
messageId, messageId,
seenByDates, seenByDates,
availableReactions, availableReactions,
animationLevel,
}) => { }) => {
const { const {
loadReactors, loadReactors,
@ -169,6 +174,7 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
className="ReactorListModal narrow" className="ReactorListModal narrow"
title={oldLang('Reactions')} title={oldLang('Reactions')}
onCloseAnimationEnd={handleCloseAnimationEnd} onCloseAnimationEnd={handleCloseAnimationEnd}
isCondensedHeader
hasCloseButton hasCloseButton
> >
{canShowFilters && ( {canShowFilters && (
@ -182,6 +188,7 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
size="tiny" size="tiny"
ripple ripple
iconName="heart" iconName="heart"
className={chosenTab ? 'not-chosen-button' : undefined}
pill pill
fluid fluid
onClick={() => setChosenTab(undefined)} onClick={() => setChosenTab(undefined)}
@ -191,10 +198,12 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
{allReactions.map((reaction) => { {allReactions.map((reaction) => {
const count = reactions?.results const count = reactions?.results
.find((reactionsCount) => isSameReaction(reactionsCount.reaction, reaction))?.count; .find((reactionsCount) => isSameReaction(reactionsCount.reaction, reaction))?.count;
const isChosen = isSameReaction(chosenTab, reaction);
return ( return (
<Button <Button
key={getReactionKey(reaction)} key={getReactionKey(reaction)}
color={isSameReaction(chosenTab, reaction) ? 'primary' : 'adaptive'} className={!isChosen ? 'not-chosen-button' : undefined}
color={isChosen ? 'primary' : 'adaptive'}
size="tiny" size="tiny"
pill pill
fluid fluid
@ -219,7 +228,10 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
dir={lang.isRtl ? 'rtl' : undefined} dir={lang.isRtl ? 'rtl' : undefined}
className="reactor-list-wrapper" className="reactor-list-wrapper"
> >
<Transition activeKey={contentActiveKey} name="slide"> <Transition
activeKey={contentActiveKey}
name={resolveTransitionName('slide', animationLevel, undefined, lang.isRtl)}
>
{viewportIds?.length ? ( {viewportIds?.length ? (
<InfiniteScroll <InfiniteScroll
className="reactor-list custom-scroll" className="reactor-list custom-scroll"
@ -305,6 +317,7 @@ export default memo(withGlobal<OwnProps>(
reactors: message?.reactors, reactors: message?.reactors,
seenByDates: message?.seenByDates, seenByDates: message?.seenByDates,
availableReactions: global.reactions.availableReactions, availableReactions: global.reactions.availableReactions,
animationLevel: selectSharedSettings(global).animationLevel,
}; };
}, },
)(ReactorListModal)); )(ReactorListModal));

View File

@ -17,12 +17,12 @@
color: var(--color-white); color: var(--color-white);
text-transform: none; text-transform: none;
background: var(--pattern-color); background: var(--action-message-bg);
transition: filter 150ms ease-in-out; transition: filter 150ms ease-in-out;
&:not(.disabled):not(:disabled):hover { &:not(.disabled):not(:disabled):hover {
background-color: var(--pattern-color); background-color: var(--action-message-bg);
filter: brightness(1.05); filter: brightness(1.05);
} }
} }
@ -37,7 +37,7 @@
padding: 1.0625rem 0; padding: 1.0625rem 0;
border-radius: 1.5rem; border-radius: 1.5rem;
background: var(--pattern-color); background: var(--action-message-bg);
&[dir="rtl"] { &[dir="rtl"] {
text-align: right; text-align: right;

View File

@ -451,7 +451,7 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
<Button <Button
round round
ripple={!isMobile} ripple={!isMobile}
size="smaller" size="tiny"
color="translucent" color="translucent"
className={isMenuOpen ? 'active' : ''} className={isMenuOpen ? 'active' : ''}
onClick={onTrigger} onClick={onTrigger}
@ -534,7 +534,7 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel="Cancel attachments" ariaLabel="Cancel attachments"
onClick={onClear} onClick={onClear}
iconName="close" iconName="close"

View File

@ -251,7 +251,7 @@ const PollModal = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel="Cancel poll creation" ariaLabel="Cancel poll creation"
onClick={onClear} onClick={onClear}
iconName="close" iconName="close"

View File

@ -293,7 +293,7 @@ const ToDoListModal = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={lang('AriaToDoCancel')} ariaLabel={lang('AriaToDoCancel')}
onClick={onClear} onClick={onClear}
iconName="close" iconName="close"
@ -301,7 +301,7 @@ const ToDoListModal = ({
<div className="modal-title">{lang(modalTitle)}</div> <div className="modal-title">{lang(modalTitle)}</div>
<Button <Button
color="primary" color="primary"
size="smaller" size="tiny"
className="modal-action-button" className="modal-action-button"
onClick={handleCreate} onClick={handleCreate}
> >

View File

@ -17,6 +17,7 @@ import { MESSAGE_APPEARANCE_DELAY } from '../../../config';
import { getMessageHtmlId } from '../../../global/helpers'; import { getMessageHtmlId } from '../../../global/helpers';
import { getMessageReplyInfo } from '../../../global/helpers/replies'; import { getMessageReplyInfo } from '../../../global/helpers/replies';
import { import {
selectActionMessageBg,
selectChat, selectChat,
selectChatMessage, selectChatMessage,
selectIsCurrentUserFrozen, selectIsCurrentUserFrozen,
@ -25,7 +26,6 @@ import {
selectIsMessageFocused, selectIsMessageFocused,
selectSender, selectSender,
selectTabState, selectTabState,
selectTheme,
} from '../../../global/selectors'; } from '../../../global/selectors';
import { IS_TAURI } from '../../../util/browser/globalEnvironment'; import { IS_TAURI } from '../../../util/browser/globalEnvironment';
import { IS_ANDROID, IS_FLUID_BACKGROUND_SUPPORTED } from '../../../util/browser/windowEnvironment'; import { IS_ANDROID, IS_FLUID_BACKGROUND_SUPPORTED } from '../../../util/browser/windowEnvironment';
@ -83,7 +83,7 @@ type StateProps = {
focusDirection?: FocusDirection; focusDirection?: FocusDirection;
noFocusHighlight?: boolean; noFocusHighlight?: boolean;
replyMessage?: ApiMessage; replyMessage?: ApiMessage;
patternColor?: string; actionMessageBg?: string;
isCurrentUserPremium?: boolean; isCurrentUserPremium?: boolean;
isInSelectMode?: boolean; isInSelectMode?: boolean;
hasUnreadReaction?: boolean; hasUnreadReaction?: boolean;
@ -118,7 +118,7 @@ const ActionMessage = ({
focusDirection, focusDirection,
noFocusHighlight, noFocusHighlight,
replyMessage, replyMessage,
patternColor, actionMessageBg,
isCurrentUserPremium, isCurrentUserPremium,
isInSelectMode, isInSelectMode,
hasUnreadReaction, hasUnreadReaction,
@ -245,7 +245,7 @@ const ActionMessage = ({
} }
}, [action.type, id, isLocal, memoFirstUnreadIdRef]); }, [action.type, id, isLocal, memoFirstUnreadIdRef]);
const fluidBackgroundStyle = useFluidBackgroundFilter(isFluidMultiline ? patternColor : undefined); const fluidBackgroundStyle = useFluidBackgroundFilter(isFluidMultiline ? actionMessageBg : undefined);
const handleClick = useLastCallback(() => { const handleClick = useLastCallback(() => {
switch (action.type) { switch (action.type) {
@ -515,7 +515,6 @@ const ActionMessage = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global, { message, threadId }): Complete<StateProps> => { (global, { message, threadId }): Complete<StateProps> => {
const tabState = selectTabState(global); const tabState = selectTabState(global);
const { themes } = global.settings;
const chat = selectChat(global, message.chatId); const chat = selectChat(global, message.chatId);
@ -549,7 +548,7 @@ export default memo(withGlobal<OwnProps>(
isInsideTopic, isInsideTopic,
replyMessage, replyMessage,
isInSelectMode: selectIsInSelectMode(global), isInSelectMode: selectIsInSelectMode(global),
patternColor: themes[selectTheme(global)]?.patternColor, actionMessageBg: selectActionMessageBg(global),
hasUnreadReaction, hasUnreadReaction,
isResizingContainer, isResizingContainer,
scrollTargetPosition, scrollTargetPosition,

View File

@ -19,13 +19,13 @@
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
text-transform: none; text-transform: none;
background: var(--pattern-color); background: var(--action-message-bg);
transition: background-color 150ms, color 150ms, backdrop-filter 150ms, filter 150ms; transition: background-color 150ms, color 150ms, backdrop-filter 150ms, filter 150ms;
&:hover, &:hover,
&:focus { &:focus {
background: var(--pattern-color) !important; background: var(--action-message-bg) !important;
backdrop-filter: brightness(115%); backdrop-filter: brightness(115%);
@supports not (backdrop-filter: brightness(115%)) { @supports not (backdrop-filter: brightness(115%)) {

View File

@ -719,7 +719,7 @@
border-radius: 1.125rem; border-radius: 1.125rem;
opacity: 0; opacity: 0;
background-color: var(--pattern-color); background-color: var(--action-message-bg);
transition: opacity 150ms; transition: opacity 150ms;
@ -729,6 +729,8 @@
} }
.message-action-button { .message-action-button {
width: 2.25rem;
height: 2.25rem;
color: white; color: white;
} }

View File

@ -1820,7 +1820,6 @@ const Message = ({
className="message-action-button" className="message-action-button"
color="translucent-white" color="translucent-white"
round round
size="tiny"
ariaLabel={oldLang('lng_context_forward_msg')} ariaLabel={oldLang('lng_context_forward_msg')}
onClick={isLastInDocumentGroup ? handleGroupForward : handleForward} onClick={isLastInDocumentGroup ? handleGroupForward : handleForward}
iconName="share-filled" iconName="share-filled"
@ -1831,7 +1830,6 @@ const Message = ({
className="message-action-button" className="message-action-button"
color="translucent-white" color="translucent-white"
round round
size="tiny"
ariaLabel={lang('FocusMessage')} ariaLabel={lang('FocusMessage')}
onClick={isPinnedList ? handleFocus : handleFocusForwarded} onClick={isPinnedList ? handleFocus : handleFocusForwarded}
iconName="arrow-right" iconName="arrow-right"

View File

@ -137,7 +137,7 @@
} }
.Message .custom-shape & { .Message .custom-shape & {
background: var(--pattern-color); background: var(--action-message-bg);
} }
.voice &[dir="rtl"] { .voice &[dir="rtl"] {

View File

@ -98,10 +98,10 @@
height: 1.3125rem; height: 1.3125rem;
border-radius: 0.5rem; border-radius: 0.5rem;
background: var(--pattern-color); background: var(--action-message-bg);
&:hover { &:hover {
opacity: 0.8; opacity: 0.8;
background: var(--pattern-color) !important; background: var(--action-message-bg) !important;
} }
} }

View File

@ -298,7 +298,6 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
className="message-action-button" className="message-action-button"
color="translucent-white" color="translucent-white"
round round
size="tiny"
iconName="close" iconName="close"
iconClassName="sponsored-action-icon" iconClassName="sponsored-action-icon"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
@ -309,7 +308,6 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
className="message-action-button" className="message-action-button"
color="translucent-white" color="translucent-white"
round round
size="tiny"
iconName="more" iconName="more"
iconClassName="sponsored-action-icon" iconClassName="sponsored-action-icon"
ariaLabel={lang('More')} ariaLabel={lang('More')}

View File

@ -12,7 +12,7 @@
font-size: calc(var(--message-text-size, 1rem) - 0.125rem); font-size: calc(var(--message-text-size, 1rem) - 0.125rem);
background-color: var(--pattern-color); background-color: var(--action-message-bg);
box-shadow: 0 1px 2px var(--color-default-shadow); box-shadow: 0 1px 2px var(--color-default-shadow);
@media (max-width: 600px) { @media (max-width: 600px) {

View File

@ -101,16 +101,8 @@ const CollectibleInfoModal: FC<OwnProps & StateProps> = ({
isSlim isSlim
contentClassName={styles.content} contentClassName={styles.content}
onClose={closeCollectibleInfoModal} onClose={closeCollectibleInfoModal}
hasAbsoluteCloseButton
> >
<Button
round
color="translucent"
size="smaller"
className={styles.closeButton}
ariaLabel={lang('Close')}
onClick={handleClose}
iconName="close"
/>
<div className={styles.icon}> <div className={styles.icon}>
<AnimatedIconWithPreview <AnimatedIconWithPreview
tgsUrl={isUsername ? LOCAL_TGS_URLS.Mention : LOCAL_TGS_URLS.Fragment} tgsUrl={isUsername ? LOCAL_TGS_URLS.Mention : LOCAL_TGS_URLS.Fragment}

View File

@ -1,10 +1,45 @@
.root :global(.modal-dialog) { .root {
overflow: hidden;
width: 26.25rem;
}
.title { :global(.modal-dialog) {
font-weight: var(--font-weight-medium); overflow: hidden;
width: 26.25rem;
}
:global(.modal-content) {
padding-bottom: 1rem;
padding-inline: 1rem;
}
:global(.ListItem) {
:global(.ListItem-button) {
align-items: flex-start;
padding-inline: 1.5rem;
}
:global(.ListItem-main-icon) {
margin-top: 0.875rem;
margin-right: 0.875rem;
font-size: 1.5rem;
color: var(--accent-color);
}
:global(.multiline-item .subtitle) {
margin-top: 0.125rem;
font-size: 1rem;
line-height: 1.375rem;
}
}
:global(.Checkbox-main) {
&::before,
&::after {
left: 2.25rem;
}
}
:global(.Checkbox) {
padding-inline-start: 4.5rem;
}
} }
.secondary { .secondary {
@ -32,11 +67,6 @@
background: var(--premium-gradient); background: var(--premium-gradient);
} }
.listItemIcon {
font-size: 1.875rem !important;
color: var(--accent-color) !important;
}
.content { .content {
overflow-x: hidden; overflow-x: hidden;
display: flex; display: flex;
@ -45,6 +75,15 @@
align-items: center; align-items: center;
} }
.listItem {
padding-bottom: 0.5rem;
}
.listItemTitle {
font-size: 1rem;
font-weight: var(--font-weight-medium);
}
.separator { .separator {
width: calc(100% + 2rem); // Hack to cover modal paddings width: calc(100% + 2rem); // Hack to cover modal paddings
margin-block: 1rem; margin-block: 1rem;

View File

@ -67,9 +67,9 @@ const TableAboutModal = ({
isStatic isStatic
multiline multiline
icon={icon} icon={icon}
iconClassName={styles.listItemIcon} className={styles.listItem}
> >
<span className={buildClassName('title', styles.title)}>{title}</span> <span className={buildClassName('title', styles.listItemTitle)}>{title}</span>
<span className="subtitle">{subtitle}</span> <span className="subtitle">{subtitle}</span>
</ListItem> </ListItem>
); );

View File

@ -28,7 +28,7 @@
gap: 1px; gap: 1px;
border: 1px solid var(--color-borders); border: 1px solid var(--color-borders);
border-radius: 0.3125rem; border-radius: 1rem;
background-color: var(--color-borders); background-color: var(--color-borders);
} }

View File

@ -4,13 +4,13 @@
align-items: center; align-items: center;
width: 100%; width: 100%;
margin-top: 0.5rem; margin-top: 0.125rem;
margin-bottom: 0.75rem; margin-bottom: 0.25rem;
} }
.title { .title {
padding-top: 0.5rem; padding-top: 0.25rem;
font-size: 1.25rem; font-size: 1.5rem;
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
text-align: center; text-align: center;
} }

View File

@ -29,6 +29,8 @@ type StateProps = {
freezeUntilDate?: number; freezeUntilDate?: number;
}; };
const ICON_SIZE = 130;
const FrozenAccountModal = ({ const FrozenAccountModal = ({
modal, modal,
freezeUntilDate, freezeUntilDate,
@ -58,7 +60,7 @@ const FrozenAccountModal = ({
return ( return (
<div className={styles.header}> <div className={styles.header}>
<AnimatedIconWithPreview <AnimatedIconWithPreview
size={160} size={ICON_SIZE}
tgsUrl={LOCAL_TGS_URLS.BannedDuck} tgsUrl={LOCAL_TGS_URLS.BannedDuck}
noLoop noLoop
/> />
@ -76,14 +78,12 @@ const FrozenAccountModal = ({
<Button <Button
className={styles.buttonAppeal} className={styles.buttonAppeal}
onClick={handleAppeal} onClick={handleAppeal}
noForcedUpperCase
> >
{lang('ButtonAppeal')} {lang('ButtonAppeal')}
</Button> </Button>
<Button <Button
isText isText
onClick={handleClose} onClick={handleClose}
noForcedUpperCase
> >
{lang('ButtonUnderstood')} {lang('ButtonUnderstood')}
</Button> </Button>
@ -123,7 +123,6 @@ const FrozenAccountModal = ({
header={header} header={header}
listItemData={listItemData} listItemData={listItemData}
footer={footer} footer={footer}
hasBackdrop
onClose={handleClose} onClose={handleClose}
/> />
); );

View File

@ -83,7 +83,7 @@ function GiftItemPremium({
<div className={styles.description}> <div className={styles.description}>
{lang('PremiumGiftDescription')} {lang('PremiumGiftDescription')}
</div> </div>
<Button className={styles.buy} nonInteractive size="tiny" pill fluid> <Button className={styles.buy} color="adaptive" nonInteractive size="tiny" pill fluid>
{formatCurrencyAsString(amount, currency)} {formatCurrencyAsString(amount, currency)}
</Button> </Button>
{optionByStars && ( {optionByStars && (

View File

@ -119,7 +119,11 @@
background: var(--color-background); background: var(--color-background);
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */ /* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
transition: height 0.25s ease-out, transform 0.25s ease-out; transition: height 0.25s ease-out, transform 0.25s ease-out, border-color 0.2s ease;
&.noBorder {
border-bottom-color: transparent;
}
} }
.resaleHeader { .resaleHeader {
@ -174,8 +178,8 @@
.closeButton { .closeButton {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
top: 0.375rem; top: 0.875rem;
left: 0.375rem; left: 0.875rem;
} }
.balance { .balance {
@ -209,9 +213,12 @@
} }
.logoBackground { .logoBackground {
pointer-events: none;
position: absolute; position: absolute;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
height: 7rem; height: 7rem;
} }

View File

@ -1,7 +1,7 @@
import type { FC } from '@teact'; import type { FC } from '@teact';
import { import {
memo, useEffect, useMemo, useRef, useState, memo, useEffect,
} from '@teact'; useMemo, useRef, useState } from '@teact';
import type React from '../../../lib/teact/teact'; import type React from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
@ -24,8 +24,10 @@ import { selectTabState } from '../../../global/selectors';
import { selectPeer, selectUserFullInfo } from '../../../global/selectors'; import { selectPeer, selectUserFullInfo } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { throttle } from '../../../util/schedulers'; import { throttle } from '../../../util/schedulers';
import { REM } from '../../common/helpers/mediaDimensions';
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev'; import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
import useFlag from '../../../hooks/useFlag';
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver'; import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback'; import useLastCallback from '../../../hooks/useLastCallback';
@ -74,6 +76,7 @@ const AVATAR_SIZE = 100;
const INTERSECTION_THROTTLE = 200; const INTERSECTION_THROTTLE = 200;
const SCROLL_THROTTLE = 200; const SCROLL_THROTTLE = 200;
const AVATAR_SPARKLES_CENTER_SHIFT = [0, -50] as const; const AVATAR_SPARKLES_CENTER_SHIFT = [0, -50] as const;
const CATEGORY_LIST_STICKY_TOP = 3.5 * REM;
const runThrottledForScroll = throttle((cb) => cb(), SCROLL_THROTTLE, true); const runThrottledForScroll = throttle((cb) => cb(), SCROLL_THROTTLE, true);
@ -105,6 +108,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
const dialogRef = useRef<HTMLDivElement>(); const dialogRef = useRef<HTMLDivElement>();
const transitionRef = useRef<HTMLDivElement>(); const transitionRef = useRef<HTMLDivElement>();
const giftHeaderRef = useRef<HTMLHeadingElement>(); const giftHeaderRef = useRef<HTMLHeadingElement>();
const categoryListRef = useRef<HTMLDivElement>();
const scrollerRef = useRef<HTMLDivElement>(); const scrollerRef = useRef<HTMLDivElement>();
@ -118,8 +122,8 @@ const GiftModal: FC<OwnProps & StateProps> = ({
const [shouldShowMainScreenHeader, setShouldShowMainScreenHeader] = useState(false); const [shouldShowMainScreenHeader, setShouldShowMainScreenHeader] = useState(false);
const [isMainScreenHeaderForStarGifts, setIsMainScreenHeaderForStarGifts] = useState(false); const [isMainScreenHeaderForStarGifts, setIsMainScreenHeaderForStarGifts] = useState(false);
const [isGiftScreenHeaderForStarGifts, setIsGiftScreenHeaderForStarGifts] = useState(false); const [isGiftScreenHeaderForStarGifts, setIsGiftScreenHeaderForStarGifts] = useState(false);
const [selectedCategory, setSelectedCategory] = useState<StarGiftCategory>('all'); const [selectedCategory, setSelectedCategory] = useState<StarGiftCategory>('all');
const [isCategoryListPinned, pinCategoryList, unpinCategoryList] = useFlag(false);
const triggerSparklesRef = useRef<(() => void) | undefined>(); const triggerSparklesRef = useRef<(() => void) | undefined>();
const areAllGiftsDisallowed = useMemo(() => { const areAllGiftsDisallowed = useMemo(() => {
@ -207,6 +211,17 @@ const GiftModal: FC<OwnProps & StateProps> = ({
const { top: transitionTop } = transitionRef.current.getBoundingClientRect(); const { top: transitionTop } = transitionRef.current.getBoundingClientRect();
setIsMainScreenHeaderForStarGifts(headerTop - transitionTop <= 0); setIsMainScreenHeaderForStarGifts(headerTop - transitionTop <= 0);
} }
if (categoryListRef.current && scrollerRef.current) {
const { top: listTop } = categoryListRef.current.getBoundingClientRect();
const { top: scrollerTop } = scrollerRef.current.getBoundingClientRect();
const isPinned = listTop - scrollerTop <= CATEGORY_LIST_STICKY_TOP;
if (isPinned) {
pinCategoryList();
} else {
unpinCategoryList();
}
}
}); });
}); });
@ -463,10 +478,12 @@ const GiftModal: FC<OwnProps & StateProps> = ({
{renderStarGiftsHeader()} {renderStarGiftsHeader()}
{renderStarGiftsDescription()} {renderStarGiftsDescription()}
<StarGiftCategoryList <StarGiftCategoryList
ref={categoryListRef}
areUniqueStarGiftsDisallowed={areUniqueStarGiftsDisallowed} areUniqueStarGiftsDisallowed={areUniqueStarGiftsDisallowed}
areLimitedStarGiftsDisallowed={areLimitedStarGiftsDisallowed} areLimitedStarGiftsDisallowed={areLimitedStarGiftsDisallowed}
isSelf={isSelf} isSelf={isSelf}
hasMyUnique={Boolean(myUniqueGiftIds?.length)} hasMyUnique={Boolean(myUniqueGiftIds?.length)}
isPinned={isCategoryListPinned}
onCategoryChanged={onCategoryChanged} onCategoryChanged={onCategoryChanged}
/> />
<Transition <Transition
@ -537,7 +554,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
className={styles.closeButton} className={styles.closeButton}
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
onClick={handleCloseButtonClick} onClick={handleCloseButtonClick}
ariaLabel={isBackButton ? oldLang('Common.Back') : oldLang('Common.Close')} ariaLabel={isBackButton ? oldLang('Common.Back') : oldLang('Common.Close')}
> >
@ -547,7 +564,8 @@ const GiftModal: FC<OwnProps & StateProps> = ({
<div className={buildClassName( <div className={buildClassName(
styles.header, styles.header,
isResaleScreen && styles.resaleHeader, isResaleScreen && styles.resaleHeader,
!shouldShowHeader && styles.hiddenHeader)} !shouldShowHeader && styles.hiddenHeader,
isCategoryListPinned && styles.noBorder)}
> >
<Transition <Transition
name="slideVerticalFade" name="slideVerticalFade"

View File

@ -1,7 +1,7 @@
@use '../../../styles/mixins';
.list { .list {
position: sticky;
z-index: 1; z-index: 1;
top: 3.5rem;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
@ -16,16 +16,21 @@
margin-left: -0.5rem; margin-left: -0.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
padding-block: 0.25rem; padding-block: 0.25rem;
border-bottom: 0.0625rem solid transparent;
font-size: 0.875rem; font-size: 0.875rem;
background-color: var(--color-background); background-color: var(--color-background);
transition: border-color 0.2s ease;
:global(html.theme-dark) & { :global(html.theme-dark) & {
background-color: #181818; background-color: #181818;
} }
@include mixins.gradient-border-horizontal(0.5rem, 0.5rem); &.pinned {
border-bottom-color: var(--color-borders);
}
} }
.item-selected, .item-selected,

View File

@ -1,3 +1,4 @@
import type { ElementRef } from '../../../lib/teact/teact';
import { import {
memo, useRef, useState, memo, useRef, useState,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
@ -13,10 +14,12 @@ import useLang from '../../../hooks/useLang';
import styles from './StarGiftCategoryList.module.scss'; import styles from './StarGiftCategoryList.module.scss';
type OwnProps = { type OwnProps = {
ref?: ElementRef<HTMLDivElement>;
areUniqueStarGiftsDisallowed?: boolean; areUniqueStarGiftsDisallowed?: boolean;
areLimitedStarGiftsDisallowed?: boolean; areLimitedStarGiftsDisallowed?: boolean;
isSelf?: boolean; isSelf?: boolean;
hasMyUnique?: boolean; hasMyUnique?: boolean;
isPinned?: boolean;
onCategoryChanged: (category: StarGiftCategory) => void; onCategoryChanged: (category: StarGiftCategory) => void;
}; };
@ -25,14 +28,19 @@ type StateProps = {
}; };
const StarGiftCategoryList = ({ const StarGiftCategoryList = ({
ref: externalRef,
idsByCategory, idsByCategory,
onCategoryChanged, onCategoryChanged,
areUniqueStarGiftsDisallowed, areUniqueStarGiftsDisallowed,
areLimitedStarGiftsDisallowed, areLimitedStarGiftsDisallowed,
isSelf, isSelf,
hasMyUnique, hasMyUnique,
isPinned,
}: StateProps & OwnProps) => { }: StateProps & OwnProps) => {
const ref = useRef<HTMLDivElement>(); let ref = useRef<HTMLDivElement>();
if (externalRef) {
ref = externalRef;
}
const lang = useLang(); const lang = useLang();
@ -42,9 +50,7 @@ const StarGiftCategoryList = ({
function handleItemClick(category: StarGiftCategory) { function handleItemClick(category: StarGiftCategory) {
setSelectedCategory(category); setSelectedCategory(category);
onCategoryChanged( onCategoryChanged(category);
category,
);
} }
function renderCategoryName(category: StarGiftCategory) { function renderCategoryName(category: StarGiftCategory) {
@ -71,7 +77,7 @@ const StarGiftCategoryList = ({
useHorizontalScroll(ref, undefined, true); useHorizontalScroll(ref, undefined, true);
return ( return (
<div ref={ref} className={buildClassName(styles.list, 'no-scrollbar')}> <div ref={ref} className={buildClassName(styles.list, isPinned && styles.pinned, 'no-scrollbar')}>
{renderCategoryItem('all')} {renderCategoryItem('all')}
{!areUniqueStarGiftsDisallowed && !isSelf && hasMyUnique && renderCategoryItem('myUnique')} {!areUniqueStarGiftsDisallowed && !isSelf && hasMyUnique && renderCategoryItem('myUnique')}
{(!areUniqueStarGiftsDisallowed || !areLimitedStarGiftsDisallowed) {(!areUniqueStarGiftsDisallowed || !areLimitedStarGiftsDisallowed)

View File

@ -12,15 +12,22 @@
padding-bottom: 1rem; padding-bottom: 1rem;
&.withManageButtons { &.withManageButtons {
--_height: 18.5rem; --_height: 19.25rem;
.sticker { .sticker {
margin-top: 2.5rem; margin-top: 2.625rem;
}
:global {
canvas {
transform-origin: center 32%;
}
} }
} }
:global { :global {
canvas { canvas {
transform-origin: center 45%;
transition: 250ms transform; transition: 250ms transform;
} }
} }
@ -48,7 +55,7 @@
.radialPattern { .radialPattern {
position: absolute; position: absolute;
z-index: -1; z-index: -1;
inset: 0; inset: -5%;
} }
.amount { .amount {
@ -65,7 +72,7 @@
} }
.sticker { .sticker {
margin-top: 2rem; margin-top: 2.875rem;
} }
.transition { .transition {
@ -83,14 +90,16 @@
.title { .title {
margin-top: auto; margin-top: auto;
font-size: 1.25rem;
font-size: 1.5rem;
font-weight: var(--font-weight-semibold);
line-height: 1.75rem;
color: white; color: white;
} }
.subtitle { .subtitle {
max-width: 85%; font-size: 1rem;
line-height: 1.375rem;
font-size: 0.875rem;
text-align: center; text-align: center;
text-wrap: balance; text-wrap: balance;

View File

@ -17,6 +17,7 @@ import buildStyle from '../../../util/buildStyle';
import { REM } from '../../common/helpers/mediaDimensions.ts'; import { REM } from '../../common/helpers/mediaDimensions.ts';
import { useTransitionActiveKey } from '../../../hooks/animations/useTransitionActiveKey'; import { useTransitionActiveKey } from '../../../hooks/animations/useTransitionActiveKey';
import useAppLayout from '../../../hooks/useAppLayout';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
@ -60,6 +61,8 @@ const UniqueGiftHeader = ({
openChat, openChat,
} = getActions(); } = getActions();
const { isMobile } = useAppLayout();
const lang = useLang(); const lang = useLang();
const [isGiftHover, markGiftHover, unmarkGiftHover] = useFlag(false); const [isGiftHover, markGiftHover, unmarkGiftHover] = useFlag(false);
const activeKey = useTransitionActiveKey([modelAttribute, backdropAttribute, patternAttribute]); const activeKey = useTransitionActiveKey([modelAttribute, backdropAttribute, patternAttribute]);
@ -71,16 +74,20 @@ const UniqueGiftHeader = ({
return ( return (
<RadialPatternBackground <RadialPatternBackground
className={styles.radialPattern} className={styles.radialPattern}
canvasClassName={styles.radialPatternCanvas}
backgroundColors={backdropColors} backgroundColors={backdropColors}
patternIcon={patternAttribute.sticker} patternIcon={patternAttribute.sticker}
yPosition={6.5 * REM} yPosition={7.5 * REM}
maxRadius={0.26}
patternSize={isMobile ? 14 : 16}
ovalFactor={1.2}
/> />
); );
}, [backdropAttribute, patternAttribute]); }, [backdropAttribute, patternAttribute, isMobile]);
return ( return (
<div className={buildClassName(styles.root, <div className={buildClassName(styles.root,
isGiftHover && 'interactive-gift', 'interactive-gift',
showManageButtons && styles.withManageButtons, showManageButtons && styles.withManageButtons,
className)} className)}
> >

View File

@ -5,7 +5,7 @@
gap: 0.5rem; gap: 0.5rem;
width: 100%; width: 100%;
margin-top: 1rem; margin-top: 0.375rem;
} }
.manageButton { .manageButton {

View File

@ -63,31 +63,44 @@
backdrop-filter: blur(0.5rem); backdrop-filter: blur(0.5rem);
} }
.headerButton, .moreMenuButton {
position: absolute;
z-index: 1;
top: 0.875rem;
right: 0.875rem;
}
.closeButton {
position: absolute;
z-index: 1;
top: 0.875rem;
left: 0.875rem;
}
.giftResalePriceContainer { .giftResalePriceContainer {
pointer-events: auto; pointer-events: auto;
position: absolute;
top: 0.875rem;
right: 3.25rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: fit-content; width: fit-content;
height: 1.75rem; height: 1.875rem;
padding: 0.25rem; padding: 0.25rem;
padding-inline: 0.625rem; padding-inline: 0.625rem;
border-radius: 1rem; border-radius: 1rem;
font-size: 1rem; font-size: 0.875rem;
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
color: white; color: white;
background-color: rgba(0, 0, 0, 0.2); background-color: rgba(255, 255, 255, 0.1);
outline: none !important;
}
.giftResalePriceContainer {
font-size: 0.75rem;
backdrop-filter: blur(25px); backdrop-filter: blur(25px);
outline: none !important;
} }
.starAmountIcon, .starAmountIcon,
@ -137,6 +150,24 @@
text-align: center; text-align: center;
} }
.footerHint {
display: flex;
align-items: center;
font-size: 0.75rem;
line-height: 1.125rem;
color: var(--color-white);
text-align: center;
text-transform: none;
opacity: 0.6;
}
.buyButton {
display: flex;
flex-direction: column;
}
.unknown { .unknown {
margin-inline-start: 0.25rem; margin-inline-start: 0.25rem;
} }

View File

@ -108,7 +108,7 @@ const GiftInfoModal = ({
const [isConfirmModalOpen, setIsConfirmModalOpen] = useState<boolean>(false); const [isConfirmModalOpen, setIsConfirmModalOpen] = useState<boolean>(false);
const [shouldPayInTon, setShouldPayInTon] = useState<boolean>(false); const [shouldPayInTon, setShouldPayInTon] = useState<boolean>(false);
const splitButtonRef = useRef<HTMLDivElement>(); const moreButtonRef = useRef<HTMLButtonElement>();
const menuRef = useRef<HTMLDivElement>(); const menuRef = useRef<HTMLDivElement>();
const uniqueGiftHeaderRef = useRef<HTMLDivElement>(); const uniqueGiftHeaderRef = useRef<HTMLDivElement>();
const { const {
@ -117,7 +117,7 @@ const GiftInfoModal = ({
handleContextMenu, handleContextMenu,
handleContextMenuClose, handleContextMenuClose,
handleContextMenuHide, handleContextMenuHide,
} = useContextMenuHandlers(splitButtonRef); } = useContextMenuHandlers(moreButtonRef);
const handleSymbolClick = useLastCallback(() => { const handleSymbolClick = useLastCallback(() => {
if (!gift || !giftAttributes?.pattern) return; if (!gift || !giftAttributes?.pattern) return;
@ -245,6 +245,9 @@ const GiftInfoModal = ({
const resellPrice = getResalePrice(); const resellPrice = getResalePrice();
const confirmPrice = getResalePrice(shouldPayInTon); const confirmPrice = getResalePrice(shouldPayInTon);
const resellPriceInStars = resellPrice?.currency === TON_CURRENCY_CODE && isGiftUnique
? gift.resellPrice?.find((amount) => amount.currency === STARS_CURRENCY_CODE)
: undefined;
const canBuyGift = !isSelfUnique && gift?.type === 'starGiftUnique' const canBuyGift = !isSelfUnique && gift?.type === 'starGiftUnique'
&& gift.ownerId !== currentUserId && Boolean(resellPrice); && gift.ownerId !== currentUserId && Boolean(resellPrice);
@ -330,37 +333,24 @@ const GiftInfoModal = ({
return gift && getGiftAttributes(gift); return gift && getGiftAttributes(gift);
}, [gift]); }, [gift]);
const SettingsMenuButton = useMemo(() => {
return (
<div
className={buildClassName(
styles.headerButton,
styles.left,
)}
tabIndex={0}
role="button"
aria-haspopup="menu"
aria-label={lang('AriaMoreButton')}
onContextMenu={handleContextMenu}
onClick={handleContextMenu}
>
<Icon
name="more"
className={styles.icon}
/>
</div>
);
}, [lang, handleContextMenu]);
const renderFooterButton = useLastCallback(() => { const renderFooterButton = useLastCallback(() => {
if (canBuyGift) { if (canBuyGift) {
return ( return (
<Button noForcedUpperCase onClick={handleBuyGift}> <Button className={styles.buyButton} onClick={handleBuyGift}>
{lang('ButtonBuyGift', { <div>
stars: resellPrice?.currency === TON_CURRENCY_CODE {lang('ButtonBuyGift', {
? formatTonAsIcon(lang, resellPrice.amount, { shouldConvertFromNanos: true }) stars: resellPrice?.currency === TON_CURRENCY_CODE
: formatStarsAsIcon(lang, resellPrice?.amount, { asFont: true }), ? formatTonAsIcon(lang, resellPrice.amount, { shouldConvertFromNanos: true })
}, { withNodes: true })} : formatStarsAsIcon(lang, resellPrice?.amount, { asFont: true }),
}, { withNodes: true })}
</div>
{resellPrice?.currency === TON_CURRENCY_CODE && Boolean(resellPriceInStars) && (
<div className={styles.footerHint}>
{lang('GiftBuyEqualsTo', {
stars: formatStarsAsIcon(lang, resellPriceInStars.amount, { asFont: true }),
}, { withNodes: true })}
</div>
)}
</Button> </Button>
); );
} }
@ -536,6 +526,30 @@ const GiftInfoModal = ({
<div <div
className={styles.modalHeader} className={styles.modalHeader}
> >
<Button
className={styles.closeButton}
round
color="translucent-white"
size="tiny"
iconName="close"
ariaLabel={lang('Close')}
onClick={handleClose}
/>
<Button
ref={moreButtonRef}
className={styles.moreMenuButton}
round
color="translucent-white"
size="tiny"
iconName="more"
aria-haspopup="menu"
aria-label={lang('AriaMoreButton')}
onContextMenu={handleContextMenu}
onClick={handleContextMenu}
/>
{Boolean(resellPrice?.amount) && ( {Boolean(resellPrice?.amount) && (
<div className={styles.giftResalePriceContainer}> <div className={styles.giftResalePriceContainer}>
{resellPrice.currency === TON_CURRENCY_CODE {resellPrice.currency === TON_CURRENCY_CODE
@ -549,28 +563,6 @@ const GiftInfoModal = ({
})} })}
</div> </div>
)} )}
<div className={styles.headerSplitButton} ref={splitButtonRef}>
{SettingsMenuButton}
<div
className={buildClassName(
styles.headerButton,
styles.right,
)}
tabIndex={0}
role="button"
aria-haspopup="menu"
aria-label={lang('Close')}
onClick={handleClose}
>
<Icon
name="close"
className={buildClassName(
styles.icon,
styles.moreIcon,
)}
/>
</div>
</div>
</div> </div>
); );
@ -883,13 +875,14 @@ const GiftInfoModal = ({
typeGift, savedGift, renderingTargetPeer, giftSticker, lang, typeGift, savedGift, renderingTargetPeer, giftSticker, lang,
canManage, hasConvertOption, isSender, oldLang, tonExplorerUrl, canManage, hasConvertOption, isSender, oldLang, tonExplorerUrl,
gift, giftAttributes, renderFooterButton, isTargetChat, gift, giftAttributes, renderFooterButton, isTargetChat,
SettingsMenuButton, isGiftUnique, saleDateInfo, isGiftUnique, saleDateInfo,
canBuyGift, giftOwnerTitle, resellPrice, giftSubtitle, canBuyGift, giftOwnerTitle, resellPrice, giftSubtitle,
releasedByPeer, handleSymbolClick, handleBackdropClick, handleModelClick, releasedByPeer, handleSymbolClick, handleBackdropClick, handleModelClick,
handleContextMenu,
]); ]);
const getRootElement = useLastCallback(() => uniqueGiftHeaderRef.current); const getRootElement = useLastCallback(() => uniqueGiftHeaderRef.current);
const getTriggerElement = useLastCallback(() => splitButtonRef.current); const getTriggerElement = useLastCallback(() => moreButtonRef.current);
const getMenuElement = useLastCallback(() => menuRef.current); const getMenuElement = useLastCallback(() => menuRef.current);
const getLayout = useLastCallback(() => ({ withPortal: true })); const getLayout = useLastCallback(() => ({ withPortal: true }));

View File

@ -28,7 +28,7 @@
} }
.avatar { .avatar {
margin-top: 2rem; margin-top: 2.375rem;
} }
.userTitle { .userTitle {
@ -36,7 +36,7 @@
width: 100%; width: 100%;
margin-top: auto; margin-top: auto;
padding-top: 1rem; padding-top: 1.75rem;
font-size: 1.25rem; font-size: 1.25rem;
color: white; color: white;

View File

@ -11,6 +11,7 @@ import buildClassName from '../../../../util/buildClassName';
import buildStyle from '../../../../util/buildStyle'; import buildStyle from '../../../../util/buildStyle';
import { REM } from '../../../common/helpers/mediaDimensions'; import { REM } from '../../../common/helpers/mediaDimensions';
import useAppLayout from '../../../../hooks/useAppLayout';
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev'; import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
import useLang from '../../../../hooks/useLang'; import useLang from '../../../../hooks/useLang';
import useLastCallback from '../../../../hooks/useLastCallback'; import useLastCallback from '../../../../hooks/useLastCallback';
@ -34,6 +35,8 @@ type StateProps = {
isCurrentUserPremium?: boolean; isCurrentUserPremium?: boolean;
}; };
const AVATAR_SIZE = 7 * REM;
const GiftStatusInfoModal = ({ const GiftStatusInfoModal = ({
modal, modal,
currentUser, currentUser,
@ -44,6 +47,8 @@ const GiftStatusInfoModal = ({
setEmojiStatus, setEmojiStatus,
} = getActions(); } = getActions();
const lang = useLang(); const lang = useLang();
const { isMobile } = useAppLayout();
const isOpen = Boolean(modal); const isOpen = Boolean(modal);
const renderingModal = useCurrentOrPrev(modal); const renderingModal = useCurrentOrPrev(modal);
@ -74,10 +79,13 @@ const GiftStatusInfoModal = ({
className={styles.radialPattern} className={styles.radialPattern}
backgroundColors={backdropColors} backgroundColors={backdropColors}
patternIcon={patternIcon.customEmoji} patternIcon={patternIcon.customEmoji}
yPosition={6.5 * REM} yPosition={6.875 * REM}
maxRadius={0.31}
patternSize={isMobile ? 13 : 15}
ovalFactor={1}
/> />
); );
}, [emojiStatus, isOpen, patternIcon]); }, [emojiStatus, isOpen, isMobile, patternIcon]);
const mockPeerWithStatus = useMemo(() => { const mockPeerWithStatus = useMemo(() => {
return { return {
@ -95,7 +103,7 @@ const GiftStatusInfoModal = ({
> >
{radialPatternBackdrop} {radialPatternBackdrop}
<Avatar peer={mockPeerWithStatus} size="jumbo" className={styles.avatar} /> <Avatar peer={mockPeerWithStatus} size={AVATAR_SIZE} className={styles.avatar} />
<FullNameTitle <FullNameTitle
peer={mockPeerWithStatus} peer={mockPeerWithStatus}
className={styles.userTitle} className={styles.userTitle}

View File

@ -1,33 +1,3 @@
.content {
:global(.ListItem-main-icon) {
margin-top: 0.6875rem !important;
margin-right: 0.625rem !important;
font-size: 1.875rem !important;
}
:global(.ListItem-button) {
align-items: flex-start;
padding-inline: 2rem;
}
:global(.modal-content) {
padding-bottom: 1rem;
padding-inline: 1rem;
}
:global(.ListItem) {
padding-bottom: 0.5rem;
:global(.title) {
font-size: 0.9375rem;
}
:global(.subtitle) {
margin-top: 0.125rem;
}
}
}
.header { .header {
width: 100%; width: 100%;
padding-top: 0; padding-top: 0;
@ -77,17 +47,13 @@
} }
.ratingProgress { .ratingProgress {
margin: 4.5rem auto 1.5rem; margin: 4.75rem auto 1.5rem;
&.withPreview { &.withPreview {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
} }
.subtitle {
line-height: 1.375rem;
}
.footer { .footer {
display: flex; display: flex;
align-self: stretch; align-self: stretch;

View File

@ -193,19 +193,19 @@ const ProfileRatingModal = ({
const listItemData = [ const listItemData = [
['closed-gift', lang('RatingGiftsFromTelegram'), ( ['closed-gift', lang('RatingGiftsFromTelegram'), (
<span className={styles.subtitle}> <span>
{renderBadge('added')} {renderBadge('added')}
{lang('RatingGiftsFromTelegramDesc')} {lang('RatingGiftsFromTelegramDesc')}
</span> </span>
)], )],
['user-stars', lang('RatingGiftsAndPostsFromUsers'), ( ['user-stars', lang('RatingGiftsAndPostsFromUsers'), (
<span className={styles.subtitle}> <span>
{renderBadge('added')} {renderBadge('added')}
{lang('RatingGiftsAndPostsFromUsersDesc')} {lang('RatingGiftsAndPostsFromUsersDesc')}
</span> </span>
)], )],
['stars-refund', lang('RatingRefundsAndConversions'), ( ['stars-refund', lang('RatingRefundsAndConversions'), (
<span className={styles.subtitle}> <span>
{renderBadge('deducted')} {renderBadge('deducted')}
{lang('RatingRefundsAndConversionsDesc')} {lang('RatingRefundsAndConversionsDesc')}
</span> </span>

View File

@ -21,8 +21,8 @@
.closeButton { .closeButton {
position: absolute !important; position: absolute !important;
top: 0.5rem; top: 0.875rem;
right: 0.5rem; right: 0.875rem;
} }
.markAsReadButton { .markAsReadButton {

View File

@ -84,7 +84,7 @@ const QuickPreviewModalHeader: FC<OwnProps & StateProps> = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
onClick={onClose} onClick={onClose}
className={styles.closeButton} className={styles.closeButton}

View File

@ -82,7 +82,7 @@ const ReportAdModal = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={lang(renderingDepth ? 'Back' : 'Close')} ariaLabel={lang(renderingDepth ? 'Back' : 'Close')}
onClick={handleBackClick} onClick={handleBackClick}
iconName={renderingDepth ? 'arrow-left' : 'close'} iconName={renderingDepth ? 'arrow-left' : 'close'}

View File

@ -86,7 +86,7 @@ const ReportModal = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={lang('Back')} ariaLabel={lang('Back')}
onClick={handleBackClick} onClick={handleBackClick}
iconName="arrow-left" iconName="arrow-left"
@ -95,7 +95,7 @@ const ReportModal = ({
<Button <Button
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
onClick={handleCloseClick} onClick={handleCloseClick}
iconName="close" iconName="close"

View File

@ -60,7 +60,6 @@
color: var(--color-primary); color: var(--color-primary);
} }
.hint,
.tos { .tos {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
padding-top: 0; padding-top: 0;
@ -72,8 +71,9 @@
} }
.hint { .hint {
padding-block: 0.5rem; margin-block: 0.25rem;
padding-inline: 1.5rem; font-size: 0.9375rem;
color: var(--color-text-secondary);
} }
.topUpButton, .topUpButton,
@ -140,7 +140,7 @@
background: var(--color-background); background: var(--color-background);
transition: 0.25s ease-out transform; transition: 0.25s ease-out transform, 0.25s ease-out border-bottom-color;
} }
.starHeaderText { .starHeaderText {
@ -158,11 +158,15 @@
transform: translateY(-100%); transform: translateY(-100%);
} }
.noSeparator {
border-bottom-color: transparent;
}
.closeButton { .closeButton {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
top: 0.5rem; top: 0.875rem;
left: 0.5rem; left: 0.875rem;
} }
.addStarsButton { .addStarsButton {
@ -294,6 +298,7 @@
// Disable tabs rounded corners // Disable tabs rounded corners
--border-radius-messages-small: 0; --border-radius-messages-small: 0;
z-index: 1;
top: 3.5rem; top: 3.5rem;
padding-inline: 0; padding-inline: 0;
} }

View File

@ -1,4 +1,4 @@
import { memo, useEffect, useMemo, useState } from '@teact'; import { memo, useEffect, useMemo, useRef, useState } from '@teact';
import { getActions, getGlobal, withGlobal } from '../../../global'; import { getActions, getGlobal, withGlobal } from '../../../global';
import type { ApiStarTopupOption } from '../../../api/types'; import type { ApiStarTopupOption } from '../../../api/types';
@ -18,6 +18,7 @@ import { selectSharedSettings } from '../../../global/selectors/sharedState.ts';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { convertCurrencyFromBaseUnit, convertTonToUsd, formatCurrencyAsString } from '../../../util/formatCurrency'; import { convertCurrencyFromBaseUnit, convertTonToUsd, formatCurrencyAsString } from '../../../util/formatCurrency';
import { resolveTransitionName } from '../../../util/resolveTransitionName.ts'; import { resolveTransitionName } from '../../../util/resolveTransitionName.ts';
import { REM } from '../../common/helpers/mediaDimensions';
import renderText from '../../common/helpers/renderText'; import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
@ -40,6 +41,7 @@ import StarsTransactionItem from './transaction/StarsTransactionItem';
import styles from './StarsBalanceModal.module.scss'; import styles from './StarsBalanceModal.module.scss';
const HEADER_HEIGHT = 3.5 * REM;
const TRANSACTION_TYPES = ['all', 'inbound', 'outbound'] as const; const TRANSACTION_TYPES = ['all', 'inbound', 'outbound'] as const;
const TRANSACTION_TABS_KEYS: RegularLangKey[] = [ const TRANSACTION_TABS_KEYS: RegularLangKey[] = [
'StarsTransactionsAll', 'StarsTransactionsAll',
@ -80,9 +82,12 @@ const StarsBalanceModal = ({
const lang = useLang(); const lang = useLang();
const [isHeaderHidden, setHeaderHidden] = useState(true); const [isHeaderHidden, setHeaderHidden] = useState(true);
const [areTabsPinned, pinTabs, unpinTabs] = useFlag(false);
const [selectedTabIndex, setSelectedTabIndex] = useState(0); const [selectedTabIndex, setSelectedTabIndex] = useState(0);
const [areBuyOptionsShown, showBuyOptions, hideBuyOptions] = useFlag(); const [areBuyOptionsShown, showBuyOptions, hideBuyOptions] = useFlag();
const tabsRef = useRef<HTMLDivElement>();
const isOpen = Boolean(modal && (starsBalanceState || tonBalanceState)); const isOpen = Boolean(modal && (starsBalanceState || tonBalanceState));
const { const {
@ -160,6 +165,7 @@ const StarsBalanceModal = ({
setHeaderHidden(true); setHeaderHidden(true);
setSelectedTabIndex(0); setSelectedTabIndex(0);
hideBuyOptions(); hideBuyOptions();
unpinTabs();
} }
}, [isOpen]); }, [isOpen]);
@ -261,6 +267,12 @@ const StarsBalanceModal = ({
> >
{lang('ButtonTopUpViaFragment')} {lang('ButtonTopUpViaFragment')}
</Button> </Button>
{currency === TON_CURRENCY_CODE && (
<div className={styles.hint}>
{lang('TonModalHint')}
</div>
)}
</> </>
); );
}; };
@ -269,6 +281,17 @@ const StarsBalanceModal = ({
const { scrollTop } = e.currentTarget; const { scrollTop } = e.currentTarget;
setHeaderHidden(scrollTop <= 150); setHeaderHidden(scrollTop <= 150);
if (tabsRef.current) {
const { top: tabsTop } = tabsRef.current.getBoundingClientRect();
const { top: scrollerTop } = e.currentTarget.getBoundingClientRect();
const isPinned = tabsTop - scrollerTop <= HEADER_HEIGHT;
if (isPinned) {
pinTabs();
} else {
unpinTabs();
}
}
} }
const handleLoadMoreTransactions = useLastCallback(() => { const handleLoadMoreTransactions = useLastCallback(() => {
@ -305,19 +328,15 @@ const StarsBalanceModal = ({
isOpen={isOpen} isOpen={isOpen}
onClose={closeStarsBalanceModal} onClose={closeStarsBalanceModal}
dialogStyle={`--modal-height: ${modalHeight}`} dialogStyle={`--modal-height: ${modalHeight}`}
hasAbsoluteCloseButton
> >
<div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}> <div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
<Button
round
size="smaller"
className={styles.closeButton}
color="translucent"
onClick={() => closeStarsBalanceModal()}
ariaLabel={lang('Close')}
iconName="close"
/>
{currency !== TON_CURRENCY_CODE && <BalanceBlock balance={balance} className={styles.modalBalance} />} {currency !== TON_CURRENCY_CODE && <BalanceBlock balance={balance} className={styles.modalBalance} />}
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}> <div
className={buildClassName(
styles.header, isHeaderHidden && styles.hiddenHeader, areTabsPinned && styles.noSeparator,
)}
>
<h2 className={styles.starHeaderText}> <h2 className={styles.starHeaderText}>
{oldLang('TelegramStars')} {oldLang('TelegramStars')}
</h2> </h2>
@ -330,11 +349,6 @@ const StarsBalanceModal = ({
{tosText} {tosText}
</div> </div>
)} )}
{currency === TON_CURRENCY_CODE && (
<div className={styles.hint}>
{lang('TonModalHint')}
</div>
)}
{shouldShowItems && Boolean(subscriptions?.list.length) && ( {shouldShowItems && Boolean(subscriptions?.list.length) && (
<div className={styles.section}> <div className={styles.section}>
<h3 className={styles.sectionTitle}>{oldLang('StarMySubscriptions')}</h3> <h3 className={styles.sectionTitle}>{oldLang('StarMySubscriptions')}</h3>
@ -391,6 +405,7 @@ const StarsBalanceModal = ({
</Transition> </Transition>
</div> </div>
<TabList <TabList
ref={tabsRef}
className={styles.tabs} className={styles.tabs}
tabClassName={styles.tab} tabClassName={styles.tab}
activeTab={selectedTabIndex} activeTab={selectedTabIndex}

View File

@ -92,8 +92,8 @@
.closeButton { .closeButton {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
top: 0.5rem; top: 0.875rem;
left: 0.5rem; left: 0.875rem;
} }
.avatar { .avatar {

View File

@ -25,7 +25,6 @@ import useOldLang from '../../../../hooks/useOldLang';
import Avatar from '../../../common/Avatar'; import Avatar from '../../../common/Avatar';
import SafeLink from '../../../common/SafeLink'; import SafeLink from '../../../common/SafeLink';
import Button from '../../../ui/Button';
import Modal from '../../../ui/Modal'; import Modal from '../../../ui/Modal';
import StarTopupOptionList from '../StarTopupOptionList'; import StarTopupOptionList from '../StarTopupOptionList';
@ -154,17 +153,9 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
isSlim isSlim
onClose={handleClose} onClose={handleClose}
isOpen={isOpen} isOpen={isOpen}
hasAbsoluteCloseButton
> >
<div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}> <div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
<Button
round
size="smaller"
className={styles.closeButton}
color="translucent"
onClick={() => closeStarsGiftModal()}
ariaLabel={oldLang('Close')}
iconName="close"
/>
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}> <div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
<h2 className={styles.starHeaderText}> <h2 className={styles.starHeaderText}>
{user ? oldLang('GiftStarsTitle') : oldLang('Star.List.GetStars')} {user ? oldLang('GiftStarsTitle') : oldLang('Star.List.GetStars')}

View File

@ -157,7 +157,7 @@
.modal-header { .modal-header {
padding: 0; padding: 0;
padding-inline: 0.5rem; padding-inline: 0.875rem;
border-bottom: 0; border-bottom: 0;
} }

View File

@ -378,7 +378,7 @@ function StorySettings({
className={buildClassName(styles.closeButton, 'close-button')} className={buildClassName(styles.closeButton, 'close-button')}
round round
color="translucent" color="translucent"
size="smaller" size="tiny"
onClick={handleCloseButtonClick} onClick={handleCloseButtonClick}
ariaLabel={isBackButton ? lang('Common.Back') : lang('Common.Close')} ariaLabel={isBackButton ? lang('Common.Back') : lang('Common.Close')}
> >

View File

@ -151,7 +151,7 @@ function StoryViewer({
<Button <Button
className={styles.close} className={styles.close}
round round
size="smaller" size="tiny"
color="translucent-white" color="translucent-white"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
onClick={handleClose} onClick={handleClose}

View File

@ -41,7 +41,7 @@
height: 3rem; height: 3rem;
padding: 0.625rem; padding: 0.625rem;
border: 0; border: 0;
border-radius: var(--border-radius-default); border-radius: var(--border-radius-button);
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
line-height: 1.2; line-height: 1.2;
@ -53,7 +53,7 @@
background-size: cover; background-size: cover;
outline: none !important; outline: none !important;
transition: background-color 0.15s, color 0.15s, opacity 0.15s; transition: background-color 0.2s, color 0.2s, opacity 0.2s;
white-space-collapse: preserve; white-space-collapse: preserve;
@ -91,7 +91,7 @@
background-color: var(--color-primary); background-color: var(--color-primary);
@include active-styles() { @include active-styles() {
background-color: var(--color-primary-shade); background-color: rgba(var(--color-primary-shade-rgb), 0.9);
} }
@include no-ripple-styles() { @include no-ripple-styles() {
@ -331,11 +331,11 @@
&.transparentBlured { &.transparentBlured {
color: white; color: white;
background-color: rgba(0, 0, 0, 0.2); background-color: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(0.5rem); backdrop-filter: blur(0.5rem);
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(255, 255, 255, 0.2);
} }
} }
@ -366,12 +366,12 @@
&.tiny { &.tiny {
height: 2.25rem; height: 2.25rem;
padding: 0.4375rem; padding: 0.4375rem;
border-radius: var(--border-radius-default-small); border-radius: var(--border-radius-button-tiny);
font-size: 0.875rem; font-size: 0.875rem;
&.round { &.round {
width: 2.25rem; width: 1.875rem;
height: 2.25rem; height: 1.875rem;
border-radius: 50%; border-radius: 50%;
} }

View File

@ -140,7 +140,8 @@
.modal-header-condensed { .modal-header-condensed {
@extend %modal-header; @extend %modal-header;
padding: 0.375rem 0.5rem !important; min-height: 3.5rem;
padding: 0.375rem 0.75rem !important;
.modal-action-button { .modal-action-button {
width: auto; width: auto;
@ -242,8 +243,8 @@
.modal-absolute-close-button { .modal-absolute-close-button {
position: absolute; position: absolute;
z-index: 1; z-index: 3;
top: 0.375rem; top: 0.875rem;
left: 0.375rem; left: 0.875rem;
} }
} }

View File

@ -149,7 +149,7 @@ const Modal: FC<OwnProps> = ({
className={buildClassName(hasAbsoluteCloseButton && 'modal-absolute-close-button')} className={buildClassName(hasAbsoluteCloseButton && 'modal-absolute-close-button')}
round round
color={absoluteCloseButtonColor} color={absoluteCloseButtonColor}
size="smaller" size="tiny"
iconName="close" iconName="close"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
onClick={onClose} onClick={onClose}

View File

@ -1,4 +1,4 @@
import type { TeactNode } from '../../lib/teact/teact'; import type { ElementRef, TeactNode } from '../../lib/teact/teact';
import { memo, useEffect, useRef } from '../../lib/teact/teact'; import { memo, useEffect, useRef } from '../../lib/teact/teact';
import type { ApiMessageEntityCustomEmoji } from '../../api/types'; import type { ApiMessageEntityCustomEmoji } from '../../api/types';
@ -33,6 +33,7 @@ type OwnProps = {
className?: string; className?: string;
tabClassName?: string; tabClassName?: string;
contextRootElementSelector?: string; contextRootElementSelector?: string;
ref?: ElementRef<HTMLDivElement>;
onSwitchTab: (index: number) => void; onSwitchTab: (index: number) => void;
}; };
@ -46,9 +47,13 @@ const TabList = ({
className, className,
tabClassName, tabClassName,
contextRootElementSelector, contextRootElementSelector,
ref,
onSwitchTab, onSwitchTab,
}: OwnProps) => { }: OwnProps) => {
const containerRef = useRef<HTMLDivElement>(); let containerRef = useRef<HTMLDivElement>();
if (ref) {
containerRef = ref;
}
const previousActiveTab = usePreviousDeprecated(activeTab); const previousActiveTab = usePreviousDeprecated(activeTab);
const lang = useLang(); const lang = useLang();

View File

@ -372,7 +372,7 @@ export const BOT_VERIFICATION_PEERS_LIMIT = 20;
export const LIGHT_THEME_BG_COLOR = '#99BA92'; export const LIGHT_THEME_BG_COLOR = '#99BA92';
export const DARK_THEME_BG_COLOR = '#0F0F0F'; export const DARK_THEME_BG_COLOR = '#0F0F0F';
export const DEFAULT_PATTERN_COLOR = '#4A8E3A8C'; export const DEFAULT_PATTERN_COLOR = '#4A8E3A8C';
export const DARK_THEME_PATTERN_COLOR = '#0A0A0A8C'; export const DARK_THEME_PATTERN_COLOR = '#48576166';
export const PEER_COLOR_BG_OPACITY = '1a'; export const PEER_COLOR_BG_OPACITY = '1a';
export const PEER_COLOR_BG_ACTIVE_OPACITY = '2b'; export const PEER_COLOR_BG_ACTIVE_OPACITY = '2b';
export const PEER_COLOR_GRADIENT_STEP = 5; // px export const PEER_COLOR_GRADIENT_STEP = 5; // px

View File

@ -80,6 +80,11 @@ export function selectThemeValues<T extends GlobalState>(global: T, themeKey: Th
return global.settings.themes[themeKey]; return global.settings.themes[themeKey];
} }
export function selectActionMessageBg<T extends GlobalState>(global: T) {
const theme = selectTheme(global);
return global.settings.themes[theme]?.patternColor;
}
export function selectIsForumPanelOpen<T extends GlobalState>( export function selectIsForumPanelOpen<T extends GlobalState>(
global: T, global: T,
...[tabId = getCurrentTabId()]: TabArgs<T> ...[tabId = getCurrentTabId()]: TabArgs<T>

View File

@ -6,13 +6,16 @@ import { requestMutation } from '../lib/fasterdom/fasterdom.ts';
import { throttle } from '../util/schedulers.ts'; import { throttle } from '../util/schedulers.ts';
const THROTTLE_DELAY = 100; const THROTTLE_DELAY = 100;
const SCROLL_THRESHOLD = 5;
const useScrollNotch = ({ const useScrollNotch = ({
containerRef, containerRef,
selector, selector,
isBottomNotch,
}: { }: {
containerRef: ElementRef<HTMLDivElement>; containerRef: ElementRef<HTMLDivElement>;
selector: string; selector: string;
isBottomNotch?: boolean;
}, deps: unknown[]) => { }, deps: unknown[]) => {
useLayoutEffect(() => { useLayoutEffect(() => {
const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector); const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector);
@ -21,14 +24,24 @@ const useScrollNotch = ({
const handleScroll = throttle((event: Event) => { const handleScroll = throttle((event: Event) => {
const target = event.target as HTMLElement; const target = event.target as HTMLElement;
const isScrolled = target.scrollTop > 0; const isScrolled = target.scrollTop > 0;
const { scrollHeight, scrollTop, clientHeight } = target;
const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
requestMutation(() => { requestMutation(() => {
toggleExtraClass(target, 'scrolled', isScrolled); if (isBottomNotch) {
toggleExtraClass(target, 'scrolled-to-end', isAtEnd);
} else {
toggleExtraClass(target, 'scrolled', isScrolled);
}
}); });
}, THROTTLE_DELAY); }, THROTTLE_DELAY);
elements.forEach((el) => { elements.forEach((el) => {
addExtraClass(el, 'with-notch'); if (isBottomNotch) {
addExtraClass(el, 'with-bottom-notch');
} else {
addExtraClass(el, 'with-notch');
}
el.addEventListener('scroll', handleScroll, { passive: true }); el.addEventListener('scroll', handleScroll, { passive: true });
}); });
@ -36,10 +49,13 @@ const useScrollNotch = ({
elements.forEach((el) => { elements.forEach((el) => {
el.removeEventListener('scroll', handleScroll); el.removeEventListener('scroll', handleScroll);
removeExtraClass(el, 'with-notch'); removeExtraClass(el, 'with-notch');
removeExtraClass(el, 'with-bottom-notch');
removeExtraClass(el, 'scrolled');
removeExtraClass(el, 'scrolled-to-end');
}); });
}; };
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
}, [containerRef, selector, ...deps]); }, [containerRef, selector, isBottomNotch, ...deps]);
useEffect(() => { useEffect(() => {
const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector); const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector);
@ -47,12 +63,19 @@ const useScrollNotch = ({
elements.forEach((el) => { elements.forEach((el) => {
const isScrolled = el.scrollTop > 0; const isScrolled = el.scrollTop > 0;
const { scrollHeight, scrollTop, clientHeight } = el;
const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
requestMutation(() => { requestMutation(() => {
toggleExtraClass(el, 'scrolled', isScrolled); if (isBottomNotch) {
toggleExtraClass(el, 'scrolled-to-end', isAtEnd);
} else {
toggleExtraClass(el, 'scrolled', isScrolled);
}
}); });
}); });
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
}, [containerRef, selector, ...deps]); }, [containerRef, selector, isBottomNotch, ...deps]);
}; };
export default useScrollNotch; export default useScrollNotch;

View File

@ -212,7 +212,9 @@ $color-message-story-mention-to: #74bcff;
--vh: 1vh; --vh: 1vh;
--border-radius-modal: 1rem; --border-radius-button: 1rem;
--border-radius-button-tiny: 0.875rem;
--border-radius-modal: 2rem;
--border-radius-default: 0.75rem; --border-radius-default: 0.75rem;
--border-radius-default-small: 0.625rem; --border-radius-default-small: 0.625rem;
--border-radius-default-tiny: 0.375rem; --border-radius-default-tiny: 0.375rem;

View File

@ -3,8 +3,8 @@
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
font-display: block; font-display: block;
src: url("./icons.woff2?cc3fadda4d577575d1b441ec5d6c8994") format("woff2"), src: url("./icons.woff2?a07bab7d97a4c6540cca18b1d787228b") format("woff2"),
url("./icons.woff?cc3fadda4d577575d1b441ec5d6c8994") format("woff"); url("./icons.woff?a07bab7d97a4c6540cca18b1d787228b") format("woff");
} }
.icon-char::before { .icon-char::before {

Binary file not shown.

Binary file not shown.

View File

@ -396,6 +396,15 @@ body:not(.is-ios) {
} }
} }
.with-bottom-notch {
border-bottom: 1px solid var(--color-borders);
transition: border-color 0.2s ease-in-out;
&.scrolled-to-end {
border-bottom-color: transparent;
}
}
@keyframes grow-icon { @keyframes grow-icon {
0% { 0% {
transform: scale(0.5); transform: scale(0.5);

View File

@ -2830,6 +2830,9 @@ export interface LangPairWithVariables<V = LangVariable> {
'stars': V; 'stars': V;
'peer': V; 'peer': V;
}; };
'GiftBuyEqualsTo': {
'stars': V;
};
'ComposerTitleForwardFrom': { 'ComposerTitleForwardFrom': {
'users': V; 'users': V;
}; };

View File

@ -234,10 +234,9 @@ export function getPatternColor(rgb: Number3) {
? Math.max(0, v * 0.65) ? Math.max(0, v * 0.65)
: Math.max(0, Math.min(1, 1 - v * 0.65)); : Math.max(0, Math.min(1, 1 - v * 0.65));
const newRgb = hsl2rgb([h * 360, s, v]); const newRgb = hsv2rgb([h, s, v]);
const mappedRgb = newRgb.map((c) => Math.floor(c * 255)) as Number3;
return rgba2hex([...mappedRgb, 102]); return rgba2hex([...newRgb, 102]);
} }
export function int2cssRgba(color: number): string { export function int2cssRgba(color: number): string {