@burdenoff/microfe-files 2026.830.1 → 2026.830.2

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.
Files changed (33) hide show
  1. package/dist/files/FilesRoot.d.ts.map +1 -1
  2. package/dist/files/FilesRoot.js +42 -37
  3. package/dist/files/FilesRoot.js.map +1 -1
  4. package/dist/files/components/StorageBanner.d.ts.map +1 -1
  5. package/dist/files/components/StorageBanner.js +50 -41
  6. package/dist/files/components/StorageBanner.js.map +1 -1
  7. package/dist/files/components/viewers/AudioPlayer.d.ts.map +1 -1
  8. package/dist/files/components/viewers/AudioPlayer.js +59 -58
  9. package/dist/files/components/viewers/AudioPlayer.js.map +1 -1
  10. package/dist/files/components/viewers/CodeViewer.d.ts.map +1 -1
  11. package/dist/files/components/viewers/CodeViewer.js +49 -44
  12. package/dist/files/components/viewers/CodeViewer.js.map +1 -1
  13. package/dist/files/components/viewers/ImageViewer.d.ts.map +1 -1
  14. package/dist/files/components/viewers/ImageViewer.js +75 -74
  15. package/dist/files/components/viewers/ImageViewer.js.map +1 -1
  16. package/dist/files/components/viewers/PDFViewer.d.ts.map +1 -1
  17. package/dist/files/components/viewers/PDFViewer.js +44 -41
  18. package/dist/files/components/viewers/PDFViewer.js.map +1 -1
  19. package/dist/files/components/viewers/TextViewer.d.ts.map +1 -1
  20. package/dist/files/components/viewers/TextViewer.js +77 -72
  21. package/dist/files/components/viewers/TextViewer.js.map +1 -1
  22. package/dist/files/components/viewers/VideoPlayer.d.ts.map +1 -1
  23. package/dist/files/components/viewers/VideoPlayer.js +75 -74
  24. package/dist/files/components/viewers/VideoPlayer.js.map +1 -1
  25. package/dist/shared/hooks/useTr.d.ts +17 -0
  26. package/dist/shared/hooks/useTr.d.ts.map +1 -0
  27. package/dist/shared/hooks/useTr.js +14 -0
  28. package/dist/shared/hooks/useTr.js.map +1 -0
  29. package/dist/translations/en.d.ts +85 -0
  30. package/dist/translations/en.d.ts.map +1 -1
  31. package/dist/translations/en.js +84 -1
  32. package/dist/translations/en.js.map +1 -1
  33. package/package.json +1 -1
@@ -1,86 +1,91 @@
1
- import { useEffect as e, useState as t } from "react";
2
- import { Check as n, Copy as r, WrapText as i } from "lucide-react";
3
- import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
1
+ import { useTr as e } from "../../../shared/hooks/useTr.js";
2
+ import { useEffect as t, useState as n } from "react";
3
+ import { Check as r, Copy as i, WrapText as a } from "lucide-react";
4
+ import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
4
5
  //#region src/files/components/viewers/CodeViewer.tsx
5
- function c({ file: c, url: u, language: d }) {
6
- let [f, p] = t(""), [m, h] = t(!0), [g, _] = t(!1), [v, y] = t(!1), b = d || l(c.name);
7
- return e(() => {
8
- fetch(u).then((e) => e.text()).then((e) => {
9
- p(e), h(!1);
6
+ function l({ file: l, url: d, language: f }) {
7
+ let p = e(), [m, h] = n(""), [g, _] = n(!0), [v, y] = n(!1), [b, x] = n(!1), S = f || u(l.name);
8
+ return t(() => {
9
+ fetch(d).then((e) => e.text()).then((e) => {
10
+ h(e), _(!1);
10
11
  }).catch(() => {
11
- h(!1);
12
+ _(!1);
12
13
  });
13
- }, [u]), e(() => {
14
- if (v) {
15
- let e = setTimeout(() => y(!1), 2e3);
14
+ }, [d]), t(() => {
15
+ if (b) {
16
+ let e = setTimeout(() => x(!1), 2e3);
16
17
  return () => clearTimeout(e);
17
18
  }
18
- }, [v]), m ? /* @__PURE__ */ o("div", {
19
+ }, [b]), g ? /* @__PURE__ */ s("div", {
19
20
  className: "flex items-center justify-center h-full bg-bg-canvas",
20
- children: /* @__PURE__ */ o("span", {
21
+ children: /* @__PURE__ */ s("span", {
21
22
  className: "text-text-secondary",
22
- children: "Loading code..."
23
+ children: p("files.preview.code.loading", "Loading code...")
23
24
  })
24
- }) : /* @__PURE__ */ s("div", {
25
+ }) : /* @__PURE__ */ c("div", {
25
26
  className: "flex flex-col h-full bg-bg-canvas",
26
27
  children: [
27
- /* @__PURE__ */ s("div", {
28
+ /* @__PURE__ */ c("div", {
28
29
  className: "flex items-center justify-between p-3 bg-bg-surface border-b border-border-default",
29
- children: [/* @__PURE__ */ s("div", {
30
+ children: [/* @__PURE__ */ c("div", {
30
31
  className: "flex items-center gap-2",
31
- children: [/* @__PURE__ */ o("span", {
32
+ children: [/* @__PURE__ */ s("span", {
32
33
  className: "px-2 py-1 text-xs font-medium text-text-link bg-bg-accent rounded",
33
- children: b || "Text"
34
- }), /* @__PURE__ */ o("span", {
34
+ children: S || p("files.preview.code.text", "Text")
35
+ }), /* @__PURE__ */ s("span", {
35
36
  className: "text-sm text-text-secondary",
36
- children: c.name
37
+ children: l.name
37
38
  })]
38
- }), /* @__PURE__ */ s("div", {
39
+ }), /* @__PURE__ */ c("div", {
39
40
  className: "flex items-center gap-2",
40
- children: [/* @__PURE__ */ o("button", {
41
+ children: [/* @__PURE__ */ s("button", {
41
42
  type: "button",
42
- onClick: () => _(!g),
43
- className: `p-2 rounded transition-colors duration-200 ${g ? "text-text-link bg-bg-accent" : "text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover"}`,
44
- title: g ? "Disable word wrap" : "Enable word wrap",
45
- "aria-label": g ? "Disable word wrap" : "Enable word wrap",
46
- children: /* @__PURE__ */ o(i, { className: "size-4" })
47
- }), /* @__PURE__ */ o("button", {
43
+ onClick: () => y(!v),
44
+ className: `p-2 rounded transition-colors duration-200 ${v ? "text-text-link bg-bg-accent" : "text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover"}`,
45
+ title: v ? p("files.preview.code.disableWordWrap", "Disable word wrap") : p("files.preview.code.enableWordWrap", "Enable word wrap"),
46
+ "aria-label": v ? p("files.preview.code.disableWordWrap", "Disable word wrap") : p("files.preview.code.enableWordWrap", "Enable word wrap"),
47
+ children: /* @__PURE__ */ s(a, { className: "size-4" })
48
+ }), /* @__PURE__ */ s("button", {
48
49
  type: "button",
49
50
  onClick: () => {
50
- navigator.clipboard.writeText(f), y(!0);
51
+ navigator.clipboard.writeText(m), x(!0);
51
52
  },
52
53
  className: "flex items-center gap-1.5 rounded px-3 py-1.5 text-sm font-medium text-text-inverse bg-action-primary-bg transition-colors duration-200 hover:bg-action-primary-bg-hover",
53
- title: "Copy code",
54
- "aria-label": "Copy code content",
55
- children: v ? /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o(n, { className: "size-4" }), "Copied!"] }) : /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o(r, { className: "size-4" }), "Copy"] })
54
+ title: p("files.preview.code.copyCode", "Copy code"),
55
+ "aria-label": p("files.preview.code.copyCodeContent", "Copy code content"),
56
+ children: b ? /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s(r, { className: "size-4" }), p("files.preview.code.copied", "Copied!")] }) : /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s(i, { className: "size-4" }), p("files.preview.code.copy", "Copy")] })
56
57
  })]
57
58
  })]
58
59
  }),
59
- /* @__PURE__ */ o("div", {
60
+ /* @__PURE__ */ s("div", {
60
61
  className: "flex-1 overflow-auto",
61
- children: /* @__PURE__ */ o("pre", {
62
- className: `p-4 text-sm font-mono leading-relaxed ${g ? "whitespace-pre-wrap" : "whitespace-pre"}`,
62
+ children: /* @__PURE__ */ s("pre", {
63
+ className: `p-4 text-sm font-mono leading-relaxed ${v ? "whitespace-pre-wrap" : "whitespace-pre"}`,
63
64
  style: { tabSize: 2 },
64
- children: f.split("\n").map((e, t) => /* @__PURE__ */ s("div", {
65
+ children: m.split("\n").map((e, t) => /* @__PURE__ */ c("div", {
65
66
  className: "flex",
66
- children: [/* @__PURE__ */ o("span", {
67
+ children: [/* @__PURE__ */ s("span", {
67
68
  className: "inline-block w-12 text-right pr-4 text-text-tertiary select-none",
68
69
  children: t + 1
69
- }), /* @__PURE__ */ o("span", {
70
+ }), /* @__PURE__ */ s("span", {
70
71
  className: "text-text-primary",
71
72
  children: e || " "
72
73
  })]
73
74
  }, t))
74
75
  })
75
76
  }),
76
- /* @__PURE__ */ s("div", {
77
+ /* @__PURE__ */ c("div", {
77
78
  className: "flex items-center justify-between p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary",
78
- children: [/* @__PURE__ */ s("span", { children: [f.split("\n").length, " lines"] }), /* @__PURE__ */ s("span", { children: [(c.size / 1024).toFixed(2), " KB"] })]
79
+ children: [/* @__PURE__ */ c("span", { children: [
80
+ m.split("\n").length,
81
+ " ",
82
+ p("files.preview.code.lines", "lines")
83
+ ] }), /* @__PURE__ */ c("span", { children: [(l.size / 1024).toFixed(2), " KB"] })]
79
84
  })
80
85
  ]
81
86
  });
82
87
  }
83
- function l(e) {
88
+ function u(e) {
84
89
  return {
85
90
  js: "JavaScript",
86
91
  jsx: "React JSX",
@@ -115,6 +120,6 @@ function l(e) {
115
120
  }[e.split(".").pop()?.toLowerCase() || ""] || "Text";
116
121
  }
117
122
  //#endregion
118
- export { c as CodeViewer };
123
+ export { l as CodeViewer };
119
124
 
120
125
  //# sourceMappingURL=CodeViewer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodeViewer.js","names":[],"sources":["../../../../src/files/components/viewers/CodeViewer.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { Copy, Check, WrapText } from \"lucide-react\";\nimport type { FileItem } from \"../../types\";\n\ninterface CodeViewerProps {\n file: FileItem;\n url: string;\n language?: string;\n}\n\n/**\n * CodeViewer - Displays code files with syntax highlighting\n *\n * Note: This is a simplified implementation with basic highlighting.\n * For full syntax highlighting, install prism-react-renderer:\n * bun add prism-react-renderer\n */\nexport function CodeViewer({ file, url, language }: CodeViewerProps) {\n const [code, setCode] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [wordWrap, setWordWrap] = useState(false);\n const [copied, setCopied] = useState(false);\n\n const detectedLanguage = language || detectLanguage(file.name);\n\n useEffect(() => {\n fetch(url)\n .then((res) => res.text())\n .then((text) => {\n setCode(text);\n setLoading(false);\n })\n .catch(() => {\n setLoading(false);\n });\n }, [url]);\n\n const handleCopy = () => {\n navigator.clipboard.writeText(code);\n setCopied(true);\n };\n\n // Cleanup timeout on unmount to prevent React state update warning\n useEffect(() => {\n if (copied) {\n const timer = setTimeout(() => setCopied(false), 2000);\n return () => clearTimeout(timer);\n }\n return undefined;\n }, [copied]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full bg-bg-canvas\">\n <span className=\"text-text-secondary\">Loading code...</span>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full bg-bg-canvas\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-between p-3 bg-bg-surface border-b border-border-default\">\n <div className=\"flex items-center gap-2\">\n <span className=\"px-2 py-1 text-xs font-medium text-text-link bg-bg-accent rounded\">\n {detectedLanguage || \"Text\"}\n </span>\n <span className=\"text-sm text-text-secondary\">{file.name}</span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setWordWrap(!wordWrap)}\n className={`p-2 rounded transition-colors duration-200 ${\n wordWrap\n ? \"text-text-link bg-bg-accent\"\n : \"text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover\"\n }`}\n title={wordWrap ? \"Disable word wrap\" : \"Enable word wrap\"}\n aria-label={wordWrap ? \"Disable word wrap\" : \"Enable word wrap\"}\n >\n <WrapText className=\"size-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"flex items-center gap-1.5 rounded px-3 py-1.5 text-sm font-medium text-text-inverse bg-action-primary-bg transition-colors duration-200 hover:bg-action-primary-bg-hover\"\n title=\"Copy code\"\n aria-label=\"Copy code content\"\n >\n {copied ? (\n <>\n <Check className=\"size-4\" />\n Copied!\n </>\n ) : (\n <>\n <Copy className=\"size-4\" />\n Copy\n </>\n )}\n </button>\n </div>\n </div>\n\n {/* Code Content */}\n <div className=\"flex-1 overflow-auto\">\n <pre\n className={`p-4 text-sm font-mono leading-relaxed ${\n wordWrap ? \"whitespace-pre-wrap\" : \"whitespace-pre\"\n }`}\n style={{ tabSize: 2 }}\n >\n {code.split(\"\\n\").map((line, i) => (\n <div key={i} className=\"flex\">\n <span className=\"inline-block w-12 text-right pr-4 text-text-tertiary select-none\">\n {i + 1}\n </span>\n <span className=\"text-text-primary\">{line || \" \"}</span>\n </div>\n ))}\n </pre>\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-between p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary\">\n <span>{code.split(\"\\n\").length} lines</span>\n <span>{(file.size / 1024).toFixed(2)} KB</span>\n </div>\n </div>\n );\n}\n\nfunction detectLanguage(filename: string): string {\n const ext = filename.split(\".\").pop()?.toLowerCase();\n const languageMap: Record<string, string> = {\n js: \"JavaScript\",\n jsx: \"React JSX\",\n ts: \"TypeScript\",\n tsx: \"React TSX\",\n py: \"Python\",\n java: \"Java\",\n cpp: \"C++\",\n c: \"C\",\n cs: \"C#\",\n rb: \"Ruby\",\n go: \"Go\",\n rs: \"Rust\",\n php: \"PHP\",\n html: \"HTML\",\n css: \"CSS\",\n scss: \"SCSS\",\n json: \"JSON\",\n md: \"Markdown\",\n yaml: \"YAML\",\n yml: \"YAML\",\n xml: \"XML\",\n sql: \"SQL\",\n sh: \"Shell\",\n bash: \"Bash\",\n vue: \"Vue\",\n swift: \"Swift\",\n kt: \"Kotlin\",\n r: \"R\",\n dart: \"Dart\",\n lua: \"Lua\",\n };\n return languageMap[ext || \"\"] || \"Text\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CodeViewer.js","names":[],"sources":["../../../../src/files/components/viewers/CodeViewer.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { Copy, Check, WrapText } from \"lucide-react\";\nimport type { FileItem } from \"../../types\";\nimport { useTr } from \"../../../shared/hooks/useTr\";\n\ninterface CodeViewerProps {\n file: FileItem;\n url: string;\n language?: string;\n}\n\n/**\n * CodeViewer - Displays code files with syntax highlighting\n *\n * Note: This is a simplified implementation with basic highlighting.\n * For full syntax highlighting, install prism-react-renderer:\n * bun add prism-react-renderer\n */\nexport function CodeViewer({ file, url, language }: CodeViewerProps) {\n const tr = useTr();\n const [code, setCode] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [wordWrap, setWordWrap] = useState(false);\n const [copied, setCopied] = useState(false);\n\n const detectedLanguage = language || detectLanguage(file.name);\n\n useEffect(() => {\n fetch(url)\n .then((res) => res.text())\n .then((text) => {\n setCode(text);\n setLoading(false);\n })\n .catch(() => {\n setLoading(false);\n });\n }, [url]);\n\n const handleCopy = () => {\n navigator.clipboard.writeText(code);\n setCopied(true);\n };\n\n // Cleanup timeout on unmount to prevent React state update warning\n useEffect(() => {\n if (copied) {\n const timer = setTimeout(() => setCopied(false), 2000);\n return () => clearTimeout(timer);\n }\n return undefined;\n }, [copied]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full bg-bg-canvas\">\n <span className=\"text-text-secondary\">\n {tr(\"files.preview.code.loading\", \"Loading code...\")}\n </span>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full bg-bg-canvas\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-between p-3 bg-bg-surface border-b border-border-default\">\n <div className=\"flex items-center gap-2\">\n <span className=\"px-2 py-1 text-xs font-medium text-text-link bg-bg-accent rounded\">\n {detectedLanguage || tr(\"files.preview.code.text\", \"Text\")}\n </span>\n <span className=\"text-sm text-text-secondary\">{file.name}</span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setWordWrap(!wordWrap)}\n className={`p-2 rounded transition-colors duration-200 ${\n wordWrap\n ? \"text-text-link bg-bg-accent\"\n : \"text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover\"\n }`}\n title={\n wordWrap\n ? tr(\"files.preview.code.disableWordWrap\", \"Disable word wrap\")\n : tr(\"files.preview.code.enableWordWrap\", \"Enable word wrap\")\n }\n aria-label={\n wordWrap\n ? tr(\"files.preview.code.disableWordWrap\", \"Disable word wrap\")\n : tr(\"files.preview.code.enableWordWrap\", \"Enable word wrap\")\n }\n >\n <WrapText className=\"size-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"flex items-center gap-1.5 rounded px-3 py-1.5 text-sm font-medium text-text-inverse bg-action-primary-bg transition-colors duration-200 hover:bg-action-primary-bg-hover\"\n title={tr(\"files.preview.code.copyCode\", \"Copy code\")}\n aria-label={tr(\n \"files.preview.code.copyCodeContent\",\n \"Copy code content\",\n )}\n >\n {copied ? (\n <>\n <Check className=\"size-4\" />\n {tr(\"files.preview.code.copied\", \"Copied!\")}\n </>\n ) : (\n <>\n <Copy className=\"size-4\" />\n {tr(\"files.preview.code.copy\", \"Copy\")}\n </>\n )}\n </button>\n </div>\n </div>\n\n {/* Code Content */}\n <div className=\"flex-1 overflow-auto\">\n <pre\n className={`p-4 text-sm font-mono leading-relaxed ${\n wordWrap ? \"whitespace-pre-wrap\" : \"whitespace-pre\"\n }`}\n style={{ tabSize: 2 }}\n >\n {code.split(\"\\n\").map((line, i) => (\n <div key={i} className=\"flex\">\n <span className=\"inline-block w-12 text-right pr-4 text-text-tertiary select-none\">\n {i + 1}\n </span>\n <span className=\"text-text-primary\">{line || \" \"}</span>\n </div>\n ))}\n </pre>\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-between p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary\">\n <span>\n {code.split(\"\\n\").length} {tr(\"files.preview.code.lines\", \"lines\")}\n </span>\n <span>{(file.size / 1024).toFixed(2)} KB</span>\n </div>\n </div>\n );\n}\n\nfunction detectLanguage(filename: string): string {\n const ext = filename.split(\".\").pop()?.toLowerCase();\n const languageMap: Record<string, string> = {\n js: \"JavaScript\",\n jsx: \"React JSX\",\n ts: \"TypeScript\",\n tsx: \"React TSX\",\n py: \"Python\",\n java: \"Java\",\n cpp: \"C++\",\n c: \"C\",\n cs: \"C#\",\n rb: \"Ruby\",\n go: \"Go\",\n rs: \"Rust\",\n php: \"PHP\",\n html: \"HTML\",\n css: \"CSS\",\n scss: \"SCSS\",\n json: \"JSON\",\n md: \"Markdown\",\n yaml: \"YAML\",\n yml: \"YAML\",\n xml: \"XML\",\n sql: \"SQL\",\n sh: \"Shell\",\n bash: \"Bash\",\n vue: \"Vue\",\n swift: \"Swift\",\n kt: \"Kotlin\",\n r: \"R\",\n dart: \"Dart\",\n lua: \"Lua\",\n };\n return languageMap[ext || \"\"] || \"Text\";\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImageViewer.d.ts","sourceRoot":"","sources":["../../../../src/files/components/viewers/ImageViewer.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,gBAAgB,+BAiK1D"}
1
+ {"version":3,"file":"ImageViewer.d.ts","sourceRoot":"","sources":["../../../../src/files/components/viewers/ImageViewer.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,gBAAgB,+BAoK1D"}
@@ -1,142 +1,143 @@
1
- import { useRef as e, useState as t } from "react";
2
- import { AlertCircle as n, Minimize2 as r, RotateCw as i, ZoomIn as a, ZoomOut as o } from "lucide-react";
3
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
1
+ import { useTr as e } from "../../../shared/hooks/useTr.js";
2
+ import { useRef as t, useState as n } from "react";
3
+ import { AlertCircle as r, Minimize2 as i, RotateCw as a, ZoomIn as o, ZoomOut as s } from "lucide-react";
4
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
4
5
  //#region src/files/components/viewers/ImageViewer.tsx
5
- function l({ file: l, url: u }) {
6
- let [d, f] = t(1), [p, m] = t(0), [h, g] = t({
6
+ function u({ file: u, url: d }) {
7
+ let f = e(), [p, m] = n(1), [h, g] = n(0), [_, v] = n({
7
8
  x: 0,
8
9
  y: 0
9
- }), [_, v] = t(!1), [y, b] = t({
10
+ }), [y, b] = n(!1), [x, S] = n({
10
11
  x: 0,
11
12
  y: 0
12
- }), [x, S] = t(null), C = e(null), [w, T] = t({
13
+ }), [C, w] = n(null), T = t(null), [E, D] = n({
13
14
  width: 0,
14
15
  height: 0
15
- }), E = () => f((e) => Math.min(e + .25, 4)), D = () => f((e) => Math.max(e - .25, .25)), O = () => {
16
- f(1), g({
16
+ }), O = () => m((e) => Math.min(e + .25, 4)), k = () => m((e) => Math.max(e - .25, .25)), A = () => {
17
+ m(1), v({
17
18
  x: 0,
18
19
  y: 0
19
- }), m(0);
20
- }, k = () => m((e) => (e + 90) % 360), A = (e) => {
21
- d > 1 && (v(!0), b({
22
- x: e.clientX - h.x,
23
- y: e.clientY - h.y
20
+ }), g(0);
21
+ }, j = () => g((e) => (e + 90) % 360), M = (e) => {
22
+ p > 1 && (b(!0), S({
23
+ x: e.clientX - _.x,
24
+ y: e.clientY - _.y
24
25
  }));
25
- }, j = (e) => {
26
- _ && d > 1 && g({
27
- x: e.clientX - y.x,
28
- y: e.clientY - y.y
26
+ }, N = (e) => {
27
+ y && p > 1 && v({
28
+ x: e.clientX - x.x,
29
+ y: e.clientY - x.y
29
30
  });
30
- }, M = () => {
31
- v(!1);
31
+ }, P = () => {
32
+ b(!1);
32
33
  };
33
- return /* @__PURE__ */ c("div", {
34
+ return /* @__PURE__ */ l("div", {
34
35
  className: "flex flex-col h-full bg-bg-canvas",
35
36
  children: [
36
- /* @__PURE__ */ c("div", {
37
+ /* @__PURE__ */ l("div", {
37
38
  className: "flex items-center justify-center gap-2 p-4 bg-bg-surface border-b border-border-default",
38
39
  children: [
39
- /* @__PURE__ */ s("button", {
40
+ /* @__PURE__ */ c("button", {
40
41
  type: "button",
41
- onClick: D,
42
- disabled: d <= .25,
42
+ onClick: k,
43
+ disabled: p <= .25,
43
44
  className: "p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
44
- title: "Zoom out",
45
- children: /* @__PURE__ */ s(o, { className: "size-5" })
45
+ title: f("files.preview.image.zoomOut", "Zoom out"),
46
+ children: /* @__PURE__ */ c(s, { className: "size-5" })
46
47
  }),
47
- /* @__PURE__ */ c("span", {
48
+ /* @__PURE__ */ l("span", {
48
49
  className: "min-w-16 text-center text-sm font-medium text-text-primary",
49
- children: [Math.round(d * 100), "%"]
50
+ children: [Math.round(p * 100), "%"]
50
51
  }),
51
- /* @__PURE__ */ s("button", {
52
+ /* @__PURE__ */ c("button", {
52
53
  type: "button",
53
- onClick: E,
54
- disabled: d >= 4,
54
+ onClick: O,
55
+ disabled: p >= 4,
55
56
  className: "p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
56
- title: "Zoom in",
57
- children: /* @__PURE__ */ s(a, { className: "size-5" })
57
+ title: f("files.preview.image.zoomIn", "Zoom in"),
58
+ children: /* @__PURE__ */ c(o, { className: "size-5" })
58
59
  }),
59
- /* @__PURE__ */ s("div", { className: "w-px h-6 bg-border-default mx-2" }),
60
- /* @__PURE__ */ s("button", {
60
+ /* @__PURE__ */ c("div", { className: "w-px h-6 bg-border-default mx-2" }),
61
+ /* @__PURE__ */ c("button", {
61
62
  type: "button",
62
- onClick: O,
63
+ onClick: A,
63
64
  className: "p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200",
64
- title: "Fit to screen",
65
- children: /* @__PURE__ */ s(r, { className: "size-5" })
65
+ title: f("files.preview.image.fitToScreen", "Fit to screen"),
66
+ children: /* @__PURE__ */ c(i, { className: "size-5" })
66
67
  }),
67
- /* @__PURE__ */ s("button", {
68
+ /* @__PURE__ */ c("button", {
68
69
  type: "button",
69
- onClick: k,
70
+ onClick: j,
70
71
  className: "p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200",
71
- title: "Rotate 90°",
72
- children: /* @__PURE__ */ s(i, { className: "size-5" })
72
+ title: f("files.preview.image.rotate", "Rotate 90°"),
73
+ children: /* @__PURE__ */ c(a, { className: "size-5" })
73
74
  })
74
75
  ]
75
76
  }),
76
- /* @__PURE__ */ c("div", {
77
+ /* @__PURE__ */ l("div", {
77
78
  className: "flex-1 overflow-hidden flex items-center justify-center relative",
78
- onMouseDown: A,
79
- onMouseMove: j,
80
- onMouseUp: M,
81
- onMouseLeave: M,
82
- style: { cursor: d > 1 ? _ ? "grabbing" : "grab" : "default" },
83
- children: [/* @__PURE__ */ s("img", {
84
- ref: C,
85
- src: u,
86
- alt: l.name,
79
+ onMouseDown: M,
80
+ onMouseMove: N,
81
+ onMouseUp: P,
82
+ onMouseLeave: P,
83
+ style: { cursor: p > 1 ? y ? "grabbing" : "grab" : "default" },
84
+ children: [/* @__PURE__ */ c("img", {
85
+ ref: T,
86
+ src: d,
87
+ alt: u.name,
87
88
  onLoad: () => {
88
- C.current && T({
89
- width: C.current.naturalWidth,
90
- height: C.current.naturalHeight
89
+ T.current && D({
90
+ width: T.current.naturalWidth,
91
+ height: T.current.naturalHeight
91
92
  });
92
93
  },
93
94
  onError: () => {
94
- S("Failed to load image from URL");
95
+ w(f("files.preview.image.loadError", "Failed to load image from URL"));
95
96
  },
96
97
  draggable: !1,
97
98
  className: "max-w-full max-h-full object-contain transition-transform duration-200",
98
99
  style: {
99
- transform: `scale(${d}) rotate(${p}deg) translate(${h.x / d}px, ${h.y / d}px)`,
100
+ transform: `scale(${p}) rotate(${h}deg) translate(${_.x / p}px, ${_.y / p}px)`,
100
101
  userSelect: "none"
101
102
  }
102
- }), x && /* @__PURE__ */ c("div", {
103
+ }), C && /* @__PURE__ */ l("div", {
103
104
  className: "absolute inset-0 flex flex-col items-center justify-center bg-bg-canvas/90 z-10",
104
105
  children: [
105
- /* @__PURE__ */ s(n, { className: "size-12 text-status-error-text mb-4" }),
106
- /* @__PURE__ */ s("p", {
106
+ /* @__PURE__ */ c(r, { className: "size-12 text-status-error-text mb-4" }),
107
+ /* @__PURE__ */ c("p", {
107
108
  className: "text-text-primary font-medium mb-2",
108
- children: "Failed to load image"
109
+ children: f("files.preview.image.failedToLoad", "Failed to load image")
109
110
  }),
110
- /* @__PURE__ */ s("p", {
111
+ /* @__PURE__ */ c("p", {
111
112
  className: "text-text-secondary text-sm max-w-md text-center px-4",
112
- children: x
113
+ children: C
113
114
  }),
114
- /* @__PURE__ */ s("a", {
115
- href: u,
115
+ /* @__PURE__ */ c("a", {
116
+ href: d,
116
117
  target: "_blank",
117
118
  rel: "noopener noreferrer",
118
119
  className: "mt-4 px-4 py-2 bg-action-primary-bg text-text-inverse rounded-lg hover:bg-action-primary-bg-hover",
119
- children: "Open in new tab"
120
+ children: f("files.preview.image.openInNewTab", "Open in new tab")
120
121
  })
121
122
  ]
122
123
  })]
123
124
  }),
124
- /* @__PURE__ */ c("div", {
125
+ /* @__PURE__ */ l("div", {
125
126
  className: "flex items-center justify-center gap-6 p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary",
126
127
  children: [
127
- /* @__PURE__ */ s("span", { children: l.name }),
128
- w.width > 0 && /* @__PURE__ */ c("span", { children: [
129
- w.width,
128
+ /* @__PURE__ */ c("span", { children: u.name }),
129
+ E.width > 0 && /* @__PURE__ */ l("span", { children: [
130
+ E.width,
130
131
  " × ",
131
- w.height
132
+ E.height
132
133
  ] }),
133
- /* @__PURE__ */ c("span", { children: [(l.size / 1024 / 1024).toFixed(2), " MB"] })
134
+ /* @__PURE__ */ l("span", { children: [(u.size / 1024 / 1024).toFixed(2), " MB"] })
134
135
  ]
135
136
  })
136
137
  ]
137
138
  });
138
139
  }
139
140
  //#endregion
140
- export { l as ImageViewer };
141
+ export { u as ImageViewer };
141
142
 
142
143
  //# sourceMappingURL=ImageViewer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ImageViewer.js","names":[],"sources":["../../../../src/files/components/viewers/ImageViewer.tsx"],"sourcesContent":["import { useState, useRef } from \"react\";\nimport {\n ZoomIn,\n ZoomOut,\n RotateCw,\n Maximize2,\n Minimize2,\n AlertCircle,\n} from \"lucide-react\";\nimport type { FileItem } from \"../../types\";\n\ninterface ImageViewerProps {\n file: FileItem;\n url: string;\n}\n\nexport function ImageViewer({ file, url }: ImageViewerProps) {\n const [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [imageError, setImageError] = useState<string | null>(null);\n const imageRef = useRef<HTMLImageElement>(null);\n const [imageDimensions, setImageDimensions] = useState({\n width: 0,\n height: 0,\n });\n\n const handleZoomIn = () => setZoom((prev) => Math.min(prev + 0.25, 4));\n const handleZoomOut = () => setZoom((prev) => Math.max(prev - 0.25, 0.25));\n const handleResetZoom = () => {\n setZoom(1);\n setPosition({ x: 0, y: 0 });\n setRotation(0);\n };\n const handleRotate = () => setRotation((prev) => (prev + 90) % 360);\n\n const handleMouseDown = (e: React.MouseEvent) => {\n if (zoom > 1) {\n setIsDragging(true);\n setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });\n }\n };\n\n const handleMouseMove = (e: React.MouseEvent) => {\n if (isDragging && zoom > 1) {\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n }\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n };\n\n const handleImageLoad = () => {\n if (imageRef.current) {\n setImageDimensions({\n width: imageRef.current.naturalWidth,\n height: imageRef.current.naturalHeight,\n });\n }\n };\n\n const handleImageError = () => {\n setImageError(`Failed to load image from URL`);\n };\n\n return (\n <div className=\"flex flex-col h-full bg-bg-canvas\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-center gap-2 p-4 bg-bg-surface border-b border-border-default\">\n <button\n type=\"button\"\n onClick={handleZoomOut}\n disabled={zoom <= 0.25}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title=\"Zoom out\"\n >\n <ZoomOut className=\"size-5\" />\n </button>\n\n <span className=\"min-w-16 text-center text-sm font-medium text-text-primary\">\n {Math.round(zoom * 100)}%\n </span>\n\n <button\n type=\"button\"\n onClick={handleZoomIn}\n disabled={zoom >= 4}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title=\"Zoom in\"\n >\n <ZoomIn className=\"size-5\" />\n </button>\n\n <div className=\"w-px h-6 bg-border-default mx-2\" />\n\n <button\n type=\"button\"\n onClick={handleResetZoom}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n title=\"Fit to screen\"\n >\n <Minimize2 className=\"size-5\" />\n </button>\n\n <button\n type=\"button\"\n onClick={handleRotate}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n title=\"Rotate 90°\"\n >\n <RotateCw className=\"size-5\" />\n </button>\n </div>\n\n {/* Image Container */}\n <div\n className=\"flex-1 overflow-hidden flex items-center justify-center relative\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{\n cursor: zoom > 1 ? (isDragging ? \"grabbing\" : \"grab\") : \"default\",\n }}\n >\n <img\n ref={imageRef}\n src={url}\n alt={file.name}\n onLoad={handleImageLoad}\n onError={handleImageError}\n draggable={false}\n className=\"max-w-full max-h-full object-contain transition-transform duration-200\"\n style={{\n transform: `scale(${zoom}) rotate(${rotation}deg) translate(${position.x / zoom}px, ${position.y / zoom}px)`,\n userSelect: \"none\",\n }}\n />\n {imageError && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-bg-canvas/90 z-10\">\n <AlertCircle className=\"size-12 text-status-error-text mb-4\" />\n <p className=\"text-text-primary font-medium mb-2\">\n Failed to load image\n </p>\n <p className=\"text-text-secondary text-sm max-w-md text-center px-4\">\n {imageError}\n </p>\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-4 px-4 py-2 bg-action-primary-bg text-text-inverse rounded-lg hover:bg-action-primary-bg-hover\"\n >\n Open in new tab\n </a>\n </div>\n )}\n </div>\n\n {/* Metadata */}\n <div className=\"flex items-center justify-center gap-6 p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary\">\n <span>{file.name}</span>\n {imageDimensions.width > 0 && (\n <span>\n {imageDimensions.width} × {imageDimensions.height}\n </span>\n )}\n <span>{(file.size / 1024 / 1024).toFixed(2)} MB</span>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ImageViewer.js","names":[],"sources":["../../../../src/files/components/viewers/ImageViewer.tsx"],"sourcesContent":["import { useState, useRef } from \"react\";\nimport {\n ZoomIn,\n ZoomOut,\n RotateCw,\n Maximize2,\n Minimize2,\n AlertCircle,\n} from \"lucide-react\";\nimport type { FileItem } from \"../../types\";\nimport { useTr } from \"../../../shared/hooks/useTr\";\n\ninterface ImageViewerProps {\n file: FileItem;\n url: string;\n}\n\nexport function ImageViewer({ file, url }: ImageViewerProps) {\n const tr = useTr();\n const [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [imageError, setImageError] = useState<string | null>(null);\n const imageRef = useRef<HTMLImageElement>(null);\n const [imageDimensions, setImageDimensions] = useState({\n width: 0,\n height: 0,\n });\n\n const handleZoomIn = () => setZoom((prev) => Math.min(prev + 0.25, 4));\n const handleZoomOut = () => setZoom((prev) => Math.max(prev - 0.25, 0.25));\n const handleResetZoom = () => {\n setZoom(1);\n setPosition({ x: 0, y: 0 });\n setRotation(0);\n };\n const handleRotate = () => setRotation((prev) => (prev + 90) % 360);\n\n const handleMouseDown = (e: React.MouseEvent) => {\n if (zoom > 1) {\n setIsDragging(true);\n setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });\n }\n };\n\n const handleMouseMove = (e: React.MouseEvent) => {\n if (isDragging && zoom > 1) {\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n }\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n };\n\n const handleImageLoad = () => {\n if (imageRef.current) {\n setImageDimensions({\n width: imageRef.current.naturalWidth,\n height: imageRef.current.naturalHeight,\n });\n }\n };\n\n const handleImageError = () => {\n setImageError(\n tr(\"files.preview.image.loadError\", \"Failed to load image from URL\"),\n );\n };\n\n return (\n <div className=\"flex flex-col h-full bg-bg-canvas\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-center gap-2 p-4 bg-bg-surface border-b border-border-default\">\n <button\n type=\"button\"\n onClick={handleZoomOut}\n disabled={zoom <= 0.25}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tr(\"files.preview.image.zoomOut\", \"Zoom out\")}\n >\n <ZoomOut className=\"size-5\" />\n </button>\n\n <span className=\"min-w-16 text-center text-sm font-medium text-text-primary\">\n {Math.round(zoom * 100)}%\n </span>\n\n <button\n type=\"button\"\n onClick={handleZoomIn}\n disabled={zoom >= 4}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tr(\"files.preview.image.zoomIn\", \"Zoom in\")}\n >\n <ZoomIn className=\"size-5\" />\n </button>\n\n <div className=\"w-px h-6 bg-border-default mx-2\" />\n\n <button\n type=\"button\"\n onClick={handleResetZoom}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n title={tr(\"files.preview.image.fitToScreen\", \"Fit to screen\")}\n >\n <Minimize2 className=\"size-5\" />\n </button>\n\n <button\n type=\"button\"\n onClick={handleRotate}\n className=\"p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n title={tr(\"files.preview.image.rotate\", \"Rotate 90°\")}\n >\n <RotateCw className=\"size-5\" />\n </button>\n </div>\n\n {/* Image Container */}\n <div\n className=\"flex-1 overflow-hidden flex items-center justify-center relative\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{\n cursor: zoom > 1 ? (isDragging ? \"grabbing\" : \"grab\") : \"default\",\n }}\n >\n <img\n ref={imageRef}\n src={url}\n alt={file.name}\n onLoad={handleImageLoad}\n onError={handleImageError}\n draggable={false}\n className=\"max-w-full max-h-full object-contain transition-transform duration-200\"\n style={{\n transform: `scale(${zoom}) rotate(${rotation}deg) translate(${position.x / zoom}px, ${position.y / zoom}px)`,\n userSelect: \"none\",\n }}\n />\n {imageError && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-bg-canvas/90 z-10\">\n <AlertCircle className=\"size-12 text-status-error-text mb-4\" />\n <p className=\"text-text-primary font-medium mb-2\">\n {tr(\"files.preview.image.failedToLoad\", \"Failed to load image\")}\n </p>\n <p className=\"text-text-secondary text-sm max-w-md text-center px-4\">\n {imageError}\n </p>\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-4 px-4 py-2 bg-action-primary-bg text-text-inverse rounded-lg hover:bg-action-primary-bg-hover\"\n >\n {tr(\"files.preview.image.openInNewTab\", \"Open in new tab\")}\n </a>\n </div>\n )}\n </div>\n\n {/* Metadata */}\n <div className=\"flex items-center justify-center gap-6 p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary\">\n <span>{file.name}</span>\n {imageDimensions.width > 0 && (\n <span>\n {imageDimensions.width} × {imageDimensions.height}\n </span>\n )}\n <span>{(file.size / 1024 / 1024).toFixed(2)} MB</span>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PDFViewer.d.ts","sourceRoot":"","sources":["../../../../src/files/components/viewers/PDFViewer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,UAAU,cAAc;IACtB,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,+BA6EtD"}
1
+ {"version":3,"file":"PDFViewer.d.ts","sourceRoot":"","sources":["../../../../src/files/components/viewers/PDFViewer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,UAAU,cAAc;IACtB,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,+BAuFtD"}
@@ -1,75 +1,78 @@
1
- import { useState as e } from "react";
2
- import { ZoomIn as t, ZoomOut as n } from "lucide-react";
3
- import { jsx as r, jsxs as i } from "react/jsx-runtime";
1
+ import { useTr as e } from "../../../shared/hooks/useTr.js";
2
+ import { useState as t } from "react";
3
+ import { ZoomIn as n, ZoomOut as r } from "lucide-react";
4
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
4
5
  //#region src/files/components/viewers/PDFViewer.tsx
5
- function a({ file: a, url: o }) {
6
- let [s, c] = e(100), l = () => c((e) => Math.min(e + 25, 200)), u = () => c((e) => Math.max(e - 25, 50)), d = `${o}#view=FitH&zoom=${s}`;
7
- return /* @__PURE__ */ i("div", {
6
+ function o({ file: o, url: s }) {
7
+ let c = e(), [l, u] = t(100), d = () => u((e) => Math.min(e + 25, 200)), f = () => u((e) => Math.max(e - 25, 50)), p = `${s}#view=FitH&zoom=${l}`;
8
+ return /* @__PURE__ */ a("div", {
8
9
  className: "flex flex-col h-full bg-bg-canvas",
9
10
  children: [
10
- /* @__PURE__ */ i("div", {
11
+ /* @__PURE__ */ a("div", {
11
12
  className: "flex items-center justify-between p-4 bg-bg-surface border-b border-border-default",
12
- children: [/* @__PURE__ */ i("div", {
13
+ children: [/* @__PURE__ */ a("div", {
13
14
  className: "flex items-center gap-2",
14
15
  children: [
15
- /* @__PURE__ */ r("button", {
16
+ /* @__PURE__ */ i("button", {
16
17
  type: "button",
17
- onClick: u,
18
- disabled: s <= 50,
18
+ onClick: f,
19
+ disabled: l <= 50,
19
20
  className: "p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
20
- title: "Zoom out",
21
- children: /* @__PURE__ */ r(n, { className: "size-5" })
21
+ title: c("files.preview.pdf.zoomOut", "Zoom out"),
22
+ children: /* @__PURE__ */ i(r, { className: "size-5" })
22
23
  }),
23
- /* @__PURE__ */ i("span", {
24
+ /* @__PURE__ */ a("span", {
24
25
  className: "min-w-16 text-center text-sm font-medium text-text-primary",
25
- children: [s, "%"]
26
+ children: [l, "%"]
26
27
  }),
27
- /* @__PURE__ */ r("button", {
28
+ /* @__PURE__ */ i("button", {
28
29
  type: "button",
29
- onClick: l,
30
- disabled: s >= 200,
30
+ onClick: d,
31
+ disabled: l >= 200,
31
32
  className: "p-2 text-text-secondary hover:text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
32
- title: "Zoom in",
33
- children: /* @__PURE__ */ r(t, { className: "size-5" })
33
+ title: c("files.preview.pdf.zoomIn", "Zoom in"),
34
+ children: /* @__PURE__ */ i(n, { className: "size-5" })
34
35
  })
35
36
  ]
36
- }), /* @__PURE__ */ r("span", {
37
+ }), /* @__PURE__ */ i("span", {
37
38
  className: "text-sm text-text-secondary",
38
- children: a.name
39
+ children: o.name
39
40
  })]
40
41
  }),
41
- /* @__PURE__ */ r("div", {
42
+ /* @__PURE__ */ i("div", {
42
43
  className: "flex-1 overflow-hidden",
43
- children: /* @__PURE__ */ r("object", {
44
- data: d,
44
+ children: /* @__PURE__ */ i("object", {
45
+ data: p,
45
46
  type: "application/pdf",
46
47
  className: "w-full h-full",
47
- title: a.name,
48
- children: /* @__PURE__ */ i("div", {
48
+ title: o.name,
49
+ children: /* @__PURE__ */ a("div", {
49
50
  className: "flex flex-col items-center justify-center h-full gap-4 p-8",
50
- children: [/* @__PURE__ */ i("div", {
51
+ children: [/* @__PURE__ */ a("div", {
51
52
  className: "text-text-secondary text-center",
52
- children: [/* @__PURE__ */ r("p", {
53
+ children: [/* @__PURE__ */ i("p", {
53
54
  className: "font-text-lg font-weight-medium mb-2",
54
- children: "Unable to display PDF"
55
- }), /* @__PURE__ */ r("p", {
55
+ children: c("files.preview.pdf.unableToDisplay", "Unable to display PDF")
56
+ }), /* @__PURE__ */ i("p", {
56
57
  className: "font-text-sm",
57
- children: "Your browser may not support embedded PDF viewing."
58
+ children: c("files.preview.pdf.browserUnsupported", "Your browser may not support embedded PDF viewing.")
58
59
  })]
59
- }), /* @__PURE__ */ r("a", {
60
- href: o,
61
- download: a.name,
60
+ }), /* @__PURE__ */ i("a", {
61
+ href: s,
62
+ download: o.name,
62
63
  className: "px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-btn hover:bg-action-primary-bg-hover transition-colors",
63
- children: "Download PDF"
64
+ children: c("files.preview.pdf.download", "Download PDF")
64
65
  })]
65
66
  })
66
67
  })
67
68
  }),
68
- /* @__PURE__ */ r("div", {
69
+ /* @__PURE__ */ i("div", {
69
70
  className: "flex items-center justify-center p-3 bg-bg-surface border-t border-border-default text-xs text-text-secondary",
70
- children: /* @__PURE__ */ i("span", { children: [
71
- "PDF Document · ",
72
- (a.size / 1024 / 1024).toFixed(2),
71
+ children: /* @__PURE__ */ a("span", { children: [
72
+ c("files.preview.pdf.documentLabel", "PDF Document"),
73
+ " ·",
74
+ " ",
75
+ (o.size / 1024 / 1024).toFixed(2),
73
76
  " MB"
74
77
  ] })
75
78
  })
@@ -77,6 +80,6 @@ function a({ file: a, url: o }) {
77
80
  });
78
81
  }
79
82
  //#endregion
80
- export { a as PDFViewer };
83
+ export { o as PDFViewer };
81
84
 
82
85
  //# sourceMappingURL=PDFViewer.js.map