Spaces:
Sleeping
Sleeping
Add 'Your Name' easter egg: random movie quotes for themed searches
Browse files- client/src/app/Home.css +65 -0
- client/src/app/page.jsx +14 -0
- server/src/controllers/search.controller.js +19 -0
client/src/app/Home.css
CHANGED
|
@@ -264,6 +264,71 @@
|
|
| 264 |
color: var(--text-secondary);
|
| 265 |
}
|
| 266 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
@media (max-width: 768px) {
|
| 268 |
.home-headline {
|
| 269 |
font-size: 1.75rem;
|
|
|
|
| 264 |
color: var(--text-secondary);
|
| 265 |
}
|
| 266 |
|
| 267 |
+
/* Easter Egg Styling */
|
| 268 |
+
.home-easter-egg {
|
| 269 |
+
max-width: 720px;
|
| 270 |
+
margin: 1.5rem auto;
|
| 271 |
+
padding: 1.5rem;
|
| 272 |
+
background: linear-gradient(135deg, rgba(238, 105, 131, 0.05) 0%, rgba(108, 92, 231, 0.05) 100%);
|
| 273 |
+
border: 1px solid rgba(238, 105, 131, 0.2);
|
| 274 |
+
border-radius: var(--radius-md);
|
| 275 |
+
position: relative;
|
| 276 |
+
overflow: hidden;
|
| 277 |
+
text-align: center;
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
.home-easter-egg::before {
|
| 281 |
+
content: '';
|
| 282 |
+
position: absolute;
|
| 283 |
+
top: 0;
|
| 284 |
+
left: 0;
|
| 285 |
+
right: 0;
|
| 286 |
+
height: 1px;
|
| 287 |
+
background: linear-gradient(90deg, transparent, rgba(238, 105, 131, 0.4), transparent);
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
.easter-egg-content {
|
| 291 |
+
position: relative;
|
| 292 |
+
z-index: 1;
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
.easter-egg-sparkle {
|
| 296 |
+
display: block;
|
| 297 |
+
font-size: 1.25rem;
|
| 298 |
+
margin-bottom: 0.75rem;
|
| 299 |
+
animation: bounce 2s infinite ease-in-out;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
@keyframes bounce {
|
| 303 |
+
|
| 304 |
+
0%,
|
| 305 |
+
100% {
|
| 306 |
+
transform: translateY(0);
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
50% {
|
| 310 |
+
transform: translateY(-5px);
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
.easter-egg-quote {
|
| 315 |
+
font-size: 1.05rem;
|
| 316 |
+
font-style: italic;
|
| 317 |
+
color: var(--text-primary);
|
| 318 |
+
line-height: 1.6;
|
| 319 |
+
margin-bottom: 0.5rem;
|
| 320 |
+
font-family: 'Outfit', serif;
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
.easter-egg-movie {
|
| 324 |
+
font-size: 0.75rem;
|
| 325 |
+
font-weight: 600;
|
| 326 |
+
text-transform: uppercase;
|
| 327 |
+
letter-spacing: 0.15em;
|
| 328 |
+
color: var(--accent-secondary);
|
| 329 |
+
opacity: 0.8;
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
@media (max-width: 768px) {
|
| 333 |
.home-headline {
|
| 334 |
font-size: 1.75rem;
|
client/src/app/page.jsx
CHANGED
|
@@ -28,6 +28,7 @@ function SearchContent() {
|
|
| 28 |
const [selectedResult, setSelectedResult] = useState(null);
|
| 29 |
const [scopeMessage, setScopeMessage] = useState(null);
|
| 30 |
const [clarification, setClarification] = useState(null);
|
|
|
|
| 31 |
|
| 32 |
const { addEntry, history } = useSearchHistory();
|
| 33 |
const { addToast } = useToast();
|
|
@@ -62,6 +63,8 @@ function SearchContent() {
|
|
| 62 |
setLoadingMsg('Searching...');
|
| 63 |
setError(null);
|
| 64 |
setScopeMessage(null);
|
|
|
|
|
|
|
| 65 |
setHasSearched(true);
|
| 66 |
|
| 67 |
const timeoutId = setTimeout(() => {
|
|
@@ -91,6 +94,7 @@ function SearchContent() {
|
|
| 91 |
setResults(res);
|
| 92 |
setIntent(data.intent || null);
|
| 93 |
setMeta(data.meta || null);
|
|
|
|
| 94 |
setDynamicFilters(data.dynamicFilters || []);
|
| 95 |
setFilters({});
|
| 96 |
addEntry(query, data.intent, res.length);
|
|
@@ -272,6 +276,16 @@ function SearchContent() {
|
|
| 272 |
</section>
|
| 273 |
)}
|
| 274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
{!loading && hasSearched && results.length > 0 && (
|
| 276 |
<section className="home-results-layout">
|
| 277 |
<FilterPanel
|
|
|
|
| 28 |
const [selectedResult, setSelectedResult] = useState(null);
|
| 29 |
const [scopeMessage, setScopeMessage] = useState(null);
|
| 30 |
const [clarification, setClarification] = useState(null);
|
| 31 |
+
const [easterEgg, setEasterEgg] = useState(null);
|
| 32 |
|
| 33 |
const { addEntry, history } = useSearchHistory();
|
| 34 |
const { addToast } = useToast();
|
|
|
|
| 63 |
setLoadingMsg('Searching...');
|
| 64 |
setError(null);
|
| 65 |
setScopeMessage(null);
|
| 66 |
+
setClarification(null);
|
| 67 |
+
setEasterEgg(null);
|
| 68 |
setHasSearched(true);
|
| 69 |
|
| 70 |
const timeoutId = setTimeout(() => {
|
|
|
|
| 94 |
setResults(res);
|
| 95 |
setIntent(data.intent || null);
|
| 96 |
setMeta(data.meta || null);
|
| 97 |
+
setEasterEgg(data.easterEgg || null);
|
| 98 |
setDynamicFilters(data.dynamicFilters || []);
|
| 99 |
setFilters({});
|
| 100 |
addEntry(query, data.intent, res.length);
|
|
|
|
| 276 |
</section>
|
| 277 |
)}
|
| 278 |
|
| 279 |
+
{easterEgg && !loading && (
|
| 280 |
+
<div className="home-easter-egg fade-in-up">
|
| 281 |
+
<div className="easter-egg-content">
|
| 282 |
+
<span className="easter-egg-sparkle">✨</span>
|
| 283 |
+
<p className="easter-egg-quote">"{easterEgg}"</p>
|
| 284 |
+
<span className="easter-egg-movie">— Kimi no Na wa (Your Name)</span>
|
| 285 |
+
</div>
|
| 286 |
+
</div>
|
| 287 |
+
)}
|
| 288 |
+
|
| 289 |
{!loading && hasSearched && results.length > 0 && (
|
| 290 |
<section className="home-results-layout">
|
| 291 |
<FilterPanel
|
server/src/controllers/search.controller.js
CHANGED
|
@@ -132,11 +132,30 @@ async function handleSearch(req, res, next) {
|
|
| 132 |
]);
|
| 133 |
logger.info('AI ranking complete', { topCount: rankedResults.length });
|
| 134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
success(res, {
|
| 136 |
query,
|
| 137 |
intent,
|
| 138 |
results: rankedResults,
|
| 139 |
dynamicFilters,
|
|
|
|
| 140 |
meta: {
|
| 141 |
...data.meta,
|
| 142 |
total: rankedResults.length,
|
|
|
|
| 132 |
]);
|
| 133 |
logger.info('AI ranking complete', { topCount: rankedResults.length });
|
| 134 |
|
| 135 |
+
// --- Easter Egg: Your Name (Kimi no Na wa) ---
|
| 136 |
+
const quotes = [
|
| 137 |
+
"Musubi is the old way of calling the guardian god. To tie thread is Musubi. To connect people is Musubi. The flow of time is Musubi.",
|
| 138 |
+
"I’m always searching for something, a person, a place... I don't know what it is or where it is, but I know it's important to me...",
|
| 139 |
+
"Treasure the experience. Dreams fade away after you wake up.",
|
| 140 |
+
"Wherever you are in the world, I'll search for you.",
|
| 141 |
+
"It's like a dream. It's like a miracle.",
|
| 142 |
+
"The names are... Mitsuha! Taki!",
|
| 143 |
+
"Once in a while when I wake up. I find myself crying."
|
| 144 |
+
];
|
| 145 |
+
|
| 146 |
+
const isEasterEgg = query.toLowerCase().includes('your name') ||
|
| 147 |
+
query.toLowerCase().includes('kimi no na wa') ||
|
| 148 |
+
(intent.reasoning && intent.reasoning.toLowerCase().includes('kimi no na wa')) ||
|
| 149 |
+
(intent.reasoning && intent.reasoning.toLowerCase().includes('your name'));
|
| 150 |
+
|
| 151 |
+
const easterEgg = isEasterEgg ? quotes[Math.floor(Math.random() * quotes.length)] : null;
|
| 152 |
+
|
| 153 |
success(res, {
|
| 154 |
query,
|
| 155 |
intent,
|
| 156 |
results: rankedResults,
|
| 157 |
dynamicFilters,
|
| 158 |
+
easterEgg,
|
| 159 |
meta: {
|
| 160 |
...data.meta,
|
| 161 |
total: rankedResults.length,
|