From c57e927d3cd2ad7e7c27e0e57fdfb9796f8626db Mon Sep 17 00:00:00 2001 From: Blue Mouse Date: Mon, 30 Sep 2024 01:45:28 +0100 Subject: [PATCH] sonner.css styles --- app/root.tsx | 2 + app/styles/sonner.css | 638 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 640 insertions(+) create mode 100644 app/styles/sonner.css diff --git a/app/root.tsx b/app/root.tsx index 09c26469..7be0a01f 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -32,6 +32,7 @@ import { SEO } from 'components/SEO' import mainCss from 'styles/index.css' import tailwindCss from 'styles/tailwind.css' +import sonnerCss from 'styles/sonner.css' import FlatpickerCss from 'styles/Flatpicker.css' import FlatpickrLightCss from 'flatpickr/dist/themes/light.css' import FlatpickrDarkCss from 'flatpickr/dist/themes/dark.css' @@ -54,6 +55,7 @@ if (isBrowser && process.env.NODE_ENV !== 'production') { export const links: LinksFunction = () => [ { rel: 'stylesheet', href: tailwindCss }, + { rel: 'stylesheet', href: sonnerCss }, { rel: 'stylesheet', href: mainCss }, { rel: 'stylesheet', href: BillboardCss }, { rel: 'stylesheet', href: FlatpickerCss }, diff --git a/app/styles/sonner.css b/app/styles/sonner.css new file mode 100644 index 00000000..81536232 --- /dev/null +++ b/app/styles/sonner.css @@ -0,0 +1,638 @@ +:where(html[dir='ltr']), +:where([data-sonner-toaster][dir='ltr']) { + --toast-icon-margin-start: -3px; + --toast-icon-margin-end: 4px; + --toast-svg-margin-start: -1px; + --toast-svg-margin-end: 0px; + --toast-button-margin-start: auto; + --toast-button-margin-end: 0; + --toast-close-button-start: 0; + --toast-close-button-end: unset; + --toast-close-button-transform: translate(-35%, -35%); +} + +:where(html[dir='rtl']), +:where([data-sonner-toaster][dir='rtl']) { + --toast-icon-margin-start: 4px; + --toast-icon-margin-end: -3px; + --toast-svg-margin-start: 0px; + --toast-svg-margin-end: -1px; + --toast-button-margin-start: 0; + --toast-button-margin-end: auto; + --toast-close-button-start: unset; + --toast-close-button-end: 0; + --toast-close-button-transform: translate(35%, -35%); +} + +:where([data-sonner-toaster]) { + position: fixed; + width: var(--width); + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, + Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; + --gray1: hsl(0, 0%, 99%); + --gray2: hsl(0, 0%, 97.3%); + --gray3: hsl(0, 0%, 95.1%); + --gray4: hsl(0, 0%, 93%); + --gray5: hsl(0, 0%, 90.9%); + --gray6: hsl(0, 0%, 88.7%); + --gray7: hsl(0, 0%, 85.8%); + --gray8: hsl(0, 0%, 78%); + --gray9: hsl(0, 0%, 56.1%); + --gray10: hsl(0, 0%, 52.3%); + --gray11: hsl(0, 0%, 43.5%); + --gray12: hsl(0, 0%, 9%); + --border-radius: 8px; + box-sizing: border-box; + padding: 0; + margin: 0; + list-style: none; + outline: none; + z-index: 999999999; +} + +:where([data-sonner-toaster][data-x-position='right']) { + right: max(var(--offset), env(safe-area-inset-right)); +} + +:where([data-sonner-toaster][data-x-position='left']) { + left: max(var(--offset), env(safe-area-inset-left)); +} + +:where([data-sonner-toaster][data-x-position='center']) { + left: 50%; + transform: translateX(-50%); +} + +:where([data-sonner-toaster][data-y-position='top']) { + top: max(var(--offset), env(safe-area-inset-top)); +} + +:where([data-sonner-toaster][data-y-position='bottom']) { + bottom: max(var(--offset), env(safe-area-inset-bottom)); +} + +:where([data-sonner-toast]) { + --y: translateY(100%); + --lift-amount: calc(var(--lift) * var(--gap)); + z-index: var(--z-index); + position: absolute; + opacity: 0; + transform: var(--y); + filter: blur(0); + /* https://stackoverflow.com/questions/48124372/pointermove-event-not-working-with-touch-why-not */ + touch-action: none; + transition: transform 400ms, opacity 400ms, height 400ms, box-shadow 200ms; + box-sizing: border-box; + outline: none; + overflow-wrap: anywhere; +} + +:where([data-sonner-toast][data-styled='true']) { + padding: 16px; + background: var(--normal-bg); + border: 1px solid var(--normal-border); + color: var(--normal-text); + border-radius: var(--border-radius); + box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1); + width: var(--width); + font-size: 13px; + display: flex; + align-items: center; + gap: 6px; +} + +:where([data-sonner-toast]:focus-visible) { + box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(0, 0, 0, 0.2); +} + +:where([data-sonner-toast][data-y-position='top']) { + top: 0; + --y: translateY(-100%); + --lift: 1; + --lift-amount: calc(1 * var(--gap)); +} + +:where([data-sonner-toast][data-y-position='bottom']) { + bottom: 0; + --y: translateY(100%); + --lift: -1; + --lift-amount: calc(var(--lift) * var(--gap)); +} + +:where([data-sonner-toast]) :where([data-description]) { + font-weight: 400; + line-height: 1.4; + color: inherit; +} + +:where([data-sonner-toast]) :where([data-title]) { + font-weight: 500; + line-height: 1.5; + color: inherit; +} + +:where([data-sonner-toast]) :where([data-icon]) { + display: flex; + height: 16px; + width: 16px; + position: relative; + justify-content: flex-start; + align-items: center; + flex-shrink: 0; + margin-left: var(--toast-icon-margin-start); + margin-right: var(--toast-icon-margin-end); +} + +:where([data-sonner-toast][data-promise='true']) :where([data-icon]) > svg { + opacity: 0; + transform: scale(0.8); + transform-origin: center; + animation: sonner-fade-in 300ms ease forwards; +} + +:where([data-sonner-toast]) :where([data-icon]) > * { + flex-shrink: 0; +} + +:where([data-sonner-toast]) :where([data-icon]) svg { + margin-left: var(--toast-svg-margin-start); + margin-right: var(--toast-svg-margin-end); +} + +:where([data-sonner-toast]) :where([data-content]) { + display: flex; + flex-direction: column; + gap: 2px; +} + +[data-sonner-toast][data-styled='true'] [data-button] { + border-radius: 4px; + padding-left: 8px; + padding-right: 8px; + height: 24px; + font-size: 12px; + color: var(--normal-bg); + background: var(--normal-text); + margin-left: var(--toast-button-margin-start); + margin-right: var(--toast-button-margin-end); + border: none; + cursor: pointer; + outline: none; + display: flex; + align-items: center; + flex-shrink: 0; + transition: opacity 400ms, box-shadow 200ms; +} + +:where([data-sonner-toast]) :where([data-button]):focus-visible { + box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.4); +} + +:where([data-sonner-toast]) :where([data-button]):first-of-type { + margin-left: var(--toast-button-margin-start); + margin-right: var(--toast-button-margin-end); +} + +:where([data-sonner-toast]) :where([data-cancel]) { + color: var(--normal-text); + background: rgba(0, 0, 0, 0.08); +} + +:where([data-sonner-toast][data-theme='dark']) :where([data-cancel]) { + background: rgba(255, 255, 255, 0.3); +} + +:where([data-sonner-toast]) :where([data-close-button]) { + position: absolute; + left: var(--toast-close-button-start); + right: var(--toast-close-button-end); + top: 0; + height: 20px; + width: 20px; + display: flex; + justify-content: center; + align-items: center; + padding: 0; + background: var(--gray1); + color: var(--gray12); + border: 1px solid var(--gray4); + transform: var(--toast-close-button-transform); + border-radius: 50%; + cursor: pointer; + z-index: 1; + transition: opacity 100ms, background 200ms, border-color 200ms; +} + +:where([data-sonner-toast]) :where([data-close-button]):focus-visible { + box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(0, 0, 0, 0.2); +} + +:where([data-sonner-toast]) :where([data-disabled='true']) { + cursor: not-allowed; +} + +:where([data-sonner-toast]):hover :where([data-close-button]):hover { + background: var(--gray2); + border-color: var(--gray5); +} + +/* Leave a ghost div to avoid setting hover to false when swiping out */ +:where([data-sonner-toast][data-swiping='true'])::before { + content: ''; + position: absolute; + left: 0; + right: 0; + height: 100%; + z-index: -1; +} + +:where([data-sonner-toast][data-y-position='top'][data-swiping='true'])::before { + /* y 50% needed to distribute height additional height evenly */ + bottom: 50%; + transform: scaleY(3) translateY(50%); +} + +:where([data-sonner-toast][data-y-position='bottom'][data-swiping='true'])::before { + /* y -50% needed to distribute height additional height evenly */ + top: 50%; + transform: scaleY(3) translateY(-50%); +} + +/* Leave a ghost div to avoid setting hover to false when transitioning out */ +:where([data-sonner-toast][data-swiping='false'][data-removed='true'])::before { + content: ''; + position: absolute; + inset: 0; + transform: scaleY(2); +} + +/* Needed to avoid setting hover to false when inbetween toasts */ +:where([data-sonner-toast])::after { + content: ''; + position: absolute; + left: 0; + height: calc(var(--gap) + 1px); + bottom: 100%; + width: 100%; +} + +:where([data-sonner-toast][data-mounted='true']) { + --y: translateY(0); + opacity: 1; +} + +:where([data-sonner-toast][data-expanded='false'][data-front='false']) { + --scale: var(--toasts-before) * 0.05 + 1; + --y: translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale))); + height: var(--front-toast-height); +} + +:where([data-sonner-toast]) > * { + transition: opacity 400ms; +} + +:where([data-sonner-toast][data-expanded='false'][data-front='false'][data-styled='true']) > * { + opacity: 0; +} + +:where([data-sonner-toast][data-visible='false']) { + opacity: 0; + pointer-events: none; +} + +:where([data-sonner-toast][data-mounted='true'][data-expanded='true']) { + --y: translateY(calc(var(--lift) * var(--offset))); + height: var(--initial-height); +} + +:where([data-sonner-toast][data-removed='true'][data-front='true'][data-swipe-out='false']) { + --y: translateY(calc(var(--lift) * -100%)); + opacity: 0; +} + +:where([data-sonner-toast][data-removed='true'][data-front='false'][data-swipe-out='false'][data-expanded='true']) { + --y: translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%)); + opacity: 0; +} + +:where([data-sonner-toast][data-removed='true'][data-front='false'][data-swipe-out='false'][data-expanded='false']) { + --y: translateY(40%); + opacity: 0; + transition: transform 500ms, opacity 200ms; +} + +/* Bump up the height to make sure hover state doesn't get set to false */ +:where([data-sonner-toast][data-removed='true'][data-front='false'])::before { + height: calc(var(--initial-height) + 20%); +} + +[data-sonner-toast][data-swiping='true'] { + transform: var(--y) translateY(var(--swipe-amount, 0px)); + transition: none; +} + +[data-sonner-toast][data-swipe-out='true'][data-y-position='bottom'], +[data-sonner-toast][data-swipe-out='true'][data-y-position='top'] { + animation: swipe-out 200ms ease-out forwards; +} + +@keyframes swipe-out { + from { + transform: translateY(calc(var(--lift) * var(--offset) + var(--swipe-amount))); + opacity: 1; + } + + to { + transform: translateY(calc(var(--lift) * var(--offset) + var(--swipe-amount) + var(--lift) * -100%)); + opacity: 0; + } +} + +@media (max-width: 600px) { + [data-sonner-toaster] { + position: fixed; + --mobile-offset: 16px; + right: var(--mobile-offset); + left: var(--mobile-offset); + width: 100%; + } + + [data-sonner-toaster][dir='rtl'] { + left: calc(var(--mobile-offset) * -1); + } + + [data-sonner-toaster] [data-sonner-toast] { + left: 0; + right: 0; + width: calc(100% - var(--mobile-offset) * 2); + } + + [data-sonner-toaster][data-x-position='left'] { + left: var(--mobile-offset); + } + + [data-sonner-toaster][data-y-position='bottom'] { + bottom: 20px; + } + + [data-sonner-toaster][data-y-position='top'] { + top: 20px; + } + + [data-sonner-toaster][data-x-position='center'] { + left: var(--mobile-offset); + right: var(--mobile-offset); + transform: none; + } +} + +[data-sonner-toaster][data-theme='light'] { + --normal-bg: #fff; + --normal-border: var(--gray4); + --normal-text: var(--gray12); + + --success-bg: hsl(143, 85%, 96%); + --success-border: hsl(145, 92%, 91%); + --success-text: hsl(140, 100%, 27%); + + --info-bg: hsl(208, 100%, 97%); + --info-border: hsl(221, 91%, 91%); + --info-text: hsl(210, 92%, 45%); + + --warning-bg: hsl(49, 100%, 97%); + --warning-border: hsl(49, 91%, 91%); + --warning-text: hsl(31, 92%, 45%); + + --error-bg: hsl(359, 100%, 97%); + --error-border: hsl(359, 100%, 94%); + --error-text: hsl(360, 100%, 45%); +} + +[data-sonner-toaster][data-theme='light'] [data-sonner-toast][data-invert='true'] { + --normal-bg: #000; + --normal-border: hsl(0, 0%, 20%); + --normal-text: var(--gray1); +} + +[data-sonner-toaster][data-theme='dark'] [data-sonner-toast][data-invert='true'] { + --normal-bg: #fff; + --normal-border: var(--gray3); + --normal-text: var(--gray12); +} + +[data-sonner-toaster][data-theme='dark'] { + --normal-bg: #000; + --normal-border: hsl(0, 0%, 20%); + --normal-text: var(--gray1); + + --success-bg: hsl(150, 100%, 6%); + --success-border: hsl(147, 100%, 12%); + --success-text: hsl(150, 86%, 65%); + + --info-bg: hsl(215, 100%, 6%); + --info-border: hsl(223, 100%, 12%); + --info-text: hsl(216, 87%, 65%); + + --warning-bg: hsl(64, 100%, 6%); + --warning-border: hsl(60, 100%, 12%); + --warning-text: hsl(46, 87%, 65%); + + --error-bg: hsl(358, 76%, 10%); + --error-border: hsl(357, 89%, 16%); + --error-text: hsl(358, 100%, 81%); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='success'] { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='success'] [data-close-button] { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='info'] { + background: var(--info-bg); + border-color: var(--info-border); + color: var(--info-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='info'] [data-close-button] { + background: var(--info-bg); + border-color: var(--info-border); + color: var(--info-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='warning'] { + background: var(--warning-bg); + border-color: var(--warning-border); + color: var(--warning-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='warning'] [data-close-button] { + background: var(--warning-bg); + border-color: var(--warning-border); + color: var(--warning-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='error'] { + background: var(--error-bg); + border-color: var(--error-border); + color: var(--error-text); +} + +[data-rich-colors='true'][data-sonner-toast][data-type='error'] [data-close-button] { + background: var(--error-bg); + border-color: var(--error-border); + color: var(--error-text); +} + +.sonner-loading-wrapper { + --size: 16px; + height: var(--size); + width: var(--size); + position: absolute; + inset: 0; + z-index: 10; +} + +.sonner-loading-wrapper[data-visible='false'] { + transform-origin: center; + animation: sonner-fade-out 0.2s ease forwards; +} + +.sonner-spinner { + position: relative; + top: 50%; + left: 50%; + height: var(--size); + width: var(--size); +} + +.sonner-loading-bar { + animation: sonner-spin 1.2s linear infinite; + background: var(--gray11); + border-radius: 6px; + height: 8%; + left: -10%; + position: absolute; + top: -3.9%; + width: 24%; +} + +.sonner-loading-bar:nth-child(1) { + animation-delay: -1.2s; + transform: rotate(0.0001deg) translate(146%); +} + +.sonner-loading-bar:nth-child(2) { + animation-delay: -1.1s; + transform: rotate(30deg) translate(146%); +} + +.sonner-loading-bar:nth-child(3) { + animation-delay: -1s; + transform: rotate(60deg) translate(146%); +} + +.sonner-loading-bar:nth-child(4) { + animation-delay: -0.9s; + transform: rotate(90deg) translate(146%); +} + +.sonner-loading-bar:nth-child(5) { + animation-delay: -0.8s; + transform: rotate(120deg) translate(146%); +} + +.sonner-loading-bar:nth-child(6) { + animation-delay: -0.7s; + transform: rotate(150deg) translate(146%); +} + +.sonner-loading-bar:nth-child(7) { + animation-delay: -0.6s; + transform: rotate(180deg) translate(146%); +} + +.sonner-loading-bar:nth-child(8) { + animation-delay: -0.5s; + transform: rotate(210deg) translate(146%); +} + +.sonner-loading-bar:nth-child(9) { + animation-delay: -0.4s; + transform: rotate(240deg) translate(146%); +} + +.sonner-loading-bar:nth-child(10) { + animation-delay: -0.3s; + transform: rotate(270deg) translate(146%); +} + +.sonner-loading-bar:nth-child(11) { + animation-delay: -0.2s; + transform: rotate(300deg) translate(146%); +} + +.sonner-loading-bar:nth-child(12) { + animation-delay: -0.1s; + transform: rotate(330deg) translate(146%); +} + +@keyframes sonner-fade-in { + 0% { + opacity: 0; + transform: scale(0.8); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + +@keyframes sonner-fade-out { + 0% { + opacity: 1; + transform: scale(1); + } + 100% { + opacity: 0; + transform: scale(0.8); + } +} + +@keyframes sonner-spin { + 0% { + opacity: 1; + } + 100% { + opacity: 0.15; + } +} + +@media (prefers-reduced-motion) { + [data-sonner-toast], + [data-sonner-toast] > *, + .sonner-loading-bar { + transition: none !important; + animation: none !important; + } +} + +.sonner-loader { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + transform-origin: center; + transition: opacity 200ms, transform 200ms; +} + +.sonner-loader[data-visible='false'] { + opacity: 0; + transform: scale(0.8) translate(-50%, -50%); +}