@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
@@ -4,17 +4,18 @@ import { useLocation } from "@docusaurus/router";
4
4
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
5
5
  import { Rnd } from "react-rnd";
6
6
  import { AnimatePresence, motion } from "framer-motion";
7
- import { usePreview } from "../state/index.js";
8
- import { classify, getExt, resolveUrl } from "../utils/index.js";
9
- import { useFileFetch } from "../hooks/useFileFetch.js";
10
- import { useDockLayout } from "../hooks/useDockLayout.js";
11
- import { useDeepLinkHash } from "../hooks/useDeepLinkHash.js";
12
- import { useAdaptiveSizing } from "../hooks/useAdaptiveSizing.js";
13
- import { useTouchZoom } from "../hooks/useTouchZoom.js";
14
- import PreviewHeader from "./PreviewHeader.js";
15
- import FileTabs from "./FileTabs.js";
16
- import PreviewContent from "./PreviewContent.js";
7
+ import { usePreview } from "../state/index.jsx";
8
+ import { classify, getExt, resolveUrl } from "../utils/index.jsx";
9
+ import { useFileFetch } from "../hooks/useFileFetch.jsx";
10
+ import { useDockLayout } from "../hooks/useDockLayout.jsx";
11
+ import { useDeepLinkHash } from "../hooks/useDeepLinkHash.jsx";
12
+ import { useAdaptiveSizing } from "../hooks/useAdaptiveSizing.jsx";
13
+ import { useTouchZoom } from "../hooks/useTouchZoom.jsx";
14
+ import PreviewHeader from "./PreviewHeader.jsx";
15
+ import FileTabs from "./FileTabs.jsx";
16
+ import PreviewContent from "./PreviewContent.jsx";
17
17
  import styles from "../styles.module.css";
18
+
18
19
  export default function PreviewViewer() {
19
20
  const {
20
21
  isOpen,
@@ -33,10 +34,12 @@ export default function PreviewViewer() {
33
34
  floatingState,
34
35
  setFloatingState,
35
36
  } = usePreview();
37
+
36
38
  const { siteConfig } = useDocusaurusContext();
37
39
  const customFields = siteConfig?.customFields;
38
40
  const corsProxyList = customFields?.corsProxyList || [];
39
41
  const location = useLocation();
42
+
40
43
  const [mounted, setMounted] = useState(typeof window !== "undefined");
41
44
  const [zoomLevel, setZoomLevel] = useState(1);
42
45
  const [isOnline, setIsOnline] = useState(
@@ -48,6 +51,7 @@ export default function PreviewViewer() {
48
51
  const [isInteracting, setIsInteracting] = useState(false);
49
52
  const [isDownloading, setIsDownloading] = useState(false);
50
53
  const popupBodyRef = useRef(null);
54
+
51
55
  useEffect(() => {
52
56
  setMounted(true);
53
57
  const handleOnline = () => setIsOnline(true);
@@ -64,6 +68,7 @@ export default function PreviewViewer() {
64
68
  window.removeEventListener("resize", handleResize);
65
69
  };
66
70
  }, []);
71
+
67
72
  const layout = useAdaptiveSizing({
68
73
  mode,
69
74
  windowWidth,
@@ -73,6 +78,7 @@ export default function PreviewViewer() {
73
78
  setFloatingState,
74
79
  });
75
80
  const { isDockMode, showAsPeek, isPipMode, isPopupMode } = layout;
81
+
76
82
  useTouchZoom({ containerRef: popupBodyRef, isOpen, zoomLevel, setZoomLevel });
77
83
  useDockLayout({
78
84
  isOpen,
@@ -83,6 +89,7 @@ export default function PreviewViewer() {
83
89
  peekHeight,
84
90
  });
85
91
  useDeepLinkHash(isOpen, sources, activeIndex, mode, baseSlug);
92
+
86
93
  const prevPathRef = useRef(location.pathname);
87
94
  useEffect(() => {
88
95
  if (prevPathRef.current !== location.pathname) {
@@ -90,9 +97,11 @@ export default function PreviewViewer() {
90
97
  if (isOpen) closePreview();
91
98
  }
92
99
  }, [location.pathname, isOpen, closePreview]);
100
+
93
101
  useEffect(() => {
94
102
  if (isOpen) setZoomLevel(1);
95
103
  }, [mode, isOpen]);
104
+
96
105
  useEffect(() => {
97
106
  if (!isOpen) return;
98
107
  const handler = (e) => {
@@ -102,10 +111,12 @@ export default function PreviewViewer() {
102
111
  return () =>
103
112
  window.removeEventListener("keydown", handler, { capture: true });
104
113
  }, [isOpen, closePreview]);
114
+
105
115
  const currentFile = sources[activeIndex] ?? sources[0] ?? null;
106
116
  const fileType = currentFile ? classify(currentFile.url) : null;
107
117
  const ext = currentFile ? getExt(currentFile.url) : "";
108
118
  const fileUrl = currentFile ? resolveUrl(currentFile.url) : "";
119
+
109
120
  const {
110
121
  content: textContent,
111
122
  loading: textLoading,
@@ -113,6 +124,7 @@ export default function PreviewViewer() {
113
124
  retry: retryFetch,
114
125
  setError,
115
126
  } = useFileFetch(currentFile?.url, fileType, isOpen);
127
+
116
128
  const handleDownload = useCallback(async () => {
117
129
  if (!fileUrl) return;
118
130
  setIsDownloading(true);
@@ -161,108 +173,66 @@ export default function PreviewViewer() {
161
173
  setIsDownloading(false);
162
174
  }
163
175
  }, [fileUrl, currentFile, corsProxyList]);
176
+
164
177
  if (!mounted || !currentFile) return null;
178
+
165
179
  const displayTitle =
166
180
  currentFile.title ||
167
181
  (fileType === "web"
168
182
  ? currentFile.url.replace(/^https?:\/\//, "").split("/")[0]
169
183
  : currentFile.url.split("/").pop() || "File");
170
- const header = jsxDEV_7x81h0kn(
171
- "div",
172
- {
173
- className: styles.headerWrapper,
174
- children: [
175
- showAsPeek &&
176
- jsxDEV_7x81h0kn(
177
- "div",
178
- { className: styles.peekHandle },
179
- undefined,
180
- false,
181
- undefined,
182
- this,
183
- ),
184
- jsxDEV_7x81h0kn(
185
- PreviewHeader,
186
- {
187
- displayTitle,
188
- fileType,
189
- fileUrl,
190
- mode,
191
- zoomLevel,
192
- onZoomChange: setZoomLevel,
193
- onToggleMode: toggleMode,
194
- onClose: closePreview,
195
- onDownload: handleDownload,
196
- isDownloading,
197
- modeSwitch,
198
- },
199
- undefined,
200
- false,
201
- undefined,
202
- this,
203
- ),
204
- ],
205
- },
206
- undefined,
207
- true,
208
- undefined,
209
- this,
184
+
185
+ const header = (
186
+ <div className={styles.headerWrapper}>
187
+ {showAsPeek && <div className={styles.peekHandle} />}
188
+ <PreviewHeader
189
+ displayTitle={displayTitle}
190
+ fileType={fileType}
191
+ fileUrl={fileUrl}
192
+ mode={mode}
193
+ zoomLevel={zoomLevel}
194
+ onZoomChange={setZoomLevel}
195
+ onToggleMode={toggleMode}
196
+ onClose={closePreview}
197
+ onDownload={handleDownload}
198
+ isDownloading={isDownloading}
199
+ modeSwitch={modeSwitch}
200
+ />
201
+ </div>
210
202
  );
211
- const innerContent = jsxDEV_7x81h0kn(
212
- "div",
213
- {
214
- className: styles.windowContent,
215
- children: [
216
- jsxDEV_7x81h0kn(
217
- FileTabs,
218
- { sources, activeIndex, onSelect: setActiveIndex },
219
- undefined,
220
- false,
221
- undefined,
222
- this,
223
- ),
224
- jsxDEV_7x81h0kn(
225
- "div",
226
- {
227
- className: `${styles.popupBody} ${fileType === "code" ? styles.isText : styles.isGrabbable}`,
228
- ref: (el) => {
229
- popupBodyRef.current = el;
230
- if (el && isOpen) el.focus({ preventScroll: true });
231
- },
232
- tabIndex: -1,
233
- children: jsxDEV_7x81h0kn(
234
- PreviewContent,
235
- {
236
- currentFile,
237
- fileType,
238
- fileUrl,
239
- isOnline,
240
- fetchErrors,
241
- textLoading,
242
- textContent,
243
- zoomLevel,
244
- ext,
245
- retryFetch,
246
- setError,
247
- },
248
- undefined,
249
- false,
250
- undefined,
251
- this,
252
- ),
253
- },
254
- undefined,
255
- false,
256
- undefined,
257
- this,
258
- ),
259
- ],
260
- },
261
- undefined,
262
- true,
263
- undefined,
264
- this,
203
+
204
+ const innerContent = (
205
+ <div className={styles.windowContent}>
206
+ <FileTabs
207
+ sources={sources}
208
+ activeIndex={activeIndex}
209
+ onSelect={setActiveIndex}
210
+ />
211
+ <div
212
+ className={`${styles.popupBody} ${fileType === "code" ? styles.isText : styles.isGrabbable}`}
213
+ ref={(el) => {
214
+ popupBodyRef.current = el;
215
+ if (el && isOpen) el.focus({ preventScroll: true });
216
+ }}
217
+ tabIndex={-1}
218
+ >
219
+ <PreviewContent
220
+ currentFile={currentFile}
221
+ fileType={fileType}
222
+ fileUrl={fileUrl}
223
+ isOnline={isOnline}
224
+ fetchErrors={fetchErrors}
225
+ textLoading={textLoading}
226
+ textContent={textContent}
227
+ zoomLevel={zoomLevel}
228
+ ext={ext}
229
+ retryFetch={retryFetch}
230
+ setError={setError}
231
+ />
232
+ </div>
233
+ </div>
265
234
  );
235
+
266
236
  const rndEnableResizing = isDockMode
267
237
  ? { left: true }
268
238
  : showAsPeek
@@ -311,6 +281,7 @@ export default function PreviewViewer() {
311
281
  },
312
282
  }
313
283
  : {};
284
+
314
285
  const rndMinWidth = isDockMode ? 380 : showAsPeek ? windowWidth : 380;
315
286
  const rndMinHeight = showAsPeek ? 150 : isDockMode ? undefined : 60;
316
287
  const rndMaxWidth = isDockMode
@@ -319,171 +290,92 @@ export default function PreviewViewer() {
319
290
  ? windowWidth
320
291
  : undefined;
321
292
  const rndMaxHeight = showAsPeek ? layout.vh * 0.85 : undefined;
293
+
322
294
  return createPortal(
323
- jsxDEV_7x81h0kn(
324
- AnimatePresence,
325
- {
326
- children:
327
- isOpen &&
328
- jsxDEV_7x81h0kn(
329
- motion.div,
330
- {
331
- id: "pv-viewer",
332
- "data-mode": mode,
333
- className: `${styles.previewSystem} ${showAsPeek ? styles.modePeek : ""} ${isDockMode ? styles.modeDock : ""} ${isPipMode ? styles.modePip : ""} ${isPopupMode ? styles.modePopup : ""}`,
334
- initial: { opacity: 0 },
335
- animate: { opacity: 1 },
336
- exit: { opacity: 0 },
337
- transition: { duration: 0.2 },
338
- onWheel: (e) => e.stopPropagation(),
339
- children: [
340
- isPopupMode &&
341
- jsxDEV_7x81h0kn(
342
- "div",
343
- {
344
- className: styles.previewBackdrop,
345
- onClick: closePreview,
346
- },
347
- undefined,
348
- false,
349
- undefined,
350
- this,
351
- ),
352
- isPopupMode
353
- ? jsxDEV_7x81h0kn(
354
- motion.div,
355
- {
356
- className: styles.windowFrame,
357
- initial: {
358
- opacity: 0,
359
- scale: 0.9,
360
- y: "-45%",
361
- x: "-50%",
362
- },
363
- animate: { opacity: 1, scale: 1, y: "-50%", x: "-50%" },
364
- exit: { opacity: 0, scale: 0.9, y: "-45%", x: "-50%" },
365
- transition: {
366
- type: "spring",
367
- damping: 25,
368
- stiffness: 300,
369
- },
370
- onClick: (e) => e.stopPropagation(),
371
- children: [
372
- jsxDEV_7x81h0kn(
373
- "div",
374
- {
375
- className: styles.dragHandleWrapper,
376
- children: header,
377
- },
378
- undefined,
379
- false,
380
- undefined,
381
- this,
382
- ),
383
- innerContent,
384
- ],
385
- },
386
- "desktop-popup",
387
- true,
388
- undefined,
389
- this,
390
- )
391
- : jsxDEV_7x81h0kn(
392
- Rnd,
393
- {
394
- position: layout.rndPosition,
395
- size: layout.rndSize,
396
- disableDragging: isDockMode || showAsPeek,
397
- enableResizing: rndEnableResizing,
398
- dragHandleClassName: styles.dragHandleWrapper,
399
- minWidth: rndMinWidth,
400
- minHeight: rndMinHeight,
401
- maxWidth: rndMaxWidth,
402
- maxHeight: rndMaxHeight,
403
- bounds: layout.rndBounds,
404
- resizeHandleStyles: rndResizeHandleStyles,
405
- onDragStart: () => setIsInteracting(true),
406
- onDragStop: (_e, d) => {
407
- setIsInteracting(false);
408
- if (!isDockMode && !showAsPeek)
409
- setFloatingState({ x: d.x, y: d.y });
410
- },
411
- onResizeStart: () => setIsInteracting(true),
412
- onResizeStop: (
413
- _e,
414
- _direction,
415
- ref,
416
- _delta,
417
- position,
418
- ) => {
419
- setIsInteracting(false);
420
- const newWidth = parseInt(ref.style.width, 10);
421
- const newHeight = parseInt(ref.style.height, 10);
422
- if (isDockMode) setDockWidth(newWidth);
423
- else if (showAsPeek) setPeekHeight(newHeight);
424
- else
425
- setFloatingState({
426
- width: newWidth,
427
- height: newHeight,
428
- ...position,
429
- });
430
- },
431
- className: styles.rndWrapper,
432
- style: {
433
- zIndex: 10,
434
- transition: isInteracting
435
- ? "none"
436
- : "all 0.4s cubic-bezier(0.22, 1, 0.36, 1)",
437
- },
438
- children: jsxDEV_7x81h0kn(
439
- "div",
440
- {
441
- className: `${styles.windowFrame} ${isInteracting ? styles.windowInteracting : ""}`,
442
- style: {
443
- width: "100%",
444
- height: "100%",
445
- position: "relative",
446
- },
447
- onClick: (e) => e.stopPropagation(),
448
- children: [
449
- jsxDEV_7x81h0kn(
450
- "div",
451
- {
452
- className: styles.dragHandleWrapper,
453
- children: header,
454
- },
455
- undefined,
456
- false,
457
- undefined,
458
- this,
459
- ),
460
- innerContent,
461
- ],
462
- },
463
- undefined,
464
- true,
465
- undefined,
466
- this,
467
- ),
468
- },
469
- `${mode}-${showAsPeek}`,
470
- false,
471
- undefined,
472
- this,
473
- ),
474
- ],
475
- },
476
- undefined,
477
- true,
478
- undefined,
479
- this,
480
- ),
481
- },
482
- undefined,
483
- false,
484
- undefined,
485
- this,
486
- ),
295
+ <AnimatePresence>
296
+ {isOpen && (
297
+ <motion.div
298
+ id="pv-viewer"
299
+ data-mode={mode}
300
+ className={`${styles.previewSystem} ${showAsPeek ? styles.modePeek : ""} ${isDockMode ? styles.modeDock : ""} ${isPipMode ? styles.modePip : ""} ${isPopupMode ? styles.modePopup : ""}`}
301
+ initial={{ opacity: 0 }}
302
+ animate={{ opacity: 1 }}
303
+ exit={{ opacity: 0 }}
304
+ transition={{ duration: 0.2 }}
305
+ onWheel={(e) => e.stopPropagation()}
306
+ >
307
+ {isPopupMode && (
308
+ <div className={styles.previewBackdrop} onClick={closePreview} />
309
+ )}
310
+
311
+ {isPopupMode ? (
312
+ <motion.div
313
+ key="desktop-popup"
314
+ className={styles.windowFrame}
315
+ initial={{ opacity: 0, scale: 0.9, y: "-45%", x: "-50%" }}
316
+ animate={{ opacity: 1, scale: 1, y: "-50%", x: "-50%" }}
317
+ exit={{ opacity: 0, scale: 0.9, y: "-45%", x: "-50%" }}
318
+ transition={{ type: "spring", damping: 25, stiffness: 300 }}
319
+ onClick={(e) => e.stopPropagation()}
320
+ >
321
+ <div className={styles.dragHandleWrapper}>{header}</div>
322
+ {innerContent}
323
+ </motion.div>
324
+ ) : (
325
+ <Rnd
326
+ key={`${mode}-${showAsPeek}`}
327
+ position={layout.rndPosition}
328
+ size={layout.rndSize}
329
+ disableDragging={isDockMode || showAsPeek}
330
+ enableResizing={rndEnableResizing}
331
+ dragHandleClassName={styles.dragHandleWrapper}
332
+ minWidth={rndMinWidth}
333
+ minHeight={rndMinHeight}
334
+ maxWidth={rndMaxWidth}
335
+ maxHeight={rndMaxHeight}
336
+ bounds={layout.rndBounds}
337
+ resizeHandleStyles={rndResizeHandleStyles}
338
+ onDragStart={() => setIsInteracting(true)}
339
+ onDragStop={(_e, d) => {
340
+ setIsInteracting(false);
341
+ if (!isDockMode && !showAsPeek)
342
+ setFloatingState({ x: d.x, y: d.y });
343
+ }}
344
+ onResizeStart={() => setIsInteracting(true)}
345
+ onResizeStop={(_e, _direction, ref, _delta, position) => {
346
+ setIsInteracting(false);
347
+ const newWidth = parseInt(ref.style.width, 10);
348
+ const newHeight = parseInt(ref.style.height, 10);
349
+ if (isDockMode) setDockWidth(newWidth);
350
+ else if (showAsPeek) setPeekHeight(newHeight);
351
+ else
352
+ setFloatingState({
353
+ width: newWidth,
354
+ height: newHeight,
355
+ ...position,
356
+ });
357
+ }}
358
+ className={styles.rndWrapper}
359
+ style={{
360
+ zIndex: 10,
361
+ transition: isInteracting
362
+ ? "none"
363
+ : "all 0.4s cubic-bezier(0.22, 1, 0.36, 1)",
364
+ }}
365
+ >
366
+ <div
367
+ className={`${styles.windowFrame} ${isInteracting ? styles.windowInteracting : ""}`}
368
+ style={{ width: "100%", height: "100%", position: "relative" }}
369
+ onClick={(e) => e.stopPropagation()}
370
+ >
371
+ <div className={styles.dragHandleWrapper}>{header}</div>
372
+ {innerContent}
373
+ </div>
374
+ </Rnd>
375
+ )}
376
+ </motion.div>
377
+ )}
378
+ </AnimatePresence>,
487
379
  document.body,
488
380
  );
489
381
  }
@@ -1,3 +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";
1
+ export { PreviewProvider, usePreview } from "./state/index.jsx";
2
+ export { default as ViewerWindow } from "./components/ViewerWindow.jsx";
3
+ export { Pv, SrcPv } from "./components/Triggers/index.jsx";