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

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/index.js CHANGED
@@ -167,6 +167,10 @@ var EXTENSION_MIME_MAP = {
167
167
  ".wav": "audio/wav",
168
168
  ".aac": "audio/aac",
169
169
  ".flac": "audio/flac",
170
+ ".m4a": "audio/mp4",
171
+ ".wma": "audio/x-ms-wma",
172
+ ".opus": "audio/opus",
173
+ ".weba": "audio/webm",
170
174
  // Code/Text
171
175
  ".txt": "text/plain",
172
176
  ".log": "text/plain",
@@ -578,6 +582,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
578
582
  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>`;
579
583
  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>`;
580
584
  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>`;
585
+ 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>`;
581
586
  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>`;
582
587
  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>`;
583
588
  var ICON_MAP = {
@@ -612,7 +617,8 @@ var ICON_MAP = {
612
617
  "openSeparateWindow": ICON_EXTERNAL_WINDOW,
613
618
  "reset-zoom": ICON_RESET_ZOOM,
614
619
  "zoom-reset": ICON_RESET_ZOOM,
615
- "resetZoom": ICON_RESET_ZOOM
620
+ "resetZoom": ICON_RESET_ZOOM,
621
+ "speed": ICON_SPEED
616
622
  };
617
623
  var ToolbarController = class {
618
624
  el;
@@ -2746,13 +2752,42 @@ var MediaPlugin = class {
2746
2752
  }
2747
2753
  });
2748
2754
  }
2755
+ actions.push({
2756
+ id: "open-window",
2757
+ icon: "open-window",
2758
+ label: "Open in Separate Full Window",
2759
+ type: "button",
2760
+ group: "actions",
2761
+ execute: () => {
2762
+ instance.openInSeparateWindow?.();
2763
+ }
2764
+ });
2749
2765
  return actions;
2750
2766
  }
2751
2767
  async render(ctx) {
2752
- const mimeType = ctx.metadata.mimeType || "application/octet-stream";
2753
- const isImage = mimeType.startsWith("image/") || IMAGE_EXTS.includes(ctx.metadata.extension || "");
2754
- const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2755
- const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2768
+ const ext = (ctx.metadata.extension || "").toLowerCase();
2769
+ let mimeType = ctx.metadata.mimeType || "";
2770
+ if (!mimeType || mimeType === "application/octet-stream") {
2771
+ const audioMimes = {
2772
+ ".mp3": "audio/mpeg",
2773
+ ".wav": "audio/wav",
2774
+ ".ogg": "audio/ogg",
2775
+ ".flac": "audio/flac",
2776
+ ".aac": "audio/aac",
2777
+ ".m4a": "audio/mp4",
2778
+ ".wma": "audio/x-ms-wma",
2779
+ ".opus": "audio/opus",
2780
+ ".weba": "audio/webm"
2781
+ };
2782
+ if (audioMimes[ext]) {
2783
+ mimeType = audioMimes[ext];
2784
+ } else {
2785
+ mimeType = "application/octet-stream";
2786
+ }
2787
+ }
2788
+ const isImage = mimeType.startsWith("image/") || IMAGE_EXTS.includes(ext);
2789
+ const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ext);
2790
+ const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ext);
2756
2791
  let url = "";
2757
2792
  let naturalW = 800;
2758
2793
  let naturalH = 600;
@@ -2824,10 +2859,79 @@ var MediaPlugin = class {
2824
2859
  video.addEventListener("canplay", onMeta, { once: true });
2825
2860
  }
2826
2861
  } else if (isAudio) {
2862
+ const audioCard = document.createElement("div");
2863
+ audioCard.className = "fp-audio-card";
2864
+ const artWrapper = document.createElement("div");
2865
+ artWrapper.className = "fp-audio-artwork-wrapper";
2866
+ const disc = document.createElement("div");
2867
+ disc.className = "fp-audio-disc";
2868
+ const discCenter = document.createElement("div");
2869
+ discCenter.className = "fp-audio-disc-center";
2870
+ const discHole = document.createElement("div");
2871
+ discHole.className = "fp-audio-disc-hole";
2872
+ discCenter.appendChild(discHole);
2873
+ disc.appendChild(discCenter);
2874
+ artWrapper.appendChild(disc);
2875
+ audioCard.appendChild(artWrapper);
2876
+ const info = document.createElement("div");
2877
+ info.className = "fp-audio-info";
2878
+ const title = document.createElement("div");
2879
+ title.className = "fp-audio-title";
2880
+ title.textContent = ctx.metadata.name || "Audio Track";
2881
+ const badges = document.createElement("div");
2882
+ badges.className = "fp-audio-badges";
2883
+ const extTag = document.createElement("span");
2884
+ extTag.className = "fp-audio-ext-tag";
2885
+ const cleanExt = (ext || ".mp3").replace(".", "").toUpperCase();
2886
+ extTag.textContent = `${cleanExt} AUDIO`;
2887
+ badges.appendChild(extTag);
2888
+ const timeTag = document.createElement("span");
2889
+ timeTag.className = "fp-audio-time-tag";
2890
+ timeTag.textContent = "0:00";
2891
+ badges.appendChild(timeTag);
2892
+ info.appendChild(title);
2893
+ info.appendChild(badges);
2894
+ audioCard.appendChild(info);
2895
+ const waveform = document.createElement("div");
2896
+ waveform.className = "fp-audio-waveform";
2897
+ for (let i = 0; i < 16; i++) {
2898
+ const bar = document.createElement("div");
2899
+ bar.className = "fp-audio-wave-bar";
2900
+ waveform.appendChild(bar);
2901
+ }
2902
+ audioCard.appendChild(waveform);
2903
+ const nativeWrapper = document.createElement("div");
2904
+ nativeWrapper.className = "fp-audio-native-wrapper";
2827
2905
  const audio = document.createElement("audio");
2828
2906
  audio.src = url;
2829
2907
  audio.controls = true;
2830
- element = audio;
2908
+ nativeWrapper.appendChild(audio);
2909
+ audioCard.appendChild(nativeWrapper);
2910
+ const onPlay = () => {
2911
+ disc.classList.add("playing");
2912
+ waveform.classList.add("playing");
2913
+ };
2914
+ const onPause = () => {
2915
+ disc.classList.remove("playing");
2916
+ waveform.classList.remove("playing");
2917
+ };
2918
+ const formatTime = (secs) => {
2919
+ if (!isFinite(secs) || isNaN(secs)) return "0:00";
2920
+ const m = Math.floor(secs / 60);
2921
+ const s = Math.floor(secs % 60);
2922
+ return `${m}:${s < 10 ? "0" : ""}${s}`;
2923
+ };
2924
+ const onTimeUpdate = () => {
2925
+ timeTag.textContent = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
2926
+ };
2927
+ const onLoadedMetadata = () => {
2928
+ timeTag.textContent = `0:00 / ${formatTime(audio.duration)}`;
2929
+ };
2930
+ audio.addEventListener("play", onPlay);
2931
+ audio.addEventListener("pause", onPause);
2932
+ audio.addEventListener("timeupdate", onTimeUpdate);
2933
+ audio.addEventListener("loadedmetadata", onLoadedMetadata);
2934
+ element = audioCard;
2831
2935
  mediaElement = audio;
2832
2936
  } else {
2833
2937
  element = document.createElement("div");
@@ -2837,11 +2941,12 @@ var MediaPlugin = class {
2837
2941
  scrollWrapper.className = "fp-media-scroll-wrapper";
2838
2942
  scrollWrapper.style.minWidth = "100%";
2839
2943
  scrollWrapper.style.minHeight = "100%";
2840
- scrollWrapper.style.width = "max-content";
2841
- scrollWrapper.style.height = "max-content";
2944
+ scrollWrapper.style.width = isAudio ? "100%" : "max-content";
2945
+ scrollWrapper.style.height = isAudio ? "100%" : "max-content";
2842
2946
  scrollWrapper.style.display = "flex";
2843
2947
  scrollWrapper.style.flexDirection = "column";
2844
2948
  scrollWrapper.style.alignItems = "center";
2949
+ scrollWrapper.style.justifyContent = isAudio ? "center" : "flex-start";
2845
2950
  scrollWrapper.style.padding = "16px";
2846
2951
  scrollWrapper.style.boxSizing = "border-box";
2847
2952
  const sizer = document.createElement("div");
@@ -2852,6 +2957,11 @@ var MediaPlugin = class {
2852
2957
  sizer.style.justifyContent = "center";
2853
2958
  sizer.style.alignItems = "center";
2854
2959
  sizer.style.margin = "auto 0";
2960
+ if (isAudio) {
2961
+ sizer.style.width = "100%";
2962
+ sizer.style.maxWidth = "520px";
2963
+ sizer.style.margin = "auto";
2964
+ }
2855
2965
  sizer.appendChild(element);
2856
2966
  scrollWrapper.appendChild(sizer);
2857
2967
  ctx.container.style.overflow = "auto";
@@ -2910,7 +3020,9 @@ var MediaPlugin = class {
2910
3020
  element.style.transformOrigin = "center center";
2911
3021
  element.style.flexShrink = "0";
2912
3022
  } else {
2913
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
3023
+ if (!isAudio) {
3024
+ element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
3025
+ }
2914
3026
  }
2915
3027
  };
2916
3028
  updateBaseDimensions();
@@ -2936,6 +3048,10 @@ var MediaPlugin = class {
2936
3048
  ro?.observe(ctx.container);
2937
3049
  const cleanup = () => {
2938
3050
  ro?.disconnect();
3051
+ if (mediaElement) {
3052
+ mediaElement.pause();
3053
+ mediaElement.src = "";
3054
+ }
2939
3055
  if (url) URL.revokeObjectURL(url);
2940
3056
  scrollWrapper.remove();
2941
3057
  ctx.container.innerHTML = "";
@@ -2959,36 +3075,54 @@ var MediaPlugin = class {
2959
3075
  currentZoom = level;
2960
3076
  applyTransform();
2961
3077
  } : void 0,
2962
- fitToPage: isImage || isVideo ? () => {
2963
- isUserZoomed = false;
2964
- fitMode = "page";
2965
- currentZoom = 1;
2966
- rotation = 0;
2967
- ctx.container.scrollTop = 0;
2968
- ctx.container.scrollLeft = 0;
2969
- updateBaseDimensions();
2970
- applyTransform();
2971
- } : void 0,
2972
- fitToWidth: isImage || isVideo ? () => {
2973
- isUserZoomed = false;
2974
- fitMode = "width";
2975
- currentZoom = 1;
2976
- rotation = 0;
2977
- ctx.container.scrollTop = 0;
2978
- ctx.container.scrollLeft = 0;
2979
- updateBaseDimensions();
2980
- applyTransform();
2981
- } : void 0,
2982
- resetZoom: isImage || isVideo ? () => {
2983
- isUserZoomed = false;
2984
- fitMode = ctx?.options?.fitMode || "width";
2985
- currentZoom = 1;
2986
- rotation = 0;
2987
- ctx.container.scrollTop = 0;
2988
- ctx.container.scrollLeft = 0;
2989
- updateBaseDimensions();
2990
- applyTransform();
2991
- } : void 0,
3078
+ fitToPage: () => {
3079
+ if (isImage || isVideo) {
3080
+ isUserZoomed = false;
3081
+ fitMode = "page";
3082
+ currentZoom = 1;
3083
+ rotation = 0;
3084
+ ctx.container.scrollTop = 0;
3085
+ ctx.container.scrollLeft = 0;
3086
+ updateBaseDimensions();
3087
+ applyTransform();
3088
+ } else if (isAudio) {
3089
+ ctx.container.scrollTop = 0;
3090
+ ctx.container.scrollLeft = 0;
3091
+ currentZoom = 1;
3092
+ }
3093
+ },
3094
+ fitToWidth: () => {
3095
+ if (isImage || isVideo) {
3096
+ isUserZoomed = false;
3097
+ fitMode = "width";
3098
+ currentZoom = 1;
3099
+ rotation = 0;
3100
+ ctx.container.scrollTop = 0;
3101
+ ctx.container.scrollLeft = 0;
3102
+ updateBaseDimensions();
3103
+ applyTransform();
3104
+ } else if (isAudio) {
3105
+ ctx.container.scrollTop = 0;
3106
+ ctx.container.scrollLeft = 0;
3107
+ currentZoom = 1;
3108
+ }
3109
+ },
3110
+ resetZoom: () => {
3111
+ if (isImage || isVideo) {
3112
+ isUserZoomed = false;
3113
+ fitMode = ctx?.options?.fitMode || "width";
3114
+ currentZoom = 1;
3115
+ rotation = 0;
3116
+ ctx.container.scrollTop = 0;
3117
+ ctx.container.scrollLeft = 0;
3118
+ updateBaseDimensions();
3119
+ applyTransform();
3120
+ } else if (isAudio) {
3121
+ ctx.container.scrollTop = 0;
3122
+ ctx.container.scrollLeft = 0;
3123
+ currentZoom = 1;
3124
+ }
3125
+ },
2992
3126
  rotateCW: isImage || isVideo ? () => {
2993
3127
  rotation = (rotation + 90) % 360;
2994
3128
  applyTransform();