@portosaur/theme 0.1.5 → 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.
Files changed (31) hide show
  1. package/package.json +10 -3
  2. package/src/plugins/theme.mjs +2 -0
  3. package/theme/DocCategoryGeneratedIndexPage/index.jsx +4 -10
  4. package/theme/MDXComponents.jsx +1 -1
  5. package/theme/Root.jsx +1 -1
  6. package/theme/components/AboutSection/index.jsx +89 -249
  7. package/theme/components/ContactSection/index.jsx +72 -153
  8. package/theme/components/ExperienceSection/index.jsx +35 -106
  9. package/theme/components/HeroSection/index.jsx +64 -186
  10. package/theme/components/NavArrow/index.jsx +38 -55
  11. package/theme/components/NoteIndex/index.jsx +50 -116
  12. package/theme/components/Preview/components/FeedbackStates.jsx +45 -190
  13. package/theme/components/Preview/components/FileTabs.jsx +17 -24
  14. package/theme/components/Preview/components/PreviewContent.jsx +37 -62
  15. package/theme/components/Preview/components/PreviewHeader.jsx +146 -380
  16. package/theme/components/Preview/components/Triggers/Pv.jsx +50 -78
  17. package/theme/components/Preview/components/Triggers/SrcPv.jsx +16 -47
  18. package/theme/components/Preview/components/Triggers/index.jsx +2 -2
  19. package/theme/components/Preview/components/ViewerWindow.jsx +160 -268
  20. package/theme/components/Preview/index.jsx +3 -3
  21. package/theme/components/Preview/renderers/CodeRenderer.jsx +81 -109
  22. package/theme/components/Preview/renderers/ImageRenderer.jsx +30 -67
  23. package/theme/components/Preview/renderers/PdfRenderer.jsx +31 -52
  24. package/theme/components/Preview/renderers/WebRenderer.jsx +18 -32
  25. package/theme/components/Preview/state/index.jsx +46 -30
  26. package/theme/components/ProjectsSection/index.jsx +278 -573
  27. package/theme/components/SocialLinks/index.jsx +43 -55
  28. package/theme/components/Tooltip/index.jsx +28 -39
  29. package/theme/pages/index.jsx +23 -87
  30. package/theme/pages/notes.jsx +26 -104
  31. 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
- return jsxDEV_7x81h0kn(
13
- Highlight,
14
- {
15
- code,
16
- language: normalizedLanguage,
17
- theme: prismTheme,
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
- 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
- }
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
- 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,
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
- 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,
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 jsxDEV_7x81h0kn(LoadingState, {}, undefined, false, undefined, this);
45
+ return <LoadingState />;
43
46
  }
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,
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
- 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,
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
- const setMode = useCallback((mode) => {
117
- dispatch({ type: "SET_MODE", mode });
118
- }, []);
119
- const setActiveIndex = useCallback((index) => {
120
- dispatch({ type: "SET_ACTIVE_INDEX", index });
121
- }, []);
122
- const setDockWidth = useCallback((width) => {
123
- dispatch({ type: "SET_DOCK_WIDTH", width });
124
- }, []);
125
- const setPeekHeight = useCallback((height) => {
126
- dispatch({ type: "SET_PEEK_HEIGHT", height });
127
- }, []);
128
- const setFloatingState = useCallback((newState) => {
129
- dispatch({ type: "SET_FLOATING_STATE", state: newState });
130
- }, []);
131
- const toggleMode = useCallback(() => {
132
- dispatch({ type: "TOGGLE_MODE" });
133
- }, []);
134
- return jsxDEV_7x81h0kn(
135
- PreviewContext.Provider,
136
- {
137
- value: {
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
- children,
149
- },
150
- undefined,
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
  }