six-degrees 0.4.10 → 0.5.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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +9 -9
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/admin-delete/route.js +1 -1
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js +3 -2
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/social/crm/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/social/crm/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/social/crm/route.js +10 -0
- package/.next/standalone/.next/server/app/api/social/crm/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/social/crm/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/social/messages/route.js +4 -3
- package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js +4 -3
- package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +15 -15
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/launch.html +2 -2
- package/.next/standalone/.next/server/app/launch.rsc +15 -15
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths.html +1 -1
- package/.next/standalone/.next/server/app/paths.rsc +15 -15
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/profile.html +1 -1
- package/.next/standalone/.next/server/app/profile.rsc +15 -15
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/queue.html +1 -1
- package/.next/standalone/.next/server/app/queue.rsc +15 -15
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/scores.html +1 -1
- package/.next/standalone/.next/server/app/scores.rsc +15 -15
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +15 -15
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +15 -15
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/social.html +1 -1
- package/.next/standalone/.next/server/app/social.rsc +15 -15
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0bat8nx._.js → [root-of-the-server]__05_3-22._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__06mi9k2._.js → [root-of-the-server]__13dx4sd._.js} +7 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__15wc9e-._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__20rwfdw._.js +8 -0
- package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0ea9qwy._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1oqfuh8._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1xh07bp._.js +1 -1
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_social_crm_route_actions_0d1aflv.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +8 -0
- package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +8 -0
- package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +8 -0
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +8 -8
- package/.next/standalone/.next/server/chunks/lib_linkedin-export_12imqxg.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_04s8mzr.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_053z7as.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0b_-2te.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0dhbxdm.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0dxlk31.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0f8b-qc.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0pzie7_.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0r76fq_.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0ut7pjp.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_15zyqaz.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_18zpjtq.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1a8xkiz.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1e_55xo.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1oxfd1_.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1s0lod0.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_scoring_1-e4ur0.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_01kacen._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_1ap1tu_._.js → _0gtv9jb._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0jdkqgi._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0xi-fbs._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0xmwmfv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1-b9hj7._.js +9 -0
- package/.next/standalone/.next/server/chunks/ssr/_112ewem._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_16ab63q._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1fxm0-s._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1ra1d3r._.js +9 -0
- package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +22 -10
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +6 -5
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +19 -3
- package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_13rapwj._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +3 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/03bziijw5srol.js +1 -0
- package/.next/standalone/.next/static/chunks/0bgq8wmopl_ig.js +7 -0
- package/.next/standalone/.next/static/chunks/0ezus6p2eb-vg.js +1 -0
- package/.next/standalone/.next/static/chunks/0g_fy2034bp0x.js +34 -0
- package/.next/standalone/.next/static/chunks/0q5dru4q6gxl5.js +22 -0
- package/.next/standalone/.next/static/chunks/0w-byiwb2zax8.js +2 -0
- package/.next/standalone/.next/static/chunks/1g7jcovdejc9-.js +1 -0
- package/.next/standalone/.next/static/chunks/1i51yylxdzht1.js +1 -0
- package/.next/{static/chunks/1xptlvtcz6654.css → standalone/.next/static/chunks/1x_ysly42-teq.css} +1 -1
- package/.next/standalone/.next/static/chunks/1zf8swaasjf1e.js +43 -0
- package/.next/standalone/.next/static/chunks/2rqtpccruavf2.js +1 -0
- package/.next/standalone/.next/static/chunks/2wgz9ietkqqe6.js +1 -0
- package/.next/standalone/.next/static/chunks/30x3oq_st7a5r.js +1 -0
- package/.next/standalone/.next/static/chunks/355ryio1b7sm1.js +1 -0
- package/.next/standalone/.next/static/chunks/3ap5hgma7n0o7.js +1 -0
- package/.next/standalone/.next/static/chunks/3fci6qi39-1n5.js +1 -0
- package/.next/standalone/.next/static/chunks/{24tvdun1cb3g1.js → 3sowbvbaj1s6n.js} +1 -1
- package/.next/standalone/CHANGELOG.md +235 -0
- package/.next/standalone/app/api/data/export/route.js +2 -1
- package/.next/standalone/app/api/ingest/route.js +40 -1
- package/.next/standalone/app/api/scraper/route.js +12 -2
- package/.next/standalone/app/api/settings/sector-preview/route.js +2 -1
- package/.next/standalone/app/api/social/crm/route.js +37 -0
- package/.next/standalone/app/api/social/messages/route.js +44 -8
- package/.next/standalone/app/api/social/route.js +80 -22
- package/.next/standalone/app/components/AppTabs.js +59 -0
- package/.next/standalone/app/components/ChainView.js +303 -89
- package/.next/standalone/app/components/CirclePanel.js +162 -0
- package/.next/standalone/app/components/CompanyScores.js +2 -2
- package/.next/standalone/app/components/FieldStep.js +4 -4
- package/.next/standalone/app/components/FilterPanel.js +121 -183
- package/.next/standalone/app/components/ForceGraph.js +41 -3
- package/.next/standalone/app/components/GalaxyLab.js +26 -31
- package/.next/standalone/app/components/LegacyScoresCard.js +2 -2
- package/.next/standalone/app/components/MapControls.js +154 -0
- package/.next/standalone/app/components/NoteDetail.js +118 -0
- package/.next/standalone/app/components/PathsAnalyzer.js +147 -110
- package/.next/standalone/app/components/PeopleMap.js +308 -0
- package/.next/standalone/app/components/ScanRadar.js +129 -0
- package/.next/standalone/app/components/ScanStatusBar.js +72 -27
- package/.next/standalone/app/components/SeparationView.js +626 -118
- package/.next/standalone/app/components/Sidebar.js +28 -2
- package/.next/standalone/app/components/settings/DataSection.js +12 -3
- package/.next/standalone/app/components/settings/NetworkHealthSection.js +1 -1
- package/.next/standalone/app/components/settings/SectorSection.js +2 -2
- package/.next/standalone/app/components/settings/TierSection.js +1 -1
- package/.next/standalone/app/components/settings/TitleSection.js +149 -0
- package/.next/standalone/app/components/views.js +15 -14
- package/.next/standalone/app/globals.css +11 -0
- package/.next/standalone/app/page.js +89 -156
- package/.next/standalone/app/paths/page.js +39 -27
- package/.next/standalone/app/profile/page.js +33 -5
- package/.next/standalone/app/queue/page.js +56 -34
- package/.next/standalone/app/scores/page.js +16 -66
- package/.next/standalone/app/settings/page.js +27 -13
- package/.next/standalone/app/setup/page.js +298 -205
- package/.next/standalone/app/social/Crm.js +683 -0
- package/.next/standalone/app/social/SocialHub.js +374 -0
- package/.next/standalone/app/social/Thread.js +90 -0
- package/.next/standalone/app/social/page.js +10 -351
- package/.next/standalone/lib/chain-layout.js +105 -35
- package/.next/standalone/lib/data-export.js +10 -4
- package/.next/standalone/lib/data-folder.js +9 -0
- package/.next/standalone/lib/data-import.js +13 -3
- package/.next/standalone/lib/degrees.js +0 -6
- package/.next/standalone/lib/dot-rings.js +25 -0
- package/.next/standalone/lib/galaxy-lab.js +65 -6
- package/.next/standalone/lib/ingest.js +2 -0
- package/.next/standalone/lib/island.js +40 -0
- package/.next/standalone/lib/linkedin-export.js +267 -46
- package/.next/standalone/lib/linkedin-limits.js +6 -2
- package/.next/standalone/lib/map-heat.js +20 -0
- package/.next/standalone/lib/network-health.js +1 -1
- package/.next/standalone/lib/notifications.js +121 -0
- package/.next/standalone/lib/people-map.js +82 -0
- package/.next/standalone/lib/rarity.js +45 -3
- package/.next/standalone/lib/reach.js +7 -6
- package/.next/standalone/lib/rpc.js +15 -4
- package/.next/standalone/lib/scan-pace.js +46 -0
- package/.next/standalone/lib/scoring.js +39 -8
- package/.next/standalone/lib/scraper-client.js +19 -6
- package/.next/standalone/lib/sector-focus.js +4 -4
- package/.next/standalone/lib/separation.js +137 -10
- package/.next/standalone/lib/settings-effects.js +20 -11
- package/.next/standalone/lib/settings.js +3 -0
- package/.next/standalone/lib/social-crm.js +415 -0
- package/.next/standalone/lib/social-store.js +13 -6
- package/.next/standalone/lib/tier-grid.js +99 -0
- package/.next/standalone/lib/title-ranking.js +83 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +177 -35
- package/.next/static/chunks/03bziijw5srol.js +1 -0
- package/.next/static/chunks/0bgq8wmopl_ig.js +7 -0
- package/.next/static/chunks/0ezus6p2eb-vg.js +1 -0
- package/.next/static/chunks/0g_fy2034bp0x.js +34 -0
- package/.next/static/chunks/0q5dru4q6gxl5.js +22 -0
- package/.next/static/chunks/0w-byiwb2zax8.js +2 -0
- package/.next/static/chunks/1g7jcovdejc9-.js +1 -0
- package/.next/static/chunks/1i51yylxdzht1.js +1 -0
- package/.next/{standalone/.next/static/chunks/1xptlvtcz6654.css → static/chunks/1x_ysly42-teq.css} +1 -1
- package/.next/static/chunks/1zf8swaasjf1e.js +43 -0
- package/.next/static/chunks/2rqtpccruavf2.js +1 -0
- package/.next/static/chunks/2wgz9ietkqqe6.js +1 -0
- package/.next/static/chunks/30x3oq_st7a5r.js +1 -0
- package/.next/static/chunks/355ryio1b7sm1.js +1 -0
- package/.next/static/chunks/3ap5hgma7n0o7.js +1 -0
- package/.next/static/chunks/3fci6qi39-1n5.js +1 -0
- package/.next/static/chunks/{24tvdun1cb3g1.js → 3sowbvbaj1s6n.js} +1 -1
- package/CHANGELOG.md +235 -0
- package/lib/chain-layout.js +105 -35
- package/lib/data-export.js +10 -4
- package/lib/data-folder.js +9 -0
- package/lib/data-import.js +13 -3
- package/lib/degrees.js +0 -6
- package/lib/dot-rings.js +25 -0
- package/lib/galaxy-lab.js +65 -6
- package/lib/ingest.js +2 -0
- package/lib/island.js +40 -0
- package/lib/linkedin-export.js +267 -46
- package/lib/linkedin-limits.js +6 -2
- package/lib/map-heat.js +20 -0
- package/lib/network-health.js +1 -1
- package/lib/notifications.js +121 -0
- package/lib/people-map.js +82 -0
- package/lib/rarity.js +45 -3
- package/lib/reach.js +7 -6
- package/lib/rpc.js +15 -4
- package/lib/scan-pace.js +46 -0
- package/lib/scoring.js +39 -8
- package/lib/scraper-client.js +19 -6
- package/lib/sector-focus.js +4 -4
- package/lib/separation.js +137 -10
- package/lib/settings-effects.js +20 -11
- package/lib/settings.js +3 -0
- package/lib/social-crm.js +415 -0
- package/lib/social-store.js +13 -6
- package/lib/tier-grid.js +99 -0
- package/lib/title-ranking.js +83 -0
- package/package.json +1 -1
- package/scripts/scrape.py +177 -35
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08f5awg._.js +0 -8
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17hjtzl._.js +0 -8
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__20tmem7._.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_18cr1gi._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_rpc_03i8xef.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_08fc3rp.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_08r2t_q.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0btpv1t.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_rpc_0cm2ev3.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0iovswz.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0is8flp.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0v8ajtd.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0xgmvvt.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_144mzbf.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1bggi0n.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1dkcu9f.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1o0jb6w.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0c_y09g._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0ezj4e0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0j4-lc3._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0l8cxmo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0xkur4p._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_14iv_zy._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_15x6q32._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1errbuf._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_212xw8q._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_19c2d9c._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_scores_page_09wepvv.js +0 -3
- package/.next/standalone/.next/static/chunks/07dyt47mp4s9-.js +0 -1
- package/.next/standalone/.next/static/chunks/0a5iadnmt9u9k.js +0 -1
- package/.next/standalone/.next/static/chunks/160wjb73ddwqd.js +0 -6
- package/.next/standalone/.next/static/chunks/1c_n0973t07l0.js +0 -2
- package/.next/standalone/.next/static/chunks/1e1n0kkz-psdb.js +0 -1
- package/.next/standalone/.next/static/chunks/206rm6j42gl_a.js +0 -1
- package/.next/standalone/.next/static/chunks/236f0jtp68j_h.js +0 -1
- package/.next/standalone/.next/static/chunks/2coxzjm_k6ilr.js +0 -1
- package/.next/standalone/.next/static/chunks/2kfhc58df2xyo.js +0 -1
- package/.next/standalone/.next/static/chunks/2pw6_osz1n_te.js +0 -1
- package/.next/standalone/.next/static/chunks/39hr8d-b2ibtw.js +0 -31
- package/.next/standalone/.next/static/chunks/3zw8bv7-mc4n6.js +0 -33
- package/.next/standalone/app/components/OrbitGraph.js +0 -737
- package/.next/standalone/app/social/Conversations.js +0 -246
- package/.next/static/chunks/07dyt47mp4s9-.js +0 -1
- package/.next/static/chunks/0a5iadnmt9u9k.js +0 -1
- package/.next/static/chunks/160wjb73ddwqd.js +0 -6
- package/.next/static/chunks/1c_n0973t07l0.js +0 -2
- package/.next/static/chunks/1e1n0kkz-psdb.js +0 -1
- package/.next/static/chunks/206rm6j42gl_a.js +0 -1
- package/.next/static/chunks/236f0jtp68j_h.js +0 -1
- package/.next/static/chunks/2coxzjm_k6ilr.js +0 -1
- package/.next/static/chunks/2kfhc58df2xyo.js +0 -1
- package/.next/static/chunks/2pw6_osz1n_te.js +0 -1
- package/.next/static/chunks/39hr8d-b2ibtw.js +0 -31
- package/.next/static/chunks/3zw8bv7-mc4n6.js +0 -33
- /package/.next/standalone/.next/static/{7zWJnSkfSoRhRsqY6ZKtD → I-cj79yE2IZ8taX2dZGp3}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{7zWJnSkfSoRhRsqY6ZKtD → I-cj79yE2IZ8taX2dZGp3}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{7zWJnSkfSoRhRsqY6ZKtD → I-cj79yE2IZ8taX2dZGp3}/_ssgManifest.js +0 -0
- /package/.next/static/{7zWJnSkfSoRhRsqY6ZKtD → I-cj79yE2IZ8taX2dZGp3}/_buildManifest.js +0 -0
- /package/.next/static/{7zWJnSkfSoRhRsqY6ZKtD → I-cj79yE2IZ8taX2dZGp3}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{7zWJnSkfSoRhRsqY6ZKtD → I-cj79yE2IZ8taX2dZGp3}/_ssgManifest.js +0 -0
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
16
16
|
import { forceCollide, forceLink, forceManyBody, forceSimulation, forceX, forceY } from 'd3';
|
|
17
17
|
import { useCompanyScores, ScorePicker } from './CompanyScores';
|
|
18
|
+
import PeopleMap from './PeopleMap';
|
|
19
|
+
import { TierGrid } from './FilterPanel';
|
|
20
|
+
import { MapLook, useLivePhysics, HeatDefs, HeatGlow, PHYSICS_OFF } from './MapControls';
|
|
21
|
+
import { makeGrid, shows, gridCounts } from '../../lib/tier-grid';
|
|
22
|
+
import { heatBy, heatColour } from '../../lib/galaxy-lab';
|
|
23
|
+
import { companyStrength } from '../../lib/map-heat';
|
|
18
24
|
import {
|
|
19
25
|
buildCompanyIndex, companyLinks, companyOf, getSeniority, industryOf, industryByKey,
|
|
20
26
|
INDUSTRIES, UNKNOWN_INDUSTRY, waysInto, isSenior,
|
|
@@ -25,13 +31,13 @@ const LINE = '1px solid rgba(255,255,255,0.1)';
|
|
|
25
31
|
const MAX_BUBBLES = 140;
|
|
26
32
|
const ALL_INDUSTRIES = [...INDUSTRIES, UNKNOWN_INDUSTRY];
|
|
27
33
|
|
|
28
|
-
function jitter(text) {
|
|
34
|
+
export function jitter(text) {
|
|
29
35
|
let h = 2166136261;
|
|
30
36
|
for (let i = 0; i < text.length; i++) h = Math.imul(h ^ text.charCodeAt(i), 16777619);
|
|
31
37
|
return ((h >>> 0) % 1000) / 1000;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
function Seg({ value, onChange, options }) {
|
|
40
|
+
export function Seg({ value, onChange, options }) {
|
|
35
41
|
return (
|
|
36
42
|
<div style={{ display: 'flex', borderRadius: 7, overflow: 'hidden', border: LINE }}>
|
|
37
43
|
{options.map(([v, label]) => (
|
|
@@ -44,7 +50,7 @@ function Seg({ value, onChange, options }) {
|
|
|
44
50
|
);
|
|
45
51
|
}
|
|
46
52
|
|
|
47
|
-
function useSize(ref) {
|
|
53
|
+
export function useSize(ref) {
|
|
48
54
|
const [size, setSize] = useState({ w: 0, h: 0 });
|
|
49
55
|
useEffect(() => {
|
|
50
56
|
const el = ref.current;
|
|
@@ -61,22 +67,73 @@ function useSize(ref) {
|
|
|
61
67
|
return size;
|
|
62
68
|
}
|
|
63
69
|
|
|
64
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* The left panel, as on the map page (app/components/FilterPanel.js): a
|
|
72
|
+
* Filters tab at the edge until opened, then a column the map makes room for.
|
|
73
|
+
* Paths' filters, and the ways to read the map, live here (Blake, 2026-10-02:
|
|
74
|
+
* "incorporate the filter with maybe ways to read the data more").
|
|
75
|
+
*/
|
|
76
|
+
export function SidePanel({ open, onToggle, children }) {
|
|
77
|
+
if (!open) {
|
|
78
|
+
return (
|
|
79
|
+
<button type="button" onClick={onToggle} style={{
|
|
80
|
+
position: 'fixed', left: 16, top: 140, zIndex: 30, cursor: 'pointer', height: 36, borderRadius: 18, padding: '0 14px 0 10px',
|
|
81
|
+
display: 'flex', alignItems: 'center', gap: 6, background: 'rgba(52,152,219,0.15)', border: '2px solid rgba(52,152,219,0.5)',
|
|
82
|
+
color: '#3498DB', fontWeight: 700, boxShadow: '0 0 12px rgba(52,152,219,0.3)', backdropFilter: 'blur(8px)',
|
|
83
|
+
}}>
|
|
84
|
+
<span style={{ fontSize: 18 }}>›</span><span style={{ fontSize: 11, fontWeight: 600 }}>Filters</span>
|
|
85
|
+
</button>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return (
|
|
89
|
+
<aside style={{
|
|
90
|
+
width: 300, flexShrink: 0, height: '100%', overflowY: 'auto', boxSizing: 'border-box', padding: '16px 14px',
|
|
91
|
+
borderRight: '1px solid rgba(52,152,219,0.15)', background: 'rgba(10,15,30,0.65)', fontSize: 13,
|
|
92
|
+
}}>
|
|
93
|
+
<button type="button" onClick={onToggle} style={{
|
|
94
|
+
display: 'flex', alignItems: 'center', gap: 6, width: '100%', marginBottom: 14, padding: '6px 12px', borderRadius: 6, cursor: 'pointer',
|
|
95
|
+
background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)', color: '#aaa', fontSize: 12, fontWeight: 600,
|
|
96
|
+
}}><span style={{ fontSize: 16 }}>›</span> Close</button>
|
|
97
|
+
{children}
|
|
98
|
+
</aside>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const panelHeading = { fontSize: 9, fontWeight: 700, color: '#555', letterSpacing: 1, margin: '14px 0 6px', textTransform: 'uppercase' };
|
|
103
|
+
|
|
104
|
+
/** Does this person pass the filters? Tier and degree from the grid, as in Network Circle. */
|
|
65
105
|
function passes(p, f) {
|
|
66
|
-
if (f.
|
|
106
|
+
if (f.grid && !shows(f.grid, p.tier, Number(p.degree) || 1)) return false;
|
|
67
107
|
if (f.seniority === 'senior' && !isSenior(p.headline)) return false;
|
|
68
108
|
if (f.seniority === 'csuite' && getSeniority(p.headline).level < 6) return false;
|
|
69
|
-
if (f.tier === 'SA' && p.tier !== 'S' && p.tier !== 'A') return false;
|
|
70
109
|
return true;
|
|
71
110
|
}
|
|
72
111
|
|
|
73
|
-
|
|
74
|
-
|
|
112
|
+
/** What the map's bubbles are: companies, or your connections (Paths → People). An easy switch at the top of the panel. */
|
|
113
|
+
function ShowSwitch({ show, onShow }) {
|
|
114
|
+
return (
|
|
115
|
+
<div style={{ marginBottom: 6 }}>
|
|
116
|
+
<div style={{ ...panelHeading, marginTop: 0 }}>Bubbles are</div>
|
|
117
|
+
<Seg value={show} onChange={onShow} options={[['companies', 'Companies'], ['people', 'People']]} />
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default function PathsAnalyzer({ d1 = [], d2 = [], d3 = [], initialShow = 'companies', onOpenCompany }) {
|
|
123
|
+
const [show, setShow] = useState(initialShow);
|
|
124
|
+
const [filters, setFilters] = useState(() => ({ seniority: 'all', grid: makeGrid([1, 2, 3]) }));
|
|
125
|
+
const [colourBy, setColourBy] = useState('sector');
|
|
126
|
+
const [physics, setPhysics] = useState(PHYSICS_OFF);
|
|
75
127
|
const [hidden, setHidden] = useState(() => new Set()); // industries toggled off
|
|
76
128
|
const [query, setQuery] = useState('');
|
|
77
129
|
const [focus, setFocus] = useState(null); // { kind: 'company'|'industry', key }
|
|
130
|
+
const [panelOpen, setPanelOpen] = useState(true);
|
|
131
|
+
// Ways to read the map: what a bubble's size means, and which names show.
|
|
132
|
+
const [sizeBy, setSizeBy] = useState('people'); // 'people' | 'sa' | 'known'
|
|
133
|
+
const [labels, setLabels] = useState('top'); // 'top' | 'all' | 'none'
|
|
78
134
|
|
|
79
135
|
const rows = useMemo(() => [...d1, ...d2, ...d3], [d1, d2, d3]);
|
|
136
|
+
const counts = useMemo(() => gridCounts({ 1: d1, 2: d2, 3: d3 }), [d1, d2, d3]);
|
|
80
137
|
const index = useMemo(() => buildCompanyIndex(rows), [rows]);
|
|
81
138
|
const links = useMemo(() => companyLinks(d1, d2), [d1, d2]);
|
|
82
139
|
|
|
@@ -115,44 +172,65 @@ export default function PathsAnalyzer({ d1 = [], d2 = [], d3 = [], tab = 'map',
|
|
|
115
172
|
const panel = focus?.kind === 'company' ? index.get(focus.key)
|
|
116
173
|
: focus?.kind === 'industry' ? industries.find((i) => i.key === focus.key) : null;
|
|
117
174
|
|
|
175
|
+
const look = (heatHint) => (
|
|
176
|
+
<MapLook colourBy={colourBy} onColourBy={setColourBy} physics={physics} onPhysics={setPhysics} heatHint={heatHint} />
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// People: the same map with your connections as the bubbles (app/components/PeopleMap.js),
|
|
180
|
+
// with the same switch, colours and physics.
|
|
181
|
+
if (show === 'people') {
|
|
182
|
+
return (
|
|
183
|
+
<PeopleMap d1={d1} d2={d2} top={<ShowSwitch show={show} onShow={setShow} />}
|
|
184
|
+
colourBy={colourBy} physics={physics}
|
|
185
|
+
look={look('How strong each cluster is, person for person (S counts 3, A 2, the rest 1): the hotter, the stronger. Size is still how big it is.')} />
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
118
189
|
return (
|
|
119
190
|
<div style={{ display: 'flex', flex: 1, minHeight: 0 }}>
|
|
120
|
-
<
|
|
121
|
-
<
|
|
191
|
+
<SidePanel open={panelOpen} onToggle={() => setPanelOpen((o) => !o)}>
|
|
192
|
+
<ShowSwitch show={show} onShow={setShow} />
|
|
193
|
+
<Filters filters={filters} setFilters={setFilters} counts={counts} query={query} setQuery={setQuery}
|
|
122
194
|
industries={industries} hidden={hidden} setHidden={setHidden}
|
|
123
195
|
onIndustry={(key) => setFocus({ kind: 'industry', key })} />
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
196
|
+
<div style={panelHeading}>Read the map</div>
|
|
197
|
+
<div style={{ fontSize: 11, color: '#8b9a9a', marginBottom: 4 }}>Bubble size</div>
|
|
198
|
+
<Seg value={sizeBy} onChange={setSizeBy} options={[['people', 'Your people'], ['sa', 'S & A there'], ['known', 'You know']]} />
|
|
199
|
+
<div style={{ fontSize: 11, color: '#8b9a9a', margin: '10px 0 4px' }}>Names</div>
|
|
200
|
+
<Seg value={labels} onChange={setLabels} options={[['top', 'Biggest'], ['all', 'All'], ['none', 'None']]} />
|
|
201
|
+
{look('How strong your people at each company are: the average power score of the five strongest. The hotter, the stronger; size is still how many.')}
|
|
202
|
+
</SidePanel>
|
|
203
|
+
{/* Room at the top for the notch's Map / Companies, so it never covers a label */}
|
|
204
|
+
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', paddingTop: 40, boxSizing: 'border-box' }}>
|
|
205
|
+
<CompanyMap companies={companies} links={links} focus={focus} sizeBy={sizeBy} labels={labels}
|
|
206
|
+
colourBy={colourBy} physics={physics}
|
|
207
|
+
onCompany={(name) => setFocus({ kind: 'company', key: name })}
|
|
208
|
+
onIndustry={(key) => setFocus({ kind: 'industry', key })}
|
|
209
|
+
onClear={() => setFocus(null)} />
|
|
134
210
|
</div>
|
|
135
211
|
{panel && (
|
|
136
212
|
<AnalyzerPanel focus={focus} data={panel} index={index} links={links} d1={d1} d2={d2}
|
|
137
213
|
filters={filters} onClose={() => setFocus(null)}
|
|
138
214
|
onCompany={(name) => setFocus({ kind: 'company', key: name })}
|
|
215
|
+
onIndustry={(key) => setFocus({ kind: 'industry', key })}
|
|
139
216
|
onOpenCompany={onOpenCompany} />
|
|
140
217
|
)}
|
|
141
218
|
</div>
|
|
142
219
|
);
|
|
143
220
|
}
|
|
144
221
|
|
|
145
|
-
function Filters({ filters, setFilters, query, setQuery, industries, hidden, setHidden, onIndustry }) {
|
|
222
|
+
function Filters({ filters, setFilters, counts, query, setQuery, industries, hidden, setHidden, onIndustry }) {
|
|
146
223
|
const set = (k, v) => setFilters((f) => ({ ...f, [k]: v }));
|
|
147
224
|
return (
|
|
148
|
-
<div style={{
|
|
149
|
-
<div style={
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
225
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
|
226
|
+
<div style={panelHeading}>Filter</div>
|
|
227
|
+
<input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Find a company"
|
|
228
|
+
style={{ padding: '6px 10px', borderRadius: 7, border: LINE, background: 'rgba(255,255,255,0.05)', color: '#fff', fontSize: 13, width: '100%', boxSizing: 'border-box' }} />
|
|
229
|
+
{/* The same tiers × degrees as Network Circle (Blake, 2026-10-02) */}
|
|
230
|
+
<TierGrid grid={filters.grid} counts={counts} onChange={(g) => set('grid', g)} mode="paths" />
|
|
231
|
+
<div style={{ fontSize: 11, color: '#8b9a9a', marginTop: -10 }}>Level</div>
|
|
232
|
+
<Seg value={filters.seniority} onChange={(v) => set('seniority', v)} options={[['all', 'Any level'], ['senior', 'Director+'], ['csuite', 'C-suite']]} />
|
|
233
|
+
<div style={panelHeading}>Industries</div>
|
|
156
234
|
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
|
|
157
235
|
{industries.map((i) => {
|
|
158
236
|
const off = hidden.has(i.key);
|
|
@@ -168,13 +246,13 @@ function Filters({ filters, setFilters, query, setQuery, industries, hidden, set
|
|
|
168
246
|
</span>
|
|
169
247
|
);
|
|
170
248
|
})}
|
|
171
|
-
<span style={{ fontSize: 11, color: '#667', alignSelf: 'center' }}>
|
|
249
|
+
<span style={{ fontSize: 11, color: '#667', alignSelf: 'center' }}>Inferred from companies and headlines. ● hides one; its name opens it.</span>
|
|
172
250
|
</div>
|
|
173
251
|
</div>
|
|
174
252
|
);
|
|
175
253
|
}
|
|
176
254
|
|
|
177
|
-
function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear }) {
|
|
255
|
+
function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear, sizeBy = 'people', labels: names = 'top', colourBy = 'sector', physics = PHYSICS_OFF }) {
|
|
178
256
|
const wrap = useRef(null);
|
|
179
257
|
const { w, h } = useSize(wrap);
|
|
180
258
|
const [hover, setHover] = useState(null);
|
|
@@ -191,17 +269,22 @@ function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear })
|
|
|
191
269
|
return [k, { x: Math.cos(a) * R, y: Math.sin(a) * R }];
|
|
192
270
|
}));
|
|
193
271
|
const nodes = shown.map((c) => ({
|
|
194
|
-
id: c.name, co: c,
|
|
272
|
+
id: c.name, co: c,
|
|
273
|
+
// Size: your people there, the S and A among them, or the ones you already know.
|
|
274
|
+
r: 4 + Math.sqrt(sizeBy === 'sa' ? c.shown.filter((p) => p.tier === 'S' || p.tier === 'A').length : sizeBy === 'known' ? c.d1 : c.shown.length) * (sizeBy === 'people' ? 3.4 : 5),
|
|
195
275
|
// A fixed jitter from the name, so the same network always lays out the same.
|
|
196
276
|
x: anchor.get(c.industry.key).x + (jitter(c.name) - 0.5) * 40, y: anchor.get(c.industry.key).y + (jitter(c.name + '#') - 0.5) * 40,
|
|
277
|
+
// Where its industry sits, for live physics (MapControls.js).
|
|
278
|
+
ax: anchor.get(c.industry.key).x, ay: anchor.get(c.industry.key).y,
|
|
197
279
|
}));
|
|
198
|
-
const edges = links.filter((l) => names.has(l.a) && names.has(l.b))
|
|
280
|
+
const edges = links.filter((l) => names.has(l.a) && names.has(l.b))
|
|
281
|
+
.map((l) => ({ source: l.a, target: l.b, weight: l.weight, via: l.via.size, k: Math.min(0.25, 0.03 * l.weight) }));
|
|
199
282
|
const sim = forceSimulation(nodes)
|
|
200
283
|
.force('x', forceX((d) => anchor.get(d.co.industry.key).x).strength(0.12))
|
|
201
284
|
.force('y', forceY((d) => anchor.get(d.co.industry.key).y).strength(0.12))
|
|
202
285
|
.force('collide', forceCollide((d) => d.r + 3))
|
|
203
286
|
.force('charge', forceManyBody().strength(-25))
|
|
204
|
-
.force('link', forceLink(edges).id((d) => d.id).strength((e) =>
|
|
287
|
+
.force('link', forceLink(edges).id((d) => d.id).strength((e) => e.k).distance(60))
|
|
205
288
|
.stop();
|
|
206
289
|
for (let i = 0; i < 320; i++) sim.tick();
|
|
207
290
|
const xs = nodes.flatMap((n) => [n.x - n.r, n.x + n.r]);
|
|
@@ -232,7 +315,14 @@ function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear })
|
|
|
232
315
|
// cluster's label never lands on it.
|
|
233
316
|
box.h += Math.max(60, box.h * 0.1);
|
|
234
317
|
return { nodes, edges, box, labels, cut: Math.max(0, companies.length - shown.length) };
|
|
235
|
-
}, [companies, links]);
|
|
318
|
+
}, [companies, links, sizeBy]);
|
|
319
|
+
const { drag, clicked } = useLivePhysics(layout, physics);
|
|
320
|
+
// Heat: how strong your people at each company are, ranked among the bubbles shown.
|
|
321
|
+
const heat = useMemo(() => {
|
|
322
|
+
const strength = new Map(layout.nodes.map((n) => [n.id, companyStrength(n.co.shown)]));
|
|
323
|
+
return heatBy(layout.nodes, (n) => strength.get(n.id));
|
|
324
|
+
}, [layout]);
|
|
325
|
+
const hot = colourBy === 'heat';
|
|
236
326
|
|
|
237
327
|
const active = hover || (focus?.kind === 'company' ? focus.key : null);
|
|
238
328
|
const activeInd = focus?.kind === 'industry' ? focus.key : null;
|
|
@@ -245,12 +335,14 @@ function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear })
|
|
|
245
335
|
}
|
|
246
336
|
return s;
|
|
247
337
|
}, [active, layout]);
|
|
248
|
-
const labelled = useMemo(() => new Set(layout.nodes.slice(0, 28).map((n) => n.id)), [layout]);
|
|
338
|
+
const labelled = useMemo(() => new Set(names === 'none' ? [] : (names === 'all' ? layout.nodes : [...layout.nodes].sort((a, b) => b.r - a.r).slice(0, 28)).map((n) => n.id)), [layout, names]);
|
|
249
339
|
|
|
250
340
|
return (
|
|
251
341
|
<div ref={wrap} style={{ flex: 1, minHeight: 360, position: 'relative' }} onClick={onClear}>
|
|
252
342
|
{w > 0 && (
|
|
253
|
-
<svg width={w} height={h} viewBox={`${layout.box.x} ${layout.box.y} ${layout.box.w} ${layout.box.h}`} style={{ display: 'block' }}>
|
|
343
|
+
<svg width={w} height={h} viewBox={`${layout.box.x} ${layout.box.y} ${layout.box.w} ${layout.box.h}`} style={{ display: 'block', touchAction: drag ? 'none' : undefined }}>
|
|
344
|
+
{hot && <HeatDefs id="coheat" />}
|
|
345
|
+
{hot && <HeatGlow id="coheat" nodes={layout.nodes} heat={heat} />}
|
|
254
346
|
<g>
|
|
255
347
|
{layout.edges.map((e, i) => {
|
|
256
348
|
const on = active && (e.source.id === active || e.target.id === active);
|
|
@@ -272,12 +364,13 @@ function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear })
|
|
|
272
364
|
const dim = (neighbours && !neighbours.has(n.id)) || (activeInd && n.co.industry.key !== activeInd);
|
|
273
365
|
const sel = focus?.kind === 'company' && focus.key === n.id;
|
|
274
366
|
return (
|
|
275
|
-
<g key={n.id} transform={`translate(${n.x},${n.y})`} style={{ cursor: 'pointer' }}
|
|
367
|
+
<g key={n.id} transform={`translate(${n.x},${n.y})`} style={{ cursor: drag ? 'grab' : 'pointer' }}
|
|
276
368
|
opacity={dim ? 0.18 : 1}
|
|
277
369
|
onMouseEnter={() => setHover(n.id)} onMouseLeave={() => setHover(null)}
|
|
278
|
-
|
|
370
|
+
onPointerDown={drag ? (ev) => drag(ev, n) : undefined}
|
|
371
|
+
onClick={(ev) => { ev.stopPropagation(); if (clicked()) onCompany(n.id); }}>
|
|
279
372
|
<title>{`${n.co.name} · ${n.co.industry.label} (inferred)\n${n.co.d1} you know · ${n.co.d2} reachable${n.co.d3 ? ` · ${n.co.d3} further` : ''}`}</title>
|
|
280
|
-
<circle r={n.r} fill={n.co.industry.color} fillOpacity={0.75}
|
|
373
|
+
<circle r={n.r} fill={hot ? heatColour(heat(n)) : n.co.industry.color} fillOpacity={hot ? 0.9 : 0.75}
|
|
281
374
|
stroke={sel ? '#fff' : n.co.S ? TIER.S : 'rgba(0,0,0,0.35)'} strokeWidth={sel ? 2.5 : n.co.S ? 1.5 : 0.6} />
|
|
282
375
|
{/* the share you already know, as an inner disc */}
|
|
283
376
|
{n.co.d1 > 0 && <circle r={n.r * Math.sqrt(n.co.d1 / Math.max(1, n.co.people.length))} fill="#fff" fillOpacity={0.35} />}
|
|
@@ -290,9 +383,9 @@ function CompanyMap({ companies, links, focus, onCompany, onIndustry, onClear })
|
|
|
290
383
|
</svg>
|
|
291
384
|
)}
|
|
292
385
|
<div style={{ position: 'absolute', left: 12, bottom: 10, fontSize: 11, color: '#778', lineHeight: 1.6, pointerEvents: 'none' }}>
|
|
293
|
-
Bubble = a company, sized by your people there; white centre = the share you already know; gold ring = an S-tier person inside.<br />
|
|
386
|
+
Bubble = a company, sized by your people there; {hot ? 'colour = how strong they are, cold to white hot' : 'colour = its industry'}; white centre = the share you already know; gold ring = an S-tier person inside.<br />
|
|
294
387
|
A line = one of your connections at one company knows people at the other.
|
|
295
|
-
{layout.cut ? ` Showing the ${MAX_BUBBLES} largest; ${layout.cut} smaller companies are in
|
|
388
|
+
{layout.cut ? ` Showing the ${MAX_BUBBLES} largest; ${layout.cut} smaller companies are in Companies.` : ''}
|
|
296
389
|
</div>
|
|
297
390
|
</div>
|
|
298
391
|
);
|
|
@@ -306,69 +399,6 @@ function Bar({ parts, total }) {
|
|
|
306
399
|
);
|
|
307
400
|
}
|
|
308
401
|
|
|
309
|
-
function IndustryCards({ industries, index, d1, d2, onIndustry, onCompany }) {
|
|
310
|
-
const bridgesInto = useMemo(() => {
|
|
311
|
-
const byId = new Map(d1.map((c) => [c.id, c]));
|
|
312
|
-
const out = new Map();
|
|
313
|
-
for (const r of d2) {
|
|
314
|
-
const co = companyOf(r);
|
|
315
|
-
const ind = co ? index.get(co)?.industry.key : industryOf(null, r.headline).key;
|
|
316
|
-
if (!ind) continue;
|
|
317
|
-
const m = out.get(ind) || new Map();
|
|
318
|
-
m.set(r.source_connection_id, (m.get(r.source_connection_id) || 0) + 1);
|
|
319
|
-
out.set(ind, m);
|
|
320
|
-
}
|
|
321
|
-
const best = new Map();
|
|
322
|
-
for (const [ind, m] of out) {
|
|
323
|
-
const [id, n] = [...m.entries()].sort((a, b) => b[1] - a[1])[0] || [];
|
|
324
|
-
if (byId.get(id)) best.set(ind, { bridge: byId.get(id), n });
|
|
325
|
-
}
|
|
326
|
-
return best;
|
|
327
|
-
}, [index, d1, d2]);
|
|
328
|
-
|
|
329
|
-
return (
|
|
330
|
-
<div style={{ flex: 1, overflow: 'auto', padding: 16 }}>
|
|
331
|
-
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12 }}>
|
|
332
|
-
{industries.map((i) => {
|
|
333
|
-
const d1n = i.people.filter((p) => p.degree === 1).length;
|
|
334
|
-
const d2n = i.people.filter((p) => p.degree === 2).length;
|
|
335
|
-
const senior = i.people.filter((p) => isSenior(p.headline)).length;
|
|
336
|
-
const S = i.people.filter((p) => p.tier === 'S').length;
|
|
337
|
-
const topCos = [...i.companies.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
338
|
-
const way = bridgesInto.get(i.key);
|
|
339
|
-
return (
|
|
340
|
-
<div key={i.key} onClick={() => onIndustry(i.key)} style={{ padding: 14, borderRadius: 10, border: LINE, borderTop: `3px solid ${i.color}`, background: 'rgba(255,255,255,0.03)', cursor: 'pointer' }}>
|
|
341
|
-
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
|
|
342
|
-
<b style={{ fontSize: 14, color: i.color }}>{i.label}</b>
|
|
343
|
-
<span style={{ fontSize: 20, fontWeight: 800 }}>{i.people.length}</span>
|
|
344
|
-
</div>
|
|
345
|
-
<div style={{ fontSize: 11.5, color: '#8b9a9a', margin: '4px 0 6px' }}>
|
|
346
|
-
{d1n} you know · {d2n} reachable · {i.companies.size} companies · {senior} director+ · {S} S-tier
|
|
347
|
-
</div>
|
|
348
|
-
<Bar total={i.people.length} parts={[[d1n, '#00ff88'], [d2n, '#FF6B35']]} />
|
|
349
|
-
{topCos.length > 0 && (
|
|
350
|
-
<div style={{ marginTop: 8, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
|
|
351
|
-
{topCos.map(([name, n]) => (
|
|
352
|
-
<button key={name} onClick={(e) => { e.stopPropagation(); onCompany(name); }}
|
|
353
|
-
style={{ padding: '2px 8px', borderRadius: 10, border: LINE, background: 'rgba(255,255,255,0.05)', color: '#dfe6e9', fontSize: 11, cursor: 'pointer' }}>
|
|
354
|
-
{name} <span style={{ color: '#778' }}>{n}</span>
|
|
355
|
-
</button>
|
|
356
|
-
))}
|
|
357
|
-
</div>
|
|
358
|
-
)}
|
|
359
|
-
{way && (
|
|
360
|
-
<div style={{ marginTop: 8, fontSize: 11.5, color: '#aab7b7' }}>
|
|
361
|
-
Best way in: <b style={{ color: TIER[way.bridge.tier] || '#ccc' }}>{way.bridge.name}</b> knows {way.n} here
|
|
362
|
-
</div>
|
|
363
|
-
)}
|
|
364
|
-
</div>
|
|
365
|
-
);
|
|
366
|
-
})}
|
|
367
|
-
</div>
|
|
368
|
-
</div>
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
402
|
function PersonLine({ p, note }) {
|
|
373
403
|
return (
|
|
374
404
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0', fontSize: 12.5 }}>
|
|
@@ -381,7 +411,7 @@ function PersonLine({ p, note }) {
|
|
|
381
411
|
);
|
|
382
412
|
}
|
|
383
413
|
|
|
384
|
-
function AnalyzerPanel({ focus, data, index, links, d1, d2, filters, onClose, onCompany, onOpenCompany }) {
|
|
414
|
+
function AnalyzerPanel({ focus, data, index, links, d1, d2, filters, onClose, onCompany, onIndustry, onOpenCompany }) {
|
|
385
415
|
const isCompany = focus.kind === 'company';
|
|
386
416
|
const people = (isCompany ? data.people : data.people).filter((p) => passes(p, filters));
|
|
387
417
|
const levels = useMemo(() => {
|
|
@@ -410,9 +440,16 @@ function AnalyzerPanel({ focus, data, index, links, d1, d2, filters, onClose, on
|
|
|
410
440
|
<button onClick={onClose} style={{ background: 'none', border: 'none', color: '#888', cursor: 'pointer', fontSize: 12, padding: 0 }}>✕ Close</button>
|
|
411
441
|
<div style={{ fontSize: 10, letterSpacing: 1, color: '#8b9a9a', marginTop: 8 }}>{isCompany ? 'COMPANY' : 'INDUSTRY'} ANALYZER</div>
|
|
412
442
|
<h2 style={{ margin: '4px 0 6px', fontSize: 20 }}>{isCompany ? data.name : data.label}</h2>
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
443
|
+
{/* A company's industry opens that industry here (Blake, 2026-10-02: industries live in the side card, not a tab). */}
|
|
444
|
+
{isCompany && onIndustry ? (
|
|
445
|
+
<button type="button" onClick={() => onIndustry(industry.key)} title={`Open ${industry.label}: everyone there and its top companies`} style={{
|
|
446
|
+
fontSize: 11, padding: '2px 8px', borderRadius: 10, border: 'none', cursor: 'pointer', background: `${industry.color}22`, color: industry.color,
|
|
447
|
+
}}>{industry.label} · inferred →</button>
|
|
448
|
+
) : (
|
|
449
|
+
<span style={{ fontSize: 11, padding: '2px 8px', borderRadius: 10, background: `${industry.color}22`, color: industry.color }}>
|
|
450
|
+
{industry.label}{isCompany ? ' · inferred' : ''}
|
|
451
|
+
</span>
|
|
452
|
+
)}
|
|
416
453
|
{isCompany && <CompanyScoreLine name={data.name} />}
|
|
417
454
|
|
|
418
455
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8, margin: '14px 0' }}>
|
|
@@ -505,7 +542,7 @@ function Section({ title, children }) {
|
|
|
505
542
|
}
|
|
506
543
|
|
|
507
544
|
// The company's score in people's power, where it comes from, and a control
|
|
508
|
-
// to set it (
|
|
545
|
+
// to set it (Settings → Scores has every company).
|
|
509
546
|
function CompanyScoreLine({ name }) {
|
|
510
547
|
const { companies, setScore } = useCompanyScores();
|
|
511
548
|
const c = companies?.find((x) => x.name === name);
|