@johndimm/constellations 1.0.1 → 1.0.3
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/App.tsx +360 -66
- package/FullPageConstellations.tsx +7 -4
- package/components/AppConfirmDialog.tsx +1 -0
- package/components/AppHeader.tsx +67 -30
- package/components/AppNotifications.tsx +1 -0
- package/components/BrowsePeople.tsx +3 -0
- package/components/ControlPanel.tsx +229 -250
- package/components/Graph.tsx +251 -87
- package/components/HelpOverlay.tsx +2 -1
- package/components/NodeContextMenu.tsx +123 -3
- package/components/PeopleBrowserSidebar.tsx +15 -6
- package/components/Sidebar.tsx +46 -19
- package/components/TimelineView.tsx +1 -0
- package/hooks/useExpansion.ts +85 -230
- package/hooks/useGraphActions.ts +1 -0
- package/hooks/useGraphState.ts +75 -40
- package/hooks/useKioskMode.ts +1 -0
- package/hooks/useNodeClickHandler.ts +23 -15
- package/hooks/useSearchHandlers.ts +60 -21
- package/host.ts +1 -1
- package/index.css +17 -3
- package/index.tsx +5 -3
- package/package.json +4 -2
- package/services/aiService.ts +27 -0
- package/services/aiUtils.ts +285 -195
- package/services/cacheService.ts +1 -0
- package/services/crossrefService.ts +1 -0
- package/services/deepseekService.ts +479 -0
- package/services/geminiService.ts +543 -736
- package/services/graphUtils.ts +128 -18
- package/services/imageService.ts +18 -0
- package/services/openAlexService.ts +1 -0
- package/services/resolveImageForTitle.ts +458 -0
- package/services/wikipediaImage.ts +1 -0
- package/services/wikipediaService.ts +79 -49
- package/sessionHandoff.ts +26 -0
- package/types.ts +3 -0
- package/utils/evidenceUtils.ts +1 -0
- package/utils/graphLogicUtils.ts +1 -0
- package/utils/wikiUtils.ts +14 -2
package/components/AppHeader.tsx
CHANGED
|
@@ -1,70 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import { ChevronRight, ChevronLeft,
|
|
3
|
+
import { ChevronRight, ChevronLeft, X } from 'lucide-react';
|
|
3
4
|
import { GraphNode } from '../types';
|
|
4
5
|
|
|
5
6
|
interface AppHeaderProps {
|
|
6
7
|
showHeader: boolean;
|
|
7
8
|
panelCollapsed: boolean;
|
|
8
9
|
setPanelCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
|
|
9
|
-
showBrowse: boolean;
|
|
10
|
-
handleOpenPeopleBrowser: () => void;
|
|
11
10
|
selectedNode: GraphNode | null;
|
|
12
11
|
sidebarCollapsed: boolean;
|
|
13
|
-
setSidebarCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
|
|
14
12
|
setSidebarToggleSignal: React.Dispatch<React.SetStateAction<number>>;
|
|
15
|
-
|
|
13
|
+
/** When set, shows a top-right control that leaves full-screen (e.g. back to player). */
|
|
14
|
+
onClose?: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* When set (e.g. `/` or `/player`), the close control is a real `href` link so navigation works
|
|
17
|
+
* even if pointer-event layering blocked the old button. `onClick` can still run for cleanup.
|
|
18
|
+
*/
|
|
19
|
+
closeHref?: string;
|
|
20
|
+
/**
|
|
21
|
+
* When the host app shows its own top bar (e.g. Trailer Vision nav, ~44px), set so this header
|
|
22
|
+
* does not sit at viewport top:0 and steal clicks from the host nav. Use `top-11` for 2.75rem.
|
|
23
|
+
*/
|
|
24
|
+
offsetTopClass?: string;
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
const AppHeader: React.FC<AppHeaderProps> = ({
|
|
19
28
|
showHeader,
|
|
20
29
|
panelCollapsed,
|
|
21
30
|
setPanelCollapsed,
|
|
22
|
-
showBrowse,
|
|
23
|
-
handleOpenPeopleBrowser,
|
|
24
31
|
selectedNode,
|
|
25
32
|
sidebarCollapsed,
|
|
26
|
-
setSidebarCollapsed,
|
|
27
33
|
setSidebarToggleSignal,
|
|
28
|
-
|
|
34
|
+
onClose,
|
|
35
|
+
closeHref,
|
|
36
|
+
offsetTopClass = "top-0",
|
|
29
37
|
}) => {
|
|
30
38
|
if (!showHeader) return null;
|
|
31
39
|
|
|
32
40
|
return (
|
|
33
|
-
<header
|
|
34
|
-
|
|
41
|
+
<header
|
|
42
|
+
className={`absolute left-0 right-0 z-[200] h-14 max-h-14 min-h-14 shrink-0 pointer-events-auto bg-slate-900/95 backdrop-blur flex items-center justify-between px-2 sm:px-3 py-2 gap-2 overflow-x-hidden max-w-full ${offsetTopClass}`}
|
|
43
|
+
>
|
|
44
|
+
<div className="pointer-events-auto flex min-w-0 items-center gap-1.5 sm:gap-2">
|
|
35
45
|
<button
|
|
46
|
+
type="button"
|
|
36
47
|
onClick={() => setPanelCollapsed(c => !c)}
|
|
37
48
|
className="w-9 h-9 sm:w-10 sm:h-10 bg-slate-800/80 border border-slate-700 rounded-lg flex items-center justify-center text-slate-300 hover:text-white transition flex-shrink-0"
|
|
38
|
-
title={
|
|
49
|
+
title={
|
|
50
|
+
panelCollapsed
|
|
51
|
+
? "Show left panel — search, save/load, graph options"
|
|
52
|
+
: "Hide left panel"
|
|
53
|
+
}
|
|
54
|
+
aria-label={panelCollapsed ? "Show control panel" : "Hide control panel"}
|
|
39
55
|
>
|
|
40
56
|
{panelCollapsed ? <ChevronRight size={18} /> : <ChevronLeft size={18} />}
|
|
41
57
|
</button>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
{closeHref ? (
|
|
59
|
+
<a
|
|
60
|
+
href={closeHref}
|
|
61
|
+
title="Film & Music — return to hub"
|
|
62
|
+
className="text-base sm:text-lg font-bold text-red-500 whitespace-nowrap hover:text-red-400 transition-colors"
|
|
63
|
+
>
|
|
64
|
+
Constellations
|
|
65
|
+
</a>
|
|
66
|
+
) : (
|
|
67
|
+
<span className="text-base sm:text-lg font-bold text-red-500 whitespace-nowrap">
|
|
68
|
+
Constellations
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
51
71
|
</div>
|
|
52
|
-
<div className="flex items-center gap-
|
|
53
|
-
<button
|
|
54
|
-
onClick={handleOpenPeopleBrowser}
|
|
55
|
-
className={`text-sm font-bold uppercase tracking-widest transition-colors ${showBrowse ? 'text-red-500' : 'text-slate-400 hover:text-white'}`}
|
|
56
|
-
>
|
|
57
|
-
People
|
|
58
|
-
</button>
|
|
72
|
+
<div className="flex items-center gap-2 sm:gap-3 flex-shrink-0 mr-1">
|
|
59
73
|
{selectedNode && (
|
|
60
74
|
<button
|
|
61
|
-
|
|
75
|
+
type="button"
|
|
76
|
+
onClick={() => {
|
|
77
|
+
setSidebarToggleSignal((s) => s + 1);
|
|
78
|
+
}}
|
|
62
79
|
className="w-9 h-9 sm:w-10 sm:h-10 bg-slate-800/80 border border-slate-700 rounded-lg flex items-center justify-center text-slate-300 hover:text-white transition flex-shrink-0"
|
|
63
|
-
title=
|
|
80
|
+
title={
|
|
81
|
+
sidebarCollapsed
|
|
82
|
+
? "Show right details (selected node on graph)"
|
|
83
|
+
: "Hide right details"
|
|
84
|
+
}
|
|
85
|
+
aria-label={sidebarCollapsed ? "Show details panel" : "Hide details panel"}
|
|
64
86
|
>
|
|
65
87
|
{sidebarCollapsed ? <ChevronLeft size={18} /> : <ChevronRight size={18} />}
|
|
66
88
|
</button>
|
|
67
89
|
)}
|
|
90
|
+
{!closeHref && onClose && (
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
onClick={(e) => {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
onClose();
|
|
97
|
+
}}
|
|
98
|
+
className="w-9 h-9 sm:w-10 sm:h-10 bg-slate-800/80 border border-slate-700 rounded-lg flex items-center justify-center text-slate-300 hover:text-white hover:border-slate-600 transition flex-shrink-0"
|
|
99
|
+
title="Leave full screen and return to Trailer Vision"
|
|
100
|
+
aria-label="Close constellations"
|
|
101
|
+
>
|
|
102
|
+
<X size={20} strokeWidth={2} />
|
|
103
|
+
</button>
|
|
104
|
+
)}
|
|
68
105
|
</div>
|
|
69
106
|
</header>
|
|
70
107
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
3
|
import { Search, ChevronLeft, ChevronRight, X, Filter } from 'lucide-react';
|
|
3
4
|
|
|
@@ -124,6 +125,8 @@ const BrowsePeople: React.FC<BrowsePeopleProps> = ({ baseUrl = '', onSelect, exp
|
|
|
124
125
|
'South African', 'New Zealander', 'Israeli', 'Saudi Arabian', 'Korean', 'Thai', 'Vietnamese', 'Indonesian'
|
|
125
126
|
];
|
|
126
127
|
|
|
128
|
+
const isPureBrowse = useCallback(() => !searchTerm.trim() && !occupation && !nationality, [searchTerm, occupation, nationality]);
|
|
129
|
+
|
|
127
130
|
const buildSearchQuery = useCallback(() => {
|
|
128
131
|
const parts: string[] = [];
|
|
129
132
|
|