@portosaur/theme 0.1.4 → 0.2.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.
- package/package.json +10 -3
- package/src/plugins/theme.mjs +2 -0
- package/theme/DocCategoryGeneratedIndexPage/index.jsx +4 -10
- package/theme/MDXComponents.jsx +1 -1
- package/theme/Root.jsx +1 -1
- package/theme/components/AboutSection/index.jsx +89 -249
- package/theme/components/ContactSection/index.jsx +72 -153
- package/theme/components/ExperienceSection/index.jsx +35 -106
- package/theme/components/HeroSection/index.jsx +64 -186
- package/theme/components/NavArrow/index.jsx +38 -55
- package/theme/components/NoteIndex/index.jsx +50 -116
- package/theme/components/Preview/components/FeedbackStates.jsx +45 -190
- package/theme/components/Preview/components/FileTabs.jsx +17 -24
- package/theme/components/Preview/components/PreviewContent.jsx +37 -62
- package/theme/components/Preview/components/PreviewHeader.jsx +146 -380
- package/theme/components/Preview/components/Triggers/Pv.jsx +50 -78
- package/theme/components/Preview/components/Triggers/SrcPv.jsx +16 -47
- package/theme/components/Preview/components/Triggers/index.jsx +2 -2
- package/theme/components/Preview/components/ViewerWindow.jsx +160 -268
- package/theme/components/Preview/index.jsx +3 -3
- package/theme/components/Preview/renderers/CodeRenderer.jsx +81 -109
- package/theme/components/Preview/renderers/ImageRenderer.jsx +30 -67
- package/theme/components/Preview/renderers/PdfRenderer.jsx +31 -52
- package/theme/components/Preview/renderers/WebRenderer.jsx +18 -32
- package/theme/components/Preview/state/index.jsx +46 -30
- package/theme/components/ProjectsSection/index.jsx +278 -573
- package/theme/components/SocialLinks/index.jsx +43 -55
- package/theme/components/Tooltip/index.jsx +28 -39
- package/theme/pages/index.jsx +23 -87
- package/theme/pages/notes.jsx +26 -104
- package/theme/pages/tasks.jsx +220 -903
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
|
3
3
|
import { Highlight } from "prism-react-renderer";
|
|
4
|
+
|
|
4
5
|
export default function CodeRenderer({ code, language, zoomLevel = 1 }) {
|
|
5
6
|
const { siteConfig } = useDocusaurusContext();
|
|
6
7
|
const isDark =
|
|
@@ -9,116 +10,87 @@ export default function CodeRenderer({ code, language, zoomLevel = 1 }) {
|
|
|
9
10
|
const prismConfig = siteConfig?.themeConfig?.prism || {};
|
|
10
11
|
const prismTheme = isDark ? prismConfig.darkTheme : prismConfig.theme;
|
|
11
12
|
const normalizedLanguage = language === "patch" ? "diff" : language || "text";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
code
|
|
16
|
-
language
|
|
17
|
-
theme
|
|
18
|
-
...(typeof window !== "undefined" && window.Prism
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Highlight
|
|
16
|
+
code={code}
|
|
17
|
+
language={normalizedLanguage}
|
|
18
|
+
theme={prismTheme}
|
|
19
|
+
{...(typeof window !== "undefined" && window.Prism
|
|
19
20
|
? { prism: window.Prism }
|
|
20
|
-
: {})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
style
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
21
|
+
: {})}
|
|
22
|
+
>
|
|
23
|
+
{({ className, style, tokens, getLineProps, getTokenProps }) => (
|
|
24
|
+
<pre
|
|
25
|
+
className={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
|
+
>
|
|
37
|
+
{tokens.map((line, i) => {
|
|
38
|
+
const lineProps = getLineProps({ line });
|
|
39
|
+
const lineContent = line.map((t) => t.content).join("");
|
|
40
|
+
let diffStyle = {};
|
|
41
|
+
|
|
42
|
+
if (normalizedLanguage === "diff") {
|
|
43
|
+
if (lineContent.startsWith("+")) {
|
|
44
|
+
diffStyle = {
|
|
45
|
+
background: "rgba(var(--ifm-color-success-rgb), 0.15)",
|
|
46
|
+
borderLeft: "3px solid var(--ifm-color-success)",
|
|
47
|
+
};
|
|
48
|
+
} else if (lineContent.startsWith("-")) {
|
|
49
|
+
diffStyle = {
|
|
50
|
+
background: "rgba(var(--ifm-color-danger-rgb), 0.15)",
|
|
51
|
+
borderLeft: "3px solid var(--ifm-color-danger)",
|
|
52
|
+
};
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
key={i}
|
|
59
|
+
{...lineProps}
|
|
60
|
+
style={{
|
|
61
|
+
...lineProps.style,
|
|
62
|
+
...diffStyle,
|
|
63
|
+
display: "flex",
|
|
64
|
+
paddingLeft: diffStyle.borderLeft ? "0px" : "3px",
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
{/* Line number gutter */}
|
|
68
|
+
<span
|
|
69
|
+
style={{
|
|
70
|
+
display: "inline-block",
|
|
71
|
+
width: "1.7em",
|
|
72
|
+
textAlign: "right",
|
|
73
|
+
marginRight: "12px",
|
|
74
|
+
userSelect: "none",
|
|
75
|
+
opacity: 0.35,
|
|
76
|
+
flexShrink: 0,
|
|
77
|
+
fontFamily: "var(--ifm-font-family-monospace)",
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{i + 1}
|
|
81
|
+
</span>
|
|
82
|
+
|
|
83
|
+
{/* Token content */}
|
|
84
|
+
<span style={{ paddingRight: "14px", flex: 1 }}>
|
|
85
|
+
{line.map((token, key) => (
|
|
86
|
+
<span key={key} {...getTokenProps({ token })} />
|
|
87
|
+
))}
|
|
88
|
+
</span>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
</pre>
|
|
93
|
+
)}
|
|
94
|
+
</Highlight>
|
|
123
95
|
);
|
|
124
96
|
}
|
|
@@ -1,74 +1,37 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { LoadingState } from "../components/FeedbackStates";
|
|
3
3
|
import styles from "../styles.module.css";
|
|
4
|
+
|
|
4
5
|
export default function ImageRenderer({ fileUrl, label, zoomLevel, onError }) {
|
|
5
6
|
const [loading, setLoading] = useState(true);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
className
|
|
10
|
-
style
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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,
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
className={styles.imageView}
|
|
11
|
+
style={{ "--zoom": zoomLevel, position: "relative" }}
|
|
12
|
+
>
|
|
13
|
+
{loading && (
|
|
14
|
+
<div
|
|
15
|
+
style={{ position: "absolute", inset: 0, zIndex: 5, display: "flex" }}
|
|
16
|
+
>
|
|
17
|
+
<LoadingState />
|
|
18
|
+
</div>
|
|
19
|
+
)}
|
|
20
|
+
<div
|
|
21
|
+
className={styles.imageScrollArea}
|
|
22
|
+
style={{ opacity: loading ? 0 : 1, transition: "opacity 0.3s ease" }}
|
|
23
|
+
>
|
|
24
|
+
<img
|
|
25
|
+
src={fileUrl}
|
|
26
|
+
alt={label || ""}
|
|
27
|
+
className={styles.image}
|
|
28
|
+
onLoad={() => setLoading(false)}
|
|
29
|
+
onError={() => {
|
|
30
|
+
setLoading(false);
|
|
31
|
+
onError?.("Failed to load image.");
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
73
36
|
);
|
|
74
37
|
}
|
|
@@ -3,12 +3,15 @@ import { LoadingState } from "../components/FeedbackStates";
|
|
|
3
3
|
import styles from "../styles.module.css";
|
|
4
4
|
import "react-pdf/dist/Page/AnnotationLayer.css";
|
|
5
5
|
import "react-pdf/dist/Page/TextLayer.css";
|
|
6
|
+
|
|
6
7
|
let PdfDocument, PdfPage, pdfjs;
|
|
8
|
+
|
|
7
9
|
export default function PdfRenderer({ fileUrl, zoomLevel, onError }) {
|
|
8
10
|
const [pdfReady, setPdfReady] = useState(!!PdfDocument);
|
|
9
11
|
const [numPages, setNumPages] = useState(null);
|
|
10
12
|
const [containerWidth, setContainerWidth] = useState(760);
|
|
11
13
|
const wrapperRef = useRef(null);
|
|
14
|
+
|
|
12
15
|
useEffect(() => {
|
|
13
16
|
if (PdfDocument) return;
|
|
14
17
|
import("react-pdf").then((mod) => {
|
|
@@ -19,6 +22,7 @@ export default function PdfRenderer({ fileUrl, zoomLevel, onError }) {
|
|
|
19
22
|
setPdfReady(true);
|
|
20
23
|
});
|
|
21
24
|
}, []);
|
|
25
|
+
|
|
22
26
|
useEffect(() => {
|
|
23
27
|
if (!wrapperRef.current) return;
|
|
24
28
|
let timeoutId = null;
|
|
@@ -28,9 +32,7 @@ export default function PdfRenderer({ fileUrl, zoomLevel, onError }) {
|
|
|
28
32
|
const diff = Math.abs(width - containerWidth);
|
|
29
33
|
if (diff < 15) return;
|
|
30
34
|
if (timeoutId) clearTimeout(timeoutId);
|
|
31
|
-
timeoutId = setTimeout(() =>
|
|
32
|
-
setContainerWidth(width);
|
|
33
|
-
}, 150);
|
|
35
|
+
timeoutId = setTimeout(() => setContainerWidth(width), 150);
|
|
34
36
|
});
|
|
35
37
|
observer.observe(wrapperRef.current);
|
|
36
38
|
return () => {
|
|
@@ -38,56 +40,33 @@ export default function PdfRenderer({ fileUrl, zoomLevel, onError }) {
|
|
|
38
40
|
if (timeoutId) clearTimeout(timeoutId);
|
|
39
41
|
};
|
|
40
42
|
}, [pdfReady, containerWidth]);
|
|
43
|
+
|
|
41
44
|
if (!pdfReady || !PdfDocument) {
|
|
42
|
-
return
|
|
45
|
+
return <LoadingState />;
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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,
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={styles.pdfView} ref={wrapperRef}>
|
|
50
|
+
<PdfDocument
|
|
51
|
+
file={fileUrl}
|
|
52
|
+
onLoadSuccess={({ numPages: n }) => setNumPages(n)}
|
|
53
|
+
onLoadError={(err) =>
|
|
54
|
+
onError?.(err.message || "Invalid or missing PDF file.")
|
|
55
|
+
}
|
|
56
|
+
loading={<LoadingState />}
|
|
57
|
+
>
|
|
58
|
+
{Array.from({ length: numPages || 0 }, (_, i) => (
|
|
59
|
+
<PdfPage
|
|
60
|
+
key={i}
|
|
61
|
+
pageNumber={i + 1}
|
|
62
|
+
width={containerWidth}
|
|
63
|
+
scale={zoomLevel}
|
|
64
|
+
className={styles.pdfPage}
|
|
65
|
+
renderTextLayer={true}
|
|
66
|
+
renderAnnotationLayer={true}
|
|
67
|
+
/>
|
|
68
|
+
))}
|
|
69
|
+
</PdfDocument>
|
|
70
|
+
</div>
|
|
92
71
|
);
|
|
93
72
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { useState, useEffect, useRef } from "react";
|
|
2
2
|
import { LoadingState } from "../components/FeedbackStates";
|
|
3
3
|
import styles from "../styles.module.css";
|
|
4
|
+
|
|
4
5
|
export default function WebRenderer({ fileUrl, label, onError }) {
|
|
5
6
|
const [loaded, setLoaded] = useState(false);
|
|
6
7
|
const loadedRef = useRef(false);
|
|
7
8
|
const timeoutRef = useRef(null);
|
|
9
|
+
|
|
8
10
|
useEffect(() => {
|
|
9
11
|
setLoaded(false);
|
|
10
12
|
loadedRef.current = false;
|
|
@@ -18,42 +20,26 @@ export default function WebRenderer({ fileUrl, label, onError }) {
|
|
|
18
20
|
}, 1e4);
|
|
19
21
|
return () => clearTimeout(timeoutRef.current);
|
|
20
22
|
}, [fileUrl]);
|
|
23
|
+
|
|
21
24
|
const handleLoad = () => {
|
|
22
25
|
setLoaded(true);
|
|
23
26
|
loadedRef.current = true;
|
|
24
27
|
clearTimeout(timeoutRef.current);
|
|
25
28
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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,
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className={styles.webView}>
|
|
32
|
+
{!loaded && <LoadingState />}
|
|
33
|
+
<iframe
|
|
34
|
+
src={fileUrl}
|
|
35
|
+
title={label}
|
|
36
|
+
className={styles.webFrame}
|
|
37
|
+
onLoad={handleLoad}
|
|
38
|
+
style={{ opacity: loaded ? 1 : 0, transition: "opacity 0.3s ease" }}
|
|
39
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
40
|
+
allowFullScreen={true}
|
|
41
|
+
sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-presentation"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
58
44
|
);
|
|
59
45
|
}
|
|
@@ -3,11 +3,18 @@ import React, {
|
|
|
3
3
|
useContext,
|
|
4
4
|
useReducer,
|
|
5
5
|
useCallback,
|
|
6
|
-
ReactNode,
|
|
7
6
|
} from "react";
|
|
7
|
+
|
|
8
8
|
const PreviewContext = createContext(null);
|
|
9
9
|
const DEFAULT_SIZE = { width: 720, height: 400 };
|
|
10
10
|
const DEFAULT_DOCK_PERCENTAGE = 0.42;
|
|
11
|
+
|
|
12
|
+
export const PreviewMode = {
|
|
13
|
+
POPUP: "popup",
|
|
14
|
+
DOCK: "dock",
|
|
15
|
+
PIP: "pip",
|
|
16
|
+
};
|
|
17
|
+
|
|
11
18
|
function getInitialState() {
|
|
12
19
|
if (typeof window === "undefined") {
|
|
13
20
|
return {
|
|
@@ -22,6 +29,7 @@ function getInitialState() {
|
|
|
22
29
|
floatingState: { ...DEFAULT_SIZE, x: null, y: null },
|
|
23
30
|
};
|
|
24
31
|
}
|
|
32
|
+
|
|
25
33
|
let defaultDockWidth = Math.floor(
|
|
26
34
|
window.innerWidth * DEFAULT_DOCK_PERCENTAGE,
|
|
27
35
|
);
|
|
@@ -29,6 +37,7 @@ function getInitialState() {
|
|
|
29
37
|
380,
|
|
30
38
|
Math.min(defaultDockWidth, window.innerWidth * 0.8),
|
|
31
39
|
);
|
|
40
|
+
|
|
32
41
|
return {
|
|
33
42
|
isOpen: false,
|
|
34
43
|
mode: "popup",
|
|
@@ -41,6 +50,7 @@ function getInitialState() {
|
|
|
41
50
|
floatingState: { ...DEFAULT_SIZE, x: null, y: null },
|
|
42
51
|
};
|
|
43
52
|
}
|
|
53
|
+
|
|
44
54
|
function reducer(state, action) {
|
|
45
55
|
switch (action.type) {
|
|
46
56
|
case "OPEN":
|
|
@@ -85,8 +95,10 @@ function reducer(state, action) {
|
|
|
85
95
|
return state;
|
|
86
96
|
}
|
|
87
97
|
}
|
|
98
|
+
|
|
88
99
|
export function PreviewProvider({ children }) {
|
|
89
100
|
const [state, dispatch] = useReducer(reducer, undefined, getInitialState);
|
|
101
|
+
|
|
90
102
|
const openPreview = useCallback(
|
|
91
103
|
(
|
|
92
104
|
sources,
|
|
@@ -103,6 +115,7 @@ export function PreviewProvider({ children }) {
|
|
|
103
115
|
},
|
|
104
116
|
[],
|
|
105
117
|
);
|
|
118
|
+
|
|
106
119
|
const closePreview = useCallback(() => {
|
|
107
120
|
if (typeof window !== "undefined") {
|
|
108
121
|
window.history.replaceState(
|
|
@@ -113,28 +126,32 @@ export function PreviewProvider({ children }) {
|
|
|
113
126
|
}
|
|
114
127
|
dispatch({ type: "CLOSE" });
|
|
115
128
|
}, []);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
dispatch({ type: "
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
129
|
+
|
|
130
|
+
const setMode = useCallback(
|
|
131
|
+
(mode) => dispatch({ type: "SET_MODE", mode }),
|
|
132
|
+
[],
|
|
133
|
+
);
|
|
134
|
+
const setActiveIndex = useCallback(
|
|
135
|
+
(index) => dispatch({ type: "SET_ACTIVE_INDEX", index }),
|
|
136
|
+
[],
|
|
137
|
+
);
|
|
138
|
+
const setDockWidth = useCallback(
|
|
139
|
+
(width) => dispatch({ type: "SET_DOCK_WIDTH", width }),
|
|
140
|
+
[],
|
|
141
|
+
);
|
|
142
|
+
const setPeekHeight = useCallback(
|
|
143
|
+
(height) => dispatch({ type: "SET_PEEK_HEIGHT", height }),
|
|
144
|
+
[],
|
|
145
|
+
);
|
|
146
|
+
const setFloatingState = useCallback(
|
|
147
|
+
(newState) => dispatch({ type: "SET_FLOATING_STATE", state: newState }),
|
|
148
|
+
[],
|
|
149
|
+
);
|
|
150
|
+
const toggleMode = useCallback(() => dispatch({ type: "TOGGLE_MODE" }), []);
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<PreviewContext.Provider
|
|
154
|
+
value={{
|
|
138
155
|
...state,
|
|
139
156
|
openPreview,
|
|
140
157
|
closePreview,
|
|
@@ -144,15 +161,13 @@ export function PreviewProvider({ children }) {
|
|
|
144
161
|
setPeekHeight,
|
|
145
162
|
setFloatingState,
|
|
146
163
|
toggleMode,
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
false,
|
|
152
|
-
undefined,
|
|
153
|
-
this,
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{children}
|
|
167
|
+
</PreviewContext.Provider>
|
|
154
168
|
);
|
|
155
169
|
}
|
|
170
|
+
|
|
156
171
|
const DEFAULT_CTX = {
|
|
157
172
|
isOpen: false,
|
|
158
173
|
mode: "popup",
|
|
@@ -172,6 +187,7 @@ const DEFAULT_CTX = {
|
|
|
172
187
|
setFloatingState: () => {},
|
|
173
188
|
toggleMode: () => {},
|
|
174
189
|
};
|
|
190
|
+
|
|
175
191
|
export function usePreview() {
|
|
176
192
|
return useContext(PreviewContext) ?? DEFAULT_CTX;
|
|
177
193
|
}
|