six-degrees 0.7.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +32 -4
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +16 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/admin-delete/route.js +1 -1
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js +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 +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js +4 -4
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +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 +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +18 -18
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +18 -18
- 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 +16 -16
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +19 -19
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +19 -19
- 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.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 +18 -18
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +18 -18
- 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 +16 -16
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths.html +1 -1
- package/.next/standalone/.next/server/app/paths.rsc +19 -19
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +19 -19
- 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 +16 -16
- 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 +19 -19
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +19 -19
- 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 +16 -16
- 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 +19 -19
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +19 -19
- 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 -20
- 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 +18 -18
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +18 -18
- 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 +16 -16
- 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 +19 -19
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +19 -19
- 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 +16 -16
- 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 +19 -19
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +19 -19
- 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 +16 -16
- 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 +18 -18
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +18 -18
- 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 +16 -16
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__063s0x7._.js → [root-of-the-server]__0r-0t-9._.js} +1 -1
- 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} +5 -2
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +9 -9
- package/.next/standalone/.next/server/chunks/{lib_rpc_0jnfp2e.js → lib_rpc_00nndai.js} +1 -1
- package/.next/standalone/.next/server/chunks/{lib_rpc_0b17r6v.js → lib_rpc_03ibb-x.js} +1 -1
- package/.next/standalone/.next/server/chunks/{lib_rpc_0doq0t-.js → lib_rpc_03ri3ji.js} +1 -1
- package/.next/standalone/.next/server/chunks/{lib_rpc_0fd2rlw.js → lib_rpc_078ce48.js} +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
- package/.next/standalone/.next/server/chunks/{lib_rpc_005abye.js → lib_rpc_0cej3t8.js} +1 -1
- 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_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_0is4qoc.js → lib_rpc_1hjjjr4.js} +1 -1
- 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/_04am_h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_1k9qfsk._.js → _14jak5s._.js} +6 -2
- package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0gy11ar._.js → _1r62six._.js} +6 -2
- 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_components_0uuff77._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_01o3i5y._.js → app_components_settings_SectorPicker_1c-29qw.js} +2 -6
- package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +14 -14
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +3 -3
- 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 +4 -4
- 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/0hggugbh84m4t.js +21 -0
- package/.next/{static/chunks/2eo9pqq9gay3r.js → standalone/.next/static/chunks/0ka4prpk3w9wn.js} +4 -4
- package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/{static/chunks/44yn0tcd9dfk3.js → standalone/.next/static/chunks/1bkt_hhjzvbh8.js} +1 -1
- package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/{static/chunks/1qbjermbf68xj.js → standalone/.next/static/chunks/1d8yv3k_atka7.js} +1 -1
- package/.next/standalone/.next/static/chunks/1ods5h86raivz.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/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
- package/.next/{static/chunks/2zf4jmz9l3li2.js → standalone/.next/static/chunks/2w-y83mjlpnse.js} +1 -1
- package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -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/{static/chunks/0an_b6zi1r_qq.js → standalone/.next/static/chunks/3y40z6of3r9py.js} +1 -5
- package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/.next/standalone/CHANGELOG.md +83 -0
- package/.next/standalone/README.md +40 -14
- package/.next/standalone/SECURITY.md +17 -4
- package/.next/standalone/app/api/outreach/route.js +13 -73
- package/.next/standalone/app/api/scraper/route.js +106 -5
- package/.next/standalone/app/components/AppHeader.js +22 -6
- package/.next/standalone/app/components/AppTabs.js +4 -0
- package/.next/standalone/app/components/AutoConnect.js +286 -0
- package/.next/standalone/app/components/ChainView.js +75 -2
- package/.next/standalone/app/components/FilterPanel.js +8 -1
- package/.next/standalone/app/components/LinkedInLimits.js +38 -13
- package/.next/standalone/app/components/OutlinkQuest.js +32 -11
- package/.next/standalone/app/components/ScanStatusBar.js +18 -3
- package/.next/standalone/app/components/ScanTrail.js +13 -3
- package/.next/standalone/app/components/SeparationView.js +6 -22
- package/.next/standalone/app/components/Sidebar.js +147 -38
- 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/UsageSection.js +50 -3
- package/.next/standalone/app/globals.css +2 -3
- package/.next/standalone/app/insights/page.js +220 -0
- package/.next/standalone/app/page.js +1 -17
- package/.next/standalone/app/queue/page.js +30 -18
- package/.next/standalone/app/setup/page.js +71 -13
- package/.next/standalone/install.sh +7 -6
- package/.next/standalone/lib/auto-connect.js +145 -0
- package/.next/standalone/lib/companies.js +1 -1
- package/.next/standalone/lib/in-progress.js +46 -0
- package/.next/standalone/lib/insights-board.js +613 -0
- package/.next/standalone/lib/linkedin-limits.js +36 -11
- package/.next/standalone/lib/requests-client.js +10 -0
- package/.next/standalone/lib/requests.js +124 -0
- package/.next/standalone/lib/scan-state.js +1 -0
- package/.next/standalone/lib/scanner-setup.js +82 -3
- package/.next/standalone/lib/scraper-client.js +18 -5
- package/.next/standalone/lib/settings.js +6 -0
- package/.next/standalone/lib/usage.js +5 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/build-app.mjs +167 -11
- package/.next/standalone/scripts/build-desktop.mjs +3 -2
- package/.next/standalone/scripts/ci-mac-signing.sh +128 -0
- package/.next/standalone/scripts/entitlements/electron.plist +23 -0
- package/.next/standalone/scripts/entitlements/node.plist +27 -0
- package/.next/standalone/scripts/mac-sign.mjs +563 -0
- package/.next/standalone/scripts/make-dmg-background.mjs +2 -1
- package/.next/standalone/scripts/scrape.py +569 -9
- package/.next/standalone/scripts/set-signing-secrets.sh +96 -0
- package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
- package/.next/static/chunks/0hggugbh84m4t.js +21 -0
- package/.next/{standalone/.next/static/chunks/2eo9pqq9gay3r.js → static/chunks/0ka4prpk3w9wn.js} +4 -4
- package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/{standalone/.next/static/chunks/44yn0tcd9dfk3.js → static/chunks/1bkt_hhjzvbh8.js} +1 -1
- package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/{standalone/.next/static/chunks/1qbjermbf68xj.js → static/chunks/1d8yv3k_atka7.js} +1 -1
- package/.next/static/chunks/1ods5h86raivz.js +1 -0
- package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
- package/.next/{standalone/.next/static/chunks/2zf4jmz9l3li2.js → static/chunks/2w-y83mjlpnse.js} +1 -1
- package/.next/static/chunks/2ws1xf293j-tm.js +5 -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/{standalone/.next/static/chunks/0an_b6zi1r_qq.js → static/chunks/3y40z6of3r9py.js} +1 -5
- package/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/CHANGELOG.md +83 -0
- package/README.md +40 -14
- package/SECURITY.md +17 -4
- package/lib/auto-connect.js +145 -0
- package/lib/companies.js +1 -1
- package/lib/in-progress.js +46 -0
- package/lib/insights-board.js +613 -0
- package/lib/linkedin-limits.js +36 -11
- package/lib/requests-client.js +10 -0
- package/lib/requests.js +124 -0
- package/lib/scan-state.js +1 -0
- package/lib/scanner-setup.js +82 -3
- package/lib/scraper-client.js +18 -5
- package/lib/settings.js +6 -0
- package/lib/usage.js +5 -0
- package/package.json +1 -1
- package/scripts/scrape.py +569 -9
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_4y8z7._.js +0 -8
- package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
- package/.next/standalone/.next/server/chunks/lib_rpc_0nef_n7.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0plrzra.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_13a4m0c.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1if17c-.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1j-zw7v.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1sngt-q.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1v2sgme.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1vh-tgx.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1zaubz7.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_02sband._.js +0 -7
- package/.next/standalone/.next/server/chunks/ssr/_189g8lg._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
- package/.next/standalone/.next/static/chunks/0e3g0sil79cus.js +0 -21
- package/.next/standalone/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
- package/.next/standalone/.next/static/chunks/163b-20vwa06i.js +0 -34
- package/.next/standalone/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
- package/.next/standalone/.next/static/chunks/23_1z47al92nz.js +0 -57
- package/.next/standalone/.next/static/chunks/260bomtr214m8.js +0 -34
- package/.next/standalone/.next/static/chunks/2xk2ra4piiuod.js +0 -34
- package/.next/standalone/.next/static/chunks/3b0-14cxqsprt.js +0 -1
- package/.next/standalone/.next/static/chunks/3jarus1_38s2z.js +0 -1
- package/.next/standalone/.next/static/chunks/3ssu341hav_sq.css +0 -3
- package/.next/standalone/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
- package/.next/static/chunks/0e3g0sil79cus.js +0 -21
- package/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
- package/.next/static/chunks/163b-20vwa06i.js +0 -34
- package/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
- package/.next/static/chunks/23_1z47al92nz.js +0 -57
- package/.next/static/chunks/260bomtr214m8.js +0 -34
- package/.next/static/chunks/2xk2ra4piiuod.js +0 -34
- package/.next/static/chunks/3b0-14cxqsprt.js +0 -1
- package/.next/static/chunks/3jarus1_38s2z.js +0 -1
- package/.next/static/chunks/3ssu341hav_sq.css +0 -3
- package/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
- /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
- /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
- /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// Insights → People: the Power Index. Everyone within two steps of you, each
|
|
4
|
+
// once, ranked by power, with the filters above it and the rail of boards
|
|
5
|
+
// beside it (mock-up B). The table shows a hundred rows at a time (25 on a
|
|
6
|
+
// phone), so a network of thousands stays quick; ranks are the whole list's,
|
|
7
|
+
// so a filter never renumbers anyone.
|
|
8
|
+
|
|
9
|
+
import { memo, useDeferredValue, useMemo, useState } from 'react';
|
|
10
|
+
import { filterIndex, bandText } from '../../../lib/insights-board';
|
|
11
|
+
import { hasRequest } from '../../../lib/requests-client';
|
|
12
|
+
import { shortName, TIERS } from '../../../lib/separation';
|
|
13
|
+
import { RARITY, toggle } from '../../../lib/rarity';
|
|
14
|
+
import Avatar from '../Avatar';
|
|
15
|
+
import { TIER_COLORS } from '../../../lib/themes';
|
|
16
|
+
import {
|
|
17
|
+
fmt, one, TierChip, DegreeChip, RarityTag, PersonCell, Src, Hero, OpenCircle, ScanCircle, AskButton,
|
|
18
|
+
LINE, SOFT_LINE, CARD_BG, ELLIPSIS,
|
|
19
|
+
} from './parts';
|
|
20
|
+
import Rail from './Rail';
|
|
21
|
+
|
|
22
|
+
export const PAGE = 100;
|
|
23
|
+
const COLS = '58px minmax(0,1.55fr) 148px minmax(0,1.45fr) 118px 100px';
|
|
24
|
+
|
|
25
|
+
export default function PeopleView({ data, heavy, open, net, source, isMobile, onView, requests }) {
|
|
26
|
+
const { index } = data;
|
|
27
|
+
const [degree, setDegree] = useState('all');
|
|
28
|
+
const [tiers, setTiers] = useState(() => new Set());
|
|
29
|
+
const [rarities, setRarities] = useState(() => new Set());
|
|
30
|
+
const [query, setQuery] = useState('');
|
|
31
|
+
const q = useDeferredValue(query);
|
|
32
|
+
// A hundred rows at a time on a computer, twenty-five on a phone, where the boards sit under the table.
|
|
33
|
+
const step = isMobile ? 25 : PAGE;
|
|
34
|
+
const [pages, setPages] = useState(1);
|
|
35
|
+
const shown = pages * step;
|
|
36
|
+
const filtering = degree !== 'all' || tiers.size > 0 || rarities.size > 0 || q.trim() !== '';
|
|
37
|
+
const list = useMemo(() => (filtering ? filterIndex(index, { degree, tiers, rarities, query: q }) : index.people),
|
|
38
|
+
[index, filtering, degree, tiers, rarities, q]);
|
|
39
|
+
const bandAt = useMemo(() => new Map(index.bands.map((b) => [b.start, b])), [index]);
|
|
40
|
+
// A new filter starts from the top again.
|
|
41
|
+
const filterKey = `${degree}|${[...tiers].join()}|${[...rarities].join()}|${q}`;
|
|
42
|
+
const [lastKey, setLastKey] = useState(filterKey);
|
|
43
|
+
if (lastKey !== filterKey) { setLastKey(filterKey); setPages(1); }
|
|
44
|
+
|
|
45
|
+
const rows = list.slice(0, shown);
|
|
46
|
+
const left = list.length - rows.length;
|
|
47
|
+
const next = list[rows.length];
|
|
48
|
+
const sameTieLeft = next && rows.length && rows[rows.length - 1].score === next.score
|
|
49
|
+
? list.slice(rows.length).filter((p) => p.score === next.score).length : 0;
|
|
50
|
+
const scoped = source === 'own';
|
|
51
|
+
// No 2nd degree (a CSV import, or nothing scanned yet): no degree or rarity to filter by.
|
|
52
|
+
const second = index.counts.degree[2] > 0;
|
|
53
|
+
|
|
54
|
+
// "All →" on Hidden giants: the table, narrowed to them.
|
|
55
|
+
const showHidden = () => { setDegree(2); setTiers(new Set(['S'])); setRarities(new Set(['only'])); setQuery(''); window.scrollTo(0, 0); };
|
|
56
|
+
|
|
57
|
+
const filters = (
|
|
58
|
+
<div style={{
|
|
59
|
+
display: 'flex', alignItems: 'center', gap: isMobile ? 8 : 14, flexWrap: 'wrap', padding: isMobile ? '8px 10px' : '10px 12px',
|
|
60
|
+
border: `1px solid ${LINE}`, borderRadius: 12, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.025)', marginBottom: 14,
|
|
61
|
+
}}>
|
|
62
|
+
{second && (
|
|
63
|
+
<Group label="Degree" isMobile={isMobile}>
|
|
64
|
+
{[['all', 'All', index.total], [1, '1st', index.counts.degree[1]], [2, '2nd', index.counts.degree[2]]].map(([k, label, n]) => (
|
|
65
|
+
<Chip key={k} on={degree === k} onClick={() => setDegree(k)} count={n}>{label}</Chip>
|
|
66
|
+
))}
|
|
67
|
+
</Group>
|
|
68
|
+
)}
|
|
69
|
+
<Group label="Tier" isMobile={isMobile}>
|
|
70
|
+
{TIERS.map((t) => (
|
|
71
|
+
<Chip key={t} on={tiers.has(t)} onClick={() => setTiers((s) => toggle(s, t))} count={index.counts.tiers[t]} title={`${t} tier`}>
|
|
72
|
+
<TierChip tier={t} size={16} />
|
|
73
|
+
</Chip>
|
|
74
|
+
))}
|
|
75
|
+
</Group>
|
|
76
|
+
{second && (
|
|
77
|
+
<Group label="Rarity" isMobile={isMobile}>
|
|
78
|
+
{RARITY.map((r) => (
|
|
79
|
+
<Chip key={r.key} on={rarities.has(r.key)} onClick={() => setRarities((s) => toggle(s, r.key))} count={index.counts.rarity[r.key]}
|
|
80
|
+
title={`${r.label}: ${r.range} mutual connection${r.range === '1' ? '' : 's'}`}>
|
|
81
|
+
<i className="sd-dot-html" style={{ width: 7, height: 7, borderRadius: '50%', background: r.color, display: 'inline-block' }} />{r.label}
|
|
82
|
+
</Chip>
|
|
83
|
+
))}
|
|
84
|
+
</Group>
|
|
85
|
+
)}
|
|
86
|
+
<input type="search" value={query} onChange={(e) => setQuery(e.target.value)} aria-label="Search a name, company, or who knows them"
|
|
87
|
+
placeholder="Search a name or company" style={{
|
|
88
|
+
marginLeft: isMobile ? 0 : 'auto', width: isMobile ? '100%' : 240, height: isMobile ? 40 : 32, padding: '0 12px', borderRadius: 8, outline: 'none',
|
|
89
|
+
fontSize: isMobile ? 16 : 12.5, color: 'var(--sd-fg-1, #fff)', border: `1px solid ${LINE}`, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.04)',
|
|
90
|
+
}} />
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<>
|
|
96
|
+
<Hero title="The Power Index" isMobile={isMobile}>
|
|
97
|
+
{second
|
|
98
|
+
? <>Everyone within two steps of you, ranked by power: <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(index.total)}</b> people, each once.</>
|
|
99
|
+
: <>Your connections, ranked by power: <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(index.total)}</b> people.{' '}
|
|
100
|
+
{source === 'csv' ? 'A CSV import has no circles, so the people one step further out aren’t here.' : 'Scan their circles to add the people one step further out.'}</>}
|
|
101
|
+
</Hero>
|
|
102
|
+
{filters}
|
|
103
|
+
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'minmax(0,1fr) 370px', gap: 16, alignItems: 'start' }}>
|
|
104
|
+
<div style={{ border: `1px solid ${LINE}`, borderRadius: 14, background: CARD_BG, overflow: 'hidden', minWidth: 0 }}>
|
|
105
|
+
{!isMobile && (
|
|
106
|
+
<div style={{ display: 'grid', gridTemplateColumns: COLS, gap: 10, padding: '0 16px', alignItems: 'center', height: 36, borderBottom: `1px solid ${LINE}`, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.02)', fontSize: 10.5, color: 'var(--sd-fg-4, #6f7a88)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 700 }}>
|
|
107
|
+
<span>Rank</span><span>Person</span><span>Power</span><span>Way in</span><span>Rarity</span><span />
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
{rows.length === 0 && (
|
|
111
|
+
<div style={{ padding: '28px 16px', fontSize: 13, color: 'var(--sd-fg-3, #8b9a9a)' }}>Nobody matches these filters.</div>
|
|
112
|
+
)}
|
|
113
|
+
{rows.map((p, i) => {
|
|
114
|
+
const band = !filtering ? bandAt.get(i) : null;
|
|
115
|
+
return (
|
|
116
|
+
<div key={p.key}>
|
|
117
|
+
{band && <Band band={band} isMobile={isMobile} />}
|
|
118
|
+
<Row p={p} isMobile={isMobile} scoped={scoped} csv={source === 'csv'} asked={p.degree === 2 && hasRequest(p.row, requests)} />
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
})}
|
|
122
|
+
{left > 0 && (
|
|
123
|
+
<button type="button" onClick={() => setPages((n) => n + 1)} style={{
|
|
124
|
+
display: 'block', width: '100%', textAlign: 'left', padding: '12px 16px', border: 'none', borderBottom: `1px solid ${LINE}`,
|
|
125
|
+
background: 'transparent', cursor: 'pointer', fontSize: 12.5, fontWeight: 600, color: 'var(--sd-blue, #3498DB)',
|
|
126
|
+
}}>
|
|
127
|
+
Show {fmt(Math.min(step, left))} more →
|
|
128
|
+
<span style={{ color: 'var(--sd-fg-4, #6f7a88)', fontWeight: 400, marginLeft: 8 }}>
|
|
129
|
+
{sameTieLeft ? `${fmt(sameTieLeft)} more at ${one(next.score)}, ${fmt(left)} in all` : `${fmt(left)} to go`}
|
|
130
|
+
</span>
|
|
131
|
+
</button>
|
|
132
|
+
)}
|
|
133
|
+
<Src style={{ padding: '10px 16px 14px', marginTop: 0 }}>{index.source}</Src>
|
|
134
|
+
</div>
|
|
135
|
+
<Rail data={data} heavy={heavy} open={open} source={source} onView={onView} onHidden={showHidden} isMobile={isMobile} net={net} />
|
|
136
|
+
</div>
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function Group({ label, children, isMobile }) {
|
|
142
|
+
// On a phone each group is one row that scrolls sideways, rather than four rows of chips.
|
|
143
|
+
return (
|
|
144
|
+
<div style={{ display: 'flex', gap: 5, alignItems: 'center', flexWrap: isMobile ? 'nowrap' : 'wrap', minWidth: 0, ...(isMobile ? { overflowX: 'auto', width: '100%', scrollbarWidth: 'none' } : null) }}>
|
|
145
|
+
<span style={{ fontSize: 10.5, color: 'var(--sd-fg-4, #6f7a88)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 700, marginRight: 3 }}>{label}</span>
|
|
146
|
+
{children}
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function Chip({ on, onClick, count, children, title }) {
|
|
152
|
+
return (
|
|
153
|
+
<button type="button" aria-pressed={on} onClick={onClick} title={title} style={{
|
|
154
|
+
fontSize: 12, padding: '4px 9px', borderRadius: 16, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap',
|
|
155
|
+
border: `1px solid ${on ? 'rgba(var(--sd-ink, 255, 255, 255), 0.55)' : LINE}`,
|
|
156
|
+
background: on ? 'rgba(var(--sd-ink, 255, 255, 255), 0.12)' : 'rgba(var(--sd-ink, 255, 255, 255), 0.03)',
|
|
157
|
+
color: on ? 'var(--sd-fg-1, #fff)' : 'var(--sd-fg-2, #b8c4c4)', fontWeight: on ? 700 : 500,
|
|
158
|
+
}}>
|
|
159
|
+
{children}
|
|
160
|
+
{count != null && <small style={{ color: 'var(--sd-fg-4, #6f7a88)', fontSize: 11 }}>{fmt(count)}</small>}
|
|
161
|
+
</button>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** A tie of many: how many share the score, and the working most of them share. */
|
|
166
|
+
function Band({ band, isMobile }) {
|
|
167
|
+
const t = bandText(band);
|
|
168
|
+
const mixed = band.yours > 0 && band.yours < band.count;
|
|
169
|
+
return (
|
|
170
|
+
<div style={{
|
|
171
|
+
display: 'flex', alignItems: isMobile ? 'flex-start' : 'center', gap: 12, padding: isMobile ? '10px 12px' : '10px 16px',
|
|
172
|
+
background: 'linear-gradient(90deg, rgba(255,215,0,0.1), rgba(255,215,0,0.02))',
|
|
173
|
+
borderTop: '1px solid rgba(255,215,0,0.22)', borderBottom: '1px solid rgba(255,215,0,0.22)',
|
|
174
|
+
}}>
|
|
175
|
+
<span style={{ fontSize: 15, fontWeight: 800, color: 'var(--sd-gold, #FFD700)', fontVariantNumeric: 'tabular-nums', flexShrink: 0 }}>#{fmt(band.rank)}=</span>
|
|
176
|
+
<span style={{ fontSize: 12.5, color: 'var(--sd-fg-1, #e9edf3)', lineHeight: 1.45 }}>
|
|
177
|
+
<b>{t.head}</b> {t.rest}{' '}
|
|
178
|
+
<span style={{ color: 'var(--sd-fg-3, #8b9a9a)' }}>{mixed ? 'Yours first, then most ways in.' : band.yours ? 'All yours.' : 'Most ways in first.'}</span>
|
|
179
|
+
</span>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** One person: rank, who, power, way in, rarity and what to do. */
|
|
185
|
+
const Row = memo(function Row({ p, isMobile, scoped, csv, asked }) {
|
|
186
|
+
const rank = `#${fmt(p.rank)}${p.tied ? '=' : ''}`;
|
|
187
|
+
const podium = p.rank <= 5;
|
|
188
|
+
const power = (
|
|
189
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 7, flexShrink: 0 }}>
|
|
190
|
+
<b style={{ fontSize: isMobile ? 16 : 17, fontWeight: 800, minWidth: 30, textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--sd-fg-1, #fff)' }}>{one(p.score)}</b>
|
|
191
|
+
<TierChip tier={p.tier} />
|
|
192
|
+
{!isMobile && p.boost > 0 && (
|
|
193
|
+
<span title="Added for a strong circle: their scanned circle holds many S and A people (lib/scoring.js bridge boost, up to +2)" style={{
|
|
194
|
+
fontSize: 10, fontWeight: 700, color: 'var(--sd-green, #00ff88)', background: 'rgba(0,255,136,0.08)', border: '1px solid rgba(0,255,136,0.28)',
|
|
195
|
+
padding: '1px 6px', borderRadius: 10, whiteSpace: 'nowrap',
|
|
196
|
+
}}>+{p.boost} circle</span>
|
|
197
|
+
)}
|
|
198
|
+
</span>
|
|
199
|
+
);
|
|
200
|
+
const way = <Way p={p} max={isMobile ? 1 : 2} csv={csv} />;
|
|
201
|
+
const rarity = p.degree === 1
|
|
202
|
+
? <span style={{ fontSize: 11.5, color: 'var(--sd-fg-4, #6f7a88)', whiteSpace: 'nowrap' }}>Your connection</span>
|
|
203
|
+
: <RarityTag rarity={p.rarity} count={!isMobile} small={isMobile} />;
|
|
204
|
+
const action = <Action p={p} scoped={scoped} asked={asked} compact={isMobile} />;
|
|
205
|
+
|
|
206
|
+
if (isMobile) {
|
|
207
|
+
return (
|
|
208
|
+
<div style={{ display: 'grid', gridTemplateColumns: '40px minmax(0,1fr) 66px', columnGap: 8, rowGap: 6, padding: '10px 12px', borderBottom: `1px solid ${SOFT_LINE}` }}>
|
|
209
|
+
<span style={{ gridRow: '1 / span 2', paddingTop: 9, fontSize: 11.5, fontWeight: 700, color: podium ? 'var(--sd-gold, #FFD700)' : 'var(--sd-fg-3, #8b9a9a)', whiteSpace: 'nowrap' }}>{rank}</span>
|
|
210
|
+
<PersonCell row={p.row} size={32} chip={false} />
|
|
211
|
+
<span style={{ justifySelf: 'end' }}>{power}</span>
|
|
212
|
+
<div style={{ gridColumn: '2 / span 2', display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
|
|
213
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0, flex: 1, overflow: 'hidden', fontSize: 12, color: 'var(--sd-fg-2, #b8c4c4)' }}>{way}</span>
|
|
214
|
+
{p.degree === 2 && rarity}
|
|
215
|
+
{action}
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return (
|
|
221
|
+
<div style={{ display: 'grid', gridTemplateColumns: COLS, gap: 10, padding: '0 16px', alignItems: 'center', minHeight: 56, borderBottom: `1px solid ${SOFT_LINE}` }}>
|
|
222
|
+
<span style={{ fontSize: 13, fontWeight: 700, color: podium ? 'var(--sd-gold, #FFD700)' : 'var(--sd-fg-3, #8b9a9a)', fontVariantNumeric: 'tabular-nums' }}>{rank}</span>
|
|
223
|
+
<PersonCell row={p.row} chip={false} />
|
|
224
|
+
{power}
|
|
225
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, fontSize: 12, color: 'var(--sd-fg-2, #b8c4c4)' }}>{way}</span>
|
|
226
|
+
<span style={{ minWidth: 0 }}>{rarity}</span>
|
|
227
|
+
<span style={{ justifySelf: 'end' }}>{action}</span>
|
|
228
|
+
</div>
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
/** Yours: their circle. 2nd degree: who of yours knows them, best first. */
|
|
233
|
+
function Way({ p, max = 2, csv }) {
|
|
234
|
+
if (p.degree === 1) {
|
|
235
|
+
const c = p.circle;
|
|
236
|
+
// A CSV import has no circles to scan: the chip says enough.
|
|
237
|
+
if (csv) return <DegreeChip degree={1} />;
|
|
238
|
+
const text = c.state === 'scanned'
|
|
239
|
+
? <span style={{ whiteSpace: 'nowrap' }}>Circle {fmt(c.size)} · <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(c.S + c.A)}</b> S+A</span>
|
|
240
|
+
: <span style={{ color: 'var(--sd-fg-4, #6f7a88)', fontSize: 11.5, whiteSpace: 'nowrap' }}>{c.state === 'hidden' ? 'Their list is hidden' : 'Circle not scanned'}</span>;
|
|
241
|
+
return <><DegreeChip degree={1} />{text}</>;
|
|
242
|
+
}
|
|
243
|
+
const named = p.routes.filter((r) => r.bridge);
|
|
244
|
+
const extra = p.routes.length - Math.min(max, named.length);
|
|
245
|
+
return (
|
|
246
|
+
<>
|
|
247
|
+
<DegreeChip degree={2} />
|
|
248
|
+
<span style={{ display: 'flex', gap: 8, minWidth: 0, overflow: 'hidden' }} title={p.routes.map((r) => (r.bridge ? r.bridge.name : 'a connection the app can’t name')).join('\n')}>
|
|
249
|
+
{named.slice(0, max).map((r) => (
|
|
250
|
+
<span key={r.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 12, color: 'var(--sd-fg-2, #b8c4c4)', whiteSpace: 'nowrap' }}>
|
|
251
|
+
<Avatar person={r.bridge} size={18} tierColors={TIER_COLORS} />{shortName(r.bridge.name)}
|
|
252
|
+
</span>
|
|
253
|
+
))}
|
|
254
|
+
{!named.length && <span style={{ fontSize: 11.5, color: 'var(--sd-fg-4, #6f7a88)', ...ELLIPSIS }}>a connection the app can’t name</span>}
|
|
255
|
+
{extra > 0 && <span style={{ fontSize: 11.5, color: 'var(--sd-fg-4, #6f7a88)', whiteSpace: 'nowrap' }}>+{fmt(extra)}</span>}
|
|
256
|
+
</span>
|
|
257
|
+
</>
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function Action({ p, scoped, asked, compact }) {
|
|
262
|
+
if (p.degree === 2) return <AskButton row={p.row} bridgeId={p.routes[0]?.id ?? p.row.source_connection_id} asked={asked} compact={compact} canAuto={scoped} />;
|
|
263
|
+
if (p.circle.state === 'scanned') return <OpenCircle id={p.row.id} compact={compact} />;
|
|
264
|
+
if (p.circle.state === 'todo' && scoped) return <ScanCircle id={p.row.id} compact={compact} />;
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// The cards beside the Power Index: Untapped, Kingmakers, Gatekeepers,
|
|
4
|
+
// Hidden giants, Company power, How sure, and Richest?, the honest answer to
|
|
5
|
+
// a question the app can't answer (it never sees money). Each card's top five,
|
|
6
|
+
// and a link to its board.
|
|
7
|
+
|
|
8
|
+
import { shortName } from '../../../lib/separation';
|
|
9
|
+
import Avatar from '../Avatar';
|
|
10
|
+
import { TIER_COLORS } from '../../../lib/themes';
|
|
11
|
+
import { fmt, one, pc, Card, CardHead, MiniRow, TierChip, Src, NeedsCircles, ELLIPSIS } from './parts';
|
|
12
|
+
|
|
13
|
+
export default function Rail({ data, heavy, open, source, onView, onHidden }) {
|
|
14
|
+
const { kings, gates, hidden, sure } = data;
|
|
15
|
+
const circles = kings.scanned > 0;
|
|
16
|
+
return (
|
|
17
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
|
18
|
+
{/* The four boards that read circles; with none scanned, one card says so once. */}
|
|
19
|
+
{!circles ? (
|
|
20
|
+
<Card>
|
|
21
|
+
<CardHead title="Kingmakers, Gatekeepers, Hidden giants, Untapped" sub="Who stands behind your connections, read from their circles" />
|
|
22
|
+
<NeedsCircles source={source} compact />
|
|
23
|
+
</Card>
|
|
24
|
+
) : (
|
|
25
|
+
<>
|
|
26
|
+
<Untapped open={open} />
|
|
27
|
+
|
|
28
|
+
<Card>
|
|
29
|
+
<CardHead title="Kingmakers" sub="Most S and A people behind them" more="Board →" onMore={() => onView('kingmakers')} />
|
|
30
|
+
{kings.list.slice(0, 5).map((k, i) => (
|
|
31
|
+
<MiniRow key={k.row.id} first={i === 0} rank={i + 1} value={fmt(k.SA)} label="S+A behind"
|
|
32
|
+
left={<Who row={k.row} sub={<><TierChip tier={k.row.tier} size={15} /><span style={ELLIPSIS}>circle of {fmt(k.size)}</span></>} />} />
|
|
33
|
+
))}
|
|
34
|
+
</Card>
|
|
35
|
+
|
|
36
|
+
<Card>
|
|
37
|
+
<CardHead title="Gatekeepers" sub={`S and A who reach you through one connection only. Top three: ${pc(gates.top3Share)} of your S and A reach.`}
|
|
38
|
+
more="Board →" onMore={() => onView('gatekeepers')} />
|
|
39
|
+
{gates.list.slice(0, 5).map((g, i) => (
|
|
40
|
+
<MiniRow key={g.row.id} first={i === 0} rank={i + 1} value={fmt(g.onlySA)} valueColor="var(--sd-green, #00ff88)" label="S+A only via them"
|
|
41
|
+
left={<Who row={g.row} sub={<><TierChip tier={g.row.tier} size={15} /><span style={ELLIPSIS}>circle of {fmt(g.size)}</span></>} />} />
|
|
42
|
+
))}
|
|
43
|
+
</Card>
|
|
44
|
+
|
|
45
|
+
<Card>
|
|
46
|
+
<CardHead title={`Hidden giants · ${fmt(hidden.count)}`} sub="S-tier with one way in: the connection who knows them is the only door you have."
|
|
47
|
+
more={hidden.count ? 'All →' : null} onMore={onHidden} />
|
|
48
|
+
{hidden.count === 0 ? <div style={{ fontSize: 12, color: 'var(--sd-fg-3, #8b9a9a)', padding: '2px 0 6px' }}>None yet: every S-tier person you can reach has two or more ways in.</div>
|
|
49
|
+
: hidden.list.slice(0, 4).map((h, i) => (
|
|
50
|
+
<MiniRow key={h.key} first={i === 0} value={one(h.score)} label={h.from === 'linkedin' ? '1 mutual (LinkedIn)' : '1 way in (scans)'}
|
|
51
|
+
left={<Who row={h.row} sub={<span style={ELLIPSIS}>{[h.row.company, h.via ? `only via ${shortName(h.via.name)}` : 'only via a connection the app can’t name'].filter(Boolean).join(' · ')}</span>} />} />
|
|
52
|
+
))}
|
|
53
|
+
{hidden.count > 0 && <Src>{fmt(hidden.fromLinkedIn)} from LinkedIn’s own mutual count, {fmt(hidden.fromScans)} from the ways in your scans saw, which can only go up.</Src>}
|
|
54
|
+
</Card>
|
|
55
|
+
</>
|
|
56
|
+
)}
|
|
57
|
+
|
|
58
|
+
<Card>
|
|
59
|
+
<CardHead title="Company power" sub="Everyone there now, power added up" more={heavy ? 'Board →' : null} onMore={() => onView('companies')} />
|
|
60
|
+
{!heavy ? <Counting /> : heavy.companies.list.slice(0, 5).map((c, i) => (
|
|
61
|
+
<MiniRow key={c.name} first={i === 0} rank={i + 1} value={fmt(Math.round(c.total))} label="total power"
|
|
62
|
+
left={<span style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
|
|
63
|
+
<Logo name={c.name} />
|
|
64
|
+
<span style={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
|
|
65
|
+
<b style={{ fontSize: 12.5, fontWeight: 650, ...ELLIPSIS }}>{c.name}</b>
|
|
66
|
+
<span style={{ fontSize: 11.5, color: 'var(--sd-fg-3, #8b9a9a)', ...ELLIPSIS }}>
|
|
67
|
+
<span style={{ color: TIER_COLORS.S }}>{fmt(c.S)} S</span> · <span style={{ color: TIER_COLORS.A }}>{fmt(c.A)} A</span> · {fmt(c.people)} people
|
|
68
|
+
</span>
|
|
69
|
+
</span>
|
|
70
|
+
</span>} />
|
|
71
|
+
))}
|
|
72
|
+
</Card>
|
|
73
|
+
|
|
74
|
+
<Card>
|
|
75
|
+
<CardHead title="How sure" sub="How much of this ranking rests on a guess" />
|
|
76
|
+
<div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
|
|
77
|
+
<b style={{ fontSize: 26, fontWeight: 850, color: sure.share >= 50 ? 'var(--sd-orange, #FF6B35)' : 'var(--sd-fg-1, #fff)' }}>{pc(sure.share)}</b>
|
|
78
|
+
<span style={{ fontSize: 12.5, color: 'var(--sd-fg-2, #b8c4c4)', lineHeight: 1.4 }}>
|
|
79
|
+
of these scores lean on an estimate{sure.tie ? <>{sure.share >= 50 ? ', which is why' : '. At the top,'} <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(sure.tie.count)}</b> people share {one(sure.tie.score)}</> : null}.
|
|
80
|
+
</span>
|
|
81
|
+
</div>
|
|
82
|
+
<Src>{fmt(sure.company + sure.both)} with a company no list knows, {fmt(sure.title + sure.both)} with a title the app couldn’t read. Score the companies you know on the Scores tab and the top of the list separates.</Src>
|
|
83
|
+
</Card>
|
|
84
|
+
|
|
85
|
+
<Richest heavy={heavy} />
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Untapped({ open }) {
|
|
91
|
+
return (
|
|
92
|
+
<Card style={{ padding: '14px 16px' }}>
|
|
93
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
|
|
94
|
+
<b style={{ fontSize: 30, fontWeight: 850, color: 'var(--sd-orange, #FF6B35)', fontVariantNumeric: 'tabular-nums' }}>{fmt(open?.total)}</b>
|
|
95
|
+
<span style={{ fontSize: 12.5, color: 'var(--sd-fg-2, #b8c4c4)', lineHeight: 1.45 }}>
|
|
96
|
+
<b style={{ color: 'var(--sd-fg-1, #fff)' }}>Untapped:</b> S and A people in your 2nd degree with no request out. {fmt(open?.S)} of them S. Requests marked sent so far: {fmt(open?.asked)}.
|
|
97
|
+
</span>
|
|
98
|
+
</div>
|
|
99
|
+
</Card>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** "Richest?": the app never sees money, and says so; power at big companies is what it can count. */
|
|
104
|
+
function Richest({ heavy }) {
|
|
105
|
+
return (
|
|
106
|
+
<Card dashed>
|
|
107
|
+
<CardHead title="Richest?" />
|
|
108
|
+
<p style={{ fontSize: 12.5, color: 'var(--sd-fg-1, #e9edf3)', margin: '6px 0 8px', lineHeight: 1.5 }}>
|
|
109
|
+
Six Degrees doesn’t know anyone’s money. LinkedIn shows titles and companies, not wealth. The closest honest measure is
|
|
110
|
+
power: who runs the biggest companies you can reach.
|
|
111
|
+
</p>
|
|
112
|
+
{!heavy ? <Counting /> : (
|
|
113
|
+
<div style={{ display: 'flex', gap: 10 }}>
|
|
114
|
+
<Stat n={heavy.companies.big.people} text={`people whose score rests on a company scored 8 or more (Fortune 500 scale)${heavy.companies.big.people ? `, at ${fmt(heavy.companies.big.companies)} compan${heavy.companies.big.companies === 1 ? 'y' : 'ies'}` : ''}`} />
|
|
115
|
+
<Stat n={heavy.ladder.rungs.find((r) => r.key === 'csuite').total} text="C-suite and founders within two steps, by their headline" />
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
118
|
+
<Src>{heavy ? heavy.companies.bigSource : null}</Src>
|
|
119
|
+
</Card>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function Stat({ n, text }) {
|
|
124
|
+
return (
|
|
125
|
+
<div style={{ flex: 1, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', borderRadius: 9, padding: '8px 10px', minWidth: 0 }}>
|
|
126
|
+
<b style={{ fontSize: 20, fontWeight: 800, display: 'block', fontVariantNumeric: 'tabular-nums' }}>{fmt(n)}</b>
|
|
127
|
+
<span style={{ fontSize: 11, color: 'var(--sd-fg-3, #8b9a9a)', lineHeight: 1.35, display: 'block' }}>{text}</span>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function Who({ row, sub }) {
|
|
133
|
+
return (
|
|
134
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
|
|
135
|
+
<Avatar person={row} size={26} tierColors={TIER_COLORS} />
|
|
136
|
+
<span style={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
|
|
137
|
+
<b style={{ fontSize: 12.5, fontWeight: 650, ...ELLIPSIS }}>{row.name}</b>
|
|
138
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: 'var(--sd-fg-3, #8b9a9a)', minWidth: 0 }}>{sub}</span>
|
|
139
|
+
</span>
|
|
140
|
+
</span>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function Logo({ name, size = 26 }) {
|
|
145
|
+
const letters = String(name || '').split(/\s+/).filter(Boolean).map((w) => w[0]).join('').slice(0, 2).toUpperCase();
|
|
146
|
+
return (
|
|
147
|
+
<span style={{
|
|
148
|
+
width: size, height: size, borderRadius: 7, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', flexShrink: 0,
|
|
149
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 800, color: 'var(--sd-fg-2, #b8c4c4)',
|
|
150
|
+
}}>{letters}</span>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function Counting() {
|
|
155
|
+
return <div style={{ fontSize: 12, color: 'var(--sd-fg-4, #6f7a88)', padding: '4px 0 6px' }}>Counting…</div>;
|
|
156
|
+
}
|