six-degrees 0.4.2 → 0.4.4
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 +3 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +41 -13
- package/.next/standalone/.next/routes-manifest.json +12 -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 +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 +19 -17
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +19 -17
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +15 -13
- 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.nft.json +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.nft.json +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.nft.json +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.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.nft.json +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.nft.json +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.nft.json +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 +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +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.nft.json +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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/social/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/social/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/social/route.js +8 -0
- package/.next/standalone/.next/server/app/api/social/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/social/route_client-reference-manifest.js +3 -0
- 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.nft.json +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 +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 +23 -21
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +21 -19
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +17 -15
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +21 -19
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch/page.js +1 -1
- 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 +23 -21
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/page.js +1 -1
- 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 +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 +23 -21
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/profile/page.js +1 -1
- 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 +23 -21
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/queue/page.js +1 -1
- 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 +23 -21
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/scores/page.js +1 -1
- 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 +23 -21
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- 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 +23 -21
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/setup/page.js +1 -1
- 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 +23 -21
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +23 -21
- 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 +17 -15
- package/.next/standalone/.next/server/app/social/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/social/page/build-manifest.json +20 -0
- package/.next/standalone/.next/server/app/social/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/social/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/social/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/social/page.js +13 -0
- package/.next/standalone/.next/server/app/social/page.js.map +5 -0
- package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/social.html +1 -0
- package/.next/standalone/.next/server/app/social.meta +26 -0
- package/.next/standalone/.next/server/app/social.rsc +26 -0
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +26 -0
- package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +30 -0
- package/.next/standalone/.next/server/app-paths-manifest.json +3 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17kn1mk._.js +8 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0uag-k5._.js → [root-of-the-server]__1dmc7-t._.js} +1 -1
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +5 -5
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1xh07bp._.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_social_route_actions_1_3c6qn.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16hs8kw._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1feicqq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jeztd-._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_005q9n1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08_03wh._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08cfj2b._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0j4-lc3._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0hw_qnj._.js → _0wxbq78._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0xkur4p._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_15x6q32._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_1cyxocj._.js → _1ap1tu_._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1mj739k._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_social_page_actions_176i1kl.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/app_scores_page_09wepvv.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.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/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +4 -0
- 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/prefetch-hints.json +14 -0
- 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/04a3zockahetx.js +1 -0
- package/.next/standalone/.next/static/chunks/0a5iadnmt9u9k.js +1 -0
- package/.next/standalone/.next/static/chunks/{2p6o90z0vgcwr.css → 0bo1dxn5gwzpk.css} +1 -1
- package/.next/standalone/.next/static/chunks/0g_p4p7oci18u.js +1 -0
- package/.next/standalone/.next/static/chunks/{0ax_9zzboyv6d.js → 17-rhp8sg4m1b.js} +2 -2
- package/.next/standalone/.next/static/chunks/1ra4cwcp75tfa.js +1 -0
- package/.next/standalone/.next/static/chunks/236f0jtp68j_h.js +1 -0
- package/.next/standalone/.next/static/chunks/24m745q_85u34.js +6 -0
- package/.next/standalone/.next/static/chunks/2_wcobfqry2uj.js +1 -0
- package/.next/standalone/.next/static/chunks/2dwtoszeq91us.js +1 -0
- package/.next/standalone/.next/static/chunks/2hvcevue9aro4.js +1 -0
- package/.next/standalone/.next/static/chunks/2uo9i03_05rqi.js +18 -0
- package/.next/standalone/.next/static/chunks/3p_pwu5gx2i9h.js +1 -0
- package/.next/standalone/.next/static/chunks/3yc3rzp4dxvyo.js +1 -0
- package/.next/standalone/.next/static/chunks/3zw8bv7-mc4n6.js +33 -0
- package/.next/standalone/CHANGELOG.md +63 -0
- package/.next/standalone/app/api/network/route.js +11 -0
- package/.next/standalone/app/api/scraper/route.js +19 -0
- package/.next/standalone/app/api/social/route.js +96 -0
- package/.next/standalone/app/components/AutoScanButton.js +41 -0
- package/.next/standalone/app/components/ChainView.js +7 -0
- package/.next/standalone/app/components/FilterPanel.js +37 -5
- package/.next/standalone/app/components/OrbitGraph.js +17 -4
- package/.next/standalone/app/components/ScanStatusBar.js +96 -0
- package/.next/standalone/app/components/SeparationView.js +9 -1
- package/.next/standalone/app/components/Sidebar.js +88 -26
- package/.next/standalone/app/components/SocialAutoSync.js +34 -0
- package/.next/standalone/app/components/settings/NetworkHealthSection.js +85 -0
- package/.next/standalone/app/globals.css +4 -0
- package/.next/standalone/app/layout.js +6 -0
- package/.next/standalone/app/page.js +37 -4
- package/.next/standalone/app/scores/page.js +3 -0
- package/.next/standalone/app/setup/page.js +13 -1
- package/.next/standalone/app/social/page.js +293 -0
- package/.next/standalone/lib/experimental-client.js +38 -0
- package/.next/standalone/lib/insights.js +54 -0
- package/.next/standalone/lib/linkedin-export.js +156 -0
- package/.next/standalone/lib/network-health.js +42 -0
- package/.next/standalone/lib/network.js +1 -0
- package/.next/standalone/lib/scraper-client.js +1 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +335 -5
- package/.next/static/chunks/04a3zockahetx.js +1 -0
- package/.next/static/chunks/0a5iadnmt9u9k.js +1 -0
- package/.next/static/chunks/{2p6o90z0vgcwr.css → 0bo1dxn5gwzpk.css} +1 -1
- package/.next/static/chunks/0g_p4p7oci18u.js +1 -0
- package/.next/static/chunks/{0ax_9zzboyv6d.js → 17-rhp8sg4m1b.js} +2 -2
- package/.next/static/chunks/1ra4cwcp75tfa.js +1 -0
- package/.next/static/chunks/236f0jtp68j_h.js +1 -0
- package/.next/static/chunks/24m745q_85u34.js +6 -0
- package/.next/static/chunks/2_wcobfqry2uj.js +1 -0
- package/.next/static/chunks/2dwtoszeq91us.js +1 -0
- package/.next/static/chunks/2hvcevue9aro4.js +1 -0
- package/.next/static/chunks/2uo9i03_05rqi.js +18 -0
- package/.next/static/chunks/3p_pwu5gx2i9h.js +1 -0
- package/.next/static/chunks/3yc3rzp4dxvyo.js +1 -0
- package/.next/static/chunks/3zw8bv7-mc4n6.js +33 -0
- package/CHANGELOG.md +63 -0
- package/lib/experimental-client.js +38 -0
- package/lib/insights.js +54 -0
- package/lib/linkedin-export.js +156 -0
- package/lib/network-health.js +42 -0
- package/lib/network.js +1 -0
- package/lib/scraper-client.js +1 -0
- package/package.json +1 -1
- package/scripts/scrape.py +335 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h1_f_2._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19ip1qq._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_06w_gl4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_13kzrwv._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_15xuwkv._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1hgd5dp._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1vpfyd-._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_20w06i-._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_1bn38gs._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1f8t_rp._.js +0 -23
- package/.next/standalone/.next/static/chunks/049vavjsmqgmn.js +0 -33
- package/.next/standalone/.next/static/chunks/0cuuo2jwc9h94.js +0 -1
- package/.next/standalone/.next/static/chunks/0ljxa-wk_iu__.js +0 -18
- package/.next/standalone/.next/static/chunks/0mp9b72fm-jp6.js +0 -6
- package/.next/standalone/.next/static/chunks/1pre1cotntk6-.js +0 -1
- package/.next/standalone/.next/static/chunks/22x2_r768-u5i.js +0 -1
- package/.next/standalone/.next/static/chunks/28bu26ausqzmn.js +0 -1
- package/.next/standalone/.next/static/chunks/2jz311xl1pp_8.js +0 -1
- package/.next/standalone/.next/static/chunks/2ot61qsv6_0eq.js +0 -1
- package/.next/standalone/.next/static/chunks/2xjho0lroiwlq.js +0 -1
- package/.next/standalone/.next/static/chunks/3zs_6-nn0dapb.js +0 -1
- package/.next/static/chunks/049vavjsmqgmn.js +0 -33
- package/.next/static/chunks/0cuuo2jwc9h94.js +0 -1
- package/.next/static/chunks/0ljxa-wk_iu__.js +0 -18
- package/.next/static/chunks/0mp9b72fm-jp6.js +0 -6
- package/.next/static/chunks/1pre1cotntk6-.js +0 -1
- package/.next/static/chunks/22x2_r768-u5i.js +0 -1
- package/.next/static/chunks/28bu26ausqzmn.js +0 -1
- package/.next/static/chunks/2jz311xl1pp_8.js +0 -1
- package/.next/static/chunks/2ot61qsv6_0eq.js +0 -1
- package/.next/static/chunks/2xjho0lroiwlq.js +0 -1
- package/.next/static/chunks/3zs_6-nn0dapb.js +0 -1
- /package/.next/standalone/.next/static/{wGVrXBkFLmEB4snfhtOcO → VE8LeJXfD2H0_OgJxuJcm}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{wGVrXBkFLmEB4snfhtOcO → VE8LeJXfD2H0_OgJxuJcm}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{wGVrXBkFLmEB4snfhtOcO → VE8LeJXfD2H0_OgJxuJcm}/_ssgManifest.js +0 -0
- /package/.next/static/{wGVrXBkFLmEB4snfhtOcO → VE8LeJXfD2H0_OgJxuJcm}/_buildManifest.js +0 -0
- /package/.next/static/{wGVrXBkFLmEB4snfhtOcO → VE8LeJXfD2H0_OgJxuJcm}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{wGVrXBkFLmEB4snfhtOcO → VE8LeJXfD2H0_OgJxuJcm}/_ssgManifest.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,2776,e=>{"use strict";var t=e.i(43476),n=e.i(15812);e.s(["default",0,function({children:e}){let{userId:r,ready:o}=(0,n.useUser)();return o&&r?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:o?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},28867,86106,e=>{"use strict";var t=e.i(71645),n=e.i(7214);let r=Object.freeze({known:!1,sent:new Set,mine:new Map,version:0}),o=new Set,l=r,i=null,a=new Map;function s(e=l.sent,t=l.known){for(let n of(l=Object.freeze({known:t,sent:e,mine:new Map(a),version:l.version+1}),[...o]))n()}function d(e){return o.add(e),i||l.known||(i=fetch("/api/outreach").then(e=>e.ok?e.json():null).then(e=>{e&&s(new Set((e.pending||[]).map(n.keyFor)),!0)}).catch(()=>{}).finally(()=>{i=null})),()=>o.delete(e)}function u(){return l}async function c(e){let t=await fetch("/api/outreach",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),n=await t.json().catch(()=>({}));if(!t.ok)throw Error(n.error||"Could not save that.");return n}async function f(e,{bridgeId:t}={}){let r=(0,n.keyFor)(e),o=a.has(r)?a.get(r):void 0;a.set(r,!0),s();try{return await c({action:"mark-sent",connectionId:e.id,profileUrl:e.profile_url,bridgeId:t})}catch(e){throw void 0===o?a.delete(r):a.set(r,o),s(),e}}async function h(e){let t=(0,n.keyFor)(e),r=a.has(t)?a.get(t):void 0;a.set(t,!1),s();try{return await c({action:"undo",connectionId:e.id,profileUrl:e.profile_url})}catch(e){throw void 0===r?a.delete(t):a.set(t,r),s(),e}}e.s(["REQUESTS_UNKNOWN",0,r,"hasRequest",0,function(e,t=l){if(!e)return!1;let r=(0,n.keyFor)(e);return t.mine.has(r)?t.mine.get(r):t.known?t.sent.has(r):"pending"===e.unlock_status||"sent"===e.outreach_status},"markRequested",0,f,"requestCount",0,function(e=l){let t=new Set(e.known?e.sent:[]);for(let[n,r]of e.mine)r?t.add(n):t.delete(n);return t.size},"requestsNow",0,u,"undoRequest",0,h,"watchRequests",0,d],86106),e.s(["default",0,function(){return(0,t.useSyncExternalStore)(d,u,()=>r)}],28867)},64666,e=>{"use strict";var t=e.i(7214);function n(e=[],r=[]){let o=new Set((r||[]).map(t.keyFor)),l=new Map;for(let n of e||[]){let e=n?.source_connection_id;if(null==e)continue;let r=(0,t.keyFor)(n);if(o.has(r))continue;let i=l.get(r);i||l.set(r,i=new Set),i.add(e)}let i=new Map;for(let e of l.values())for(let t of e){let n=i.get(t)||{reach:0,only:0,total:0};n.reach+=1/e.size,n.total+=1,1===e.size&&(n.only+=1),i.set(t,n)}return i}e.s(["bridgeOverlap",0,function(e=[],r=[]){let o=n(e,r),l=new Set((r||[]).map(t.keyFor)),i=new Map;for(let n of e||[]){let e=n?.source_connection_id;if(null==e)continue;let r=(0,t.keyFor)(n);if(l.has(r))continue;let o=i.get(r);o||i.set(r,o=new Set),o.add(e)}let a=new Map;for(let e of i.values()){if(e.size<2)continue;let t=[...e];for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++){let r=t[e]<t[n]?`${t[e]}|${t[n]}`:`${t[n]}|${t[e]}`;a.set(r,(a.get(r)||0)+1)}}let s=new Map;for(let[e,t]of a){let[n,r]=e.split("|"),l=o.get(n).total+o.get(r).total-t,i=l?t/l:0;for(let[e,o]of[[n,r],[r,n]]){let n=s.get(e);(!n||i>n.share)&&s.set(e,{with:o,share:i,shared:t})}}return s},"exclusiveReach",0,n,"redundancy",0,function(e=[],t=[]){let r=n(e,t),o=0,l=0;for(let e of r.values())o+=e.reach,l+=e.only;return o?1-l/o:0}])},19821,e=>{"use strict";async function t(e){let t=e?`/api/network?userId=${encodeURIComponent(e)}`:"/api/network",n=await fetch(t);if(!n.ok)throw Error(`Failed to load network (${n.status})`);let r=await n.json();return{degree1:r.degree1||[],degree2:r.degree2||[],degree3:r.degree3||[],ties:Number(r.ties)||0}}e.s(["loadNetwork",0,t])},36774,e=>{"use strict";let t=/^[A-Za-z0-9_-]+\.(webp|jpg|jpeg|png)$/,n="/avatars/";e.s(["localPhoto",0,function(e){return"string"==typeof e&&e.startsWith(n)&&t.test(e.slice(n.length))?e:null}])},48235,e=>{"use strict";var t=e.i(7214);function n(e,n){return e?n.scanned.has(e.id)||e.profile_url&&n.read?.has((0,t.keyFor)(e))?"scanned":e.profile_url&&n.hidden.has((0,t.keyFor)(e))?"hidden":"todo":"todo"}function r(e,t){if(!e||1!==e.degree||null==e.unlocked_from_bridge_id)return null;let r=n(e,t);return"todo"===r?"ready":r}e.s(["circleScanCost",0,function(e=100){let t=Math.max(1,Math.min(100,Math.round(e)||100));return{profileViews:1,searches:t,minutes:t>=100?55:Math.max(5,Math.round(.55*t))}},"circleState",0,n,"reachIndex",0,function(e=[],n=[],r={}){let o=new Set;for(let e of n||[])e?.source_connection_id!=null&&o.add(e.source_connection_id);let l=new Set;for(let e of r?.skips||[])e?.profileUrl&&l.add((0,t.keyFor)({profile_url:e.profileUrl}));let i=new Set;for(let e of r?.read||[])e&&i.add((0,t.keyFor)({profile_url:e}));let a=new Map;for(let[e,n]of Object.entries(r?.lists||{}))e&&n&&a.set((0,t.keyFor)({profile_url:e}),n);let s=new Map;for(let t of e||[]){let e=t?.unlocked_from_bridge_id;if(null==e||1!==t.degree)continue;let n=s.get(e);n||s.set(e,n=[]),n.push(t)}return{scanned:o,read:i,hidden:l,reachedFrom:s,lists:a}},"reachState",0,r,"readyByCircle",0,function(e){let t=new Map;for(let[n,o]of e.reachedFrom){let l=o.filter(t=>"ready"===r(t,e)).length;l&&t.set(n,l)}return t},"readyToScan",0,function(e,n){return(e||[]).filter(e=>"ready"===r(e,n)).sort(t.compareBridges)},"scanBars",0,function(e,r){let o=n(e,r),l=e?.profile_url?r.lists?.get((0,t.keyFor)(e)):null;return"hidden"===o?null:l?l.more?l.total?Math.max(1,Math.min(4,Math.round(5*Math.min(1,10*l.pages/l.total)))):2:5:"scanned"===o?2:null}])},7214,e=>{"use strict";var t=e.i(36774);let n={S:0,A:1,B:2,C:3,D:4};function r(e){let t=parseFloat(e?.power_score);return Number.isFinite(t)?t:0}function o(e){return Math.round(10*r(e))/10}function l(e){return String(e?.profile_url||"").split(/[?#]/)[0].replace(/\/+$/,"")||`id:${e?.id}`}let i=(e,t)=>String(e??"").localeCompare(String(t??""),void 0,{numeric:!0});function a(e,t){return(n[e.tier]??9)-(n[t.tier]??9)||r(t)-r(e)||String(e.name||"").localeCompare(String(t.name||""))||i(e.id,t.id)}function s(e,t){return e.bridge&&t.bridge?a(e.bridge,t.bridge):e.bridge?-1:t.bridge?1:i(e.id,t.id)}function d(e,t){return t.score-e.score||t.waysIn-e.waysIn||s(e.routes[0]||u,t.routes[0]||u)||String(e.person.name||"").localeCompare(String(t.person.name||""))||(e.key<t.key?-1:+(e.key>t.key))}let u={id:null,bridge:null};function c(e){let t=String(e||"").trim().split(/\s+/).filter(Boolean);return t.length<2?t[0]||"":`${t[0]} ${t[t.length-1].charAt(0)}.`}function f(e,t){let n=String(e||"");return t<=1?n?"…":"":n.length>t?`${n.slice(0,t-1)}…`:n}e.s(["TIERS",0,["S","A","B","C","D"],"compareBridges",0,a,"compareWaysIn",0,function(e,t){return t.waysIn-e.waysIn||d(e,t)},"keyFor",0,l,"routeIndex",0,function(e=[]){let t=new Map;for(let n of e||[]){let e=l(n),r=t.get(e);r||(r=new Set,t.set(e,r)),r.add(n.source_connection_id??null)}return t},"routesFor",0,function(e,t,n){return e?[...t?.get(l(e))??(null!=e.source_connection_id?new Set([e.source_connection_id]):new Set)].map(e=>({id:e,bridge:n?.get(e)??null})).sort(s):[]},"score",0,r,"score1",0,o,"separationPeople",0,function(e=[],n=[]){let r=new Map;for(let e of n||[])r.set(e.id,e);let a=new Map,u=new Map;for(let n of e||[]){let e=l(n);u.set(n.id,e);let r=a.get(e);r?function(e,n){let r=o(e)-o(n);if(r)return r>0;let l=!!(0,t.localPhoto)(e.profile_image_url);return!!(0,t.localPhoto)(n.profile_image_url)!==l?l:0>i(e.id,n.id)}(n,r.person)&&(r.person=n):(r={key:e,person:n,rowIds:[],routeIds:new Set},a.set(e,r)),r.rowIds.push(n.id),r.routeIds.add(n.source_connection_id??null)}let c={people:a.size,byTier:{S:0,A:0,B:0,C:0,D:0},multi:0,bridges:0,unresolvedIds:0,peopleOnlyUnresolved:0,onlyUnresolvedVia:0},f=new Set,h=new Set,g=new Set,p=[];for(let e of a.values()){let t=[...e.routeIds].map(e=>({id:e,bridge:r.get(e)??null}));t.sort(s);let n=t.filter(e=>e.bridge);for(let e of t)(e.bridge?f:h).add(e.id);if(!n.length)for(let e of(c.peopleOnlyUnresolved++,t))g.add(e.id);let{person:l}=e,i=l.tier;void 0!==c.byTier[i]&&c.byTier[i]++,t.length>1&&c.multi++,p.push({key:e.key,person:l,score:o(l),tier:i,routes:t,waysIn:t.length,rowIds:e.rowIds,haystack:[l.name,l.headline,l.company,l.role,...n.map(e=>e.bridge.name)].filter(Boolean).join("\n").toLowerCase(),rank:0,tied:!1})}return c.bridges=f.size,c.unresolvedIds=h.size,c.onlyUnresolvedVia=g.size,p.sort(d),function(e){for(let t=0;t<e.length;t++){let n=e[t],r=e[t-1],o=r&&r.score===n.score&&r.waysIn===n.waysIn;n.rank=o?r.rank:t+1,o&&(n.tied=!0,r.tied=!0)}}(p),{people:p,rowToKey:u,summary:c}},"shortName",0,c,"summitLayout",0,function(e=[],t=800,n=!1){let r=n?36:26,o=Math.round(.42*t),l=Math.round(.58*t),i=e.map((e,n)=>{var o;return{key:e.key,p:e,x:l,y:16+n*r,r:(o=e.waysIn)>=4?8.5:3===o?7:2===o?5.5:4,label:f(`#${e.rank}${e.tied?"=":""} ${e.person.name||""}`,Math.floor((t-l-60)/6.2))}}),s=new Map,d="\0unresolved";for(let e of i)for(let t of e.p.routes){let n=t.bridge?t.id:d,r=s.get(n);r||(r={id:t.bridge?t.id:null,bridge:t.bridge,unresolved:!t.bridge,ys:[],count:0},s.set(n,r)),r.count++,r.ys.push(e.y)}let u=[...s.values()].map(e=>({...e,bary:e.ys.reduce((e,t)=>e+t,0)/e.ys.length}));u.sort((e,t)=>e.bary-t.bary||e.unresolved-t.unresolved||(e.bridge&&t.bridge?a(e.bridge,t.bridge):0));let h=i.length?i[i.length-1].y:16,g=u.length>1?Math.max(18,(h-16)/(u.length-1)):0,p=Math.max(4,Math.floor((o-10-42)/6));u.forEach((e,t)=>{if(e.x=o,e.y=1===u.length?(16+h)/2:16+t*g,e.r=5,e.unresolved)e.label=f(`can't be named (${e.count})`,p);else{let t=e.bridge.name||"";e.label=t.length<=p?t:f(c(t),p)}delete e.ys});let y=new Map(u.map(e=>[e.unresolved?d:e.id,e])),w=[];for(let e of i){let t=new Set;e.p.routes.forEach((n,r)=>{let o=n.bridge?n.id:d;if(t.has(o))return;t.add(o);let l=y.get(o);w.push({key:e.key,bridgeId:l.id,primary:0===r&&!l.unresolved,unresolved:l.unresolved,tier:l.bridge?.tier??null,x1:l.x,y1:l.y,x2:e.x,y2:e.y})})}let m=Math.max(h,u.length?u[u.length-1].y:0),S=i.length?Math.ceil(m+16):0,b={x:20,y:i.length?(16+Math.max(h,m))/2:16,r:14},k=u.map(e=>({id:e.id,x1:b.x,y1:b.y,x2:e.x,y2:e.y}));return{width:t,height:S,you:b,people:i,bridges:u,links:w,spokes:k}}])},5258,e=>{"use strict";e.s(["TIER_COLORS",0,{S:"#f6c344",A:"#a78bfa",B:"#60a5fa",C:"#94a3b8",D:"#6b7280"},"TIER_COLORS_CLASSIC",0,{S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},"TIER_ORDER",0,["S","A","B","C","D"],"TIER_RING_RADIUS",0,{S:150,A:230,B:310,C:390,D:470},"initialsFor",0,function(e){let t=String(e||"").trim().split(/\s+/).filter(Boolean);return 0===t.length?"?":(t[0].charAt(0)+(t.length>1?t[t.length-1].charAt(0):"")).toUpperCase()}])},18566,(e,t,n)=>{t.exports=e.r(76562)}]);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,2776,e=>{"use strict";var t=e.i(43476),r=e.i(15812);e.s(["default",0,function({children:e}){let{userId:n,ready:i}=(0,r.useUser)();return i&&n?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:i?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},28867,86106,e=>{"use strict";var t=e.i(71645),r=e.i(7214);let n=Object.freeze({known:!1,sent:new Set,mine:new Map,version:0}),i=new Set,o=n,l=null,s=new Map;function d(e=o.sent,t=o.known){for(let r of(o=Object.freeze({known:t,sent:e,mine:new Map(s),version:o.version+1}),[...i]))r()}function a(e){return i.add(e),l||o.known||(l=fetch("/api/outreach").then(e=>e.ok?e.json():null).then(e=>{e&&d(new Set((e.pending||[]).map(r.keyFor)),!0)}).catch(()=>{}).finally(()=>{l=null})),()=>i.delete(e)}function c(){return o}async function g(e){let t=await fetch("/api/outreach",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),r=await t.json().catch(()=>({}));if(!t.ok)throw Error(r.error||"Could not save that.");return r}async function p(e,{bridgeId:t}={}){let n=(0,r.keyFor)(e),i=s.has(n)?s.get(n):void 0;s.set(n,!0),d();try{return await g({action:"mark-sent",connectionId:e.id,profileUrl:e.profile_url,bridgeId:t})}catch(e){throw void 0===i?s.delete(n):s.set(n,i),d(),e}}async function h(e){let t=(0,r.keyFor)(e),n=s.has(t)?s.get(t):void 0;s.set(t,!1),d();try{return await g({action:"undo",connectionId:e.id,profileUrl:e.profile_url})}catch(e){throw void 0===n?s.delete(t):s.set(t,n),d(),e}}e.s(["REQUESTS_UNKNOWN",0,n,"hasRequest",0,function(e,t=o){if(!e)return!1;let n=(0,r.keyFor)(e);return t.mine.has(n)?t.mine.get(n):t.known?t.sent.has(n):"pending"===e.unlock_status||"sent"===e.outreach_status},"markRequested",0,p,"requestCount",0,function(e=o){let t=new Set(e.known?e.sent:[]);for(let[r,n]of e.mine)n?t.add(r):t.delete(r);return t.size},"requestsNow",0,c,"undoRequest",0,h,"watchRequests",0,a],86106),e.s(["default",0,function(){return(0,t.useSyncExternalStore)(a,c,()=>n)}],28867)},77305,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(19821),i=e.i(64745),o=e.i(22016),l=e.i(48235);let s={S:25,A:15,B:10,C:5,D:2},d={S:100,A:60,B:35,C:15,D:5};var a=e.i(5258),c=e.i(36774);let g={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},p="1px solid rgba(255,255,255,0.1)";function h({person:e,size:r=36,ring:n}){let i=g[e?.tier]||"#667";return(0,t.jsxs)("div",{style:{position:"relative",width:r,height:r,flexShrink:0},children:[(0,t.jsx)("div",{style:{width:r,height:r,borderRadius:"50%",background:i,color:e?.tier==="S"?"#000":"#fff",display:"flex",alignItems:"center",justifyContent:"center",fontSize:.34*r,fontWeight:800,border:`2px solid ${n||i}`},children:(0,a.initialsFor)(e?.name||"?")}),(0,c.localPhoto)(e?.profile_image_url)&&(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",onError:e=>{e.currentTarget.style.display="none"},style:{position:"absolute",inset:0,width:r,height:r,borderRadius:"50%",objectFit:"cover",border:`2px solid ${n||i}`}})]})}function f({progress:e,size:r=86,color:n="#FF6B35",children:i}){let o=r/2-5,l=2*Math.PI*o;return(0,t.jsxs)("div",{style:{position:"relative",width:r,height:r},children:[(0,t.jsxs)("svg",{width:r,height:r,style:{position:"absolute",inset:0,transform:"rotate(-90deg)"},children:[(0,t.jsx)("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:"rgba(255,255,255,0.08)",strokeWidth:5}),(0,t.jsx)("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:n,strokeWidth:5,strokeLinecap:"round",strokeDasharray:`${l*Math.min(1,e)} ${l}`,style:{transition:"stroke-dasharray 0.5s ease"}})]}),(0,t.jsx)("div",{style:{position:"absolute",inset:9,display:"flex",alignItems:"center",justifyContent:"center"},children:i})]})}function u({recs:e,sentIds:n,added:i,mappedIds:a,reach:c,onSend:y,onUndo:m}){let S=(0,r.useMemo)(()=>(function({recs:e=[],sentIds:t=new Set,added:r=[],mappedIds:n=new Set,reach:i=null}){var o;let a,c,g,p=new Map,h=new Set;for(let t of[...e].sort((e,t)=>(t.priority||0)-(e.priority||0))){if(!t.bridge)continue;let e=`${t.bridge.id}|${t.profile_url||t.id}`;if(h.has(e))continue;h.add(e);let r=p.get(t.bridge.id);r||(r={bridge:t.bridge,people:[]},p.set(t.bridge.id,r)),r.people.push(t)}let f=new Map;for(let e of r){let t=e.unlocked_from_bridge_id;t&&f.set(t,[...f.get(t)||[],e])}let u=[],x=0,b=0;for(let{bridge:e,people:r}of p.values()){let n=r.filter(e=>t.has(e.id)),i=f.get(e.id)||[];b+=n.length,x+=n.reduce((e,t)=>e+(s[t.tier]||2),0),x+=i.reduce((e,t)=>e+(d[t.tier]||5),0);let o=Math.ceil(r.length/5)||1,l=0;for(;l<o-1&&r.slice(5*l,(l+1)*5).every(e=>t.has(e.id));)l++;let a=r.slice(5*l,(l+1)*5),c=a.filter(e=>t.has(e.id)).length,g=c===a.length&&l===o-1;u.push({bridge:e,people:r,stage:l+1,stages:o,targets:a,done:c,progress:a.length?c/a.length:1,complete:g,sent:n.length,added:i,value:a.filter(e=>!t.has(e.id)).reduce((e,t)=>e+(t.priority||0),0),open:{S:a.filter(e=>"S"===e.tier&&!t.has(e.id)).length,A:a.filter(e=>"A"===e.tier&&!t.has(e.id)).length}})}u.sort((e,t)=>e.complete-t.complete||(t.progress>0&&t.progress<1)-(e.progress>0&&e.progress<1)||t.progress-e.progress||t.value-e.value);let y=u.filter(e=>!e.complete).flatMap(e=>e.targets.filter(e=>!t.has(e.id)).map(t=>({person:t,cluster:e,score:(t.priority||0)*(1+.6*e.progress)}))).sort((e,t)=>t.score-e.score),m=new Set,S=[];for(let e of y){let t=e.person.profile_url||e.person.id;if(!m.has(t)&&(m.add(t),S.push(e),3===S.length))break}let k=r.filter(e=>e.unlocked_from_bridge_id).length;return{clusters:u,nextMoves:S,points:x,level:(c=((a=Math.floor(Math.sqrt(Math.max(0,o=x)/40))+1)-1)**2*40,g=a**2*40,{level:a,floor:c,next:g,progress:(o-c)/(g-c)}),sentTotal:b,addedTotal:k,newDoors:r.filter(e=>e.unlocked_from_bridge_id&&"todo"===(0,l.circleState)(e,i||{scanned:n,hidden:new Set})),clearedStages:u.reduce((e,t)=>e+(t.stage-1)+ +!!t.complete,0)}})({recs:e,sentIds:n,added:i,mappedIds:a,reach:c}),[e,n,i,a,c]),[k,j]=(0,r.useState)(null),[v,w]=(0,r.useState)(null),{level:_}=S;async function F(e,t){await y(e);let r=t.done+1,n=String(t.bridge.name||"").split(/[\s,]+/)[0];w(r>=t.targets.length?`+${s[e.tier]||2} \xb7 Stage ${t.stage} of ${n}'s circle cleared — the next 5 are up`:`+${s[e.tier]||2} \xb7 ${n}'s circle ${r}/${t.targets.length}`),setTimeout(()=>w(null),3500)}let z=S.clusters.find(e=>e.bridge.id===k);return(0,t.jsxs)("div",{style:{maxWidth:1100,margin:"0 auto",padding:"16px 20px 60px"},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:16,alignItems:"center",flexWrap:"wrap",padding:16,borderRadius:12,border:p,background:"linear-gradient(135deg, rgba(255,107,53,0.10), rgba(155,89,182,0.08))"},children:[(0,t.jsxs)("div",{style:{width:64,height:64,borderRadius:16,background:"linear-gradient(135deg, #FFD700, #FF6B35)",color:"#000",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},children:[(0,t.jsx)("div",{style:{fontSize:10,fontWeight:800},children:"LEVEL"}),(0,t.jsx)("div",{style:{fontSize:26,fontWeight:900,lineHeight:1},children:_.level})]}),(0,t.jsxs)("div",{style:{flex:1,minWidth:220},children:[(0,t.jsxs)("div",{style:{fontSize:13,color:"#dfe6e9"},children:[(0,t.jsx)("b",{children:S.points})," points · ",(0,t.jsx)("b",{children:_.next-S.points})," to level ",_.level+1]}),(0,t.jsx)("div",{style:{height:8,borderRadius:4,background:"rgba(255,255,255,0.08)",marginTop:6,overflow:"hidden"},children:(0,t.jsx)("div",{style:{height:"100%",width:`${Math.round(100*_.progress)}%`,background:"linear-gradient(90deg, #FFD700, #FF6B35)",transition:"width 0.5s"}})}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",marginTop:6},children:"Points come from invites you send and people who accept — not from browsing."})]}),[[S.sentTotal,"invites sent"],[S.addedTotal,"people added"],[S.clearedStages,"stages cleared"]].map(([e,r])=>(0,t.jsxs)("div",{style:{textAlign:"center",minWidth:80},children:[(0,t.jsx)("div",{style:{fontSize:24,fontWeight:900},children:e}),(0,t.jsx)("div",{style:{fontSize:11,color:"#8b9a9a"},children:r})]},r))]}),S.newDoors.length>0&&(0,t.jsxs)("div",{style:{marginTop:12,padding:"10px 14px",borderRadius:10,border:"1px solid rgba(0,255,136,0.3)",background:"rgba(0,255,136,0.06)",fontSize:13},children:["🚪 ",(0,t.jsxs)("b",{children:[S.newDoors.length," new ",1===S.newDoors.length?"door":"doors",":"]})," people you added through a circle, whose own circle isn’t mapped yet. That’s the next degree. ",(0,t.jsx)(o.default,{href:"/setup",style:{color:"#00ff88"},children:"Map them on the Scan page →"})]}),S.nextMoves.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h3",{style:{margin:"22px 0 10px",fontSize:15},children:"Next best moves"}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(300px, 1fr))",gap:12},children:S.nextMoves.map(({person:e,cluster:r},n)=>(0,t.jsxs)("div",{style:{padding:14,borderRadius:12,border:`1px solid ${g[e.tier]}55`,background:"rgba(255,255,255,0.03)",position:"relative"},children:[(0,t.jsxs)("div",{style:{position:"absolute",top:10,right:12,fontSize:11,fontWeight:800,color:"#FF6B35"},children:["#",n+1]}),(0,t.jsxs)("div",{style:{display:"flex",gap:10,alignItems:"center"},children:[(0,t.jsx)(h,{person:e,size:44}),(0,t.jsxs)("div",{style:{minWidth:0},children:[(0,t.jsx)("div",{style:{fontWeight:700,fontSize:14},children:e.name}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",maxWidth:220},children:e.headline})]})]}),(0,t.jsxs)("div",{style:{fontSize:11.5,color:"#aab7b7",margin:"10px 0"},children:["via ",(0,t.jsx)("b",{style:{color:g[r.bridge.tier]},children:r.bridge.name})," · their circle ",r.done,"/",r.targets.length," this stage"]}),(0,t.jsxs)("div",{style:{display:"flex",gap:8},children:[e.profile_url&&(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:b,children:"Open on LinkedIn"}),(0,t.jsxs)("button",{onClick:()=>F(e,r),style:x,children:["I sent an invite · +",s[e.tier]||2]})]})]},e.id))})]}),(0,t.jsx)("h3",{style:{margin:"26px 0 4px",fontSize:15},children:"Circles to work through"}),(0,t.jsxs)("div",{style:{fontSize:12,color:"#8b9a9a",marginBottom:12},children:["Each is one of your connections and the best people they know, ",5," at a time. Fill the ring to clear a stage."]}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(190px, 1fr))",gap:12},children:S.clusters.map(e=>{let r=k===e.bridge.id;return(0,t.jsxs)("button",{onClick:()=>j(r?null:e.bridge.id),style:{padding:12,borderRadius:12,cursor:"pointer",textAlign:"center",color:"#fff",border:r?"1px solid #FF6B35":p,background:e.complete?"rgba(0,255,136,0.06)":"rgba(255,255,255,0.03)",display:"flex",flexDirection:"column",alignItems:"center",gap:6},children:[(0,t.jsx)(f,{progress:e.progress,color:e.complete?"#00ff88":"#FF6B35",children:(0,t.jsx)(h,{person:e.bridge,size:60})}),(0,t.jsx)("div",{style:{fontWeight:700,fontSize:13,maxWidth:170,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.bridge.name}),(0,t.jsx)("div",{style:{fontSize:11,color:e.complete?"#00ff88":"#aab7b7"},children:e.complete?"Circle cleared":`Stage ${e.stage} of ${e.stages} \xb7 ${e.done}/${e.targets.length}`}),(0,t.jsx)("div",{style:{display:"flex",gap:4},children:e.targets.map(e=>(0,t.jsx)("span",{title:e.name,style:{width:12,height:12,borderRadius:"50%",border:`2px solid ${g[e.tier]||"#667"}`,background:n.has(e.id)?g[e.tier]||"#667":"transparent"}},e.id))}),(0,t.jsxs)("div",{style:{fontSize:10.5,color:"#778"},children:[e.open.S?`${e.open.S} S \xb7 `:"",e.open.A?`${e.open.A} A \xb7 `:"",e.people.length," worth adding",e.added.length?` \xb7 ★ ${e.added.length} added`:""]})]},e.bridge.id)})}),z&&(0,t.jsxs)("div",{style:{marginTop:14,padding:16,borderRadius:12,border:"1px solid rgba(255,107,53,0.4)",background:"rgba(255,107,53,0.05)"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:10},children:[(0,t.jsx)(h,{person:z.bridge,size:40}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{style:{fontWeight:800},children:[z.bridge.name,"’s circle · stage ",z.stage," of ",z.stages]}),(0,t.jsxs)("div",{style:{fontSize:12,color:"#aab7b7"},children:["Ask ",z.bridge.name?.split(" ")[0]," for an intro, or invite them directly. Mark each one when it’s sent."]})]})]}),z.targets.map(e=>{let r=n.has(e.id);return(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"8px 0",borderTop:"1px solid rgba(255,255,255,0.05)"},children:[(0,t.jsx)(h,{person:e,size:34,ring:r?"#00ff88":void 0}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsxs)("div",{style:{fontWeight:600,fontSize:13},children:[e.name," ",(0,t.jsx)("span",{style:{color:g[e.tier],fontSize:11},children:e.tier})]}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline})]}),e.profile_url&&(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:b,children:"LinkedIn"}),r?(0,t.jsx)("button",{onClick:()=>m(e),style:{...b,color:"#00ff88"},children:"Sent ✓ (undo)"}):(0,t.jsxs)("button",{onClick:()=>F(e,z),style:x,children:["Sent · +",s[e.tier]||2]})]},e.id)}),z.added.length>0&&(0,t.jsxs)("div",{style:{marginTop:10,fontSize:12,color:"#00ff88"},children:["★ Added from this circle: ",z.added.map(e=>e.name).join(", ")]})]}),v&&(0,t.jsx)("div",{role:"status",style:{position:"fixed",bottom:24,left:"50%",transform:"translateX(-50%)",padding:"10px 18px",borderRadius:24,background:"linear-gradient(135deg, #FFD700, #FF6B35)",color:"#000",fontWeight:800,fontSize:13,boxShadow:"0 8px 30px rgba(0,0,0,0.5)",zIndex:50},children:v})]})}let x={padding:"7px 12px",borderRadius:8,border:"none",cursor:"pointer",fontWeight:800,fontSize:12,background:"linear-gradient(135deg, #FF6B35, #FFD700)",color:"#000"},b={padding:"7px 12px",borderRadius:8,border:p,cursor:"pointer",fontWeight:600,fontSize:12,background:"rgba(255,255,255,0.05)",color:"#dfe6e9",textDecoration:"none"};var y=e.i(2776),m=e.i(15812),S=e.i(90179),k=e.i(28867),j=e.i(86106),v=e.i(7214),w=e.i(40996);let _={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"};function F(){let{userId:e,userProfile:s}=(0,m.useUser)(),d=s?.sectors||[],[a,g]=(0,r.useState)([]),[p,h]=(0,r.useState)(!0),[f,x]=(0,r.useState)("all"),[b,y]=(0,r.useState)(new Set),F=(0,k.default)(),[z,B]=(0,r.useState)([]),[C,R]=(0,r.useState)({}),[I,W]=(0,r.useState)("quest"),[A,$]=(0,r.useState)([]),[M,D]=(0,r.useState)(()=>new Set),[T,O]=(0,r.useState)(null),[E,P]=(0,r.useState)(null),[U,L]=(0,r.useState)(()=>{{let e=new URLSearchParams(window.location.search);if(e.get("groupBy"))return e.get("groupBy")}return"bridge"});(0,r.useEffect)(()=>{{let e=new URLSearchParams(window.location.search).get("bridge");e&&P(e)}},[]),(0,r.useEffect)(()=>{!i.IS_DEMO&&e&&t();async function t(){let[t,r,i]=await Promise.all([(0,n.loadNetwork)(e),fetch(`/api/outreach?userId=${e}`).then(e=>e.json()).catch(()=>({pending:[]})),(0,w.loadScanNotes)()]),o=t.degree1,s=t.degree2;$(o.filter(e=>e.unlocked_from_bridge_id)),D(new Set(s.map(e=>e.source_connection_id).filter(Boolean))),O((0,l.reachIndex)(o,s,i));let a=new Set(o.map(e=>e.profile_url)),c={};o.forEach(e=>{c[e.id]=e}),B(r.pending||[]),R(c),g(s.filter(e=>("S"===e.tier||"A"===e.tier||"B"===e.tier)&&!a.has(e.profile_url)).map(e=>{let t,r,n=c[e.source_connection_id],i=(t=parseFloat(e.power_score)||0,r=(e.headline||"").toLowerCase(),(0,S.rowCompanyScore)(e)>=S.TOP_COMPANY&&(t+=1),(d||[]).forEach(e=>{r.includes(e.toLowerCase())&&(t+=.5)}),"S"===e.tier?t*=1.5:"A"===e.tier&&(t*=1.2),t),o="S"===e.tier?50:"A"===e.tier?25:10;return{...e,bridge:n,priority:i,xp:o}}).sort((e,t)=>t.priority-e.priority)),h(!1)}},[e]);let q=(0,r.useMemo)(()=>new Set([...z,...a].filter(e=>(0,j.hasRequest)(e,F)).map(e=>e.id)),[z,a,F]),N=(0,r.useMemo)(()=>{let e=new Set,t=[];for(let r of[...z,...a]){let n=(0,v.keyFor)(r);!e.has(n)&&(0,j.hasRequest)(r,F)&&(e.add(n),t.push({...r,bridge:C[r.source_connection_id]||r.bridge||null}))}return t},[z,a,F,C]);if(i.IS_DEMO)return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"rgba(255,255,255,0.7)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:10,textAlign:"center",padding:24},children:[(0,t.jsx)("h2",{style:{margin:0,fontSize:18,fontWeight:700,color:"#fff"},children:"Not part of the demo"}),(0,t.jsx)("div",{style:{fontSize:13},children:"The public demo includes the Network Circle and Degrees views only."}),(0,t.jsx)(o.default,{href:"/",style:{fontSize:12,color:"rgba(255,255,255,0.5)",textDecoration:"none"},children:"← Back to the network"})]});let H="all"===f?a:a.filter(e=>e.tier===f);E&&(H=H.filter(e=>e.bridge?.id===E));let V={S:0,A:0,B:0};a.forEach(e=>{void 0!==V[e.tier]&&V[e.tier]++});let Y={};H.forEach(e=>{let t;Y[t="bridge"===U?e.bridge?.id||"unknown":"company"===U?(e.company||"Unknown").trim()||"Unknown":e.tier]||(Y[t]=[]),Y[t].push(e)});let K={S:0,A:1,B:2},G=Object.entries(Y).sort((e,t)=>{if("tier"===U)return(K[e[0]]||9)-(K[t[0]]||9);if("bridge"===U){let r=e[1][0]?.bridge,n=t[1][0]?.bridge,i=K[r?.tier]??9,o=K[n?.tier]??9;if(i!==o)return i-o}return t[1].length-e[1].length});function X(e){y(t=>{let r=new Set(t);return r.has(e)?r.delete(e):r.add(e),r})}return p?(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff"},children:"Loading..."}):(0,t.jsxs)("div",{style:{height:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",overflow:"hidden"},children:[(0,t.jsxs)("header",{style:{padding:"14px 24px",borderBottom:"1px solid rgba(255,255,255,0.1)",flexShrink:0},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:10},children:[(0,t.jsxs)(o.default,{href:"/",style:{display:"flex",alignItems:"center",gap:6,color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.1)"},children:[(0,t.jsx)("span",{style:{fontSize:16},children:"←"})," Map"]}),(0,t.jsx)("h1",{style:{fontSize:20,fontWeight:700,margin:0,background:"linear-gradient(135deg, #FF6B35, #FFD700)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent"},children:"Outlink"}),(0,t.jsxs)("div",{style:{display:"flex",gap:2,background:"rgba(255,255,255,0.06)",borderRadius:6,padding:2},children:[(0,t.jsx)("button",{onClick:()=>W("quest"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:700,cursor:"pointer",background:"quest"===I?"linear-gradient(135deg, #FFD700, #FF6B35)":"transparent",color:"quest"===I?"#000":"#FFD700"},children:"Circles"}),(0,t.jsxs)("button",{onClick:()=>W("recs"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:"recs"===I?"#fff":"transparent",color:"recs"===I?"#000":"#888"},children:["To Add (",a.length,")"]}),(0,t.jsxs)("button",{onClick:()=>W("pending"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:"pending"===I?"linear-gradient(135deg, #FF6B35, #FFD700)":"transparent",color:"pending"===I?"#000":"#FF6B35"},children:["Pending (",N.length,")"]})]}),(0,t.jsx)("div",{style:{marginLeft:"auto",display:"flex",gap:6},children:"recs"===I&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{onClick:()=>L("tier"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"tier"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"tier"===U?"#fff":"#666"},children:"By Tier"}),(0,t.jsx)("button",{onClick:()=>L("bridge"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"bridge"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"bridge"===U?"#fff":"#666"},children:"By Bridge"}),(0,t.jsx)("button",{onClick:()=>L("company"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"company"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"company"===U?"#fff":"#666"},children:"By Company"})]})})]}),(0,t.jsx)("div",{style:{display:"quest"===I?"none":"flex",gap:6},children:[{k:"all",l:`All (${a.length})`},{k:"S",l:`S (${V.S})`,c:_.S},{k:"A",l:`A (${V.A})`,c:_.A},{k:"B",l:`B (${V.B})`,c:_.B}].map(e=>(0,t.jsx)("button",{onClick:()=>x(e.k),style:{padding:"4px 12px",borderRadius:16,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:f===e.k?e.c||"#fff":"rgba(255,255,255,0.06)",color:f===e.k?"#000":e.c||"#888"},children:e.l},e.k))})]}),"recs"===I&&b.size>0&&(0,t.jsxs)("div",{style:{padding:"10px 24px",background:"rgba(255,215,0,0.08)",borderBottom:"1px solid rgba(255,215,0,0.2)",display:"flex",alignItems:"center",gap:12,flexShrink:0},children:[(0,t.jsxs)("span",{style:{fontSize:12,color:"#FFD700",fontWeight:600},children:[b.size," selected"]}),(0,t.jsxs)("button",{onClick:function(){let e=H.filter(e=>b.has(e.id));if(0===e.length)return;if(1===e.length)return void window.open(e[0].profile_url,"_blank");let t=new Blob([`<!DOCTYPE html><html><head><title>Outlink — ${e.length} profiles</title>
|
|
2
|
+
<style>body{background:#0a0a1a;color:#fff;font-family:-apple-system,sans-serif;padding:24px;margin:0}
|
|
3
|
+
h2{color:#FFD700;margin-bottom:4px}p{color:#888;font-size:13px;margin-bottom:16px}
|
|
4
|
+
.btn{display:block;padding:12px 16px;margin-bottom:6px;background:rgba(255,255,255,0.06);
|
|
5
|
+
border:1px solid rgba(255,255,255,0.1);border-radius:8px;color:#fff;text-decoration:none;
|
|
6
|
+
font-size:13px;transition:background 0.15s}.btn:hover{background:rgba(0,119,181,0.2)}
|
|
7
|
+
.name{font-weight:700}.tier{font-size:11px;margin-left:8px;font-weight:600}
|
|
8
|
+
.open-all{display:inline-block;padding:12px 24px;background:linear-gradient(135deg,#FFD700,#FF6B35);
|
|
9
|
+
color:#000;border-radius:8px;font-weight:700;font-size:14px;cursor:pointer;border:none;margin-bottom:20px}</style></head>
|
|
10
|
+
<body><h2>Open ${e.length} Profiles</h2>
|
|
11
|
+
<p>Click each link or use the button below to open all at once.</p>
|
|
12
|
+
<button class="open-all" onclick="document.querySelectorAll('.btn').forEach((a,i)=>setTimeout(()=>a.click(),i*300))">
|
|
13
|
+
Open All (${e.length})</button>
|
|
14
|
+
${e.map(e=>{let t="S"===e.tier?"#FFD700":"A"===e.tier?"#9B59B6":"#3498DB";return'<a class="btn" href="'+e.profile_url+'" target="_blank"><span class="name">'+(e.name||"")+'</span><span class="tier" style="color:'+t+'">'+e.tier+" · "+parseFloat(e.power_score||0).toFixed(1)+'</span><br><span style="color:#666;font-size:11px">'+(e.headline||"").substring(0,60)+"</span></a>"}).join("")}
|
|
15
|
+
</body></html>`],{type:"text/html"});window.open(URL.createObjectURL(t),"_blank")},style:{padding:"6px 16px",borderRadius:6,border:"none",cursor:"pointer",background:"#0077B5",color:"#fff",fontWeight:700,fontSize:12},children:["Open ",b.size," on LinkedIn"]}),(0,t.jsxs)("span",{style:{fontSize:10,color:"#888"},children:["+",H.filter(e=>b.has(e.id)).reduce((e,t)=>e+t.xp,0)," XP potential"]}),(0,t.jsx)("button",{onClick:()=>y(new Set),style:{marginLeft:"auto",background:"none",border:"none",color:"#888",cursor:"pointer",fontSize:11},children:"Clear"})]}),"quest"===I&&(0,t.jsx)("div",{style:{flex:1,overflow:"auto"},children:(0,t.jsx)(u,{recs:a,sentIds:q,added:A,mappedIds:M,reach:T,onSend:e=>(0,j.markRequested)(e,{bridgeId:e.source_connection_id}).catch(()=>{}),onUndo:e=>(0,j.undoRequest)(e).catch(()=>{})})}),"quest"!==I&&(0,t.jsx)("div",{style:{flex:1,overflow:"auto",padding:"12px 24px"},children:(0,t.jsxs)("div",{style:{maxWidth:700,margin:"0 auto"},children:["pending"===I&&(0,t.jsx)(t.Fragment,{children:0===N.length?(0,t.jsxs)("div",{style:{textAlign:"center",padding:40,color:"#555"},children:[(0,t.jsx)("div",{style:{fontSize:32,marginBottom:8},children:"⏳"}),(0,t.jsx)("div",{style:{fontSize:14,fontWeight:600},children:"No pending requests"}),(0,t.jsx)("div",{style:{fontSize:11,color:"#444",marginTop:4},children:'Click "Add" on someone to track your outreach'})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{fontSize:10,color:"#666",marginBottom:12},children:"Waiting for response. When they accept, their cluster unlocks for bridging."}),N.map(e=>(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"10px 12px",marginBottom:4,background:"rgba(255,107,53,0.04)",borderRadius:8,border:"1px solid rgba(255,107,53,0.1)"},children:[(0,c.localPhoto)(e.profile_image_url)?(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",style:{width:36,height:36,borderRadius:"50%",objectFit:"cover",flexShrink:0,border:`2px solid ${_[e.tier]||"#555"}`},onError:e=>{e.target.style.display="none"}}):(0,t.jsx)("div",{style:{width:36,height:36,borderRadius:"50%",flexShrink:0,fontSize:14,fontWeight:700,background:_[e.tier]||"#555",color:"S"===e.tier?"#000":"#fff",display:"flex",alignItems:"center",justifyContent:"center"},children:e.name?.charAt(0)}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsx)("div",{style:{fontSize:13,fontWeight:600},children:e.name}),(0,t.jsx)("div",{style:{fontSize:10,color:"#888",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline?.substring(0,55)}),e.bridge&&(0,t.jsxs)("div",{style:{fontSize:9,color:"#FF6B35",marginTop:2},children:["via ",e.bridge.name?.split(" ")[0]," · unlocks bridge cluster"]})]}),(0,t.jsxs)("div",{style:{textAlign:"center",flexShrink:0},children:[(0,t.jsx)("div",{style:{fontSize:10,fontWeight:800,color:_[e.tier],padding:"2px 8px",borderRadius:4,background:`${_[e.tier]||"#555"}15`},children:e.tier}),(0,t.jsx)("div",{style:{fontSize:8,color:"#FF6B35",marginTop:2,fontWeight:600},children:"PENDING"})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:4,flexShrink:0},children:[(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:{padding:"4px 8px",borderRadius:4,fontSize:9,fontWeight:700,background:"#0077B5",color:"#fff",textDecoration:"none"},children:"View"}),(0,t.jsx)("button",{onClick:()=>{(0,j.undoRequest)(e).catch(()=>{})},style:{padding:"4px 8px",borderRadius:4,fontSize:9,fontWeight:600,background:"rgba(255,255,255,0.06)",color:"#666",border:"none",cursor:"pointer"},children:"Undo"})]})]},e.id))]})}),"recs"===I&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:8},children:[(0,t.jsx)("input",{type:"checkbox",checked:b.size===H.length&&H.length>0,onChange:function(){b.size===H.length?y(new Set):y(new Set(H.map(e=>e.id)))},style:{cursor:"pointer"}}),(0,t.jsxs)("span",{style:{fontSize:10,color:"#666"},children:["Select all (",H.length,")"]})]}),G.map(([e,r])=>(0,t.jsxs)("div",{style:{marginBottom:16},children:["bridge"===U?(()=>{let e=r[0]?.bridge;if(!e)return null;let n=r.filter(e=>"S"===e.tier).length,i=r.filter(e=>"A"===e.tier).length,o=r.filter(e=>"B"===e.tier).length,l=3*n+2*i+o;return(0,t.jsxs)("div",{style:{padding:"10px 12px",marginBottom:6,borderRadius:8,background:`${_[e.tier]||"#555"}08`,border:`1px solid ${_[e.tier]||"#555"}20`},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10},children:[(0,c.localPhoto)(e.profile_image_url)?(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",style:{width:36,height:36,borderRadius:"50%",objectFit:"cover",border:`2px solid ${_[e.tier]}`},onError:e=>{e.target.style.display="none"}}):(0,t.jsx)("div",{style:{width:36,height:36,borderRadius:"50%",fontSize:14,fontWeight:700,background:_[e.tier],color:"S"===e.tier?"#000":"#fff",display:"flex",alignItems:"center",justifyContent:"center"},children:e.name?.charAt(0)}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsx)("div",{style:{fontSize:13,fontWeight:700,color:"#fff"},children:e.name}),(0,t.jsx)("div",{style:{fontSize:9,color:"#888",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline?.substring(0,50)})]}),(0,t.jsxs)("div",{style:{textAlign:"right",flexShrink:0},children:[(0,t.jsx)("div",{style:{fontSize:11,fontWeight:800,color:_[e.tier]},children:e.tier}),(0,t.jsxs)("div",{style:{fontSize:8,color:"#666"},children:[r.length," to add"]})]})]}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,marginTop:8},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:4,fontSize:9},children:[n>0&&(0,t.jsxs)("span",{style:{color:"#FFD700",fontWeight:700},children:[n,"S"]}),i>0&&(0,t.jsxs)("span",{style:{color:"#9B59B6",fontWeight:700},children:[i,"A"]}),o>0&&(0,t.jsxs)("span",{style:{color:"#3498DB",fontWeight:700},children:[o,"B"]})]}),(0,t.jsx)("div",{style:{flex:1,height:4,background:"rgba(255,255,255,0.06)",borderRadius:2},children:(0,t.jsx)("div",{style:{height:"100%",borderRadius:2,width:`${Math.min(100,l/30*100)}%`,background:`linear-gradient(90deg, ${_[e.tier]}, #FF6B35)`}})}),(0,t.jsxs)("button",{onClick:()=>{let e=r.map(e=>e.profile_url);if(1===e.length)return void window.open(e[0],"_blank");let t=`<!DOCTYPE html><html><head><title>Top ${Math.min(10,e.length)}</title>
|
|
16
|
+
<style>body{background:#0a0a1a;color:#fff;font-family:-apple-system,sans-serif;padding:24px}
|
|
17
|
+
.btn{display:block;padding:10px 14px;margin-bottom:4px;background:rgba(255,255,255,0.06);
|
|
18
|
+
border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#fff;text-decoration:none;font-size:12px}
|
|
19
|
+
.btn:hover{background:rgba(0,119,181,0.2)}
|
|
20
|
+
.oa{display:inline-block;padding:10px 20px;background:#0077B5;color:#fff;border-radius:6px;
|
|
21
|
+
font-weight:700;font-size:13px;cursor:pointer;border:none;margin-bottom:16px}</style></head>
|
|
22
|
+
<body><h3 style="color:#FF6B35">Top ${Math.min(10,e.length)} to connect</h3>
|
|
23
|
+
<button class="oa" onclick="document.querySelectorAll('.btn').forEach((a,i)=>setTimeout(()=>a.click(),i*300))">
|
|
24
|
+
Open All</button>${e.slice(0,10).map(e=>'<a class="btn" href="'+e+'" target="_blank">'+e.split("/in/")[1]?.replace("/","")+"</a>").join("")}</body></html>`;window.open(URL.createObjectURL(new Blob([t],{type:"text/html"})),"_blank")},style:{padding:"4px 10px",borderRadius:4,border:"none",cursor:"pointer",background:"#0077B5",color:"#fff",fontSize:9,fontWeight:700,whiteSpace:"nowrap"},children:["Open Top ",Math.min(10,r.length)]})]})]})})():(0,t.jsxs)("div",{style:{padding:"6px 10px",marginBottom:4,background:"tier"===U?`${_[e]||"#555"}15`:"rgba(255,255,255,0.04)",borderLeft:`3px solid ${"tier"===U?_[e]||"#555":"#FF6B35"}`,borderRadius:4,display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,t.jsx)("span",{style:{fontSize:11,fontWeight:700,color:"tier"===U?_[e]||"#888":"#FF6B35"},children:"tier"===U?`${e}-Tier`:e}),(0,t.jsx)("span",{style:{fontSize:10,color:"#666"},children:r.length})]}),"bridge"===U?["S","A","B"].map(e=>{let n=r.filter(t=>t.tier===e);return 0===n.length?null:(0,t.jsxs)("div",{style:{marginBottom:6},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:6,padding:"3px 8px",marginBottom:2,borderLeft:`2px solid ${_[e]}`},children:[(0,t.jsx)("input",{type:"checkbox",checked:n.every(e=>b.has(e.id)),onChange:()=>{let e=n.every(e=>b.has(e.id));y(t=>{let r=new Set(t);return n.forEach(t=>{e?r.delete(t.id):r.add(t.id)}),r})},style:{cursor:"pointer",flexShrink:0}}),(0,t.jsx)("div",{style:{width:6,height:6,borderRadius:"50%",background:_[e]}}),(0,t.jsxs)("span",{style:{fontSize:9,fontWeight:700,color:_[e]},children:[e,"-Tier"]}),(0,t.jsx)("span",{style:{fontSize:8,color:"#555"},children:n.length}),(0,t.jsxs)("button",{onClick:()=>{if(1===n.length)return void window.open(n[0].profile_url,"_blank");let t=`<!DOCTYPE html><html><head><title>${e}-Tier — ${n.length}</title>
|
|
25
|
+
<style>body{background:#0a0a1a;color:#fff;font-family:-apple-system,sans-serif;padding:24px}
|
|
26
|
+
.btn{display:block;padding:10px 14px;margin-bottom:4px;background:rgba(255,255,255,0.06);
|
|
27
|
+
border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#fff;text-decoration:none;font-size:12px}
|
|
28
|
+
.btn:hover{background:rgba(0,119,181,0.2)}
|
|
29
|
+
.oa{display:inline-block;padding:10px 20px;background:#0077B5;color:#fff;border-radius:6px;
|
|
30
|
+
font-weight:700;font-size:13px;cursor:pointer;border:none;margin-bottom:16px}</style></head>
|
|
31
|
+
<body><h3 style="color:${_[e]}">${e}-Tier (${n.length})</h3>
|
|
32
|
+
<button class="oa" onclick="document.querySelectorAll('.btn').forEach((a,i)=>setTimeout(()=>a.click(),i*300))">
|
|
33
|
+
Open All</button>${n.map(e=>'<a class="btn" href="'+e.profile_url+'" target="_blank">'+e.name+" · "+parseFloat(e.power_score||0).toFixed(1)+"</a>").join("")}</body></html>`;window.open(URL.createObjectURL(new Blob([t],{type:"text/html"})),"_blank")},style:{marginLeft:"auto",padding:"2px 8px",borderRadius:3,border:"none",cursor:"pointer",background:"#0077B5",color:"#fff",fontSize:8,fontWeight:700},children:["Open All ",e]})]}),n.map(e=>(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"5px 8px 5px 16px",borderBottom:"1px solid rgba(255,255,255,0.02)",background:b.has(e.id)?"rgba(255,215,0,0.05)":"transparent",cursor:"pointer"},onMouseEnter:t=>{b.has(e.id)||(t.currentTarget.style.background="rgba(255,255,255,0.04)")},onMouseLeave:t=>{b.has(e.id)||(t.currentTarget.style.background="transparent")},children:[(0,t.jsx)("input",{type:"checkbox",checked:b.has(e.id),onChange:()=>X(e.id),onClick:e=>e.stopPropagation(),style:{cursor:"pointer",flexShrink:0}}),(0,c.localPhoto)(e.profile_image_url)?(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",style:{width:28,height:28,borderRadius:"50%",objectFit:"cover",flexShrink:0,border:`1.5px solid ${_[e.tier]||"#555"}`},onError:e=>{e.target.style.display="none"}}):(0,t.jsx)("div",{style:{width:28,height:28,borderRadius:"50%",flexShrink:0,fontSize:10,fontWeight:700,background:_[e.tier]||"#555",color:"S"===e.tier?"#000":"#fff",display:"flex",alignItems:"center",justifyContent:"center"},children:e.name?.charAt(0)}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},onClick:()=>X(e.id),children:[(0,t.jsx)("div",{style:{fontSize:11,fontWeight:600,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name}),(0,t.jsx)("div",{style:{fontSize:8,color:"#666",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline?.substring(0,45)})]}),(0,t.jsx)("span",{style:{fontSize:9,fontWeight:700,color:_[e.tier],flexShrink:0},children:parseFloat(e.power_score||0).toFixed(1)}),q.has(e.id)?(0,t.jsx)("span",{style:{padding:"3px 6px",borderRadius:3,fontSize:8,fontWeight:700,background:"rgba(255,107,53,0.15)",color:"#FF6B35",flexShrink:0},children:"Sent"}):(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",onClick:t=>{t.stopPropagation(),(0,j.markRequested)(e,{bridgeId:e.source_connection_id}).catch(()=>{})},style:{padding:"3px 6px",borderRadius:3,fontSize:8,fontWeight:700,background:"#0077B5",color:"#fff",textDecoration:"none",flexShrink:0},children:"Add"})]},e.id))]},e)}):r.map(e=>(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"6px 8px",borderBottom:"1px solid rgba(255,255,255,0.03)",background:b.has(e.id)?"rgba(255,215,0,0.05)":"transparent",cursor:"pointer"},onMouseEnter:t=>{b.has(e.id)||(t.currentTarget.style.background="rgba(255,255,255,0.04)")},onMouseLeave:t=>{b.has(e.id)||(t.currentTarget.style.background="transparent")},children:[(0,t.jsx)("input",{type:"checkbox",checked:b.has(e.id),onChange:()=>X(e.id),onClick:e=>e.stopPropagation(),style:{cursor:"pointer",flexShrink:0}}),(0,c.localPhoto)(e.profile_image_url)?(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",style:{width:32,height:32,borderRadius:"50%",objectFit:"cover",flexShrink:0,border:`1.5px solid ${_[e.tier]||"#555"}`},onError:e=>{e.target.style.display="none",e.target.nextSibling.style.display="flex"}}):null,(0,t.jsx)("div",{style:{width:32,height:32,borderRadius:"50%",flexShrink:0,fontSize:12,fontWeight:700,background:_[e.tier]||"#555",color:"S"===e.tier?"#000":"#fff",display:(0,c.localPhoto)(e.profile_image_url)?"none":"flex",alignItems:"center",justifyContent:"center"},children:e.name?.charAt(0)}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},onClick:()=>X(e.id),children:[(0,t.jsx)("div",{style:{fontSize:12,fontWeight:600,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name}),(0,t.jsx)("div",{style:{fontSize:9,color:"#666",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline?.substring(0,50)})]}),e.bridge&&(0,t.jsxs)("span",{style:{fontSize:8,color:"#555",flexShrink:0,maxWidth:60,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:["via ",e.bridge.name?.split(" ")[0]]}),(0,t.jsx)("div",{style:{textAlign:"right",flexShrink:0,minWidth:32},children:(0,t.jsx)("div",{style:{fontSize:10,fontWeight:700,color:_[e.tier]},children:parseFloat(e.power_score).toFixed(1)})}),q.has(e.id)?(0,t.jsx)("span",{style:{padding:"4px 8px",borderRadius:4,fontSize:9,fontWeight:700,background:"rgba(255,107,53,0.15)",color:"#FF6B35",flexShrink:0},children:"⏳ Sent"}):(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",onClick:t=>{t.stopPropagation(),(0,j.markRequested)(e,{bridgeId:e.source_connection_id}).catch(()=>{})},style:{padding:"4px 8px",borderRadius:4,fontSize:9,fontWeight:700,background:"#0077B5",color:"#fff",textDecoration:"none",flexShrink:0},children:"Add"})]},e.id))]},e))]})]})})]})}e.s(["default",0,function(){return(0,t.jsx)(y.default,{children:(0,t.jsx)(F,{})})}],77305)},19821,e=>{"use strict";async function t(e){let t=e?`/api/network?userId=${encodeURIComponent(e)}`:"/api/network",r=await fetch(t);if(!r.ok)throw Error(`Failed to load network (${r.status})`);let n=await r.json();return{degree1:n.degree1||[],degree2:n.degree2||[],degree3:n.degree3||[],ties:Number(n.ties)||0}}e.s(["loadNetwork",0,t])},36774,e=>{"use strict";let t=/^[A-Za-z0-9_-]+\.(webp|jpg|jpeg|png)$/,r="/avatars/";e.s(["localPhoto",0,function(e){return"string"==typeof e&&e.startsWith(r)&&t.test(e.slice(r.length))?e:null}])},48235,e=>{"use strict";var t=e.i(7214);function r(e,r){return e?r.scanned.has(e.id)||e.profile_url&&r.read?.has((0,t.keyFor)(e))?"scanned":e.profile_url&&r.hidden.has((0,t.keyFor)(e))?"hidden":"todo":"todo"}function n(e,t){if(!e||1!==e.degree||null==e.unlocked_from_bridge_id)return null;let n=r(e,t);return"todo"===n?"ready":n}e.s(["circleScanCost",0,function(e=100){let t=Math.max(1,Math.min(100,Math.round(e)||100));return{profileViews:1,searches:t,minutes:t>=100?55:Math.max(5,Math.round(.55*t))}},"circleState",0,r,"reachIndex",0,function(e=[],r=[],n={}){let i=new Set;for(let e of r||[])e?.source_connection_id!=null&&i.add(e.source_connection_id);let o=new Set;for(let e of n?.skips||[])e?.profileUrl&&o.add((0,t.keyFor)({profile_url:e.profileUrl}));let l=new Set;for(let e of n?.read||[])e&&l.add((0,t.keyFor)({profile_url:e}));let s=new Map;for(let[e,r]of Object.entries(n?.lists||{}))e&&r&&s.set((0,t.keyFor)({profile_url:e}),r);let d=new Map;for(let t of e||[]){let e=t?.unlocked_from_bridge_id;if(null==e||1!==t.degree)continue;let r=d.get(e);r||d.set(e,r=[]),r.push(t)}return{scanned:i,read:l,hidden:o,reachedFrom:d,lists:s}},"reachState",0,n,"readyByCircle",0,function(e){let t=new Map;for(let[r,i]of e.reachedFrom){let o=i.filter(t=>"ready"===n(t,e)).length;o&&t.set(r,o)}return t},"readyToScan",0,function(e,r){return(e||[]).filter(e=>"ready"===n(e,r)).sort(t.compareBridges)},"scanBars",0,function(e,n){let i=r(e,n),o=e?.profile_url?n.lists?.get((0,t.keyFor)(e)):null;return"hidden"===i?null:o?o.more?o.total?Math.max(1,Math.min(4,Math.round(5*Math.min(1,10*o.pages/o.total)))):2:5:"scanned"===i?2:null}])},7214,e=>{"use strict";var t=e.i(36774);let r={S:0,A:1,B:2,C:3,D:4};function n(e){let t=parseFloat(e?.power_score);return Number.isFinite(t)?t:0}function i(e){return Math.round(10*n(e))/10}function o(e){return String(e?.profile_url||"").split(/[?#]/)[0].replace(/\/+$/,"")||`id:${e?.id}`}let l=(e,t)=>String(e??"").localeCompare(String(t??""),void 0,{numeric:!0});function s(e,t){return(r[e.tier]??9)-(r[t.tier]??9)||n(t)-n(e)||String(e.name||"").localeCompare(String(t.name||""))||l(e.id,t.id)}function d(e,t){return e.bridge&&t.bridge?s(e.bridge,t.bridge):e.bridge?-1:t.bridge?1:l(e.id,t.id)}function a(e,t){return t.score-e.score||t.waysIn-e.waysIn||d(e.routes[0]||c,t.routes[0]||c)||String(e.person.name||"").localeCompare(String(t.person.name||""))||(e.key<t.key?-1:+(e.key>t.key))}let c={id:null,bridge:null};function g(e){let t=String(e||"").trim().split(/\s+/).filter(Boolean);return t.length<2?t[0]||"":`${t[0]} ${t[t.length-1].charAt(0)}.`}function p(e,t){let r=String(e||"");return t<=1?r?"…":"":r.length>t?`${r.slice(0,t-1)}…`:r}e.s(["TIERS",0,["S","A","B","C","D"],"compareBridges",0,s,"compareWaysIn",0,function(e,t){return t.waysIn-e.waysIn||a(e,t)},"keyFor",0,o,"routeIndex",0,function(e=[]){let t=new Map;for(let r of e||[]){let e=o(r),n=t.get(e);n||(n=new Set,t.set(e,n)),n.add(r.source_connection_id??null)}return t},"routesFor",0,function(e,t,r){return e?[...t?.get(o(e))??(null!=e.source_connection_id?new Set([e.source_connection_id]):new Set)].map(e=>({id:e,bridge:r?.get(e)??null})).sort(d):[]},"score",0,n,"score1",0,i,"separationPeople",0,function(e=[],r=[]){let n=new Map;for(let e of r||[])n.set(e.id,e);let s=new Map,c=new Map;for(let r of e||[]){let e=o(r);c.set(r.id,e);let n=s.get(e);n?function(e,r){let n=i(e)-i(r);if(n)return n>0;let o=!!(0,t.localPhoto)(e.profile_image_url);return!!(0,t.localPhoto)(r.profile_image_url)!==o?o:0>l(e.id,r.id)}(r,n.person)&&(n.person=r):(n={key:e,person:r,rowIds:[],routeIds:new Set},s.set(e,n)),n.rowIds.push(r.id),n.routeIds.add(r.source_connection_id??null)}let g={people:s.size,byTier:{S:0,A:0,B:0,C:0,D:0},multi:0,bridges:0,unresolvedIds:0,peopleOnlyUnresolved:0,onlyUnresolvedVia:0},p=new Set,h=new Set,f=new Set,u=[];for(let e of s.values()){let t=[...e.routeIds].map(e=>({id:e,bridge:n.get(e)??null}));t.sort(d);let r=t.filter(e=>e.bridge);for(let e of t)(e.bridge?p:h).add(e.id);if(!r.length)for(let e of(g.peopleOnlyUnresolved++,t))f.add(e.id);let{person:o}=e,l=o.tier;void 0!==g.byTier[l]&&g.byTier[l]++,t.length>1&&g.multi++,u.push({key:e.key,person:o,score:i(o),tier:l,routes:t,waysIn:t.length,rowIds:e.rowIds,haystack:[o.name,o.headline,o.company,o.role,...r.map(e=>e.bridge.name)].filter(Boolean).join("\n").toLowerCase(),rank:0,tied:!1})}return g.bridges=p.size,g.unresolvedIds=h.size,g.onlyUnresolvedVia=f.size,u.sort(a),function(e){for(let t=0;t<e.length;t++){let r=e[t],n=e[t-1],i=n&&n.score===r.score&&n.waysIn===r.waysIn;r.rank=i?n.rank:t+1,i&&(r.tied=!0,n.tied=!0)}}(u),{people:u,rowToKey:c,summary:g}},"shortName",0,g,"summitLayout",0,function(e=[],t=800,r=!1){let n=r?36:26,i=Math.round(.42*t),o=Math.round(.58*t),l=e.map((e,r)=>{var i;return{key:e.key,p:e,x:o,y:16+r*n,r:(i=e.waysIn)>=4?8.5:3===i?7:2===i?5.5:4,label:p(`#${e.rank}${e.tied?"=":""} ${e.person.name||""}`,Math.floor((t-o-60)/6.2))}}),d=new Map,a="\0unresolved";for(let e of l)for(let t of e.p.routes){let r=t.bridge?t.id:a,n=d.get(r);n||(n={id:t.bridge?t.id:null,bridge:t.bridge,unresolved:!t.bridge,ys:[],count:0},d.set(r,n)),n.count++,n.ys.push(e.y)}let c=[...d.values()].map(e=>({...e,bary:e.ys.reduce((e,t)=>e+t,0)/e.ys.length}));c.sort((e,t)=>e.bary-t.bary||e.unresolved-t.unresolved||(e.bridge&&t.bridge?s(e.bridge,t.bridge):0));let h=l.length?l[l.length-1].y:16,f=c.length>1?Math.max(18,(h-16)/(c.length-1)):0,u=Math.max(4,Math.floor((i-10-42)/6));c.forEach((e,t)=>{if(e.x=i,e.y=1===c.length?(16+h)/2:16+t*f,e.r=5,e.unresolved)e.label=p(`can't be named (${e.count})`,u);else{let t=e.bridge.name||"";e.label=t.length<=u?t:p(g(t),u)}delete e.ys});let x=new Map(c.map(e=>[e.unresolved?a:e.id,e])),b=[];for(let e of l){let t=new Set;e.p.routes.forEach((r,n)=>{let i=r.bridge?r.id:a;if(t.has(i))return;t.add(i);let o=x.get(i);b.push({key:e.key,bridgeId:o.id,primary:0===n&&!o.unresolved,unresolved:o.unresolved,tier:o.bridge?.tier??null,x1:o.x,y1:o.y,x2:e.x,y2:e.y})})}let y=Math.max(h,c.length?c[c.length-1].y:0),m=l.length?Math.ceil(y+16):0,S={x:20,y:l.length?(16+Math.max(h,y))/2:16,r:14},k=c.map(e=>({id:e.id,x1:S.x,y1:S.y,x2:e.x,y2:e.y}));return{width:t,height:m,you:S,people:l,bridges:c,links:b,spokes:k}}])},5258,e=>{"use strict";e.s(["TIER_COLORS",0,{S:"#f6c344",A:"#a78bfa",B:"#60a5fa",C:"#94a3b8",D:"#6b7280"},"TIER_COLORS_CLASSIC",0,{S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},"TIER_ORDER",0,["S","A","B","C","D"],"TIER_RING_RADIUS",0,{S:150,A:230,B:310,C:390,D:470},"initialsFor",0,function(e){let t=String(e||"").trim().split(/\s+/).filter(Boolean);return 0===t.length?"?":(t[0].charAt(0)+(t.length>1?t[t.length-1].charAt(0):"")).toUpperCase()}])}]);
|
|
@@ -6,6 +6,69 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.4] - 2026-09-29
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Social (experimental): a tab for your relationships.** It works from your own LinkedIn data:
|
|
13
|
+
- **Your export:** the folder LinkedIn emails you from *Settings → Data privacy → Get a copy
|
|
14
|
+
of your data*, read in the app window with no traffic to LinkedIn.
|
|
15
|
+
- **A live messages sync:** reads your messages list once in your own Chrome, by hand or once
|
|
16
|
+
a day in the daytime, using no search budget.
|
|
17
|
+
|
|
18
|
+
It shows:
|
|
19
|
+
- how many of your connections are warm, cool, dormant or never messaged;
|
|
20
|
+
- who's waiting on a reply (S and A tier first), or has unread messages;
|
|
21
|
+
- your career chapters, with the connections made in each and how many you're still in
|
|
22
|
+
touch with;
|
|
23
|
+
- whether posting works (new connections the week after a post against a usual week);
|
|
24
|
+
- how many connection requests came to you and how many you sent.
|
|
25
|
+
|
|
26
|
+
Only dates, who wrote last and counts are kept, one file per profile in the data folder, and
|
|
27
|
+
*Forget it* removes it. Message text is never kept. Email addresses are kept only if you tick
|
|
28
|
+
the box. The live sync hasn't been tried on a live account yet.
|
|
29
|
+
- **Auto scan.** With the Scan page's experimental all-day box ticked, an *Auto scan* button sits
|
|
30
|
+
beside Scan and starts the all-day Auto-Bridge with your Scan page choices. The status bar sits
|
|
31
|
+
under the tabs, dimmed while it's ready, and lights up once it runs.
|
|
32
|
+
- **Insights on a connection's card.** A collapsible panel with their circle's size (*Explore →*
|
|
33
|
+
opens it in Bridge Chains), how many only they reach, whose circle overlaps theirs most
|
|
34
|
+
(*Open →*), the tier mix of their circle, where most of it works, how much is scanned (*Scan →*
|
|
35
|
+
or *Finish →*), when you connected and how many requests you have out through them, and their
|
|
36
|
+
rank by who only they reach. *Show them →* opens Separation filtered to the people only they
|
|
37
|
+
reach, and *S only →* to the S-tier people in their circle. All from what the app already
|
|
38
|
+
keeps. It replaces the *Only through …* box.
|
|
39
|
+
- **Network health on the Scores tab.** How much of your 2nd degree you reach two or more ways,
|
|
40
|
+
the effective reach of your own network (Burt's effective size, from the ties between your
|
|
41
|
+
connections that circle scans keep), and your five connections who reach the most people no
|
|
42
|
+
one else does, each with *Explore →*. With fewer than five circles scanned it says it's an
|
|
43
|
+
early estimate. Only your own numbers: never a percentile against other people.
|
|
44
|
+
|
|
45
|
+
## [0.4.3] - 2026-09-29
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- **Experimental Auto-Bridge (a switch on the Scan page).** All-day pacing that stays openly
|
|
49
|
+
slow: up to 10 pages in a sitting, then a 45-minute rest; searches only from 09:00 to 19:00 on
|
|
50
|
+
this computer's clock; at the daily budget it waits for it to free up instead of stopping;
|
|
51
|
+
and every page is saved as it's read. It also reads the data LinkedIn already sends for each
|
|
52
|
+
page of results (no extra requests) beside the page text. That fills in headlines, photos and
|
|
53
|
+
mutual counts the page text missed, and gives each list's real length for the scan bars. Each
|
|
54
|
+
page logs how the two compare, and a few raw responses are kept in the data folder
|
|
55
|
+
(`wire-samples/`) to tune it. People only LinkedIn's data shows are logged, not added. The
|
|
56
|
+
timing is never randomised to look like a person. Not yet tried on a live account.
|
|
57
|
+
- **A status bar while a scan runs, on every page.** It shows what's running and for whom, how
|
|
58
|
+
far it's got, today's LinkedIn searches against your daily budget (green, then amber past 60%,
|
|
59
|
+
red past 90%), what the scanner is doing right now (for example the wait before the next
|
|
60
|
+
profile), a link to the Scan page and Stop. Stop saves what was read, and Resume carries on
|
|
61
|
+
from the same page. It sits just under the header's tabs, on every page, the Scan page too.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
- **Network Circle's tiers switch on and off.** In the Filter panel, click a tier to hide it or
|
|
65
|
+
show it again, so C and D can go while S, A and B stay. *All* shows everyone. Degrees still
|
|
66
|
+
picks one bridge tier at a time.
|
|
67
|
+
- **Orbit: the circles behind added people sit behind their bridge.** They're centred on the
|
|
68
|
+
bridge's slice, side by side, with a line back to whoever they came through, wherever that
|
|
69
|
+
person sits. Before, each was centred on that person and could spill into the next bridge's
|
|
70
|
+
space.
|
|
71
|
+
|
|
9
72
|
## [0.4.2] - 2026-09-29
|
|
10
73
|
|
|
11
74
|
### Added
|
|
@@ -33,7 +33,18 @@ export async function GET(request) {
|
|
|
33
33
|
return Response.json({ error: firstError.message }, { status: 500 });
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// How many ties between your own connections circle scans have kept (lib/ties.js),
|
|
37
|
+
// for network health on the Scores tab.
|
|
38
|
+
let ties = 0;
|
|
39
|
+
try {
|
|
40
|
+
let tq = supabase.from('connection_ties').select('a_url');
|
|
41
|
+
if (userId) tq = tq.eq('user_id', userId);
|
|
42
|
+
const { data } = await tq;
|
|
43
|
+
ties = data?.length || 0;
|
|
44
|
+
} catch { /* an older database: none yet */ }
|
|
45
|
+
|
|
36
46
|
return Response.json({
|
|
47
|
+
ties,
|
|
37
48
|
degree1: d1.data || [],
|
|
38
49
|
degree2: d2.data || [],
|
|
39
50
|
degree3: d3.data || [],
|
|
@@ -342,9 +342,23 @@ function job() {
|
|
|
342
342
|
progress: state.running ? scanProgress(state.log, state.action) : null,
|
|
343
343
|
log: state.log.slice(-120),
|
|
344
344
|
recent: state.recent,
|
|
345
|
+
budget: state.running ? budgetNow() : null,
|
|
345
346
|
};
|
|
346
347
|
}
|
|
347
348
|
|
|
349
|
+
/** Today's LinkedIn budget, for the status bar every page shows while a scan runs. */
|
|
350
|
+
function budgetNow() {
|
|
351
|
+
try {
|
|
352
|
+
const li = linkedinState(dataDir());
|
|
353
|
+
return {
|
|
354
|
+
searches: li.searchesToday ?? 0, cap: li.limits?.daily ?? null,
|
|
355
|
+
profiles: li.profilesToday ?? 0, profileCap: li.limits?.profiles ?? null,
|
|
356
|
+
};
|
|
357
|
+
} catch {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
348
362
|
/**
|
|
349
363
|
* Where Resume would carry on with one of your connections, for their profile
|
|
350
364
|
* card: { nextPage, pagesRead, legacy }, or null when there is nothing to carry
|
|
@@ -408,6 +422,8 @@ const ACTIONS = {
|
|
|
408
422
|
company: { flag: '--company', needsName: true, label: 'Scanning' },
|
|
409
423
|
// Photos an older version kept as links to LinkedIn: saved here, once each.
|
|
410
424
|
// No browser, no search; every scan does the same at its end.
|
|
425
|
+
// Experimental, for the Social tab: your messages list, once (who, when, unread; never text).
|
|
426
|
+
messages: { flag: '--messages', label: 'Reading your messages list' },
|
|
411
427
|
photos: { flag: '--save-photos', label: 'Saving profile photos to this computer' },
|
|
412
428
|
};
|
|
413
429
|
|
|
@@ -633,6 +649,9 @@ export async function POST(request) {
|
|
|
633
649
|
...(maxBridges && (action.startsWith('auto-bridge') || action === 'resume-all') ? [`--max-bridges=${maxBridges}`] : []),
|
|
634
650
|
...(tiers.length && action.startsWith('auto-bridge') ? [`--tiers=${tiers.join(',')}`] : []),
|
|
635
651
|
...(action.startsWith('auto-bridge') ? [`--order=${order}`] : []),
|
|
652
|
+
// Experimental Auto-Bridge (Scan page switch): all-day pacing and LinkedIn's
|
|
653
|
+
// own data read beside the page text (scripts/scrape.py EXPERIMENT).
|
|
654
|
+
...(body.experimental === true && action.startsWith('auto-bridge') ? ['--experimental'] : []),
|
|
636
655
|
// Resuming always reads to the end: a remembered "10 pages" would
|
|
637
656
|
// otherwise leave everyone paused at page 11 and do nothing.
|
|
638
657
|
...(readsCircles ? [`--max-pages=${action.startsWith('resume') ? 100 : maxPages}`] : []),
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, rmSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { dataDir } from '../../../lib/db-client';
|
|
4
|
+
import { resolveProfile } from '../../../lib/profile';
|
|
5
|
+
|
|
6
|
+
// The Social tab's saved findings (lib/linkedin-export.js): numbers and dates
|
|
7
|
+
// from your own LinkedIn export, one file per profile in the data folder. No
|
|
8
|
+
// message text ever reaches here. GET reads it, POST replaces it, DELETE
|
|
9
|
+
// forgets it.
|
|
10
|
+
|
|
11
|
+
function fileFor() {
|
|
12
|
+
const me = resolveProfile({ create: false });
|
|
13
|
+
if (!me?.id || !/^[\w-]+$/.test(String(me.id))) return null;
|
|
14
|
+
return path.join(dataDir(), `social-${me.id}.json`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function GET() {
|
|
18
|
+
const file = fileFor();
|
|
19
|
+
if (!file) return Response.json({ social: null });
|
|
20
|
+
try { return Response.json({ social: JSON.parse(readFileSync(file, 'utf8')) }); } catch { return Response.json({ social: null }); }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function POST(request) {
|
|
24
|
+
const file = fileFor();
|
|
25
|
+
if (!file) return Response.json({ error: 'Pick a profile first.' }, { status: 400 });
|
|
26
|
+
let body;
|
|
27
|
+
try { body = await request.json(); } catch { return Response.json({ error: 'That isn’t readable.' }, { status: 400 }); }
|
|
28
|
+
// Only the known fields, so nothing else rides along into the file.
|
|
29
|
+
let before = {};
|
|
30
|
+
try { before = JSON.parse(readFileSync(file, 'utf8')) || {}; } catch { /* none yet */ }
|
|
31
|
+
const clean = {
|
|
32
|
+
live: before.live || {},
|
|
33
|
+
liveAt: before.liveAt || null,
|
|
34
|
+
autoSync: before.autoSync === true,
|
|
35
|
+
importedAt: new Date().toISOString(),
|
|
36
|
+
asOf: Number(body?.asOf) || null,
|
|
37
|
+
people: body?.people && typeof body.people === 'object' ? body.people : {},
|
|
38
|
+
chapters: Array.isArray(body?.chapters) ? body.chapters : [],
|
|
39
|
+
posts: body?.posts && typeof body.posts === 'object' ? body.posts : null,
|
|
40
|
+
invites: body?.invites && typeof body.invites === 'object' ? body.invites : null,
|
|
41
|
+
emails: body?.emails === true,
|
|
42
|
+
};
|
|
43
|
+
for (const p of Object.values(clean.people)) {
|
|
44
|
+
if (p && typeof p === 'object') {
|
|
45
|
+
for (const k of Object.keys(p)) if (!['last', 'lastFromThem', 'total', 'recent', 'email'].includes(k)) delete p[k];
|
|
46
|
+
if (!clean.emails) delete p.email;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
50
|
+
writeFileSync(tmp, JSON.stringify(clean));
|
|
51
|
+
renameSync(tmp, file);
|
|
52
|
+
return Response.json({ ok: true, people: Object.keys(clean.people).length });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// From the scanner's experimental messages sync (scripts/scrape.py sync_messages):
|
|
56
|
+
// per person, when your 1:1 conversation was last active and unread count.
|
|
57
|
+
// Merged in beside what the export gave, kept under `live`.
|
|
58
|
+
export async function PUT(request) {
|
|
59
|
+
const file = fileFor();
|
|
60
|
+
if (!file) return Response.json({ error: 'Pick a profile first.' }, { status: 400 });
|
|
61
|
+
let body;
|
|
62
|
+
try { body = await request.json(); } catch { return Response.json({ error: 'That isn’t readable.' }, { status: 400 }); }
|
|
63
|
+
let saved = {};
|
|
64
|
+
try { saved = JSON.parse(readFileSync(file, 'utf8')) || {}; } catch { /* first sync */ }
|
|
65
|
+
const live = {};
|
|
66
|
+
for (const [url, v] of Object.entries(body?.live || {})) {
|
|
67
|
+
if (typeof url !== 'string' || !url.includes('/in/') || !v || typeof v !== 'object') continue;
|
|
68
|
+
live[url] = { last: Number(v.last) || null, unread: Number.isFinite(Number(v.unread)) ? Number(v.unread) : null };
|
|
69
|
+
}
|
|
70
|
+
const next = { ...saved, live, liveAt: new Date().toISOString() };
|
|
71
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
72
|
+
writeFileSync(tmp, JSON.stringify(next));
|
|
73
|
+
renameSync(tmp, file);
|
|
74
|
+
return Response.json({ ok: true, people: Object.keys(live).length });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The Social tab's "once a day" switch for the live messages sync.
|
|
78
|
+
export async function PATCH(request) {
|
|
79
|
+
const file = fileFor();
|
|
80
|
+
if (!file) return Response.json({ error: 'Pick a profile first.' }, { status: 400 });
|
|
81
|
+
let body = {};
|
|
82
|
+
try { body = await request.json(); } catch { /* nothing to change */ }
|
|
83
|
+
let saved = {};
|
|
84
|
+
try { saved = JSON.parse(readFileSync(file, 'utf8')) || {}; } catch { /* none yet */ }
|
|
85
|
+
const next = { ...saved, autoSync: body?.autoSync === true };
|
|
86
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
87
|
+
writeFileSync(tmp, JSON.stringify(next));
|
|
88
|
+
renameSync(tmp, file);
|
|
89
|
+
return Response.json({ ok: true, autoSync: next.autoSync });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function DELETE() {
|
|
93
|
+
const file = fileFor();
|
|
94
|
+
if (file) rmSync(file, { force: true });
|
|
95
|
+
return Response.json({ ok: true });
|
|
96
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// "Auto scan" in the header, beside Scan, while the Scan page's experimental
|
|
4
|
+
// all-day switch is on: starts Auto-Bridge in all-day mode (lib/experimental-client.js).
|
|
5
|
+
// Unlit until it runs; lit while it does, and then it opens the Scan page.
|
|
6
|
+
|
|
7
|
+
import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
8
|
+
import Link from 'next/link';
|
|
9
|
+
import { watchScanner, scannerNow } from '../../lib/scraper-client';
|
|
10
|
+
import { watchAllDay, allDayNow, startAutoScan } from '../../lib/experimental-client';
|
|
11
|
+
|
|
12
|
+
export default function AutoScanButton({ isMobile = false }) {
|
|
13
|
+
const on = useSyncExternalStore(watchAllDay, allDayNow, () => false);
|
|
14
|
+
const [job, setJob] = useState(() => scannerNow());
|
|
15
|
+
const [starting, setStarting] = useState(false);
|
|
16
|
+
useEffect(() => watchScanner(() => { setJob(scannerNow()); setStarting(false); }), []);
|
|
17
|
+
if (!on) return null;
|
|
18
|
+
const mine = job?.running && String(job.action || '').startsWith('auto-bridge');
|
|
19
|
+
const style = {
|
|
20
|
+
padding: isMobile ? '8px 12px' : '8px 16px', borderRadius: 6, fontSize: 13, fontWeight: 600, textDecoration: 'none',
|
|
21
|
+
display: 'flex', alignItems: 'center', gap: 6, whiteSpace: 'nowrap',
|
|
22
|
+
};
|
|
23
|
+
if (mine) {
|
|
24
|
+
return (
|
|
25
|
+
<Link href="/setup" title="Auto scan is running: see it on the Scan page" style={{ ...style, background: 'rgba(0,255,136,0.15)', color: '#00ff88', border: '1px solid rgba(0,255,136,0.45)' }}>
|
|
26
|
+
<span style={{ width: 7, height: 7, borderRadius: '50%', background: '#00ff88' }} />Auto scan
|
|
27
|
+
</Link>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const busy = job?.running || starting;
|
|
31
|
+
return (
|
|
32
|
+
<button
|
|
33
|
+
onClick={() => { setStarting(true); startAutoScan().catch(() => setStarting(false)); }}
|
|
34
|
+
disabled={busy}
|
|
35
|
+
title={busy ? 'The scanner is busy: one scan at a time' : 'Start the all-day Auto-Bridge (experimental)'}
|
|
36
|
+
style={{ ...style, cursor: busy ? 'default' : 'pointer', background: 'rgba(255,255,255,0.04)', color: busy ? '#555' : '#8b9a9a', border: '1px solid rgba(255,215,0,0.25)' }}
|
|
37
|
+
>
|
|
38
|
+
<span style={{ width: 7, height: 7, borderRadius: '50%', background: '#556' }} />Auto scan
|
|
39
|
+
</button>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -110,6 +110,13 @@ export default function ChainView({ connections, degree2 = [], onSelect, userNam
|
|
|
110
110
|
// The circles opened, outermost last: [bridge id, person id, …]; [] is the overview.
|
|
111
111
|
const [path, setPath] = useState(() => trailTo(chainOpen, all1));
|
|
112
112
|
// A link is followed once: coming back to this view later starts from the overview.
|
|
113
|
+
// One asked for while this view is already showing (a card's Insights) opens too.
|
|
114
|
+
const [openedFor, setOpenedFor] = useState(chainOpen);
|
|
115
|
+
if (chainOpen && chainOpen !== openedFor) {
|
|
116
|
+
setOpenedFor(chainOpen);
|
|
117
|
+
const trail = trailTo(chainOpen, all1);
|
|
118
|
+
if (trail.length) setPath(trail);
|
|
119
|
+
}
|
|
113
120
|
useEffect(() => {
|
|
114
121
|
if (chainOpen) onChainOpened?.();
|
|
115
122
|
}, [chainOpen, onChainOpened]);
|
|
@@ -12,9 +12,12 @@ function useIsMobile() {
|
|
|
12
12
|
const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
export default function FilterPanel({ collapsed, onToggle, mode, filter, onFilterChange, visualMode, onVisualModeChange, tierCounts, bridgeTierCounts, degrees = [1], onDegreesChange, degreeCounts = {} }) {
|
|
15
|
+
export default function FilterPanel({ collapsed, onToggle, mode, filter, onFilterChange, visualMode, onVisualModeChange, tierCounts, bridgeTierCounts, degrees = [1], onDegreesChange, degreeCounts = {}, hiddenTiers = [], onHiddenTiersChange }) {
|
|
16
16
|
const isMobile = useIsMobile();
|
|
17
17
|
const isDegreesMode = mode === 'degrees';
|
|
18
|
+
// Network Circle: each tier switches on and off, so the noisy ones (C, D) can go
|
|
19
|
+
// while the rest stay. Degrees keeps one tier at a time.
|
|
20
|
+
const toggles = !isDegreesMode && !!onHiddenTiersChange;
|
|
18
21
|
// Same source of truth the renderer uses, so the menu can never offer a
|
|
19
22
|
// view that does not exist or miss one that does.
|
|
20
23
|
const modes = viewsForMode(isDegreesMode ? 'degrees' : 'network');
|
|
@@ -151,19 +154,48 @@ export default function FilterPanel({ collapsed, onToggle, mode, filter, onFilte
|
|
|
151
154
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
152
155
|
{/* All button */}
|
|
153
156
|
<button
|
|
154
|
-
onClick={() => onFilterChange && onFilterChange('all')}
|
|
157
|
+
onClick={() => (toggles ? onHiddenTiersChange([]) : onFilterChange && onFilterChange('all'))}
|
|
155
158
|
style={{
|
|
156
159
|
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
|
157
160
|
padding: '7px 10px', borderRadius: 6, border: 'none', cursor: 'pointer', width: '100%',
|
|
158
|
-
background: filter === 'all' ? 'rgba(255,255,255,0.12)' : 'rgba(255,255,255,0.03)',
|
|
159
|
-
color: filter === 'all' ? '#fff' : '#888',
|
|
161
|
+
background: (toggles ? !hiddenTiers.length : filter === 'all') ? 'rgba(255,255,255,0.12)' : 'rgba(255,255,255,0.03)',
|
|
162
|
+
color: (toggles ? !hiddenTiers.length : filter === 'all') ? '#fff' : '#888',
|
|
160
163
|
}}
|
|
161
164
|
>
|
|
162
165
|
<span style={{ fontSize: 11, fontWeight: 600 }}>All</span>
|
|
163
166
|
<span style={{ fontSize: 10, color: '#555' }}>{allCount}</span>
|
|
164
167
|
</button>
|
|
165
168
|
{/* Tier buttons */}
|
|
166
|
-
{
|
|
169
|
+
{toggles && (
|
|
170
|
+
<div style={{ fontSize: 10, color: '#667', margin: '2px 2px 4px' }}>Click a tier to hide or show it</div>
|
|
171
|
+
)}
|
|
172
|
+
{toggles && ['S', 'A', 'B', 'C', 'D'].map(t => {
|
|
173
|
+
const on = !hiddenTiers.includes(t);
|
|
174
|
+
const last = on && hiddenTiers.length >= 4;
|
|
175
|
+
return (
|
|
176
|
+
<button
|
|
177
|
+
key={t}
|
|
178
|
+
aria-pressed={on}
|
|
179
|
+
title={last ? 'Keep at least one tier showing' : on ? `Hide ${t}-Tier` : `Show ${t}-Tier`}
|
|
180
|
+
onClick={() => !last && onHiddenTiersChange(on ? [...hiddenTiers, t] : hiddenTiers.filter(x => x !== t))}
|
|
181
|
+
style={{
|
|
182
|
+
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
|
183
|
+
padding: '7px 10px', borderRadius: 6, border: 'none', cursor: last ? 'default' : 'pointer', width: '100%',
|
|
184
|
+
background: on ? `${TIER_COLORS[t]}14` : 'rgba(255,255,255,0.02)',
|
|
185
|
+
color: on ? TIER_COLORS[t] : '#555',
|
|
186
|
+
borderLeft: on ? `3px solid ${TIER_COLORS[t]}` : '3px solid transparent',
|
|
187
|
+
}}
|
|
188
|
+
>
|
|
189
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
|
190
|
+
<div style={{ width: 8, height: 8, borderRadius: '50%', background: TIER_COLORS[t], opacity: on ? 1 : 0.2 }} />
|
|
191
|
+
<span style={{ fontSize: 11, fontWeight: 600, textDecoration: on ? 'none' : 'line-through' }}>{t}-Tier</span>
|
|
192
|
+
{!on && <span style={{ fontSize: 9.5, color: '#667' }}>hidden</span>}
|
|
193
|
+
</div>
|
|
194
|
+
<span style={{ fontSize: 10, color: '#555' }}>{counts[t] || 0}</span>
|
|
195
|
+
</button>
|
|
196
|
+
);
|
|
197
|
+
})}
|
|
198
|
+
{!toggles && ['S', 'A', 'B', 'C', 'D'].map(t => (
|
|
167
199
|
<button
|
|
168
200
|
key={t}
|
|
169
201
|
onClick={() => onFilterChange && onFilterChange(t)}
|
|
@@ -295,11 +295,24 @@ const OrbitGraph = forwardRef(function OrbitGraph(
|
|
|
295
295
|
placed += row.length;
|
|
296
296
|
r += step;
|
|
297
297
|
}
|
|
298
|
+
// Their people go behind this fan, centred on it (not on wherever the
|
|
299
|
+
// person they came through sits), side by side in the order those people
|
|
300
|
+
// sit, so no fan spills into the next one's space; a line runs back to
|
|
301
|
+
// each. Wider than the wedge, they close up to fit it.
|
|
298
302
|
let edge = r;
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
+
const next = subs.filter(({ d }) => depth < 6 && reachOf(d)).sort((x, y) => x.a - y.a);
|
|
304
|
+
if (next.length) {
|
|
305
|
+
const from = r + 24;
|
|
306
|
+
const gap = 10 / from;
|
|
307
|
+
const want = next.map(({ d }) => Math.max(0.12, (Math.min(reachOf(d), 60) * 8) / from));
|
|
308
|
+
const need = want.reduce((sum, w) => sum + w, 0) + gap * (next.length - 1);
|
|
309
|
+
const scale = need > wedge ? wedge / need : 1;
|
|
310
|
+
let at = angle - (need * scale) / 2;
|
|
311
|
+
next.forEach(({ d }, k) => {
|
|
312
|
+
const w = want[k] * scale;
|
|
313
|
+
edge = Math.max(edge, placeFan(d, at + w / 2, w, from, depth + 1));
|
|
314
|
+
at += w + gap * scale;
|
|
315
|
+
});
|
|
303
316
|
}
|
|
304
317
|
return edge;
|
|
305
318
|
};
|