Refine gallery hover border flow
This commit is contained in:
@@ -77,7 +77,7 @@ Use this guide when the user reports behavior. Start from the symptom row, inspe
|
||||
| Gallery delete does not remove public item | `src/app/api/gallery/route.ts`, admin UI route using it | DELETE unpublishes by setting `is_public = false`, not hard delete. |
|
||||
| Search/filter/sort wrong | `src/app/api/gallery/route.ts`, `src/app/gallery/page.tsx` | Query params `type`, `limit`, `offset`, `sort`, `q/search`; SQL where/order. |
|
||||
| Gallery search box looks inconsistent with the rest of the UI | `src/app/gallery/page.tsx` | The search field is a custom glass panel with an inner focused input surface; avoid reverting it to a plain transparent input row. |
|
||||
| Gallery hover makes images muddy, covers the image with prompt text, or action buttons disappear on dark/light images | `src/app/gallery/page.tsx`, `src/app/globals.css` | Gallery cards should not use a full-image dark hover overlay or center prompt text. Keep hover feedback on the card container with image-color glow/scale, and keep like/download buttons legible through sampled image brightness inversion. |
|
||||
| Gallery hover makes images muddy, covers the image with prompt text, shows a rotating glow block, or action buttons disappear on dark/light images | `src/app/gallery/page.tsx`, `src/app/globals.css` | Gallery cards should not use a full-image dark hover overlay, center prompt text, or broad square glow under the card. Keep hover feedback on the card container with scale plus a thin image-color perimeter flow, and keep like/download buttons legible through sampled image brightness inversion. |
|
||||
|
||||
## Canvas
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ Use this document to jump directly to code before broad searching.
|
||||
|
||||
| Feature | Files | Notes |
|
||||
| --- | --- | --- |
|
||||
| Public gallery page | `src/app/gallery/page.tsx`, `src/app/globals.css` | Lists public works, search/sort/filter, preview/download. The search box is custom styled in-page to match the glass UI; gallery cards use hover scale plus image-color glow instead of an image-covering dark overlay, and hover like/download buttons invert against sampled image brightness. Gallery detail image previews use `ImageMetadataBadge` for actual ratio/resolution. |
|
||||
| Public gallery page | `src/app/gallery/page.tsx`, `src/app/globals.css` | Lists public works, search/sort/filter, preview/download. The search box is custom styled in-page to match the glass UI; gallery cards use hover scale plus a thin image-color perimeter flow instead of an image-covering dark overlay or broad glow block, and hover like/download buttons invert against sampled image brightness. Gallery detail image previews use `ImageMetadataBadge` for actual ratio/resolution. |
|
||||
| Public gallery API | `src/app/api/gallery/route.ts` | GET public works, admin DELETE unpublishes. |
|
||||
| Publish API | `src/app/api/gallery/publish/route.ts` | Copies media into gallery folders and inserts public work. |
|
||||
| History persistence | `src/app/api/creation-history/route.ts`, `src/lib/creation-history-store.ts` | User-private completed works and published state. Single-record deletion is server-first when logged in; detail dialogs call the same store path and then refresh local history. |
|
||||
|
||||
@@ -659,15 +659,6 @@ export default function GalleryPage() {
|
||||
className="gallery-work-shell group"
|
||||
style={getGalleryCardStyle(cardPalettes[work.id])}
|
||||
>
|
||||
{mediaPreviewUrl && (
|
||||
<img
|
||||
src={mediaPreviewUrl}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="gallery-work-image-glow"
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
<Card
|
||||
className={`${galleryGlassCard} gallery-work-card w-full overflow-hidden cursor-pointer !rounded-2xl !py-0`}
|
||||
onClick={() => setSelectedWork(work)}
|
||||
|
||||
@@ -227,39 +227,66 @@
|
||||
.gallery-work-shell::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -10px;
|
||||
z-index: -2;
|
||||
border-radius: 1.35rem;
|
||||
inset: -2px;
|
||||
z-index: -1;
|
||||
padding: 2px;
|
||||
border-radius: 1.12rem;
|
||||
background:
|
||||
conic-gradient(
|
||||
from 0deg,
|
||||
var(--gallery-accent-1),
|
||||
var(--gallery-accent-2),
|
||||
var(--gallery-accent-3),
|
||||
var(--gallery-accent-1)
|
||||
transparent 0deg,
|
||||
transparent 38deg,
|
||||
var(--gallery-accent-1) 62deg,
|
||||
var(--gallery-accent-2) 86deg,
|
||||
var(--gallery-accent-3) 112deg,
|
||||
transparent 142deg,
|
||||
transparent 360deg
|
||||
);
|
||||
filter: blur(22px);
|
||||
opacity: 0;
|
||||
transform: scale(0.94) rotate(0deg);
|
||||
transition:
|
||||
opacity 320ms ease,
|
||||
transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||
animation: gallery-glow-flow 5.5s linear infinite;
|
||||
transition: opacity 260ms ease;
|
||||
animation: gallery-border-flow 2.8s linear infinite;
|
||||
animation-play-state: paused;
|
||||
-webkit-mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
||||
.gallery-work-shell::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -2px;
|
||||
z-index: -1;
|
||||
border-radius: 1.05rem;
|
||||
inset: -5px;
|
||||
z-index: -2;
|
||||
padding: 5px;
|
||||
border-radius: 1.28rem;
|
||||
background:
|
||||
linear-gradient(135deg, rgb(255 255 255 / 0.24), transparent 32% 68%, rgb(255 255 255 / 0.12)),
|
||||
linear-gradient(120deg, var(--gallery-accent-1), transparent 38% 62%, var(--gallery-accent-2));
|
||||
filter: blur(10px);
|
||||
conic-gradient(
|
||||
from 0deg,
|
||||
transparent 0deg,
|
||||
transparent 42deg,
|
||||
var(--gallery-accent-1) 66deg,
|
||||
var(--gallery-accent-2) 92deg,
|
||||
var(--gallery-accent-3) 118deg,
|
||||
transparent 152deg,
|
||||
transparent 360deg
|
||||
);
|
||||
filter: blur(8px);
|
||||
opacity: 0;
|
||||
transition: opacity 320ms ease;
|
||||
animation: gallery-border-flow 2.8s linear infinite;
|
||||
animation-play-state: paused;
|
||||
-webkit-mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
||||
.gallery-work-shell:hover {
|
||||
@@ -269,13 +296,13 @@
|
||||
}
|
||||
|
||||
.gallery-work-shell:hover::before {
|
||||
opacity: 0.62;
|
||||
transform: scale(1.02) rotate(360deg);
|
||||
opacity: 0.98;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
.gallery-work-shell:hover::after {
|
||||
opacity: 0.5;
|
||||
opacity: 0.42;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
.gallery-work-card {
|
||||
@@ -290,34 +317,10 @@
|
||||
.gallery-work-shell:hover .gallery-work-card {
|
||||
border-color: color-mix(in srgb, var(--gallery-accent-1) 48%, white 24%);
|
||||
box-shadow:
|
||||
0 18px 46px rgb(0 0 0 / 0.22),
|
||||
0 16px 34px rgb(0 0 0 / 0.18),
|
||||
inset 0 1px 0 rgb(255 255 255 / 0.12);
|
||||
}
|
||||
|
||||
.gallery-work-image-glow {
|
||||
position: absolute;
|
||||
inset: -18px;
|
||||
z-index: -1;
|
||||
width: calc(100% + 36px);
|
||||
height: calc(100% + 36px);
|
||||
object-fit: cover;
|
||||
border-radius: 1.6rem;
|
||||
opacity: 0;
|
||||
filter: blur(28px) saturate(1.38);
|
||||
transform: scale(0.98);
|
||||
transition:
|
||||
opacity 320ms ease,
|
||||
transform 520ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||
animation: gallery-image-aura 7s ease-in-out infinite;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
.gallery-work-shell:hover .gallery-work-image-glow {
|
||||
opacity: 0.42;
|
||||
transform: scale(1.08);
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
.gallery-work-action-button {
|
||||
border-radius: 9999px !important;
|
||||
border: 1px solid var(--gallery-action-border) !important;
|
||||
@@ -343,22 +346,12 @@
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
@keyframes gallery-glow-flow {
|
||||
@keyframes gallery-border-flow {
|
||||
0% {
|
||||
transform: scale(1.02) rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1.02) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gallery-image-aura {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1.06) translate3d(-1%, 0, 0);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1) translate3d(1%, -1%, 0);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +359,6 @@
|
||||
.gallery-work-shell,
|
||||
.gallery-work-shell::before,
|
||||
.gallery-work-shell::after,
|
||||
.gallery-work-image-glow,
|
||||
.gallery-work-action-button {
|
||||
animation: none !important;
|
||||
transition-duration: 1ms !important;
|
||||
|
||||
Reference in New Issue
Block a user