diff --git a/apps/app/public/common.css b/apps/app/public/common.css index 3136f6be..12059887 100644 --- a/apps/app/public/common.css +++ b/apps/app/public/common.css @@ -1 +1,1673 @@ -/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:Manrope,sans-serif;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}h1,h2,h3,h4{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b{font-weight:bolder}code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}button,select{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0;text-transform:none}[type=button],button{-webkit-appearance:button;background-color:transparent;background-image:none}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}h1,h2,h3,h4,p,ul{margin:0}ul{list-style:none;padding:0}button{cursor:pointer}iframe,img,svg{display:block;vertical-align:middle}img{height:auto;max-width:100%}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(138,219,201,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(138,219,201,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.bottom-2{bottom:.5rem}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.-z-50{z-index:-50}.z-10{z-index:10}.z-50{z-index:50}.m-2{margin:.5rem}.-my-1{margin-bottom:-.25rem;margin-top:-.25rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-0{margin-bottom:0}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-10{margin-left:2.5rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.h-16{height:4rem}.h-4{height:1rem}.h-45{height:11.93rem}.h-5{height:1.25rem}.h-7{height:1.75rem}.h-72{height:18rem}.h-8{height:2rem}.h-80{height:20rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-60{max-height:15rem}.w-20{width:5rem}.w-4{width:1rem}.w-44{width:11rem}.w-5{width:1.25rem}.w-60{width:15rem}.w-65{width:16.5rem}.w-7{width:1.75rem}.w-80{width:20rem}.w-full{width:100%}.max-w-full{max-width:100%}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{user-select:none}.appearance-none{appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.overflow-hidden,.truncate{overflow:hidden}.truncate{text-overflow:ellipsis;white-space:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-b-lg{border-bottom-left-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-bl-md{border-bottom-left-radius:.375rem}.rounded-tr{border-top-right-radius:.25rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-solid{border-style:solid}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-neargreen-200{--tw-border-opacity:1;border-color:rgb(51 142 123/var(--tw-border-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(27 27 27/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(13 73 74/var(--tw-bg-opacity))}.bg-neargreen-200{--tw-bg-opacity:1;background-color:rgb(51 142 123/var(--tw-bg-opacity))}.bg-warning-light{--tw-bg-opacity:1;background-color:rgb(235 199 199/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-opacity-10{--tw-bg-opacity:0.1}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-current{fill:currentColor}.fill-white{fill:#fff}.p-0{padding:0}.p-1{padding:.25rem}.p-3{padding:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.pb-2{padding-bottom:.5rem}.pr-2{padding-right:.5rem}.pt-1{padding-top:.25rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.font-thin{font-weight:100}.leading-6{line-height:1.5rem}.leading-8{line-height:2rem}.text-black{--tw-text-opacity:1;color:rgb(27 27 27/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(128 209 191/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-green-500{--tw-text-opacity:1;color:rgb(13 73 74/var(--tw-text-opacity))}.text-warning-dark{--tw-text-opacity:1;color:rgb(191 79 79/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.no-underline{text-decoration-line:none}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.drop-shadow-md{--tw-drop-shadow:drop-shadow(0 4px 3px rgba(0,0,0,.07)) drop-shadow(0 2px 2px rgba(0,0,0,.06));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}b{font-weight:600}.soft-shadow{box-shadow:0 2.6px 6.3px rgba(0,0,0,.06),0 6.3px 16px rgba(0,0,0,.04),0 12px 32.6px rgba(0,0,0,.027),0 21.4px 67.2px rgba(0,0,0,.018),0 43px 184px rgba(0,0,0,.011)} \ No newline at end of file +/* +! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com +*//* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; /* 1 */ + border-width: 0; /* 2 */ + border-style: solid; /* 2 */ + border-color: #e5e7eb; /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +*/ + +html { + line-height: 1.5; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -moz-tab-size: 4; /* 3 */ + -o-tab-size: 4; + tab-size: 4; /* 3 */ + font-family: 'Manrope', sans-serif; /* 4 */ + font-feature-settings: normal; /* 5 */ + font-variation-settings: normal; /* 6 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; /* 1 */ + line-height: inherit; /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ + border-top-width: 1px; /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ + border-collapse: collapse; /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ + font-size: 100%; /* 1 */ + font-weight: inherit; /* 1 */ + line-height: inherit; /* 1 */ + color: inherit; /* 1 */ + margin: 0; /* 2 */ + padding: 0; /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; /* 1 */ + background-color: transparent; /* 2 */ + background-image: none; /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(138 219 201 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(138 219 201 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} +.container { + width: 100%; +} +@media (min-width: 640px) { + + .container { + max-width: 640px; + } +} +@media (min-width: 768px) { + + .container { + max-width: 768px; + } +} +@media (min-width: 1024px) { + + .container { + max-width: 1024px; + } +} +@media (min-width: 1280px) { + + .container { + max-width: 1280px; + } +} +@media (min-width: 1536px) { + + .container { + max-width: 1536px; + } +} +.pointer-events-none { + pointer-events: none; +} +.fixed { + position: fixed; +} +.absolute { + position: absolute; +} +.relative { + position: relative; +} +.inset-0 { + inset: 0px; +} +.bottom-2 { + bottom: 0.5rem; +} +.left-\[50\%\] { + left: 50%; +} +.right-0 { + right: 0px; +} +.right-2 { + right: 0.5rem; +} +.top-0 { + top: 0px; +} +.top-2 { + top: 0.5rem; +} +.top-\[50\%\] { + top: 50%; +} +.-z-50 { + z-index: -50; +} +.z-0 { + z-index: 0; +} +.z-10 { + z-index: 10; +} +.z-50 { + z-index: 50; +} +.order-1 { + order: 1; +} +.order-2 { + order: 2; +} +.col-span-2 { + grid-column: span 2 / span 2; +} +.m-2 { + margin: 0.5rem; +} +.-my-1 { + margin-top: -0.25rem; + margin-bottom: -0.25rem; +} +.mx-3 { + margin-left: 0.75rem; + margin-right: 0.75rem; +} +.mx-auto { + margin-left: auto; + margin-right: auto; +} +.-mt-14 { + margin-top: -3.5rem; +} +.-mt-48 { + margin-top: -12rem; +} +.mb-0 { + margin-bottom: 0px; +} +.mb-10 { + margin-bottom: 2.5rem; +} +.mb-2 { + margin-bottom: 0.5rem; +} +.mb-3 { + margin-bottom: 0.75rem; +} +.mb-4 { + margin-bottom: 1rem; +} +.ml-1 { + margin-left: 0.25rem; +} +.ml-10 { + margin-left: 2.5rem; +} +.ml-2 { + margin-left: 0.5rem; +} +.ml-4 { + margin-left: 1rem; +} +.ml-auto { + margin-left: auto; +} +.mr-1 { + margin-right: 0.25rem; +} +.mr-2 { + margin-right: 0.5rem; +} +.mr-3 { + margin-right: 0.75rem; +} +.mt-1 { + margin-top: 0.25rem; +} +.mt-10 { + margin-top: 2.5rem; +} +.mt-2 { + margin-top: 0.5rem; +} +.block { + display: block; +} +.inline-block { + display: inline-block; +} +.flex { + display: flex; +} +.inline-flex { + display: inline-flex; +} +.table { + display: table; +} +.grid { + display: grid; +} +.h-10 { + height: 2.5rem; +} +.h-16 { + height: 4rem; +} +.h-3 { + height: 0.75rem; +} +.h-4 { + height: 1rem; +} +.h-45 { + height: 11.93rem; +} +.h-5 { + height: 1.25rem; +} +.h-7 { + height: 1.75rem; +} +.h-72 { + height: 18rem; +} +.h-8 { + height: 2rem; +} +.h-80 { + height: 20rem; +} +.h-9 { + height: 2.25rem; +} +.h-\[57px\] { + height: 57px; +} +.h-auto { + height: auto; +} +.h-full { + height: 100%; +} +.h-screen { + height: 100vh; +} +.max-h-60 { + max-height: 15rem; +} +.max-h-\[85vh\] { + max-height: 85vh; +} +.w-10 { + width: 2.5rem; +} +.w-14 { + width: 3.5rem; +} +.w-20 { + width: 5rem; +} +.w-24 { + width: 6rem; +} +.w-3 { + width: 0.75rem; +} +.w-32 { + width: 8rem; +} +.w-36 { + width: 9rem; +} +.w-4 { + width: 1rem; +} +.w-44 { + width: 11rem; +} +.w-5 { + width: 1.25rem; +} +.w-60 { + width: 15rem; +} +.w-65 { + width: 16.5rem; +} +.w-7 { + width: 1.75rem; +} +.w-80 { + width: 20rem; +} +.w-9 { + width: 2.25rem; +} +.w-full { + width: 100%; +} +.min-w-full { + min-width: 100%; +} +.max-w-\[110px\] { + max-width: 110px; +} +.max-w-\[120px\] { + max-width: 120px; +} +.max-w-\[450px\] { + max-width: 450px; +} +.max-w-\[80px\] { + max-width: 80px; +} +.max-w-full { + max-width: 100%; +} +.max-w-xs { + max-width: 20rem; +} +.flex-1 { + flex: 1 1 0%; +} +.flex-shrink-0 { + flex-shrink: 0; +} +.flex-grow { + flex-grow: 1; +} +.translate-x-\[-50\%\] { + --tw-translate-x: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} +.translate-y-\[-50\%\] { + --tw-translate-y: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} +.rotate-0 { + --tw-rotate: 0deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} +.rotate-180 { + --tw-rotate: 180deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} +.transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} +@keyframes pulse { + + 50% { + opacity: .5; + } +} +.animate-pulse { + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} +.cursor-pointer { + cursor: pointer; +} +.touch-none { + touch-action: none; +} +.select-none { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.appearance-none { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} +.grid-flow-col { + grid-auto-flow: column; +} +.grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); +} +.grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} +.grid-rows-2 { + grid-template-rows: repeat(2, minmax(0, 1fr)); +} +.grid-rows-3 { + grid-template-rows: repeat(3, minmax(0, 1fr)); +} +.flex-row { + flex-direction: row; +} +.flex-col { + flex-direction: column; +} +.flex-wrap { + flex-wrap: wrap; +} +.items-center { + align-items: center; +} +.justify-end { + justify-content: flex-end; +} +.justify-center { + justify-content: center; +} +.justify-between { + justify-content: space-between; +} +.gap-2 { + gap: 0.5rem; +} +.gap-3 { + gap: 0.75rem; +} +.gap-4 { + gap: 1rem; +} +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} +.space-y-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); +} +.divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} +.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-divide-opacity)); +} +.overflow-hidden { + overflow: hidden; +} +.overflow-x-auto { + overflow-x: auto; +} +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.whitespace-nowrap { + white-space: nowrap; +} +.break-words { + overflow-wrap: break-word; +} +.break-all { + word-break: break-all; +} +.rounded { + border-radius: 0.25rem; +} +.rounded-\[10px\] { + border-radius: 10px; +} +.rounded-\[6px\] { + border-radius: 6px; +} +.rounded-full { + border-radius: 9999px; +} +.rounded-lg { + border-radius: 0.5rem; +} +.rounded-md { + border-radius: 0.375rem; +} +.rounded-xl { + border-radius: 0.75rem; +} +.rounded-b-lg { + border-bottom-right-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; +} +.rounded-bl-md { + border-bottom-left-radius: 0.375rem; +} +.rounded-tr { + border-top-right-radius: 0.25rem; +} +.border { + border-width: 1px; +} +.border-2 { + border-width: 2px; +} +.border-b { + border-bottom-width: 1px; +} +.border-t { + border-top-width: 1px; +} +.border-solid { + border-style: solid; +} +.border-gray-100 { + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity)); +} +.border-green-900\/10 { + border-color: rgb(0 33 34 / 0.1); +} +.border-neargreen-200 { + --tw-border-opacity: 1; + border-color: rgb(51 142 123 / var(--tw-border-opacity)); +} +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(27 27 27 / var(--tw-bg-opacity)); +} +.bg-blue-900\/10 { + background-color: rgb(76 189 187 / 0.1); +} +.bg-emerald-50 { + --tw-bg-opacity: 1; + background-color: rgb(236 253 245 / var(--tw-bg-opacity)); +} +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} +.bg-gray-300 { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)); +} +.bg-gray-400 { + --tw-bg-opacity: 1; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)); +} +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} +.bg-green-100 { + --tw-bg-opacity: 1; + background-color: rgb(53 113 114 / var(--tw-bg-opacity)); +} +.bg-green-500 { + --tw-bg-opacity: 1; + background-color: rgb(13 73 74 / var(--tw-bg-opacity)); +} +.bg-neargreen-200 { + --tw-bg-opacity: 1; + background-color: rgb(51 142 123 / var(--tw-bg-opacity)); +} +.bg-red-50 { + --tw-bg-opacity: 1; + background-color: rgb(254 242 242 / var(--tw-bg-opacity)); +} +.bg-warning-light { + --tw-bg-opacity: 1; + background-color: rgb(235 199 199 / var(--tw-bg-opacity)); +} +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} +.bg-yellow-50 { + --tw-bg-opacity: 1; + background-color: rgb(254 252 232 / var(--tw-bg-opacity)); +} +.bg-opacity-10 { + --tw-bg-opacity: 0.1; +} +.bg-opacity-90 { + --tw-bg-opacity: 0.9; +} +.bg-hero-pattern { + background-image: url('/images/wavey-fingerprint.png'); +} +.fill-current { + fill: currentColor; +} +.fill-white { + fill: #fff; +} +.p-0 { + padding: 0px; +} +.p-0\.5 { + padding: 0.125rem; +} +.p-1 { + padding: 0.25rem; +} +.p-1\.5 { + padding: 0.375rem; +} +.p-2 { + padding: 0.5rem; +} +.p-3 { + padding: 0.75rem; +} +.p-\[25px\] { + padding: 25px; +} +.px-1 { + padding-left: 0.25rem; + padding-right: 0.25rem; +} +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} +.px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; +} +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} +.py-5 { + padding-top: 1.25rem; + padding-bottom: 1.25rem; +} +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} +.pb-2 { + padding-bottom: 0.5rem; +} +.pb-3 { + padding-bottom: 0.75rem; +} +.pb-5 { + padding-bottom: 1.25rem; +} +.pb-8 { + padding-bottom: 2rem; +} +.pl-2 { + padding-left: 0.5rem; +} +.pl-5 { + padding-left: 1.25rem; +} +.pl-6 { + padding-left: 1.5rem; +} +.pr-2 { + padding-right: 0.5rem; +} +.pr-4 { + padding-right: 1rem; +} +.pt-1 { + padding-top: 0.25rem; +} +.pt-14 { + padding-top: 3.5rem; +} +.pt-3 { + padding-top: 0.75rem; +} +.pt-4 { + padding-top: 1rem; +} +.pt-8 { + padding-top: 2rem; +} +.text-left { + text-align: left; +} +.text-center { + text-align: center; +} +.text-right { + text-align: right; +} +.align-middle { + vertical-align: middle; +} +.align-bottom { + vertical-align: bottom; +} +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} +.font-bold { + font-weight: 700; +} +.font-medium { + font-weight: 500; +} +.font-normal { + font-weight: 400; +} +.font-semibold { + font-weight: 600; +} +.font-thin { + font-weight: 100; +} +.uppercase { + text-transform: uppercase; +} +.leading-6 { + line-height: 1.5rem; +} +.leading-7 { + line-height: 1.75rem; +} +.leading-8 { + line-height: 2rem; +} +.tracking-wider { + letter-spacing: 0.05em; +} +.text-black { + --tw-text-opacity: 1; + color: rgb(27 27 27 / var(--tw-text-opacity)); +} +.text-blue-600 { + --tw-text-opacity: 1; + color: rgb(128 209 191 / var(--tw-text-opacity)); +} +.text-emerald-500 { + --tw-text-opacity: 1; + color: rgb(16 185 129 / var(--tw-text-opacity)); +} +.text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} +.text-green-400 { + --tw-text-opacity: 1; + color: rgb(23 83 84 / var(--tw-text-opacity)); +} +.text-green-500 { + --tw-text-opacity: 1; + color: rgb(13 73 74 / var(--tw-text-opacity)); +} +.text-nearblue-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} +.text-neargreen { + --tw-text-opacity: 1; + color: rgb(53 193 84 / var(--tw-text-opacity)); +} +.text-red-500 { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); +} +.text-warning-dark { + --tw-text-opacity: 1; + color: rgb(191 79 79 / var(--tw-text-opacity)); +} +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} +.text-yellow-500 { + --tw-text-opacity: 1; + color: rgb(234 179 8 / var(--tw-text-opacity)); +} +.no-underline { + text-decoration-line: none; +} +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} +.shadow-\[0_2px_10px\] { + --tw-shadow: 0 2px 10px; + --tw-shadow-colored: 0 2px 10px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} +.shadow-\[hsl\(206_22\%_7\%_\/_35\%\)_0px_10px_38px_-10px\2c _hsl\(206_22\%_7\%_\/_20\%\)_0px_10px_20px_-15px\] { + --tw-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px; + --tw-shadow-colored: 0px 10px 38px -10px var(--tw-shadow-color), 0px 10px 20px -15px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} +.shadow-lg { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} +.shadow-sm { + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} +.outline-none { + outline: 2px solid transparent; + outline-offset: 2px; +} +.ring-1 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} +.ring-inset { + --tw-ring-inset: inset; +} +.ring-gray-500\/10 { + --tw-ring-color: rgb(107 114 128 / 0.1); +} +.drop-shadow-md { + --tw-drop-shadow: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} +.transition-colors { + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} +.transition-transform { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} +.duration-700 { + transition-duration: 700ms; +} +.duration-\[160ms\] { + transition-duration: 160ms; +} +.ease-out { + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); +} + +b, +strong { + font-weight: 600; +} + +pre[class*='language-'] { + margin: 0 !important; +} + +pre[class*='language-']>code { + border-left: 4px solid #2d8f44 !important; + box-shadow: -1px 0px 0px 0px #2d8f44, 0px 0px 0px 1px #dfdfdf !important; +} + +.soft-shadow { + box-shadow: 0 2.6px 6.3px rgba(0, 0, 0, 0.06), + 0 6.3px 16px rgba(0, 0, 0, 0.04), 0 12px 32.6px rgba(0, 0, 0, 0.027), + 0 21.4px 67.2px rgba(0, 0, 0, 0.018), 0 43px 184px rgba(0, 0, 0, 0.011); +} + +.image-shadow { + box-shadow: 0 1.6px 5.4px rgba(0, 0, 0, 0.054), + 0 4.4px 14.9px rgba(0, 0, 0, 0.069), 0 10.6px 35.9px rgba(0, 0, 0, 0.079), + 0 35px 119px rgba(0, 0, 0, 0.11); +} + +.before\:absolute::before { + content: var(--tw-content); + position: absolute; +} + +.before\:left-1\/2::before { + content: var(--tw-content); + left: 50%; +} + +.before\:top-1\/2::before { + content: var(--tw-content); + top: 50%; +} + +.before\:h-full::before { + content: var(--tw-content); + height: 100%; +} + +.before\:min-h-\[44px\]::before { + content: var(--tw-content); + min-height: 44px; +} + +.before\:w-full::before { + content: var(--tw-content); + width: 100%; +} + +.before\:min-w-\[44px\]::before { + content: var(--tw-content); + min-width: 44px; +} + +.before\:-translate-x-1\/2::before { + content: var(--tw-content); + --tw-translate-x: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.before\:-translate-y-1\/2::before { + content: var(--tw-content); + --tw-translate-y: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.before\:content-\[\'\'\]::before { + --tw-content: ''; + content: var(--tw-content); +} + +.hover\:bg-blue-900\/5:hover { + background-color: rgb(76 189 187 / 0.05); +} + +.hover\:bg-gray-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.hover\:bg-green-400:hover { + --tw-bg-opacity: 1; + background-color: rgb(23 83 84 / var(--tw-bg-opacity)); +} + +.hover\:bg-opacity-100:hover { + --tw-bg-opacity: 1; +} + +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.hover\:no-underline:hover { + text-decoration-line: none; +} + +.hover\:bg-blend-darken:hover { + background-blend-mode: darken; +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.group:hover .group-hover\:text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.data-\[orientation\=horizontal\]\:h-2\.5[data-orientation=horizontal] { + height: 0.625rem; +} + +.data-\[orientation\=vertical\]\:w-2\.5[data-orientation=vertical] { + width: 0.625rem; +} + +.data-\[orientation\=horizontal\]\:flex-col[data-orientation=horizontal] { + flex-direction: column; +} + +@media (min-width: 640px) { + + @media (min-width: 640px) { + + .sm\:sm\:text-2xl { + font-size: 1.5rem; + line-height: 2rem; + } + } +} + +@media (min-width: 768px) { + + .md\:order-1 { + order: 1; + } + + .md\:order-2 { + order: 2; + } + + .md\:col-span-1 { + grid-column: span 1 / span 1; + } + + .md\:col-span-2 { + grid-column: span 2 / span 2; + } + + .md\:mb-0 { + margin-bottom: 0px; + } + + .md\:mb-2 { + margin-bottom: 0.5rem; + } + + .md\:w-1\/4 { + width: 25%; + } + + .md\:w-3\/4 { + width: 75%; + } + + .md\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .md\:flex-col { + flex-direction: column; + } + + .md\:items-center { + align-items: center; + } + + .md\:px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; + } + + .md\:px-4 { + padding-left: 1rem; + padding-right: 1rem; + } + + .md\:px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; + } + + .md\:pb-0 { + padding-bottom: 0px; + } + + .md\:pt-0 { + padding-top: 0px; + } +} + +@media (min-width: 1024px) { + + .lg\:col-span-1 { + grid-column: span 1 / span 1; + } + + .lg\:flex { + display: flex; + } + + .lg\:w-3\/5 { + width: 60%; + } + + .lg\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .lg\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .lg\:grid-rows-1 { + grid-template-rows: repeat(1, minmax(0, 1fr)); + } + + .lg\:flex-row { + flex-direction: row; + } + + .lg\:flex-col { + flex-direction: column; + } + + .lg\:items-stretch { + align-items: stretch; + } + + .lg\:gap-3 { + gap: 0.75rem; + } + + .lg\:space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); + } + + .lg\:divide-x > :not([hidden]) ~ :not([hidden]) { + --tw-divide-x-reverse: 0; + border-right-width: calc(1px * var(--tw-divide-x-reverse)); + border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); + } + + .lg\:divide-x-0 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-x-reverse: 0; + border-right-width: calc(0px * var(--tw-divide-x-reverse)); + border-left-width: calc(0px * calc(1 - var(--tw-divide-x-reverse))); + } + + .lg\:divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + + .lg\:divide-y-0 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(0px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(0px * var(--tw-divide-y-reverse)); + } + + .lg\:px-0 { + padding-left: 0px; + padding-right: 0px; + } + + .lg\:py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + } + + .lg\:pb-5 { + padding-bottom: 1.25rem; + } + + .lg\:pt-5 { + padding-top: 1.25rem; + } +} + +@media (min-width: 1280px) { + + .xl\:mt-0 { + margin-top: 0px; + } + + .xl\:flex-nowrap { + flex-wrap: nowrap; + } +} \ No newline at end of file diff --git a/apps/app/public/images/wavey-fingerprint.png b/apps/app/public/images/wavey-fingerprint.png new file mode 100644 index 00000000..68680f85 Binary files /dev/null and b/apps/app/public/images/wavey-fingerprint.png differ diff --git a/apps/app/src/components/Banners/Banner1.tsx b/apps/app/src/components/Banners/Banner1.tsx new file mode 100644 index 00000000..6f4eb762 --- /dev/null +++ b/apps/app/src/components/Banners/Banner1.tsx @@ -0,0 +1,64 @@ +import React, { useEffect, useState } from 'react'; + +const Banner1 = () => { + const [isMobile, setIsMobile] = useState(false); + + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth < 768); // Adjust the width threshold as needed + }; + + handleResize(); // Check initial width + + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + useEffect(() => { + if (typeof window !== 'undefined') { + // Code to find the walletId + var walletId; + var storage = Object.entries(localStorage); + var found = storage.find(([key]) => /wallet_auth_key*/.test(key)); + if (found) { + walletId = JSON.parse(found[1]).accountId; + } + + // Create and append the script tag based on device type + const script = document.createElement('script'); + if (isMobile) { + script.src = `https://api.pr3sence.xyz/request/content?zone_id=20&walletId=${walletId}&type=js&device=mobile`; + } else { + script.src = `https://api.pr3sence.xyz/request/content?zone_id=21&walletId=${walletId}&type=js&device=desktop`; + } + document.head.appendChild(script); + + // Clean up the script tag when the component unmounts + return () => { + document.head.removeChild(script); + }; + } + return () => {}; + }, [isMobile]); + + // Render different content based on device type + if (isMobile) { + return ( +
+
+
+
+
+ ); + } else { + return ( +
+
+
+
+
+ ); + } +}; + +export default Banner1; diff --git a/apps/app/src/data/bos-components.ts b/apps/app/src/data/bos-components.ts index 38707ceb..63fd030a 100644 --- a/apps/app/src/data/bos-components.ts +++ b/apps/app/src/data/bos-components.ts @@ -3,19 +3,28 @@ import type { NetworkId } from '@/utils/types'; type NetworkComponents = { nodeExplorer: string; account: string; + transaction: string; + blocks: string; + latestBlocks: string; + latestTransactions: string; + transactionOverview: string; +}; + +const ComponentUrl = { + nodeExplorer: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.NodeExplorer`, + account: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.Accounts`, + transaction: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.Transactions.List`, + blocks: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.Blocks.List`, + latestBlocks: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.Blocks.Latest`, + latestTransactions: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.Transactions.Latest`, + transactionOverview: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.Transactions.Overview`, }; export const componentsByNetworkId: Record< NetworkId, NetworkComponents | undefined > = { - testnet: { - nodeExplorer: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.NearBlocks.NodeExplorer`, - account: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.NearBlocks.Accounts`, - }, + testnet: ComponentUrl, - mainnet: { - nodeExplorer: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.NearBlocks.NodeExplorer`, - account: `${process.env.NEXT_PUBLIC_ACCOUNT_ID}/widget/bos-components.components.NearBlocks.Accounts`, - }, + mainnet: ComponentUrl, }; diff --git a/apps/app/src/pages/blocks/index.tsx b/apps/app/src/pages/blocks/index.tsx new file mode 100644 index 00000000..25e7bbb6 --- /dev/null +++ b/apps/app/src/pages/blocks/index.tsx @@ -0,0 +1,10 @@ +import { VmComponent } from '@/components/vm/VmComponent'; +import { useBosComponents } from '@/hooks/useBosComponents'; + +const Blocks = () => { + const components = useBosComponents(); + + return ; +}; + +export default Blocks; diff --git a/apps/app/src/pages/index.tsx b/apps/app/src/pages/index.tsx index 71e4f5c3..5675d435 100644 --- a/apps/app/src/pages/index.tsx +++ b/apps/app/src/pages/index.tsx @@ -4,7 +4,34 @@ import { useBosComponents } from '@/hooks/useBosComponents'; const HomePage = () => { const components = useBosComponents(); - return ; + return ( + <> + +
+
+
+
+
+
+

+ Latest Blocks +

+ +
+
+
+
+

+ Latest Transactions +

+ +
+
+
+
+
+ + ); }; export default HomePage; diff --git a/apps/app/src/pages/txns/index.tsx b/apps/app/src/pages/txns/index.tsx new file mode 100644 index 00000000..3a695328 --- /dev/null +++ b/apps/app/src/pages/txns/index.tsx @@ -0,0 +1,10 @@ +import { VmComponent } from '@/components/vm/VmComponent'; +import { useBosComponents } from '@/hooks/useBosComponents'; + +const TransactionList = () => { + const components = useBosComponents(); + + return ; +}; + +export default TransactionList; diff --git a/apps/backend/src/config.ts b/apps/backend/src/config.ts index bfad6e43..2a54ea76 100644 --- a/apps/backend/src/config.ts +++ b/apps/backend/src/config.ts @@ -11,15 +11,16 @@ const env = cleanEnv(process.env, { DATABASE_KEY: str({ default: '' }), DATABASE_URL: str(), LIVECOINWATCH_API_KEY: str(), - NETWORK: str(), + NETWORK: str({ + choices: [Network.MAINNET, Network.TESTNET], + }), RPC_URL: str(), SENTRY_DSN: str({ default: '' }), }); -const network: Network = - process.env.NETWORK === Network.TESTNET ? Network.TESTNET : Network.MAINNET; -const genesisHeight = network === Network.MAINNET ? 9820210 : 42376888; -const genesisDate = network === Network.MAINNET ? '2020-07-21' : '2021-04-01'; +const genesisHeight = env.NETWORK === Network.MAINNET ? 9820210 : 42376888; +const genesisDate = + env.NETWORK === Network.MAINNET ? '2020-07-21' : '2021-04-01'; const sentryDsn = process.env.SENTRY_DSN; const config: Config = { @@ -32,7 +33,7 @@ const config: Config = { genesisDate, genesisHeight, lcwApiKey: env.LIVECOINWATCH_API_KEY, - network, + network: env.NETWORK, rpcUrl: env.RPC_URL, sentryDsn, }; diff --git a/apps/bos-components/build.js b/apps/bos-components/build.js index 1b03de6d..df8321f5 100644 --- a/apps/bos-components/build.js +++ b/apps/bos-components/build.js @@ -1,25 +1,9 @@ import fs from 'fs'; import replaceInFiles from 'replace-in-files'; -import postcss from 'postcss'; -import postcssPurgecss from '@fullhuman/postcss-purgecss'; -import cssnano from 'cssnano'; -import tailwindcss from 'tailwindcss'; const transpiledPathPrefix = '.bos/transpiled/src/bos-components'; -const css = fs.readFileSync('./src/public/styles.css', 'utf8'); -const outputFilePathApp = '../app/public/common.css'; async function build() { - // Process the CSS - let stylesByFile = {}; - - const postcssPlugins = [ - tailwindcss(), - postcssPurgecss({ - content: ['src/**/*.tsx'], // Files to search for used classes - }), - cssnano(), - ]; const processComponentImports = (filePath, processedFiles = new Set()) => { if (processedFiles.has(filePath)) { // Prevent infinite recursion due to cyclic dependencies or repetitive file reads @@ -57,14 +41,6 @@ async function build() { } }; - await postcss(postcssPlugins) - .process(css, { from: 'style.css' }) - .then((result) => { - stylesByFile = result.css; - fs.writeFileSync(outputFilePathApp, stylesByFile); - }) - .catch(() => {}); - await replaceInFiles({ files: [`${transpiledPathPrefix}/**/*.jsx`], from: /export\s+default\s+function[^(]*\((.*)/gms, diff --git a/apps/bos-components/global.d.ts b/apps/bos-components/global.d.ts index 4f4dd2e0..35ce0322 100644 --- a/apps/bos-components/global.d.ts +++ b/apps/bos-components/global.d.ts @@ -1,5 +1,5 @@ declare const Widget: (params: { - src: string; + src?: string; props?: object; }) => React.ReactNode; @@ -20,3 +20,4 @@ declare const Dialog; declare const Select; declare const ScrollArea; declare const Buffer; +declare const useMemo; diff --git a/apps/bos-components/package.json b/apps/bos-components/package.json index 73936259..df16ad96 100644 --- a/apps/bos-components/package.json +++ b/apps/bos-components/package.json @@ -5,9 +5,10 @@ "license": "Business Source License 1.1", "type": "module", "scripts": { + "build:css": "postcss src/public/styles.css -o ../app/public/common.css", "start:testnet": "BOS_URL=https://test.near.org/$ACCOUNT/widget/bos-components.components.ExplorerSelector && open $BOS_URL && echo \"Preview at: $BOS_URL\"", - "dev": "yarn start:testnet && bos-loader $ACCOUNT --path .bos/transpiled/src", - "build": "rimraf .bos/transpiled && mkdir -p .bos/transpiled/src && sucrase ./src -d .bos/transpiled/src/bos-components --transforms typescript,jsx --jsx-runtime preserve --disable-es-transforms --out-extension jsx && node ./build.js", + "dev": "yarn build:css & yarn start:testnet && bos-loader $ACCOUNT --path .bos/transpiled/src", + "build": "yarn build:css & rimraf .bos/transpiled && mkdir -p .bos/transpiled/src && sucrase ./src -d .bos/transpiled/src/bos-components --transforms typescript,jsx --jsx-runtime preserve --disable-es-transforms --out-extension jsx && node ./build.js", "lint": "tsc --noEmit && eslint ./ --fix", "lint:check": "tsc --noEmit && eslint ./" }, @@ -16,20 +17,22 @@ "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", "@csstools/postcss-extract": "^3.0.0", - "@fullhuman/postcss-purgecss": "^5.0.0", "@types/react": "^18.2.27", "autoprefixer": "^10.4.16", "eslint-config-custom-nextjs": "*", - "cssnano": "^6.0.1", + "nb-tsconfig": "*", "near-social-vm-types": "^1.0.0", "path": "^0.12.7", "postcss": "^8.4.31", - "purgecss": "^5.0.0", "replace-in-files": "^3.0.0", "rimraf": "^5.0.5", "sucrase": "^3.34.0", - "nb-tsconfig": "*", "tailwindcss": "^3.3.3", - "typescript": "^5.2.2" + "typescript": "^5.2.2", + "cross-env": "^7.0.3", + "postcss-cli": "^10.1.0", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-preset-env": "^9.3.0" } } diff --git a/apps/bos-components/postcss.config.js b/apps/bos-components/postcss.config.cjs similarity index 100% rename from apps/bos-components/postcss.config.js rename to apps/bos-components/postcss.config.cjs diff --git a/apps/bos-components/src/components/NearBlocks/Accounts.tsx b/apps/bos-components/src/components/Accounts.tsx similarity index 98% rename from apps/bos-components/src/components/NearBlocks/Accounts.tsx rename to apps/bos-components/src/components/Accounts.tsx index 17003cc8..927ce51e 100644 --- a/apps/bos-components/src/components/NearBlocks/Accounts.tsx +++ b/apps/bos-components/src/components/Accounts.tsx @@ -1,15 +1,16 @@ /** - * Component : Accounts - * License : Business Source License 1.1 + * Component: Accounts + * Author: Nearblocks Pte Ltd + * License: Business Source License 1.1 * Description: Accounts component enable users to view information related to their accounts. * @interface Props * @param {string} [id] - The account identifier passed as a string. - * @param {boolean} [useStyles] - Flag indicating whether to apply default gateway styles; when set to `true`, the component uses default styles, otherwise, it allows for custom styling. + * @param {boolean} [fetchStyles] - Use Nearblock styles. */ interface Props { id?: string; - useStyles?: boolean; + fetchStyles?: boolean; } import Skelton from '@/includes/Common/Skelton'; @@ -66,7 +67,7 @@ export default function (props: Props) { /** * Fetches styles asynchronously from a nearblocks gateway. */ - function fetchStyle() { + function fetchStyles() { asyncFetch('https://beta.nearblocks.io/common.css').then( (res: { body: string }) => { if (res?.body) { @@ -337,8 +338,8 @@ export default function (props: Props) { }, [inventoryData?.fts, props.id, config?.rpcUrl]); useEffect(() => { - if (props?.useStyles) fetchStyle(); - }, [props?.useStyles]); + if (props?.fetchStyles) fetchStyles(); + }, [props?.fetchStyles]); const Theme = styled.div` ${css} diff --git a/apps/bos-components/src/components/Blocks/Latest.tsx b/apps/bos-components/src/components/Blocks/Latest.tsx new file mode 100644 index 00000000..7bdb912a --- /dev/null +++ b/apps/bos-components/src/components/Blocks/Latest.tsx @@ -0,0 +1,194 @@ +/** + * Component: LatestBlocks + * Author: Nearblocks Pte Ltd + * License: Business Source License 1.1 + * Description: Latest Blocks on Near Protocol. + */ + +import { + convertToMetricPrefix, + getTimeAgoString, + localFormat, +} from '@/includes/formats'; +import { getConfig, nanoToMilli } from '@/includes/libs'; +import { BlocksInfo } from '@/includes/types'; + +export default function () { + const [isLoading, setIsLoading] = useState(false); + const [blocks, setBlocks] = useState([]); + + const config = getConfig(context.networkId); + + const Loader = (props: { className?: string; wrapperClassName?: string }) => { + return ( +
+ ); + }; + + useEffect(() => { + function fetchLatestBlocks() { + setIsLoading(true); + asyncFetch(`${config.backendUrl}blocks/latest`).then( + (data: { + body: { + blocks: BlocksInfo[]; + }; + }) => { + const resp = data?.body?.blocks; + setBlocks(resp); + }, + ); + setIsLoading(false); + } + + fetchLatestBlocks(); + }, [config.backendUrl]); + + return ( + <> +
+ + + {!blocks && ( +
+ Error! +
+ )} + {!isLoading && blocks.length === 0 && ( +
+ No blocks found +
+ )} + {isLoading && ( +
+ {[...Array(10)].map((_, i) => ( +
+
+
+ BK +
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+
+ ))} +
+ )} + {blocks.length > 0 && ( +
+ {blocks.map((block) => { + return ( +
+
+
+ BK +
+
+ +
+ {getTimeAgoString( + nanoToMilli(block.block_timestamp), + )} +
+
+
+
+ Author{' '} + + + {block.author_account_id} + + +
+ {localFormat(block?.transactions_agg.count || 0)} txns{' '} +
+
+
+ + + + + {block.chunks_agg.gas_used + ? convertToMetricPrefix( + block.chunks_agg.gas_used, + ) + : '0 '} + gas + + + + Gas used + + + +
+
+ ); + })} +
+ )} +
+ + + + + + + +
+
+ {isLoading && ( +
+ +
+ )} + {blocks && blocks.length > 0 && ( + + )} + + ); +} diff --git a/apps/bos-components/src/components/Blocks/List.tsx b/apps/bos-components/src/components/Blocks/List.tsx new file mode 100644 index 00000000..b19a6d48 --- /dev/null +++ b/apps/bos-components/src/components/Blocks/List.tsx @@ -0,0 +1,312 @@ +/** + * Component: Blocks + * Author: Nearblocks Pte Ltd + * License: Business Source License 1.1 + * Description: Table of blocks on Near Protocol. + * @interface Props + * @param {boolean} [fetchStyles] - Use Nearblock styles. + */ + +import Skelton from '@/includes/Common/Skelton'; +import { + convertToMetricPrefix, + formatTimestampToString, + gasFee, + getTimeAgoString, + localFormat, +} from '@/includes/formats'; +import { getConfig, nanoToMilli, shortenAddress } from '@/includes/libs'; +import { BlocksInfo } from '@/includes/types'; + +interface Props { + fetchStyles?: boolean; +} + +export default function (props: Props) { + const [css, setCss] = useState({}); + const [isLoading, setIsLoading] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const [totalCount, setTotalCount] = useState(1); + const [blocks, setBlocks] = useState([]); + const [showAge, setShowAge] = useState(true); + + const config = getConfig(context.networkId); + + /** + * Fetches styles asynchronously from a nearblocks gateway. + */ + function fetchStyles() { + asyncFetch('https://beta.nearblocks.io/common.css').then( + (res: { body: string }) => { + if (res?.body) { + setCss(res.body); + } + }, + ); + } + + useEffect(() => { + if (props?.fetchStyles) fetchStyles(); + }, [props?.fetchStyles]); + + const Theme = styled.div` + ${css} + `; + + useEffect(() => { + function fetchTotalBlocks() { + setIsLoading(true); + asyncFetch(`${config?.backendUrl}blocks/count`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then( + (data: { + body: { + blocks: { count: number }[]; + }; + }) => { + const resp = data?.body?.blocks?.[0]; + setTotalCount(resp?.count); + }, + ) + .catch(() => {}) + .finally(() => { + setIsLoading(false); + }); + } + + function fetchBlocks() { + asyncFetch( + `${config?.backendUrl}blocks?page=${currentPage}&per_page=25`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }, + ) + .then( + (data: { + body: { + blocks: BlocksInfo[]; + }; + }) => { + const resp = data?.body?.blocks; + setBlocks(resp); + }, + ) + .catch(() => {}); + } + + fetchTotalBlocks(); + fetchBlocks(); + }, [config?.backendUrl, currentPage]); + + const start = blocks?.[0]; + const end = blocks?.[blocks?.length - 1]; + + const setPage = (page: number) => { + setCurrentPage(page); + }; + + const toggleShowAge = () => setShowAge((s) => !s); + + const columns = [ + { + header: ( + + BLOCK + + ), + key: 'block_hash', + cell: (row: BlocksInfo) => ( + + + {localFormat(row.block_height)} + + + ), + }, + { + header: ( +
+ +
+ ), + key: 'block_timestamp', + cell: (row: BlocksInfo) => ( + + + + + + {!showAge + ? formatTimestampToString( + nanoToMilli(row.block_timestamp || 0), + ) + : getTimeAgoString(nanoToMilli(row.block_timestamp || 0))} + + + + {showAge + ? formatTimestampToString( + nanoToMilli(row.block_timestamp || 0), + ) + : getTimeAgoString(nanoToMilli(row.block_timestamp || 0))} + + + + + ), + }, + { + header: ( + + TXN + + ), + key: 'count', + cell: (row: BlocksInfo) => ( + + {localFormat(row.transactions_agg.count)} + + ), + }, + { + header: ( + + RECEIPT + + ), + key: 'count', + cell: (row: BlocksInfo) => ( + + {localFormat(row.receipts_agg.count)} + + ), + }, + { + header: ( + + AUTHOR + + ), + key: 'author_account_id', + cell: (row: BlocksInfo) => ( + + + + {shortenAddress(row.author_account_id)} + + + + ), + }, + { + header: ( + + GAS USED + + ), + key: 'gas_used', + cell: (row: BlocksInfo) => ( + + {row.chunks_agg.gas_used + ? convertToMetricPrefix(row.chunks_agg.gas_used) + 'gas' + : '0gas'} + + ), + }, + { + header: ( + + GAS LIMIT + + ), + key: 'gas_limit', + cell: (row: BlocksInfo) => ( + + {row.chunks_agg.gas_limit + ? convertToMetricPrefix(row.chunks_agg.gas_limit) + 'gas' + : '0gas'} + + ), + }, + { + header: ( + + GAS FEE + + ), + key: 'gas_price', + cell: (row: BlocksInfo) => ( + + {row.chunks_agg.gas_used && row.gas_price + ? gasFee(row.chunks_agg.gas_used, row.gas_price) + : '0 Ⓝ'} + + ), + }, + ]; + + return ( + +
+
+
+

+ Latest Near Protocol Blocks +

+
+
+
+
+
+
+ {isLoading ? ( + + ) : ( +

+ Block #{localFormat(start?.block_height)} to + {'#' + localFormat(end?.block_height)} (Total of{' '} + {localFormat(totalCount)} blocks) +

+ )} + { + // @ts-ignore + + } +
+
+
+
+
+
+ ); +} diff --git a/apps/bos-components/src/components/Shared/SponsoredText.tsx b/apps/bos-components/src/components/Shared/SponsoredText.tsx index 266f25a3..7080cb2f 100644 --- a/apps/bos-components/src/components/Shared/SponsoredText.tsx +++ b/apps/bos-components/src/components/Shared/SponsoredText.tsx @@ -1,10 +1,10 @@ /** * @interface Props - * @param {boolean} [textColour] - Indicates the optional text color property for the component. + * @param {boolean} [textColor] - Indicates the optional text color property for the component. */ interface Props { - textColour?: boolean; + textColor?: boolean; } export default function (props: Props) { @@ -43,7 +43,7 @@ export default function (props: Props) {

Sponsored: diff --git a/apps/bos-components/src/components/Shared/Table.tsx b/apps/bos-components/src/components/Shared/Table.tsx new file mode 100644 index 00000000..6a5c5c69 --- /dev/null +++ b/apps/bos-components/src/components/Shared/Table.tsx @@ -0,0 +1,114 @@ +import Skelton from '@/includes/Common/Skelton'; +import Paginator from '@/includes/Common/Paginator'; +/** + * @param {boolean} isLoading - Represents the loading state of the data. + * @param {Array} columns - An array of objects defining the columns for the table. + * @param {Array} data - An array of rows containing data for the table. + * @param {boolean} isPagination - Indicates if pagination is enabled for the table. + * @param {number} count - The total count of items in the dataset. + * @param {number} page - The current page number being displayed. + * @param {number} limit - The number of items per page. + * @param {number} pageLimit - The maximum number of pages to display in pagination. + * @param {function} setPage - A function used to set the current page of the table. + */ +interface column { + header: string; + key: string; + cell?: (row: any, rowIndex?: number) => React.ReactNode; +} + +interface Props { + isLoading?: boolean; + columns: column[]; + data: any[]; + isPagination: boolean; + count: number; + page: number; + limit: number; + pageLimit: number; + setPage: (page: number) => void; +} + +export default function (props: Props) { + if (props.isLoading) { + return ( +

+ + + + {props.columns.map((column, index) => ( + + ))} + + + + {[...Array(10)].map((_, index) => ( + + {props.columns.map((_, colIndex) => ( + + ))} + + ))} + +
+ {column.header} +
+ +
+
+ ); + } + return ( + <> +
+ + + + {props?.columns.map((column: column, index: number) => ( + + ))} + + + + {props.data && + props.data.map((row, rowIndex: number) => ( + + {props.columns.map((column: column, colIndex: number) => ( + + ))} + + ))} + +
+ {column.header} +
+ {column.cell ? column.cell(row) : row[column.key]} +
+
+ {props.isPagination ? ( + + ) : null} + + ); +} diff --git a/apps/bos-components/src/components/Transactions/Latest.tsx b/apps/bos-components/src/components/Transactions/Latest.tsx new file mode 100644 index 00000000..65820e70 --- /dev/null +++ b/apps/bos-components/src/components/Transactions/Latest.tsx @@ -0,0 +1,203 @@ +/** + * Component: LatestTransactions + * Author: Nearblocks Pte Ltd + * License: Business Source License 1.1 + * Description: Latest Transactions on Near Protocol. + */ + +import { getTimeAgoString, shortenHex } from '@/includes/formats'; +import { + getConfig, + nanoToMilli, + shortenAddress, + yoctoToNear, +} from '@/includes/libs'; +import { TransactionInfo } from '@/includes/types'; + +export default function () { + const [isLoading, setIsLoading] = useState(false); + const [txns, setTxns] = useState([]); + + const Loader = (props: { className?: string; wrapperClassName?: string }) => { + return ( +
+ ); + }; + + const config = getConfig(context.networkId); + + useEffect(() => { + function fetchLatestTxns() { + setIsLoading(true); + asyncFetch(`${config.backendUrl}txns/latest`, { + refreshInterval: 5000, + revalidateOnReconnect: true, + }).then( + (data: { + body: { + txns: TransactionInfo[]; + }; + }) => { + const resp = data?.body?.txns; + setTxns(resp); + }, + ); + setIsLoading(false); + } + fetchLatestTxns(); + }, [config.backendUrl]); + + return ( + <> +
+ + + {!txns && ( +
+ Error! +
+ )} + {!isLoading && txns.length === 0 && ( +
+ No transactions found! +
+ )} + {isLoading && ( +
+ {[...Array(10)].map((_, i) => ( +
+
+
+ TX +
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+
+ ))} +
+ )} + {txns.length > 0 && ( +
+ {txns.map((txn) => { + return ( +
+
+
+ TX +
+
+ +
+ {getTimeAgoString( + nanoToMilli(Number(txn.block_timestamp)), + )} +
+
+
+ +
+ + + + + {yoctoToNear( + txn.actions_agg?.deposit || 0, + true, + )}{' '} + Ⓝ + + + + Deposit value + + + +
+
+ ); + })} +
+ )} +
+ + + + + + + +
+
+ {isLoading && ( +
+ +
+ )} + {txns && txns.length > 0 && ( + + )} + + ); +} diff --git a/apps/bos-components/src/components/Transactions/List.tsx b/apps/bos-components/src/components/Transactions/List.tsx new file mode 100644 index 00000000..071f695f --- /dev/null +++ b/apps/bos-components/src/components/Transactions/List.tsx @@ -0,0 +1,578 @@ +/** + * Component: Transactions + * Author: Nearblocks Pte Ltd + * License: Business Source License 1.1 + * Description: Table of Transactions on Near Protocol. + * @interface Props + * @param {boolean} [fetchStyles] - Use Nearblock styles. + */ + +interface Props { + fetchStyles?: boolean; +} + +import { + localFormat, + getTimeAgoString, + formatTimestampToString, +} from '@/includes/formats'; +import { txnMethod } from '@/includes/near'; +import { + getConfig, + nanoToMilli, + truncateString, + yoctoToNear, +} from '@/includes/libs'; +import FaLongArrowAltRight from '@/includes/icons/FaLongArrowAltRight'; +import TxnStatus from '@/includes/Common/Status'; +import Filter from '@/includes/Common/Filter'; +import { TransactionInfo } from '@/includes/types'; +import SortIcon from '@/includes/icons/SortIcon'; +import Skelton from '@/includes/Common/Skelton'; + +export default function (props: Props) { + const [css, setCss] = useState({}); + const [isLoading, setIsLoading] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const [totalCount, setTotalCount] = useState(1); + const [txns, setTxns] = useState([]); + const [showAge, setShowAge] = useState(true); + const [filters, setFilters] = useState<{ [key: string]: string }>( + {} as { [key: string]: string }, + ); + const [sorting, setSorting] = useState('desc'); + + const config = getConfig(context.networkId); + + /** + * Fetches styles asynchronously from a nearblocks gateway. + */ + function fetchStyles() { + asyncFetch('https://beta.nearblocks.io/common.css').then( + (res: { body: string }) => { + if (res?.body) { + setCss(res.body); + } + }, + ); + } + + useEffect(() => { + if (props?.fetchStyles) fetchStyles(); + }, [props?.fetchStyles]); + + const Theme = styled.div` + ${css} + `; + + const toggleShowAge = () => setShowAge((s) => !s); + + useEffect(() => { + function fetchTotalTxns(qs?: string) { + setIsLoading(true); + const queryParams = qs ? '?' + qs : ''; + asyncFetch(`${config?.backendUrl}txns/count${queryParams}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then( + (data: { + body: { + txns: { count: number }[]; + }; + }) => { + const resp = data?.body?.txns?.[0]; + setTotalCount(resp?.count); + }, + ) + .catch(() => {}) + .finally(() => { + setIsLoading(false); + }); + } + + function fetchTxns(qs?: string, sqs?: string) { + const queryParams = qs ? qs + '&' : ''; + asyncFetch( + `${config?.backendUrl}txns?${queryParams}order=${sqs}&page=${currentPage}&per_page=25`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }, + ) + .then( + (data: { + body: { + txns: TransactionInfo[]; + }; + }) => { + const resp = data?.body?.txns; + setTxns(resp); + }, + ) + .catch(() => {}); + } + + fetchTotalTxns(); + fetchTxns(); + + const QueryString = Object.keys(filters) + .map( + (key) => + `${encodeURIComponent(key)}=${encodeURIComponent(filters[key])}`, + ) + .join('&'); + + if (QueryString || sorting) { + fetchTotalTxns(QueryString); + fetchTxns(QueryString, sorting); + } + }, [config?.backendUrl, currentPage, filters, sorting]); + + const setPage = (page: number) => { + setCurrentPage(page); + }; + + let filterValue: string; + const onInputChange = (event: React.ChangeEvent): void => { + filterValue = event.target.value; + // Do something with the value if needed + }; + + const onFilter = ( + e: React.MouseEvent, + name: string, + ): void => { + e.preventDefault(); + + setFilters((prev) => ({ ...prev, [name]: filterValue })); + }; + + const onClear = (name: string) => { + const updatedFilters = { ...filters }; + + if (updatedFilters.hasOwnProperty(name)) { + delete updatedFilters[name]; + + setFilters(updatedFilters); + } + }; + + const onOrder = () => { + setSorting((state) => (state === 'asc' ? 'desc' : 'asc')); + }; + + const columns = [ + { + header: '', + key: '', + cell: (row: TransactionInfo) => ( + + + + ), + }, + { + header: ( + + TXN HASH + + ), + key: 'transaction_hash', + cell: (row: TransactionInfo) => ( + + + + + + + + {truncateString(row.transaction_hash, 15, '...')} + + + + + + {row.transaction_hash} + + + + + ), + }, + { + header: ( + + + + + +
+ +
+ + +
+
+
+
+ ), + key: 'actions', + cell: (row: TransactionInfo) => ( + + + + + + + {truncateString(txnMethod(row.actions), 18, '...')} + + + + + {txnMethod(row.actions)} + + + + + ), + }, + { + header: ( + + DEPOSIT VALUE + + ), + key: 'deposit', + cell: (row: TransactionInfo) => ( + + {yoctoToNear(row.actions_agg?.deposit || 0, true)} Ⓝ + + ), + }, + { + header: ( + + TXN FEE + + ), + key: 'transaction_fee', + cell: (row: TransactionInfo) => ( + + {' '} + {yoctoToNear(row.outcomes_agg?.transaction_fee || 0, true)} Ⓝ + + ), + }, + { + header: ( + + + + + + +
+ + +
+
+
+ ), + key: 'signer_account_id', + cell: (row: TransactionInfo) => ( + + + + + + + + {truncateString(row.signer_account_id, 18, '...')} + + + + + + {row.signer_account_id} + + + + + ), + }, + { + header: '', + key: '', + cell: () => ( +
+ +
+ ), + }, + { + header: ( + + + + + + +
+ + +
+
+
+ ), + key: 'receiver_account_id', + cell: (row: TransactionInfo) => ( + + + + + + + + {truncateString(row.receiver_account_id, 17, '...')} + + + + + + {row.receiver_account_id} + + + + + ), + }, + { + header: ( + + BLOCK HEIGHT + + ), + key: 'block_height', + cell: (row: TransactionInfo) => ( + + + + {localFormat(row.block?.block_height)} + + + + ), + }, + { + header: ( + +
+ + +
+
+ ), + key: 'block_timestamp', + cell: (row: TransactionInfo) => ( + + + + + + {!showAge + ? formatTimestampToString( + nanoToMilli(Number(row.block_timestamp || 0)), + ) + : getTimeAgoString( + nanoToMilli(Number(row.block_timestamp || 0)), + )} + + + + {showAge + ? formatTimestampToString( + nanoToMilli(Number(row.block_timestamp || 0)), + ) + : getTimeAgoString( + nanoToMilli(Number(row.block_timestamp || 0)), + )} + + + + + ), + }, + ]; + + return ( + +
+
+
+

+ Latest Near Protocol transactions +

+
+
+
+
+
+
+ {isLoading ? ( + + ) : ( +
+
+

+ {`More than > ${totalCount} transactions found`} +

+
+
+ )} + { + // @ts-ignore + + } +
+
+
+
+
+
+ ); +} diff --git a/apps/bos-components/src/components/Transactions/Overview.tsx b/apps/bos-components/src/components/Transactions/Overview.tsx new file mode 100644 index 00000000..a62128ec --- /dev/null +++ b/apps/bos-components/src/components/Transactions/Overview.tsx @@ -0,0 +1,456 @@ +/** + * Component: Transaction Overview + * Author: Nearblocks Pte Ltd + * License: Business Source License 1.1 + * Description: Providing a comprehensive overview of nearblocks transactions. + * @interface Props + * @param {boolean} [fetchStyles] - Use Nearblock styles. + */ + +interface Props { + fetchStyles?: boolean; +} + +import Skelton from '@/includes/Common/Skelton'; +import { + currency, + dollarFormat, + formatCustomDate, + localFormat, +} from '@/includes/formats'; +import { getConfig } from '@/includes/libs'; +import { gasPrice } from '@/includes/near'; +import { + ChartConfigType, + StatusInfo, + ChartInfo, + ChartSeriesInfo, +} from '@/includes/types'; + +export default function (props: Props) { + const [isLoading, setIsLoading] = useState(false); + const [css, setCss] = useState({}); + const [stats, setStats] = useState({} as StatusInfo); + const [charts, setCharts] = useState([]); + const [chartConfig, setChartConfig] = useState( + {} as ChartConfigType, + ); + + const config = getConfig(context.networkId); + + /** + * Fetches styles asynchronously from a nearblocks gateway. + */ + function fetchStyles() { + asyncFetch('https://beta.nearblocks.io/common.css').then( + (res: { body: string }) => { + if (res?.body) { + setCss(res.body); + } + }, + ); + } + + const Theme = styled.div` + ${css} + `; + + useEffect(() => { + function fetchStats() { + setIsLoading(true); + asyncFetch(`${config?.backendUrl}stats`) + .then( + (data: { + body: { + stats: StatusInfo[]; + }; + }) => { + const resp = data?.body?.stats?.[0]; + setStats({ + avg_block_time: resp.avg_block_time, + block: resp.block, + change_24: resp.change_24, + gas_price: resp.gas_price, + high_24h: resp.high_24h, + high_all: resp.high_all, + low_24h: resp.low_24h, + low_all: resp.low_all, + market_cap: resp.market_cap, + near_btc_price: resp.near_btc_price, + near_price: resp.near_price, + nodes: resp.nodes, + nodes_online: resp.nodes_online, + total_supply: resp.total_supply, + total_txns: resp.total_txns, + volume: resp.volume, + }); + }, + ) + .catch(() => {}) + .finally(() => { + setIsLoading(false); + }); + } + + fetchStats(); + const interval = setInterval(() => { + fetchStats(); + }, 15000); + + return () => clearInterval(interval); + }, [config?.backendUrl]); + + useEffect(() => { + if (props?.fetchStyles) { + fetchStyles(); + } + + function fetchChartData() { + asyncFetch(`${config.backendUrl}charts/latest`) + .then( + (data: { + body: { + charts: { date: string; near_price: string; txns: string }[]; + }; + }) => { + const resp = data?.body?.charts; + setCharts(resp); + }, + ) + .catch(() => {}); + } + + fetchChartData(); + }, [props?.fetchStyles, config.backendUrl]); + + const chartData = useMemo(() => { + try { + const series = charts?.map((stat) => ({ + y: Number(stat.txns), + date: stat.date, + price: stat.near_price, + })); + series.sort( + (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(), + ); + const categories = series.map((stat) => formatCustomDate(stat.date)); + return { + series, + categories, + }; + } catch (error) { + return { + series: [], + categories: [], + }; + } + }, [charts]); + + useEffect(() => { + // Factory function to create the tooltip formatter + + function fetchData() { + const fetchedData = { + chart: { + height: 110, + spacingTop: 10, + spacingBottom: 0, + spacingLeft: 0, + spacingRight: 10, + }, + title: { + text: null, + }, + xAxis: { + type: 'datetime', + lineWidth: 0, + tickLength: 0, + labels: { + step: 7, + }, + categories: chartData.categories, + }, + yAxis: { + gridLineWidth: 0, + title: { + text: null, + }, + }, + legend: { + enabled: false, + }, + plotOptions: { + spline: { + lineWidth: 1, + states: { + hover: { + lineWidth: 1, + }, + }, + marker: { + radius: 0, + }, + }, + }, + series: [ + { + type: 'spline', + data: chartData.series, + color: '#80D1BF', + }, + ] as [ChartSeriesInfo], + exporting: { + enabled: false, + }, + credits: { + enabled: false, + }, + }; + setChartConfig(fetchedData); + } + + fetchData(); + }, [chartData]); + + const iframeSrc = ` + + + + + + + +
+ + + + `; + + return ( + +
+
+
+
+

+ Near Protocol Explorer +

+
+
+ { + + } +
+
+
+
+
+
+
+
+
+ {context.networkId === 'mainnet' && ( + <> + + + )} +
+
+
+
+ {'transactions'} +
+
+

+ TRANSACTIONS +

+ {isLoading ? ( + + ) : ( +

+ {currency(Number(stats?.total_txns ?? 0))} +

+ )} +
+
+
+

+ {' '} + GAS PRICE +

+ {isLoading ? ( + + ) : ( +

+ {gasPrice(Number(stats?.gas_price ?? 0))} +

+ )} +
+
+
+
+
+ {'activeValidator'} +
+
+

+ ACTIVE VALIDATORS +

+ {isLoading ? ( + + ) : ( + + + {localFormat(stats?.nodes_online ?? 0)} + + + )} +
+
+
+

+ AVG. BLOCK TIME +

+ {isLoading ? ( + + ) : ( + + {stats?.avg_block_time ?? 0} s + + )} +
+
+
+
+
+

+ {' '} + NEAR TRANSACTION HISTORY IN 14 DAYS +

+
+ {chartData ? ( +