seawolf2357 commited on
Commit
ac61d23
Β·
verified Β·
1 Parent(s): fb08ce6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +203 -49
app.py CHANGED
@@ -172,6 +172,21 @@ if __name__ == '__main__':
172
  margin-bottom: 1rem;
173
  }
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  .user-controls {
176
  display: flex;
177
  justify-content: space-between;
@@ -237,19 +252,43 @@ if __name__ == '__main__':
237
  }
238
 
239
  .card {
240
- border: 1px solid #ccc;
241
- border-radius: 5px;
242
  padding: 1rem;
243
  width: 300px;
244
- box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
245
  position: relative;
246
- background-color: #f9f9f9;
 
 
 
 
 
 
 
 
 
 
 
247
  }
248
 
249
  .card a {
250
  text-decoration: none;
251
- color: #333;
252
  word-break: break-all;
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
254
 
255
  .like-button {
@@ -258,18 +297,40 @@ if __name__ == '__main__':
258
  right: 1rem;
259
  border: none;
260
  background: transparent;
261
- font-size: 1.5rem;
262
  cursor: pointer;
263
- transition: color 0.2s;
 
 
 
 
 
264
  }
265
 
266
  .like-button.liked {
267
- color: red;
 
268
  }
269
 
270
  .like-button.not-liked {
 
 
 
 
 
 
 
 
271
  color: white;
272
- -webkit-text-stroke: 1px #333;
 
 
 
 
 
 
 
 
273
  }
274
 
275
  .status-message {
@@ -312,6 +373,23 @@ if __name__ == '__main__':
312
  margin-top: 1rem;
313
  }
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  @media (max-width: 768px) {
316
  .user-controls {
317
  flex-direction: column;
@@ -325,6 +403,12 @@ if __name__ == '__main__':
325
  .card {
326
  width: 100%;
327
  }
 
 
 
 
 
 
328
  }
329
  </style>
330
  </head>
@@ -351,12 +435,19 @@ if __name__ == '__main__':
351
  </div>
352
  </div>
353
 
 
 
 
 
 
 
 
 
 
 
 
354
  <div class="filter-controls">
355
  <label>
356
- <input type="checkbox" id="showOnlyLiked" />
357
- λ‚΄κ°€ μ’‹μ•„μš”ν•œ URL만 보기
358
- </label>
359
- <label style="margin-left: 1rem;">
360
  <input type="text" id="searchInput" placeholder="URL λ˜λŠ” 제λͺ©μœΌλ‘œ 검색" style="width: 250px;" />
361
  </label>
362
  </div>
@@ -378,17 +469,23 @@ if __name__ == '__main__':
378
  cardsContainer: document.getElementById('cardsContainer'),
379
  loadingIndicator: document.getElementById('loadingIndicator'),
380
  statusMessage: document.getElementById('statusMessage'),
381
- showOnlyLiked: document.getElementById('showOnlyLiked'),
382
  searchInput: document.getElementById('searchInput'),
383
  loginSection: document.getElementById('loginSection'),
384
- loggedInSection: document.getElementById('loggedInSection')
 
 
 
 
 
385
  };
386
 
387
  // μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒνƒœ
388
  const state = {
389
  username: null,
390
  likedURLs: {},
391
- isLoading: false
 
 
392
  };
393
 
394
  // 둜컬 μŠ€ν† λ¦¬μ§€ ν‚€
@@ -413,6 +510,15 @@ if __name__ == '__main__':
413
  localStorage.setItem(key, JSON.stringify(state.likedURLs));
414
  }
415
 
 
 
 
 
 
 
 
 
 
416
  // λ‘œλ”© μƒνƒœ ν‘œμ‹œ ν•¨μˆ˜
417
  function setLoading(isLoading) {
418
  state.isLoading = isLoading;
@@ -451,6 +557,7 @@ if __name__ == '__main__':
451
  elements.currentUser.textContent = data.username;
452
  elements.loginSection.style.display = 'none';
453
  elements.loggedInSection.style.display = 'block';
 
454
 
455
  // 둜컬 μŠ€ν† λ¦¬μ§€μ—μ„œ μ’‹μ•„μš” 정보 λ‘œλ“œ
456
  state.likedURLs = loadLikesFromStorage();
@@ -492,6 +599,7 @@ if __name__ == '__main__':
492
  elements.currentUser.textContent = state.username;
493
  elements.loginSection.style.display = 'none';
494
  elements.loggedInSection.style.display = 'block';
 
495
 
496
  showMessage(`${state.username}λ‹˜μœΌλ‘œ λ‘œκ·ΈμΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€.`);
497
 
@@ -522,11 +630,13 @@ if __name__ == '__main__':
522
  if (data.success) {
523
  state.username = null;
524
  state.likedURLs = {};
 
525
 
526
  elements.currentUser.textContent = 'λ‘œκ·ΈμΈλ˜μ§€ μ•ŠμŒ';
527
  elements.tokenInput.value = '';
528
  elements.loginSection.style.display = 'block';
529
  elements.loggedInSection.style.display = 'none';
 
530
 
531
  showMessage('λ‘œκ·Έμ•„μ›ƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.');
532
 
@@ -549,27 +659,13 @@ if __name__ == '__main__':
549
  const response = await fetch('/api/urls');
550
  const urls = await handleApiResponse(response);
551
 
552
- // 필터링 적용
553
- const showOnlyLiked = elements.showOnlyLiked.checked;
554
- const searchText = elements.searchInput.value.toLowerCase();
555
 
556
- const filteredUrls = urls.filter(item => {
557
- const { url, title } = item;
558
-
559
- // μ’‹μ•„μš” 필터링
560
- if (showOnlyLiked && !state.likedURLs[url]) {
561
- return false;
562
- }
563
-
564
- // 검색 필터링
565
- if (searchText && !url.toLowerCase().includes(searchText) && !title.toLowerCase().includes(searchText)) {
566
- return false;
567
- }
568
-
569
- return true;
570
- });
571
 
572
- renderCards(filteredUrls);
 
573
  } catch (error) {
574
  console.error('URL λͺ©λ‘ λ‘œλ“œ 였λ₯˜:', error);
575
  showMessage(`URL λ‘œλ“œ 였λ₯˜: ${error.message}`, true);
@@ -578,8 +674,32 @@ if __name__ == '__main__':
578
  }
579
  }
580
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  // μ’‹μ•„μš” ν† κΈ€
582
- function toggleLike(url, button) {
583
  if (!state.username) {
584
  showMessage('μ’‹μ•„μš”λ₯Ό ν•˜λ €λ©΄ ν—ˆκΉ…νŽ˜μ΄μŠ€ API ν† ν°μœΌλ‘œ 인증이 ν•„μš”ν•©λ‹ˆλ‹€.', true);
585
  return;
@@ -594,22 +714,33 @@ if __name__ == '__main__':
594
  // μƒνƒœ ν† κΈ€
595
  if (isCurrentlyLiked) {
596
  delete state.likedURLs[url];
597
- button.classList.remove('liked');
598
- button.classList.add('not-liked');
 
 
 
 
599
  showMessage('μ’‹μ•„μš”λ₯Ό μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€.');
600
  } else {
601
  state.likedURLs[url] = true;
602
- button.classList.add('liked');
603
- button.classList.remove('not-liked');
 
 
 
 
604
  showMessage('μ’‹μ•„μš”λ₯Ό μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.');
605
  }
606
 
607
  // 둜컬 μŠ€ν† λ¦¬μ§€μ— μ €μž₯
608
  saveLikesToStorage();
609
 
610
- // ν•„ν„°λ§λœ 경우 λͺ©λ‘ λ‹€μ‹œ λ‘œλ“œ
611
- if (elements.showOnlyLiked.checked) {
612
- loadUrls();
 
 
 
613
  }
614
  } catch (error) {
615
  console.error('μ’‹μ•„μš” ν† κΈ€ 였λ₯˜:', error);
@@ -638,10 +769,17 @@ if __name__ == '__main__':
638
 
639
  // μΉ΄λ“œ 생성
640
  const card = document.createElement('div');
641
- card.className = 'card';
 
 
 
 
 
 
642
 
643
  // 제λͺ©
644
  const titleEl = document.createElement('h3');
 
645
  titleEl.textContent = title;
646
  card.appendChild(titleEl);
647
 
@@ -656,10 +794,11 @@ if __name__ == '__main__':
656
  const likeBtn = document.createElement('button');
657
  likeBtn.className = `like-button ${isLiked ? 'liked' : 'not-liked'}`;
658
  likeBtn.textContent = 'β™₯';
 
659
 
660
  likeBtn.addEventListener('click', function(e) {
661
  e.preventDefault();
662
- toggleLike(url, likeBtn);
663
  });
664
  card.appendChild(likeBtn);
665
 
@@ -668,6 +807,18 @@ if __name__ == '__main__':
668
  });
669
  }
670
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  // 이벀트 λ¦¬μŠ€λ„ˆ μ„€μ •
672
  elements.loginButton.addEventListener('click', () => {
673
  login(elements.tokenInput.value);
@@ -682,14 +833,17 @@ if __name__ == '__main__':
682
  }
683
  });
684
 
685
- // 필터링 이벀트 λ¦¬μŠ€λ„ˆ
686
- elements.showOnlyLiked.addEventListener('change', loadUrls);
687
  elements.searchInput.addEventListener('input', () => {
688
- // μž…λ ₯ μ§€μ—° 처리 (타이핑할 λ•Œλ§ˆλ‹€ API 호좜 λ°©μ§€)
689
  clearTimeout(state.searchTimeout);
690
- state.searchTimeout = setTimeout(loadUrls, 300);
691
  });
692
 
 
 
 
 
693
  // μ΄ˆκΈ°ν™”
694
  checkSessionStatus();
695
  </script>
 
172
  margin-bottom: 1rem;
173
  }
174
 
175
+ .stats-bar {
176
+ background-color: #e9f7ef;
177
+ padding: 1rem;
178
+ border-radius: 5px;
179
+ margin-bottom: 1rem;
180
+ display: flex;
181
+ justify-content: space-between;
182
+ align-items: center;
183
+ }
184
+
185
+ .stats-bar .liked-count {
186
+ font-weight: bold;
187
+ color: #e74c3c;
188
+ }
189
+
190
  .user-controls {
191
  display: flex;
192
  justify-content: space-between;
 
252
  }
253
 
254
  .card {
255
+ border: 1px solid #ddd;
256
+ border-radius: 8px;
257
  padding: 1rem;
258
  width: 300px;
259
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
260
  position: relative;
261
+ background-color: #fff;
262
+ transition: all 0.3s ease;
263
+ }
264
+
265
+ .card:hover {
266
+ transform: translateY(-5px);
267
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
268
+ }
269
+
270
+ .card.liked {
271
+ border-color: #e74c3c;
272
+ background-color: #fff9f9;
273
  }
274
 
275
  .card a {
276
  text-decoration: none;
277
+ color: #2980b9;
278
  word-break: break-all;
279
+ display: block;
280
+ margin-top: 0.5rem;
281
+ }
282
+
283
+ .card a:hover {
284
+ text-decoration: underline;
285
+ }
286
+
287
+ .card-title {
288
+ margin-top: 0;
289
+ color: #333;
290
+ font-size: 1.2rem;
291
+ padding-right: 30px; /* μ’‹μ•„μš” λ²„νŠΌ 곡간 확보 */
292
  }
293
 
294
  .like-button {
 
297
  right: 1rem;
298
  border: none;
299
  background: transparent;
300
+ font-size: 1.8rem;
301
  cursor: pointer;
302
+ transition: all 0.2s;
303
+ z-index: 2;
304
+ }
305
+
306
+ .like-button:hover {
307
+ transform: scale(1.2);
308
  }
309
 
310
  .like-button.liked {
311
+ color: #e74c3c;
312
+ text-shadow: 0 0 5px rgba(231, 76, 60, 0.3);
313
  }
314
 
315
  .like-button.not-liked {
316
+ color: #ccc;
317
+ }
318
+
319
+ .like-label {
320
+ position: absolute;
321
+ top: 10px;
322
+ left: 10px;
323
+ background-color: #e74c3c;
324
  color: white;
325
+ padding: 2px 8px;
326
+ border-radius: 10px;
327
+ font-size: 0.7rem;
328
+ font-weight: bold;
329
+ display: none;
330
+ }
331
+
332
+ .card.liked .like-label {
333
+ display: block;
334
  }
335
 
336
  .status-message {
 
373
  margin-top: 1rem;
374
  }
375
 
376
+ .view-toggle {
377
+ margin-bottom: 1rem;
378
+ display: flex;
379
+ gap: 0.5rem;
380
+ }
381
+
382
+ .view-toggle button {
383
+ background-color: #f8f9fa;
384
+ color: #333;
385
+ border: 1px solid #ddd;
386
+ }
387
+
388
+ .view-toggle button.active {
389
+ background-color: #4CAF50;
390
+ color: white;
391
+ }
392
+
393
  @media (max-width: 768px) {
394
  .user-controls {
395
  flex-direction: column;
 
403
  .card {
404
  width: 100%;
405
  }
406
+
407
+ .stats-bar {
408
+ flex-direction: column;
409
+ gap: 0.5rem;
410
+ align-items: flex-start;
411
+ }
412
  }
413
  </style>
414
  </head>
 
435
  </div>
436
  </div>
437
 
438
+ <!-- μ’‹μ•„μš” 톡계 및 ν‘œμ‹œ ν† κΈ€ -->
439
+ <div id="statsBar" class="stats-bar" style="display: none;">
440
+ <div>
441
+ 총 <span id="totalCount">0</span>개 쀑 <span id="likedCount" class="liked-count">0</span>개 μ’‹μ•„μš” 함
442
+ </div>
443
+ <div class="view-toggle">
444
+ <button id="allViewBtn" class="active">전체 보기</button>
445
+ <button id="likedViewBtn">μ’‹μ•„μš”λ§Œ 보기</button>
446
+ </div>
447
+ </div>
448
+
449
  <div class="filter-controls">
450
  <label>
 
 
 
 
451
  <input type="text" id="searchInput" placeholder="URL λ˜λŠ” 제λͺ©μœΌλ‘œ 검색" style="width: 250px;" />
452
  </label>
453
  </div>
 
469
  cardsContainer: document.getElementById('cardsContainer'),
470
  loadingIndicator: document.getElementById('loadingIndicator'),
471
  statusMessage: document.getElementById('statusMessage'),
 
472
  searchInput: document.getElementById('searchInput'),
473
  loginSection: document.getElementById('loginSection'),
474
+ loggedInSection: document.getElementById('loggedInSection'),
475
+ statsBar: document.getElementById('statsBar'),
476
+ totalCount: document.getElementById('totalCount'),
477
+ likedCount: document.getElementById('likedCount'),
478
+ allViewBtn: document.getElementById('allViewBtn'),
479
+ likedViewBtn: document.getElementById('likedViewBtn')
480
  };
481
 
482
  // μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒνƒœ
483
  const state = {
484
  username: null,
485
  likedURLs: {},
486
+ allURLs: [],
487
+ isLoading: false,
488
+ viewMode: 'all' // 'all' λ˜λŠ” 'liked'
489
  };
490
 
491
  // 둜컬 μŠ€ν† λ¦¬μ§€ ν‚€
 
510
  localStorage.setItem(key, JSON.stringify(state.likedURLs));
511
  }
512
 
513
+ // μ’‹μ•„μš” 톡계 μ—…λ°μ΄νŠΈ
514
+ function updateLikeStats() {
515
+ const totalCount = state.allURLs.length;
516
+ const likedCount = Object.keys(state.likedURLs).length;
517
+
518
+ elements.totalCount.textContent = totalCount;
519
+ elements.likedCount.textContent = likedCount;
520
+ }
521
+
522
  // λ‘œλ”© μƒνƒœ ν‘œμ‹œ ν•¨μˆ˜
523
  function setLoading(isLoading) {
524
  state.isLoading = isLoading;
 
557
  elements.currentUser.textContent = data.username;
558
  elements.loginSection.style.display = 'none';
559
  elements.loggedInSection.style.display = 'block';
560
+ elements.statsBar.style.display = 'flex';
561
 
562
  // 둜컬 μŠ€ν† λ¦¬μ§€μ—μ„œ μ’‹μ•„μš” 정보 λ‘œλ“œ
563
  state.likedURLs = loadLikesFromStorage();
 
599
  elements.currentUser.textContent = state.username;
600
  elements.loginSection.style.display = 'none';
601
  elements.loggedInSection.style.display = 'block';
602
+ elements.statsBar.style.display = 'flex';
603
 
604
  showMessage(`${state.username}λ‹˜μœΌλ‘œ λ‘œκ·ΈμΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€.`);
605
 
 
630
  if (data.success) {
631
  state.username = null;
632
  state.likedURLs = {};
633
+ state.allURLs = [];
634
 
635
  elements.currentUser.textContent = 'λ‘œκ·ΈμΈλ˜μ§€ μ•ŠμŒ';
636
  elements.tokenInput.value = '';
637
  elements.loginSection.style.display = 'block';
638
  elements.loggedInSection.style.display = 'none';
639
+ elements.statsBar.style.display = 'none';
640
 
641
  showMessage('λ‘œκ·Έμ•„μ›ƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.');
642
 
 
659
  const response = await fetch('/api/urls');
660
  const urls = await handleApiResponse(response);
661
 
662
+ state.allURLs = urls;
 
 
663
 
664
+ // 필터링 및 λ Œλ”λ§
665
+ filterAndRenderCards();
 
 
 
 
 
 
 
 
 
 
 
 
 
666
 
667
+ // μ’‹μ•„μš” 톡계 μ—…λ°μ΄νŠΈ
668
+ updateLikeStats();
669
  } catch (error) {
670
  console.error('URL λͺ©λ‘ λ‘œλ“œ 였λ₯˜:', error);
671
  showMessage(`URL λ‘œλ“œ 였λ₯˜: ${error.message}`, true);
 
674
  }
675
  }
676
 
677
+ // 필터링 및 μΉ΄λ“œ λ Œλ”λ§
678
+ function filterAndRenderCards() {
679
+ const searchText = elements.searchInput.value.toLowerCase();
680
+
681
+ // 필터링 적용
682
+ const filteredUrls = state.allURLs.filter(item => {
683
+ const { url, title } = item;
684
+
685
+ // μ’‹μ•„μš” 필터링 (μ’‹μ•„μš”λ§Œ 보기 λͺ¨λ“œ)
686
+ if (state.viewMode === 'liked' && !state.likedURLs[url]) {
687
+ return false;
688
+ }
689
+
690
+ // 검색 필터링
691
+ if (searchText && !url.toLowerCase().includes(searchText) && !title.toLowerCase().includes(searchText)) {
692
+ return false;
693
+ }
694
+
695
+ return true;
696
+ });
697
+
698
+ renderCards(filteredUrls);
699
+ }
700
+
701
  // μ’‹μ•„μš” ν† κΈ€
702
+ function toggleLike(url, card) {
703
  if (!state.username) {
704
  showMessage('μ’‹μ•„μš”λ₯Ό ν•˜λ €λ©΄ ν—ˆκΉ…νŽ˜μ΄μŠ€ API ν† ν°μœΌλ‘œ 인증이 ν•„μš”ν•©λ‹ˆλ‹€.', true);
705
  return;
 
714
  // μƒνƒœ ν† κΈ€
715
  if (isCurrentlyLiked) {
716
  delete state.likedURLs[url];
717
+ card.classList.remove('liked');
718
+ const likeBtn = card.querySelector('.like-button');
719
+ if (likeBtn) {
720
+ likeBtn.classList.remove('liked');
721
+ likeBtn.classList.add('not-liked');
722
+ }
723
  showMessage('μ’‹μ•„μš”λ₯Ό μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€.');
724
  } else {
725
  state.likedURLs[url] = true;
726
+ card.classList.add('liked');
727
+ const likeBtn = card.querySelector('.like-button');
728
+ if (likeBtn) {
729
+ likeBtn.classList.add('liked');
730
+ likeBtn.classList.remove('not-liked');
731
+ }
732
  showMessage('μ’‹μ•„μš”λ₯Ό μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.');
733
  }
734
 
735
  // 둜컬 μŠ€ν† λ¦¬μ§€μ— μ €μž₯
736
  saveLikesToStorage();
737
 
738
+ // μ’‹μ•„μš” 톡계 μ—…λ°μ΄νŠΈ
739
+ updateLikeStats();
740
+
741
+ // μ’‹μ•„μš”λ§Œ 보기 λͺ¨λ“œμΈ 경우 λͺ©λ‘ λ‹€μ‹œ λ Œλ”λ§
742
+ if (state.viewMode === 'liked') {
743
+ filterAndRenderCards();
744
  }
745
  } catch (error) {
746
  console.error('μ’‹μ•„μš” ν† κΈ€ 였λ₯˜:', error);
 
769
 
770
  // μΉ΄λ“œ 생성
771
  const card = document.createElement('div');
772
+ card.className = `card ${isLiked ? 'liked' : ''}`;
773
+
774
+ // μ’‹μ•„μš” 라벨
775
+ const likeLabel = document.createElement('span');
776
+ likeLabel.className = 'like-label';
777
+ likeLabel.textContent = 'μ’‹μ•„μš”';
778
+ card.appendChild(likeLabel);
779
 
780
  // 제λͺ©
781
  const titleEl = document.createElement('h3');
782
+ titleEl.className = 'card-title';
783
  titleEl.textContent = title;
784
  card.appendChild(titleEl);
785
 
 
794
  const likeBtn = document.createElement('button');
795
  likeBtn.className = `like-button ${isLiked ? 'liked' : 'not-liked'}`;
796
  likeBtn.textContent = 'β™₯';
797
+ likeBtn.title = isLiked ? 'μ’‹μ•„μš” μ·¨μ†Œ' : 'μ’‹μ•„μš”';
798
 
799
  likeBtn.addEventListener('click', function(e) {
800
  e.preventDefault();
801
+ toggleLike(url, card);
802
  });
803
  card.appendChild(likeBtn);
804
 
 
807
  });
808
  }
809
 
810
+ // λͺ¨λ“œ λ³€κ²½ ν•¨μˆ˜
811
+ function changeViewMode(mode) {
812
+ state.viewMode = mode;
813
+
814
+ // λ²„νŠΌ μƒνƒœ μ—…λ°μ΄νŠΈ
815
+ elements.allViewBtn.classList.toggle('active', mode === 'all');
816
+ elements.likedViewBtn.classList.toggle('active', mode === 'liked');
817
+
818
+ // μΉ΄λ“œ λ‹€μ‹œ λ Œλ”λ§
819
+ filterAndRenderCards();
820
+ }
821
+
822
  // 이벀트 λ¦¬μŠ€λ„ˆ μ„€μ •
823
  elements.loginButton.addEventListener('click', () => {
824
  login(elements.tokenInput.value);
 
833
  }
834
  });
835
 
836
+ // 검색 이벀트 λ¦¬μŠ€λ„ˆ
 
837
  elements.searchInput.addEventListener('input', () => {
838
+ // μž…λ ₯ μ§€μ—° 처리 (타이핑할 λ•Œλ§ˆλ‹€ 필터링 λ°©μ§€)
839
  clearTimeout(state.searchTimeout);
840
+ state.searchTimeout = setTimeout(filterAndRenderCards, 300);
841
  });
842
 
843
+ // 보기 λͺ¨λ“œ μ „ν™˜ λ²„νŠΌ
844
+ elements.allViewBtn.addEventListener('click', () => changeViewMode('all'));
845
+ elements.likedViewBtn.addEventListener('click', () => changeViewMode('liked'));
846
+
847
  // μ΄ˆκΈ°ν™”
848
  checkSessionStatus();
849
  </script>