mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
a81549768c
Introduce cursor-based pagination and group counts for /api/requests (status groups, nextCursor, counts) and fetch one extra record to detect next page. Add a client-side My Requests experience: useSWRInfinite hook (useMyRequests) with smart polling for active requests, tabbed filters, badges, skeletons, load-more, and animated list entries. Update RequestCard and admin actions to treat awaiting_search as cancellable. Adjust Plex processors to ignore requests with status 'denied' when matching new media. Add static ffmpeg in the Docker image and remove preinstalled ImageMagick to avoid transitive deps. Update tests to account for pagination/take+1 and the new hook/UX behavior.
250 lines
4.5 KiB
CSS
250 lines
4.5 KiB
CSS
@import "tailwindcss";
|
|
|
|
:root {
|
|
--background: #ffffff;
|
|
--foreground: #171717;
|
|
}
|
|
|
|
@theme inline {
|
|
--color-background: var(--background);
|
|
--color-foreground: var(--foreground);
|
|
--font-sans: var(--font-geist-sans);
|
|
--font-mono: var(--font-geist-mono);
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--background: #0a0a0a;
|
|
--foreground: #ededed;
|
|
}
|
|
}
|
|
|
|
body {
|
|
background: var(--background);
|
|
color: var(--foreground);
|
|
font-family: Arial, Helvetica, sans-serif;
|
|
}
|
|
|
|
@keyframes slide-in-right {
|
|
from {
|
|
transform: translateX(100%);
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.animate-slide-in-right {
|
|
animation: slide-in-right 0.3s ease-out;
|
|
}
|
|
|
|
/* BookDate Card Stack Animations */
|
|
|
|
/* Exit animations - card swipes away */
|
|
@keyframes card-exit-left {
|
|
0% {
|
|
transform: translate(0, 0) rotate(0deg);
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
transform: translate(-150%, 50px) rotate(-25deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes card-exit-right {
|
|
0% {
|
|
transform: translate(0, 0) rotate(0deg);
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
transform: translate(150%, 50px) rotate(25deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes card-exit-up {
|
|
0% {
|
|
transform: translate(0, 0) scale(1);
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
transform: translate(0, -120%) scale(0.8);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
/* Advance animations - cards move forward in stack */
|
|
@keyframes card-advance-to-top {
|
|
0% {
|
|
transform: scale(0.95) translateY(-12px);
|
|
opacity: 0.95;
|
|
}
|
|
100% {
|
|
transform: scale(1) translateY(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes card-advance-to-middle {
|
|
0% {
|
|
transform: scale(0.90) translateY(-24px);
|
|
opacity: 0.90;
|
|
}
|
|
100% {
|
|
transform: scale(0.95) translateY(-12px);
|
|
opacity: 0.95;
|
|
}
|
|
}
|
|
|
|
/* Enter animation - new card enters from bottom of stack */
|
|
@keyframes card-enter {
|
|
0% {
|
|
transform: scale(0.85) translateY(-36px);
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
transform: scale(0.90) translateY(-24px);
|
|
opacity: 0.90;
|
|
}
|
|
}
|
|
|
|
/* Animation classes */
|
|
.animate-exit-left {
|
|
animation: card-exit-left 400ms ease-in-out forwards;
|
|
}
|
|
|
|
.animate-exit-right {
|
|
animation: card-exit-right 400ms ease-in-out forwards;
|
|
}
|
|
|
|
.animate-exit-up {
|
|
animation: card-exit-up 400ms ease-in-out forwards;
|
|
}
|
|
|
|
.animate-advance-to-top {
|
|
animation: card-advance-to-top 350ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
}
|
|
|
|
.animate-advance-to-middle {
|
|
animation: card-advance-to-middle 350ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
}
|
|
|
|
.animate-enter {
|
|
animation: card-enter 350ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
}
|
|
|
|
/* Stack positioning classes */
|
|
.card-stack-position-0 {
|
|
z-index: 50;
|
|
transform: scale(1) translateY(0);
|
|
opacity: 1;
|
|
pointer-events: auto;
|
|
}
|
|
|
|
.card-stack-position-1 {
|
|
z-index: 40;
|
|
transform: scale(0.95) translateY(-12px);
|
|
opacity: 0.95;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.card-stack-position-2 {
|
|
z-index: 30;
|
|
transform: scale(0.90) translateY(-24px);
|
|
opacity: 0.90;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Performance optimizations */
|
|
.card-stack-container {
|
|
perspective: 1000px;
|
|
transform-style: preserve-3d;
|
|
}
|
|
|
|
.card-stack-item {
|
|
will-change: transform, opacity;
|
|
backface-visibility: hidden;
|
|
-webkit-backface-visibility: hidden;
|
|
transform-origin: center center;
|
|
}
|
|
|
|
/* Premium Shimmer Animation for Skeletons */
|
|
@keyframes shimmer {
|
|
0% {
|
|
transform: translateX(-100%);
|
|
}
|
|
100% {
|
|
transform: translateX(100%);
|
|
}
|
|
}
|
|
|
|
/* Smooth Toast Slide In */
|
|
@keyframes toast-slide-in {
|
|
0% {
|
|
opacity: 0;
|
|
transform: translate(-50%, 20px);
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
transform: translate(-50%, 0);
|
|
}
|
|
}
|
|
|
|
.animate-toast-in {
|
|
animation: toast-slide-in 0.3s ease-out;
|
|
}
|
|
|
|
/* Requests page list entry animations */
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/* Confirmation Dialog */
|
|
@keyframes dialog-backdrop-in {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
@keyframes dialog-panel-in {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.95) translateY(8px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1) translateY(0);
|
|
}
|
|
}
|
|
|
|
.animate-dialog-backdrop {
|
|
animation: dialog-backdrop-in 0.15s ease-out forwards;
|
|
}
|
|
|
|
.animate-dialog-panel {
|
|
animation: dialog-panel-in 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
}
|
|
|
|
/* Hide scrollbar while keeping scroll functional */
|
|
.scrollbar-hide {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
.scrollbar-hide::-webkit-scrollbar {
|
|
display: none;
|
|
}
|