AdityaAdaki commited on
Commit
7bda8d1
·
1 Parent(s): e1cef6b

css update mobile

Browse files
Files changed (4) hide show
  1. app.py +4 -1
  2. static/css/style.css +101 -0
  3. static/js/main.js +91 -31
  4. templates/index.html +11 -6
app.py CHANGED
@@ -14,7 +14,7 @@ import mutagen.flac
14
  import mutagen.oggvorbis
15
  from werkzeug.utils import secure_filename
16
 
17
- app = Flask(__name__)
18
  # Create a temporary directory for uploads
19
  TEMP_UPLOAD_DIR = tempfile.mkdtemp()
20
  app.config['UPLOAD_FOLDER'] = TEMP_UPLOAD_DIR
@@ -206,6 +206,9 @@ def upload_file():
206
  'error': 'Invalid file type'
207
  })
208
 
 
 
 
209
  return jsonify({
210
  'success': True,
211
  'files': results
 
14
  import mutagen.oggvorbis
15
  from werkzeug.utils import secure_filename
16
 
17
+ app = Flask(__name__, static_folder='static')
18
  # Create a temporary directory for uploads
19
  TEMP_UPLOAD_DIR = tempfile.mkdtemp()
20
  app.config['UPLOAD_FOLDER'] = TEMP_UPLOAD_DIR
 
206
  'error': 'Invalid file type'
207
  })
208
 
209
+ # Debug log to check the response
210
+ app.logger.debug(f"Upload response: {results}")
211
+
212
  return jsonify({
213
  'success': True,
214
  'files': results
static/css/style.css CHANGED
@@ -886,4 +886,105 @@ input[type="file"] {
886
  display: block;
887
  opacity: 1;
888
  transform: translateY(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
889
  }
 
886
  display: block;
887
  opacity: 1;
888
  transform: translateY(0);
889
+ }
890
+
891
+ /* Add these styles for the visualization type dropdown */
892
+ .viz-type-dropdown {
893
+ position: fixed;
894
+ top: 60px;
895
+ right: -200px;
896
+ background: var(--surface-color);
897
+ backdrop-filter: blur(12px);
898
+ border-radius: 8px;
899
+ padding: 8px;
900
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
901
+ transition: right 0.3s ease;
902
+ z-index: 99;
903
+ width: 200px;
904
+ }
905
+
906
+ .viz-type-dropdown.visible {
907
+ right: 16px;
908
+ }
909
+
910
+ .viz-type-options {
911
+ display: flex;
912
+ flex-direction: column;
913
+ gap: 8px;
914
+ }
915
+
916
+ .viz-type-options button {
917
+ background: transparent;
918
+ border: none;
919
+ color: var(--text-primary);
920
+ padding: 8px 16px;
921
+ text-align: left;
922
+ border-radius: 4px;
923
+ cursor: pointer;
924
+ transition: background-color 0.2s;
925
+ width: 100%;
926
+ }
927
+
928
+ .viz-type-options button:hover {
929
+ background: rgba(255, 255, 255, 0.1);
930
+ }
931
+
932
+ .viz-type-options button.active {
933
+ background: var(--primary-color);
934
+ color: white;
935
+ }
936
+
937
+ /* Update mobile styles */
938
+ @media screen and (max-width: 768px) {
939
+ .header-controls {
940
+ gap: 4px;
941
+ }
942
+
943
+ .header-btn {
944
+ width: 32px;
945
+ height: 32px;
946
+ }
947
+
948
+ .viz-type-dropdown {
949
+ top: 50px;
950
+ width: calc(100% - 32px);
951
+ right: -100%;
952
+ }
953
+
954
+ .viz-type-dropdown.visible {
955
+ right: 16px;
956
+ }
957
+ }
958
+
959
+ /* Fix the main content positioning */
960
+ .main-content {
961
+ position: fixed;
962
+ top: 60px; /* Adjust based on header height */
963
+ right: -420px;
964
+ width: 400px;
965
+ max-height: calc(100vh - 180px); /* Adjust for header and player */
966
+ z-index: 10;
967
+ overflow: visible;
968
+ transition: right 0.3s cubic-bezier(0.4, 0, 0.2, 1);
969
+ padding: 16px;
970
+ box-sizing: border-box;
971
+ }
972
+
973
+ /* Update the mobile layout */
974
+ @media screen and (max-width: 768px) {
975
+ .main-content {
976
+ width: 100%;
977
+ right: -100%;
978
+ padding: 8px;
979
+ }
980
+
981
+ .main-content.visible {
982
+ right: 0;
983
+ }
984
+
985
+ .playlist-container,
986
+ .upload-area {
987
+ margin: 0;
988
+ border-radius: 8px;
989
+ }
990
  }
static/js/main.js CHANGED
@@ -276,22 +276,30 @@ async function handleFiles(files) {
276
  const data = await response.json();
277
 
278
  if (data.success) {
279
- playlist = data.files.map(file => ({
 
 
 
280
  name: file.filename,
281
  url: file.filepath,
282
  metadata: file.metadata
283
  }));
284
 
 
 
 
285
  createPlaylist();
286
- if (playlist.length > 0) {
287
  playTrack(0);
 
 
288
  }
289
  } else {
290
- showError(data.error);
291
  }
292
  } catch (error) {
293
- showError('Error uploading files');
294
  console.error('Upload error:', error);
 
295
  }
296
  }
297
 
@@ -528,7 +536,7 @@ function updateNowPlayingInfo() {
528
 
529
  // Play selected track
530
  function playTrack(index) {
531
- if (index < 0 || index >= playlist.length) return;
532
 
533
  currentTrackIndex = index;
534
  const track = playlist[index];
@@ -537,33 +545,39 @@ function playTrack(index) {
537
  initAudio();
538
  }
539
 
 
 
 
 
 
 
540
  // Update playlist UI
541
  document.querySelectorAll('.playlist-item').forEach((item, i) => {
542
  item.classList.toggle('active', i === index);
543
  });
544
 
545
  // Enable controls
546
- document.getElementById('play-pause').disabled = false;
547
- document.querySelector('.previous-btn').disabled = false;
548
- document.querySelector('.next-btn').disabled = false;
 
 
 
 
549
 
550
  // Update audio source and play
551
  audioElement.src = track.url;
552
  audioElement.play()
553
  .then(() => {
554
  isPlaying = true;
555
- document.getElementById('play-pause').innerHTML = '<i class="fas fa-pause"></i>';
556
- updateNowPlayingInfo();
557
-
558
- // Add event listeners for time updates if not already added
559
- if (!audioElement.onended) {
560
- audioElement.addEventListener('timeupdate', updateTimeDisplay);
561
- audioElement.addEventListener('ended', handleTrackEnd);
562
  }
 
563
  })
564
  .catch(error => {
565
  console.error('Error playing track:', error);
566
- showError('Error playing track');
567
  });
568
  }
569
 
@@ -574,39 +588,85 @@ function setupToggleHandlers() {
574
  const playlistContainer = document.querySelector('.playlist-container');
575
  const uploadToggleBtn = document.querySelector('.upload-toggle-btn');
576
  const playlistToggleBtn = document.querySelector('.playlist-toggle-btn');
 
 
 
577
 
578
  // Show playlist by default
579
- mainContent.classList.add('visible');
580
- playlistContainer.classList.add('visible');
581
- playlistToggleBtn.classList.add('active');
582
 
583
  uploadToggleBtn?.addEventListener('click', () => {
584
- const isVisible = uploadArea.classList.contains('visible');
585
 
586
  // Hide playlist if it's visible
587
- playlistContainer.classList.remove('visible');
588
- playlistToggleBtn.classList.remove('active');
589
 
590
  // Toggle upload area
591
- uploadArea.classList.toggle('visible');
592
- uploadToggleBtn.classList.toggle('active');
593
 
594
  // Show/hide main content
595
- mainContent.classList.toggle('visible', !isVisible || playlistContainer.classList.contains('visible'));
596
  });
597
 
598
  playlistToggleBtn?.addEventListener('click', () => {
599
- const isVisible = playlistContainer.classList.contains('visible');
600
 
601
  // Hide upload area if it's visible
602
- uploadArea.classList.remove('visible');
603
- uploadToggleBtn.classList.remove('active');
604
 
605
  // Toggle playlist
606
- playlistContainer.classList.toggle('visible');
607
- playlistToggleBtn.classList.toggle('active');
608
 
609
  // Show/hide main content
610
- mainContent.classList.toggle('visible', !isVisible || uploadArea.classList.contains('visible'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
  });
612
  }
 
276
  const data = await response.json();
277
 
278
  if (data.success) {
279
+ // Debug log to check the response
280
+ console.log('Upload response:', data);
281
+
282
+ playlist = data.files.filter(file => file.success).map(file => ({
283
  name: file.filename,
284
  url: file.filepath,
285
  metadata: file.metadata
286
  }));
287
 
288
+ // Debug log to check the playlist
289
+ console.log('Created playlist:', playlist);
290
+
291
  createPlaylist();
292
+ if (playlist.length > 0 && playlist[0].url) {
293
  playTrack(0);
294
+ } else {
295
+ showError('No valid tracks were uploaded');
296
  }
297
  } else {
298
+ showError(data.error || 'Upload failed');
299
  }
300
  } catch (error) {
 
301
  console.error('Upload error:', error);
302
+ showError('Error uploading files');
303
  }
304
  }
305
 
 
536
 
537
  // Play selected track
538
  function playTrack(index) {
539
+ if (!playlist || index < 0 || index >= playlist.length) return;
540
 
541
  currentTrackIndex = index;
542
  const track = playlist[index];
 
545
  initAudio();
546
  }
547
 
548
+ if (!track || !track.url) {
549
+ console.error('Invalid track or track URL');
550
+ showError('Invalid track data');
551
+ return;
552
+ }
553
+
554
  // Update playlist UI
555
  document.querySelectorAll('.playlist-item').forEach((item, i) => {
556
  item.classList.toggle('active', i === index);
557
  });
558
 
559
  // Enable controls
560
+ const playPauseBtn = document.getElementById('play-pause');
561
+ const prevBtn = document.querySelector('.previous-btn');
562
+ const nextBtn = document.querySelector('.next-btn');
563
+
564
+ if (playPauseBtn) playPauseBtn.disabled = false;
565
+ if (prevBtn) prevBtn.disabled = false;
566
+ if (nextBtn) nextBtn.disabled = false;
567
 
568
  // Update audio source and play
569
  audioElement.src = track.url;
570
  audioElement.play()
571
  .then(() => {
572
  isPlaying = true;
573
+ if (playPauseBtn) {
574
+ playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>';
 
 
 
 
 
575
  }
576
+ updateNowPlayingInfo();
577
  })
578
  .catch(error => {
579
  console.error('Error playing track:', error);
580
+ showError('Error playing track: ' + error.message);
581
  });
582
  }
583
 
 
588
  const playlistContainer = document.querySelector('.playlist-container');
589
  const uploadToggleBtn = document.querySelector('.upload-toggle-btn');
590
  const playlistToggleBtn = document.querySelector('.playlist-toggle-btn');
591
+ const vizTypeBtn = document.querySelector('.viz-type-btn');
592
+ const vizTypeDropdown = document.querySelector('.viz-type-dropdown');
593
+ const vizTypeOptions = document.querySelectorAll('.viz-type-options button');
594
 
595
  // Show playlist by default
596
+ mainContent?.classList.add('visible');
597
+ playlistContainer?.classList.add('visible');
598
+ playlistToggleBtn?.classList.add('active');
599
 
600
  uploadToggleBtn?.addEventListener('click', () => {
601
+ const isVisible = uploadArea?.classList.contains('visible');
602
 
603
  // Hide playlist if it's visible
604
+ playlistContainer?.classList.remove('visible');
605
+ playlistToggleBtn?.classList.remove('active');
606
 
607
  // Toggle upload area
608
+ uploadArea?.classList.toggle('visible');
609
+ uploadToggleBtn?.classList.toggle('active');
610
 
611
  // Show/hide main content
612
+ mainContent?.classList.toggle('visible', !isVisible || playlistContainer?.classList.contains('visible'));
613
  });
614
 
615
  playlistToggleBtn?.addEventListener('click', () => {
616
+ const isVisible = playlistContainer?.classList.contains('visible');
617
 
618
  // Hide upload area if it's visible
619
+ uploadArea?.classList.remove('visible');
620
+ uploadToggleBtn?.classList.remove('active');
621
 
622
  // Toggle playlist
623
+ playlistContainer?.classList.toggle('visible');
624
+ playlistToggleBtn?.classList.toggle('active');
625
 
626
  // Show/hide main content
627
+ mainContent?.classList.toggle('visible', !isVisible || uploadArea?.classList.contains('visible'));
628
+ });
629
+
630
+ // Handle visualization type button click
631
+ vizTypeBtn?.addEventListener('click', (e) => {
632
+ e.stopPropagation(); // Prevent document click from immediately closing
633
+ vizTypeDropdown?.classList.toggle('visible');
634
+ vizTypeBtn?.classList.toggle('active');
635
+
636
+ // Close other dropdowns
637
+ uploadArea?.classList.remove('visible');
638
+ uploadToggleBtn?.classList.remove('active');
639
+ playlistContainer?.classList.remove('visible');
640
+ playlistToggleBtn?.classList.remove('active');
641
+ });
642
+
643
+ // Handle visualization type selection
644
+ vizTypeOptions?.forEach(button => {
645
+ button.addEventListener('click', (e) => {
646
+ e.stopPropagation(); // Prevent document click from closing dropdown
647
+ const type = button.dataset.type;
648
+
649
+ // Update active state
650
+ vizTypeOptions.forEach(btn => btn.classList.remove('active'));
651
+ button.classList.add('active');
652
+
653
+ // Update visualization
654
+ visualizationType = type;
655
+ createVisualization();
656
+
657
+ // Close dropdown
658
+ vizTypeDropdown?.classList.remove('visible');
659
+ vizTypeBtn?.classList.remove('active');
660
+ });
661
+ });
662
+
663
+ // Close dropdown when clicking outside
664
+ document.addEventListener('click', (e) => {
665
+ if (vizTypeBtn && vizTypeDropdown &&
666
+ !vizTypeBtn.contains(e.target) &&
667
+ !vizTypeDropdown.contains(e.target)) {
668
+ vizTypeDropdown.classList.remove('visible');
669
+ vizTypeBtn.classList.remove('active');
670
+ }
671
  });
672
  }
templates/index.html CHANGED
@@ -22,6 +22,9 @@
22
  <button class="header-btn playlist-toggle-btn" title="Show playlist">
23
  <i class="fas fa-list"></i>
24
  </button>
 
 
 
25
  <button class="header-btn theme-btn" title="Toggle theme">
26
  <i class="fas fa-moon"></i>
27
  </button>
@@ -97,18 +100,20 @@
97
  <input type="range" id="volume" min="0" max="1" step="0.1" value="0.5">
98
  </div>
99
  </div>
100
-
101
- <select id="visualization-type">
102
- <option value="bars">Circular Bars</option>
103
- <option value="sphere">Sphere</option>
104
- <option value="particles">Particles</option>
105
- </select>
106
  </div>
107
  </div>
108
 
109
  <div class="error-toast"></div>
110
  <div class="tooltip"></div>
111
 
 
 
 
 
 
 
 
 
112
  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
113
  </body>
114
  </html>
 
22
  <button class="header-btn playlist-toggle-btn" title="Show playlist">
23
  <i class="fas fa-list"></i>
24
  </button>
25
+ <button class="header-btn viz-type-btn" title="Change visualization">
26
+ <i class="fas fa-cube"></i>
27
+ </button>
28
  <button class="header-btn theme-btn" title="Toggle theme">
29
  <i class="fas fa-moon"></i>
30
  </button>
 
100
  <input type="range" id="volume" min="0" max="1" step="0.1" value="0.5">
101
  </div>
102
  </div>
 
 
 
 
 
 
103
  </div>
104
  </div>
105
 
106
  <div class="error-toast"></div>
107
  <div class="tooltip"></div>
108
 
109
+ <div class="viz-type-dropdown">
110
+ <div class="viz-type-options">
111
+ <button data-type="bars" class="active">Circular Bars</button>
112
+ <button data-type="sphere">Sphere</button>
113
+ <button data-type="particles">Particles</button>
114
+ </div>
115
+ </div>
116
+
117
  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
118
  </body>
119
  </html>