Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions frontend/static/css/common/dino-loader.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* 귀여운 아기 공룡 로딩 애니메이션 (개별 4장 즉시 교체)
*
* 프레임 이미지 (dino_frame_01.png 제외, 가로 정렬 순서대로 4장):
* frontend/static/img/dino_frame_02.png ~ dino_frame_05.png (각 248 x 263, 투명 배경)
*
* 4장을 겹쳐 두고 매 순간 한 장만 즉시 켜고 끕니다(opacity 0/1 즉시 전환).
* 따라서 프레임이 바뀔 때 흐릿한 페이드가 전혀 없습니다.
*
* div 로 그렸던 이전(CSS) 버전은 dino-loader.v1-backup.css 에 백업되어 있습니다.
*/
.dino-loader {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1.25rem;
padding: 3.5rem 1rem;
user-select: none;
}

/* 5장을 같은 자리에 겹쳐 둠 */
.dino-sprite {
position: relative;
width: 150px;
height: 128px;
}
.dino-frame {
position: absolute;
inset: 0;
background-repeat: no-repeat;
background-position: center bottom;
background-size: auto 122px;
image-rendering: auto;
opacity: 0; /* 기본은 숨김, 자기 차례에만 켜짐 */
/* 0.4초에 4장 = 프레임당 0.1초. steps 가 아닌 즉시 on/off 키프레임 사용 */
animation: dino-flip 0.4s linear infinite;
}
.dino-frame.f2 { background-image: url('/static/img/dino_frame_02.png'); animation-delay: 0s; }
.dino-frame.f3 { background-image: url('/static/img/dino_frame_03.png'); animation-delay: 0.1s; }
.dino-frame.f4 { background-image: url('/static/img/dino_frame_04.png'); animation-delay: 0.2s; }
.dino-frame.f5 { background-image: url('/static/img/dino_frame_05.png'); animation-delay: 0.3s; }

/* 로딩 텍스트 */
.dino-loading-text {
font-size: 0.95rem;
font-weight: 600;
color: #566168;
letter-spacing: 0.01em;
}
.dino-loading-text .dot {
animation: dino-dot 1.4s infinite;
}
.dino-loading-text .dot:nth-child(2) { animation-delay: 0.2s; }
.dino-loading-text .dot:nth-child(3) { animation-delay: 0.4s; }

/* 각 프레임: 자기 차례(전체의 1/4 = 0~25%)에만 불투명, 나머지는 즉시 투명.
* 24.999%->25% 사이에서 opacity 1->0 으로 사실상 즉시 꺼져 페이드가 없습니다. */
@keyframes dino-flip {
0%, 24.999% { opacity: 1; }
25%, 100% { opacity: 0; }
}

@keyframes dino-dot {
0%, 60%, 100% { opacity: 0.2; }
30% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
.dino-frame { animation: none; }
.dino-frame.f2 { opacity: 1; } /* 정지 시 첫 프레임만 표시 */
}
199 changes: 199 additions & 0 deletions frontend/static/css/common/dino-loader.v1-backup.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/* 귀여운 공룡 로딩 애니메이션 */
.dino-loader {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1.25rem;
padding: 3.5rem 1rem;
user-select: none;
}

.dino-scene {
position: relative;
width: 220px;
height: 130px;
}

/* 땅 (스크롤되는 줄무늬) */
.dino-ground {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 8px;
border-radius: 999px;
background: repeating-linear-gradient(
90deg,
#c7d1ee 0,
#c7d1ee 14px,
transparent 14px,
transparent 28px
);
background-size: 28px 100%;
animation: dino-ground-scroll 0.5s linear infinite;
}

/* 달려가는 공룡 (위아래로 깡총) */
.dino {
position: absolute;
left: 50%;
bottom: 8px;
width: 78px;
height: 84px;
transform: translateX(-50%);
transform-origin: bottom center;
animation: dino-hop 0.5s ease-in-out infinite;
}

/* 몸통 */
.dino-body {
position: absolute;
left: 8px;
bottom: 14px;
width: 50px;
height: 44px;
background: #6cc24a;
border-radius: 18px 22px 16px 14px;
box-shadow: inset -4px -4px 0 rgba(0, 0, 0, 0.08);
}

/* 머리 */
.dino-head {
position: absolute;
right: 2px;
top: 0;
width: 40px;
height: 36px;
background: #6cc24a;
border-radius: 16px 18px 6px 16px;
box-shadow: inset -4px -3px 0 rgba(0, 0, 0, 0.08);
}

/* 주둥이 */
.dino-snout {
position: absolute;
right: -8px;
top: 14px;
width: 16px;
height: 16px;
background: #5cb13e;
border-radius: 6px 8px 8px 4px;
}

/* 눈 */
.dino-eye {
position: absolute;
right: 8px;
top: 9px;
width: 11px;
height: 11px;
background: #ffffff;
border-radius: 50%;
}
.dino-eye::after {
content: "";
position: absolute;
right: 1px;
top: 2px;
width: 5px;
height: 5px;
background: #1f2937;
border-radius: 50%;
animation: dino-blink 2.4s ease-in-out infinite;
}

/* 등 가시 */
.dino-spike {
position: absolute;
top: -6px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 9px solid #4f9e34;
}
.dino-spike.s1 { left: 12px; }
.dino-spike.s2 { left: 24px; }
.dino-spike.s3 { left: 36px; }

/* 꼬리 */
.dino-tail {
position: absolute;
left: -10px;
bottom: 22px;
width: 0;
height: 0;
border-top: 12px solid transparent;
border-bottom: 12px solid transparent;
border-right: 18px solid #6cc24a;
}

/* 다리 (번갈아 달리기) */
.dino-leg {
position: absolute;
bottom: 0;
width: 12px;
height: 18px;
background: #4f9e34;
border-radius: 0 0 5px 5px;
}
.dino-leg.front {
left: 30px;
animation: dino-run-front 0.5s ease-in-out infinite;
}
.dino-leg.back {
left: 14px;
animation: dino-run-back 0.5s ease-in-out infinite;
}

/* 로딩 텍스트 */
.dino-loading-text {
font-size: 0.95rem;
font-weight: 600;
color: #566168;
letter-spacing: 0.01em;
}
.dino-loading-text .dot {
animation: dino-dot 1.4s infinite;
}
.dino-loading-text .dot:nth-child(2) { animation-delay: 0.2s; }
.dino-loading-text .dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes dino-hop {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-12px); }
}

@keyframes dino-ground-scroll {
from { background-position: 0 0; }
to { background-position: -28px 0; }
}

@keyframes dino-run-front {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-6px) rotate(-18deg); }
}

@keyframes dino-run-back {
0%, 100% { transform: translateY(-6px) rotate(18deg); }
50% { transform: translateY(0) rotate(0deg); }
}

@keyframes dino-blink {
0%, 92%, 100% { transform: scaleY(1); }
96% { transform: scaleY(0.1); }
}

@keyframes dino-dot {
0%, 60%, 100% { opacity: 0.2; }
30% { opacity: 1; }
}

/* 깡총 멈추고 싶을 때를 위한 접근성 배려 */
@media (prefers-reduced-motion: reduce) {
.dino,
.dino-ground,
.dino-leg,
.dino-eye::after { animation: none; }
}
Binary file added frontend/static/img/dino_frame_02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/static/img/dino_frame_03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/static/img/dino_frame_04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/static/img/dino_frame_05.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions frontend/static/js/search/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ document.addEventListener('DOMContentLoaded', async () => {
renderCurrentPage();
} catch (error) {
console.error('Fetch error:', error);
results = [];
renderCurrentPage();
alert('검색 결과를 불러오지 못했습니다.');
}

Expand Down
16 changes: 13 additions & 3 deletions frontend/templates/search/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
.no-scrollbar::-webkit-scrollbar { display: none; }
</style>
<link rel="stylesheet" href="/static/css/common/nav.css">
<link rel="stylesheet" href="/static/css/common/dino-loader.css">
</head>
<body class="bg-surface text-on-surface antialiased">
<!-- TopNavBar -->
Expand Down Expand Up @@ -187,9 +188,18 @@ <h1 class="text-3xl font-extrabold tracking-tight text-on-surface">
<!-- Results Grid -->
<section id="results-container" class="relative z-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<!-- list.js에 의해 동적으로 카드가 생성될 자리입니다 -->
<div class="col-span-full flex flex-col items-center justify-center py-20 text-slate-400">
<span class="material-symbols-outlined text-5xl mb-4 animate-pulse">sync</span>
<p>검색 결과를 불러오는 중입니다...</p>
<div class="col-span-full">
<div class="dino-loader">
<div class="dino-sprite">
<span class="dino-frame f2"></span>
<span class="dino-frame f3"></span>
<span class="dino-frame f4"></span>
<span class="dino-frame f5"></span>
</div>
<p class="dino-loading-text">
웹스토어에서 열심히 찾아오는 중<span class="dot">.</span><span class="dot">.</span><span class="dot">.</span>
</p>
</div>
</div>
</section>
<div id="search-pagination-controls" class="relative z-10 flex justify-center items-center gap-2 pt-2"></div>
Expand Down
Loading