@files-preview-app/preview-file 1.3.12 → 1.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/styles.css CHANGED
@@ -409,3 +409,179 @@
409
409
  text-transform: uppercase;
410
410
  flex-shrink: 0;
411
411
  }
412
+
413
+ /* ==========================================================================
414
+ Audio Preview Card Component
415
+ ========================================================================== */
416
+ .fp-audio-card {
417
+ width: 100%;
418
+ max-width: 520px;
419
+ background: var(--fp-toolbar-bg, #ffffff);
420
+ border: 1px solid var(--fp-toolbar-border, #e2e8f0);
421
+ border-radius: 20px;
422
+ box-shadow: 0 12px 32px -4px rgba(0, 0, 0, 0.08), 0 4px 12px -2px rgba(0, 0, 0, 0.04);
423
+ padding: 36px 32px 28px;
424
+ display: flex;
425
+ flex-direction: column;
426
+ align-items: center;
427
+ text-align: center;
428
+ box-sizing: border-box;
429
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
430
+ }
431
+
432
+ .fp-audio-artwork-wrapper {
433
+ position: relative;
434
+ width: 120px;
435
+ height: 120px;
436
+ margin-bottom: 22px;
437
+ display: flex;
438
+ align-items: center;
439
+ justify-content: center;
440
+ }
441
+
442
+ .fp-audio-disc {
443
+ width: 120px;
444
+ height: 120px;
445
+ border-radius: 50%;
446
+ background: radial-gradient(circle at center, #1e293b 0%, #0f172a 60%, #020617 100%);
447
+ border: 4px solid var(--fp-toolbar-border, #e2e8f0);
448
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2),
449
+ inset 0 0 0 8px rgba(255, 255, 255, 0.05),
450
+ inset 0 0 0 18px rgba(0, 0, 0, 0.3),
451
+ inset 0 0 0 28px rgba(255, 255, 255, 0.03);
452
+ display: flex;
453
+ align-items: center;
454
+ justify-content: center;
455
+ position: relative;
456
+ transform: rotate(0deg);
457
+ transition: transform 0.3s ease;
458
+ }
459
+
460
+ .fp-audio-disc.playing {
461
+ animation: fp-spin 4s linear infinite;
462
+ }
463
+
464
+ .fp-audio-disc-center {
465
+ width: 40px;
466
+ height: 40px;
467
+ border-radius: 50%;
468
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
469
+ display: flex;
470
+ align-items: center;
471
+ justify-content: center;
472
+ color: #ffffff;
473
+ box-shadow: 0 2px 8px rgba(37, 99, 235, 0.5);
474
+ }
475
+
476
+ .fp-audio-disc-hole {
477
+ width: 8px;
478
+ height: 8px;
479
+ border-radius: 50%;
480
+ background: #ffffff;
481
+ }
482
+
483
+ .fp-audio-info {
484
+ display: flex;
485
+ flex-direction: column;
486
+ align-items: center;
487
+ width: 100%;
488
+ margin-bottom: 12px;
489
+ }
490
+
491
+ .fp-audio-title {
492
+ font-size: 17px;
493
+ font-weight: 600;
494
+ color: var(--fp-text-color, #0f172a);
495
+ margin-bottom: 6px;
496
+ max-width: 100%;
497
+ white-space: nowrap;
498
+ overflow: hidden;
499
+ text-overflow: ellipsis;
500
+ }
501
+
502
+ .fp-audio-badges {
503
+ display: flex;
504
+ align-items: center;
505
+ justify-content: center;
506
+ gap: 8px;
507
+ font-size: 12px;
508
+ color: var(--fp-btn-color, #64748b);
509
+ margin-bottom: 8px;
510
+ }
511
+
512
+ .fp-audio-ext-tag {
513
+ background: rgba(59, 130, 246, 0.12);
514
+ color: var(--fp-accent, #3b82f6);
515
+ font-weight: 700;
516
+ font-size: 11px;
517
+ padding: 2px 8px;
518
+ border-radius: 6px;
519
+ letter-spacing: 0.5px;
520
+ text-transform: uppercase;
521
+ }
522
+
523
+ .fp-audio-time-tag {
524
+ font-size: 12px;
525
+ color: var(--fp-btn-color, #64748b);
526
+ font-variant-numeric: tabular-nums;
527
+ }
528
+
529
+ /* Sound Waveform / Equalizer Bars */
530
+ .fp-audio-waveform {
531
+ display: flex;
532
+ align-items: center;
533
+ justify-content: center;
534
+ gap: 4px;
535
+ height: 32px;
536
+ margin-bottom: 20px;
537
+ width: 100%;
538
+ }
539
+
540
+ .fp-audio-wave-bar {
541
+ width: 4px;
542
+ height: 8px;
543
+ background: var(--fp-accent, #3b82f6);
544
+ border-radius: 2px;
545
+ opacity: 0.35;
546
+ transition: height 0.2s ease, opacity 0.2s ease;
547
+ }
548
+
549
+ .fp-audio-waveform.playing .fp-audio-wave-bar {
550
+ opacity: 0.85;
551
+ animation: fp-wave-dance 1.2s ease-in-out infinite alternate;
552
+ }
553
+
554
+ @keyframes fp-wave-dance {
555
+ 0% { height: 6px; }
556
+ 50% { height: 26px; }
557
+ 100% { height: 10px; }
558
+ }
559
+
560
+ .fp-audio-wave-bar:nth-child(1) { animation-delay: 0.05s !important; }
561
+ .fp-audio-wave-bar:nth-child(2) { animation-delay: 0.20s !important; }
562
+ .fp-audio-wave-bar:nth-child(3) { animation-delay: 0.35s !important; }
563
+ .fp-audio-wave-bar:nth-child(4) { animation-delay: 0.10s !important; }
564
+ .fp-audio-wave-bar:nth-child(5) { animation-delay: 0.45s !important; }
565
+ .fp-audio-wave-bar:nth-child(6) { animation-delay: 0.25s !important; }
566
+ .fp-audio-wave-bar:nth-child(7) { animation-delay: 0.50s !important; }
567
+ .fp-audio-wave-bar:nth-child(8) { animation-delay: 0.15s !important; }
568
+ .fp-audio-wave-bar:nth-child(9) { animation-delay: 0.40s !important; }
569
+ .fp-audio-wave-bar:nth-child(10) { animation-delay: 0.30s !important; }
570
+ .fp-audio-wave-bar:nth-child(11) { animation-delay: 0.55s !important; }
571
+ .fp-audio-wave-bar:nth-child(12) { animation-delay: 0.18s !important; }
572
+ .fp-audio-wave-bar:nth-child(13) { animation-delay: 0.42s !important; }
573
+ .fp-audio-wave-bar:nth-child(14) { animation-delay: 0.22s !important; }
574
+ .fp-audio-wave-bar:nth-child(15) { animation-delay: 0.48s !important; }
575
+ .fp-audio-wave-bar:nth-child(16) { animation-delay: 0.12s !important; }
576
+
577
+ .fp-audio-native-wrapper {
578
+ width: 100%;
579
+ }
580
+
581
+ .fp-audio-native-wrapper audio {
582
+ width: 100%;
583
+ height: 44px;
584
+ border-radius: 22px;
585
+ outline: none;
586
+ }
587
+
package/dist/vue.cjs CHANGED
@@ -201,6 +201,10 @@ var EXTENSION_MIME_MAP = {
201
201
  ".wav": "audio/wav",
202
202
  ".aac": "audio/aac",
203
203
  ".flac": "audio/flac",
204
+ ".m4a": "audio/mp4",
205
+ ".wma": "audio/x-ms-wma",
206
+ ".opus": "audio/opus",
207
+ ".weba": "audio/webm",
204
208
  // Code/Text
205
209
  ".txt": "text/plain",
206
210
  ".log": "text/plain",
@@ -527,6 +531,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
527
531
  var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
528
532
  var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
529
533
  var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
534
+ var ICON_SPEED = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>`;
530
535
  var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="3" y1="8" x2="21" y2="8"></line><circle cx="6" cy="5.5" r="0.75" fill="currentColor"></circle><circle cx="8.5" cy="5.5" r="0.75" fill="currentColor"></circle><polyline points="14 13 18 13 18 17"></polyline><line x1="11" y1="20" x2="18" y2="13"></line></svg>`;
531
536
  var ICON_RESET_ZOOM = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><path d="M13 11a3 3 0 1 0-3 3"></path><path d="M10 11v3h3"></path></svg>`;
532
537
  var ICON_MAP = {
@@ -561,7 +566,8 @@ var ICON_MAP = {
561
566
  "openSeparateWindow": ICON_EXTERNAL_WINDOW,
562
567
  "reset-zoom": ICON_RESET_ZOOM,
563
568
  "zoom-reset": ICON_RESET_ZOOM,
564
- "resetZoom": ICON_RESET_ZOOM
569
+ "resetZoom": ICON_RESET_ZOOM,
570
+ "speed": ICON_SPEED
565
571
  };
566
572
  var ToolbarController = class {
567
573
  el;
@@ -2695,13 +2701,42 @@ var MediaPlugin = class {
2695
2701
  }
2696
2702
  });
2697
2703
  }
2704
+ actions.push({
2705
+ id: "open-window",
2706
+ icon: "open-window",
2707
+ label: "Open in Separate Full Window",
2708
+ type: "button",
2709
+ group: "actions",
2710
+ execute: () => {
2711
+ instance.openInSeparateWindow?.();
2712
+ }
2713
+ });
2698
2714
  return actions;
2699
2715
  }
2700
2716
  async render(ctx) {
2701
- const mimeType = ctx.metadata.mimeType || "application/octet-stream";
2702
- const isImage = mimeType.startsWith("image/") || IMAGE_EXTS.includes(ctx.metadata.extension || "");
2703
- const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2704
- const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2717
+ const ext = (ctx.metadata.extension || "").toLowerCase();
2718
+ let mimeType = ctx.metadata.mimeType || "";
2719
+ if (!mimeType || mimeType === "application/octet-stream") {
2720
+ const audioMimes = {
2721
+ ".mp3": "audio/mpeg",
2722
+ ".wav": "audio/wav",
2723
+ ".ogg": "audio/ogg",
2724
+ ".flac": "audio/flac",
2725
+ ".aac": "audio/aac",
2726
+ ".m4a": "audio/mp4",
2727
+ ".wma": "audio/x-ms-wma",
2728
+ ".opus": "audio/opus",
2729
+ ".weba": "audio/webm"
2730
+ };
2731
+ if (audioMimes[ext]) {
2732
+ mimeType = audioMimes[ext];
2733
+ } else {
2734
+ mimeType = "application/octet-stream";
2735
+ }
2736
+ }
2737
+ const isImage = mimeType.startsWith("image/") || IMAGE_EXTS.includes(ext);
2738
+ const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ext);
2739
+ const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ext);
2705
2740
  let url = "";
2706
2741
  let naturalW = 800;
2707
2742
  let naturalH = 600;
@@ -2773,10 +2808,79 @@ var MediaPlugin = class {
2773
2808
  video.addEventListener("canplay", onMeta, { once: true });
2774
2809
  }
2775
2810
  } else if (isAudio) {
2811
+ const audioCard = document.createElement("div");
2812
+ audioCard.className = "fp-audio-card";
2813
+ const artWrapper = document.createElement("div");
2814
+ artWrapper.className = "fp-audio-artwork-wrapper";
2815
+ const disc = document.createElement("div");
2816
+ disc.className = "fp-audio-disc";
2817
+ const discCenter = document.createElement("div");
2818
+ discCenter.className = "fp-audio-disc-center";
2819
+ const discHole = document.createElement("div");
2820
+ discHole.className = "fp-audio-disc-hole";
2821
+ discCenter.appendChild(discHole);
2822
+ disc.appendChild(discCenter);
2823
+ artWrapper.appendChild(disc);
2824
+ audioCard.appendChild(artWrapper);
2825
+ const info = document.createElement("div");
2826
+ info.className = "fp-audio-info";
2827
+ const title = document.createElement("div");
2828
+ title.className = "fp-audio-title";
2829
+ title.textContent = ctx.metadata.name || "Audio Track";
2830
+ const badges = document.createElement("div");
2831
+ badges.className = "fp-audio-badges";
2832
+ const extTag = document.createElement("span");
2833
+ extTag.className = "fp-audio-ext-tag";
2834
+ const cleanExt = (ext || ".mp3").replace(".", "").toUpperCase();
2835
+ extTag.textContent = `${cleanExt} AUDIO`;
2836
+ badges.appendChild(extTag);
2837
+ const timeTag = document.createElement("span");
2838
+ timeTag.className = "fp-audio-time-tag";
2839
+ timeTag.textContent = "0:00";
2840
+ badges.appendChild(timeTag);
2841
+ info.appendChild(title);
2842
+ info.appendChild(badges);
2843
+ audioCard.appendChild(info);
2844
+ const waveform = document.createElement("div");
2845
+ waveform.className = "fp-audio-waveform";
2846
+ for (let i = 0; i < 16; i++) {
2847
+ const bar = document.createElement("div");
2848
+ bar.className = "fp-audio-wave-bar";
2849
+ waveform.appendChild(bar);
2850
+ }
2851
+ audioCard.appendChild(waveform);
2852
+ const nativeWrapper = document.createElement("div");
2853
+ nativeWrapper.className = "fp-audio-native-wrapper";
2776
2854
  const audio = document.createElement("audio");
2777
2855
  audio.src = url;
2778
2856
  audio.controls = true;
2779
- element = audio;
2857
+ nativeWrapper.appendChild(audio);
2858
+ audioCard.appendChild(nativeWrapper);
2859
+ const onPlay = () => {
2860
+ disc.classList.add("playing");
2861
+ waveform.classList.add("playing");
2862
+ };
2863
+ const onPause = () => {
2864
+ disc.classList.remove("playing");
2865
+ waveform.classList.remove("playing");
2866
+ };
2867
+ const formatTime = (secs) => {
2868
+ if (!isFinite(secs) || isNaN(secs)) return "0:00";
2869
+ const m = Math.floor(secs / 60);
2870
+ const s = Math.floor(secs % 60);
2871
+ return `${m}:${s < 10 ? "0" : ""}${s}`;
2872
+ };
2873
+ const onTimeUpdate = () => {
2874
+ timeTag.textContent = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
2875
+ };
2876
+ const onLoadedMetadata = () => {
2877
+ timeTag.textContent = `0:00 / ${formatTime(audio.duration)}`;
2878
+ };
2879
+ audio.addEventListener("play", onPlay);
2880
+ audio.addEventListener("pause", onPause);
2881
+ audio.addEventListener("timeupdate", onTimeUpdate);
2882
+ audio.addEventListener("loadedmetadata", onLoadedMetadata);
2883
+ element = audioCard;
2780
2884
  mediaElement = audio;
2781
2885
  } else {
2782
2886
  element = document.createElement("div");
@@ -2786,11 +2890,12 @@ var MediaPlugin = class {
2786
2890
  scrollWrapper.className = "fp-media-scroll-wrapper";
2787
2891
  scrollWrapper.style.minWidth = "100%";
2788
2892
  scrollWrapper.style.minHeight = "100%";
2789
- scrollWrapper.style.width = "max-content";
2790
- scrollWrapper.style.height = "max-content";
2893
+ scrollWrapper.style.width = isAudio ? "100%" : "max-content";
2894
+ scrollWrapper.style.height = isAudio ? "100%" : "max-content";
2791
2895
  scrollWrapper.style.display = "flex";
2792
2896
  scrollWrapper.style.flexDirection = "column";
2793
2897
  scrollWrapper.style.alignItems = "center";
2898
+ scrollWrapper.style.justifyContent = isAudio ? "center" : "flex-start";
2794
2899
  scrollWrapper.style.padding = "16px";
2795
2900
  scrollWrapper.style.boxSizing = "border-box";
2796
2901
  const sizer = document.createElement("div");
@@ -2801,6 +2906,11 @@ var MediaPlugin = class {
2801
2906
  sizer.style.justifyContent = "center";
2802
2907
  sizer.style.alignItems = "center";
2803
2908
  sizer.style.margin = "auto 0";
2909
+ if (isAudio) {
2910
+ sizer.style.width = "100%";
2911
+ sizer.style.maxWidth = "520px";
2912
+ sizer.style.margin = "auto";
2913
+ }
2804
2914
  sizer.appendChild(element);
2805
2915
  scrollWrapper.appendChild(sizer);
2806
2916
  ctx.container.style.overflow = "auto";
@@ -2859,7 +2969,9 @@ var MediaPlugin = class {
2859
2969
  element.style.transformOrigin = "center center";
2860
2970
  element.style.flexShrink = "0";
2861
2971
  } else {
2862
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2972
+ if (!isAudio) {
2973
+ element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2974
+ }
2863
2975
  }
2864
2976
  };
2865
2977
  updateBaseDimensions();
@@ -2885,6 +2997,10 @@ var MediaPlugin = class {
2885
2997
  ro?.observe(ctx.container);
2886
2998
  const cleanup = () => {
2887
2999
  ro?.disconnect();
3000
+ if (mediaElement) {
3001
+ mediaElement.pause();
3002
+ mediaElement.src = "";
3003
+ }
2888
3004
  if (url) URL.revokeObjectURL(url);
2889
3005
  scrollWrapper.remove();
2890
3006
  ctx.container.innerHTML = "";
@@ -2908,36 +3024,54 @@ var MediaPlugin = class {
2908
3024
  currentZoom = level;
2909
3025
  applyTransform();
2910
3026
  } : void 0,
2911
- fitToPage: isImage || isVideo ? () => {
2912
- isUserZoomed = false;
2913
- fitMode = "page";
2914
- currentZoom = 1;
2915
- rotation = 0;
2916
- ctx.container.scrollTop = 0;
2917
- ctx.container.scrollLeft = 0;
2918
- updateBaseDimensions();
2919
- applyTransform();
2920
- } : void 0,
2921
- fitToWidth: isImage || isVideo ? () => {
2922
- isUserZoomed = false;
2923
- fitMode = "width";
2924
- currentZoom = 1;
2925
- rotation = 0;
2926
- ctx.container.scrollTop = 0;
2927
- ctx.container.scrollLeft = 0;
2928
- updateBaseDimensions();
2929
- applyTransform();
2930
- } : void 0,
2931
- resetZoom: isImage || isVideo ? () => {
2932
- isUserZoomed = false;
2933
- fitMode = ctx?.options?.fitMode || "width";
2934
- currentZoom = 1;
2935
- rotation = 0;
2936
- ctx.container.scrollTop = 0;
2937
- ctx.container.scrollLeft = 0;
2938
- updateBaseDimensions();
2939
- applyTransform();
2940
- } : void 0,
3027
+ fitToPage: () => {
3028
+ if (isImage || isVideo) {
3029
+ isUserZoomed = false;
3030
+ fitMode = "page";
3031
+ currentZoom = 1;
3032
+ rotation = 0;
3033
+ ctx.container.scrollTop = 0;
3034
+ ctx.container.scrollLeft = 0;
3035
+ updateBaseDimensions();
3036
+ applyTransform();
3037
+ } else if (isAudio) {
3038
+ ctx.container.scrollTop = 0;
3039
+ ctx.container.scrollLeft = 0;
3040
+ currentZoom = 1;
3041
+ }
3042
+ },
3043
+ fitToWidth: () => {
3044
+ if (isImage || isVideo) {
3045
+ isUserZoomed = false;
3046
+ fitMode = "width";
3047
+ currentZoom = 1;
3048
+ rotation = 0;
3049
+ ctx.container.scrollTop = 0;
3050
+ ctx.container.scrollLeft = 0;
3051
+ updateBaseDimensions();
3052
+ applyTransform();
3053
+ } else if (isAudio) {
3054
+ ctx.container.scrollTop = 0;
3055
+ ctx.container.scrollLeft = 0;
3056
+ currentZoom = 1;
3057
+ }
3058
+ },
3059
+ resetZoom: () => {
3060
+ if (isImage || isVideo) {
3061
+ isUserZoomed = false;
3062
+ fitMode = ctx?.options?.fitMode || "width";
3063
+ currentZoom = 1;
3064
+ rotation = 0;
3065
+ ctx.container.scrollTop = 0;
3066
+ ctx.container.scrollLeft = 0;
3067
+ updateBaseDimensions();
3068
+ applyTransform();
3069
+ } else if (isAudio) {
3070
+ ctx.container.scrollTop = 0;
3071
+ ctx.container.scrollLeft = 0;
3072
+ currentZoom = 1;
3073
+ }
3074
+ },
2941
3075
  rotateCW: isImage || isVideo ? () => {
2942
3076
  rotation = (rotation + 90) % 360;
2943
3077
  applyTransform();