@portosaur/theme 0.1.0

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 (76) hide show
  1. package/README.md +13 -0
  2. package/assets/img/icon-old.png +0 -0
  3. package/assets/img/icon.png +0 -0
  4. package/assets/img/project-blank.png +0 -0
  5. package/assets/img/social-card.jpeg +0 -0
  6. package/assets/img/svg/icon-blog.svg +2 -0
  7. package/assets/img/svg/icon-close.svg +3 -0
  8. package/assets/img/svg/icon-dock.svg +4 -0
  9. package/assets/img/svg/icon-link.svg +5 -0
  10. package/assets/img/svg/icon-note.svg +2 -0
  11. package/assets/img/svg/icon-popup.svg +1 -0
  12. package/assets/img/svg/icon-save.svg +5 -0
  13. package/assets/img/svg/icon.svg +240 -0
  14. package/assets/img/svg/project-blank.svg +140 -0
  15. package/assets/sample-resume.pdf +0 -0
  16. package/package.json +41 -0
  17. package/plugins/README.md +8 -0
  18. package/src/index.d.ts +11 -0
  19. package/src/index.mjs +14 -0
  20. package/src/plugins/theme.mjs +13 -0
  21. package/theme/DocCategoryGeneratedIndexPage/index.jsx +15 -0
  22. package/theme/MDXComponents.jsx +19 -0
  23. package/theme/README.md +9 -0
  24. package/theme/Root.jsx +11 -0
  25. package/theme/components/AboutSection/index.jsx +264 -0
  26. package/theme/components/AboutSection/styles.module.css +309 -0
  27. package/theme/components/ContactSection/index.jsx +188 -0
  28. package/theme/components/ContactSection/styles.module.css +343 -0
  29. package/theme/components/ExperienceSection/index.jsx +119 -0
  30. package/theme/components/ExperienceSection/styles.module.css +183 -0
  31. package/theme/components/HeroSection/index.jsx +198 -0
  32. package/theme/components/HeroSection/styles.module.css +484 -0
  33. package/theme/components/NavArrow/index.jsx +124 -0
  34. package/theme/components/NavArrow/styles.module.css +107 -0
  35. package/theme/components/NoteIndex/index.jsx +182 -0
  36. package/theme/components/NoteIndex/styles.module.css +167 -0
  37. package/theme/components/Preview/components/FeedbackStates.jsx +200 -0
  38. package/theme/components/Preview/components/FileTabs.jsx +41 -0
  39. package/theme/components/Preview/components/PreviewContent.jsx +104 -0
  40. package/theme/components/Preview/components/PreviewHeader.jsx +411 -0
  41. package/theme/components/Preview/components/Triggers/Pv.jsx +253 -0
  42. package/theme/components/Preview/components/Triggers/SrcPv.jsx +55 -0
  43. package/theme/components/Preview/components/Triggers/index.jsx +2 -0
  44. package/theme/components/Preview/components/ViewerWindow.jsx +489 -0
  45. package/theme/components/Preview/hooks/useAdaptiveSizing.jsx +90 -0
  46. package/theme/components/Preview/hooks/useDeepLinkHash.jsx +24 -0
  47. package/theme/components/Preview/hooks/useDockLayout.jsx +86 -0
  48. package/theme/components/Preview/hooks/useFileFetch.jsx +38 -0
  49. package/theme/components/Preview/hooks/useTouchZoom.jsx +98 -0
  50. package/theme/components/Preview/index.jsx +3 -0
  51. package/theme/components/Preview/renderers/CodeRenderer.jsx +124 -0
  52. package/theme/components/Preview/renderers/ImageRenderer.jsx +74 -0
  53. package/theme/components/Preview/renderers/PdfRenderer.jsx +93 -0
  54. package/theme/components/Preview/renderers/WebRenderer.jsx +59 -0
  55. package/theme/components/Preview/state/index.jsx +177 -0
  56. package/theme/components/Preview/styles.module.css +776 -0
  57. package/theme/components/Preview/utils/index.jsx +62 -0
  58. package/theme/components/ProjectsSection/index.jsx +790 -0
  59. package/theme/components/ProjectsSection/styles.module.css +900 -0
  60. package/theme/components/SocialLinks/index.jsx +115 -0
  61. package/theme/components/SocialLinks/styles.module.css +57 -0
  62. package/theme/components/Tooltip/index.jsx +104 -0
  63. package/theme/components/Tooltip/styles.module.css +168 -0
  64. package/theme/config/iconMappings.jsx +427 -0
  65. package/theme/config/prism.jsx +72 -0
  66. package/theme/config/sidebar.jsx +11 -0
  67. package/theme/css/bootstrap.css +5 -0
  68. package/theme/css/catppuccin.css +618 -0
  69. package/theme/css/custom.css +253 -0
  70. package/theme/css/tasks.css +874 -0
  71. package/theme/hooks/useScrollReveal.jsx +20 -0
  72. package/theme/pages/index.jsx +104 -0
  73. package/theme/pages/notes.jsx +131 -0
  74. package/theme/pages/tasks.jsx +989 -0
  75. package/theme/utils/HashNavigation.jsx +185 -0
  76. package/theme/utils/updateTitle.jsx +65 -0
@@ -0,0 +1,86 @@
1
+ import { useEffect, useRef } from "react";
2
+ export function useDockLayout({
3
+ isOpen,
4
+ isPopupMode,
5
+ isSidebarDock,
6
+ isPeekDock,
7
+ dockWidth,
8
+ peekHeight,
9
+ }) {
10
+ const weCollapsedSidebar = useRef(false);
11
+ useEffect(() => {
12
+ if (typeof document === "undefined") return;
13
+ if (isOpen && isPopupMode) {
14
+ document.body.style.overflow = "hidden";
15
+ } else {
16
+ document.body.style.overflow = "";
17
+ }
18
+ if (isSidebarDock) {
19
+ document.body.classList.add("pv-dock-active");
20
+ document.body.style.setProperty("--pv-dock-width", `${dockWidth}px`);
21
+ } else {
22
+ document.body.classList.remove("pv-dock-active");
23
+ document.body.style.setProperty("--pv-dock-width", "0px");
24
+ }
25
+ if (isPeekDock) {
26
+ document.body.classList.add("pv-peek-active");
27
+ document.body.style.setProperty(
28
+ "--mobile-peek-height",
29
+ `${peekHeight}px`,
30
+ );
31
+ } else {
32
+ document.body.classList.remove("pv-peek-active");
33
+ document.body.style.setProperty("--mobile-peek-height", "0px");
34
+ }
35
+ const sidebarToggleBtn = document.querySelector(
36
+ '[class*="collapseSidebarButton"]',
37
+ );
38
+ const isCollapsed = !!document.querySelector(
39
+ '[aria-label="Expand sidebar"]',
40
+ );
41
+ if (isSidebarDock) {
42
+ if (sidebarToggleBtn && !isCollapsed) {
43
+ weCollapsedSidebar.current = true;
44
+ sidebarToggleBtn.click();
45
+ }
46
+ } else {
47
+ if (weCollapsedSidebar.current && isCollapsed && sidebarToggleBtn) {
48
+ weCollapsedSidebar.current = false;
49
+ sidebarToggleBtn.click();
50
+ }
51
+ }
52
+ const updateNavOffset = () => {
53
+ const nav = document.querySelector(".navbar");
54
+ if (nav) {
55
+ document.documentElement.style.setProperty(
56
+ "--ifm-navbar-height",
57
+ `${nav.offsetHeight}px`,
58
+ );
59
+ }
60
+ };
61
+ if (isSidebarDock) {
62
+ updateNavOffset();
63
+ window.addEventListener("resize", updateNavOffset, { passive: true });
64
+ }
65
+ return () => {
66
+ document.body.classList.remove("pv-dock-active");
67
+ document.body.classList.remove("pv-peek-active");
68
+ document.body.style.overflow = "";
69
+ document.body.style.removeProperty("--pv-dock-width");
70
+ document.body.style.removeProperty("--mobile-peek-height");
71
+ if (weCollapsedSidebar.current) {
72
+ const sidebarToggleBtn = document.querySelector(
73
+ '[class*="collapseSidebarButton"]',
74
+ );
75
+ const isCollapsed = !!document.querySelector(
76
+ '[aria-label="Expand sidebar"]',
77
+ );
78
+ if (sidebarToggleBtn && isCollapsed) {
79
+ sidebarToggleBtn.click();
80
+ }
81
+ weCollapsedSidebar.current = false;
82
+ }
83
+ window.removeEventListener("resize", updateNavOffset);
84
+ };
85
+ }, [isOpen, isPopupMode, isSidebarDock, isPeekDock, dockWidth, peekHeight]);
86
+ }
@@ -0,0 +1,38 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { resolveUrl } from "../utils";
3
+ export function useFileFetch(path, fileType, isActive) {
4
+ const [cache, setCache] = useState({});
5
+ const [loading, setLoading] = useState(false);
6
+ const [errors, setErrors] = useState({});
7
+ useEffect(() => {
8
+ if (!isActive || !path || fileType !== "text") return;
9
+ if (cache[path] || errors[path]) return;
10
+ setLoading(true);
11
+ fetch(resolveUrl(path))
12
+ .then((r) => {
13
+ if (!r.ok) throw new Error(r.statusText);
14
+ return r.text();
15
+ })
16
+ .then((text) => setCache((prev) => ({ ...prev, [path]: text })))
17
+ .catch((err) => setErrors((prev) => ({ ...prev, [path]: err.message })))
18
+ .finally(() => setLoading(false));
19
+ }, [isActive, path, fileType]);
20
+ const retry = useCallback(() => {
21
+ setErrors((prev) => {
22
+ const next = { ...prev };
23
+ delete next[path];
24
+ return next;
25
+ });
26
+ }, [path]);
27
+ const setError = useCallback((p, msg) => {
28
+ setErrors((prev) => ({ ...prev, [p]: msg }));
29
+ }, []);
30
+ return {
31
+ content: cache[path] || null,
32
+ loading,
33
+ error: errors[path] || null,
34
+ errors,
35
+ retry,
36
+ setError,
37
+ };
38
+ }
@@ -0,0 +1,98 @@
1
+ import { useEffect } from "react";
2
+ import styles from "../styles.module.css";
3
+ export function useTouchZoom({
4
+ containerRef,
5
+ isOpen,
6
+ zoomLevel,
7
+ setZoomLevel,
8
+ }) {
9
+ useEffect(() => {
10
+ const el = containerRef.current;
11
+ if (!el || !isOpen) return;
12
+ let initialDistance = null;
13
+ let initialZoom = zoomLevel;
14
+ const getDistance = (touches) => {
15
+ return Math.hypot(
16
+ touches[0].clientX - touches[1].clientX,
17
+ touches[0].clientY - touches[1].clientY,
18
+ );
19
+ };
20
+ const handleWheel = (e) => {
21
+ if (e.ctrlKey) {
22
+ e.preventDefault();
23
+ const delta = -e.deltaY * 0.01;
24
+ setZoomLevel((prev) => Math.min(Math.max(0.5, prev + delta), 3));
25
+ }
26
+ };
27
+ const handleTouchStart = (e) => {
28
+ if (e.touches.length === 2) {
29
+ initialDistance = getDistance(e.touches);
30
+ setZoomLevel((prev) => {
31
+ initialZoom = prev;
32
+ return prev;
33
+ });
34
+ }
35
+ };
36
+ const handleTouchMove = (e) => {
37
+ if (e.touches.length === 2 && initialDistance) {
38
+ e.preventDefault();
39
+ const currentDistance = getDistance(e.touches);
40
+ const ratio = currentDistance / initialDistance;
41
+ setZoomLevel(Math.min(Math.max(0.5, initialZoom * ratio), 3));
42
+ }
43
+ };
44
+ const handleTouchEnd = (e) => {
45
+ if (e.touches.length < 2) {
46
+ initialDistance = null;
47
+ }
48
+ };
49
+ let isPanning = false;
50
+ let startX = 0;
51
+ let startY = 0;
52
+ let initialScrollLeft = 0;
53
+ let initialScrollTop = 0;
54
+ const handleMouseDown = (e) => {
55
+ if (e.button !== 0) return;
56
+ isPanning = true;
57
+ startX = e.pageX;
58
+ startY = e.pageY;
59
+ initialScrollLeft = el.scrollLeft;
60
+ initialScrollTop = el.scrollTop;
61
+ el.classList.add(styles.isPanning);
62
+ document.body.classList.add(styles.isPanning);
63
+ };
64
+ const handleMouseMove = (e) => {
65
+ if (!isPanning) return;
66
+ e.preventDefault();
67
+ const x = e.pageX;
68
+ const y = e.pageY;
69
+ const walkX = (x - startX) * 1;
70
+ const walkY = (y - startY) * 1;
71
+ el.scrollLeft = initialScrollLeft - walkX;
72
+ el.scrollTop = initialScrollTop - walkY;
73
+ };
74
+ const handleMouseUpOrLeave = () => {
75
+ isPanning = false;
76
+ el.classList.remove(styles.isPanning);
77
+ document.body.classList.remove(styles.isPanning);
78
+ };
79
+ el.addEventListener("wheel", handleWheel, { passive: false });
80
+ el.addEventListener("touchstart", handleTouchStart, { passive: false });
81
+ el.addEventListener("touchmove", handleTouchMove, { passive: false });
82
+ el.addEventListener("touchend", handleTouchEnd);
83
+ el.addEventListener("mousedown", handleMouseDown);
84
+ el.addEventListener("mousemove", handleMouseMove);
85
+ el.addEventListener("mouseup", handleMouseUpOrLeave);
86
+ el.addEventListener("mouseleave", handleMouseUpOrLeave);
87
+ return () => {
88
+ el.removeEventListener("wheel", handleWheel);
89
+ el.removeEventListener("touchstart", handleTouchStart);
90
+ el.removeEventListener("touchmove", handleTouchMove);
91
+ el.removeEventListener("touchend", handleTouchEnd);
92
+ el.removeEventListener("mousedown", handleMouseDown);
93
+ el.removeEventListener("mousemove", handleMouseMove);
94
+ el.removeEventListener("mouseup", handleMouseUpOrLeave);
95
+ el.removeEventListener("mouseleave", handleMouseUpOrLeave);
96
+ };
97
+ }, [isOpen, setZoomLevel, containerRef, zoomLevel]);
98
+ }
@@ -0,0 +1,3 @@
1
+ export { PreviewProvider, usePreview } from "./state/index.js";
2
+ export { default as ViewerWindow } from "./components/ViewerWindow.js";
3
+ export { Pv, SrcPv } from "./components/Triggers/index.js";
@@ -0,0 +1,124 @@
1
+ import React from "react";
2
+ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
3
+ import { Highlight } from "prism-react-renderer";
4
+ export default function CodeRenderer({ code, language, zoomLevel = 1 }) {
5
+ const { siteConfig } = useDocusaurusContext();
6
+ const isDark =
7
+ typeof document !== "undefined" &&
8
+ document.documentElement.getAttribute("data-theme") === "dark";
9
+ const prismConfig = siteConfig?.themeConfig?.prism || {};
10
+ const prismTheme = isDark ? prismConfig.darkTheme : prismConfig.theme;
11
+ const normalizedLanguage = language === "patch" ? "diff" : language || "text";
12
+ return jsxDEV_7x81h0kn(
13
+ Highlight,
14
+ {
15
+ code,
16
+ language: normalizedLanguage,
17
+ theme: prismTheme,
18
+ ...(typeof window !== "undefined" && window.Prism
19
+ ? { prism: window.Prism }
20
+ : {}),
21
+ children: ({ className, style, tokens, getLineProps, getTokenProps }) =>
22
+ jsxDEV_7x81h0kn(
23
+ "pre",
24
+ {
25
+ className,
26
+ style: {
27
+ ...style,
28
+ margin: 0,
29
+ borderRadius: 0,
30
+ padding: "14px 0",
31
+ fontSize: `calc(0.85rem * ${zoomLevel})`,
32
+ lineHeight: 1.6,
33
+ minHeight: "100%",
34
+ background: "var(--ifm-background-color)",
35
+ },
36
+ children: tokens.map((line, i) => {
37
+ const lineProps = getLineProps({ line });
38
+ const lineContent = line.map((t) => t.content).join("");
39
+ let diffStyle = {};
40
+ if (normalizedLanguage === "diff") {
41
+ if (lineContent.startsWith("+")) {
42
+ diffStyle = {
43
+ background: "rgba(var(--ifm-color-success-rgb), 0.15)",
44
+ borderLeft: "3px solid var(--ifm-color-success)",
45
+ };
46
+ } else if (lineContent.startsWith("-")) {
47
+ diffStyle = {
48
+ background: "rgba(var(--ifm-color-danger-rgb), 0.15)",
49
+ borderLeft: "3px solid var(--ifm-color-danger)",
50
+ };
51
+ }
52
+ }
53
+ return jsxDEV_7x81h0kn(
54
+ "div",
55
+ {
56
+ ...lineProps,
57
+ style: {
58
+ ...lineProps.style,
59
+ ...diffStyle,
60
+ display: "flex",
61
+ paddingLeft: diffStyle.borderLeft ? "0px" : "3px",
62
+ },
63
+ children: [
64
+ jsxDEV_7x81h0kn(
65
+ "span",
66
+ {
67
+ style: {
68
+ display: "inline-block",
69
+ width: "1.7em",
70
+ textAlign: "right",
71
+ marginRight: "12px",
72
+ userSelect: "none",
73
+ opacity: 0.35,
74
+ flexShrink: 0,
75
+ fontFamily: "var(--ifm-font-family-monospace)",
76
+ },
77
+ children: i + 1,
78
+ },
79
+ undefined,
80
+ false,
81
+ undefined,
82
+ this,
83
+ ),
84
+ jsxDEV_7x81h0kn(
85
+ "span",
86
+ {
87
+ style: { paddingRight: "14px", flex: 1 },
88
+ children: line.map((token, key) =>
89
+ jsxDEV_7x81h0kn(
90
+ "span",
91
+ { ...getTokenProps({ token }) },
92
+ key,
93
+ false,
94
+ undefined,
95
+ this,
96
+ ),
97
+ ),
98
+ },
99
+ undefined,
100
+ false,
101
+ undefined,
102
+ this,
103
+ ),
104
+ ],
105
+ },
106
+ i,
107
+ true,
108
+ undefined,
109
+ this,
110
+ );
111
+ }),
112
+ },
113
+ undefined,
114
+ false,
115
+ undefined,
116
+ this,
117
+ ),
118
+ },
119
+ undefined,
120
+ false,
121
+ undefined,
122
+ this,
123
+ );
124
+ }
@@ -0,0 +1,74 @@
1
+ import React, { useState } from "react";
2
+ import { LoadingState } from "../components/FeedbackStates";
3
+ import styles from "../styles.module.css";
4
+ export default function ImageRenderer({ fileUrl, label, zoomLevel, onError }) {
5
+ const [loading, setLoading] = useState(true);
6
+ return jsxDEV_7x81h0kn(
7
+ "div",
8
+ {
9
+ className: styles.imageView,
10
+ style: { "--zoom": zoomLevel, position: "relative" },
11
+ children: [
12
+ loading &&
13
+ jsxDEV_7x81h0kn(
14
+ "div",
15
+ {
16
+ style: {
17
+ position: "absolute",
18
+ inset: 0,
19
+ zIndex: 5,
20
+ display: "flex",
21
+ },
22
+ children: jsxDEV_7x81h0kn(
23
+ LoadingState,
24
+ {},
25
+ undefined,
26
+ false,
27
+ undefined,
28
+ this,
29
+ ),
30
+ },
31
+ undefined,
32
+ false,
33
+ undefined,
34
+ this,
35
+ ),
36
+ jsxDEV_7x81h0kn(
37
+ "div",
38
+ {
39
+ className: styles.imageScrollArea,
40
+ style: {
41
+ opacity: loading ? 0 : 1,
42
+ transition: "opacity 0.3s ease",
43
+ },
44
+ children: jsxDEV_7x81h0kn(
45
+ "img",
46
+ {
47
+ src: fileUrl,
48
+ alt: label || "",
49
+ className: styles.image,
50
+ onLoad: () => setLoading(false),
51
+ onError: () => {
52
+ setLoading(false);
53
+ onError?.("Failed to load image.");
54
+ },
55
+ },
56
+ undefined,
57
+ false,
58
+ undefined,
59
+ this,
60
+ ),
61
+ },
62
+ undefined,
63
+ false,
64
+ undefined,
65
+ this,
66
+ ),
67
+ ],
68
+ },
69
+ undefined,
70
+ true,
71
+ undefined,
72
+ this,
73
+ );
74
+ }
@@ -0,0 +1,93 @@
1
+ import React, { useState, useEffect, useRef } from "react";
2
+ import { LoadingState } from "../components/FeedbackStates";
3
+ import styles from "../styles.module.css";
4
+ import "react-pdf/dist/Page/AnnotationLayer.css";
5
+ import "react-pdf/dist/Page/TextLayer.css";
6
+ let PdfDocument, PdfPage, pdfjs;
7
+ export default function PdfRenderer({ fileUrl, zoomLevel, onError }) {
8
+ const [pdfReady, setPdfReady] = useState(!!PdfDocument);
9
+ const [numPages, setNumPages] = useState(null);
10
+ const [containerWidth, setContainerWidth] = useState(760);
11
+ const wrapperRef = useRef(null);
12
+ useEffect(() => {
13
+ if (PdfDocument) return;
14
+ import("react-pdf").then((mod) => {
15
+ PdfDocument = mod.Document;
16
+ PdfPage = mod.Page;
17
+ pdfjs = mod.pdfjs;
18
+ pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
19
+ setPdfReady(true);
20
+ });
21
+ }, []);
22
+ useEffect(() => {
23
+ if (!wrapperRef.current) return;
24
+ let timeoutId = null;
25
+ const observer = new ResizeObserver((entries) => {
26
+ const { width } = entries[0].contentRect;
27
+ if (width <= 0) return;
28
+ const diff = Math.abs(width - containerWidth);
29
+ if (diff < 15) return;
30
+ if (timeoutId) clearTimeout(timeoutId);
31
+ timeoutId = setTimeout(() => {
32
+ setContainerWidth(width);
33
+ }, 150);
34
+ });
35
+ observer.observe(wrapperRef.current);
36
+ return () => {
37
+ observer.disconnect();
38
+ if (timeoutId) clearTimeout(timeoutId);
39
+ };
40
+ }, [pdfReady, containerWidth]);
41
+ if (!pdfReady || !PdfDocument) {
42
+ return jsxDEV_7x81h0kn(LoadingState, {}, undefined, false, undefined, this);
43
+ }
44
+ return jsxDEV_7x81h0kn(
45
+ "div",
46
+ {
47
+ className: styles.pdfView,
48
+ ref: wrapperRef,
49
+ children: jsxDEV_7x81h0kn(
50
+ PdfDocument,
51
+ {
52
+ file: fileUrl,
53
+ onLoadSuccess: ({ numPages: n }) => setNumPages(n),
54
+ onLoadError: (err) =>
55
+ onError?.(err.message || "Invalid or missing PDF file."),
56
+ loading: jsxDEV_7x81h0kn(
57
+ LoadingState,
58
+ {},
59
+ undefined,
60
+ false,
61
+ undefined,
62
+ this,
63
+ ),
64
+ children: Array.from({ length: numPages || 0 }, (_, i) =>
65
+ jsxDEV_7x81h0kn(
66
+ PdfPage,
67
+ {
68
+ pageNumber: i + 1,
69
+ width: containerWidth,
70
+ scale: zoomLevel,
71
+ className: styles.pdfPage,
72
+ renderTextLayer: true,
73
+ renderAnnotationLayer: true,
74
+ },
75
+ i,
76
+ false,
77
+ undefined,
78
+ this,
79
+ ),
80
+ ),
81
+ },
82
+ undefined,
83
+ false,
84
+ undefined,
85
+ this,
86
+ ),
87
+ },
88
+ undefined,
89
+ false,
90
+ undefined,
91
+ this,
92
+ );
93
+ }
@@ -0,0 +1,59 @@
1
+ import { useState, useEffect, useRef } from "react";
2
+ import { LoadingState } from "../components/FeedbackStates";
3
+ import styles from "../styles.module.css";
4
+ export default function WebRenderer({ fileUrl, label, onError }) {
5
+ const [loaded, setLoaded] = useState(false);
6
+ const loadedRef = useRef(false);
7
+ const timeoutRef = useRef(null);
8
+ useEffect(() => {
9
+ setLoaded(false);
10
+ loadedRef.current = false;
11
+ clearTimeout(timeoutRef.current);
12
+ timeoutRef.current = setTimeout(() => {
13
+ if (!loadedRef.current) {
14
+ onError?.(
15
+ "The page took too long to respond. It may block embedding or you may be offline.",
16
+ );
17
+ }
18
+ }, 1e4);
19
+ return () => clearTimeout(timeoutRef.current);
20
+ }, [fileUrl]);
21
+ const handleLoad = () => {
22
+ setLoaded(true);
23
+ loadedRef.current = true;
24
+ clearTimeout(timeoutRef.current);
25
+ };
26
+ return jsxDEV_7x81h0kn(
27
+ "div",
28
+ {
29
+ className: styles.webView,
30
+ children: [
31
+ !loaded &&
32
+ jsxDEV_7x81h0kn(LoadingState, {}, undefined, false, undefined, this),
33
+ jsxDEV_7x81h0kn(
34
+ "iframe",
35
+ {
36
+ src: fileUrl,
37
+ title: label,
38
+ className: styles.webFrame,
39
+ onLoad: handleLoad,
40
+ style: { opacity: loaded ? 1 : 0, transition: "opacity 0.3s ease" },
41
+ allow:
42
+ "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
43
+ allowFullScreen: true,
44
+ sandbox:
45
+ "allow-scripts allow-same-origin allow-popups allow-forms allow-presentation",
46
+ },
47
+ undefined,
48
+ false,
49
+ undefined,
50
+ this,
51
+ ),
52
+ ],
53
+ },
54
+ undefined,
55
+ true,
56
+ undefined,
57
+ this,
58
+ );
59
+ }