OhMyDitzzy commited on
Commit
c586cfa
·
1 Parent(s): 56ca819
src/modules/comic/ComicLanding.css CHANGED
@@ -292,12 +292,38 @@
292
  font-size: 1.25rem;
293
  }
294
 
295
- .synopsis p {
296
- margin: 0;
 
 
 
 
297
  line-height: 1.7;
298
  opacity: 0.85;
299
  }
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  .chapters-section {
302
  max-width: 1200px;
303
  margin: 0 auto;
@@ -359,10 +385,39 @@
359
  border-color: #667eea;
360
  }
361
 
 
 
 
 
362
  .chapters-list {
363
  display: flex;
364
  flex-direction: column;
365
  gap: 0.75rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
  }
367
 
368
  .chapter-item {
@@ -375,12 +430,15 @@
375
  border-radius: 12px;
376
  cursor: pointer;
377
  transition: all 0.3s;
 
 
378
  }
379
 
380
  .chapter-item:hover {
381
  background: rgba(255, 255, 255, 0.08);
382
  border-color: #667eea;
383
  transform: translateX(4px);
 
384
  }
385
 
386
  .chapter-info {
@@ -417,6 +475,36 @@
417
  transform: translateX(4px);
418
  }
419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  .no-results {
421
  text-align: center;
422
  padding: 3rem;
@@ -493,4 +581,27 @@
493
  .auth-card {
494
  padding: 2rem;
495
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  }
 
292
  font-size: 1.25rem;
293
  }
294
 
295
+ .synopsis-content {
296
+ position: relative;
297
+ }
298
+
299
+ .synopsis-content p {
300
+ margin: 0 0 0.5rem 0;
301
  line-height: 1.7;
302
  opacity: 0.85;
303
  }
304
 
305
+ .expand-btn {
306
+ background: none;
307
+ border: none;
308
+ color: #667eea;
309
+ font-size: 0.9rem;
310
+ font-weight: 600;
311
+ cursor: pointer;
312
+ padding: 0.5rem 0;
313
+ transition: all 0.2s ease;
314
+ text-decoration: none;
315
+ display: inline-block;
316
+ }
317
+
318
+ .expand-btn:hover {
319
+ color: #5568d3;
320
+ text-decoration: underline;
321
+ }
322
+
323
+ .expand-btn:active {
324
+ color: #4451b8;
325
+ }
326
+
327
  .chapters-section {
328
  max-width: 1200px;
329
  margin: 0 auto;
 
385
  border-color: #667eea;
386
  }
387
 
388
+ .chapters-list-wrapper {
389
+ position: relative;
390
+ }
391
+
392
  .chapters-list {
393
  display: flex;
394
  flex-direction: column;
395
  gap: 0.75rem;
396
+ position: relative;
397
+ }
398
+
399
+ .chapters-list.has-fade {
400
+ position: relative;
401
+ }
402
+
403
+ .chapters-list.has-fade::after {
404
+ content: '';
405
+ position: absolute;
406
+ bottom: 0;
407
+ left: 0;
408
+ right: 0;
409
+ height: 180px;
410
+ background: linear-gradient(
411
+ to bottom,
412
+ transparent 0%,
413
+ rgba(15, 15, 30, 0.3) 20%,
414
+ rgba(15, 15, 30, 0.6) 40%,
415
+ rgba(15, 15, 30, 0.85) 60%,
416
+ rgba(15, 15, 30, 0.95) 80%,
417
+ #0f0f1e 100%
418
+ );
419
+ pointer-events: none;
420
+ z-index: 1;
421
  }
422
 
423
  .chapter-item {
 
430
  border-radius: 12px;
431
  cursor: pointer;
432
  transition: all 0.3s;
433
+ position: relative;
434
+ z-index: 0;
435
  }
436
 
437
  .chapter-item:hover {
438
  background: rgba(255, 255, 255, 0.08);
439
  border-color: #667eea;
440
  transform: translateX(4px);
441
+ z-index: 2;
442
  }
443
 
444
  .chapter-info {
 
475
  transform: translateX(4px);
476
  }
477
 
478
+ .show-more-container {
479
+ display: flex;
480
+ justify-content: center;
481
+ padding: 2rem 0 1rem;
482
+ margin-top: -0.5rem;
483
+ position: relative;
484
+ z-index: 2;
485
+ }
486
+
487
+ .show-more-chapters {
488
+ font-size: 1rem;
489
+ padding: 0.75rem 1.5rem;
490
+ background: rgba(102, 126, 234, 0.15);
491
+ border: 1px solid rgba(102, 126, 234, 0.3);
492
+ border-radius: 10px;
493
+ transition: all 0.3s ease;
494
+ color: #667eea;
495
+ }
496
+
497
+ .show-more-chapters:hover {
498
+ background: rgba(102, 126, 234, 0.25);
499
+ border-color: #667eea;
500
+ transform: translateY(-2px);
501
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
502
+ }
503
+
504
+ .show-more-chapters:active {
505
+ transform: translateY(0);
506
+ }
507
+
508
  .no-results {
509
  text-align: center;
510
  padding: 3rem;
 
581
  .auth-card {
582
  padding: 2rem;
583
  }
584
+
585
+ .chapters-list.has-fade::after {
586
+ height: 150px;
587
+ }
588
+
589
+ .expand-btn {
590
+ font-size: 0.85rem;
591
+ }
592
+
593
+ .show-more-chapters {
594
+ font-size: 0.9rem;
595
+ padding: 0.65rem 1.25rem;
596
+ }
597
+ }
598
+
599
+ @media (prefers-reduced-motion: reduce) {
600
+ *,
601
+ *::before,
602
+ *::after {
603
+ animation-duration: 0.01ms !important;
604
+ animation-iteration-count: 1 !important;
605
+ transition-duration: 0.01ms !important;
606
+ }
607
  }
src/modules/comic/ComicLanding.tsx CHANGED
@@ -34,8 +34,11 @@ export function ComicLanding() {
34
  const [searchQuery, setSearchQuery] = useState('');
35
  const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
36
  const [loadingChapter, setLoadingChapter] = useState(false);
37
-
 
38
  const [ws, setWs] = useState<WebSocket | null>(null);
 
 
39
 
40
  useEffect(() => {
41
  const storedSession = sessionStorage.getItem(`comic_${sessionId}`);
@@ -219,6 +222,16 @@ export function ComicLanding() {
219
  return sortOrder === 'asc' ? numA - numB : numB - numA;
220
  });
221
 
 
 
 
 
 
 
 
 
 
 
222
  if (loading) {
223
  return (
224
  <div className="comic-landing">
@@ -349,7 +362,17 @@ export function ComicLanding() {
349
 
350
  <div className="synopsis">
351
  <h3>Synopsis</h3>
352
- <p>{comicData.synopsis}</p>
 
 
 
 
 
 
 
 
 
 
353
  </div>
354
  </div>
355
  </div>
@@ -378,33 +401,49 @@ export function ComicLanding() {
378
  </div>
379
  </div>
380
 
381
- <div className="chapters-list">
382
- {sortedChapters.length === 0 ? (
383
- <div className="no-results">
384
- <p>No chapters found</p>
385
- </div>
386
- ) : (
387
- sortedChapters.map((chapter, index) => (
388
- <div
389
- key={index}
390
- className="chapter-item"
391
- onClick={() => handleReadChapter(chapter.slug)}
392
- >
393
- <div className="chapter-info">
394
- <div className="chapter-number">{chapter.chapter}</div>
395
- <div className="chapter-meta">
396
- <span className="chapter-date">{chapter.date}</span>
397
- <span className="chapter-views">{chapter.views}</span>
 
 
 
 
 
398
  </div>
399
  </div>
400
- <div className="chapter-action">
401
- <span className="read-btn">Read →</span>
402
- </div>
403
- </div>
404
- ))
 
 
 
 
 
 
 
 
 
 
 
405
  )}
406
  </div>
407
  </div>
408
  </div>
409
  );
410
- }
 
34
  const [searchQuery, setSearchQuery] = useState('');
35
  const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
36
  const [loadingChapter, setLoadingChapter] = useState(false);
37
+ const [isSynopsisExpanded, setIsSynopsisExpanded] = useState(false);
38
+ const [isChaptersExpanded, setIsChaptersExpanded] = useState(false);
39
  const [ws, setWs] = useState<WebSocket | null>(null);
40
+ const SYNOPSIS_CHAR_LIMIT = 200;
41
+ const CHAPTERS_INITIAL_DISPLAY = 20;
42
 
43
  useEffect(() => {
44
  const storedSession = sessionStorage.getItem(`comic_${sessionId}`);
 
222
  return sortOrder === 'asc' ? numA - numB : numB - numA;
223
  });
224
 
225
+ const shouldTruncateSynopsis = comicData && comicData.synopsis.length > SYNOPSIS_CHAR_LIMIT;
226
+ const displayedSynopsis = comicData && shouldTruncateSynopsis && !isSynopsisExpanded
227
+ ? comicData.synopsis.slice(0, SYNOPSIS_CHAR_LIMIT) + '...'
228
+ : comicData?.synopsis;
229
+
230
+ const shouldShowMoreChapters = sortedChapters.length > CHAPTERS_INITIAL_DISPLAY;
231
+ const displayedChapters = isChaptersExpanded || searchQuery
232
+ ? sortedChapters
233
+ : sortedChapters.slice(0, CHAPTERS_INITIAL_DISPLAY);
234
+
235
  if (loading) {
236
  return (
237
  <div className="comic-landing">
 
362
 
363
  <div className="synopsis">
364
  <h3>Synopsis</h3>
365
+ <div className="synopsis-content">
366
+ <p>{displayedSynopsis}</p>
367
+ {shouldTruncateSynopsis && (
368
+ <button
369
+ className="expand-btn"
370
+ onClick={() => setIsSynopsisExpanded(!isSynopsisExpanded)}
371
+ >
372
+ {isSynopsisExpanded ? 'Show Less' : 'Read More'}
373
+ </button>
374
+ )}
375
+ </div>
376
  </div>
377
  </div>
378
  </div>
 
401
  </div>
402
  </div>
403
 
404
+ <div className="chapters-list-wrapper">
405
+ <div className={`chapters-list ${!isChaptersExpanded && shouldShowMoreChapters ? 'has-fade' : ''}`}>
406
+ {displayedChapters.length === 0 ? (
407
+ <div className="no-results">
408
+ <p>No chapters found</p>
409
+ </div>
410
+ ) : (
411
+ displayedChapters.map((chapter, index) => (
412
+ <div
413
+ key={index}
414
+ className="chapter-item"
415
+ onClick={() => handleReadChapter(chapter.slug)}
416
+ >
417
+ <div className="chapter-info">
418
+ <div className="chapter-number">{chapter.chapter}</div>
419
+ <div className="chapter-meta">
420
+ <span className="chapter-date">{chapter.date}</span>
421
+ <span className="chapter-views">{chapter.views}</span>
422
+ </div>
423
+ </div>
424
+ <div className="chapter-action">
425
+ <span className="read-btn">Read →</span>
426
  </div>
427
  </div>
428
+ ))
429
+ )}
430
+ </div>
431
+
432
+ {shouldShowMoreChapters && !searchQuery && (
433
+ <div className="show-more-container">
434
+ <button
435
+ className="expand-btn show-more-chapters"
436
+ onClick={() => setIsChaptersExpanded(!isChaptersExpanded)}
437
+ >
438
+ {isChaptersExpanded
439
+ ? 'Show Less'
440
+ : `Show More (${sortedChapters.length - CHAPTERS_INITIAL_DISPLAY} more chapters)`
441
+ }
442
+ </button>
443
+ </div>
444
  )}
445
  </div>
446
  </div>
447
  </div>
448
  );
449
+ }