@@ -293,6 +293,22 @@ watch(() => backend.pendingBadgeCelebration, (pending) => {
293293 fireConfetti (' gold' , 1.5 );
294294 backend .pendingBadgeCelebration = null ;
295295});
296+
297+ // ── Cell completion celebration ──
298+ const cellCelebration = ref <{ totalCells: number ; imageUrl: string } | null >(null );
299+
300+ watch (() => backend .pendingCellCelebration , (pending ) => {
301+ if (! pending ) return ;
302+ cellCelebration .value = { ... pending };
303+ fireConfetti (' cyan' , 2 );
304+ backend .pendingCellCelebration = null ;
305+ // Auto-dismiss after 6s
306+ setTimeout (() => { cellCelebration .value = null ; }, 6000 );
307+ });
308+
309+ function dismissCellCelebration() {
310+ cellCelebration .value = null ;
311+ }
296312 </script >
297313
298314<template >
@@ -346,6 +362,21 @@ watch(() => backend.pendingBadgeCelebration, (pending) => {
346362 </div >
347363 </Transition >
348364
365+ <!-- Cell completion celebration overlay -->
366+ <Transition name =" nge-cell-celebrate" >
367+ <div v-if =" cellCelebration" class =" nge-cell-overlay" @click =" dismissCellCelebration" >
368+ <div class =" nge-cell-card" >
369+ <img v-if =" cellCelebration.imageUrl" :src =" cellCelebration.imageUrl" class =" nge-cell-nurro" />
370+ <div class =" nge-cell-text" >
371+ <div class =" nge-cell-congrats" >Congratulations, Cell Complete!</div >
372+ <div class =" nge-cell-thanks" >Thank you for helping to map the brain. For science!</div >
373+ <div class =" nge-cell-stats" >+1 cell brings your total to <strong >{{ cellCelebration.totalCells }}</strong ></div >
374+ </div >
375+ <div class =" nge-cell-hint" >Click to dismiss</div >
376+ </div >
377+ </div >
378+ </Transition >
379+
349380 <div class =" nge-toast-container" >
350381 <TransitionGroup name =" nge-toast" >
351382 <div
@@ -938,4 +969,101 @@ watch(() => backend.pendingBadgeCelebration, (pending) => {
938969.nge-toast-move {
939970 transition : transform 0.3s ease ;
940971}
972+
973+ /* ═══ Cell Completion Celebration ═══ */
974+ .nge-cell-overlay {
975+ position : fixed ;
976+ inset : 0 ;
977+ z-index : 100000 ;
978+ display : flex ;
979+ align-items : center ;
980+ justify-content : center ;
981+ background : rgba (0 , 8 , 20 , 0.85 );
982+ backdrop-filter : blur (8px );
983+ cursor : pointer ;
984+ }
985+ .nge-cell-card {
986+ display : flex ;
987+ flex-direction : column ;
988+ align-items : center ;
989+ text-align : center ;
990+ max-width : 500px ;
991+ padding : 40px 50px ;
992+ animation : nge-cell-float 3s ease-in-out infinite alternate ;
993+ }
994+ .nge-cell-nurro {
995+ width : 200px ;
996+ height : 200px ;
997+ object-fit : contain ;
998+ margin-bottom : 24px ;
999+ filter : drop-shadow (0 0 20px rgba (0 , 200 , 255 , 0.3 ));
1000+ animation : nge-cell-bounce 0.6s cubic-bezier (0.34 , 1.56 , 0.64 , 1 ) forwards ;
1001+ }
1002+ .nge-cell-text {
1003+ display : flex ;
1004+ flex-direction : column ;
1005+ gap : 10px ;
1006+ }
1007+ .nge-cell-congrats {
1008+ font-family : ' Orbitron' , ' Rajdhani' , ' Audiowide' , monospace ;
1009+ font-size : 24px ;
1010+ font-weight : 700 ;
1011+ letter-spacing : 0.06em ;
1012+ text-transform : uppercase ;
1013+ background : linear-gradient (135deg , #a0ffd4 0% , #00dca0 40% , #58a6ff 100% );
1014+ -webkit-background-clip : text ;
1015+ -webkit-text-fill-color : transparent ;
1016+ background-clip : text ;
1017+ animation : nge-cell-title-in 0.5s ease-out 0.3s both ;
1018+ }
1019+ .nge-cell-thanks {
1020+ font-size : 15px ;
1021+ color : #99aabb ;
1022+ font-style : italic ;
1023+ line-height : 1.5 ;
1024+ animation : nge-cell-fade-in 0.4s ease-out 0.6s both ;
1025+ }
1026+ .nge-cell-stats {
1027+ font-size : 16px ;
1028+ color : #e0ecff ;
1029+ margin-top : 6px ;
1030+ font-family : ' Orbitron' , monospace ;
1031+ letter-spacing : 0.04em ;
1032+ animation : nge-cell-fade-in 0.4s ease-out 0.9s both ;
1033+ }
1034+ .nge-cell-stats strong {
1035+ font-size : 22px ;
1036+ color : #00dca0 ;
1037+ text-shadow : 0 0 10px rgba (0 , 220 , 160 , 0.4 );
1038+ }
1039+ .nge-cell-hint {
1040+ margin-top : 28px ;
1041+ font-size : 11px ;
1042+ color : #556 ;
1043+ letter-spacing : 0.1em ;
1044+ animation : nge-cell-fade-in 0.4s ease-out 1.2s both ;
1045+ }
1046+
1047+ @keyframes nge-cell-bounce {
1048+ 0% { transform : scale (0.3 ) translateY (40px ); opacity : 0 ; }
1049+ 60% { transform : scale (1.1 ) translateY (-8px ); opacity : 1 ; }
1050+ 100% { transform : scale (1 ) translateY (0 ); opacity : 1 ; }
1051+ }
1052+ @keyframes nge-cell-title-in {
1053+ 0% { opacity : 0 ; transform : translateY (10px ); }
1054+ 100% { opacity : 1 ; transform : translateY (0 ); }
1055+ }
1056+ @keyframes nge-cell-fade-in {
1057+ 0% { opacity : 0 ; }
1058+ 100% { opacity : 1 ; }
1059+ }
1060+ @keyframes nge-cell-float {
1061+ from { transform : translateY (0 ); }
1062+ to { transform : translateY (-6px ); }
1063+ }
1064+
1065+ /* Transition */
1066+ .nge-cell-celebrate-enter-active { transition : opacity 0.4s ease-out ; }
1067+ .nge-cell-celebrate-leave-active { transition : opacity 0.5s ease-in ; }
1068+ .nge-cell-celebrate-enter-from , .nge-cell-celebrate-leave-to { opacity : 0 ; }
9411069 </style >
0 commit comments