diff --git a/biome.json b/biome.json index 534c288..2c24fc4 100644 --- a/biome.json +++ b/biome.json @@ -15,7 +15,7 @@ ".react-router/*", "react-router.config.ts", "vite-env.d.ts", - "public/mockServiceWorker.js" + "public/**/*" ] }, "formatter": { diff --git a/public/ReactToastify.css b/public/ReactToastify.css new file mode 100644 index 0000000..82f0ac5 --- /dev/null +++ b/public/ReactToastify.css @@ -0,0 +1,800 @@ +:root { + --toastify-color-light: #fff; + --toastify-color-dark: #121212; + --toastify-color-info: #3498db; + --toastify-color-success: #07bc0c; + --toastify-color-warning: #f1c40f; + --toastify-color-error: hsl(6, 78%, 57%); + --toastify-color-transparent: rgba(255, 255, 255, 0.7); + + --toastify-icon-color-info: var(--toastify-color-info); + --toastify-icon-color-success: var(--toastify-color-success); + --toastify-icon-color-warning: var(--toastify-color-warning); + --toastify-icon-color-error: var(--toastify-color-error); + + --toastify-container-width: fit-content; + --toastify-toast-width: 320px; + --toastify-toast-offset: 16px; + --toastify-toast-top: max(var(--toastify-toast-offset), env(safe-area-inset-top)); + --toastify-toast-right: max(var(--toastify-toast-offset), env(safe-area-inset-right)); + --toastify-toast-left: max(var(--toastify-toast-offset), env(safe-area-inset-left)); + --toastify-toast-bottom: max(var(--toastify-toast-offset), env(safe-area-inset-bottom)); + --toastify-toast-background: #fff; + --toastify-toast-padding: 14px; + --toastify-toast-min-height: 64px; + --toastify-toast-max-height: 800px; + --toastify-toast-bd-radius: 6px; + --toastify-toast-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1); + --toastify-font-family: sans-serif; + --toastify-z-index: 9999; + --toastify-text-color-light: #757575; + --toastify-text-color-dark: #fff; + + /* Used only for colored theme */ + --toastify-text-color-info: #fff; + --toastify-text-color-success: #fff; + --toastify-text-color-warning: #fff; + --toastify-text-color-error: #fff; + + --toastify-spinner-color: #616161; + --toastify-spinner-color-empty-area: #e0e0e0; + --toastify-color-progress-light: linear-gradient(to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55); + --toastify-color-progress-dark: #bb86fc; + --toastify-color-progress-info: var(--toastify-color-info); + --toastify-color-progress-success: var(--toastify-color-success); + --toastify-color-progress-warning: var(--toastify-color-warning); + --toastify-color-progress-error: var(--toastify-color-error); + /* used to control the opacity of the progress trail */ + --toastify-color-progress-bgo: 0.2; +} + +.Toastify__toast-container { + z-index: var(--toastify-z-index); + -webkit-transform: translate3d(0, 0, var(--toastify-z-index)); + position: fixed; + width: var(--toastify-container-width); + box-sizing: border-box; + color: #fff; + display: flex; + flex-direction: column; +} + +.Toastify__toast-container--top-left { + top: var(--toastify-toast-top); + left: var(--toastify-toast-left); +} +.Toastify__toast-container--top-center { + top: var(--toastify-toast-top); + left: 50%; + transform: translateX(-50%); + align-items: center; +} +.Toastify__toast-container--top-right { + top: var(--toastify-toast-top); + right: var(--toastify-toast-right); + align-items: end; +} +.Toastify__toast-container--bottom-left { + bottom: var(--toastify-toast-bottom); + left: var(--toastify-toast-left); +} +.Toastify__toast-container--bottom-center { + bottom: var(--toastify-toast-bottom); + left: 50%; + transform: translateX(-50%); + align-items: center; +} +.Toastify__toast-container--bottom-right { + bottom: var(--toastify-toast-bottom); + right: var(--toastify-toast-right); + align-items: end; +} + +.Toastify__toast { + --y: 0; + position: relative; + touch-action: none; + width: var(--toastify-toast-width); + min-height: var(--toastify-toast-min-height); + box-sizing: border-box; + margin-bottom: 1rem; + padding: var(--toastify-toast-padding); + border-radius: var(--toastify-toast-bd-radius); + box-shadow: var(--toastify-toast-shadow); + max-height: var(--toastify-toast-max-height); + font-family: var(--toastify-font-family); + /* webkit only issue #791 */ + z-index: 0; + /* inner swag */ + display: flex; + flex: 1 auto; + align-items: center; + word-break: break-word; +} + +@media only screen and (max-width: 480px) { + .Toastify__toast-container { + width: 100vw; + left: env(safe-area-inset-left); + margin: 0; + } + .Toastify__toast-container--top-left, + .Toastify__toast-container--top-center, + .Toastify__toast-container--top-right { + top: env(safe-area-inset-top); + transform: translateX(0); + } + .Toastify__toast-container--bottom-left, + .Toastify__toast-container--bottom-center, + .Toastify__toast-container--bottom-right { + bottom: env(safe-area-inset-bottom); + transform: translateX(0); + } + .Toastify__toast-container--rtl { + right: env(safe-area-inset-right); + left: initial; + } + .Toastify__toast { + --toastify-toast-width: 100%; + margin-bottom: 0; + border-radius: 0; + } +} + +.Toastify__toast-container[data-stacked='true'] { + width: var(--toastify-toast-width); +} + +.Toastify__toast--stacked { + position: absolute; + width: 100%; + transform: translate3d(0, var(--y), 0) scale(var(--s)); + transition: transform 0.3s; +} + +.Toastify__toast--stacked[data-collapsed] .Toastify__toast-body, +.Toastify__toast--stacked[data-collapsed] .Toastify__close-button { + transition: opacity 0.1s; +} + +.Toastify__toast--stacked[data-collapsed='false'] { + overflow: visible; +} + +.Toastify__toast--stacked[data-collapsed='true']:not(:last-child) > * { + opacity: 0; +} + +.Toastify__toast--stacked:after { + content: ''; + position: absolute; + left: 0; + right: 0; + height: calc(var(--g) * 1px); + bottom: 100%; +} + +.Toastify__toast--stacked[data-pos='top'] { + top: 0; +} + +.Toastify__toast--stacked[data-pos='bot'] { + bottom: 0; +} + +.Toastify__toast--stacked[data-pos='bot'].Toastify__toast--stacked:before { + transform-origin: top; +} + +.Toastify__toast--stacked[data-pos='top'].Toastify__toast--stacked:before { + transform-origin: bottom; +} + +.Toastify__toast--stacked:before { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 100%; + transform: scaleY(3); + z-index: -1; +} + +.Toastify__toast--rtl { + direction: rtl; +} + +.Toastify__toast--close-on-click { + cursor: pointer; +} + +.Toastify__toast-icon { + margin-inline-end: 10px; + width: 22px; + flex-shrink: 0; + display: flex; +} + +.Toastify--animate { + animation-fill-mode: both; + animation-duration: 0.5s; +} + +.Toastify--animate-icon { + animation-fill-mode: both; + animation-duration: 0.3s; +} + +.Toastify__toast-theme--dark { + background: var(--toastify-color-dark); + color: var(--toastify-text-color-dark); +} + +.Toastify__toast-theme--light { + background: var(--toastify-color-light); + color: var(--toastify-text-color-light); +} + +.Toastify__toast-theme--colored.Toastify__toast--default { + background: var(--toastify-color-light); + color: var(--toastify-text-color-light); +} + +.Toastify__toast-theme--colored.Toastify__toast--info { + color: var(--toastify-text-color-info); + background: var(--toastify-color-info); +} + +.Toastify__toast-theme--colored.Toastify__toast--success { + color: var(--toastify-text-color-success); + background: var(--toastify-color-success); +} + +.Toastify__toast-theme--colored.Toastify__toast--warning { + color: var(--toastify-text-color-warning); + background: var(--toastify-color-warning); +} + +.Toastify__toast-theme--colored.Toastify__toast--error { + color: var(--toastify-text-color-error); + background: var(--toastify-color-error); +} + +.Toastify__progress-bar-theme--light { + background: var(--toastify-color-progress-light); +} + +.Toastify__progress-bar-theme--dark { + background: var(--toastify-color-progress-dark); +} + +.Toastify__progress-bar--info { + background: var(--toastify-color-progress-info); +} + +.Toastify__progress-bar--success { + background: var(--toastify-color-progress-success); +} + +.Toastify__progress-bar--warning { + background: var(--toastify-color-progress-warning); +} + +.Toastify__progress-bar--error { + background: var(--toastify-color-progress-error); +} + +.Toastify__progress-bar-theme--colored.Toastify__progress-bar--info, +.Toastify__progress-bar-theme--colored.Toastify__progress-bar--success, +.Toastify__progress-bar-theme--colored.Toastify__progress-bar--warning, +.Toastify__progress-bar-theme--colored.Toastify__progress-bar--error { + background: var(--toastify-color-transparent); +} + +.Toastify__close-button { + color: #fff; + position: absolute; + top: 6px; + right: 6px; + background: transparent; + outline: none; + border: none; + padding: 0; + cursor: pointer; + opacity: 0.7; + transition: 0.3s ease; + z-index: 1; +} + +.Toastify__toast--rtl .Toastify__close-button { + left: 6px; + right: unset; +} + +.Toastify__close-button--light { + color: #000; + opacity: 0.3; +} + +.Toastify__close-button > svg { + fill: currentColor; + height: 16px; + width: 14px; +} + +.Toastify__close-button:hover, +.Toastify__close-button:focus { + opacity: 1; +} + +@keyframes Toastify__trackProgress { + 0% { + transform: scaleX(1); + } + 100% { + transform: scaleX(0); + } +} + +.Toastify__progress-bar { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; + opacity: 0.7; + transform-origin: left; +} + +.Toastify__progress-bar--animated { + animation: Toastify__trackProgress linear 1 forwards; +} + +.Toastify__progress-bar--controlled { + transition: transform 0.2s; +} + +.Toastify__progress-bar--rtl { + right: 0; + left: initial; + transform-origin: right; + border-bottom-left-radius: initial; +} + +.Toastify__progress-bar--wrp { + position: absolute; + overflow: hidden; + bottom: 0; + left: 0; + width: 100%; + height: 5px; + border-bottom-left-radius: var(--toastify-toast-bd-radius); + border-bottom-right-radius: var(--toastify-toast-bd-radius); +} + +.Toastify__progress-bar--wrp[data-hidden='true'] { + opacity: 0; +} + +.Toastify__progress-bar--bg { + opacity: var(--toastify-color-progress-bgo); + width: 100%; + height: 100%; +} + +.Toastify__spinner { + width: 20px; + height: 20px; + box-sizing: border-box; + border: 2px solid; + border-radius: 100%; + border-color: var(--toastify-spinner-color-empty-area); + border-right-color: var(--toastify-spinner-color); + animation: Toastify__spin 0.65s linear infinite; +} + +@keyframes Toastify__bounceInRight { + from, + 60%, + 75%, + 90%, + to { + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + from { + opacity: 0; + transform: translate3d(3000px, 0, 0); + } + 60% { + opacity: 1; + transform: translate3d(-25px, 0, 0); + } + 75% { + transform: translate3d(10px, 0, 0); + } + 90% { + transform: translate3d(-5px, 0, 0); + } + to { + transform: none; + } +} + +@keyframes Toastify__bounceOutRight { + 20% { + opacity: 1; + transform: translate3d(-20px, var(--y), 0); + } + to { + opacity: 0; + transform: translate3d(2000px, var(--y), 0); + } +} + +@keyframes Toastify__bounceInLeft { + from, + 60%, + 75%, + 90%, + to { + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + 0% { + opacity: 0; + transform: translate3d(-3000px, 0, 0); + } + 60% { + opacity: 1; + transform: translate3d(25px, 0, 0); + } + 75% { + transform: translate3d(-10px, 0, 0); + } + 90% { + transform: translate3d(5px, 0, 0); + } + to { + transform: none; + } +} + +@keyframes Toastify__bounceOutLeft { + 20% { + opacity: 1; + transform: translate3d(20px, var(--y), 0); + } + to { + opacity: 0; + transform: translate3d(-2000px, var(--y), 0); + } +} + +@keyframes Toastify__bounceInUp { + from, + 60%, + 75%, + 90%, + to { + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + from { + opacity: 0; + transform: translate3d(0, 3000px, 0); + } + 60% { + opacity: 1; + transform: translate3d(0, -20px, 0); + } + 75% { + transform: translate3d(0, 10px, 0); + } + 90% { + transform: translate3d(0, -5px, 0); + } + to { + transform: translate3d(0, 0, 0); + } +} + +@keyframes Toastify__bounceOutUp { + 20% { + transform: translate3d(0, calc(var(--y) - 10px), 0); + } + 40%, + 45% { + opacity: 1; + transform: translate3d(0, calc(var(--y) + 20px), 0); + } + to { + opacity: 0; + transform: translate3d(0, -2000px, 0); + } +} + +@keyframes Toastify__bounceInDown { + from, + 60%, + 75%, + 90%, + to { + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + 0% { + opacity: 0; + transform: translate3d(0, -3000px, 0); + } + 60% { + opacity: 1; + transform: translate3d(0, 25px, 0); + } + 75% { + transform: translate3d(0, -10px, 0); + } + 90% { + transform: translate3d(0, 5px, 0); + } + to { + transform: none; + } +} + +@keyframes Toastify__bounceOutDown { + 20% { + transform: translate3d(0, calc(var(--y) - 10px), 0); + } + 40%, + 45% { + opacity: 1; + transform: translate3d(0, calc(var(--y) + 20px), 0); + } + to { + opacity: 0; + transform: translate3d(0, 2000px, 0); + } +} + +.Toastify__bounce-enter--top-left, +.Toastify__bounce-enter--bottom-left { + animation-name: Toastify__bounceInLeft; +} + +.Toastify__bounce-enter--top-right, +.Toastify__bounce-enter--bottom-right { + animation-name: Toastify__bounceInRight; +} + +.Toastify__bounce-enter--top-center { + animation-name: Toastify__bounceInDown; +} + +.Toastify__bounce-enter--bottom-center { + animation-name: Toastify__bounceInUp; +} + +.Toastify__bounce-exit--top-left, +.Toastify__bounce-exit--bottom-left { + animation-name: Toastify__bounceOutLeft; +} + +.Toastify__bounce-exit--top-right, +.Toastify__bounce-exit--bottom-right { + animation-name: Toastify__bounceOutRight; +} + +.Toastify__bounce-exit--top-center { + animation-name: Toastify__bounceOutUp; +} + +.Toastify__bounce-exit--bottom-center { + animation-name: Toastify__bounceOutDown; +} + +@keyframes Toastify__zoomIn { + from { + opacity: 0; + transform: scale3d(0.3, 0.3, 0.3); + } + 50% { + opacity: 1; + } +} + +@keyframes Toastify__zoomOut { + from { + opacity: 1; + } + 50% { + opacity: 0; + transform: translate3d(0, var(--y), 0) scale3d(0.3, 0.3, 0.3); + } + to { + opacity: 0; + } +} + +.Toastify__zoom-enter { + animation-name: Toastify__zoomIn; +} + +.Toastify__zoom-exit { + animation-name: Toastify__zoomOut; +} + +@keyframes Toastify__flipIn { + from { + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + animation-timing-function: ease-in; + opacity: 0; + } + 40% { + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + animation-timing-function: ease-in; + } + 60% { + transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + opacity: 1; + } + 80% { + transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + } + to { + transform: perspective(400px); + } +} + +@keyframes Toastify__flipOut { + from { + transform: translate3d(0, var(--y), 0) perspective(400px); + } + 30% { + transform: translate3d(0, var(--y), 0) perspective(400px) rotate3d(1, 0, 0, -20deg); + opacity: 1; + } + to { + transform: translate3d(0, var(--y), 0) perspective(400px) rotate3d(1, 0, 0, 90deg); + opacity: 0; + } +} + +.Toastify__flip-enter { + animation-name: Toastify__flipIn; +} + +.Toastify__flip-exit { + animation-name: Toastify__flipOut; +} + +@keyframes Toastify__slideInRight { + from { + transform: translate3d(110%, 0, 0); + visibility: visible; + } + to { + transform: translate3d(0, var(--y), 0); + } +} + +@keyframes Toastify__slideInLeft { + from { + transform: translate3d(-110%, 0, 0); + visibility: visible; + } + to { + transform: translate3d(0, var(--y), 0); + } +} + +@keyframes Toastify__slideInUp { + from { + transform: translate3d(0, 110%, 0); + visibility: visible; + } + to { + transform: translate3d(0, var(--y), 0); + } +} + +@keyframes Toastify__slideInDown { + from { + transform: translate3d(0, -110%, 0); + visibility: visible; + } + to { + transform: translate3d(0, var(--y), 0); + } +} + +@keyframes Toastify__slideOutRight { + from { + transform: translate3d(0, var(--y), 0); + } + to { + visibility: hidden; + transform: translate3d(110%, var(--y), 0); + } +} + +@keyframes Toastify__slideOutLeft { + from { + transform: translate3d(0, var(--y), 0); + } + to { + visibility: hidden; + transform: translate3d(-110%, var(--y), 0); + } +} + +@keyframes Toastify__slideOutDown { + from { + transform: translate3d(0, var(--y), 0); + } + to { + visibility: hidden; + transform: translate3d(0, 500px, 0); + } +} + +@keyframes Toastify__slideOutUp { + from { + transform: translate3d(0, var(--y), 0); + } + to { + visibility: hidden; + transform: translate3d(0, -500px, 0); + } +} + +.Toastify__slide-enter--top-left, +.Toastify__slide-enter--bottom-left { + animation-name: Toastify__slideInLeft; +} + +.Toastify__slide-enter--top-right, +.Toastify__slide-enter--bottom-right { + animation-name: Toastify__slideInRight; +} + +.Toastify__slide-enter--top-center { + animation-name: Toastify__slideInDown; +} + +.Toastify__slide-enter--bottom-center { + animation-name: Toastify__slideInUp; +} + +.Toastify__slide-exit--top-left, +.Toastify__slide-exit--bottom-left { + animation-name: Toastify__slideOutLeft; + animation-timing-function: ease-in; + animation-duration: 0.3s; +} + +.Toastify__slide-exit--top-right, +.Toastify__slide-exit--bottom-right { + animation-name: Toastify__slideOutRight; + animation-timing-function: ease-in; + animation-duration: 0.3s; +} + +.Toastify__slide-exit--top-center { + animation-name: Toastify__slideOutUp; + animation-timing-function: ease-in; + animation-duration: 0.3s; +} + +.Toastify__slide-exit--bottom-center { + animation-name: Toastify__slideOutDown; + animation-timing-function: ease-in; + animation-duration: 0.3s; +} + +@keyframes Toastify__spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/src/app/app.css b/src/app/app.css index 93e3cfe..2410ca9 100644 --- a/src/app/app.css +++ b/src/app/app.css @@ -16,6 +16,11 @@ appearance: none; -webkit-appearance: none; } + + .scrollbar-hide { + scrollbar-width: none; + -webkit-scrollbar: none; + } } @font-face { diff --git a/src/app/root.tsx b/src/app/root.tsx index f23cb0d..4e77d50 100644 --- a/src/app/root.tsx +++ b/src/app/root.tsx @@ -7,10 +7,10 @@ import { isRouteErrorResponse, } from 'react-router'; import { ToastContainer } from 'react-toastify/unstyled'; -import 'react-toastify/ReactToastify.css'; import type { Route } from './+types/root'; import './app.css'; +import { preload } from 'react-dom'; import { Slide } from 'react-toastify'; import StompProvider from './provider/StompProvider'; import UserIdProvider from './provider/UserInfoProvider'; @@ -37,6 +37,12 @@ export const links: Route.LinksFunction = () => [ type: 'image/png', sizes: '32x32', }, + { + rel: 'stylesheet', + href: '/ReactToastify.css', + media: 'print', + onload: 'this.media="all"', + }, ]; export function meta() { @@ -48,6 +54,19 @@ export function meta() { } export function Layout({ children }: Readonly<{ children: React.ReactNode }>) { + preload('/fonts/Pretendard-Medium.woff2', { + as: 'font', + crossOrigin: 'anonymous', + }); + preload('/fonts/Pretendard-Regular.woff2', { + as: 'font', + crossOrigin: 'anonymous', + }); + preload('/fonts/Pretendard-SemiBold.woff2', { + as: 'font', + crossOrigin: 'anonymous', + }); + return (
diff --git a/src/app/routes/trade.$ticker.tsx b/src/app/routes/trade.$ticker.tsx index 74275f9..fbe532b 100644 --- a/src/app/routes/trade.$ticker.tsx +++ b/src/app/routes/trade.$ticker.tsx @@ -75,7 +75,7 @@ export default function TradeRouteComponent({ {coinInfo && (