Commit 93099d26 authored by tom goriunov's avatar tom goriunov Committed by GitHub

components for Block and Tx entities (#1108)

* base implementation of entity

* refactor other components to make use of BlockEntity

* tests

* migrate entities w/o icon + L2 blocks

* base implementation of tx entity

* delet TransactionSnippet

* remove type="transaction" from AddressLink

* tests for TxEntity

* make EntityBase components

* common styles for icon color and spacing to text

* update icon color in tests

* update icons to slime format

* Address entity
parent 2df78df4
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.83 0 1 5.03v10.267l6.825 3.976-.034-1.67-5.421-3.175V6.8l6.757 3.818V19.6L9.84 20l.736-.401v-8.98L17.323 6.8v7.628l-5.388 3.108v1.67l6.858-3.834V5.029L9.829 0Zm0 9.415L3.238 5.531l6.59-3.877 6.75 3.877-6.75 3.884Zm-5.082 3.767 1.32-.752-.112-.196-1.32.752.112.196ZM7.06 11.86l1.32-.752-.113-.196-1.32.752.113.196Zm2.868-3.527V6.821h-.226v1.512h.226Zm0-2.636v-1.52h-.226v1.52h.226Zm0-2.534v-1.52h-.226v1.52h.226Zm2.854 8.51-1.31-.76-.114.195 1.311.76.114-.196Zm2.287 1.322-1.32-.76-.113.195 1.32.76.113-.195Zm-12.654 1.52 1.311-.751-.112-.196-1.311.751.112.196Zm14.979-.198-1.311-.76-.114.195 1.311.76.114-.195Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.392 1.45c.252-.288.592-.45.948-.45h8.038a.63.63 0 0 1 .474.225L17.54 6.61a.83.83 0 0 1 .196.544v12.308c0 .408-.141.799-.393 1.087-.25.289-.592.451-.947.451H4.34c-.356 0-.696-.162-.948-.45A1.661 1.661 0 0 1 3 19.461V2.538c0-.408.141-.799.392-1.087Zm.948 1.088h6.87v4.497c0 .388.315.702.702.702h4.485v11.725H4.34V2.538Zm8.274.59 2.791 3.205h-2.791V3.128ZM6.5 11a.5.5 0 0 0 0 1h7.2a.5.5 0 0 0 0-1H6.5ZM6 13.9a.5.5 0 0 1 .5-.5h7.2a.5.5 0 1 1 0 1H6.5a.5.5 0 0 1-.5-.5Zm4.5 2.1a.5.5 0 0 0 0 1h3.2a.5.5 0 0 0 0-1h-3.2Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.28 1.352A1.408 1.408 0 0 1 4.34.85h8.038a.78.78 0 0 1 .587.276l4.689 5.385a.98.98 0 0 1 .233.642v12.308c0 .442-.153.869-.43 1.187a1.408 1.408 0 0 1-1.06.502H4.34c-.403 0-.783-.184-1.06-.502a1.811 1.811 0 0 1-.43-1.187V2.538c0-.442.153-.869.43-1.186Zm1.06-.202c-.308 0-.61.14-.834.399-.226.259-.356.615-.356.99V19.46c0 .375.13.73.356.99.225.258.526.399.834.399h12.057c.309 0 .61-.14.834-.4.226-.259.356-.614.356-.989V7.153a.68.68 0 0 0-.16-.445L12.74 1.323a.48.48 0 0 0-.36-.173h-8.04Zm7.02 1.238v4.647c0 .304.248.551.552.551h4.635v12.025H4.19V2.388h7.17Zm-6.87.3v16.623h11.757V7.886h-4.335a.852.852 0 0 1-.852-.851V2.688H4.49Zm7.974.039 3.27 3.756h-3.27V2.727Zm.3.801v2.655h2.312l-2.312-2.655ZM6.5 11.15a.35.35 0 1 0 0 .7h7.2a.35.35 0 1 0 0-.7H6.5Zm-.65.35a.65.65 0 0 1 .65-.65h7.2a.65.65 0 1 1 0 1.3H6.5a.65.65 0 0 1-.65-.65Zm0 2.4a.65.65 0 0 1 .65-.65h7.2a.65.65 0 1 1 0 1.3H6.5a.65.65 0 0 1-.65-.65Zm.65-.35a.35.35 0 1 0 0 .7h7.2a.35.35 0 1 0 0-.7H6.5Zm4 2.6a.35.35 0 1 0 0 .7h3.2a.35.35 0 1 0 0-.7h-3.2Zm-.65.35a.65.65 0 0 1 .65-.65h3.2a.65.65 0 1 1 0 1.3h-3.2a.65.65 0 0 1-.65-.65Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.392.45C3.644.163 3.984 0 4.34 0h8.038a.63.63 0 0 1 .474.225L17.54 5.61a.83.83 0 0 1 .196.544v12.308c0 .408-.141.799-.393 1.087-.25.289-.592.451-.947.451H4.34c-.356 0-.696-.162-.948-.45A1.661 1.661 0 0 1 3 18.461V1.538c0-.408.141-.799.392-1.087Zm8.709 1.088H4.34v16.924h12.057V6.472l-4.296-4.934Z" fill="currentColor"/>
<path d="m7.3 13.357 2.2 2.357L13.9 11" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.912.42c.388 0 .702.315.702.703v4.21h4.21a.702.702 0 1 1 0 1.404h-4.912a.702.702 0 0 1-.702-.702V1.123c0-.388.315-.702.702-.702Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.77 7.794H.987a.97.97 0 0 1-.549-.17 1.009 1.009 0 0 1-.364-.453 1.041 1.041 0 0 1 .218-1.106l3.722-3.827a.97.97 0 0 1 1.333.06 1.033 1.033 0 0 1 .058 1.37L3.371 5.764H17.77c.262 0 .513.107.698.297.185.19.29.449.29.718 0 .269-.105.527-.29.717a.973.973 0 0 1-.698.297ZM2.23 12.066h16.783c.195 0 .386.059.549.17.162.11.289.269.364.454a1.042 1.042 0 0 1-.218 1.106l-3.737 3.842-.006.007a.99.99 0 0 1-.711.354.963.963 0 0 1-.736-.296 1.017 1.017 0 0 1-.289-.757 1.04 1.04 0 0 1 .345-.731l.007-.007 2.047-2.112H2.23a.973.973 0 0 1-.698-.298 1.03 1.03 0 0 1-.29-.717c0-.27.105-.527.29-.718a.974.974 0 0 1 .698-.297Z" fill="currentColor"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" d="M14.806 21.313H4.582A.583.583 0 0 1 4 20.731V6.179c0-.322.261-.583.582-.583h2.654V3.27c0-.321.26-.582.582-.582h7.313c.007 0 .013.002.02.004.005.001.01.003.017.003a.558.558 0 0 1 .153.031l.02.006a.575.575 0 0 1 .194.118l4.285 4.11-.002.002a.58.58 0 0 1 .181.419v9.064a1.96 1.96 0 0 1-1.958 1.959h-1.277v.95a1.96 1.96 0 0 1-1.96 1.959ZM18.31 6.798l-2.598-2.506v1.713c0 .437.356.793.793.793h1.805Zm-3.42-3.289H8.058v14.072h10.327a.794.794 0 0 0 .793-.793V7.62h-2.671c-1.08 0-1.616-.535-1.616-1.615V3.509ZM7.236 6.42H4.822v14.07H15.15c.437 0 .793-.7.793-1.136v-.951H7.818a.582.582 0 0 1-.582-.583V6.42Zm9.482 4.532a.39.39 0 1 0 0-.78h-5.12l.502-.504a.39.39 0 0 0-.55-.549l-1.168 1.169a.39.39 0 0 0 .059.599.39.39 0 0 0 .216.065h6.06Zm-.012 1.363h-6.061a.39.39 0 0 0 0 .779h5.12l-.502.504a.39.39 0 1 0 .549.55l1.168-1.17a.39.39 0 0 0-.058-.598.39.39 0 0 0-.216-.065Z" clip-rule="evenodd"/>
<path fill="currentColor" d="M7.236 5.596v.25h.25v-.25h-.25Zm7.915-2.905-.07.24.07-.24Zm.017.003.014-.25-.014.25Zm.153.031.085-.235-.003-.001-.082.236Zm.02.006.072-.239-.072.24Zm.031.012.104-.228h-.001l-.103.228Zm.162.106.173-.18-.173.18Zm4.287 4.111.177.177.18-.18-.184-.177-.173.18Zm-.002.002-.176-.177-.18.18.183.177.173-.18Zm-3.054 11.442v-.25h-.25v.25h.25ZM15.713 4.292l.174-.18-.424-.408v.588h.25Zm2.598 2.506v.25h.62l-.446-.43-.174.18ZM8.058 3.51v-.25h-.25v.25h.25Zm6.833 0h.25v-.25h-.25v.25ZM8.058 17.581h-.25v.25h.25v-.25Zm11.12-9.96h.25v-.25h-.25v.25ZM4.822 6.418v-.25h-.25v.25h.25Zm2.414 0h.25v-.25h-.25v.25ZM4.822 20.49h-.25v.25h.25v-.25Zm11.12-2.087h.25v-.25h-.25v.25Zm1.051-7.567-.177-.177.177.177Zm0-.551-.177.177.177-.177Zm-5.396-.114-.177-.177-.425.427h.602v-.25Zm.503-.505.177.177.007-.007.006-.007-.19-.163Zm.093-.268.25-.01-.25.01Zm-.114-.26.177-.177-.177.177Zm-.26-.114.01-.25-.01.25Zm-.268.093-.163-.19-.007.007-.007.007.177.176Zm-1.169 1.169.177.177-.177-.177Zm-.107.199.245.05-.245-.05Zm.022.225-.232.095.001.001.23-.096Zm.143.175.139-.209-.139.209Zm.217.065v-.25.25Zm6.049 1.363v.25-.25Zm-6.337.114.177.177-.177-.177Zm0 .55.177-.176-.177.177Zm5.396.115.177.176.425-.426h-.602v.25Zm-.502.504.162.19.008-.007.007-.007-.177-.176Zm-.098.126.225.11-.225-.11Zm-.038.155-.25-.01.25.01Zm.026.157.233-.091-.233.09Zm.088.133-.177.177.177-.177Zm.29.114-.01-.25.01.25Zm.154-.039.11.225-.11-.225Zm.127-.097-.177-.177-.007.007-.006.007.19.163Zm1.168-1.168-.176-.178v.001l.176.177Zm.086-.425.23-.095v-.001l-.23.096Zm-.144-.174-.139.208.139-.208Zm-12.34 9.184h10.224v-.5H4.582v.5Zm-.832-.832c0 .46.373.832.832.832v-.5a.333.333 0 0 1-.332-.332h-.5Zm0-14.552V20.73h.5V6.179h-.5Zm.832-.833a.833.833 0 0 0-.832.833h.5c0-.184.149-.333.332-.333v-.5Zm2.654 0H4.582v.5h2.654v-.5Zm-.25-2.077v2.327h.5V3.27h-.5Zm.832-.832a.832.832 0 0 0-.832.832h.5c0-.183.148-.332.332-.332v-.5Zm7.313 0H7.818v.5h7.313v-.5Zm.09.014c-.002 0-.041-.014-.09-.014v.5a.202.202 0 0 1-.042-.004c-.007-.002-.013-.004-.009-.002l.14-.48Zm-.04-.006a.2.2 0 0 1 .034.004l.006.002-.14.48s.034.01.073.013l.027-.5Zm.222.044a.808.808 0 0 0-.22-.044l-.03.499a.307.307 0 0 1 .085.017l.165-.472Zm.01.003a2.077 2.077 0 0 1-.007-.002s-.001 0 0 0l-.17.47.032.01.145-.478Zm.062.022a.443.443 0 0 0-.062-.022l-.145.479a.198.198 0 0 1 .008.002l-.006-.002.205-.457Zm.232.154a.823.823 0 0 0-.231-.153l-.208.455c.041.018.07.038.093.06l.346-.362Zm4.287 4.112-4.287-4.111-.346.36 4.287 4.112.346-.361Zm.002.359.002-.002-.354-.354-.001.002.353.354Zm.254.242a.83.83 0 0 0-.257-.6l-.347.361a.33.33 0 0 1 .104.239h.5Zm0 9.064V7.381h-.5v9.064h.5Zm-2.208 2.209a2.21 2.21 0 0 0 2.208-2.209h-.5a1.71 1.71 0 0 1-1.708 1.709v.5Zm-1.277 0h1.277v-.5h-1.277v.5Zm.25.7v-.95h-.5v.95h.5Zm-2.21 2.209a2.21 2.21 0 0 0 2.21-2.208h-.5a1.71 1.71 0 0 1-1.71 1.708v.5Zm.735-17.09 2.598 2.505.347-.36-2.598-2.506-.348.36Zm.423 1.532V4.292h-.5v1.713h.5Zm.543.543a.544.544 0 0 1-.543-.543h-.5c0 .575.468 1.043 1.043 1.043v-.5Zm1.805 0h-1.805v.5h1.805v-.5ZM8.058 3.76h6.833v-.5H8.058v.5Zm.25 13.822V3.51h-.5v14.072h.5Zm10.077-.25H8.058v.5h10.327v-.5Zm.543-.543c0 .3-.244.543-.543.543v.5c.575 0 1.043-.468 1.043-1.043h-.5Zm0-9.168v9.168h.5V7.62h-.5Zm-2.421.25h2.67v-.5h-2.67v.5ZM14.64 6.005c0 .578.143 1.057.476 1.39.333.332.812.475 1.39.475v-.5c-.502 0-.831-.124-1.037-.33-.205-.205-.33-.533-.33-1.035h-.5Zm0-2.496v2.496h.5V3.509h-.5ZM4.822 6.67h2.414v-.5H4.822v.5Zm.25 13.822V6.419h-.5V20.49h.5Zm10.077-.25H4.822v.5h10.326v-.5Zm.543-.886c0 .162-.07.401-.195.599-.13.21-.264.287-.348.287v.5c.352 0 .616-.272.772-.522.164-.26.27-.59.27-.864h-.5Zm0-.951v.95h.5v-.95h-.5Zm-7.874.25h8.124v-.5H7.818v.5Zm-.832-.833c0 .46.372.833.832.833v-.5a.332.332 0 0 1-.332-.333h-.5Zm0-11.402v11.4h.5V6.42h-.5Zm9.83 4.24a.14.14 0 0 1-.098.042v.5a.64.64 0 0 0 .452-.188l-.354-.353Zm.041-.098a.14.14 0 0 1-.04.099l.353.353a.64.64 0 0 0 .187-.452h-.5Zm-.04-.098a.14.14 0 0 1 .04.098h.5a.64.64 0 0 0-.187-.452l-.354.354Zm-.1-.041a.14.14 0 0 1 .1.04l.353-.353a.64.64 0 0 0-.452-.187v.5Zm-5.12 0h5.12v-.5h-5.12v.5Zm.326-.931-.503.504.355.353.502-.504-.354-.353Zm.02-.082a.14.14 0 0 1-.033.096l.38.325a.64.64 0 0 0 .153-.44l-.5.019Zm-.04-.093a.14.14 0 0 1 .04.093l.5-.02a.64.64 0 0 0-.187-.427l-.353.354Zm-.094-.041a.14.14 0 0 1 .094.04l.353-.353a.64.64 0 0 0-.427-.187l-.02.5Zm-.096.033a.14.14 0 0 1 .096-.033l.02-.5a.64.64 0 0 0-.44.153l.324.38Zm-1.154 1.155 1.168-1.168-.353-.353-1.168 1.168.353.354Zm-.039.072a.139.139 0 0 1 .039-.071l-.353-.355a.64.64 0 0 0-.176.328l.49.098Zm.008.081a.139.139 0 0 1-.008-.08l-.49-.1a.64.64 0 0 0 .036.37l.462-.19Zm.05.061a.14.14 0 0 1-.05-.062l-.462.192c.049.117.13.217.236.287l.277-.417Zm.078.024a.14.14 0 0 1-.077-.024l-.277.417a.64.64 0 0 0 .356.107l-.002-.5Zm6.062 0h-6.061v.5h6.06v-.5Zm-6.073 1.863h6.06v-.5h-6.06v.5Zm-.099.04a.14.14 0 0 1 .099-.04v-.5a.64.64 0 0 0-.452.187l.353.354Zm-.04.1a.14.14 0 0 1 .04-.1l-.353-.353a.639.639 0 0 0-.188.452h.5Zm.04.098a.14.14 0 0 1-.04-.099h-.5c0 .17.067.333.187.452l.353-.353Zm.099.04a.14.14 0 0 1-.099-.04l-.353.353a.64.64 0 0 0 .452.188v-.5Zm5.12 0h-5.12v.5h5.12v-.5Zm-.325.931.502-.504-.354-.353-.502.505.354.352Zm-.05.06a.138.138 0 0 1 .035-.046l-.325-.38a.639.639 0 0 0-.16.207l.45.218Zm-.014.054a.14.14 0 0 1 .014-.055l-.45-.218a.64.64 0 0 0-.063.254l.5.02Zm.01.057a.139.139 0 0 1-.01-.057l-.5-.019a.64.64 0 0 0 .045.258l.465-.182Zm.031.047a.139.139 0 0 1-.03-.047l-.466.182a.64.64 0 0 0 .143.219l.353-.354Zm.048.032a.139.139 0 0 1-.048-.032l-.353.354a.64.64 0 0 0 .219.143l.182-.465Zm.056.01a.139.139 0 0 1-.056-.01l-.182.465a.64.64 0 0 0 .258.044l-.02-.5Zm.056-.015a.138.138 0 0 1-.056.014l.02.5a.64.64 0 0 0 .253-.064l-.217-.45Zm.045-.035a.138.138 0 0 1-.045.035l.217.45a.64.64 0 0 0 .208-.16l-.38-.325Zm1.181-1.182-1.168 1.168.354.354 1.168-1.168-.354-.354Zm.04-.072a.139.139 0 0 1-.04.071l.353.355a.64.64 0 0 0 .176-.327l-.49-.099Zm-.009-.08a.14.14 0 0 1 .008.08l.49.099a.64.64 0 0 0-.035-.37l-.463.19Zm-.05-.062a.14.14 0 0 1 .051.063l.461-.193a.64.64 0 0 0-.236-.286l-.276.416Zm-.078-.023a.14.14 0 0 1 .078.023l.276-.416a.639.639 0 0 0-.355-.107l.001.5Z"/>
</svg>
<svg viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.013 21H2.035a.626.626 0 0 1-.625-.625V4.749c0-.345.28-.625.625-.625h2.85V1.625c0-.345.279-.625.624-.625h7.853c.008 0 .014.002.021.004l.018.004a.6.6 0 0 1 .186.04.616.616 0 0 1 .208.126l4.603 4.414-.002.002a.622.622 0 0 1 .194.45v9.733c0 1.16-.943 2.103-2.102 2.103h-1.372v1.021c0 1.16-.944 2.103-2.103 2.103Zm3.764-15.586-2.79-2.69v1.838c0 .47.382.852.852.852h1.938Zm-3.673-3.531H5.767v15.11h11.089c.469 0 .851-.382.851-.852V6.297H14.84c-1.16 0-1.735-.575-1.735-1.735v-2.68Zm-8.22 3.124H2.293v15.11H13.38c.47 0 .852-.75.852-1.22v-1.02H5.509a.625.625 0 0 1-.625-.626V5.007Zm10.182 4.866a.418.418 0 1 0 0-.836H9.568l.54-.542a.418.418 0 0 0-.302-.69c-.105-.004-.226-.068-.306 0L8.172 9.103c-.06.058-.007.191-.024.272a.418.418 0 0 0 .178.43c.069.045.137.157.22.157l6.52-.088Zm-.013 1.377H8.545c-.11 0-.217.05-.295.129-.079.078-.123.265-.123.376a.418.418 0 0 0 .418.418h5.498l-.54.542a.417.417 0 0 0 .12.707.415.415 0 0 0 .47-.118l1.347-1.218c.059-.058.007-.169.023-.25a.417.417 0 0 0-.178-.43c-.068-.045-.15-.156-.232-.156Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.784 1.625c0-.4.325-.725.725-.725h7.853c.023 0 .042.006.048.008h.001a.705.705 0 0 1 .205.044h.002l.044.016a.72.72 0 0 1 .202.134l4.677 4.485-.007.007a.717.717 0 0 1 .156.446v9.733a2.205 2.205 0 0 1-2.202 2.203h-1.272v.921a2.205 2.205 0 0 1-2.203 2.203H2.035a.726.726 0 0 1-.725-.725V4.749c0-.4.325-.725.725-.725h2.75V1.625ZM18.255 5.59l-4.53-4.344a.518.518 0 0 0-.167-.103l-.026-.008a.492.492 0 0 0-.136-.027m4.86 4.482-.003.002.074.07c.1.097.163.23.163.378v9.733a2.005 2.005 0 0 1-2.002 2.003h-1.472v1.121a2.005 2.005 0 0 1-2.003 2.003H2.035a.526.526 0 0 1-.525-.525V4.749c0-.29.235-.525.525-.525h2.95V1.625c0-.29.234-.525.524-.525h7.846m-7.688.683h7.537v2.78c0 .564.14.968.403 1.231.264.263.668.403 1.232.403h2.968v9.944a.953.953 0 0 1-.951.952H5.667V1.783Zm.2.2v14.91h10.989a.753.753 0 0 0 .751-.752V6.397H14.84c-.595 0-1.059-.147-1.373-.462-.314-.314-.462-.778-.462-1.373v-2.58H5.867Zm8.02.505 3.138 3.026h-2.186a.953.953 0 0 1-.952-.952V2.488Zm.2.471v1.603c0 .415.337.752.752.752h1.69L14.087 2.96ZM2.193 4.907h2.791V17.25c0 .29.235.525.525.525h8.824v1.121c0 .257-.103.58-.265.84-.16.254-.399.48-.687.48H2.193V4.907Zm.2.2v14.91H13.38c.18 0 .368-.148.517-.387.146-.234.235-.52.235-.733v-.92H5.509a.725.725 0 0 1-.725-.726V5.107H2.393Zm7.193 2.872L8.334 9.231a.32.32 0 0 0-.07.347.318.318 0 0 0 .294.195h6.508a.318.318 0 0 0 0-.636H9.327l.707-.71a.319.319 0 0 0-.448-.448Zm-.133-.15a.518.518 0 0 1 .73.731l-.004.006-.37.37h5.257a.518.518 0 0 1 0 1.037H8.56m-.366-.884a.518.518 0 0 0 .366.884m.894-2.143-1.26 1.26 1.26-1.26Zm-.908 3.607a.318.318 0 1 0 0 .636h5.739l-.715.718a.319.319 0 0 0 .09.537.319.319 0 0 0 .358-.089l.005-.006 1.255-1.254a.318.318 0 0 0-.047-.489.318.318 0 0 0-.177-.053H8.545Zm-.366-.048a.518.518 0 0 1 .366-.152h6.508m.365.883a.518.518 0 0 0-.365-.883m.365.883-1.251 1.252a.518.518 0 1 1-.732-.73l.367-.369H8.545a.518.518 0 0 1-.366-.884" fill="currentColor"/>
</svg>
...@@ -9,7 +9,7 @@ export const hash = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5859'; ...@@ -9,7 +9,7 @@ export const hash = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5859';
export const withName: AddressParam = { export const withName: AddressParam = {
hash: hash, hash: hash,
implementation_name: null, implementation_name: null,
is_contract: true, is_contract: false,
is_verified: null, is_verified: null,
name: 'ArianeeStore', name: 'ArianeeStore',
private_tags: [], private_tags: [],
...@@ -20,7 +20,7 @@ export const withName: AddressParam = { ...@@ -20,7 +20,7 @@ export const withName: AddressParam = {
export const withoutName: AddressParam = { export const withoutName: AddressParam = {
hash: hash, hash: hash,
implementation_name: null, implementation_name: null,
is_contract: true, is_contract: false,
is_verified: null, is_verified: null,
name: null, name: null,
private_tags: [], private_tags: [],
......
import { Box, Text, Grid, Skeleton } from '@chakra-ui/react'; import { Box, Text, Grid } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -7,7 +7,6 @@ import type { Address as TAddress } from 'types/api/address'; ...@@ -7,7 +7,6 @@ import type { Address as TAddress } from 'types/api/address';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import blockIcon from 'icons/block.svg';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
...@@ -15,10 +14,11 @@ import { ADDRESS_COUNTERS } from 'stubs/address'; ...@@ -15,10 +14,11 @@ import { ADDRESS_COUNTERS } from 'stubs/address';
import AddressCounterItem from 'ui/address/details/AddressCounterItem'; import AddressCounterItem from 'ui/address/details/AddressCounterItem';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo'; import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
import Icon from 'ui/shared/chakra/Icon';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
...@@ -104,7 +104,7 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -104,7 +104,7 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
> >
<AddressLink type="address" hash={ data.creator_address_hash } truncation="constant"/> <AddressLink type="address" hash={ data.creator_address_hash } truncation="constant"/>
<Text whiteSpace="pre"> at txn </Text> <Text whiteSpace="pre"> at txn </Text>
<AddressLink hash={ data.creation_tx_hash } type="transaction" truncation="constant"/> <TxEntity hash={ data.creation_tx_hash } truncation="constant" noIcon/>
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
{ data.is_contract && data.implementation_address && ( { data.is_contract && data.implementation_address && (
...@@ -210,16 +210,10 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -210,16 +210,10 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
py={{ base: '2px', lg: 1 }} py={{ base: '2px', lg: 1 }}
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
> >
<LinkInternal <BlockEntity
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.block_number_balance_updated_at) } }) } number={ data.block_number_balance_updated_at }
display="flex" isLoading={ addressQuery.isPlaceholderData }
alignItems="center" />
>
<Box mr={ 2 }>
<Icon as={ blockIcon } boxSize={ 6 } isLoading={ addressQuery.isPlaceholderData }/>
</Box>
<Skeleton isLoaded={ !addressQuery.isPlaceholderData }>{ data.block_number_balance_updated_at }</Skeleton>
</LinkInternal>
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
<DetailsSponsoredItem isLoading={ addressQuery.isPlaceholderData }/> <DetailsSponsoredItem isLoading={ addressQuery.isPlaceholderData }/>
......
...@@ -4,12 +4,10 @@ import React from 'react'; ...@@ -4,12 +4,10 @@ import React from 'react';
import type { Block } from 'types/api/block'; import type { Block } from 'types/api/block';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import LinkInternal from 'ui/shared/LinkInternal'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import Utilization from 'ui/shared/Utilization/Utilization'; import Utilization from 'ui/shared/Utilization/Utilization';
...@@ -19,16 +17,18 @@ type Props = Block & { ...@@ -19,16 +17,18 @@ type Props = Block & {
}; };
const AddressBlocksValidatedListItem = (props: Props) => { const AddressBlocksValidatedListItem = (props: Props) => {
const blockUrl = route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: props.height.toString() } });
const timeAgo = useTimeAgoIncrement(props.timestamp, props.page === 1); const timeAgo = useTimeAgoIncrement(props.timestamp, props.page === 1);
const totalReward = getBlockTotalReward(props); const totalReward = getBlockTotalReward(props);
return ( return (
<ListItemMobile rowGap={ 2 } isAnimated> <ListItemMobile rowGap={ 2 } isAnimated>
<Flex justifyContent="space-between" w="100%"> <Flex justifyContent="space-between" w="100%">
<Skeleton isLoaded={ !props.isLoading } display="inline-block"> <BlockEntity
<LinkInternal href={ blockUrl } fontWeight="700">{ props.height }</LinkInternal> isLoading={ props.isLoading }
</Skeleton> number={ props.height }
noIcon
fontWeight={ 700 }
/>
<Skeleton isLoaded={ !props.isLoading } color="text_secondary" display="inline-block"> <Skeleton isLoaded={ !props.isLoading } color="text_secondary" display="inline-block">
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
</Skeleton> </Skeleton>
......
...@@ -4,11 +4,9 @@ import React from 'react'; ...@@ -4,11 +4,9 @@ import React from 'react';
import type { Block } from 'types/api/block'; import type { Block } from 'types/api/block';
import { route } from 'nextjs-routes';
import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import LinkInternal from 'ui/shared/LinkInternal'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import Utilization from 'ui/shared/Utilization/Utilization'; import Utilization from 'ui/shared/Utilization/Utilization';
type Props = Block & { type Props = Block & {
...@@ -17,16 +15,20 @@ type Props = Block & { ...@@ -17,16 +15,20 @@ type Props = Block & {
}; };
const AddressBlocksValidatedTableItem = (props: Props) => { const AddressBlocksValidatedTableItem = (props: Props) => {
const blockUrl = route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(props.height) } });
const timeAgo = useTimeAgoIncrement(props.timestamp, props.page === 1); const timeAgo = useTimeAgoIncrement(props.timestamp, props.page === 1);
const totalReward = getBlockTotalReward(props); const totalReward = getBlockTotalReward(props);
return ( return (
<Tr> <Tr>
<Td> <Td>
<Skeleton isLoaded={ !props.isLoading } display="inline-block"> <BlockEntity
<LinkInternal href={ blockUrl } fontWeight="700">{ props.height }</LinkInternal> isLoading={ props.isLoading }
</Skeleton> number={ props.height }
noIcon
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 700 }
/>
</Td> </Td>
<Td> <Td>
<Skeleton isLoaded={ !props.isLoading } color="text_secondary" display="inline-block"> <Skeleton isLoaded={ !props.isLoading } color="text_secondary" display="inline-block">
......
...@@ -4,14 +4,11 @@ import React from 'react'; ...@@ -4,14 +4,11 @@ import React from 'react';
import type { AddressCoinBalanceHistoryItem } from 'types/api/address'; import type { AddressCoinBalanceHistoryItem } from 'types/api/address';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import { WEI, ZERO } from 'lib/consts'; import { WEI, ZERO } from 'lib/consts';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import AddressLink from 'ui/shared/address/AddressLink'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
type Props = AddressCoinBalanceHistoryItem & { type Props = AddressCoinBalanceHistoryItem & {
...@@ -20,7 +17,6 @@ type Props = AddressCoinBalanceHistoryItem & { ...@@ -20,7 +17,6 @@ type Props = AddressCoinBalanceHistoryItem & {
}; };
const AddressCoinBalanceListItem = (props: Props) => { const AddressCoinBalanceListItem = (props: Props) => {
const blockUrl = route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(props.block_number) } });
const deltaBn = BigNumber(props.delta).div(WEI); const deltaBn = BigNumber(props.delta).div(WEI);
const isPositiveDelta = deltaBn.gte(ZERO); const isPositiveDelta = deltaBn.gte(ZERO);
const timeAgo = useTimeAgoIncrement(props.block_timestamp, props.page === 1); const timeAgo = useTimeAgoIncrement(props.block_timestamp, props.page === 1);
...@@ -44,16 +40,23 @@ const AddressCoinBalanceListItem = (props: Props) => { ...@@ -44,16 +40,23 @@ const AddressCoinBalanceListItem = (props: Props) => {
</Flex> </Flex>
<Flex columnGap={ 2 } w="100%"> <Flex columnGap={ 2 } w="100%">
<Skeleton isLoaded={ !props.isLoading } fontWeight={ 500 } flexShrink={ 0 }>Block</Skeleton> <Skeleton isLoaded={ !props.isLoading } fontWeight={ 500 } flexShrink={ 0 }>Block</Skeleton>
<Skeleton isLoaded={ !props.isLoading }> <BlockEntity
<LinkInternal href={ blockUrl } fontWeight="700">{ props.block_number }</LinkInternal> isLoading={ props.isLoading }
</Skeleton> number={ props.block_number }
noIcon
fontWeight={ 700 }
/>
</Flex> </Flex>
{ props.transaction_hash && ( { props.transaction_hash && (
<Flex columnGap={ 2 } w="100%"> <Flex columnGap={ 2 } w="100%">
<Skeleton isLoaded={ !props.isLoading } fontWeight={ 500 } flexShrink={ 0 }>Txs</Skeleton> <Skeleton isLoaded={ !props.isLoading } fontWeight={ 500 } flexShrink={ 0 }>Txs</Skeleton>
<Address maxW="150px" fontWeight="700"> <TxEntity
<AddressLink hash={ props.transaction_hash } type="transaction" isLoading={ props.isLoading }/> hash={ props.transaction_hash }
</Address> isLoading={ props.isLoading }
noIcon
fontWeight={ 700 }
maxW="150px"
/>
</Flex> </Flex>
) } ) }
<Flex columnGap={ 2 } w="100%"> <Flex columnGap={ 2 } w="100%">
......
...@@ -4,13 +4,10 @@ import React from 'react'; ...@@ -4,13 +4,10 @@ import React from 'react';
import type { AddressCoinBalanceHistoryItem } from 'types/api/address'; import type { AddressCoinBalanceHistoryItem } from 'types/api/address';
import { route } from 'nextjs-routes';
import { WEI, ZERO } from 'lib/consts'; import { WEI, ZERO } from 'lib/consts';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import AddressLink from 'ui/shared/address/AddressLink'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import LinkInternal from 'ui/shared/LinkInternal';
type Props = AddressCoinBalanceHistoryItem & { type Props = AddressCoinBalanceHistoryItem & {
page: number; page: number;
...@@ -18,7 +15,6 @@ type Props = AddressCoinBalanceHistoryItem & { ...@@ -18,7 +15,6 @@ type Props = AddressCoinBalanceHistoryItem & {
}; };
const AddressCoinBalanceTableItem = (props: Props) => { const AddressCoinBalanceTableItem = (props: Props) => {
const blockUrl = route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(props.block_number) } });
const deltaBn = BigNumber(props.delta).div(WEI); const deltaBn = BigNumber(props.delta).div(WEI);
const isPositiveDelta = deltaBn.gte(ZERO); const isPositiveDelta = deltaBn.gte(ZERO);
const timeAgo = useTimeAgoIncrement(props.block_timestamp, props.page === 1); const timeAgo = useTimeAgoIncrement(props.block_timestamp, props.page === 1);
...@@ -26,18 +22,25 @@ const AddressCoinBalanceTableItem = (props: Props) => { ...@@ -26,18 +22,25 @@ const AddressCoinBalanceTableItem = (props: Props) => {
return ( return (
<Tr> <Tr>
<Td> <Td>
<Skeleton isLoaded={ !props.isLoading } display="inline-block"> <BlockEntity
<LinkInternal href={ blockUrl } fontWeight="700">{ props.block_number }</LinkInternal> isLoading={ props.isLoading }
</Skeleton> number={ props.block_number }
noIcon
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 700 }
/>
</Td> </Td>
<Td> <Td>
{ props.transaction_hash && { props.transaction_hash && (
( <TxEntity
<Address w="150px" fontWeight="700"> hash={ props.transaction_hash }
<AddressLink hash={ props.transaction_hash } type="transaction" isLoading={ props.isLoading }/> isLoading={ props.isLoading }
</Address> noIcon
) fontWeight={ 700 }
} maxW="150px"
/>
) }
</Td> </Td>
<Td> <Td>
<Skeleton isLoaded={ !props.isLoading } color="text_secondary" display="inline-block"> <Skeleton isLoaded={ !props.isLoading } color="text_secondary" display="inline-block">
...@@ -51,7 +54,7 @@ const AddressCoinBalanceTableItem = (props: Props) => { ...@@ -51,7 +54,7 @@ const AddressCoinBalanceTableItem = (props: Props) => {
</Td> </Td>
<Td isNumeric display="flex" justifyContent="end"> <Td isNumeric display="flex" justifyContent="end">
<Skeleton isLoaded={ !props.isLoading }> <Skeleton isLoaded={ !props.isLoading }>
<Stat flexGrow="0"> <Stat flexGrow="0" lineHeight={ 5 }>
<StatHelpText display="flex" mb={ 0 } alignItems="center"> <StatHelpText display="flex" mb={ 0 } alignItems="center">
<StatArrow type={ isPositiveDelta ? 'increase' : 'decrease' }/> <StatArrow type={ isPositiveDelta ? 'increase' : 'decrease' }/>
<Text as="span" color={ isPositiveDelta ? 'green.500' : 'red.500' } fontWeight={ 600 }> <Text as="span" color={ isPositiveDelta ? 'green.500' : 'red.500' } fontWeight={ 600 }>
......
...@@ -4,8 +4,6 @@ import React from 'react'; ...@@ -4,8 +4,6 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; import type { InternalTransaction } from 'types/api/internalTransaction';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import eastArrowIcon from 'icons/arrows/east.svg'; import eastArrowIcon from 'icons/arrows/east.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
...@@ -15,8 +13,9 @@ import AddressLink from 'ui/shared/address/AddressLink'; ...@@ -15,8 +13,9 @@ import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils'; import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
...@@ -50,16 +49,25 @@ const TxInternalsListItem = ({ ...@@ -50,16 +49,25 @@ const TxInternalsListItem = ({
<TxStatus status={ success ? 'ok' : 'error' } errorText={ error } isLoading={ isLoading }/> <TxStatus status={ success ? 'ok' : 'error' } errorText={ error } isLoading={ isLoading }/>
</Flex> </Flex>
<Flex justifyContent="space-between" width="100%"> <Flex justifyContent="space-between" width="100%">
<AddressLink fontWeight="700" hash={ txnHash } truncation="constant" type="transaction" isLoading={ isLoading }/> <TxEntity
hash={ txnHash }
isLoading={ isLoading }
fontWeight={ 700 }
truncation="constant"
/>
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm"> <Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
<span>{ dayjs(timestamp).fromNow() }</span> <span>{ dayjs(timestamp).fromNow() }</span>
</Skeleton> </Skeleton>
</Flex> </Flex>
<HStack spacing={ 1 }> <HStack spacing={ 1 }>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Block</Skeleton> <Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Block</Skeleton>
<Skeleton isLoaded={ !isLoading }> <BlockEntity
<LinkInternal href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: block.toString() } }) }>{ block }</LinkInternal> isLoading={ isLoading }
</Skeleton> number={ block }
noIcon
fontSize="sm"
lineHeight={ 5 }
/>
</HStack> </HStack>
<Box w="100%" display="flex" columnGap={ 3 }> <Box w="100%" display="flex" columnGap={ 3 }>
<Address width="calc((100% - 48px) / 2)"> <Address width="calc((100% - 48px) / 2)">
......
...@@ -4,8 +4,6 @@ import React from 'react'; ...@@ -4,8 +4,6 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; import type { InternalTransaction } from 'types/api/internalTransaction';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg'; import rightArrowIcon from 'icons/arrows/east.svg';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
...@@ -15,8 +13,9 @@ import AddressLink from 'ui/shared/address/AddressLink'; ...@@ -15,8 +13,9 @@ import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import LinkInternal from 'ui/shared/LinkInternal';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils'; import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
...@@ -48,7 +47,12 @@ const AddressIntTxsTableItem = ({ ...@@ -48,7 +47,12 @@ const AddressIntTxsTableItem = ({
<Tr alignItems="top"> <Tr alignItems="top">
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<Flex rowGap={ 3 } flexWrap="wrap"> <Flex rowGap={ 3 } flexWrap="wrap">
<AddressLink fontWeight="700" hash={ txnHash } type="transaction" isLoading={ isLoading }/> <TxEntity
hash={ txnHash }
isLoading={ isLoading }
fontWeight={ 700 }
noIcon
/>
{ timestamp && ( { timestamp && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm"> <Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
...@@ -67,11 +71,14 @@ const AddressIntTxsTableItem = ({ ...@@ -67,11 +71,14 @@ const AddressIntTxsTableItem = ({
</Flex> </Flex>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block"> <BlockEntity
<LinkInternal href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: block.toString() } }) }> isLoading={ isLoading }
{ block } number={ block }
</LinkInternal> noIcon
</Skeleton> fontSize="sm"
lineHeight={ 5 }
fontWeight={ 500 }
/>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<Address display="inline-flex" maxW="100%"> <Address display="inline-flex" maxW="100%">
......
...@@ -458,7 +458,15 @@ const BlockDetails = ({ query }: Props) => { ...@@ -458,7 +458,15 @@ const BlockDetails = ({ query }: Props) => {
hint="The hash of the block from which this block was generated" hint="The hash of the block from which this block was generated"
flexWrap="nowrap" flexWrap="nowrap"
> >
<AddressLink hash={ data.parent_hash } type="block" blockHeight={ String(data.height - 1) }/> <LinkInternal
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.height - 1) } }) }
overflow="hidden"
whiteSpace="nowrap"
>
<HashStringShortenDynamic
hash={ data.parent_hash }
/>
</LinkInternal>
<CopyToClipboard text={ data.parent_hash }/> <CopyToClipboard text={ data.parent_hash }/>
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
......
...@@ -15,6 +15,7 @@ import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; ...@@ -15,6 +15,7 @@ import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import BlockTimestamp from 'ui/blocks/BlockTimestamp'; import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio'; import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
...@@ -38,17 +39,13 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => { ...@@ -38,17 +39,13 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
<ListItemMobile rowGap={ 3 } key={ String(data.height) } isAnimated> <ListItemMobile rowGap={ 3 } key={ String(data.height) } isAnimated>
<Flex justifyContent="space-between" w="100%"> <Flex justifyContent="space-between" w="100%">
<Flex columnGap={ 2 } alignItems="center"> <Flex columnGap={ 2 } alignItems="center">
<Skeleton isLoaded={ !isLoading } display="inline-block"> <BlockEntity
<LinkInternal isLoading={ isLoading }
fontWeight={ 600 } number={ data.height }
href={ route({ hash={ data.type === 'reorg' ? data.hash : undefined }
pathname: '/block/[height_or_hash]', noIcon
query: { height_or_hash: data.type === 'reorg' ? String(data.hash) : String(data.height) }, fontWeight={ 600 }
}) } />
>
{ data.height }
</LinkInternal>
</Skeleton>
</Flex> </Flex>
<BlockTimestamp ts={ data.timestamp } isEnabled={ enableTimeIncrement } isLoading={ isLoading }/> <BlockTimestamp ts={ data.timestamp } isEnabled={ enableTimeIncrement } isLoading={ isLoading }/>
</Flex> </Flex>
......
...@@ -14,6 +14,7 @@ import { WEI } from 'lib/consts'; ...@@ -14,6 +14,7 @@ import { WEI } from 'lib/consts';
import BlockTimestamp from 'ui/blocks/BlockTimestamp'; import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio'; import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
...@@ -45,17 +46,15 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => { ...@@ -45,17 +46,15 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
<Td fontSize="sm"> <Td fontSize="sm">
<Flex columnGap={ 2 } alignItems="center" mb={ 2 }> <Flex columnGap={ 2 } alignItems="center" mb={ 2 }>
<Tooltip isDisabled={ data.type !== 'reorg' } label="Chain reorganizations"> <Tooltip isDisabled={ data.type !== 'reorg' } label="Chain reorganizations">
<Skeleton isLoaded={ !isLoading } display="inline-block"> <BlockEntity
<LinkInternal isLoading={ isLoading }
fontWeight={ 600 } number={ data.height }
href={ route({ hash={ data.type === 'reorg' ? data.hash : undefined }
pathname: '/block/[height_or_hash]', noIcon
query: { height_or_hash: data.type === 'reorg' ? String(data.hash) : String(data.height) }, fontSize="sm"
}) } lineHeight={ 5 }
> fontWeight={ 600 }
{ data.height } />
</LinkInternal>
</Skeleton>
</Tooltip> </Tooltip>
</Flex> </Flex>
<BlockTimestamp ts={ data.timestamp } isEnabled={ enableTimeIncrement } isLoading={ isLoading }/> <BlockTimestamp ts={ data.timestamp } isEnabled={ enableTimeIncrement } isLoading={ isLoading }/>
......
...@@ -10,12 +10,11 @@ import React from 'react'; ...@@ -10,12 +10,11 @@ import React from 'react';
import type { Block } from 'types/api/block'; import type { Block } from 'types/api/block';
import config from 'configs/app'; import config from 'configs/app';
import blockIcon from 'icons/block.svg';
import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import BlockTimestamp from 'ui/blocks/BlockTimestamp'; import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
type Props = { type Props = {
block: Block; block: Block;
...@@ -41,17 +40,14 @@ const LatestBlocksItem = ({ block, h, isLoading }: Props) => { ...@@ -41,17 +40,14 @@ const LatestBlocksItem = ({ block, h, isLoading }: Props) => {
w="100%" w="100%"
> >
<Flex alignItems="center" overflow="hidden" w="100%" mb={ 3 }> <Flex alignItems="center" overflow="hidden" w="100%" mb={ 3 }>
<Icon as={ blockIcon } boxSize="30px" color="link" isLoading={ isLoading } borderRadius="base"/> <BlockEntity
<AddressLink
isLoading={ isLoading } isLoading={ isLoading }
type="block" number={ block.height }
hash={ String(block.height) } tailLength={ 2 }
blockHeight={ String(block.height) }
fontSize="xl" fontSize="xl"
fontWeight="500" lineHeight={ 7 }
ml={ 2 } fontWeight={ 500 }
mr="auto" mr="auto"
tailLength={ 2 }
/> />
<BlockTimestamp <BlockTimestamp
ts={ block.timestamp } ts={ block.timestamp }
......
...@@ -8,17 +8,12 @@ import React from 'react'; ...@@ -8,17 +8,12 @@ import React from 'react';
import type { L2DepositsItem } from 'types/api/l2Deposits'; import type { L2DepositsItem } from 'types/api/l2Deposits';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import blockIcon from 'icons/block.svg';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import Icon from 'ui/shared/chakra/Icon'; import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import LinkExternal from 'ui/shared/LinkExternal'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkInternal from 'ui/shared/LinkInternal';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -36,51 +31,31 @@ const LatestTxsItem = ({ item, isLoading }: Props) => { ...@@ -36,51 +31,31 @@ const LatestTxsItem = ({ item, isLoading }: Props) => {
} }
const l1BlockLink = ( const l1BlockLink = (
<LinkExternal <BlockEntityL1
href={ feature.L1BaseUrl + number={ item.l1_block_number }
route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l1_block_number.toString() } })
}
fontWeight={ 700 }
display="inline-flex"
mr={ 2 }
isLoading={ isLoading } isLoading={ isLoading }
> fontSize="sm"
<Icon as={ blockIcon } boxSize="30px" isLoading={ isLoading } borderRadius="base"/> lineHeight={ 5 }
<Skeleton isLoaded={ !isLoading } ml={ 1 }>{ item.l1_block_number }</Skeleton> fontWeight={ 700 }
</LinkExternal> />
); );
const l1TxLink = ( const l1TxLink = (
<LinkExternal <TxEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) }
maxW="100%"
display="inline-flex"
alignItems="center"
overflow="hidden"
isLoading={ isLoading } isLoading={ isLoading }
my="3px" hash={ item.l1_tx_hash }
> fontSize="sm"
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> lineHeight={ 5 }
<Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="nowrap" ml={ 1 }> />
<HashStringShortenDynamic hash={ item.l1_tx_hash }/>
</Skeleton>
</LinkExternal>
); );
const l2TxLink = ( const l2TxLink = (
<LinkInternal <TxEntity
href={ route({ pathname: '/tx/[hash]', query: { hash: item.l2_tx_hash } }) }
display="flex"
alignItems="center"
overflow="hidden"
w="100%"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l2_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ item.l2_tx_hash }/> />
</Skeleton>
</LinkInternal>
); );
const content = (() => { const content = (() => {
......
...@@ -12,13 +12,13 @@ import type { Transaction } from 'types/api/transaction'; ...@@ -12,13 +12,13 @@ import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg'; import rightArrowIcon from 'icons/arrows/east.svg';
import transactionIcon from 'icons/transactions.svg';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType'; import TxType from 'ui/txs/TxType';
...@@ -54,24 +54,20 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -54,24 +54,20 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
mt={ 2 } mt={ 2 }
alignItems="center" alignItems="center"
> >
<Icon <TxEntity
as={ transactionIcon }
boxSize="30px"
color="link"
display="inline"
isLoading={ isLoading } isLoading={ isLoading }
borderRadius="base" hash={ tx.hash }
fontWeight="700"
/> />
<Address overflow="hidden" w="calc(100% - 130px)" maxW="calc(100% - 130px)" ml={ 2 } mr={ 2 }>
<AddressLink
hash={ tx.hash }
type="transaction"
fontWeight="700"
isLoading={ isLoading }
/>
</Address>
{ tx.timestamp && ( { tx.timestamp && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm"> <Skeleton
isLoaded={ !isLoading }
color="text_secondary"
fontWeight="400"
fontSize="sm"
flexShrink={ 0 }
ml={ 2 }
>
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
</Skeleton> </Skeleton>
) } ) }
......
...@@ -11,13 +11,13 @@ import type { Transaction } from 'types/api/transaction'; ...@@ -11,13 +11,13 @@ import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg'; import rightArrowIcon from 'icons/arrows/east.svg';
import transactionIcon from 'icons/transactions.svg';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType'; import TxType from 'ui/txs/TxType';
...@@ -54,26 +54,14 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -54,26 +54,14 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
justifyContent="space-between" justifyContent="space-between"
mb={ 6 } mb={ 6 }
> >
<Flex mr={ 3 }> <TxEntity
<Icon isLoading={ isLoading }
as={ transactionIcon } hash={ tx.hash }
boxSize="30px" fontWeight="700"
mr={ 2 } truncation="constant"
color="link" />
isLoading={ isLoading }
/>
<Address width="100%">
<AddressLink
hash={ tx.hash }
type="transaction"
fontWeight="700"
truncation="constant"
isLoading={ isLoading }
/>
</Address>
</Flex>
{ tx.timestamp && ( { tx.timestamp && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm"> <Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm" ml={ 3 }>
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
</Skeleton> </Skeleton>
) } ) }
......
...@@ -7,14 +7,13 @@ import type { L2DepositsItem } from 'types/api/l2Deposits'; ...@@ -7,14 +7,13 @@ import type { L2DepositsItem } from 'types/api/l2Deposits';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import blockIcon from 'icons/block.svg';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import Icon from 'ui/shared/chakra/Icon'; import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid'; import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -33,33 +32,23 @@ const DepositsListItem = ({ item, isLoading }: Props) => { ...@@ -33,33 +32,23 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>L1 block No</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L1 block No</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkExternal <BlockEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l1_block_number.toString() } }) } number={ item.l1_block_number }
fontWeight={ 600 }
display="flex"
isLoading={ isLoading } isLoading={ isLoading }
> fontSize="sm"
<Icon as={ blockIcon } boxSize={ 6 } isLoading={ isLoading }/> lineHeight={ 5 }
<Skeleton isLoaded={ !isLoading } ml={ 1 }>{ item.l1_block_number }</Skeleton> fontWeight={ 600 }
</LinkExternal> />
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>L2 txn hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L2 txn hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkInternal <TxEntity
href={ route({ pathname: '/tx/[hash]', query: { hash: item.l2_tx_hash } }) }
display="flex"
width="fit-content"
alignItems="center"
overflow="hidden"
w="100%"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l2_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ item.l2_tx_hash }/> />
</Skeleton>
</LinkInternal>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>Age</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>Age</ListItemMobileGrid.Label>
...@@ -69,18 +58,12 @@ const DepositsListItem = ({ item, isLoading }: Props) => { ...@@ -69,18 +58,12 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkExternal <TxEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) }
maxW="100%"
display="flex"
overflow="hidden"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l1_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 44px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ item.l1_tx_hash }/> />
</Skeleton>
</LinkExternal>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn origin</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn origin</ListItemMobileGrid.Label>
......
...@@ -7,14 +7,13 @@ import type { L2DepositsItem } from 'types/api/l2Deposits'; ...@@ -7,14 +7,13 @@ import type { L2DepositsItem } from 'types/api/l2Deposits';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import blockIcon from 'icons/block.svg';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import Icon from 'ui/shared/chakra/Icon'; import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import HashStringShorten from 'ui/shared/HashStringShorten'; import HashStringShorten from 'ui/shared/HashStringShorten';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -29,51 +28,35 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -29,51 +28,35 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
return ( return (
<Tr> <Tr>
<Td verticalAlign="middle" fontWeight={ 600 }> <Td verticalAlign="middle">
<LinkExternal <BlockEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l1_block_number.toString() } }) } number={ item.l1_block_number }
fontWeight={ 600 }
display="inline-flex"
isLoading={ isLoading } isLoading={ isLoading }
> fontSize="sm"
<Icon as={ blockIcon } boxSize={ 6 } isLoading={ isLoading }/> lineHeight={ 5 }
<Skeleton isLoaded={ !isLoading } ml={ 1 }> fontWeight={ 600 }
{ item.l1_block_number } />
</Skeleton>
</LinkExternal>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<LinkInternal <TxEntity
href={ route({ pathname: '/tx/[hash]', query: { hash: item.l2_tx_hash } }) }
display="flex"
width="fit-content"
alignItems="center"
overflow="hidden"
w="100%"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l2_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" ml={ 1 } overflow="hidden" whiteSpace="nowrap"> lineHeight={ 5 }
<HashStringShorten hash={ item.l2_tx_hash }/> truncation="constant"
</Skeleton> />
</LinkInternal>
</Td> </Td>
<Td verticalAlign="middle" pr={ 12 }> <Td verticalAlign="middle" pr={ 12 }>
<Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline-block"><span>{ timeAgo }</span></Skeleton> <Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline-block"><span>{ timeAgo }</span></Skeleton>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<LinkExternal <TxEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) }
maxW="100%"
display="inline-flex"
overflow="hidden"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l1_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> truncation="constant"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 44px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> fontSize="sm"
<HashStringShorten hash={ item.l1_tx_hash }/> lineHeight={ 5 }
</Skeleton> />
</LinkExternal>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<LinkExternal <LinkExternal
......
...@@ -3,16 +3,12 @@ import React from 'react'; ...@@ -3,16 +3,12 @@ import React from 'react';
import type { L2OutputRootsItem } from 'types/api/l2OutputRoots'; import type { L2OutputRootsItem } from 'types/api/l2OutputRoots';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Icon from 'ui/shared/chakra/Icon';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid'; import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -43,31 +39,23 @@ const OutputRootsListItem = ({ item, isLoading }: Props) => { ...@@ -43,31 +39,23 @@ const OutputRootsListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>L2 block #</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L2 block #</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
<LinkInternal <BlockEntityL2
display="flex"
width="fit-content"
alignItems="center"
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l2_block_number.toString() } }) }
isLoading={ isLoading } isLoading={ isLoading }
> number={ item.l2_block_number }
<Skeleton isLoaded={ !isLoading } display="inline-block">{ item.l2_block_number }</Skeleton> fontSize="sm"
</LinkInternal> lineHeight={ 5 }
noIcon
/>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkExternal <TxEntityL1
maxW="100%"
display="flex"
overflow="hidden"
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) }
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l1_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ item.l1_tx_hash }/> />
</Skeleton>
</LinkExternal>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>Output root</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>Output root</ListItemMobileGrid.Label>
......
...@@ -3,17 +3,12 @@ import React from 'react'; ...@@ -3,17 +3,12 @@ import React from 'react';
import type { L2OutputRootsItem } from 'types/api/l2OutputRoots'; import type { L2OutputRootsItem } from 'types/api/l2OutputRoots';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import txIcon from 'icons/transactions.svg';
import txBatchIcon from 'icons/txBatch.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Icon from 'ui/shared/chakra/Icon';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -35,34 +30,21 @@ const OutputRootsTableItem = ({ item, isLoading }: Props) => { ...@@ -35,34 +30,21 @@ const OutputRootsTableItem = ({ item, isLoading }: Props) => {
<Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline-block"><span>{ timeAgo }</span></Skeleton> <Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline-block"><span>{ timeAgo }</span></Skeleton>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<LinkInternal <BlockEntityL2
fontWeight={ 600 }
display="flex"
width="fit-content"
alignItems="center"
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l2_block_number.toString() } }) }
isLoading={ isLoading } isLoading={ isLoading }
> number={ item.l2_block_number }
<Icon as={ txBatchIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } display="inline-block" ml={ 1 }> lineHeight={ 5 }
{ item.l2_block_number } fontWeight={ 600 }
</Skeleton> />
</LinkInternal>
</Td> </Td>
<Td verticalAlign="middle" pr={ 12 }> <Td verticalAlign="middle" pr={ 12 }>
<Flex> <TxEntityL1
<LinkExternal isLoading={ isLoading }
maxW="100%" hash={ item.l1_tx_hash }
display="inline-flex" fontSize="sm"
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) } lineHeight={ 5 }
isLoading={ isLoading } />
>
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 } >
<HashStringShortenDynamic hash={ item.l1_tx_hash }/>
</Skeleton>
</LinkExternal>
</Flex>
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<Flex overflow="hidden" whiteSpace="nowrap" w="100%" alignItems="center"> <Flex overflow="hidden" whiteSpace="nowrap" w="100%" alignItems="center">
......
...@@ -6,12 +6,10 @@ import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches'; ...@@ -6,12 +6,10 @@ import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import txIcon from 'icons/transactions.svg';
import txBatchIcon from 'icons/txBatch.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Icon from 'ui/shared/chakra/Icon'; import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import LinkExternal from 'ui/shared/LinkExternal'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid'; import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
...@@ -31,19 +29,13 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => { ...@@ -31,19 +29,13 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>L2 block #</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L2 block #</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkInternal <BlockEntityL2
fontWeight={ 600 }
display="flex"
width="fit-content"
alignItems="center"
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l2_block_number.toString() } }) }
isLoading={ isLoading } isLoading={ isLoading }
> number={ item.l2_block_number }
<Icon as={ txBatchIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } ml={ 1 }> lineHeight={ 5 }
{ item.l2_block_number } fontWeight={ 600 }
</Skeleton> />
</LinkInternal>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>L2 block txn count</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L2 block txn count</ListItemMobileGrid.Label>
...@@ -60,34 +52,28 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => { ...@@ -60,34 +52,28 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>Epoch number</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>Epoch number</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
<LinkExternal <BlockEntityL1
fontWeight={ 600 }
display="inline-flex"
href={ feature.L1BaseUrl + route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.epoch_number.toString() } }) }
isLoading={ isLoading } isLoading={ isLoading }
> number={ item.epoch_number }
<Skeleton isLoaded={ !isLoading }> noIcon
{ item.epoch_number } fontSize="sm"
</Skeleton> lineHeight={ 5 }
</LinkExternal> fontWeight={ 600 }
/>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<VStack spacing={ 3 } w="100%" overflow="hidden" alignItems="flex-start"> <VStack spacing={ 3 } w="100%" overflow="hidden" alignItems="flex-start">
{ item.l1_tx_hashes.map(hash => ( { item.l1_tx_hashes.map(hash => (
<LinkExternal <TxEntityL1
maxW="100%"
display="inline-flex"
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: hash } }) }
key={ hash } key={ hash }
isLoading={ isLoading } isLoading={ isLoading }
> hash={ hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ hash }/> maxW="100%"
</Skeleton> />
</LinkExternal>
)) } )) }
</VStack> </VStack>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
......
...@@ -6,12 +6,10 @@ import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches'; ...@@ -6,12 +6,10 @@ import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import txIcon from 'icons/transactions.svg';
import txBatchIcon from 'icons/txBatch.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Icon from 'ui/shared/chakra/Icon'; import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import LinkExternal from 'ui/shared/LinkExternal'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -28,19 +26,13 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => { ...@@ -28,19 +26,13 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
return ( return (
<Tr> <Tr>
<Td> <Td>
<LinkInternal <BlockEntityL2
fontWeight={ 600 }
display="flex"
width="fit-content"
alignItems="center"
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.l2_block_number.toString() } }) }
isLoading={ isLoading } isLoading={ isLoading }
> number={ item.l2_block_number }
<Icon as={ txBatchIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } ml={ 1 }> lineHeight={ 5 }
{ item.l2_block_number } fontWeight={ 600 }
</Skeleton> />
</LinkInternal>
</Td> </Td>
<Td> <Td>
<LinkInternal <LinkInternal
...@@ -53,33 +45,27 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => { ...@@ -53,33 +45,27 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
</LinkInternal> </LinkInternal>
</Td> </Td>
<Td> <Td>
<LinkExternal <BlockEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: item.epoch_number.toString() } }) }
fontWeight={ 600 }
display="inline-flex"
isLoading={ isLoading } isLoading={ isLoading }
number={ item.epoch_number }
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 600 }
py="2px" py="2px"
> noIcon
<Skeleton isLoaded={ !isLoading } display="inline-block"> />
{ item.epoch_number }
</Skeleton>
</LinkExternal>
</Td> </Td>
<Td pr={ 12 }> <Td pr={ 12 }>
<VStack spacing={ 3 } alignItems="flex-start"> <VStack spacing={ 3 } alignItems="flex-start">
{ item.l1_tx_hashes.map(hash => ( { item.l1_tx_hashes.map(hash => (
<LinkExternal <TxEntityL1
maxW="100%"
display="inline-flex"
key={ hash } key={ hash }
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: hash } }) }
isLoading={ isLoading } isLoading={ isLoading }
> hash={ hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ hash }/> maxW="100%"
</Skeleton> />
</LinkExternal>
)) } )) }
</VStack> </VStack>
</Td> </Td>
......
...@@ -3,18 +3,14 @@ import React from 'react'; ...@@ -3,18 +3,14 @@ import React from 'react';
import type { L2WithdrawalsItem } from 'types/api/l2Withdrawals'; import type { L2WithdrawalsItem } from 'types/api/l2Withdrawals';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid'; import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -53,19 +49,12 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => { ...@@ -53,19 +49,12 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>L2 txn hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L2 txn hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkInternal <TxEntity
href={ route({ pathname: '/tx/[hash]', query: { hash: item.l2_tx_hash } }) } isLoading={ isLoading }
display="flex" hash={ item.l2_tx_hash }
width="fit-content" fontSize="sm"
alignItems="center" lineHeight={ 5 }
overflow="hidden" />
w="100%"
>
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }>
<HashStringShortenDynamic hash={ item.l2_tx_hash }/>
</Skeleton>
</LinkInternal>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
{ timeAgo && ( { timeAgo && (
...@@ -90,18 +79,12 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => { ...@@ -90,18 +79,12 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => {
<> <>
<ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>L1 txn hash</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px"> <ListItemMobileGrid.Value py="3px">
<LinkExternal <TxEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) }
maxW="100%"
display="inline-flex"
overflow="hidden"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l1_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> fontSize="sm"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 44px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> lineHeight={ 5 }
<HashStringShortenDynamic hash={ item.l1_tx_hash }/> />
</Skeleton>
</LinkExternal>
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
</> </>
) } ) }
......
...@@ -3,18 +3,14 @@ import React from 'react'; ...@@ -3,18 +3,14 @@ import React from 'react';
import type { L2WithdrawalsItem } from 'types/api/l2Withdrawals'; import type { L2WithdrawalsItem } from 'types/api/l2Withdrawals';
import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShorten from 'ui/shared/HashStringShorten'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
const feature = config.features.rollup; const feature = config.features.rollup;
...@@ -42,18 +38,13 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -42,18 +38,13 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
) : 'N/A' } ) : 'N/A' }
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<LinkInternal <TxEntity
href={ route({ pathname: '/tx/[hash]', query: { hash: item.l2_tx_hash } }) }
display="flex"
width="fit-content"
alignItems="center"
isLoading={ isLoading } isLoading={ isLoading }
> hash={ item.l2_tx_hash }
<Icon as={ txIcon } boxSize={ 6 } isLoading={ isLoading }/> truncation="constant"
<Skeleton isLoaded={ !isLoading } w="calc(100% - 36px)" overflow="hidden" whiteSpace="nowrap" ml={ 1 }> fontSize="sm"
<HashStringShorten hash={ item.l2_tx_hash }/> lineHeight={ 5 }
</Skeleton> />
</LinkInternal>
</Td> </Td>
<Td verticalAlign="middle" pr={ 12 }> <Td verticalAlign="middle" pr={ 12 }>
<Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline-block"> <Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline-block">
...@@ -68,15 +59,13 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => { ...@@ -68,15 +59,13 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
{ item.l1_tx_hash ? ( { item.l1_tx_hash ? (
<LinkExternal <TxEntityL1
href={ feature.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) }
isLoading={ isLoading } isLoading={ isLoading }
display="inline-flex" hash={ item.l1_tx_hash }
> truncation="constant"
<Skeleton isLoaded={ !isLoading }> fontSize="sm"
<HashStringShorten hash={ item.l1_tx_hash }/> lineHeight={ 5 }
</Skeleton> />
</LinkExternal>
) : ) :
'N/A' 'N/A'
} }
......
...@@ -29,7 +29,7 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s ...@@ -29,7 +29,7 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s
async() => apiFetch(configUrl), async() => apiFetch(configUrl),
{ {
select: (data) => (data as Array<MarketplaceAppOverview>).sort((a, b) => a.title.localeCompare(b.title)), select: (data) => (data as Array<MarketplaceAppOverview>).sort((a, b) => a.title.localeCompare(b.title)),
placeholderData: Array(9).fill(MARKETPLACE_APP), placeholderData: feature.isEnabled ? Array(9).fill(MARKETPLACE_APP) : undefined,
staleTime: Infinity, staleTime: Infinity,
enabled: feature.isEnabled, enabled: feature.isEnabled,
}); });
......
...@@ -4,9 +4,9 @@ import React, { useCallback } from 'react'; ...@@ -4,9 +4,9 @@ import React, { useCallback } from 'react';
import type { TransactionTag } from 'types/api/account'; import type { TransactionTag } from 'types/api/account';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
import TransactionSnippet from 'ui/shared/TransactionSnippet';
interface Props { interface Props {
item: TransactionTag; item: TransactionTag;
...@@ -27,7 +27,13 @@ const TransactionTagListItem = ({ item, isLoading, onEditClick, onDeleteClick }: ...@@ -27,7 +27,13 @@ const TransactionTagListItem = ({ item, isLoading, onEditClick, onDeleteClick }:
return ( return (
<ListItemMobile> <ListItemMobile>
<Flex alignItems="flex-start" flexDirection="column" maxW="100%"> <Flex alignItems="flex-start" flexDirection="column" maxW="100%">
<TransactionSnippet hash={ item.transaction_hash } isLoading={ isLoading }/> <TxEntity
hash={ item.transaction_hash }
isLoading={ isLoading }
withCopy
fontWeight={ 600 }
maxW="100%"
/>
<HStack spacing={ 3 } mt={ 4 }> <HStack spacing={ 3 } mt={ 4 }>
<Text fontSize="sm" fontWeight={ 500 }>Private tag</Text> <Text fontSize="sm" fontWeight={ 500 }>Private tag</Text>
<Tag isLoading={ isLoading } isTruncated>{ item.name }</Tag> <Tag isLoading={ isLoading } isTruncated>{ item.name }</Tag>
......
...@@ -7,8 +7,8 @@ import React, { useCallback } from 'react'; ...@@ -7,8 +7,8 @@ import React, { useCallback } from 'react';
import type { TransactionTag } from 'types/api/account'; import type { TransactionTag } from 'types/api/account';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
import TransactionSnippet from 'ui/shared/TransactionSnippet';
interface Props { interface Props {
item: TransactionTag; item: TransactionTag;
...@@ -29,7 +29,12 @@ const TransactionTagTableItem = ({ item, isLoading, onEditClick, onDeleteClick } ...@@ -29,7 +29,12 @@ const TransactionTagTableItem = ({ item, isLoading, onEditClick, onDeleteClick }
return ( return (
<Tr alignItems="top" key={ item.id }> <Tr alignItems="top" key={ item.id }>
<Td> <Td>
<TransactionSnippet hash={ item.transaction_hash } isLoading={ isLoading }/> <TxEntity
hash={ item.transaction_hash }
isLoading={ isLoading }
fontWeight={ 600 }
withCopy
/>
</Td> </Td>
<Td> <Td>
<Tag isLoading={ isLoading } isTruncated>{ item.name }</Tag> <Tag isLoading={ isLoading } isTruncated>{ item.name }</Tag>
......
import { Flex, Grid, Icon, Image, Box, Text, chakra, Skeleton, useColorMode } from '@chakra-ui/react'; import { Flex, Grid, Icon, Image, Box, Text, Skeleton, useColorMode } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { SearchResultItem } from 'types/api/search'; import type { SearchResultItem } from 'types/api/search';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import blockIcon from 'icons/block.svg';
import labelIcon from 'icons/publictags.svg'; import labelIcon from 'icons/publictags.svg';
import iconSuccess from 'icons/status/success.svg'; import iconSuccess from 'icons/status/success.svg';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import highlightText from 'lib/highlightText'; import highlightText from 'lib/highlightText';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
...@@ -16,6 +14,8 @@ import { saveToRecentKeywords } from 'lib/recentSearchKeywords'; ...@@ -16,6 +14,8 @@ import { saveToRecentKeywords } from 'lib/recentSearchKeywords';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import * as BlockEntity from 'ui/shared/entities/block/BlockEntity';
import * as TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
...@@ -143,28 +143,42 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -143,28 +143,42 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
case 'block': { case 'block': {
const shouldHighlightHash = data.block_hash.toLowerCase() === searchTerm.toLowerCase(); const shouldHighlightHash = data.block_hash.toLowerCase() === searchTerm.toLowerCase();
return ( return (
<Flex alignItems="center"> <BlockEntity.Container>
<Icon as={ blockIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/> <BlockEntity.Icon/>
<LinkInternal <BlockEntity.Link
fontWeight={ 700 } hash={ data.block_hash }
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.block_hash) } }) } number={ Number(data.block_number) }
onClick={ handleLinkClick } onClick={ handleLinkClick }
mr={ 4 }
> >
<Box as={ shouldHighlightHash ? 'span' : 'mark' }>{ data.block_number }</Box> <BlockEntity.Content
</LinkInternal> asProp={ shouldHighlightHash ? 'span' : 'mark' }
</Flex> number={ Number(data.block_number) }
fontSize="sm"
fontWeight={ 700 }
/>
</BlockEntity.Link>
</BlockEntity.Container>
); );
} }
case 'transaction': { case 'transaction': {
return ( return (
<Flex alignItems="center" overflow="hidden"> <TxEntity.Container>
<Icon as={ txIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/> <TxEntity.Icon/>
<chakra.mark display="block" overflow="hidden"> <TxEntity.Link
<AddressLink hash={ data.tx_hash } type="transaction" fontWeight={ 700 } display="block" onClick={ handleLinkClick }/> isLoading={ isLoading }
</chakra.mark> hash={ data.tx_hash }
</Flex> onClick={ handleLinkClick }
>
<TxEntity.Content
asProp="mark"
hash={ data.tx_hash }
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 700 }
/>
</TxEntity.Link>
</TxEntity.Container>
); );
} }
} }
......
import { chakra, Tr, Td, Text, Flex, Icon, Image, Box, Skeleton, useColorMode } from '@chakra-ui/react'; import { Tr, Td, Text, Flex, Icon, Image, Box, Skeleton, useColorMode } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { SearchResultItem } from 'types/api/search'; import type { SearchResultItem } from 'types/api/search';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import blockIcon from 'icons/block.svg';
import labelIcon from 'icons/publictags.svg'; import labelIcon from 'icons/publictags.svg';
import iconSuccess from 'icons/status/success.svg'; import iconSuccess from 'icons/status/success.svg';
import txIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import highlightText from 'lib/highlightText'; import highlightText from 'lib/highlightText';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
...@@ -16,6 +14,8 @@ import { saveToRecentKeywords } from 'lib/recentSearchKeywords'; ...@@ -16,6 +14,8 @@ import { saveToRecentKeywords } from 'lib/recentSearchKeywords';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import * as BlockEntity from 'ui/shared/entities/block/BlockEntity';
import * as TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
...@@ -220,16 +220,22 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -220,16 +220,22 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
return ( return (
<> <>
<Td fontSize="sm"> <Td fontSize="sm">
<Flex alignItems="center"> <BlockEntity.Container>
<Icon as={ blockIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/> <BlockEntity.Icon/>
<LinkInternal <BlockEntity.Link
fontWeight={ 700 } hash={ data.block_hash }
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.block_hash) } }) } number={ Number(data.block_number) }
onClick={ handleLinkClick } onClick={ handleLinkClick }
> >
<Box as={ shouldHighlightHash ? 'span' : 'mark' }>{ data.block_number }</Box> <BlockEntity.Content
</LinkInternal> asProp={ shouldHighlightHash ? 'span' : 'mark' }
</Flex> number={ Number(data.block_number) }
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 700 }
/>
</BlockEntity.Link>
</BlockEntity.Container>
</Td> </Td>
<Td fontSize="sm" verticalAlign="middle"> <Td fontSize="sm" verticalAlign="middle">
<Box overflow="hidden" whiteSpace="nowrap" as={ shouldHighlightHash ? 'mark' : 'span' } display="block"> <Box overflow="hidden" whiteSpace="nowrap" as={ shouldHighlightHash ? 'mark' : 'span' } display="block">
...@@ -247,12 +253,22 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -247,12 +253,22 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
return ( return (
<> <>
<Td colSpan={ 2 } fontSize="sm"> <Td colSpan={ 2 } fontSize="sm">
<Flex alignItems="center"> <TxEntity.Container>
<Icon as={ txIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/> <TxEntity.Icon/>
<chakra.mark overflow="hidden"> <TxEntity.Link
<AddressLink display="block" hash={ data.tx_hash } type="transaction" fontWeight={ 700 } onClick={ handleLinkClick } truncation="dynamic"/> isLoading={ isLoading }
</chakra.mark> hash={ data.tx_hash }
</Flex> onClick={ handleLinkClick }
>
<TxEntity.Content
asProp="mark"
hash={ data.tx_hash }
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 700 }
/>
</TxEntity.Link>
</TxEntity.Container>
</Td> </Td>
<Td fontSize="sm" verticalAlign="middle" isNumeric> <Td fontSize="sm" verticalAlign="middle" isNumeric>
<Text variant="secondary">{ dayjs(data.timestamp).format('llll') }</Text> <Text variant="secondary">{ dayjs(data.timestamp).format('llll') }</Text>
......
...@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react'; ...@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
import CopyIcon from 'icons/copy.svg'; import CopyIcon from 'icons/copy.svg';
interface Props { export interface Props {
text: string; text: string;
className?: string; className?: string;
isLoading?: boolean; isLoading?: boolean;
......
import { Tooltip } from '@chakra-ui/react'; import { Tooltip, chakra } from '@chakra-ui/react';
import type { As } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import shortenString from 'lib/shortenString'; import shortenString from 'lib/shortenString';
...@@ -6,16 +7,17 @@ import shortenString from 'lib/shortenString'; ...@@ -6,16 +7,17 @@ import shortenString from 'lib/shortenString';
interface Props { interface Props {
hash: string; hash: string;
isTooltipDisabled?: boolean; isTooltipDisabled?: boolean;
as?: As;
} }
const HashStringShorten = ({ hash, isTooltipDisabled }: Props) => { const HashStringShorten = ({ hash, isTooltipDisabled, as = 'span' }: Props) => {
if (hash.length <= 8) { if (hash.length <= 8) {
return <span>{ hash }</span>; return <chakra.span as={ as }>{ hash }</chakra.span>;
} }
return ( return (
<Tooltip label={ hash } isDisabled={ isTooltipDisabled }> <Tooltip label={ hash } isDisabled={ isTooltipDisabled }>
{ shortenString(hash) } <chakra.span as={ as }>{ shortenString(hash) }</chakra.span>
</Tooltip> </Tooltip>
); );
}; };
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
// so i did it with js // so i did it with js
import { Tooltip } from '@chakra-ui/react'; import type { As } from '@chakra-ui/react';
import { Tooltip, chakra } from '@chakra-ui/react';
import _debounce from 'lodash/debounce'; import _debounce from 'lodash/debounce';
import React, { useCallback, useEffect, useRef } from 'react'; import React, { useCallback, useEffect, useRef } from 'react';
import type { FontFace } from 'use-font-face-observer'; import type { FontFace } from 'use-font-face-observer';
...@@ -24,9 +25,10 @@ interface Props { ...@@ -24,9 +25,10 @@ interface Props {
fontWeight?: string | number; fontWeight?: string | number;
isTooltipDisabled?: boolean; isTooltipDisabled?: boolean;
tailLength?: number; tailLength?: number;
as?: As;
} }
const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled, tailLength = TAIL_LENGTH }: Props) => { const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled, tailLength = TAIL_LENGTH, as = 'span' }: Props) => {
const elementRef = useRef<HTMLSpanElement>(null); const elementRef = useRef<HTMLSpanElement>(null);
const [ displayedString, setDisplayedString ] = React.useState(hash); const [ displayedString, setDisplayedString ] = React.useState(hash);
...@@ -88,7 +90,7 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled, ...@@ -88,7 +90,7 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled,
}; };
}, [ calculateString ]); }, [ calculateString ]);
const content = <span ref={ elementRef }>{ displayedString }</span>; const content = <chakra.span ref={ elementRef } as={ as }>{ displayedString }</chakra.span>;
const isTruncated = hash.length !== displayedString.length; const isTruncated = hash.length !== displayedString.length;
if (isTruncated) { if (isTruncated) {
......
...@@ -5,7 +5,6 @@ import React from 'react'; ...@@ -5,7 +5,6 @@ import React from 'react';
import type { TokenTransfer } from 'types/api/tokenTransfer'; import type { TokenTransfer } from 'types/api/tokenTransfer';
import eastArrowIcon from 'icons/arrows/east.svg'; import eastArrowIcon from 'icons/arrows/east.svg';
import transactionIcon from 'icons/transactions.svg';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
...@@ -13,6 +12,7 @@ import AddressLink from 'ui/shared/address/AddressLink'; ...@@ -13,6 +12,7 @@ import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet'; import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet';
...@@ -66,23 +66,12 @@ const TokenTransferListItem = ({ ...@@ -66,23 +66,12 @@ const TokenTransferListItem = ({
{ 'token_id' in total && <TokenTransferNft hash={ token.address } id={ total.token_id } isLoading={ isLoading }/> } { 'token_id' in total && <TokenTransferNft hash={ token.address } id={ total.token_id } isLoading={ isLoading }/> }
{ showTxInfo && txHash && ( { showTxInfo && txHash && (
<Flex justifyContent="space-between" alignItems="center" lineHeight="24px" width="100%"> <Flex justifyContent="space-between" alignItems="center" lineHeight="24px" width="100%">
<Flex> <TxEntity
<Icon isLoading={ isLoading }
as={ transactionIcon } hash={ txHash }
boxSize="30px" truncation="constant"
color="link" fontWeight="700"
isLoading={ isLoading } />
/>
<Address width="100%" ml={ 2 }>
<AddressLink
hash={ txHash }
type="transaction"
fontWeight="700"
truncation="constant"
isLoading={ isLoading }
/>
</Address>
</Flex>
{ timestamp && ( { timestamp && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm"> <Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
......
...@@ -10,6 +10,7 @@ import AddressIcon from 'ui/shared/address/AddressIcon'; ...@@ -10,6 +10,7 @@ import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet'; import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet';
import { getTokenTransferTypeText } from 'ui/shared/TokenTransfer/helpers'; import { getTokenTransferTypeText } from 'ui/shared/TokenTransfer/helpers';
...@@ -59,9 +60,13 @@ const TokenTransferTableItem = ({ ...@@ -59,9 +60,13 @@ const TokenTransferTableItem = ({
</Td> </Td>
{ showTxInfo && txHash && ( { showTxInfo && txHash && (
<Td> <Td>
<Address display="inline-flex" maxW="100%" fontWeight={ 600 } mt="7px"> <TxEntity
<AddressLink type="transaction" hash={ txHash } isLoading={ isLoading }/> hash={ txHash }
</Address> isLoading={ isLoading }
fontWeight={ 600 }
noIcon
mt="7px"
/>
{ timestamp && ( { timestamp && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" mt="10px" display="inline-block"> <Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" mt="10px" display="inline-block">
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
......
import { useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import transactionIcon from 'icons/transactions.svg';
import Address from 'ui/shared/address/Address';
import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
interface Props {
hash: string;
isLoading?: boolean;
}
const TransactionSnippet = ({ hash, isLoading }: Props) => {
return (
<Address maxW="100%">
<Icon as={ transactionIcon } boxSize={ 6 } color={ useColorModeValue('gray.500', 'gray.400') } isLoading={ isLoading }/>
<AddressLink hash={ hash } fontWeight="600" type="transaction" ml={ 2 } isLoading={ isLoading }/>
<CopyToClipboard text={ hash } isLoading={ isLoading }/>
</Address>
);
};
export default React.memo(TransactionSnippet);
...@@ -6,6 +6,9 @@ interface Props { ...@@ -6,6 +6,9 @@ interface Props {
children: React.ReactNode; children: React.ReactNode;
} }
/**
* @deprecated use `ui/shared/entities/address` instead
*/
const Address = ({ children, className }: Props) => { const Address = ({ children, className }: Props) => {
return <Flex alignItems="center" overflow="hidden" className={ className }>{ children }</Flex>; return <Flex alignItems="center" overflow="hidden" className={ className }>{ children }</Flex>;
}; };
......
...@@ -24,35 +24,25 @@ type CommonProps = { ...@@ -24,35 +24,25 @@ type CommonProps = {
} }
type AddressTokenTxProps = { type AddressTokenTxProps = {
type: 'address' | 'token' | 'transaction'; type: 'address' | 'token';
hash: 'hash'; hash: 'hash';
} }
type BlockProps = {
type: 'block';
hash: string;
blockHeight: string;
}
type AddressTokenProps = { type AddressTokenProps = {
type: 'address_token'; type: 'address_token';
hash: string; hash: string;
tokenHash: string; tokenHash: string;
} }
type Props = CommonProps & (AddressTokenTxProps | BlockProps | AddressTokenProps); type Props = CommonProps & (AddressTokenTxProps | AddressTokenProps);
const AddressLink = (props: Props) => { const AddressLink = (props: Props) => {
const { alias, type, className, truncation = 'dynamic', hash, fontWeight, target = '_self', isDisabled, isLoading } = props; const { alias, type, className, truncation = 'dynamic', hash, fontWeight, target = '_self', isDisabled, isLoading } = props;
const isMobile = useIsMobile(); const isMobile = useIsMobile();
let url; let url;
if (type === 'transaction') { if (type === 'token') {
url = route({ pathname: '/tx/[hash]', query: { ...props.query, hash } });
} else if (type === 'token') {
url = route({ pathname: '/token/[hash]', query: { ...props.query, hash } }); url = route({ pathname: '/token/[hash]', query: { ...props.query, hash } });
} else if (type === 'block') {
url = route({ pathname: '/block/[height_or_hash]', query: { ...props.query, height_or_hash: props.blockHeight } });
} else if (type === 'address_token') { } else if (type === 'address_token') {
url = route({ pathname: '/address/[hash]', query: { ...props.query, hash, tab: 'token_transfers', token: props.tokenHash, scroll_to_tabs: 'true' } }); url = route({ pathname: '/address/[hash]', query: { ...props.query, hash, tab: 'token_transfers', token: props.tokenHash, scroll_to_tabs: 'true' } });
} else { } else {
......
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import * as addressMock from 'mocks/address/address';
import TestApp from 'playwright/TestApp';
import AddressEntity from './AddressEntity';
const iconSizes = [ 'md', 'lg' ];
test.use({ viewport: { width: 180, height: 100 } });
test.describe('icon size', () => {
iconSizes.forEach((size) => {
test(size, async({ mount }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={ addressMock.withoutName }
iconSize={ size }
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
});
});
test.describe('contract', () => {
test('unverified', async({ mount, page }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={{ ...addressMock.contract, is_verified: false }}
/>
</TestApp>,
);
await component.getByText(/eternal/i).hover();
await expect(page).toHaveScreenshot();
});
test('verified', async({ mount }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={{ ...addressMock.contract, is_verified: true }}
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
});
test.describe('loading', () => {
test('without alias', async({ mount }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={ addressMock.withoutName }
isLoading
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('with alias', async({ mount }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={ addressMock.withName }
isLoading
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
});
test('external link', async({ mount }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={ addressMock.withoutName }
isExternal
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('customization', async({ mount }) => {
const component = await mount(
<TestApp>
<AddressEntity
address={ addressMock.withoutName }
truncation="constant"
p={ 3 }
borderWidth="1px"
borderColor="blue.700"
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
import type { As } from '@chakra-ui/react';
import { Flex, Skeleton, Tooltip, chakra } from '@chakra-ui/react';
import _omit from 'lodash/omit';
import React from 'react';
import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
import type { AddressParam } from 'types/api/addressParams';
import { route } from 'nextjs-routes';
import iconContractVerified from 'icons/contract_verified.svg';
import iconContract from 'icons/contract.svg';
import * as EntityBase from 'ui/shared/entities/base/components';
import { getIconProps } from '../base/utils';
interface LinkProps extends Pick<EntityProps, 'className' | 'address' | 'onClick' | 'isLoading' | 'isExternal' | 'href' | 'query'> {
children: React.ReactNode;
}
const Link = chakra((props: LinkProps) => {
const defaultHref = route({ pathname: '/address/[hash]', query: { ...props.query, hash: props.address.hash } });
return (
<EntityBase.Link
{ ...props }
href={ props.href ?? defaultHref }
>
{ props.children }
</EntityBase.Link>
);
});
type IconProps = Pick<EntityProps, 'address' | 'isLoading' | 'iconSize'> & {
asProp?: As;
};
const Icon = (props: IconProps) => {
const styles = {
...getIconProps(props.iconSize),
marginRight: 2,
};
if (props.isLoading) {
return <Skeleton { ...styles } borderRadius="full" flexShrink={ 0 }/>;
}
if (props.address.is_contract) {
if (props.address.is_verified) {
return (
<EntityBase.Icon
{ ...props }
asProp={ iconContractVerified }
color="green.500"
/>
);
}
return (
<EntityBase.Icon
{ ...props }
asProp={ iconContract }
/>
);
}
return (
<Tooltip label={ props.address.implementation_name }>
<Flex { ...styles }>
<Jazzicon diameter={ props.iconSize === 'lg' ? 30 : 20 } seed={ jsNumberForAddress(props.address.hash) }/>
</Flex>
</Tooltip>
);
};
type ContentProps = Omit<EntityBase.ContentBaseProps, 'text'> & Pick<EntityProps, 'address'>;
const Content = chakra((props: ContentProps) => {
if (props.address.name) {
return (
<Tooltip label={ props.address.hash } maxW="100vw">
<Skeleton isLoaded={ !props.isLoading } overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap" as="span">
{ props.address.name }
</Skeleton>
</Tooltip>
);
}
return (
<EntityBase.Content
{ ...props }
text={ props.address.hash }
/>
);
});
type CopyProps = Omit<EntityBase.CopyBaseProps, 'text'> & Pick<EntityProps, 'address'>;
const Copy = (props: CopyProps) => {
return (
<EntityBase.Copy
{ ...props }
text={ props.address.hash }
withCopy={ props.withCopy ?? true }
/>
);
};
const Container = EntityBase.Container;
export interface EntityProps extends EntityBase.EntityBaseProps {
address: Pick<AddressParam, 'hash' | 'name' | 'is_contract' | 'is_verified' | 'implementation_name'>;
}
const AddressEntry = (props: EntityProps) => {
const linkProps = _omit(props, [ 'className' ]);
const partsProps = _omit(props, [ 'className', 'onClick' ]);
return (
<Container className={ props.className }>
<Icon { ...partsProps }/>
<Link { ...linkProps }>
<Content { ...partsProps }/>
</Link>
<Copy { ...partsProps }/>
</Container>
);
};
export default React.memo(chakra(AddressEntry));
export {
Container,
Link,
Icon,
Content,
Copy,
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment