@files-preview-app/preview-file 1.3.11 → 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/index.cjs CHANGED
@@ -198,6 +198,10 @@ var EXTENSION_MIME_MAP = {
198
198
  ".wav": "audio/wav",
199
199
  ".aac": "audio/aac",
200
200
  ".flac": "audio/flac",
201
+ ".m4a": "audio/mp4",
202
+ ".wma": "audio/x-ms-wma",
203
+ ".opus": "audio/opus",
204
+ ".weba": "audio/webm",
201
205
  // Code/Text
202
206
  ".txt": "text/plain",
203
207
  ".log": "text/plain",
@@ -609,6 +613,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
609
613
  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>`;
610
614
  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>`;
611
615
  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>`;
616
+ 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>`;
612
617
  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>`;
613
618
  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>`;
614
619
  var ICON_MAP = {
@@ -643,7 +648,8 @@ var ICON_MAP = {
643
648
  "openSeparateWindow": ICON_EXTERNAL_WINDOW,
644
649
  "reset-zoom": ICON_RESET_ZOOM,
645
650
  "zoom-reset": ICON_RESET_ZOOM,
646
- "resetZoom": ICON_RESET_ZOOM
651
+ "resetZoom": ICON_RESET_ZOOM,
652
+ "speed": ICON_SPEED
647
653
  };
648
654
  var ToolbarController = class {
649
655
  el;
@@ -2777,13 +2783,42 @@ var MediaPlugin = class {
2777
2783
  }
2778
2784
  });
2779
2785
  }
2786
+ actions.push({
2787
+ id: "open-window",
2788
+ icon: "open-window",
2789
+ label: "Open in Separate Full Window",
2790
+ type: "button",
2791
+ group: "actions",
2792
+ execute: () => {
2793
+ instance.openInSeparateWindow?.();
2794
+ }
2795
+ });
2780
2796
  return actions;
2781
2797
  }
2782
2798
  async render(ctx) {
2783
- const mimeType = ctx.metadata.mimeType || "application/octet-stream";
2784
- const isImage = mimeType.startsWith("image/") || IMAGE_EXTS.includes(ctx.metadata.extension || "");
2785
- const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2786
- const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2799
+ const ext = (ctx.metadata.extension || "").toLowerCase();
2800
+ let mimeType = ctx.metadata.mimeType || "";
2801
+ if (!mimeType || mimeType === "application/octet-stream") {
2802
+ const audioMimes = {
2803
+ ".mp3": "audio/mpeg",
2804
+ ".wav": "audio/wav",
2805
+ ".ogg": "audio/ogg",
2806
+ ".flac": "audio/flac",
2807
+ ".aac": "audio/aac",
2808
+ ".m4a": "audio/mp4",
2809
+ ".wma": "audio/x-ms-wma",
2810
+ ".opus": "audio/opus",
2811
+ ".weba": "audio/webm"
2812
+ };
2813
+ if (audioMimes[ext]) {
2814
+ mimeType = audioMimes[ext];
2815
+ } else {
2816
+ mimeType = "application/octet-stream";
2817
+ }
2818
+ }
2819
+ const isImage = mimeType.startsWith("image/") || IMAGE_EXTS.includes(ext);
2820
+ const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ext);
2821
+ const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ext);
2787
2822
  let url = "";
2788
2823
  let naturalW = 800;
2789
2824
  let naturalH = 600;
@@ -2855,10 +2890,79 @@ var MediaPlugin = class {
2855
2890
  video.addEventListener("canplay", onMeta, { once: true });
2856
2891
  }
2857
2892
  } else if (isAudio) {
2893
+ const audioCard = document.createElement("div");
2894
+ audioCard.className = "fp-audio-card";
2895
+ const artWrapper = document.createElement("div");
2896
+ artWrapper.className = "fp-audio-artwork-wrapper";
2897
+ const disc = document.createElement("div");
2898
+ disc.className = "fp-audio-disc";
2899
+ const discCenter = document.createElement("div");
2900
+ discCenter.className = "fp-audio-disc-center";
2901
+ const discHole = document.createElement("div");
2902
+ discHole.className = "fp-audio-disc-hole";
2903
+ discCenter.appendChild(discHole);
2904
+ disc.appendChild(discCenter);
2905
+ artWrapper.appendChild(disc);
2906
+ audioCard.appendChild(artWrapper);
2907
+ const info = document.createElement("div");
2908
+ info.className = "fp-audio-info";
2909
+ const title = document.createElement("div");
2910
+ title.className = "fp-audio-title";
2911
+ title.textContent = ctx.metadata.name || "Audio Track";
2912
+ const badges = document.createElement("div");
2913
+ badges.className = "fp-audio-badges";
2914
+ const extTag = document.createElement("span");
2915
+ extTag.className = "fp-audio-ext-tag";
2916
+ const cleanExt = (ext || ".mp3").replace(".", "").toUpperCase();
2917
+ extTag.textContent = `${cleanExt} AUDIO`;
2918
+ badges.appendChild(extTag);
2919
+ const timeTag = document.createElement("span");
2920
+ timeTag.className = "fp-audio-time-tag";
2921
+ timeTag.textContent = "0:00";
2922
+ badges.appendChild(timeTag);
2923
+ info.appendChild(title);
2924
+ info.appendChild(badges);
2925
+ audioCard.appendChild(info);
2926
+ const waveform = document.createElement("div");
2927
+ waveform.className = "fp-audio-waveform";
2928
+ for (let i = 0; i < 16; i++) {
2929
+ const bar = document.createElement("div");
2930
+ bar.className = "fp-audio-wave-bar";
2931
+ waveform.appendChild(bar);
2932
+ }
2933
+ audioCard.appendChild(waveform);
2934
+ const nativeWrapper = document.createElement("div");
2935
+ nativeWrapper.className = "fp-audio-native-wrapper";
2858
2936
  const audio = document.createElement("audio");
2859
2937
  audio.src = url;
2860
2938
  audio.controls = true;
2861
- element = audio;
2939
+ nativeWrapper.appendChild(audio);
2940
+ audioCard.appendChild(nativeWrapper);
2941
+ const onPlay = () => {
2942
+ disc.classList.add("playing");
2943
+ waveform.classList.add("playing");
2944
+ };
2945
+ const onPause = () => {
2946
+ disc.classList.remove("playing");
2947
+ waveform.classList.remove("playing");
2948
+ };
2949
+ const formatTime = (secs) => {
2950
+ if (!isFinite(secs) || isNaN(secs)) return "0:00";
2951
+ const m = Math.floor(secs / 60);
2952
+ const s = Math.floor(secs % 60);
2953
+ return `${m}:${s < 10 ? "0" : ""}${s}`;
2954
+ };
2955
+ const onTimeUpdate = () => {
2956
+ timeTag.textContent = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
2957
+ };
2958
+ const onLoadedMetadata = () => {
2959
+ timeTag.textContent = `0:00 / ${formatTime(audio.duration)}`;
2960
+ };
2961
+ audio.addEventListener("play", onPlay);
2962
+ audio.addEventListener("pause", onPause);
2963
+ audio.addEventListener("timeupdate", onTimeUpdate);
2964
+ audio.addEventListener("loadedmetadata", onLoadedMetadata);
2965
+ element = audioCard;
2862
2966
  mediaElement = audio;
2863
2967
  } else {
2864
2968
  element = document.createElement("div");
@@ -2868,11 +2972,12 @@ var MediaPlugin = class {
2868
2972
  scrollWrapper.className = "fp-media-scroll-wrapper";
2869
2973
  scrollWrapper.style.minWidth = "100%";
2870
2974
  scrollWrapper.style.minHeight = "100%";
2871
- scrollWrapper.style.width = "max-content";
2872
- scrollWrapper.style.height = "max-content";
2975
+ scrollWrapper.style.width = isAudio ? "100%" : "max-content";
2976
+ scrollWrapper.style.height = isAudio ? "100%" : "max-content";
2873
2977
  scrollWrapper.style.display = "flex";
2874
2978
  scrollWrapper.style.flexDirection = "column";
2875
2979
  scrollWrapper.style.alignItems = "center";
2980
+ scrollWrapper.style.justifyContent = isAudio ? "center" : "flex-start";
2876
2981
  scrollWrapper.style.padding = "16px";
2877
2982
  scrollWrapper.style.boxSizing = "border-box";
2878
2983
  const sizer = document.createElement("div");
@@ -2883,6 +2988,11 @@ var MediaPlugin = class {
2883
2988
  sizer.style.justifyContent = "center";
2884
2989
  sizer.style.alignItems = "center";
2885
2990
  sizer.style.margin = "auto 0";
2991
+ if (isAudio) {
2992
+ sizer.style.width = "100%";
2993
+ sizer.style.maxWidth = "520px";
2994
+ sizer.style.margin = "auto";
2995
+ }
2886
2996
  sizer.appendChild(element);
2887
2997
  scrollWrapper.appendChild(sizer);
2888
2998
  ctx.container.style.overflow = "auto";
@@ -2941,7 +3051,9 @@ var MediaPlugin = class {
2941
3051
  element.style.transformOrigin = "center center";
2942
3052
  element.style.flexShrink = "0";
2943
3053
  } else {
2944
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
3054
+ if (!isAudio) {
3055
+ element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
3056
+ }
2945
3057
  }
2946
3058
  };
2947
3059
  updateBaseDimensions();
@@ -2967,6 +3079,10 @@ var MediaPlugin = class {
2967
3079
  ro?.observe(ctx.container);
2968
3080
  const cleanup = () => {
2969
3081
  ro?.disconnect();
3082
+ if (mediaElement) {
3083
+ mediaElement.pause();
3084
+ mediaElement.src = "";
3085
+ }
2970
3086
  if (url) URL.revokeObjectURL(url);
2971
3087
  scrollWrapper.remove();
2972
3088
  ctx.container.innerHTML = "";
@@ -2990,36 +3106,54 @@ var MediaPlugin = class {
2990
3106
  currentZoom = level;
2991
3107
  applyTransform();
2992
3108
  } : void 0,
2993
- fitToPage: isImage || isVideo ? () => {
2994
- isUserZoomed = false;
2995
- fitMode = "page";
2996
- currentZoom = 1;
2997
- rotation = 0;
2998
- ctx.container.scrollTop = 0;
2999
- ctx.container.scrollLeft = 0;
3000
- updateBaseDimensions();
3001
- applyTransform();
3002
- } : void 0,
3003
- fitToWidth: isImage || isVideo ? () => {
3004
- isUserZoomed = false;
3005
- fitMode = "width";
3006
- currentZoom = 1;
3007
- rotation = 0;
3008
- ctx.container.scrollTop = 0;
3009
- ctx.container.scrollLeft = 0;
3010
- updateBaseDimensions();
3011
- applyTransform();
3012
- } : void 0,
3013
- resetZoom: isImage || isVideo ? () => {
3014
- isUserZoomed = false;
3015
- fitMode = ctx?.options?.fitMode || "width";
3016
- currentZoom = 1;
3017
- rotation = 0;
3018
- ctx.container.scrollTop = 0;
3019
- ctx.container.scrollLeft = 0;
3020
- updateBaseDimensions();
3021
- applyTransform();
3022
- } : void 0,
3109
+ fitToPage: () => {
3110
+ if (isImage || isVideo) {
3111
+ isUserZoomed = false;
3112
+ fitMode = "page";
3113
+ currentZoom = 1;
3114
+ rotation = 0;
3115
+ ctx.container.scrollTop = 0;
3116
+ ctx.container.scrollLeft = 0;
3117
+ updateBaseDimensions();
3118
+ applyTransform();
3119
+ } else if (isAudio) {
3120
+ ctx.container.scrollTop = 0;
3121
+ ctx.container.scrollLeft = 0;
3122
+ currentZoom = 1;
3123
+ }
3124
+ },
3125
+ fitToWidth: () => {
3126
+ if (isImage || isVideo) {
3127
+ isUserZoomed = false;
3128
+ fitMode = "width";
3129
+ currentZoom = 1;
3130
+ rotation = 0;
3131
+ ctx.container.scrollTop = 0;
3132
+ ctx.container.scrollLeft = 0;
3133
+ updateBaseDimensions();
3134
+ applyTransform();
3135
+ } else if (isAudio) {
3136
+ ctx.container.scrollTop = 0;
3137
+ ctx.container.scrollLeft = 0;
3138
+ currentZoom = 1;
3139
+ }
3140
+ },
3141
+ resetZoom: () => {
3142
+ if (isImage || isVideo) {
3143
+ isUserZoomed = false;
3144
+ fitMode = ctx?.options?.fitMode || "width";
3145
+ currentZoom = 1;
3146
+ rotation = 0;
3147
+ ctx.container.scrollTop = 0;
3148
+ ctx.container.scrollLeft = 0;
3149
+ updateBaseDimensions();
3150
+ applyTransform();
3151
+ } else if (isAudio) {
3152
+ ctx.container.scrollTop = 0;
3153
+ ctx.container.scrollLeft = 0;
3154
+ currentZoom = 1;
3155
+ }
3156
+ },
3023
3157
  rotateCW: isImage || isVideo ? () => {
3024
3158
  rotation = (rotation + 90) % 360;
3025
3159
  applyTransform();
@@ -6149,6 +6283,16 @@ var ThreeDPlugin = class {
6149
6283
  type: "button",
6150
6284
  group: "actions",
6151
6285
  execute: () => instance.download?.()
6286
+ },
6287
+ {
6288
+ id: "open-window",
6289
+ icon: "open-window",
6290
+ label: "Open in Separate Full Window",
6291
+ type: "button",
6292
+ group: "actions",
6293
+ execute: () => {
6294
+ instance.openInSeparateWindow?.();
6295
+ }
6152
6296
  }
6153
6297
  ];
6154
6298
  }
@@ -6219,12 +6363,21 @@ var ThreeDPlugin = class {
6219
6363
  });
6220
6364
  meshGroup.add(obj);
6221
6365
  }
6366
+ const initialBox = new THREE__namespace.Box3().setFromObject(meshGroup);
6367
+ const center = initialBox.getCenter(new THREE__namespace.Vector3());
6368
+ meshGroup.position.sub(center);
6222
6369
  scene.add(meshGroup);
6223
6370
  const box = new THREE__namespace.Box3().setFromObject(meshGroup);
6224
- const sphere = box.getBoundingSphere(new THREE__namespace.Sphere());
6225
- const radius = Math.max(sphere.radius, 10);
6371
+ const size = box.getSize(new THREE__namespace.Vector3());
6372
+ const maxDim = Math.max(size.x, size.y, size.z) || 10;
6373
+ grid.position.y = -size.y / 2;
6374
+ const gridScale = Math.max(0.1, maxDim / 50);
6375
+ grid.scale.set(gridScale, 1, gridScale);
6376
+ const fovRad = camera.fov * (Math.PI / 180);
6377
+ let cameraDistance = maxDim / 2 / Math.tan(fovRad / 2);
6378
+ cameraDistance = Math.max(cameraDistance * 1.5, 2);
6226
6379
  const fitCamera = () => {
6227
- camera.position.set(radius * 1.5, radius * 1.2, radius * 2);
6380
+ camera.position.set(cameraDistance * 0.8, cameraDistance * 0.6, cameraDistance);
6228
6381
  camera.lookAt(0, 0, 0);
6229
6382
  controls.target.set(0, 0, 0);
6230
6383
  controls.update();
@@ -6270,6 +6423,7 @@ var ThreeDPlugin = class {
6270
6423
  controls.update();
6271
6424
  },
6272
6425
  fitToPage: fitCamera,
6426
+ fitToWidth: fitCamera,
6273
6427
  resetZoom: fitCamera,
6274
6428
  rotateCW: () => {
6275
6429
  isWireframe = !isWireframe;