six-degrees 0.6.0 β 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +4 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +42 -14
- package/.next/standalone/.next/routes-manifest.json +24 -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 +26 -18
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +26 -18
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +25 -16
- 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 +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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +3 -3
- 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 +3 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/backup/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/backup/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/backup/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/backup/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/backup/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/backup/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/csv/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/csv/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/csv/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/csv/route.js +8 -0
- package/.next/standalone/.next/server/app/api/data/csv/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/csv/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/export/route.js +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 +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 +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/restore/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/restore/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/restore/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/restore/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/restore/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/restore/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route.js +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 +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 +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js +2 -2
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js +2 -2
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js +5 -3
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js +3 -3
- 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 +3 -3
- 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 +3 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route.js +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/messages/route.js +1 -1
- package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js +2 -2
- package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js +2 -2
- 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 +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js +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 +32 -24
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +32 -24
- 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 +23 -18
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +29 -22
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +20 -15
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +29 -22
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/insights/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/insights/page/build-manifest.json +20 -0
- package/.next/standalone/.next/server/app/insights/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/insights/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/insights/page.js +13 -0
- package/.next/standalone/.next/server/app/insights/page.js.map +5 -0
- package/.next/standalone/.next/server/app/insights/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/insights/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/insights.html +1 -0
- package/.next/standalone/.next/server/app/insights.meta +26 -0
- package/.next/standalone/.next/server/app/insights.rsc +35 -0
- package/.next/standalone/.next/server/app/insights.segments/_full.segment.rsc +35 -0
- package/.next/standalone/.next/server/app/insights.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/insights.segments/insights/__PAGE__.segment.rsc +33 -0
- 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 +32 -24
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +32 -24
- 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 +23 -18
- 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 +32 -24
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +32 -24
- 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 +21 -18
- 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 +32 -24
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +32 -24
- 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 +23 -18
- 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 +32 -24
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +32 -24
- 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 +21 -18
- 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 +32 -24
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +32 -24
- 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 +23 -18
- 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 +32 -24
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +32 -24
- 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 +20 -18
- 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 +32 -24
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +32 -24
- 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 +21 -18
- package/.next/standalone/.next/server/app/social/page.js +1 -1
- package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/social.html +1 -1
- package/.next/standalone/.next/server/app/social.rsc +32 -24
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +23 -18
- package/.next/standalone/.next/server/app-paths-manifest.json +4 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05_3-22._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__066rab1._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fooke1._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__15wc9e-._.js β [root-of-the-server]__0r-0t-9._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ra6xyg._.js +15 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20rwfdw._.js β [root-of-the-server]__0rcpjad._.js} +6 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t6y79e._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x29muh._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a_6x37._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an_8pa._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ducpz2._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xhyinn._.js +3 -0
- package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0sqqpzb._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
- package/.next/standalone/.next/server/chunks/_1fn30_l._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_backup_route_actions_0zoj04p.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_csv_route_actions_0l6m7lg.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restore_route_actions_0-b05bv.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +4 -0
- package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +4 -0
- package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +4 -0
- package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +174 -0
- package/.next/standalone/.next/server/chunks/lib_linkedin-export_12imqxg.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_00nndai.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_03ibb-x.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_03ri3ji.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_078ce48.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +7 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0cej3t8.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0cmh4g6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0nx2_pc.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0r79-w1.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0t552z6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0yx8ynd.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_12p-o9-.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1466dnb.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1sryxv6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1trn-x5.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1ygu_mv.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egamyq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qd8pzm._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0qdeuyo._.js β [root-of-the-server]__1-012q1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_04am_h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_06rgzfh._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0hb-dhy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_14jak5s._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1r62six._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_insights_page_actions_0-0tf75.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +25 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +25 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_CompanyScores_1g0mytz.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_settings_SectorPicker_1c-29qw.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +26 -14
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +11 -11
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +12 -13
- package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_1c4ieuw._.js β lib_csv_1ttiu_h.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_separation_1305zsx.js +3 -0
- package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +1 -1
- 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/02wnf8dkxegxg.js +34 -0
- package/.next/standalone/.next/static/chunks/03-_esd2x_yk6.js +1 -0
- package/.next/standalone/.next/static/chunks/03-demj2iy-0p.js +44 -0
- package/.next/standalone/.next/static/chunks/0838_s6w-i_ik.js +1 -0
- package/.next/standalone/.next/static/chunks/0_1r-3csplxnj.js +1 -0
- package/.next/standalone/.next/static/chunks/0ka4prpk3w9wn.js +34 -0
- package/.next/standalone/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
- package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/standalone/.next/static/chunks/112mv-com-mqa.js +21 -0
- package/.next/standalone/.next/static/chunks/1bkt_hhjzvbh8.js +1 -0
- package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/standalone/.next/static/chunks/1d8yv3k_atka7.js +1 -0
- package/.next/standalone/.next/static/chunks/{0ws7zy0w57ufi.js β 1eyajb9ntzlrl.js} +1 -1
- package/.next/standalone/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
- package/.next/standalone/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/standalone/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/standalone/.next/static/chunks/2q9i7pcxcnph1.js +7 -0
- package/.next/standalone/.next/static/chunks/2w-y83mjlpnse.js +1 -0
- package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -0
- package/.next/standalone/.next/static/chunks/2z1-q0_vunbql.js +2 -0
- package/.next/standalone/.next/static/chunks/34g73qhayuevu.js +1 -0
- package/.next/standalone/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
- package/.next/standalone/.next/static/chunks/3opgg1efrx8q6.js +1 -0
- package/.next/standalone/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
- package/.next/standalone/.next/static/chunks/3y40z6of3r9py.js +1 -0
- package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/.next/standalone/.next/static/chunks/43pg2sursiypz.js +1 -0
- package/.next/standalone/CHANGELOG.md +203 -0
- package/.next/standalone/README.md +96 -50
- package/.next/standalone/SECURITY.md +25 -11
- package/.next/standalone/app/api/data/backup/route.js +25 -0
- package/.next/standalone/app/api/data/csv/route.js +74 -0
- package/.next/standalone/app/api/data/export/route.js +1 -1
- package/.next/standalone/app/api/data/restore/route.js +48 -0
- package/.next/standalone/app/api/data/reveal/route.js +19 -6
- package/.next/standalone/app/api/data/route.js +15 -4
- package/.next/standalone/app/api/ingest/route.js +1 -1
- package/.next/standalone/app/api/outreach/route.js +13 -73
- package/.next/standalone/app/api/queue/route.js +1 -1
- package/.next/standalone/app/api/scraper/route.js +217 -36
- package/.next/standalone/app/api/social/crm/route.js +2 -1
- package/.next/standalone/app/components/AppHeader.js +41 -21
- package/.next/standalone/app/components/AppTabs.js +12 -8
- package/.next/standalone/app/components/AutoConnect.js +286 -0
- package/.next/standalone/app/components/AutoScanButton.js +2 -2
- package/.next/standalone/app/components/Avatar.js +1 -1
- package/.next/standalone/app/components/ChainView.js +258 -113
- package/.next/standalone/app/components/CirclePanel.js +16 -16
- package/.next/standalone/app/components/ClusterSpinner.js +64 -0
- package/.next/standalone/app/components/CompanyScores.js +20 -20
- package/.next/standalone/app/components/EmptyState.js +39 -18
- package/.next/standalone/app/components/FieldStep.js +15 -13
- package/.next/standalone/app/components/FilterPanel.js +25 -18
- package/.next/standalone/app/components/ForceGraph.js +49 -14
- package/.next/standalone/app/components/GalaxyLab.js +33 -33
- package/.next/standalone/app/components/GridView.js +18 -18
- package/.next/standalone/app/components/LegacyScoresCard.js +10 -11
- package/.next/standalone/app/components/LinkedInLimits.js +57 -27
- package/.next/standalone/app/components/LiquidGlass.js +99 -0
- package/.next/standalone/app/components/ListView.js +20 -20
- package/.next/standalone/app/components/MapControls.js +5 -5
- package/.next/standalone/app/components/MappingProgress.js +16 -16
- package/.next/standalone/app/components/NoteDetail.js +13 -13
- package/.next/standalone/app/components/OnboardingGate.js +4 -4
- package/.next/standalone/app/components/OutlinkQuest.js +56 -35
- package/.next/standalone/app/components/PathsAnalyzer.js +37 -36
- package/.next/standalone/app/components/PeopleMap.js +21 -21
- package/.next/standalone/app/components/RingsView.js +11 -11
- package/.next/standalone/app/components/ScanRadar.js +84 -39
- package/.next/standalone/app/components/ScanStatusBar.js +40 -21
- package/.next/standalone/app/components/ScanTrail.js +21 -8
- package/.next/standalone/app/components/SeparationView.js +172 -124
- package/.next/standalone/app/components/Sidebar.js +308 -199
- package/.next/standalone/app/components/StaleServerBanner.js +4 -4
- package/.next/standalone/app/components/TheirCircle.js +26 -26
- package/.next/standalone/app/components/ThemeDefs.js +42 -0
- package/.next/standalone/app/components/ThemeLoader.js +20 -1
- package/.next/standalone/app/components/UpdatePanel.js +22 -22
- package/.next/standalone/app/components/UserProvider.js +22 -15
- package/.next/standalone/app/components/insights/Boards.js +275 -0
- package/.next/standalone/app/components/insights/PeopleView.js +266 -0
- package/.next/standalone/app/components/insights/Rail.js +156 -0
- package/.next/standalone/app/components/insights/Report.js +382 -0
- package/.next/standalone/app/components/insights/parts.js +239 -0
- package/.next/standalone/app/components/settings/AppearanceSection.js +47 -24
- package/.next/standalone/app/components/settings/DataSection.js +276 -109
- package/.next/standalone/app/components/settings/NetworkHealthSection.js +13 -13
- package/.next/standalone/app/components/settings/SectorPicker.js +12 -12
- package/.next/standalone/app/components/settings/SectorSection.js +13 -14
- package/.next/standalone/app/components/settings/TierSection.js +9 -9
- package/.next/standalone/app/components/settings/TitleSection.js +11 -11
- package/.next/standalone/app/components/settings/UsageSection.js +360 -0
- package/.next/standalone/app/components/ui.js +8 -8
- package/.next/standalone/app/globals.css +161 -5
- package/.next/standalone/app/import/page.js +94 -38
- package/.next/standalone/app/insights/page.js +220 -0
- package/.next/standalone/app/launch/page.js +5 -5
- package/.next/standalone/app/layout.js +6 -2
- package/.next/standalone/app/page.js +53 -53
- package/.next/standalone/app/paths/page.js +63 -63
- package/.next/standalone/app/profile/page.js +58 -58
- package/.next/standalone/app/queue/page.js +84 -72
- package/.next/standalone/app/scores/page.js +2 -2
- package/.next/standalone/app/settings/page.js +16 -13
- package/.next/standalone/app/setup/page.js +236 -133
- package/.next/standalone/app/social/Crm.js +63 -62
- package/.next/standalone/app/social/SocialHub.js +22 -22
- package/.next/standalone/app/social/Thread.js +7 -7
- package/.next/standalone/app/social/page.js +2 -2
- package/.next/standalone/lib/auto-connect.js +145 -0
- package/.next/standalone/lib/backups.js +458 -0
- package/.next/standalone/lib/chain-layout.js +32 -0
- package/.next/standalone/lib/companies.js +1 -1
- package/.next/standalone/lib/csv-store.js +131 -0
- package/.next/standalone/lib/csv.js +137 -39
- package/.next/standalone/lib/data-folder.js +19 -3
- package/.next/standalone/lib/data-import.js +5 -2
- package/.next/standalone/lib/db-client.js +78 -20
- package/.next/standalone/lib/demo.js +5 -4
- package/.next/standalone/lib/galaxy-export.js +9 -2
- package/.next/standalone/lib/galaxy-lab.js +19 -5
- package/.next/standalone/lib/galaxy-layouts.js +43 -0
- package/.next/standalone/lib/gate.js +10 -4
- package/.next/standalone/lib/in-progress.js +46 -0
- package/.next/standalone/lib/ingest.js +1 -1
- package/.next/standalone/lib/insights-board.js +613 -0
- package/.next/standalone/lib/linkedin-limits.js +240 -14
- package/.next/standalone/lib/liquid-glass.js +59 -0
- package/.next/standalone/lib/notifications.js +13 -0
- package/.next/standalone/lib/requests-client.js +10 -0
- package/.next/standalone/lib/requests.js +124 -0
- package/.next/standalone/lib/scan-pace.js +11 -0
- package/.next/standalone/lib/scan-progress.js +20 -0
- package/.next/standalone/lib/scan-risk.js +44 -0
- package/.next/standalone/lib/scan-state.js +1 -0
- package/.next/standalone/lib/scanner-setup.js +97 -15
- package/.next/standalone/lib/scraper-client.js +35 -8
- package/.next/standalone/lib/search-risk.js +7 -3
- package/.next/standalone/lib/settings-client.js +5 -3
- package/.next/standalone/lib/settings.js +13 -0
- package/.next/standalone/lib/social-store.js +3 -2
- package/.next/standalone/lib/synced-setting.js +46 -0
- package/.next/standalone/lib/theme-store.js +42 -10
- package/.next/standalone/lib/themes.js +111 -21
- package/.next/standalone/lib/usage.js +200 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +595 -11
- package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
- package/.next/static/chunks/03-_esd2x_yk6.js +1 -0
- package/.next/static/chunks/03-demj2iy-0p.js +44 -0
- package/.next/static/chunks/0838_s6w-i_ik.js +1 -0
- package/.next/static/chunks/0_1r-3csplxnj.js +1 -0
- package/.next/static/chunks/0ka4prpk3w9wn.js +34 -0
- package/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
- package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/static/chunks/112mv-com-mqa.js +21 -0
- package/.next/static/chunks/1bkt_hhjzvbh8.js +1 -0
- package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/static/chunks/1d8yv3k_atka7.js +1 -0
- package/.next/static/chunks/{0ws7zy0w57ufi.js β 1eyajb9ntzlrl.js} +1 -1
- package/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
- package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/static/chunks/2q9i7pcxcnph1.js +7 -0
- package/.next/static/chunks/2w-y83mjlpnse.js +1 -0
- package/.next/static/chunks/2ws1xf293j-tm.js +5 -0
- package/.next/static/chunks/2z1-q0_vunbql.js +2 -0
- package/.next/static/chunks/34g73qhayuevu.js +1 -0
- package/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
- package/.next/static/chunks/3opgg1efrx8q6.js +1 -0
- package/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
- package/.next/static/chunks/3y40z6of3r9py.js +1 -0
- package/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/.next/static/chunks/43pg2sursiypz.js +1 -0
- package/CHANGELOG.md +203 -0
- package/README.md +96 -50
- package/SECURITY.md +25 -11
- package/lib/auto-connect.js +145 -0
- package/lib/backups.js +458 -0
- package/lib/chain-layout.js +32 -0
- package/lib/companies.js +1 -1
- package/lib/csv-store.js +131 -0
- package/lib/csv.js +137 -39
- package/lib/data-folder.js +19 -3
- package/lib/data-import.js +5 -2
- package/lib/db-client.js +78 -20
- package/lib/demo.js +5 -4
- package/lib/galaxy-export.js +9 -2
- package/lib/galaxy-lab.js +19 -5
- package/lib/galaxy-layouts.js +43 -0
- package/lib/gate.js +10 -4
- package/lib/in-progress.js +46 -0
- package/lib/ingest.js +1 -1
- package/lib/insights-board.js +613 -0
- package/lib/linkedin-limits.js +240 -14
- package/lib/liquid-glass.js +59 -0
- package/lib/notifications.js +13 -0
- package/lib/requests-client.js +10 -0
- package/lib/requests.js +124 -0
- package/lib/scan-pace.js +11 -0
- package/lib/scan-progress.js +20 -0
- package/lib/scan-risk.js +44 -0
- package/lib/scan-state.js +1 -0
- package/lib/scanner-setup.js +97 -15
- package/lib/scraper-client.js +35 -8
- package/lib/search-risk.js +7 -3
- package/lib/settings-client.js +5 -3
- package/lib/settings.js +13 -0
- package/lib/social-store.js +3 -2
- package/lib/synced-setting.js +46 -0
- package/lib/theme-store.js +42 -10
- package/lib/themes.js +111 -21
- package/lib/usage.js +200 -0
- package/package.json +1 -1
- package/scripts/scrape.py +595 -11
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13dx4sd._.js +0 -8
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +0 -3
- package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
- package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +0 -174
- package/.next/standalone/.next/server/chunks/lib_rpc_04s8mzr.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_053z7as.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0b_-2te.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0dhbxdm.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0dxlk31.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0f8b-qc.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0pzie7_.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0r76fq_.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0ut7pjp.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_15zyqaz.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_18zpjtq.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1a8xkiz.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1e_55xo.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1oxfd1_.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1s0lod0.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08oxiqh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_08g31gm._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0gk_ofx._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0nwsf93._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0vho1lb._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1-658fq._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1bc46kz._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_2105jz8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
- package/.next/standalone/.next/static/chunks/02pq76u7y4v9-.js +0 -22
- package/.next/standalone/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
- package/.next/standalone/.next/static/chunks/0i02yxppzds1o.js +0 -1
- package/.next/standalone/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
- package/.next/standalone/.next/static/chunks/0oyslj62jkubd.js +0 -1
- package/.next/standalone/.next/static/chunks/0vo-l8hxneba6.css +0 -3
- package/.next/standalone/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
- package/.next/standalone/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
- package/.next/standalone/.next/static/chunks/172e10mi-tpo_.js +0 -34
- package/.next/standalone/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
- package/.next/standalone/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
- package/.next/standalone/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
- package/.next/standalone/.next/static/chunks/1m3017gp790pw.js +0 -45
- package/.next/standalone/.next/static/chunks/1t20e8u0st7ep.js +0 -1
- package/.next/standalone/.next/static/chunks/2-ch9rm27eril.js +0 -11
- package/.next/standalone/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
- package/.next/standalone/.next/static/chunks/3bp284gjf7dyq.js +0 -1
- package/.next/standalone/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
- package/.next/standalone/.next/static/chunks/3l4t8je6iguzc.js +0 -1
- package/.next/standalone/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
- package/.next/standalone/.next/static/chunks/42m0bqr8pbovz.js +0 -11
- package/.next/static/chunks/02pq76u7y4v9-.js +0 -22
- package/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
- package/.next/static/chunks/0i02yxppzds1o.js +0 -1
- package/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
- package/.next/static/chunks/0oyslj62jkubd.js +0 -1
- package/.next/static/chunks/0vo-l8hxneba6.css +0 -3
- package/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
- package/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
- package/.next/static/chunks/172e10mi-tpo_.js +0 -34
- package/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
- package/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
- package/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
- package/.next/static/chunks/1m3017gp790pw.js +0 -45
- package/.next/static/chunks/1t20e8u0st7ep.js +0 -1
- package/.next/static/chunks/2-ch9rm27eril.js +0 -11
- package/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
- package/.next/static/chunks/3bp284gjf7dyq.js +0 -1
- package/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
- package/.next/static/chunks/3l4t8je6iguzc.js +0 -1
- package/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
- package/.next/static/chunks/42m0bqr8pbovz.js +0 -11
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT β 3NCyJyAPDCEYsYTwF1Ieu}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT β 3NCyJyAPDCEYsYTwF1Ieu}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT β 3NCyJyAPDCEYsYTwF1Ieu}/_ssgManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT β 3NCyJyAPDCEYsYTwF1Ieu}/_buildManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT β 3NCyJyAPDCEYsYTwF1Ieu}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT β 3NCyJyAPDCEYsYTwF1Ieu}/_ssgManifest.js +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useMemo, useCallback } from 'react';
|
|
3
|
+
import { useState, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';
|
|
4
4
|
import Link from 'next/link';
|
|
5
|
-
import { beginScrape, scraperStatus, notReadyMessage, resumePoint, scansCircleOf, isCircleScan, busyReason } from '../../lib/scraper-client';
|
|
5
|
+
import { beginScrape, scraperStatus, notReadyMessage, resumePoint, scansCircleOf, isCircleScan, busyReason, watchScanner, scannerNow } from '../../lib/scraper-client';
|
|
6
|
+
import { scanBoxTitle, stoppedLine } from '../../lib/in-progress';
|
|
6
7
|
import useScanner from './useScanner';
|
|
7
8
|
import useRequests from './useRequests';
|
|
8
9
|
import TheirCircle from './TheirCircle';
|
|
@@ -17,6 +18,7 @@ import Avatar from './Avatar';
|
|
|
17
18
|
import NoteDetail from './NoteDetail';
|
|
18
19
|
import CirclePanel from './CirclePanel';
|
|
19
20
|
import { localPhoto } from '../../lib/photos';
|
|
21
|
+
import ConnectChoice, { secondaryLook } from './AutoConnect';
|
|
20
22
|
|
|
21
23
|
export default function Sidebar({ selected, stats, tierColors, connections, degree2 = [], mode, collapsed, filter, pending = [], onToggle, onSelect, onSwitchMode, onFocusNode, onMarkSent, onUndoPending, scanNotes, csvSource = null, onOpenCircle, onShowInSeparation, note = null, onCloseNote, circle = null }) {
|
|
22
24
|
const isDegreesMode = mode === 'degrees';
|
|
@@ -54,6 +56,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
54
56
|
// Separation, the circle and the Outlink queue at once (lib/requests-client.js).
|
|
55
57
|
const requests = useRequests();
|
|
56
58
|
const isRequested = useCallback((row) => hasRequest(row, requests), [requests]);
|
|
59
|
+
// Where Resume would carry on with the person open, asked once for the whole
|
|
60
|
+
// card: the line by their name and the scan box below both show it. Only for
|
|
61
|
+
// whoever gets a scan box (the same test as below). Above the early returns,
|
|
62
|
+
// so the hook order never changes.
|
|
63
|
+
const scansHere = Boolean(selected) && canScan && (selected.degree === 1 || selected.outreach_status === 'accepted');
|
|
64
|
+
const { resume, scanning: scanningThem } = useResume(scansHere ? selected : null);
|
|
57
65
|
|
|
58
66
|
// A notification someone clicked takes the panel over until they go back (app/components/NoteDetail.js).
|
|
59
67
|
if (note) {
|
|
@@ -82,12 +90,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
82
90
|
onClick={() => onSelect && onSelect(null)}
|
|
83
91
|
style={{
|
|
84
92
|
display: 'flex', alignItems: 'center', gap: 6, background: 'none', border: 'none',
|
|
85
|
-
color: '#888', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
|
|
93
|
+
color: 'var(--sd-fg-3, #888)', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
|
|
86
94
|
}}
|
|
87
95
|
>
|
|
88
96
|
<span style={{ fontSize: 16 }}>←</span> Back to list
|
|
89
97
|
</button>
|
|
90
|
-
<div style={{ fontSize: 10, color: '#888', marginBottom: 8, letterSpacing: 1, textTransform: 'uppercase' }}>
|
|
98
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 8, letterSpacing: 1, textTransform: 'uppercase' }}>
|
|
91
99
|
{selected.degree === 2 ? 'Degree 2 Connection' : 'Degree 1 Connection'}
|
|
92
100
|
</div>
|
|
93
101
|
<div style={{ display: 'flex', gap: 6, marginBottom: 8, flexWrap: 'wrap' }}>
|
|
@@ -108,7 +116,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
108
116
|
fontSize: 11.5, color: '#8fb8d6', lineHeight: 1.5,
|
|
109
117
|
}}>
|
|
110
118
|
{selected.degree === 1 ? 'You met them through ' : 'Reachable through '}
|
|
111
|
-
<b style={{ color: '#cfe6f7' }}>{selected.unlocked_from_name}</b>
|
|
119
|
+
<b style={{ color: 'var(--sd-fg-1, #cfe6f7)' }}>{selected.unlocked_from_name}</b>
|
|
112
120
|
</div>
|
|
113
121
|
)}
|
|
114
122
|
|
|
@@ -136,13 +144,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
136
144
|
background: tierColors[selected.tier] || '#555',
|
|
137
145
|
display: localPhoto(selected.profile_image_url) ? 'none' : 'flex',
|
|
138
146
|
alignItems: 'center', justifyContent: 'center',
|
|
139
|
-
fontSize: 20, fontWeight: 700, color: selected.tier === 'S' ? '#000' : '#fff',
|
|
147
|
+
fontSize: 20, fontWeight: 700, color: selected.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
140
148
|
}}>
|
|
141
149
|
{selected.name?.charAt(0)}
|
|
142
150
|
</div>
|
|
143
151
|
<div style={{ minWidth: 0 }}>
|
|
144
152
|
<h2 style={{ fontSize: 18, fontWeight: 700, margin: 0 }}>{selected.name}</h2>
|
|
145
|
-
<p style={{ color: '#aaa', fontSize: 11, margin: '3px 0 0', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.headline?.substring(0, 60)}</p>
|
|
153
|
+
<p style={{ color: 'var(--sd-fg-3, #aaa)', fontSize: 11, margin: '3px 0 0', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.headline?.substring(0, 60)}</p>
|
|
146
154
|
{selected.profile_url && (
|
|
147
155
|
<a href={selected.profile_url} target="_blank" rel="noopener noreferrer" style={{ fontSize: 10, color: '#0077B5', textDecoration: 'none', fontWeight: 600 }}>
|
|
148
156
|
View on LinkedIn
|
|
@@ -151,6 +159,9 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
151
159
|
</div>
|
|
152
160
|
</div>
|
|
153
161
|
|
|
162
|
+
{/* Their scan stopped partway: said by their name, where it's seen without scrolling. */}
|
|
163
|
+
{scansHere && resume && <StoppedPartway resume={resume} scanning={scanningThem} />}
|
|
164
|
+
|
|
154
165
|
{/* Their circle, out to six degrees: who they know, who you added from
|
|
155
166
|
it, and who those people know (TheirCircle.js). Your connections only:
|
|
156
167
|
a 2nd-degree person's circle isn't yours to scan until they accept. */}
|
|
@@ -166,22 +177,22 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
166
177
|
if (!i) return null;
|
|
167
178
|
const first = selected.name?.split(' ')[0] || 'them';
|
|
168
179
|
const twin = i.twin && connections.find((c) => c.id === i.twin.id);
|
|
169
|
-
const row = { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, padding: '7px 0', borderTop: '1px solid rgba(255,255,255,0.05)' };
|
|
170
|
-
const label = { fontSize: 10.5, color: '#8b9a9a', minWidth: 92 };
|
|
171
|
-
const act = { background: 'none', border: 'none', padding: 0, color: '#3498DB', cursor: 'pointer', fontSize: 11.5, whiteSpace: 'nowrap' };
|
|
180
|
+
const row = { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, padding: '7px 0', borderTop: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.05)' };
|
|
181
|
+
const label = { fontSize: 10.5, color: 'var(--sd-fg-3, #8b9a9a)', minWidth: 92 };
|
|
182
|
+
const act = { background: 'none', border: 'none', padding: 0, color: 'var(--sd-blue, #3498DB)', cursor: 'pointer', fontSize: 11.5, whiteSpace: 'nowrap' };
|
|
172
183
|
const scanned = i.bars == null ? 'Not scanned yet' : i.bars === 5 ? 'Their whole list' : `About ${i.bars * 20}% of their list`;
|
|
173
184
|
return (
|
|
174
185
|
<div style={{ border: '1px solid rgba(52,152,219,0.25)', borderRadius: 8, marginBottom: 16, background: 'rgba(52,152,219,0.04)' }}>
|
|
175
186
|
<button onClick={() => setShowInsights((v) => !v)} aria-expanded={showInsights}
|
|
176
|
-
style={{ width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '9px 12px', background: 'none', border: 'none', cursor: 'pointer', color: '#cfe6f7' }}>
|
|
187
|
+
style={{ width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '9px 12px', background: 'none', border: 'none', cursor: 'pointer', color: 'var(--sd-fg-1, #cfe6f7)' }}>
|
|
177
188
|
<span style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1 }}>INSIGHTS</span>
|
|
178
|
-
<span style={{ fontSize: 11, color: '#8b9a9a' }}>
|
|
189
|
+
<span style={{ fontSize: 11, color: 'var(--sd-fg-3, #8b9a9a)' }}>
|
|
179
190
|
{!showInsights && i.circle > 0 && `${i.circle.toLocaleString()} in their circle${i.only ? ` Β· ${i.only.toLocaleString()} only through ${first}` : ''} `}
|
|
180
191
|
{showInsights ? 'β²' : 'βΌ'}
|
|
181
192
|
</span>
|
|
182
193
|
</button>
|
|
183
194
|
{showInsights && (
|
|
184
|
-
<div style={{ padding: '0 12px 8px', fontSize: 12, color: '#ccc' }}>
|
|
195
|
+
<div style={{ padding: '0 12px 8px', fontSize: 12, color: 'var(--sd-fg-2, #ccc)' }}>
|
|
185
196
|
<div style={row}>
|
|
186
197
|
<span style={label}>Their circle</span>
|
|
187
198
|
<span style={{ flex: 1 }}>{i.circle ? `${i.circle.toLocaleString()} people` : 'None scanned yet'}</span>
|
|
@@ -190,7 +201,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
190
201
|
<div style={row}>
|
|
191
202
|
<span style={label}>Only through {first}</span>
|
|
192
203
|
<span style={{ flex: 1 }}>
|
|
193
|
-
{i.circle ? <><b style={{ color: '#00ff88' }}>{i.only.toLocaleString()}</b> ({Math.round(i.onlyShare * 100)}%): none of your other connections reach them</> : '
|
|
204
|
+
{i.circle ? <><b style={{ color: 'var(--sd-green, #00ff88)' }}>{i.only.toLocaleString()}</b> ({Math.round(i.onlyShare * 100)}%): none of your other connections reach them</> : '-'}
|
|
194
205
|
</span>
|
|
195
206
|
{i.only > 0 && onShowInSeparation && (
|
|
196
207
|
<button style={act} onClick={() => onShowInSeparation({ query: selected.name, rarity: 'only' })}>Show them β</button>
|
|
@@ -199,18 +210,18 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
199
210
|
<div style={row}>
|
|
200
211
|
<span style={label}>Closest overlap</span>
|
|
201
212
|
<span style={{ flex: 1 }}>
|
|
202
|
-
{twin ? <>Opens the same doors as <b style={{ color: '#fff' }}>{twin.name}</b> ({Math.round(i.twin.share * 100)}%, {i.twin.shared.toLocaleString()} people)</> : 'No one opens the same doors'}
|
|
213
|
+
{twin ? <>Opens the same doors as <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{twin.name}</b> ({Math.round(i.twin.share * 100)}%, {i.twin.shared.toLocaleString()} people)</> : 'No one opens the same doors'}
|
|
203
214
|
</span>
|
|
204
215
|
{twin && <button style={act} onClick={() => onSelect?.(twin)}>Open β</button>}
|
|
205
216
|
</div>
|
|
206
217
|
<div style={row}>
|
|
207
218
|
<span style={label}>Tier mix</span>
|
|
208
|
-
<span style={{ flex: 1, display: 'flex', height: 8, borderRadius: 4, overflow: 'hidden', background: 'rgba(255,255,255,0.05)', alignSelf: 'center' }}>
|
|
219
|
+
<span style={{ flex: 1, display: 'flex', height: 8, borderRadius: 4, overflow: 'hidden', background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', alignSelf: 'center' }}>
|
|
209
220
|
{i.circle > 0 && ['S', 'A', 'B', 'C', 'D'].map((t) => i.mix[t] > 0 && (
|
|
210
221
|
<span key={t} title={`${t}: ${i.mix[t]}`} style={{ width: `${(100 * i.mix[t]) / i.circle}%`, background: tierColors[t] }} />
|
|
211
222
|
))}
|
|
212
223
|
</span>
|
|
213
|
-
<span style={{ fontSize: 10.5, color: '#8b9a9a' }}>{i.circle ? `${i.mix.S} S Β· ${i.mix.A} A` : ''}</span>
|
|
224
|
+
<span style={{ fontSize: 10.5, color: 'var(--sd-fg-3, #8b9a9a)' }}>{i.circle ? `${i.mix.S} S Β· ${i.mix.A} A` : ''}</span>
|
|
214
225
|
{i.mix.S > 0 && onShowInSeparation && (
|
|
215
226
|
<button style={act} onClick={() => onShowInSeparation({ query: selected.name, tier: 'S' })}>S only β</button>
|
|
216
227
|
)}
|
|
@@ -224,9 +235,15 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
224
235
|
<div style={row}>
|
|
225
236
|
<span style={label}>Scanned</span>
|
|
226
237
|
<span style={{ flex: 1 }}>{scanned}</span>
|
|
227
|
-
{
|
|
238
|
+
{/* Stopped partway: carry on from that page, the line by their name's own
|
|
239
|
+
Resume. The Scan page's Scan one circle reads the list again from page 1,
|
|
240
|
+
which spends the searches already spent; that stays for anyone else. */}
|
|
241
|
+
{i.bars !== 5 && canScan && (scansHere && resume ? (
|
|
242
|
+
<button type="button" style={act} title={`Resume from page ${resume.nextPage}`}
|
|
243
|
+
onClick={() => resumeInScanBox(scanningThem)}>Resume β</button>
|
|
244
|
+
) : (resume === null || i.bars == null || !scansHere) && (
|
|
228
245
|
<a href={`/setup?scan=${encodeURIComponent(selected.id)}`} style={act}>{i.bars == null ? 'Scan β' : 'Finish β'}</a>
|
|
229
|
-
)}
|
|
246
|
+
))}
|
|
230
247
|
</div>
|
|
231
248
|
{(() => {
|
|
232
249
|
const since = selected.connected_date ? new Date(selected.connected_date) : null;
|
|
@@ -257,11 +274,11 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
257
274
|
background: 'rgba(0,255,136,0.08)', border: '1px solid rgba(0,255,136,0.3)',
|
|
258
275
|
borderRadius: 8, padding: 12, marginBottom: 16,
|
|
259
276
|
}}>
|
|
260
|
-
<div style={{ fontSize: 10, color: '#00ff88', fontWeight: 700, marginBottom: 4, letterSpacing: 1 }}>CATALYST NODE</div>
|
|
261
|
-
<div style={{ fontSize: 12, color: '#ccc' }}>
|
|
277
|
+
<div style={{ fontSize: 10, color: 'var(--sd-green, #00ff88)', fontWeight: 700, marginBottom: 4, letterSpacing: 1 }}>CATALYST NODE</div>
|
|
278
|
+
<div style={{ fontSize: 12, color: 'var(--sd-fg-2, #ccc)' }}>
|
|
262
279
|
This person's network power exceeds their own tier. They connect to{' '}
|
|
263
|
-
<strong style={{ color: '#00ff88' }}>{selected.catalyst_score} S+A tier</strong>{' '}
|
|
264
|
-
people
|
|
280
|
+
<strong style={{ color: 'var(--sd-green, #00ff88)' }}>{selected.catalyst_score} S+A tier</strong>{' '}
|
|
281
|
+
people, making them a high-value stepping stone to reach elite connections.
|
|
265
282
|
</div>
|
|
266
283
|
</div>
|
|
267
284
|
)}
|
|
@@ -271,43 +288,43 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
271
288
|
)}
|
|
272
289
|
|
|
273
290
|
{/* === SCORE CARD === */}
|
|
274
|
-
<div style={{ background: 'rgba(255,255,255,0.04)', borderRadius: 8, padding: 12, marginBottom: 16 }}>
|
|
291
|
+
<div style={{ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.04)', borderRadius: 8, padding: 12, marginBottom: 16 }}>
|
|
275
292
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8 }}>
|
|
276
|
-
<span style={{ fontSize: 11, color: '#888', fontWeight: 600, letterSpacing: 1, textTransform: 'uppercase' }}>Score</span>
|
|
293
|
+
<span style={{ fontSize: 11, color: 'var(--sd-fg-3, #888)', fontWeight: 600, letterSpacing: 1, textTransform: 'uppercase' }}>Score</span>
|
|
277
294
|
<span style={{ fontSize: 28, fontWeight: 800, color: tierColors[selected.tier] || '#fff' }}>
|
|
278
295
|
{parseFloat(selected.power_score).toFixed(1)}
|
|
279
296
|
</span>
|
|
280
297
|
</div>
|
|
281
298
|
{/* Why: title Γ company weight + bonuses (lib/scoring.js) */}
|
|
282
299
|
{selected.score_why && (
|
|
283
|
-
<div style={{ fontSize: 11, color: '#aab7b7', lineHeight: 1.5, marginBottom: 10 }}>{selected.score_why}</div>
|
|
300
|
+
<div style={{ fontSize: 11, color: 'var(--sd-fg-2, #aab7b7)', lineHeight: 1.5, marginBottom: 10 }}>{selected.score_why}</div>
|
|
284
301
|
)}
|
|
285
302
|
{/* Job Power bar */}
|
|
286
303
|
<div style={{ marginBottom: 6 }}>
|
|
287
|
-
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#888', marginBottom: 2 }}>
|
|
304
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>
|
|
288
305
|
<span>Title</span><span>{selected.seniority_score || 0}/10</span>
|
|
289
306
|
</div>
|
|
290
|
-
<div style={{ height: 4, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
|
|
307
|
+
<div style={{ height: 4, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', borderRadius: 2 }}>
|
|
291
308
|
<div style={{ height: '100%', width: `${(selected.seniority_score || 0) * 10}%`, background: tierColors[selected.tier] || '#FFD700', borderRadius: 2 }} />
|
|
292
309
|
</div>
|
|
293
310
|
</div>
|
|
294
311
|
{/* Status Power bar */}
|
|
295
312
|
<div style={{ marginBottom: selected.circle_power > 0 ? 6 : 0 }}>
|
|
296
|
-
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#888', marginBottom: 2 }}>
|
|
313
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>
|
|
297
314
|
<span>Company</span><span>{selected.company_prestige_score || 0}/10</span>
|
|
298
315
|
</div>
|
|
299
|
-
<div style={{ height: 4, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
|
|
316
|
+
<div style={{ height: 4, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', borderRadius: 2 }}>
|
|
300
317
|
<div style={{ height: '100%', width: `${(selected.company_prestige_score || 0) * 10}%`, background: '#3498DB', borderRadius: 2 }} />
|
|
301
318
|
</div>
|
|
302
319
|
</div>
|
|
303
320
|
{/* Circle Power bar β only shows for bridges with clusters */}
|
|
304
321
|
{selected.circle_power > 0 && (
|
|
305
322
|
<div>
|
|
306
|
-
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#888', marginBottom: 2 }}>
|
|
323
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>
|
|
307
324
|
<span>Circle Power</span>
|
|
308
|
-
<span style={{ color: '#FF6B35' }}>{selected.circle_s_count || 0}S Β· {selected.circle_a_count || 0}A</span>
|
|
325
|
+
<span style={{ color: 'var(--sd-orange, #FF6B35)' }}>{selected.circle_s_count || 0}S Β· {selected.circle_a_count || 0}A</span>
|
|
309
326
|
</div>
|
|
310
|
-
<div style={{ height: 4, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
|
|
327
|
+
<div style={{ height: 4, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', borderRadius: 2 }}>
|
|
311
328
|
<div style={{ height: '100%', width: `${Math.min(parseFloat(selected.circle_power) / 70 * 100, 100)}%`, background: '#FF6B35', borderRadius: 2 }} />
|
|
312
329
|
</div>
|
|
313
330
|
</div>
|
|
@@ -316,10 +333,10 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
316
333
|
|
|
317
334
|
{/* === WHY THIS MATTERS === */}
|
|
318
335
|
<div style={{ marginBottom: 16 }}>
|
|
319
|
-
<div style={{ fontSize: 10, fontWeight: 700, color: '#FFD700', letterSpacing: 1, marginBottom: 6, textTransform: 'uppercase' }}>
|
|
336
|
+
<div style={{ fontSize: 10, fontWeight: 700, color: 'var(--sd-gold, #FFD700)', letterSpacing: 1, marginBottom: 6, textTransform: 'uppercase' }}>
|
|
320
337
|
Why This Matters
|
|
321
338
|
</div>
|
|
322
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 11, color: '#ccc' }}>
|
|
339
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 11, color: 'var(--sd-fg-2, #ccc)' }}>
|
|
323
340
|
{generateInsights(selected, userProfile, connections, degree2, routes).map((insight, idx) => (
|
|
324
341
|
<div key={idx} style={{ display: 'flex', gap: 6, alignItems: 'flex-start' }}>
|
|
325
342
|
<span style={{ color: insight.color || '#888', fontSize: 13, lineHeight: 1 }}>{insight.icon}</span>
|
|
@@ -331,13 +348,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
331
348
|
|
|
332
349
|
{selected.company && (
|
|
333
350
|
<div style={{ marginBottom: 8 }}>
|
|
334
|
-
<div style={{ color: '#666', fontSize: 10 }}>Company</div>
|
|
351
|
+
<div style={{ color: 'var(--sd-fg-4, #666)', fontSize: 10 }}>Company</div>
|
|
335
352
|
<div style={{ fontWeight: 600, fontSize: 12 }}>{selected.company}</div>
|
|
336
353
|
</div>
|
|
337
354
|
)}
|
|
338
355
|
{selected.role && (
|
|
339
356
|
<div style={{ marginBottom: 12 }}>
|
|
340
|
-
<div style={{ color: '#666', fontSize: 10 }}>Role</div>
|
|
357
|
+
<div style={{ color: 'var(--sd-fg-4, #666)', fontSize: 10 }}>Role</div>
|
|
341
358
|
<div style={{ fontSize: 12 }}>{selected.role}</div>
|
|
342
359
|
</div>
|
|
343
360
|
)}
|
|
@@ -349,12 +366,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
349
366
|
const topPeople = [...bridgeConnections].sort((a, b) => (parseFloat(b.power_score) || 0) - (parseFloat(a.power_score) || 0)).slice(0, 8);
|
|
350
367
|
return (
|
|
351
368
|
<div style={{ marginBottom: 16 }}>
|
|
352
|
-
<div style={{ fontSize: 10, fontWeight: 700, color: '#FF6B35', letterSpacing: 1, marginBottom: 8, textTransform: 'uppercase' }}>
|
|
353
|
-
Cluster Overview
|
|
369
|
+
<div style={{ fontSize: 10, fontWeight: 700, color: 'var(--sd-orange, #FF6B35)', letterSpacing: 1, marginBottom: 8, textTransform: 'uppercase' }}>
|
|
370
|
+
Cluster Overview Β· {bridgeConnections.length} connections
|
|
354
371
|
</div>
|
|
355
372
|
<div style={{ display: 'flex', gap: 6, marginBottom: 8, fontSize: 10 }}>
|
|
356
|
-
{sTier.length > 0 && <span style={{ color: '#FFD700', fontWeight: 600 }}>{sTier.length} S-tier</span>}
|
|
357
|
-
{aTier.length > 0 && <span style={{ color: '#9B59B6', fontWeight: 600 }}>{aTier.length} A-tier</span>}
|
|
373
|
+
{sTier.length > 0 && <span style={{ color: 'var(--sd-gold, #FFD700)', fontWeight: 600 }}>{sTier.length} S-tier</span>}
|
|
374
|
+
{aTier.length > 0 && <span style={{ color: 'var(--sd-purple, #9B59B6)', fontWeight: 600 }}>{aTier.length} A-tier</span>}
|
|
358
375
|
</div>
|
|
359
376
|
{/* Outlink Bridge button */}
|
|
360
377
|
<a href={`/queue?bridge=${selected.id}&groupBy=bridge`} style={{
|
|
@@ -364,7 +381,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
364
381
|
}}>
|
|
365
382
|
Outlink Bridge β Add {bridgeConnections.filter(m => m.tier === 'S' || m.tier === 'A' || m.tier === 'B').length} People
|
|
366
383
|
</a>
|
|
367
|
-
<div style={{ fontSize: 10, color: '#888', marginBottom: 8 }}>Most valuable in this cluster:</div>
|
|
384
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 8 }}>Most valuable in this cluster:</div>
|
|
368
385
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
369
386
|
{topPeople.map(m => (
|
|
370
387
|
<div key={m.id}
|
|
@@ -372,10 +389,10 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
372
389
|
style={{
|
|
373
390
|
display: 'flex', alignItems: 'center', gap: 6, padding: '4px 6px',
|
|
374
391
|
borderRadius: 4, cursor: 'pointer', borderLeft: `2px solid ${tierColors[m.tier] || '#555'}`,
|
|
375
|
-
background: 'rgba(255,255,255,0.03)',
|
|
392
|
+
background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)',
|
|
376
393
|
}}
|
|
377
|
-
onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.08)'}
|
|
378
|
-
onMouseLeave={e => e.currentTarget.style.background = 'rgba(255,255,255,0.03)'}
|
|
394
|
+
onMouseEnter={e => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.08)'}
|
|
395
|
+
onMouseLeave={e => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.03)'}
|
|
379
396
|
>
|
|
380
397
|
{localPhoto(m.profile_image_url) ? (
|
|
381
398
|
<img src={localPhoto(m.profile_image_url)} alt="" style={{
|
|
@@ -385,12 +402,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
385
402
|
) : null}
|
|
386
403
|
<div style={{
|
|
387
404
|
width: 22, height: 22, borderRadius: '50%', flexShrink: 0, fontSize: 9, fontWeight: 700,
|
|
388
|
-
background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : '#fff',
|
|
405
|
+
background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
389
406
|
display: localPhoto(m.profile_image_url) ? 'none' : 'flex', alignItems: 'center', justifyContent: 'center',
|
|
390
407
|
}}>{m.name?.charAt(0)}</div>
|
|
391
408
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
392
409
|
<div style={{ fontSize: 10, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.name}</div>
|
|
393
|
-
<div style={{ fontSize: 8, color: '#666', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.headline?.substring(0, 40)}</div>
|
|
410
|
+
<div style={{ fontSize: 8, color: 'var(--sd-fg-4, #666)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.headline?.substring(0, 40)}</div>
|
|
394
411
|
</div>
|
|
395
412
|
<span style={{ fontSize: 9, color: tierColors[m.tier], fontWeight: 600, flexShrink: 0 }}>{parseFloat(m.power_score).toFixed(1)}</span>
|
|
396
413
|
</div>
|
|
@@ -402,7 +419,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
402
419
|
|
|
403
420
|
{isBridge && bridgeConnections.length > 0 && (
|
|
404
421
|
<div style={{ marginTop: 16 }}>
|
|
405
|
-
<div style={{ fontSize: 12, fontWeight: 600, color: '#FF6B35', marginBottom: 8 }}>
|
|
422
|
+
<div style={{ fontSize: 12, fontWeight: 600, color: 'var(--sd-orange, #FF6B35)', marginBottom: 8 }}>
|
|
406
423
|
Gateway to {bridgeConnections.length} degree-2 connections:
|
|
407
424
|
</div>
|
|
408
425
|
{bridgeConnections.sort((a, b) => (parseFloat(b.power_score) || 0) - (parseFloat(a.power_score) || 0)).slice(0, 10).map(c => (
|
|
@@ -411,8 +428,8 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
411
428
|
borderLeft: '3px solid #FF6B35', marginBottom: 4, fontSize: 12,
|
|
412
429
|
}}>
|
|
413
430
|
<div style={{ fontWeight: 600 }}>{c.name}</div>
|
|
414
|
-
<div style={{ color: '#888', fontSize: 11 }}>{c.role}{c.company ? ` @ ${c.company}` : ''}</div>
|
|
415
|
-
<div style={{ color: '#FF6B35', fontSize: 10 }}>Score: {parseFloat(c.power_score).toFixed(1)}</div>
|
|
431
|
+
<div style={{ color: 'var(--sd-fg-3, #888)', fontSize: 11 }}>{c.role}{c.company ? ` @ ${c.company}` : ''}</div>
|
|
432
|
+
<div style={{ color: 'var(--sd-orange, #FF6B35)', fontSize: 10 }}>Score: {parseFloat(c.power_score).toFixed(1)}</div>
|
|
416
433
|
</div>
|
|
417
434
|
))}
|
|
418
435
|
</div>
|
|
@@ -441,20 +458,20 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
441
458
|
background: 'rgba(255,215,0,0.06)', border: `1px ${asked ? 'dashed' : 'solid'} rgba(255,215,0,${asked ? 0.45 : 0.25})`,
|
|
442
459
|
borderRadius: 10, padding: 16, marginTop: 16, textAlign: 'center',
|
|
443
460
|
}}>
|
|
444
|
-
<div style={{ fontSize: 10, color: '#FFD700', fontWeight: 700, letterSpacing: 1, marginBottom: 6 }}>
|
|
461
|
+
<div style={{ fontSize: 10, color: 'var(--sd-gold, #FFD700)', fontWeight: 700, letterSpacing: 1, marginBottom: 6 }}>
|
|
445
462
|
{asked ? 'REQUEST SENT' : 'LOCKED PATH'}
|
|
446
463
|
</div>
|
|
447
|
-
<div style={{ fontSize: 13, color: '#ccc', marginBottom: 12 }}>
|
|
464
|
+
<div style={{ fontSize: 13, color: 'var(--sd-fg-2, #ccc)', marginBottom: 12 }}>
|
|
448
465
|
{asked
|
|
449
466
|
? `Waiting for ${selected.name} to accept. The next scan of your own connections notices when they do.`
|
|
450
467
|
: `Connect with ${selected.name} to unlock their network and extend your six degrees.`
|
|
451
468
|
}
|
|
452
469
|
</div>
|
|
453
470
|
<div style={{
|
|
454
|
-
width: '100%', height: 60, background: 'rgba(255,255,255,0.03)',
|
|
455
|
-
borderRadius: 8, border: '1px dashed rgba(255,255,255,0.1)',
|
|
471
|
+
width: '100%', height: 60, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)',
|
|
472
|
+
borderRadius: 8, border: '1px dashed rgba(var(--sd-ink, 255, 255, 255), 0.1)',
|
|
456
473
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
457
|
-
fontSize: 11, color: '#444', marginBottom: 12,
|
|
474
|
+
fontSize: 11, color: 'var(--sd-fg-5, #444)', marginBottom: 12,
|
|
458
475
|
}}>
|
|
459
476
|
{asked ? '[ Cluster Pending... ]' : '[ Hidden Network ]'}
|
|
460
477
|
</div>
|
|
@@ -462,27 +479,33 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
462
479
|
<button
|
|
463
480
|
onClick={() => { undoRequest(selected).catch(() => {}); }}
|
|
464
481
|
style={{
|
|
465
|
-
background: 'none', border: 'none', color: '#888', fontSize: 11, fontWeight: 600, cursor: 'pointer',
|
|
482
|
+
background: 'none', border: 'none', color: 'var(--sd-fg-3, #888)', fontSize: 11, fontWeight: 600, cursor: 'pointer',
|
|
466
483
|
}}
|
|
467
484
|
>
|
|
468
485
|
Didn't send it? Undo
|
|
469
486
|
</button>
|
|
470
487
|
) : (
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
488
|
+
// Auto first, the better pick; Connect beside it as an outline
|
|
489
|
+
// (AutoConnect.js; Blake, 2026-10-03). Your own network only.
|
|
490
|
+
<ConnectChoice person={selected} canAuto={canScan} size="card" connect={(second) => (
|
|
491
|
+
<a href={selected.profile_url} target="_blank" rel="noopener noreferrer"
|
|
492
|
+
title={second ? 'Opens their LinkedIn profile, to connect yourself' : undefined}
|
|
493
|
+
style={second ? { ...secondaryLook('card'), flex: 1 } : {
|
|
494
|
+
display: 'block', padding: '10px 16px',
|
|
495
|
+
background: 'linear-gradient(135deg, #FFD700, #FF6B35)',
|
|
496
|
+
color: '#000', borderRadius: 8, textDecoration: 'none',
|
|
497
|
+
fontWeight: 700, fontSize: 13,
|
|
498
|
+
}}
|
|
499
|
+
onClick={() => {
|
|
500
|
+
// Opens their profile to connect, and marks the request
|
|
501
|
+
// sent, through the bridge whose circle you found them in.
|
|
502
|
+
markRequested(selected, { bridgeId: selected.source_connection_id }).catch(() => {});
|
|
503
|
+
}}
|
|
504
|
+
>
|
|
505
|
+
{/* Beside Auto there's room for one word (a 320 px panel). */}
|
|
506
|
+
{second ? 'Connect' : 'Connect to Unlock Path'}
|
|
507
|
+
</a>
|
|
508
|
+
)} />
|
|
486
509
|
)}
|
|
487
510
|
</div>
|
|
488
511
|
);
|
|
@@ -491,7 +514,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
491
514
|
{/* Create Cluster β for D1 connections OR accepted D2 (promoted, ready to bridge for D3) */}
|
|
492
515
|
{(selected.degree === 1 || selected.outreach_status === 'accepted') && (
|
|
493
516
|
canScan
|
|
494
|
-
? <CreateClusterCard key={selected.id} selected={selected} degree2={degree2} />
|
|
517
|
+
? <CreateClusterCard key={selected.id} selected={selected} degree2={degree2} resume={resume} />
|
|
495
518
|
: <ScansNeedYourNetwork csvSource={csvSource} style={{ marginTop: 16 }} />
|
|
496
519
|
)}
|
|
497
520
|
|
|
@@ -525,13 +548,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
525
548
|
onClick={onToggle}
|
|
526
549
|
style={{
|
|
527
550
|
display: 'flex', alignItems: 'center', gap: 6, background: 'none', border: 'none',
|
|
528
|
-
color: '#888', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
|
|
551
|
+
color: 'var(--sd-fg-3, #888)', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
|
|
529
552
|
}}
|
|
530
553
|
>
|
|
531
554
|
<span style={{ fontSize: 16 }}>←</span> Close
|
|
532
555
|
</button>
|
|
533
|
-
<h3 style={{ fontSize: 16, fontWeight: 700, marginTop: 0, color: '#FF6B35' }}>Degrees</h3>
|
|
534
|
-
<p style={{ fontSize: 12, color: '#888', marginBottom: 12 }}>
|
|
556
|
+
<h3 style={{ fontSize: 16, fontWeight: 700, marginTop: 0, color: 'var(--sd-orange, #FF6B35)' }}>Degrees</h3>
|
|
557
|
+
<p style={{ fontSize: 12, color: 'var(--sd-fg-3, #888)', marginBottom: 12 }}>
|
|
535
558
|
Your bridge connections and who they unlock.
|
|
536
559
|
</p>
|
|
537
560
|
|
|
@@ -556,8 +579,8 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
556
579
|
onChange={e => setSearchQuery(e.target.value)}
|
|
557
580
|
style={{
|
|
558
581
|
width: '100%', padding: '8px 12px', borderRadius: 8, fontSize: 12,
|
|
559
|
-
border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.05)',
|
|
560
|
-
color: '#fff', outline: 'none', boxSizing: 'border-box',
|
|
582
|
+
border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)', background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)',
|
|
583
|
+
color: 'var(--sd-fg-1, #fff)', outline: 'none', boxSizing: 'border-box',
|
|
561
584
|
}}
|
|
562
585
|
/>
|
|
563
586
|
{searchQuery.length >= 2 && (() => {
|
|
@@ -575,7 +598,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
575
598
|
return (
|
|
576
599
|
<div style={{
|
|
577
600
|
position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 50,
|
|
578
|
-
background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(255,255,255,0.1)',
|
|
601
|
+
background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)',
|
|
579
602
|
borderRadius: 8, overflow: 'hidden', maxHeight: 200, overflowY: 'auto',
|
|
580
603
|
boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
|
|
581
604
|
}}>
|
|
@@ -586,9 +609,9 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
586
609
|
if (onFocusNode && m._matchType === 'bridge') onFocusNode(m.id);
|
|
587
610
|
}} style={{
|
|
588
611
|
padding: '8px 12px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8,
|
|
589
|
-
borderBottom: '1px solid rgba(255,255,255,0.05)',
|
|
612
|
+
borderBottom: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.05)',
|
|
590
613
|
}}
|
|
591
|
-
onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.06)'}
|
|
614
|
+
onMouseEnter={e => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.06)'}
|
|
592
615
|
onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
|
|
593
616
|
>
|
|
594
617
|
{localPhoto(m.profile_image_url) ? (
|
|
@@ -598,7 +621,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
598
621
|
)}
|
|
599
622
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
600
623
|
<div style={{ fontSize: 11, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.name}</div>
|
|
601
|
-
<div style={{ fontSize: 8, color: '#666' }}>{m._matchType === 'bridge' ? 'Bridge' : 'Degree-2'}</div>
|
|
624
|
+
<div style={{ fontSize: 8, color: 'var(--sd-fg-4, #666)' }}>{m._matchType === 'bridge' ? 'Bridge' : 'Degree-2'}</div>
|
|
602
625
|
</div>
|
|
603
626
|
<span style={{ fontSize: 9, fontWeight: 700, color: tierColors[m.tier] }}>{m.tier}</span>
|
|
604
627
|
</div>
|
|
@@ -611,10 +634,10 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
611
634
|
{/* Pending Requests View */}
|
|
612
635
|
{filter === 'pending' && pending.length > 0 && (
|
|
613
636
|
<>
|
|
614
|
-
<h4 style={{ fontSize: 13, fontWeight: 600, color: '#FF6B35', marginBottom: 8 }}>
|
|
637
|
+
<h4 style={{ fontSize: 13, fontWeight: 600, color: 'var(--sd-orange, #FF6B35)', marginBottom: 8 }}>
|
|
615
638
|
β³ Pending Requests ({pending.length})
|
|
616
639
|
</h4>
|
|
617
|
-
<p style={{ fontSize: 10, color: '#666', marginBottom: 10, lineHeight: 1.4 }}>
|
|
640
|
+
<p style={{ fontSize: 10, color: 'var(--sd-fg-4, #666)', marginBottom: 10, lineHeight: 1.4 }}>
|
|
618
641
|
Friend requests you've sent. When accepted, their cluster unlocks for bridging.
|
|
619
642
|
</p>
|
|
620
643
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
@@ -635,7 +658,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
635
658
|
) : (
|
|
636
659
|
<div style={{
|
|
637
660
|
width: 32, height: 32, borderRadius: '50%', flexShrink: 0, fontSize: 12, fontWeight: 700,
|
|
638
|
-
background: tierColors[p.tier] || '#555', color: p.tier === 'S' ? '#000' : '#fff',
|
|
661
|
+
background: tierColors[p.tier] || '#555', color: p.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
639
662
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
640
663
|
}}>{p.name?.charAt(0)}</div>
|
|
641
664
|
)}
|
|
@@ -645,11 +668,11 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
645
668
|
<div style={{ fontSize: 11, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
646
669
|
{p.name}
|
|
647
670
|
</div>
|
|
648
|
-
<div style={{ fontSize: 8, color: '#888', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
671
|
+
<div style={{ fontSize: 8, color: 'var(--sd-fg-3, #888)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
649
672
|
{p.headline?.substring(0, 40)}
|
|
650
673
|
</div>
|
|
651
674
|
{bridge && (
|
|
652
|
-
<div style={{ fontSize: 8, color: '#FF6B35', marginTop: 1 }}>
|
|
675
|
+
<div style={{ fontSize: 8, color: 'var(--sd-orange, #FF6B35)', marginTop: 1 }}>
|
|
653
676
|
via {bridge.name?.split(' ')[0]}
|
|
654
677
|
</div>
|
|
655
678
|
)}
|
|
@@ -660,7 +683,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
660
683
|
<div style={{ fontSize: 9, fontWeight: 800, color: tierColors[p.tier] || '#888' }}>
|
|
661
684
|
{p.tier}
|
|
662
685
|
</div>
|
|
663
|
-
<div style={{ fontSize: 8, color: '#666' }}>
|
|
686
|
+
<div style={{ fontSize: 8, color: 'var(--sd-fg-4, #666)' }}>
|
|
664
687
|
{parseFloat(p.power_score || 0).toFixed(1)}
|
|
665
688
|
</div>
|
|
666
689
|
</div>
|
|
@@ -670,7 +693,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
670
693
|
onClick={() => onUndoPending && onUndoPending(p)}
|
|
671
694
|
title="Remove from pending"
|
|
672
695
|
style={{
|
|
673
|
-
background: 'none', border: 'none', color: '#555', cursor: 'pointer',
|
|
696
|
+
background: 'none', border: 'none', color: 'var(--sd-fg-5, #555)', cursor: 'pointer',
|
|
674
697
|
fontSize: 12, padding: 2, flexShrink: 0,
|
|
675
698
|
}}
|
|
676
699
|
>β</button>
|
|
@@ -683,7 +706,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
683
706
|
|
|
684
707
|
{/* Clusters View (hidden when viewing pending) */}
|
|
685
708
|
{filter !== 'pending' && (<>
|
|
686
|
-
<h4 style={{ fontSize: 13, fontWeight: 600, color: '#FF6B35', marginBottom: 8 }}>Most Valuable Clusters</h4>
|
|
709
|
+
<h4 style={{ fontSize: 13, fontWeight: 600, color: 'var(--sd-orange, #FF6B35)', marginBottom: 8 }}>Most Valuable Clusters</h4>
|
|
687
710
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
|
688
711
|
{(() => {
|
|
689
712
|
const clusterStats = Object.entries(bridgeMap).map(([bridgeId, members]) => {
|
|
@@ -757,8 +780,8 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
757
780
|
onClick={onToggle}
|
|
758
781
|
style={{
|
|
759
782
|
display: 'flex', alignItems: 'center', gap: 6,
|
|
760
|
-
background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)',
|
|
761
|
-
borderRadius: 6, color: '#aaa', fontSize: 12, cursor: 'pointer',
|
|
783
|
+
background: 'rgba(var(--sd-ink, 255, 255, 255), 0.06)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)',
|
|
784
|
+
borderRadius: 6, color: 'var(--sd-fg-3, #aaa)', fontSize: 12, cursor: 'pointer',
|
|
762
785
|
padding: '6px 12px', marginBottom: 12, fontWeight: 600,
|
|
763
786
|
}}
|
|
764
787
|
>
|
|
@@ -783,14 +806,14 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
783
806
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
784
807
|
style={{
|
|
785
808
|
width: '100%', padding: '8px 12px', borderRadius: 8, boxSizing: 'border-box',
|
|
786
|
-
border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(0,0,0,0.3)',
|
|
787
|
-
color: '#fff', fontSize: 12, outline: 'none',
|
|
809
|
+
border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)', background: 'rgba(var(--sd-shade, 0, 0, 0), 0.3)',
|
|
810
|
+
color: 'var(--sd-fg-1, #fff)', fontSize: 12, outline: 'none',
|
|
788
811
|
}}
|
|
789
812
|
/>
|
|
790
813
|
{searchResults.length > 0 && (
|
|
791
814
|
<div style={{
|
|
792
815
|
position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 10,
|
|
793
|
-
background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(255,255,255,0.1)',
|
|
816
|
+
background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)',
|
|
794
817
|
borderRadius: 8, marginTop: 4, overflow: 'hidden',
|
|
795
818
|
boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
|
|
796
819
|
}}>
|
|
@@ -804,9 +827,9 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
804
827
|
}}
|
|
805
828
|
style={{
|
|
806
829
|
display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px',
|
|
807
|
-
cursor: 'pointer', borderBottom: '1px solid rgba(255,255,255,0.04)',
|
|
830
|
+
cursor: 'pointer', borderBottom: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.04)',
|
|
808
831
|
}}
|
|
809
|
-
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.08)'}
|
|
832
|
+
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.08)'}
|
|
810
833
|
onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
|
|
811
834
|
>
|
|
812
835
|
{localPhoto(c.profile_image_url) ? (
|
|
@@ -817,13 +840,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
817
840
|
) : (
|
|
818
841
|
<div style={{
|
|
819
842
|
width: 24, height: 24, borderRadius: '50%', flexShrink: 0, fontSize: 10, fontWeight: 700,
|
|
820
|
-
background: tierColors[c.tier] || '#555', color: c.tier === 'S' ? '#000' : '#fff',
|
|
843
|
+
background: tierColors[c.tier] || '#555', color: c.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
821
844
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
822
845
|
}}>{c.name?.charAt(0)}</div>
|
|
823
846
|
)}
|
|
824
847
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
825
848
|
<div style={{ fontSize: 12, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.name}</div>
|
|
826
|
-
<div style={{ fontSize: 9, color: '#666' }}>{c.headline?.substring(0, 35)}</div>
|
|
849
|
+
<div style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)' }}>{c.headline?.substring(0, 35)}</div>
|
|
827
850
|
</div>
|
|
828
851
|
<span style={{ fontSize: 10, color: tierColors[c.tier], fontWeight: 700 }}>{c.tier}</span>
|
|
829
852
|
</div>
|
|
@@ -832,7 +855,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
832
855
|
)}
|
|
833
856
|
</div>
|
|
834
857
|
|
|
835
|
-
<h4 style={{ fontSize: 13, fontWeight: 600, color: '#FFD700', marginBottom: 8 }}>
|
|
858
|
+
<h4 style={{ fontSize: 13, fontWeight: 600, color: 'var(--sd-gold, #FFD700)', marginBottom: 8 }}>
|
|
836
859
|
Power Rankings ({allRanked.length})
|
|
837
860
|
</h4>
|
|
838
861
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
@@ -850,7 +873,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
850
873
|
if (showHeader) tierRankCounter[c.tier] = 0;
|
|
851
874
|
tierRankCounter[c.tier] = (tierRankCounter[c.tier] || 0) + 1;
|
|
852
875
|
const tierRank = tierRankCounter[c.tier];
|
|
853
|
-
const tierNames = { S: 'S-Tier
|
|
876
|
+
const tierNames = { S: 'S-Tier Β· Elite', A: 'A-Tier Β· High Value', B: 'B-Tier Β· Notable', C: 'C-Tier Β· Standard', D: 'D-Tier Β· Entry' };
|
|
854
877
|
return (
|
|
855
878
|
<div key={c.id}>
|
|
856
879
|
{showHeader && (
|
|
@@ -869,16 +892,16 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
869
892
|
<div
|
|
870
893
|
onClick={() => { onSelect && onSelect(c); onFocusNode && onFocusNode(c.id); }}
|
|
871
894
|
style={{
|
|
872
|
-
padding: '6px 8px', background: 'rgba(255,255,255,0.03)', borderRadius: 6,
|
|
895
|
+
padding: '6px 8px', background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)', borderRadius: 6,
|
|
873
896
|
borderLeft: `3px solid ${tierColors[c.tier] || '#555'}`,
|
|
874
897
|
cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8,
|
|
875
898
|
transition: 'background 0.15s',
|
|
876
899
|
}}
|
|
877
|
-
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.1)'}
|
|
878
|
-
onMouseLeave={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.03)'}
|
|
900
|
+
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.1)'}
|
|
901
|
+
onMouseLeave={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.03)'}
|
|
879
902
|
>
|
|
880
903
|
{/* Rank number β per tier */}
|
|
881
|
-
<span style={{ color: '#555', fontSize: 10, fontWeight: 600, minWidth: 22, textAlign: 'right' }}>
|
|
904
|
+
<span style={{ color: 'var(--sd-fg-5, #555)', fontSize: 10, fontWeight: 600, minWidth: 22, textAlign: 'right' }}>
|
|
882
905
|
#{tierRank}
|
|
883
906
|
</span>
|
|
884
907
|
{/* Profile photo or initial */}
|
|
@@ -896,7 +919,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
896
919
|
background: tierColors[c.tier] || '#555',
|
|
897
920
|
display: localPhoto(c.profile_image_url) ? 'none' : 'flex',
|
|
898
921
|
alignItems: 'center', justifyContent: 'center',
|
|
899
|
-
fontSize: 12, fontWeight: 700, color: c.tier === 'S' ? '#000' : '#fff',
|
|
922
|
+
fontSize: 12, fontWeight: 700, color: c.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
900
923
|
}}>
|
|
901
924
|
{c.name?.charAt(0)}
|
|
902
925
|
</div>
|
|
@@ -905,7 +928,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
905
928
|
<div style={{ fontWeight: 600, fontSize: 11, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
906
929
|
{c.name}
|
|
907
930
|
</div>
|
|
908
|
-
<div style={{ fontSize: 9, color: '#666', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
931
|
+
<div style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
909
932
|
{c.headline?.substring(0, 45)}
|
|
910
933
|
</div>
|
|
911
934
|
</div>
|
|
@@ -914,7 +937,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
|
|
|
914
937
|
<div style={{ fontSize: 10, fontWeight: 700, color: tierColors[c.tier] || '#555' }}>
|
|
915
938
|
{parseFloat(c.power_score).toFixed(1)}
|
|
916
939
|
</div>
|
|
917
|
-
<div style={{ fontSize: 8, color: '#555' }}>{c.tier}</div>
|
|
940
|
+
<div style={{ fontSize: 8, color: 'var(--sd-fg-5, #555)' }}>{c.tier}</div>
|
|
918
941
|
</div>
|
|
919
942
|
</div>
|
|
920
943
|
</div>
|
|
@@ -939,7 +962,7 @@ function SidebarWrapper({ children, collapsed, onToggle }) {
|
|
|
939
962
|
display: 'flex', alignItems: 'center', flexDirection: 'row-reverse', gap: 0,
|
|
940
963
|
height: 36, borderRadius: 18,
|
|
941
964
|
background: 'rgba(255,215,0,0.15)', border: '2px solid rgba(255,215,0,0.5)',
|
|
942
|
-
color: '#FFD700', fontWeight: 700,
|
|
965
|
+
color: 'var(--sd-gold, #FFD700)', fontWeight: 700,
|
|
943
966
|
boxShadow: '0 0 12px rgba(255,215,0,0.3)',
|
|
944
967
|
backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
|
|
945
968
|
overflow: 'hidden', transition: 'width 0.25s ease',
|
|
@@ -960,13 +983,13 @@ function SidebarWrapper({ children, collapsed, onToggle }) {
|
|
|
960
983
|
position: 'fixed', top: 0, right: 0, bottom: 0, zIndex: 100,
|
|
961
984
|
width: '100vw', pointerEvents: 'auto',
|
|
962
985
|
} : { flexShrink: 0, height: '100%' }}>
|
|
963
|
-
{isMobile && <div onClick={onToggle} style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.5)' }} />}
|
|
964
|
-
<div style={{
|
|
986
|
+
{isMobile && <div onClick={onToggle} style={{ position: 'absolute', inset: 0, background: 'rgba(var(--sd-shade, 0, 0, 0), 0.5)' }} />}
|
|
987
|
+
<div data-glass-panel={isMobile ? undefined : 'side'} style={{
|
|
965
988
|
width: isMobile ? '80vw' : 320, minWidth: isMobile ? 0 : 320, maxWidth: isMobile ? 300 : 320, height: '100%',
|
|
966
989
|
borderLeft: '1px solid rgba(255,215,0,0.12)',
|
|
967
990
|
padding: isMobile ? '12px 10px' : '16px 16px',
|
|
968
991
|
overflowY: 'auto', overflowX: 'hidden',
|
|
969
|
-
background: isMobile ? 'rgba(15,12,5,0.98)' : 'var(--sd-panel)', fontSize: 13,
|
|
992
|
+
background: isMobile ? 'var(--sd-surface, rgba(15,12,5,0.98))' : 'var(--sd-panel)', fontSize: 13,
|
|
970
993
|
backdropFilter: 'var(--sd-panel-blur)', WebkitBackdropFilter: 'var(--sd-panel-blur)',
|
|
971
994
|
boxShadow: 'inset 0 0 60px rgba(255,215,0,0.03), -4px 0 24px rgba(0,0,0,0.3)',
|
|
972
995
|
marginLeft: isMobile ? 'auto' : 0,
|
|
@@ -979,15 +1002,15 @@ function SidebarWrapper({ children, collapsed, onToggle }) {
|
|
|
979
1002
|
|
|
980
1003
|
function StatBox({ label, value }) {
|
|
981
1004
|
return (
|
|
982
|
-
<div style={{ background: 'rgba(255,255,255,0.05)', padding: '10px 12px', borderRadius: 8 }}>
|
|
983
|
-
<div style={{ fontSize: 10, color: '#888', marginBottom: 2 }}>{label}</div>
|
|
1005
|
+
<div style={{ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', padding: '10px 12px', borderRadius: 8 }}>
|
|
1006
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>{label}</div>
|
|
984
1007
|
<div style={{ fontSize: 18, fontWeight: 700 }}>{value}</div>
|
|
985
1008
|
</div>
|
|
986
1009
|
);
|
|
987
1010
|
}
|
|
988
1011
|
|
|
989
1012
|
function Arrow() {
|
|
990
|
-
return <span style={{ color: '#555', fontSize: 16 }}>→</span>;
|
|
1013
|
+
return <span style={{ color: 'var(--sd-fg-5, #555)', fontSize: 16 }}>→</span>;
|
|
991
1014
|
}
|
|
992
1015
|
|
|
993
1016
|
const CANT_NAME_TITLE = 'This route came from a scanned list whose connection record doesnβt match anyone in '
|
|
@@ -1009,15 +1032,15 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
|
|
|
1009
1032
|
background: 'rgba(255,107,53,0.1)', border: '1px solid rgba(255,107,53,0.3)',
|
|
1010
1033
|
borderRadius: 8, padding: 12, marginBottom: 16,
|
|
1011
1034
|
}}>
|
|
1012
|
-
<div style={{ fontSize: 10, color: '#FF6B35', fontWeight: 600, marginBottom: 8 }}>
|
|
1035
|
+
<div style={{ fontSize: 10, color: 'var(--sd-orange, #FF6B35)', fontWeight: 600, marginBottom: 8 }}>
|
|
1013
1036
|
PATH TO THIS PERSON{n > 1 ? ` Β· ${n} WAYS IN` : ''}
|
|
1014
1037
|
</div>
|
|
1015
1038
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
|
|
1016
1039
|
{shown.map((r, i) => {
|
|
1017
1040
|
if (!r.bridge) {
|
|
1018
1041
|
return (
|
|
1019
|
-
<div key={`unnamed-${r.id}`} title={CANT_NAME_TITLE} style={{ ...line, color: '#888', fontStyle: 'italic' }}>
|
|
1020
|
-
<span style={{ fontWeight: 700, fontStyle: 'normal', color: '#fff' }}>You</span>
|
|
1042
|
+
<div key={`unnamed-${r.id}`} title={CANT_NAME_TITLE} style={{ ...line, color: 'var(--sd-fg-3, #888)', fontStyle: 'italic' }}>
|
|
1043
|
+
<span style={{ fontWeight: 700, fontStyle: 'normal', color: 'var(--sd-fg-1, #fff)' }}>You</span>
|
|
1021
1044
|
<Arrow />
|
|
1022
1045
|
<span>a connection we can’t name</span>
|
|
1023
1046
|
<Arrow />
|
|
@@ -1045,17 +1068,17 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
|
|
|
1045
1068
|
{b.name}
|
|
1046
1069
|
</button>
|
|
1047
1070
|
<Arrow />
|
|
1048
|
-
<span style={{ color: '#FF6B35', fontWeight: 600 }}>{selected.name}</span>
|
|
1071
|
+
<span style={{ color: 'var(--sd-orange, #FF6B35)', fontWeight: 600 }}>{selected.name}</span>
|
|
1049
1072
|
{/* Not "strongest": the app knows nothing about how well they
|
|
1050
1073
|
know each other, only how this connection scores. */}
|
|
1051
1074
|
{i === 0 && n > 1 && (
|
|
1052
1075
|
<span style={{
|
|
1053
|
-
fontSize: 9, fontWeight: 700, color: '#FF6B35', padding: '1px 6px', borderRadius: 8,
|
|
1076
|
+
fontSize: 9, fontWeight: 700, color: 'var(--sd-orange, #FF6B35)', padding: '1px 6px', borderRadius: 8,
|
|
1054
1077
|
background: 'rgba(255,107,53,0.15)', whiteSpace: 'nowrap',
|
|
1055
1078
|
}}>top-scored bridge</span>
|
|
1056
1079
|
)}
|
|
1057
1080
|
</div>
|
|
1058
|
-
{about && <div style={{ fontSize: 11, color: '#888', marginTop: 3 }}>{about}</div>}
|
|
1081
|
+
{about && <div style={{ fontSize: 11, color: 'var(--sd-fg-3, #888)', marginTop: 3 }}>{about}</div>}
|
|
1059
1082
|
</div>
|
|
1060
1083
|
);
|
|
1061
1084
|
})}
|
|
@@ -1065,7 +1088,7 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
|
|
|
1065
1088
|
onClick={() => setShowAll((v) => !v)}
|
|
1066
1089
|
style={{
|
|
1067
1090
|
marginTop: 10, padding: '4px 10px', borderRadius: 6, cursor: 'pointer', fontSize: 11, fontWeight: 600,
|
|
1068
|
-
border: '1px solid rgba(255,107,53,0.35)', background: 'transparent', color: '#FF6B35',
|
|
1091
|
+
border: '1px solid rgba(255,107,53,0.35)', background: 'transparent', color: 'var(--sd-orange, #FF6B35)',
|
|
1069
1092
|
}}
|
|
1070
1093
|
>
|
|
1071
1094
|
{showAll ? 'Show fewer' : `Show all ${n}`}
|
|
@@ -1075,6 +1098,87 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
|
|
|
1075
1098
|
);
|
|
1076
1099
|
}
|
|
1077
1100
|
|
|
1101
|
+
const noWatch = () => () => {};
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* Where Resume would carry on with this person ({ nextPage, pagesRead, legacy };
|
|
1105
|
+
* null when there is nothing to carry on with; undefined until known), and
|
|
1106
|
+
* whether their circle is being scanned right now. One question to the server
|
|
1107
|
+
* for the whole card (GET /api/scraper?resume=<id>), asked again whenever a
|
|
1108
|
+
* scan ends, since every read moves it. Only those two facts are taken from the
|
|
1109
|
+
* scanner, never its whole answer: that changes every time a running scan's log
|
|
1110
|
+
* grows, and this panel would redraw with it.
|
|
1111
|
+
*/
|
|
1112
|
+
function useResume(person) {
|
|
1113
|
+
const id = person?.id ?? null;
|
|
1114
|
+
const subscribe = id ? watchScanner : noWatch;
|
|
1115
|
+
const lastEnded = useSyncExternalStore(subscribe, () => scannerNow().finished[0]?.startedAt ?? null, () => null);
|
|
1116
|
+
const scanning = useSyncExternalStore(subscribe, () => {
|
|
1117
|
+
const now = scannerNow();
|
|
1118
|
+
return Boolean(now.running && person && scansCircleOf(now, person));
|
|
1119
|
+
}, () => false);
|
|
1120
|
+
const [got, setGot] = useState({ id: null, resume: undefined });
|
|
1121
|
+
useEffect(() => {
|
|
1122
|
+
if (!id) return undefined;
|
|
1123
|
+
let live = true;
|
|
1124
|
+
resumePoint(id).then((r) => { if (live) setGot({ id, resume: r }); }, () => { if (live) setGot({ id, resume: null }); });
|
|
1125
|
+
return () => { live = false; };
|
|
1126
|
+
}, [id, lastEnded]);
|
|
1127
|
+
// Another person's answer never shows on this one's card while theirs is asked.
|
|
1128
|
+
return { resume: id && got.id === id ? got.resume : undefined, scanning: Boolean(id) && scanning };
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Resume, from anywhere on the card: bring the scan box into view and press its
|
|
1133
|
+
* own Resume, so the same checks run and the scan's log or any problem shows
|
|
1134
|
+
* where it's seen. While their scan runs (or Resume is greyed out) it only
|
|
1135
|
+
* brings the box into view, which says why.
|
|
1136
|
+
*/
|
|
1137
|
+
function resumeInScanBox(scanning = false) {
|
|
1138
|
+
const box = document.getElementById('scan-box');
|
|
1139
|
+
if (!box) return;
|
|
1140
|
+
box.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1141
|
+
box.animate?.([{ boxShadow: '0 0 0 3px rgba(255,215,0,0.75)' }, { boxShadow: '0 0 0 0 rgba(255,215,0,0)' }], { duration: 1600 });
|
|
1142
|
+
if (!scanning) box.querySelector('button[data-resume]:not([disabled])')?.click();
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* The line by their name when the read of their list stopped partway (Blake,
|
|
1147
|
+
* 2026-10-03: "if someone was scanned but not finished it needs to show that in
|
|
1148
|
+
* their profile card"). The scan box is far down the card, so this says it where
|
|
1149
|
+
* it's seen, and Resume here presses the box's own Resume: the same checks, and
|
|
1150
|
+
* the box, brought into view, is where the scan's log and any problem show.
|
|
1151
|
+
* While their scan runs it says so, and only takes you to the box.
|
|
1152
|
+
*/
|
|
1153
|
+
function StoppedPartway({ resume, scanning }) {
|
|
1154
|
+
const gold = 'var(--sd-gold, #FFD700)';
|
|
1155
|
+
return (
|
|
1156
|
+
<button type="button" onClick={() => resumeInScanBox(scanning)}
|
|
1157
|
+
aria-label={scanning ? 'Scanning their circle now: go to the scan' : `${stoppedLine(resume)}. Resume from page ${resume.nextPage}`}
|
|
1158
|
+
style={{
|
|
1159
|
+
display: 'flex', alignItems: 'center', gap: 9, width: '100%', boxSizing: 'border-box', margin: '-6px 0 16px',
|
|
1160
|
+
padding: '8px 11px', borderRadius: 8, cursor: 'pointer', textAlign: 'left', font: 'inherit',
|
|
1161
|
+
background: 'rgba(255,215,0,0.07)', border: '1px solid rgba(255,215,0,0.32)', color: 'var(--sd-fg-2, #ddd)',
|
|
1162
|
+
}}>
|
|
1163
|
+
{/* A pause sign while stopped; a pulsing dot while it runs. */}
|
|
1164
|
+
{scanning ? (
|
|
1165
|
+
// ScanLog's keyframes: the box below shows its log while their scan runs.
|
|
1166
|
+
<span aria-hidden="true" className="scanlog-dot" style={{ width: 8, height: 8, borderRadius: '50%', background: gold, flexShrink: 0, animation: 'scanlogPulse 1s ease-in-out infinite' }} />
|
|
1167
|
+
) : (
|
|
1168
|
+
<span aria-hidden="true" style={{ display: 'flex', gap: 2, flexShrink: 0 }}>
|
|
1169
|
+
<span style={{ width: 3, height: 10, borderRadius: 1, background: gold }} />
|
|
1170
|
+
<span style={{ width: 3, height: 10, borderRadius: 1, background: gold }} />
|
|
1171
|
+
</span>
|
|
1172
|
+
)}
|
|
1173
|
+
<span style={{ flex: 1, minWidth: 0, fontSize: 11.5, lineHeight: 1.35 }}>
|
|
1174
|
+
<b style={{ color: gold }}>{scanning ? 'Scanning their circle now' : `${stoppedLine(resume)}.`}</b>
|
|
1175
|
+
{!scanning && <span style={{ color: 'var(--sd-fg-3, #999)' }}> Their list isn't finished.</span>}
|
|
1176
|
+
</span>
|
|
1177
|
+
<span style={{ fontSize: 11.5, fontWeight: 800, color: gold, whiteSpace: 'nowrap' }}>{scanning ? 'See it β' : 'Resume β'}</span>
|
|
1178
|
+
</button>
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1078
1182
|
// Scan one person's circle, or carry on with it.
|
|
1079
1183
|
//
|
|
1080
1184
|
// LinkedIn lists someone else's connections in its own order, with no dates,
|
|
@@ -1085,11 +1189,18 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
|
|
|
1085
1189
|
// Whether a scan is running comes from the scanner (useScanner), not from this
|
|
1086
1190
|
// card: close the card mid-scan and open it again and the scan is still here,
|
|
1087
1191
|
// and every other card greys its buttons out until it ends.
|
|
1088
|
-
|
|
1192
|
+
//
|
|
1193
|
+
// `resume` is where Resume carries on (useResume, asked once for the card),
|
|
1194
|
+
// null when there is nothing to resume, undefined until it's known. A read that
|
|
1195
|
+
// stopped partway is the first thing the box says: SCAN IN PROGRESS, in gold,
|
|
1196
|
+
// with Resume as the main button (Blake, 2026-10-03: "if someone was scanned but
|
|
1197
|
+
// not finished it needs to show that in their profile card ... showing resume
|
|
1198
|
+
// scanner in that actual card"). It used to sit under CLUSTER ACTIVE, which
|
|
1199
|
+
// reads as done.
|
|
1200
|
+
function CreateClusterCard({ selected, degree2, resume }) {
|
|
1089
1201
|
const scan = useScanner();
|
|
1090
1202
|
const [checking, setChecking] = useState(false);
|
|
1091
1203
|
const [problem, setProblem] = useState(null); // why a scan didn't start: { text, offline }
|
|
1092
|
-
const [resume, setResume] = useState(undefined); // where Resume carries on; null: nothing to resume
|
|
1093
1204
|
const clusterCount = degree2?.filter(d => d.source_connection_id === selected.id).length || 0;
|
|
1094
1205
|
const hasCluster = clusterCount > 0;
|
|
1095
1206
|
|
|
@@ -1097,14 +1208,6 @@ function CreateClusterCard({ selected, degree2 }) {
|
|
|
1097
1208
|
const busy = scan.running && !mine ? busyReason(scan) : null;
|
|
1098
1209
|
const last = scan.finished.find((j) => scansCircleOf(j, selected));
|
|
1099
1210
|
|
|
1100
|
-
// Every read moves where Resume would carry on, so ask again whenever one ends.
|
|
1101
|
-
const lastEnded = scan.finished[0]?.startedAt ?? null;
|
|
1102
|
-
useEffect(() => {
|
|
1103
|
-
let live = true;
|
|
1104
|
-
resumePoint(selected.id).then((r) => { if (live) setResume(r); }, () => { if (live) setResume(null); });
|
|
1105
|
-
return () => { live = false; };
|
|
1106
|
-
}, [selected.id, lastEnded]);
|
|
1107
|
-
|
|
1108
1211
|
async function start(action) {
|
|
1109
1212
|
setProblem(null);
|
|
1110
1213
|
setChecking(true);
|
|
@@ -1122,27 +1225,32 @@ function CreateClusterCard({ selected, degree2 }) {
|
|
|
1122
1225
|
}
|
|
1123
1226
|
|
|
1124
1227
|
const read = hasCluster || Boolean(resume);
|
|
1125
|
-
|
|
1228
|
+
// Gold while a read is stopped partway, green once a circle is in, purple before.
|
|
1229
|
+
const accent = resume ? '#FFD700' : hasCluster ? '#00ff88' : '#9B59B6';
|
|
1230
|
+
// Gold words vanish on a light look; the theme's own gold reads on either.
|
|
1231
|
+
const ink = resume ? 'var(--sd-gold, #FFD700)' : accent;
|
|
1126
1232
|
const off = Boolean(busy) || checking;
|
|
1127
1233
|
const button = (primary) => ({
|
|
1128
1234
|
flex: 1, padding: '11px 8px', borderRadius: 8, fontWeight: 700, fontSize: primary ? 13 : 12,
|
|
1129
1235
|
cursor: off ? 'not-allowed' : 'pointer', opacity: off ? 0.45 : 1,
|
|
1130
1236
|
...(primary
|
|
1131
1237
|
? { border: 'none', background: 'linear-gradient(135deg, #9B59B6, #3498DB)', color: '#fff' }
|
|
1132
|
-
: { border: `1px solid ${accent}55`, background: `${accent}14`, color:
|
|
1238
|
+
: { border: `1px solid ${accent}55`, background: `${accent}14`, color: ink }),
|
|
1133
1239
|
});
|
|
1134
1240
|
|
|
1135
1241
|
return (
|
|
1136
1242
|
<div id="scan-box" style={{
|
|
1137
|
-
background: hasCluster ? 'rgba(0,255,136,0.06)' : 'rgba(155,89,182,0.08)',
|
|
1138
|
-
border: `1px solid ${hasCluster ? 'rgba(0,255,136,0.2)' : 'rgba(155,89,182,0.3)'}`,
|
|
1243
|
+
background: resume ? 'rgba(255,215,0,0.06)' : hasCluster ? 'rgba(0,255,136,0.06)' : 'rgba(155,89,182,0.08)',
|
|
1244
|
+
border: `1px solid ${resume ? 'rgba(255,215,0,0.32)' : hasCluster ? 'rgba(0,255,136,0.2)' : 'rgba(155,89,182,0.3)'}`,
|
|
1139
1245
|
borderRadius: 10, padding: 16, marginTop: 16,
|
|
1140
1246
|
}}>
|
|
1141
|
-
<div style={{ fontSize: 10, color:
|
|
1142
|
-
{
|
|
1247
|
+
<div style={{ fontSize: 10, color: ink, fontWeight: 700, letterSpacing: 1, marginBottom: 4, textAlign: 'center' }}>
|
|
1248
|
+
{scanBoxTitle({ resume, hasCluster })}
|
|
1143
1249
|
</div>
|
|
1144
|
-
<div style={{ fontSize: 12, color: '#aaa', marginBottom: 12, textAlign: 'center' }}>
|
|
1145
|
-
{
|
|
1250
|
+
<div style={{ fontSize: 12, color: 'var(--sd-fg-3, #aaa)', marginBottom: 12, textAlign: 'center' }}>
|
|
1251
|
+
{resume
|
|
1252
|
+
? (hasCluster ? `${clusterCount} connections mapped so far` : 'Their list is only partly read')
|
|
1253
|
+
: hasCluster
|
|
1146
1254
|
? `${clusterCount} connections mapped in Six Degrees`
|
|
1147
1255
|
: <>Scan {selected.name}'s connections to map their network</>}
|
|
1148
1256
|
</div>
|
|
@@ -1151,15 +1259,15 @@ function CreateClusterCard({ selected, degree2 }) {
|
|
|
1151
1259
|
<ScanLog title={scan.pending ? 'Startingβ¦' : `Scanning ${selected.name}βs circleβ¦`} log={scan.log} />
|
|
1152
1260
|
) : problem?.offline ? (
|
|
1153
1261
|
<>
|
|
1154
|
-
<div style={{ padding: '10px', borderRadius: 8, background: 'rgba(255,80,80,0.1)', border: '1px solid rgba(255,80,80,0.3)', color: '#ff5050', fontSize: 12, marginBottom: 8, textAlign: 'center' }}>
|
|
1262
|
+
<div style={{ padding: '10px', borderRadius: 8, background: 'rgba(255,80,80,0.1)', border: '1px solid rgba(255,80,80,0.3)', color: 'var(--sd-red, #ff5050)', fontSize: 12, marginBottom: 8, textAlign: 'center' }}>
|
|
1155
1263
|
Scanner offline
|
|
1156
1264
|
</div>
|
|
1157
|
-
<div style={{ fontSize: 10, color: '#888', textAlign: 'center', marginBottom: 8 }}>
|
|
1265
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', textAlign: 'center', marginBottom: 8 }}>
|
|
1158
1266
|
{problem.text} Open the <strong>Scan</strong> page to finish setting the scanner up.
|
|
1159
1267
|
</div>
|
|
1160
1268
|
<button onClick={() => setProblem(null)} style={{
|
|
1161
1269
|
width: '100%', padding: '10px', borderRadius: 8, border: 'none', cursor: 'pointer',
|
|
1162
|
-
background: 'rgba(255,255,255,0.1)', color: '#aaa', fontWeight: 600, fontSize: 12,
|
|
1270
|
+
background: 'rgba(var(--sd-ink, 255, 255, 255), 0.1)', color: 'var(--sd-fg-3, #aaa)', fontWeight: 600, fontSize: 12,
|
|
1163
1271
|
}}>
|
|
1164
1272
|
Retry
|
|
1165
1273
|
</button>
|
|
@@ -1169,7 +1277,8 @@ function CreateClusterCard({ selected, degree2 }) {
|
|
|
1169
1277
|
{last && <LastRead job={last} />}
|
|
1170
1278
|
<div style={{ display: 'flex', gap: 8 }}>
|
|
1171
1279
|
{resume && (
|
|
1172
|
-
|
|
1280
|
+
// data-resume: the line by their name presses this one (StoppedPartway).
|
|
1281
|
+
<button data-resume onClick={() => start('resume')} disabled={off} style={button(true)}>
|
|
1173
1282
|
Resume from page {resume.nextPage}
|
|
1174
1283
|
</button>
|
|
1175
1284
|
)}
|
|
@@ -1178,19 +1287,19 @@ function CreateClusterCard({ selected, degree2 }) {
|
|
|
1178
1287
|
</button>
|
|
1179
1288
|
</div>
|
|
1180
1289
|
{resume && (
|
|
1181
|
-
<div style={{ fontSize: 10, color: '#888', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
|
|
1290
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
|
|
1182
1291
|
Read to page {resume.pagesRead} so far. Resume carries on from page {resume.nextPage}. LinkedIn
|
|
1183
1292
|
lists their connections in its own order, not by date, so Rescan reads them all again from page 1.
|
|
1184
1293
|
</div>
|
|
1185
1294
|
)}
|
|
1186
1295
|
{hasCluster && resume === null && (
|
|
1187
|
-
<div style={{ fontSize: 10, color: '#888', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
|
|
1296
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
|
|
1188
1297
|
Their whole list has been read. LinkedIn doesn't date other people's connections, so a
|
|
1189
1298
|
rescan reads it all again to find anyone new.
|
|
1190
1299
|
</div>
|
|
1191
1300
|
)}
|
|
1192
1301
|
{busy && (
|
|
1193
|
-
<div style={{ fontSize: 10, color: '#bbb', marginTop: 8, textAlign: 'center' }}>
|
|
1302
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-2, #bbb)', marginTop: 8, textAlign: 'center' }}>
|
|
1194
1303
|
{busy}. One scan at a time: this one can start when it finishes.
|
|
1195
1304
|
</div>
|
|
1196
1305
|
)}
|
|
@@ -1203,18 +1312,18 @@ function CreateClusterCard({ selected, degree2 }) {
|
|
|
1203
1312
|
);
|
|
1204
1313
|
}
|
|
1205
1314
|
|
|
1206
|
-
// In place of the Scan buttons while the sample or a CSV import is open.
|
|
1207
|
-
//
|
|
1208
|
-
// person up
|
|
1315
|
+
// In place of the Scan buttons while the sample or a CSV import is open.
|
|
1316
|
+
// Neither is in the database, so a scan could only fail: the scanner looks the
|
|
1317
|
+
// person up there, and says "Bridge 'β¦' not found in database".
|
|
1209
1318
|
function ScansNeedYourNetwork({ csvSource, style }) {
|
|
1210
1319
|
return (
|
|
1211
1320
|
<div style={{
|
|
1212
|
-
padding: '10px 12px', borderRadius: 8, fontSize: 11, color: '#999', lineHeight: 1.5, textAlign: 'center',
|
|
1213
|
-
background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.08)', ...style,
|
|
1321
|
+
padding: '10px 12px', borderRadius: 8, fontSize: 11, color: 'var(--sd-fg-3, #999)', lineHeight: 1.5, textAlign: 'center',
|
|
1322
|
+
background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.08)', ...style,
|
|
1214
1323
|
}}>
|
|
1215
1324
|
{csvSource === 'sample'
|
|
1216
1325
|
? 'Scanning needs your own network: everyone in the sample is invented.'
|
|
1217
|
-
: 'Scanning needs your own network
|
|
1326
|
+
: 'Scanning needs your own network, not a CSV import. Remove the import (Γ at the top) and open Scan.'}
|
|
1218
1327
|
</div>
|
|
1219
1328
|
);
|
|
1220
1329
|
}
|
|
@@ -1229,9 +1338,9 @@ function ScanLog({ title, log, small = false }) {
|
|
|
1229
1338
|
{/* Its own keyframes: the 'pulse' this named was never defined anywhere, so the dot sat still. */}
|
|
1230
1339
|
<style>{'@keyframes scanlogPulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } } @media (prefers-reduced-motion: reduce) { .scanlog-dot { animation: none !important; } }'}</style>
|
|
1231
1340
|
<div className="scanlog-dot" style={{ width: small ? 6 : 8, height: small ? 6 : 8, borderRadius: '50%', background: '#9B59B6', animation: 'scanlogPulse 1s ease-in-out infinite' }} />
|
|
1232
|
-
<span style={{ fontSize: 11, fontWeight: 600, color: '#9B59B6' }}>{title}</span>
|
|
1341
|
+
<span style={{ fontSize: 11, fontWeight: 600, color: 'var(--sd-purple, #9B59B6)' }}>{title}</span>
|
|
1233
1342
|
</div>
|
|
1234
|
-
<div style={{ fontFamily: 'monospace', fontSize: small ? 9 : 10, color: '#888', maxHeight: small ? 80 : 100, overflow: 'auto' }}>
|
|
1343
|
+
<div style={{ fontFamily: 'monospace', fontSize: small ? 9 : 10, color: 'var(--sd-fg-3, #888)', maxHeight: small ? 80 : 100, overflow: 'auto' }}>
|
|
1235
1344
|
{log.slice(-40).map((l, i) => <div key={i}>{l}</div>)}
|
|
1236
1345
|
</div>
|
|
1237
1346
|
</div>
|
|
@@ -1247,7 +1356,7 @@ function LastRead({ job, who = null }) {
|
|
|
1247
1356
|
padding: '8px 10px', borderRadius: 8, marginBottom: 10, fontSize: 11, textAlign: 'center', lineHeight: 1.4,
|
|
1248
1357
|
background: ok ? 'rgba(0,255,136,0.08)' : 'rgba(255,80,80,0.08)',
|
|
1249
1358
|
border: `1px solid ${ok ? 'rgba(0,255,136,0.25)' : 'rgba(255,80,80,0.25)'}`,
|
|
1250
|
-
color: ok ? '#00ff88' : '#ff8080',
|
|
1359
|
+
color: ok ? 'var(--sd-green, #00ff88)' : '#ff8080',
|
|
1251
1360
|
}}>
|
|
1252
1361
|
{ok
|
|
1253
1362
|
? `${who ? `${who}βs circle` : 'The scan'} finished. What it found is on the map.`
|
|
@@ -1261,7 +1370,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1261
1370
|
|
|
1262
1371
|
return (
|
|
1263
1372
|
<div style={{
|
|
1264
|
-
background: 'rgba(255,255,255,0.05)', borderRadius: 6,
|
|
1373
|
+
background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', borderRadius: 6,
|
|
1265
1374
|
borderLeft: `3px solid ${tierColors[cs.bridge.tier] || '#FF6B35'}`,
|
|
1266
1375
|
overflow: 'hidden',
|
|
1267
1376
|
}}>
|
|
@@ -1280,34 +1389,34 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1280
1389
|
) : (
|
|
1281
1390
|
<div style={{
|
|
1282
1391
|
width: 28, height: 28, borderRadius: '50%', flexShrink: 0, fontSize: 11, fontWeight: 700,
|
|
1283
|
-
background: tierColors[cs.bridge.tier] || '#555', color: cs.bridge.tier === 'S' ? '#000' : '#fff',
|
|
1392
|
+
background: tierColors[cs.bridge.tier] || '#555', color: cs.bridge.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
1284
1393
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1285
1394
|
}}>{cs.bridge.name?.charAt(0)}</div>
|
|
1286
1395
|
)}
|
|
1287
1396
|
<div>
|
|
1288
1397
|
<div style={{ fontWeight: 600, fontSize: 12 }}>
|
|
1289
|
-
<span style={{ color: '#555', marginRight: 4 }}>#{rank}</span>{cs.bridge.name}
|
|
1398
|
+
<span style={{ color: 'var(--sd-fg-5, #555)', marginRight: 4 }}>#{rank}</span>{cs.bridge.name}
|
|
1290
1399
|
</div>
|
|
1291
|
-
<div style={{ fontSize: 9, color: '#666' }}>{cs.bridge.headline?.substring(0, 40)}</div>
|
|
1400
|
+
<div style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)' }}>{cs.bridge.headline?.substring(0, 40)}</div>
|
|
1292
1401
|
</div>
|
|
1293
1402
|
</div>
|
|
1294
1403
|
<span style={{
|
|
1295
1404
|
fontSize: 10, fontWeight: 700, padding: '2px 6px', borderRadius: 4,
|
|
1296
|
-
background: tierColors[cs.bridge.tier], color: cs.bridge.tier === 'S' ? '#000' : '#fff',
|
|
1405
|
+
background: tierColors[cs.bridge.tier], color: cs.bridge.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
1297
1406
|
}}>{cs.bridge.tier}</span>
|
|
1298
1407
|
</div>
|
|
1299
1408
|
<div style={{ display: 'flex', gap: 6, marginTop: 6, fontSize: 10 }}>
|
|
1300
|
-
{cs.sCount > 0 && <span style={{ color: '#FFD700', fontWeight: 600 }}>{cs.sCount}S{cs.sAvgPower > 0 ? ` (${cs.sAvgPower.toFixed(1)})` : ''}</span>}
|
|
1301
|
-
{cs.aCount > 0 && <span style={{ color: '#9B59B6', fontWeight: 600 }}>{cs.aCount}A</span>}
|
|
1302
|
-
{cs.bCount > 0 && <span style={{ color: '#3498DB' }}>{cs.bCount}B</span>}
|
|
1409
|
+
{cs.sCount > 0 && <span style={{ color: 'var(--sd-gold, #FFD700)', fontWeight: 600 }}>{cs.sCount}S{cs.sAvgPower > 0 ? ` (${cs.sAvgPower.toFixed(1)})` : ''}</span>}
|
|
1410
|
+
{cs.aCount > 0 && <span style={{ color: 'var(--sd-purple, #9B59B6)', fontWeight: 600 }}>{cs.aCount}A</span>}
|
|
1411
|
+
{cs.bCount > 0 && <span style={{ color: 'var(--sd-blue, #3498DB)' }}>{cs.bCount}B</span>}
|
|
1303
1412
|
{cs.risingCount > 0 && <span style={{ color: '#2ECC71' }}>{cs.risingCount} rising</span>}
|
|
1304
|
-
<span style={{ color: '#555' }}>{cs.members} total</span>
|
|
1413
|
+
<span style={{ color: 'var(--sd-fg-5, #555)' }}>{cs.members} total</span>
|
|
1305
1414
|
</div>
|
|
1306
1415
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 4, fontSize: 10 }}>
|
|
1307
|
-
<span style={{ color: '#666' }}>
|
|
1416
|
+
<span style={{ color: 'var(--sd-fg-4, #666)' }}>
|
|
1308
1417
|
Elite: {(cs.elitePct * 100).toFixed(0)}% Β· Avg: {cs.avgPower.toFixed(1)}
|
|
1309
1418
|
</span>
|
|
1310
|
-
<span style={{ color: '#FF6B35', fontWeight: 700 }}>
|
|
1419
|
+
<span style={{ color: 'var(--sd-orange, #FF6B35)', fontWeight: 700 }}>
|
|
1311
1420
|
{cs.clusterValue.toFixed(1)}
|
|
1312
1421
|
</span>
|
|
1313
1422
|
</div>
|
|
@@ -1326,13 +1435,13 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1326
1435
|
) : (
|
|
1327
1436
|
<div key={m.id} style={{
|
|
1328
1437
|
width: 22, height: 22, borderRadius: '50%', fontSize: 9, fontWeight: 700,
|
|
1329
|
-
background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : '#fff',
|
|
1438
|
+
background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
1330
1439
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1331
1440
|
}} title={m.name}>{m.name?.charAt(0)}</div>
|
|
1332
1441
|
)
|
|
1333
1442
|
))}
|
|
1334
1443
|
{(cs.sCount + cs.aCount) > 4 && (
|
|
1335
|
-
<span style={{ fontSize: 9, color: '#666' }}>+{cs.sCount + cs.aCount - 4} more</span>
|
|
1444
|
+
<span style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)' }}>+{cs.sCount + cs.aCount - 4} more</span>
|
|
1336
1445
|
)}
|
|
1337
1446
|
</div>
|
|
1338
1447
|
)}
|
|
@@ -1341,7 +1450,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1341
1450
|
<button
|
|
1342
1451
|
onClick={() => setExpanded(!expanded)}
|
|
1343
1452
|
style={{
|
|
1344
|
-
marginTop: 6, background: 'none', border: 'none', color: '#888',
|
|
1453
|
+
marginTop: 6, background: 'none', border: 'none', color: 'var(--sd-fg-3, #888)',
|
|
1345
1454
|
fontSize: 10, cursor: 'pointer', padding: 0, display: 'flex', alignItems: 'center', gap: 4,
|
|
1346
1455
|
}}
|
|
1347
1456
|
>
|
|
@@ -1353,7 +1462,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1353
1462
|
{/* Expanded member list */}
|
|
1354
1463
|
{expanded && (
|
|
1355
1464
|
<div style={{
|
|
1356
|
-
borderTop: '1px solid rgba(255,255,255,0.06)',
|
|
1465
|
+
borderTop: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.06)',
|
|
1357
1466
|
padding: '6px 10px 10px', maxHeight: 250, overflowY: 'auto',
|
|
1358
1467
|
}}>
|
|
1359
1468
|
{cs.topMembers.map(m => (
|
|
@@ -1364,7 +1473,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1364
1473
|
display: 'flex', alignItems: 'center', gap: 6, padding: '4px 2px',
|
|
1365
1474
|
cursor: 'pointer', borderRadius: 4,
|
|
1366
1475
|
}}
|
|
1367
|
-
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.06)'}
|
|
1476
|
+
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.06)'}
|
|
1368
1477
|
onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
|
|
1369
1478
|
>
|
|
1370
1479
|
{localPhoto(m.profile_image_url) ? (
|
|
@@ -1375,7 +1484,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
|
|
|
1375
1484
|
) : null}
|
|
1376
1485
|
<div style={{
|
|
1377
1486
|
width: 20, height: 20, borderRadius: '50%', flexShrink: 0, fontSize: 8, fontWeight: 700,
|
|
1378
|
-
background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : '#fff',
|
|
1487
|
+
background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
|
|
1379
1488
|
display: localPhoto(m.profile_image_url) ? 'none' : 'flex',
|
|
1380
1489
|
alignItems: 'center', justifyContent: 'center',
|
|
1381
1490
|
}}>{m.name?.charAt(0)}</div>
|
|
@@ -1405,13 +1514,13 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
|
|
|
1405
1514
|
|
|
1406
1515
|
// 1. Title leverage
|
|
1407
1516
|
if (role.match(/ceo|chief|founder|president|chairman/i)) {
|
|
1408
|
-
insights.push({ icon: 'π', text: `${person.role}
|
|
1517
|
+
insights.push({ icon: 'π', text: `${person.role}: C-suite executive, highest leverage contact`, color: 'var(--sd-gold, #FFD700)' });
|
|
1409
1518
|
} else if (role.match(/vp|vice president|svp|evp|managing director/i)) {
|
|
1410
|
-
insights.push({ icon: 'β‘', text: `${person.role}
|
|
1519
|
+
insights.push({ icon: 'β‘', text: `${person.role}: VP-level, strong decision-making authority`, color: 'var(--sd-gold, #FFD700)' });
|
|
1411
1520
|
} else if (role.match(/director|head of|senior director/i)) {
|
|
1412
|
-
insights.push({ icon: 'π―', text: `${person.role}
|
|
1521
|
+
insights.push({ icon: 'π―', text: `${person.role}: Senior leadership, controls team/budget`, color: 'var(--sd-orange, #FF6B35)' });
|
|
1413
1522
|
} else if (role.match(/manager|lead|principal/i)) {
|
|
1414
|
-
insights.push({ icon: 'π', text: `${person.role}
|
|
1523
|
+
insights.push({ icon: 'π', text: `${person.role}: Mid-senior, operational influence`, color: 'var(--sd-blue, #3498DB)' });
|
|
1415
1524
|
}
|
|
1416
1525
|
|
|
1417
1526
|
// 2β3. A top company now, and one before, by the model's own company scores
|
|
@@ -1421,28 +1530,28 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
|
|
|
1421
1530
|
// headline, so "Metadata Analyst" read as Meta and an ex-Googler as at Google.
|
|
1422
1531
|
const { now, before } = topCompanies(person);
|
|
1423
1532
|
if (now) {
|
|
1424
|
-
insights.push({ icon: 'π’', text: `At ${now.name} (${now.score}/10)
|
|
1533
|
+
insights.push({ icon: 'π’', text: `At ${now.name} (${now.score}/10): top-tier company network access`, color: 'var(--sd-purple, #9B59B6)' });
|
|
1425
1534
|
}
|
|
1426
1535
|
if (before) {
|
|
1427
|
-
insights.push({ icon: 'π', text: `Former ${before.name} (${before.score}/10)
|
|
1536
|
+
insights.push({ icon: 'π', text: `Former ${before.name} (${before.score}/10): carries network from previous role`, color: 'var(--sd-fg-3, #95A5A6)' });
|
|
1428
1537
|
}
|
|
1429
1538
|
|
|
1430
1539
|
// 4. Sector overlap with user
|
|
1431
1540
|
const matchingSectors = userSectors.filter(s => headline.includes(s) || company.includes(s));
|
|
1432
1541
|
if (matchingSectors.length > 0) {
|
|
1433
|
-
insights.push({ icon: 'π', text: `Shared sector: ${matchingSectors.join(', ')}
|
|
1542
|
+
insights.push({ icon: 'π', text: `Shared sector: ${matchingSectors.join(', ')}: direct industry relevance to you`, color: '#2ECC71' });
|
|
1434
1543
|
}
|
|
1435
1544
|
|
|
1436
1545
|
// 5. Bridge / gateway value
|
|
1437
1546
|
const bridgeCount = degree2.filter(d => d.source_connection_id === person.id).length;
|
|
1438
1547
|
if (bridgeCount > 0) {
|
|
1439
1548
|
const bridgeSCount = degree2.filter(d => d.source_connection_id === person.id && d.tier === 'S').length;
|
|
1440
|
-
insights.push({ icon: 'π', text: `Gateway to ${bridgeCount} degree-2 connections${bridgeSCount > 0 ? ` (${bridgeSCount} S-tier)` : ''}`, color: '#FF6B35' });
|
|
1549
|
+
insights.push({ icon: 'π', text: `Gateway to ${bridgeCount} degree-2 connections${bridgeSCount > 0 ? ` (${bridgeSCount} S-tier)` : ''}`, color: 'var(--sd-orange, #FF6B35)' });
|
|
1441
1550
|
}
|
|
1442
1551
|
|
|
1443
1552
|
// 6. Catalyst
|
|
1444
1553
|
if (person.is_catalyst) {
|
|
1445
|
-
insights.push({ icon: 'β‘', text: `Catalyst
|
|
1554
|
+
insights.push({ icon: 'β‘', text: `Catalyst: network power exceeds personal tier, high stepping-stone value`, color: 'var(--sd-green, #00ff88)' });
|
|
1446
1555
|
}
|
|
1447
1556
|
|
|
1448
1557
|
// 7. Every way in (degree 2). Built from the merged routes, so it can never
|
|
@@ -1452,8 +1561,8 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
|
|
|
1452
1561
|
const named = routes.filter(r => r.bridge);
|
|
1453
1562
|
if (routes.length === 1) {
|
|
1454
1563
|
insights.push(named.length
|
|
1455
|
-
? { icon: 'π€', text: `Reachable via ${named[0].bridge.name} (${named[0].bridge.tier}-tier)`, color: '#3498DB' }
|
|
1456
|
-
: { icon: 'π€', text: 'Reachable through a connection we canβt name', color: '#888' });
|
|
1564
|
+
? { icon: 'π€', text: `Reachable via ${named[0].bridge.name} (${named[0].bridge.tier}-tier)`, color: 'var(--sd-blue, #3498DB)' }
|
|
1565
|
+
: { icon: 'π€', text: 'Reachable through a connection we canβt name', color: 'var(--sd-fg-3, #888)' });
|
|
1457
1566
|
} else {
|
|
1458
1567
|
const firstName = (n) => String(n || '').trim().split(/\s+/)[0];
|
|
1459
1568
|
const names = named.slice(0, 2).map(r => `${firstName(r.bridge.name)} (${r.bridge.tier})`);
|
|
@@ -1461,13 +1570,13 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
|
|
|
1461
1570
|
const via = names.length === 0 ? 'connections we canβt name'
|
|
1462
1571
|
: more > 0 ? `${names.join(', ')} and ${more} more`
|
|
1463
1572
|
: names.join(' and ');
|
|
1464
|
-
insights.push({ icon: 'π€', text: `Reachable ${routes.length} ways
|
|
1573
|
+
insights.push({ icon: 'π€', text: `Reachable ${routes.length} ways, via ${via}`, color: 'var(--sd-blue, #3498DB)' });
|
|
1465
1574
|
}
|
|
1466
1575
|
}
|
|
1467
1576
|
|
|
1468
1577
|
// Fallback if no insights generated
|
|
1469
1578
|
if (insights.length === 0) {
|
|
1470
|
-
insights.push({ icon: 'π', text: `${person.tier}-tier connection with ${parseFloat(person.power_score).toFixed(1)} power score`, color: '#888' });
|
|
1579
|
+
insights.push({ icon: 'π', text: `${person.tier}-tier connection with ${parseFloat(person.power_score).toFixed(1)} power score`, color: 'var(--sd-fg-3, #888)' });
|
|
1471
1580
|
}
|
|
1472
1581
|
|
|
1473
1582
|
return insights.slice(0, 5); // Max 5 insights
|
|
@@ -1510,10 +1619,10 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1510
1619
|
background: 'rgba(0,255,136,0.05)', border: '1px solid rgba(0,255,136,0.2)',
|
|
1511
1620
|
borderRadius: 10, padding: 14, marginBottom: 16,
|
|
1512
1621
|
}}>
|
|
1513
|
-
<div style={{ fontSize: 12, fontWeight: 800, color: '#00ff88', marginBottom: 4 }}>
|
|
1622
|
+
<div style={{ fontSize: 12, fontWeight: 800, color: 'var(--sd-green, #00ff88)', marginBottom: 4 }}>
|
|
1514
1623
|
Ready to scan ({ready.length})
|
|
1515
1624
|
</div>
|
|
1516
|
-
<div style={{ fontSize: 10.5, color: '#999', lineHeight: 1.5, marginBottom: 10 }}>
|
|
1625
|
+
<div style={{ fontSize: 10.5, color: 'var(--sd-fg-3, #999)', lineHeight: 1.5, marginBottom: 10 }}>
|
|
1517
1626
|
People you added through a circle whose own circle isn't scanned yet. Scanning one
|
|
1518
1627
|
brings in who they know: 3rd degree, through the circle you found them in.
|
|
1519
1628
|
</div>
|
|
@@ -1525,7 +1634,7 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1525
1634
|
) : last && <LastRead job={last} who={last.target?.name} />}
|
|
1526
1635
|
|
|
1527
1636
|
{ready.length === 0 ? (
|
|
1528
|
-
<div style={{ fontSize: 11, color: '#aaa', lineHeight: 1.5 }}>
|
|
1637
|
+
<div style={{ fontSize: 11, color: 'var(--sd-fg-3, #aaa)', lineHeight: 1.5 }}>
|
|
1529
1638
|
Nobody yet. When someone you asked from a circle accepts, β» <b>Check for new</b> brings
|
|
1530
1639
|
them into your connections, and they show here.
|
|
1531
1640
|
</div>
|
|
@@ -1539,20 +1648,20 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1539
1648
|
aria-label={`Scan ${p.name}βs circle: opens the Scan page to confirm`}
|
|
1540
1649
|
style={{
|
|
1541
1650
|
display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px', borderRadius: 8,
|
|
1542
|
-
textDecoration: 'none', color: '#fff',
|
|
1543
|
-
background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(0,255,136,0.18)',
|
|
1651
|
+
textDecoration: 'none', color: 'var(--sd-fg-1, #fff)',
|
|
1652
|
+
background: 'rgba(var(--sd-ink, 255, 255, 255), 0.04)', border: '1px solid rgba(0,255,136,0.18)',
|
|
1544
1653
|
}}>
|
|
1545
1654
|
<span style={{ width: 8, height: 8, borderRadius: '50%', flexShrink: 0, background: tierColors[p.tier] || '#888', boxShadow: '0 0 0 2px rgba(0,255,136,0.45)' }} />
|
|
1546
1655
|
<span style={{ flex: 1, minWidth: 0 }}>
|
|
1547
1656
|
<span style={{ fontSize: 12, fontWeight: 700 }}>{p.name}</span>
|
|
1548
1657
|
<span style={{ fontSize: 10, color: tierColors[p.tier] || '#888', fontWeight: 700, marginLeft: 6 }}>{p.tier}</span>
|
|
1549
1658
|
{from && (
|
|
1550
|
-
<span style={{ display: 'block', fontSize: 10, color: '#888', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
1659
|
+
<span style={{ display: 'block', fontSize: 10, color: 'var(--sd-fg-3, #888)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
1551
1660
|
was in {first(from)}'s circle
|
|
1552
1661
|
</span>
|
|
1553
1662
|
)}
|
|
1554
1663
|
</span>
|
|
1555
|
-
<span style={{ fontSize: 10.5, fontWeight: 700, color: '#00ff88', whiteSpace: 'nowrap' }}>
|
|
1664
|
+
<span style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--sd-green, #00ff88)', whiteSpace: 'nowrap' }}>
|
|
1556
1665
|
{now ? 'Scanningβ¦' : 'Scanβ¦ β'}
|
|
1557
1666
|
</span>
|
|
1558
1667
|
</Link>
|
|
@@ -1560,7 +1669,7 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1560
1669
|
})}
|
|
1561
1670
|
{ready.length > 5 && (
|
|
1562
1671
|
<button type="button" onClick={() => setAll((v) => !v)} style={{
|
|
1563
|
-
background: 'none', border: 'none', color: '#888', fontSize: 10.5, fontWeight: 600, cursor: 'pointer', padding: '2px 0', textAlign: 'left',
|
|
1672
|
+
background: 'none', border: 'none', color: 'var(--sd-fg-3, #888)', fontSize: 10.5, fontWeight: 600, cursor: 'pointer', padding: '2px 0', textAlign: 'left',
|
|
1564
1673
|
}}>
|
|
1565
1674
|
{all ? 'Show fewer' : `Show all ${ready.length}`}
|
|
1566
1675
|
</button>
|
|
@@ -1569,7 +1678,7 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1569
1678
|
)}
|
|
1570
1679
|
|
|
1571
1680
|
{ready.length > 0 && (
|
|
1572
|
-
<div style={{ fontSize: 10, color: '#888', lineHeight: 1.5, marginTop: 8 }}>
|
|
1681
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', lineHeight: 1.5, marginTop: 8 }}>
|
|
1573
1682
|
Each scan: {cost.profileViews} profile view, then one LinkedIn search for every page of their
|
|
1574
1683
|
list, up to {cost.searches} pages (about {cost.minutes} min for a whole list). Nothing starts
|
|
1575
1684
|
until you confirm it on the Scan page.
|
|
@@ -1577,10 +1686,10 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1577
1686
|
)}
|
|
1578
1687
|
|
|
1579
1688
|
{hidden.length > 0 && (
|
|
1580
|
-
<div style={{ marginTop: 10, fontSize: 10.5, color: '#777', lineHeight: 1.6 }}>
|
|
1689
|
+
<div style={{ marginTop: 10, fontSize: 10.5, color: 'var(--sd-fg-4, #777)', lineHeight: 1.6 }}>
|
|
1581
1690
|
{hidden.slice(0, 3).map((p) => (
|
|
1582
1691
|
<div key={p.id} style={{ opacity: 0.7 }}>
|
|
1583
|
-
<span aria-hidden="true">π</span> {p.name} <span style={{ color: '#666' }}>Β· their list is hidden</span>
|
|
1692
|
+
<span aria-hidden="true">π</span> {p.name} <span style={{ color: 'var(--sd-fg-4, #666)' }}>Β· their list is hidden</span>
|
|
1584
1693
|
</div>
|
|
1585
1694
|
))}
|
|
1586
1695
|
{hidden.length > 3 && <div style={{ opacity: 0.7 }}>π and {hidden.length - 3} more with hidden lists</div>}
|
|
@@ -1588,13 +1697,13 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
|
|
|
1588
1697
|
)}
|
|
1589
1698
|
|
|
1590
1699
|
{others > 0 && (
|
|
1591
|
-
<div style={{ fontSize: 10.5, color: '#888', lineHeight: 1.5, marginTop: 10 }}>
|
|
1700
|
+
<div style={{ fontSize: 10.5, color: 'var(--sd-fg-3, #888)', lineHeight: 1.5, marginTop: 10 }}>
|
|
1592
1701
|
{others.toLocaleString('en-US')} of your other connections aren't scanned yet.{' '}
|
|
1593
|
-
<Link href="/setup" style={{ color: '#3498DB', textDecoration: 'none' }}>Map them in batches on the Scan page β</Link>
|
|
1702
|
+
<Link href="/setup" style={{ color: 'var(--sd-blue, #3498DB)', textDecoration: 'none' }}>Map them in batches on the Scan page β</Link>
|
|
1594
1703
|
</div>
|
|
1595
1704
|
)}
|
|
1596
1705
|
{busy && (
|
|
1597
|
-
<div style={{ fontSize: 10, color: '#bbb', marginTop: 8 }}>
|
|
1706
|
+
<div style={{ fontSize: 10, color: 'var(--sd-fg-2, #bbb)', marginTop: 8 }}>
|
|
1598
1707
|
{busy}. One scan at a time.
|
|
1599
1708
|
</div>
|
|
1600
1709
|
)}
|