six-degrees 0.5.0 → 0.6.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/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +14 -14
- 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 +20 -19
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +20 -19
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +16 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/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.nft.json +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 +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page.js +1 -1
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +24 -23
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +22 -21
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +18 -17
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +22 -21
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch/page.js +1 -1
- package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/launch.html +2 -2
- package/.next/standalone/.next/server/app/launch.rsc +24 -23
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- 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 +24 -23
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +24 -23
- 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 +18 -17
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +1 -1
- 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]__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]__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]__0t3v1a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0um1uey._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +1 -1
- 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]__13dx4sd._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.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]__15wc9e-._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__18bcnu4._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +2 -2
- 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]__1kbl21f._.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]__1rphsdk._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__20rwfdw._.js +2 -2
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +5 -5
- package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +5 -5
- package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +5 -5
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +9 -9
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08oxiqh._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08g31gm._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0gk_ofx._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0nwsf93._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0vho1lb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0jdkqgi._.js → _1-658fq._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1bc46kz._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +9 -0
- package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +9 -0
- package/.next/standalone/.next/server/chunks/ssr/_2105jz8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +13 -0
- package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +13 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0gtv9jb._.js → app_components_CompanyScores_1g0mytz.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_settings_SectorPicker_1c-29qw.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +14 -12
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +6 -6
- 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/chunks/ssr/app_social_page_0h7zxda.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_0i8v-s3._.js → lib_1c4ieuw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.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/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/02pq76u7y4v9-.js +22 -0
- package/.next/standalone/.next/static/chunks/0cmq0exd4d0h9.js +1 -0
- package/.next/{static/chunks/2wgz9ietkqqe6.js → standalone/.next/static/chunks/0i02yxppzds1o.js} +1 -1
- package/.next/standalone/.next/static/chunks/0m_p4k-q2qh--.js +1 -0
- package/.next/standalone/.next/static/chunks/0oyslj62jkubd.js +1 -0
- package/.next/standalone/.next/static/chunks/{1x_ysly42-teq.css → 0vo-l8hxneba6.css} +1 -1
- package/.next/{static/chunks/3sowbvbaj1s6n.js → standalone/.next/static/chunks/0ws7zy0w57ufi.js} +1 -1
- package/.next/standalone/.next/static/chunks/0yh8z2tbrc5i_.js +1 -0
- package/.next/standalone/.next/static/chunks/172e10mi-tpo_.js +34 -0
- package/.next/standalone/.next/static/chunks/1ei5vbe2uw6fl.js +1 -0
- package/.next/standalone/.next/static/chunks/1f7_pl_wq7lh3.js +11 -0
- package/.next/standalone/.next/static/chunks/1jzbe7zdx9vbj.js +2 -0
- package/.next/standalone/.next/static/chunks/1m3017gp790pw.js +45 -0
- package/.next/standalone/.next/static/chunks/1t20e8u0st7ep.js +1 -0
- package/.next/standalone/.next/static/chunks/2-ch9rm27eril.js +11 -0
- package/.next/standalone/.next/static/chunks/2ldv-v3s9yaif.js +1 -0
- package/.next/standalone/.next/static/chunks/3bp284gjf7dyq.js +1 -0
- package/.next/standalone/.next/static/chunks/3k1f6clbn3gj3.js +7 -0
- package/.next/standalone/.next/static/chunks/3l4t8je6iguzc.js +1 -0
- package/.next/standalone/.next/static/chunks/{0muwt9bykzr-1.js → 3tplzuc9jk-tl.js} +1 -1
- package/.next/standalone/.next/static/chunks/42m0bqr8pbovz.js +11 -0
- package/.next/standalone/CHANGELOG.md +61 -0
- package/.next/standalone/README.md +22 -8
- package/.next/standalone/app/api/scraper/route.js +40 -3
- package/.next/standalone/app/api/update/route.js +12 -6
- package/.next/standalone/app/components/AppHeader.js +257 -0
- package/.next/standalone/app/components/Avatar.js +2 -1
- package/.next/standalone/app/components/ChainView.js +12 -12
- package/.next/standalone/app/components/FilterPanel.js +20 -12
- package/.next/standalone/app/components/ForceGraph.js +163 -25
- package/.next/standalone/app/components/GalaxyLab.js +43 -12
- package/.next/standalone/app/components/GridView.js +4 -4
- package/.next/standalone/app/components/LinkedInLimits.js +2 -1
- package/.next/standalone/app/components/ListView.js +3 -3
- package/.next/standalone/app/components/NoteDetail.js +2 -1
- package/.next/standalone/app/components/OnboardingGate.js +2 -2
- package/.next/standalone/app/components/OutlinkQuest.js +2 -1
- package/.next/standalone/app/components/PathsAnalyzer.js +3 -2
- package/.next/standalone/app/components/PeopleMap.js +2 -1
- package/.next/standalone/app/components/RingsView.js +3 -3
- package/.next/standalone/app/components/ScanTrail.js +85 -0
- package/.next/standalone/app/components/SeparationView.js +100 -77
- package/.next/standalone/app/components/Sidebar.js +4 -4
- package/.next/standalone/app/components/TheirCircle.js +2 -1
- package/.next/standalone/app/components/ThemeLoader.js +9 -0
- package/.next/standalone/app/components/UpdatePanel.js +20 -2
- package/.next/standalone/app/components/settings/AppearanceSection.js +226 -0
- package/.next/standalone/app/components/settings/NetworkHealthSection.js +2 -1
- package/.next/standalone/app/components/ui.js +2 -1
- package/.next/standalone/app/globals.css +70 -2
- package/.next/standalone/app/import/page.js +3 -3
- package/.next/standalone/app/layout.js +11 -2
- package/.next/standalone/app/page.js +69 -215
- package/.next/standalone/app/paths/page.js +8 -21
- package/.next/standalone/app/profile/page.js +11 -10
- package/.next/standalone/app/queue/page.js +8 -21
- package/.next/standalone/app/scores/page.js +1 -1
- package/.next/standalone/app/settings/page.js +7 -3
- package/.next/standalone/app/setup/page.js +83 -88
- package/.next/standalone/app/social/Crm.js +2 -1
- package/.next/standalone/app/social/SocialHub.js +2 -2
- package/.next/standalone/app/social/page.js +1 -1
- package/.next/standalone/lib/data-import.js +1 -0
- package/.next/standalone/lib/galaxy-export.js +2 -1
- package/.next/standalone/lib/galaxy-lab.js +24 -8
- package/.next/standalone/lib/level.js +51 -0
- package/.next/standalone/lib/release.js +13 -7
- package/.next/standalone/lib/scanner-python.js +38 -8
- package/.next/standalone/lib/scraper-client.js +2 -1
- package/.next/standalone/lib/separation.js +4 -2
- package/.next/standalone/lib/theme-store.js +61 -0
- package/.next/standalone/lib/themes.js +186 -0
- package/.next/standalone/lib/tiers.js +2 -8
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +4 -4
- package/.next/standalone/scripts/build-desktop.mjs +325 -0
- package/.next/standalone/scripts/build-site.mjs +85 -15
- package/.next/standalone/scripts/gen-test-network.mjs +93 -0
- package/.next/standalone/scripts/next.mjs +20 -0
- package/.next/standalone/scripts/readme_buttons.py +3 -0
- package/.next/standalone/scripts/requirements.txt +18 -1
- package/.next/standalone/scripts/site-news.mjs +54 -9
- package/.next/standalone/scripts/smoke-desktop.mjs +177 -0
- package/.next/standalone/scripts/windows/six-degrees.iss +100 -0
- package/.next/static/chunks/02pq76u7y4v9-.js +22 -0
- package/.next/static/chunks/0cmq0exd4d0h9.js +1 -0
- package/.next/{standalone/.next/static/chunks/2wgz9ietkqqe6.js → static/chunks/0i02yxppzds1o.js} +1 -1
- package/.next/static/chunks/0m_p4k-q2qh--.js +1 -0
- package/.next/static/chunks/0oyslj62jkubd.js +1 -0
- package/.next/static/chunks/{1x_ysly42-teq.css → 0vo-l8hxneba6.css} +1 -1
- package/.next/{standalone/.next/static/chunks/3sowbvbaj1s6n.js → static/chunks/0ws7zy0w57ufi.js} +1 -1
- package/.next/static/chunks/0yh8z2tbrc5i_.js +1 -0
- package/.next/static/chunks/172e10mi-tpo_.js +34 -0
- package/.next/static/chunks/1ei5vbe2uw6fl.js +1 -0
- package/.next/static/chunks/1f7_pl_wq7lh3.js +11 -0
- package/.next/static/chunks/1jzbe7zdx9vbj.js +2 -0
- package/.next/static/chunks/1m3017gp790pw.js +45 -0
- package/.next/static/chunks/1t20e8u0st7ep.js +1 -0
- package/.next/static/chunks/2-ch9rm27eril.js +11 -0
- package/.next/static/chunks/2ldv-v3s9yaif.js +1 -0
- package/.next/static/chunks/3bp284gjf7dyq.js +1 -0
- package/.next/static/chunks/3k1f6clbn3gj3.js +7 -0
- package/.next/static/chunks/3l4t8je6iguzc.js +1 -0
- package/.next/static/chunks/{0muwt9bykzr-1.js → 3tplzuc9jk-tl.js} +1 -1
- package/.next/static/chunks/42m0bqr8pbovz.js +11 -0
- package/CHANGELOG.md +61 -0
- package/README.md +22 -8
- package/lib/data-import.js +1 -0
- package/lib/galaxy-export.js +2 -1
- package/lib/galaxy-lab.js +24 -8
- package/lib/level.js +51 -0
- package/lib/release.js +13 -7
- package/lib/scanner-python.js +38 -8
- package/lib/scraper-client.js +2 -1
- package/lib/separation.js +4 -2
- package/lib/theme-store.js +61 -0
- package/lib/themes.js +186 -0
- package/lib/tiers.js +2 -8
- package/package.json +4 -4
- package/scripts/requirements.txt +18 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljcioj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16hs8kw._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_01kacen._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0xi-fbs._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0xmwmfv._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1-b9hj7._.js +0 -9
- package/.next/standalone/.next/server/chunks/ssr/_112ewem._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_16ab63q._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1fxm0-s._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1ra1d3r._.js +0 -9
- package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_13rapwj._.js +0 -3
- package/.next/standalone/.next/static/chunks/03bziijw5srol.js +0 -1
- package/.next/standalone/.next/static/chunks/0bgq8wmopl_ig.js +0 -7
- package/.next/standalone/.next/static/chunks/0ezus6p2eb-vg.js +0 -1
- package/.next/standalone/.next/static/chunks/0g_fy2034bp0x.js +0 -34
- package/.next/standalone/.next/static/chunks/0q5dru4q6gxl5.js +0 -22
- package/.next/standalone/.next/static/chunks/0w-byiwb2zax8.js +0 -2
- package/.next/standalone/.next/static/chunks/1g7jcovdejc9-.js +0 -1
- package/.next/standalone/.next/static/chunks/1i51yylxdzht1.js +0 -1
- package/.next/standalone/.next/static/chunks/1zf8swaasjf1e.js +0 -43
- package/.next/standalone/.next/static/chunks/2dwtoszeq91us.js +0 -1
- package/.next/standalone/.next/static/chunks/2rqtpccruavf2.js +0 -1
- package/.next/standalone/.next/static/chunks/30x3oq_st7a5r.js +0 -1
- package/.next/standalone/.next/static/chunks/355ryio1b7sm1.js +0 -1
- package/.next/standalone/.next/static/chunks/3ap5hgma7n0o7.js +0 -1
- package/.next/standalone/.next/static/chunks/3fci6qi39-1n5.js +0 -1
- package/.next/static/chunks/03bziijw5srol.js +0 -1
- package/.next/static/chunks/0bgq8wmopl_ig.js +0 -7
- package/.next/static/chunks/0ezus6p2eb-vg.js +0 -1
- package/.next/static/chunks/0g_fy2034bp0x.js +0 -34
- package/.next/static/chunks/0q5dru4q6gxl5.js +0 -22
- package/.next/static/chunks/0w-byiwb2zax8.js +0 -2
- package/.next/static/chunks/1g7jcovdejc9-.js +0 -1
- package/.next/static/chunks/1i51yylxdzht1.js +0 -1
- package/.next/static/chunks/1zf8swaasjf1e.js +0 -43
- package/.next/static/chunks/2dwtoszeq91us.js +0 -1
- package/.next/static/chunks/2rqtpccruavf2.js +0 -1
- package/.next/static/chunks/30x3oq_st7a5r.js +0 -1
- package/.next/static/chunks/355ryio1b7sm1.js +0 -1
- package/.next/static/chunks/3ap5hgma7n0o7.js +0 -1
- package/.next/static/chunks/3fci6qi39-1n5.js +0 -1
- /package/.next/standalone/.next/static/{I-cj79yE2IZ8taX2dZGp3 → dQUvvVSXqbkEFC3-CNcwT}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{I-cj79yE2IZ8taX2dZGp3 → dQUvvVSXqbkEFC3-CNcwT}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{I-cj79yE2IZ8taX2dZGp3 → dQUvvVSXqbkEFC3-CNcwT}/_ssgManifest.js +0 -0
- /package/.next/static/{I-cj79yE2IZ8taX2dZGp3 → dQUvvVSXqbkEFC3-CNcwT}/_buildManifest.js +0 -0
- /package/.next/static/{I-cj79yE2IZ8taX2dZGp3 → dQUvvVSXqbkEFC3-CNcwT}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{I-cj79yE2IZ8taX2dZGp3 → dQUvvVSXqbkEFC3-CNcwT}/_ssgManifest.js +0 -0
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import { Suspense, useEffect, useState, useRef, useMemo, useCallback } from 'react';
|
|
4
4
|
import { useSearchParams } from 'next/navigation';
|
|
5
|
-
import {
|
|
5
|
+
import { isCircleScan, loadScanNotes, NO_SCAN_NOTES } from '../lib/scraper-client';
|
|
6
6
|
import useScanner from './components/useScanner';
|
|
7
7
|
import useRequests from './components/useRequests';
|
|
8
8
|
import { requestCount } from '../lib/requests-client';
|
|
9
9
|
import { loadNetwork } from '../lib/network';
|
|
10
10
|
import { resolveView } from './components/views';
|
|
11
|
-
import AutoScanButton from './components/AutoScanButton';
|
|
12
11
|
import { peopleByDegree } from '../lib/degrees';
|
|
13
12
|
import { NETWORK_GRID, DEGREES_GRID, shows, gridCounts } from '../lib/tier-grid';
|
|
14
13
|
import Sidebar from './components/Sidebar';
|
|
@@ -21,7 +20,9 @@ import { useUser } from './components/UserProvider';
|
|
|
21
20
|
import { IS_DEMO, loadDemoNetwork } from '../lib/demo';
|
|
22
21
|
import { hasCsvNetwork, loadCsvNetwork, clearCsvNetwork } from '../lib/csv';
|
|
23
22
|
import Link from 'next/link';
|
|
24
|
-
import
|
|
23
|
+
import AppHeader from './components/AppHeader';
|
|
24
|
+
import { networkLevel } from '../lib/level';
|
|
25
|
+
import { TIER_COLORS } from '../lib/themes'; // the theme's dot colours, filled before anything draws
|
|
25
26
|
|
|
26
27
|
// One shared empty list, so "no 2nd-degree data" is the same value every render.
|
|
27
28
|
const NO_DEGREE2 = [];
|
|
@@ -38,13 +39,6 @@ function statsFor(d1, d2) {
|
|
|
38
39
|
return { total: d1.length, tiers: tierCounts, d2Total: d2.length, d2Tiers: d2TierCounts };
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const TIER_COLORS = {
|
|
42
|
-
S: '#FFD700',
|
|
43
|
-
A: '#9B59B6',
|
|
44
|
-
B: '#3498DB',
|
|
45
|
-
C: '#95A5A6',
|
|
46
|
-
D: '#BDC3C7',
|
|
47
|
-
};
|
|
48
42
|
|
|
49
43
|
export default function Home() {
|
|
50
44
|
// Suspense because HomeInner reads the address's ?chain= (useSearchParams),
|
|
@@ -99,10 +93,11 @@ function HomeInner() {
|
|
|
99
93
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(true);
|
|
100
94
|
const [filterPanelCollapsed, setFilterPanelCollapsed] = useState(true);
|
|
101
95
|
const [visualMode, setVisualMode] = useState(() => (chainOpen ? 'chain' : linkedMode === 'degrees' ? 'chain' : linkedMode === 'separation' ? 'separation' : 'galaxy'));
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// A notification opened in the right panel (app/components/NoteDetail.js).
|
|
96
|
+
// A notification opened in the right panel (app/components/NoteDetail.js);
|
|
97
|
+
// one picked on another page arrives as /?note=<id> (app/components/AppHeader.js).
|
|
105
98
|
const [openNote, setOpenNote] = useState(null);
|
|
99
|
+
const linkedNote = params.get('note');
|
|
100
|
+
const openNoteHere = useCallback((n) => { setOpenNote(n); setSidebarCollapsed(false); }, []);
|
|
106
101
|
const [csvMode, setCsvMode] = useState(false);
|
|
107
102
|
const [csvSource, setCsvSource] = useState('csv');
|
|
108
103
|
// What the scanner noted: hidden lists, and lists read with nothing new in
|
|
@@ -138,8 +133,6 @@ function HomeInner() {
|
|
|
138
133
|
load();
|
|
139
134
|
if (!IS_DEMO && !hasCsvNetwork()) {
|
|
140
135
|
loadScanNotes().then(setScanNotes);
|
|
141
|
-
// Fetch notifications
|
|
142
|
-
fetch(`/api/notifications?userId=${userId}`).then(r => r.json()).then(d => setNotifications(d.notifications || [])).catch(() => {});
|
|
143
136
|
}
|
|
144
137
|
}, [userId]);
|
|
145
138
|
|
|
@@ -188,7 +181,7 @@ function HomeInner() {
|
|
|
188
181
|
|
|
189
182
|
// What the views draw. Memoised because the graph views rebuild their whole
|
|
190
183
|
// scene when these change identity: computed inline, every re-render — a click,
|
|
191
|
-
// the sidebar opening,
|
|
184
|
+
// the sidebar opening, a notification arriving — reset the galaxy's layout. The
|
|
192
185
|
// empty list in network mode was a new [] each time, which was enough on its own.
|
|
193
186
|
// Network Circle draws the degrees picked in the Filter panel, each person
|
|
194
187
|
// once, at the nearest degree they're found (lib/degrees.js).
|
|
@@ -196,30 +189,42 @@ function HomeInner() {
|
|
|
196
189
|
const grid = isDegreesMode ? grids.degrees : grids.network;
|
|
197
190
|
// Degrees draws your connections (the bridges among them) and their circles;
|
|
198
191
|
// Network Circle draws whoever the grid shows, at any degree.
|
|
192
|
+
// Separation ranks the people two steps away, and every connection is a way
|
|
193
|
+
// in to them whatever its tier, so there the tiers pick who's ranked and never
|
|
194
|
+
// which connections lead to them (Blake, 2026-10-03: hiding a tier took the
|
|
195
|
+
// purple A-tier mutuals off the map; "the filter should only apply to the output").
|
|
196
|
+
const isSeparation = mode === 'separation';
|
|
199
197
|
const filtered = useMemo(() => {
|
|
198
|
+
if (isSeparation) return connections;
|
|
200
199
|
if (isDegreesMode) return connections.filter((c) => shows(grid, c.tier, 1));
|
|
201
200
|
return [1, 2, 3].flatMap((d) => (byDegree[d] || []).filter((c) => shows(grid, c.tier, d)));
|
|
202
|
-
}, [isDegreesMode, connections, byDegree, grid]);
|
|
201
|
+
}, [isSeparation, isDegreesMode, connections, byDegree, grid]);
|
|
203
202
|
// Lookups built once per load. Every click re-renders this component, and the
|
|
204
203
|
// three places below used to scan one list inside another — degree1.find per
|
|
205
204
|
// 2nd-degree row, degree2.some per connection — about 16M comparisons, twice
|
|
206
205
|
// a click, at 20k rows.
|
|
207
206
|
const d1ById = useMemo(() => new Map(degree1.map(c => [c.id, c])), [degree1]);
|
|
207
|
+
// Your level, in the round button at the top right (lib/level.js).
|
|
208
|
+
const level = useMemo(() => networkLevel(degree1, degree2), [degree1, degree2]);
|
|
208
209
|
const bridgeIds = useMemo(
|
|
209
210
|
() => new Set(degree2.map(d => d.source_connection_id).filter(Boolean)),
|
|
210
211
|
[degree2],
|
|
211
212
|
);
|
|
212
|
-
// A 2nd-degree row shows when its own tier does at 2nd degree, and
|
|
213
|
-
// it came through shows at 1st.
|
|
213
|
+
// A 2nd-degree row shows when its own tier does at 2nd degree, and (in
|
|
214
|
+
// Degrees, not Separation) the bridge it came through shows at 1st.
|
|
214
215
|
const filteredD2 = useMemo(() => {
|
|
215
216
|
if (!isDegreesMode) return NO_DEGREE2;
|
|
217
|
+
if (isSeparation) return degree2.filter((c) => shows(grid, c.tier, 2));
|
|
216
218
|
return degree2.filter((c) => shows(grid, c.tier, 2) && shows(grid, d1ById.get(c.source_connection_id)?.tier, 1));
|
|
217
|
-
}, [isDegreesMode, grid, d1ById, degree2]);
|
|
219
|
+
}, [isDegreesMode, isSeparation, grid, d1ById, degree2]);
|
|
218
220
|
// How many people stand behind each dot of the grid. In Degrees, 1st degree
|
|
219
|
-
// counts the bridges, since those are the connections it draws
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
: byDegree
|
|
221
|
+
// counts the bridges, since those are the connections it draws; Separation
|
|
222
|
+
// only ranks the 2nd.
|
|
223
|
+
const panelCounts = useMemo(() => gridCounts(isSeparation
|
|
224
|
+
? { 2: byDegree[2] }
|
|
225
|
+
: isDegreesMode
|
|
226
|
+
? { 1: degree1.filter((c) => bridgeIds.has(c.id)), 2: byDegree[2] }
|
|
227
|
+
: byDegree), [isSeparation, isDegreesMode, degree1, bridgeIds, byDegree]);
|
|
223
228
|
const selectHandler = useCallback((node) => {
|
|
224
229
|
setSelected(node);
|
|
225
230
|
if (node) { setSidebarCollapsed(false); setOpenNote(null); }
|
|
@@ -244,7 +249,7 @@ function HomeInner() {
|
|
|
244
249
|
|
|
245
250
|
if (loading) {
|
|
246
251
|
return (
|
|
247
|
-
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', background: '
|
|
252
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', background: 'var(--sd-page)', color: '#fff' }}>
|
|
248
253
|
<div style={{ fontSize: 24, fontWeight: 700 }}>Loading Six Degrees…</div>
|
|
249
254
|
<div style={{ fontSize: 14, color: '#888', marginTop: 8 }}>Mapping your LinkedIn network</div>
|
|
250
255
|
</div>
|
|
@@ -255,157 +260,46 @@ function HomeInner() {
|
|
|
255
260
|
const canScan = !IS_DEMO && !csvMode;
|
|
256
261
|
|
|
257
262
|
return (
|
|
258
|
-
<div data-map style={{ height: '100vh', overflow: 'hidden', background: '
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}} />
|
|
285
|
-
<span style={{ fontSize: isMobile ? 10 : 12, color: 'rgba(255,255,255,0.65)', whiteSpace: 'nowrap' }}>
|
|
286
|
-
{csvSource === 'sample' ? 'Sample network' : 'Your CSV'}
|
|
287
|
-
</span>
|
|
288
|
-
<button
|
|
289
|
-
onClick={() => { clearCsvNetwork(); window.location.href = '/'; }}
|
|
290
|
-
title={csvSource === 'sample' ? 'Leave the sample network' : 'Clear this import'}
|
|
291
|
-
style={{
|
|
292
|
-
border: 'none', background: 'transparent', cursor: 'pointer',
|
|
293
|
-
color: '#888', fontSize: isMobile ? 13 : 15, lineHeight: 1,
|
|
294
|
-
padding: '0 0 0 2px',
|
|
295
|
-
}}
|
|
296
|
-
>
|
|
297
|
-
×
|
|
298
|
-
</button>
|
|
299
|
-
</div>
|
|
300
|
-
)}
|
|
301
|
-
</AppTabs>
|
|
302
|
-
{/* Settings — also in CSV/sample mode and on phones, so updates stay reachable */}
|
|
303
|
-
{!IS_DEMO && <Link
|
|
304
|
-
href="/settings"
|
|
305
|
-
title="Settings"
|
|
306
|
-
aria-label="Settings"
|
|
307
|
-
style={{
|
|
308
|
-
width: isMobile ? 28 : 32, height: isMobile ? 28 : 32, borderRadius: '50%', flexShrink: 0,
|
|
309
|
-
background: 'rgba(255,255,255,0.06)', color: '#888', fontSize: isMobile ? 14 : 16, textDecoration: 'none',
|
|
310
|
-
display: 'flex', alignItems: 'center', justifyContent: 'center', marginLeft: isMobile ? 4 : 8,
|
|
311
|
-
}}
|
|
312
|
-
>
|
|
313
|
-
{'\u2699\uFE0E'}
|
|
314
|
-
</Link>}
|
|
315
|
-
{/* Notification bell */}
|
|
316
|
-
{!IS_DEMO && !csvMode && <div style={{ position: 'relative', marginLeft: isMobile ? 4 : 8 }}>
|
|
263
|
+
<div data-map style={{ height: '100vh', overflow: 'hidden', background: 'var(--sd-page)', color: '#fff', fontFamily: 'var(--sd-font)' }}>
|
|
264
|
+
<AppHeader
|
|
265
|
+
active={mode}
|
|
266
|
+
isMobile={isMobile}
|
|
267
|
+
csvMode={csvMode}
|
|
268
|
+
onMode={(m) => { setMode(m); setSelected(null); setVisualMode(m === 'network' ? 'galaxy' : m === 'degrees' ? 'chain' : 'separation'); }}
|
|
269
|
+
level={level}
|
|
270
|
+
onOpenNote={openNoteHere}
|
|
271
|
+
openNoteId={linkedNote}
|
|
272
|
+
// Which network you are looking at, and the way back out of it. Loading
|
|
273
|
+
// the sample used to be a one-way door: it lives in sessionStorage, and
|
|
274
|
+
// nothing in the UI cleared it.
|
|
275
|
+
chips={csvMode && (
|
|
276
|
+
<div style={{
|
|
277
|
+
display: 'flex', alignItems: 'center', gap: 6,
|
|
278
|
+
marginLeft: isMobile ? 4 : 10, padding: isMobile ? '4px 8px' : '5px 10px',
|
|
279
|
+
borderRadius: 999, background: 'rgba(255,255,255,0.05)',
|
|
280
|
+
border: '1px solid rgba(255,255,255,0.12)',
|
|
281
|
+
}}>
|
|
282
|
+
<span style={{
|
|
283
|
+
width: 6, height: 6, borderRadius: '50%',
|
|
284
|
+
background: csvSource === 'sample' ? '#9B59B6' : '#2ecc71',
|
|
285
|
+
}} />
|
|
286
|
+
<span style={{ fontSize: isMobile ? 10 : 12, color: 'rgba(255,255,255,0.65)', whiteSpace: 'nowrap' }}>
|
|
287
|
+
{csvSource === 'sample' ? 'Sample network' : 'Your CSV'}
|
|
288
|
+
</span>
|
|
317
289
|
<button
|
|
318
|
-
onClick={() =>
|
|
290
|
+
onClick={() => { clearCsvNetwork(); window.location.href = '/'; }}
|
|
291
|
+
title={csvSource === 'sample' ? 'Leave the sample network' : 'Clear this import'}
|
|
319
292
|
style={{
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
293
|
+
border: 'none', background: 'transparent', cursor: 'pointer',
|
|
294
|
+
color: '#888', fontSize: isMobile ? 13 : 15, lineHeight: 1,
|
|
295
|
+
padding: '0 0 0 2px',
|
|
323
296
|
}}
|
|
324
297
|
>
|
|
325
|
-
|
|
326
|
-
{notifications.filter(n => !n.seen).length > 0 && (
|
|
327
|
-
<span style={{
|
|
328
|
-
position: 'absolute', top: -2, right: -2, width: 16, height: 16, borderRadius: '50%',
|
|
329
|
-
background: '#ff5050', color: '#fff', fontSize: 9, fontWeight: 700,
|
|
330
|
-
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
331
|
-
}}>
|
|
332
|
-
{notifications.filter(n => !n.seen).length}
|
|
333
|
-
</span>
|
|
334
|
-
)}
|
|
298
|
+
×
|
|
335
299
|
</button>
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
background: 'rgba(10,10,26,0.98)', border: '1px solid rgba(255,255,255,0.1)',
|
|
340
|
-
borderRadius: 12, overflow: 'hidden', zIndex: 100,
|
|
341
|
-
backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)',
|
|
342
|
-
boxShadow: '0 8px 32px rgba(0,0,0,0.5)',
|
|
343
|
-
}}>
|
|
344
|
-
<div style={{ padding: '12px 16px', borderBottom: '1px solid rgba(255,255,255,0.08)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
345
|
-
<span style={{ fontWeight: 700, fontSize: 14 }}>Notifications</span>
|
|
346
|
-
{notifications.filter(n => !n.seen).length > 0 && (
|
|
347
|
-
<button onClick={() => {
|
|
348
|
-
fetch('/api/notifications', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'mark-all-seen' }) });
|
|
349
|
-
setNotifications(prev => prev.map(n => ({ ...n, seen: true })));
|
|
350
|
-
}} style={{ background: 'none', border: 'none', color: '#3498DB', fontSize: 11, cursor: 'pointer', fontWeight: 600 }}>
|
|
351
|
-
Mark all read
|
|
352
|
-
</button>
|
|
353
|
-
)}
|
|
354
|
-
</div>
|
|
355
|
-
<div style={{ overflowY: 'auto', maxHeight: 340 }}>
|
|
356
|
-
{notifications.length === 0 ? (
|
|
357
|
-
<div style={{ padding: 20, textAlign: 'center', color: '#555', fontSize: 12 }}>No notifications yet</div>
|
|
358
|
-
) : notifications.slice(0, 20).map(n => (
|
|
359
|
-
<div key={n.id} role="button" tabIndex={0}
|
|
360
|
-
onClick={() => {
|
|
361
|
-
// Open it in the right panel, and count it as read.
|
|
362
|
-
if (!n.seen) {
|
|
363
|
-
fetch('/api/notifications', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'mark-seen', id: n.id }) }).catch(() => {});
|
|
364
|
-
setNotifications(prev => prev.map(x => (x.id === n.id ? { ...x, seen: true } : x)));
|
|
365
|
-
}
|
|
366
|
-
setOpenNote(n); setShowNotifs(false); setSidebarCollapsed(false);
|
|
367
|
-
}}
|
|
368
|
-
onKeyDown={(e) => { if (e.key === 'Enter') e.currentTarget.click(); }}
|
|
369
|
-
onMouseEnter={(e) => { e.currentTarget.style.background = 'rgba(255,255,255,0.06)'; }}
|
|
370
|
-
onMouseLeave={(e) => { e.currentTarget.style.background = n.seen ? 'transparent' : 'rgba(255,215,0,0.04)'; }}
|
|
371
|
-
style={{
|
|
372
|
-
padding: '10px 16px', borderBottom: '1px solid rgba(255,255,255,0.04)', cursor: 'pointer',
|
|
373
|
-
background: n.seen ? 'transparent' : 'rgba(255,215,0,0.04)',
|
|
374
|
-
}}>
|
|
375
|
-
<div style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
|
|
376
|
-
<span style={{ fontSize: 16 }}>{n.icon || '📌'}</span>
|
|
377
|
-
<div style={{ flex: 1 }}>
|
|
378
|
-
<div style={{ fontSize: 12, fontWeight: 600, color: n.seen ? '#888' : '#fff' }}>{n.title}<span style={{ color: '#556', marginLeft: 6 }}>›</span></div>
|
|
379
|
-
{n.message && <div style={{ fontSize: 10, color: '#666', marginTop: 2 }}>{n.message}</div>}
|
|
380
|
-
<div style={{ fontSize: 9, color: '#444', marginTop: 3 }}>{new Date(n.created_at).toLocaleDateString()}</div>
|
|
381
|
-
</div>
|
|
382
|
-
</div>
|
|
383
|
-
</div>
|
|
384
|
-
))}
|
|
385
|
-
</div>
|
|
386
|
-
</div>
|
|
387
|
-
)}
|
|
388
|
-
</div>}
|
|
389
|
-
{/* Refresh button — Check for new, once you say yes; notifies */}
|
|
390
|
-
{!IS_DEMO && !csvMode && <RefreshButton isMobile={isMobile} />}
|
|
391
|
-
{/* Profile icon — top right */}
|
|
392
|
-
<a href={IS_DEMO ? '/launch' : csvMode ? '/import' : '/profile'} style={{
|
|
393
|
-
width: isMobile ? 30 : 36, height: isMobile ? 30 : 36, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
394
|
-
background: 'linear-gradient(135deg, #FFD700, #FF6B35)', color: '#000', fontWeight: 800, fontSize: isMobile ? 11 : 14,
|
|
395
|
-
textDecoration: 'none', marginLeft: isMobile ? 6 : 12, flexShrink: 0,
|
|
396
|
-
}}>
|
|
397
|
-
{(() => {
|
|
398
|
-
const sCount = degree1.filter(c => c.tier === 'S').length;
|
|
399
|
-
const aCount = degree1.filter(c => c.tier === 'A').length;
|
|
400
|
-
const bCount = degree1.filter(c => c.tier === 'B').length;
|
|
401
|
-
const clusters = degree1.filter(c => bridgeIds.has(c.id)).length;
|
|
402
|
-
const d2S = degree2.filter(c => c.tier === 'S').length;
|
|
403
|
-
const np = (sCount*100)+(aCount*40)+(bCount*15)+(clusters*200)+(d2S*50)+degree1.length;
|
|
404
|
-
return Math.floor(Math.sqrt(np / 10));
|
|
405
|
-
})()}
|
|
406
|
-
</a>
|
|
407
|
-
</div>
|
|
408
|
-
|
|
300
|
+
</div>
|
|
301
|
+
)}
|
|
302
|
+
>
|
|
409
303
|
{/* Pending count badge — in header: everyone with a request out, once each (lib/requests-client.js) */}
|
|
410
304
|
{isDegreesMode && !csvMode && pendingCount > 0 && (
|
|
411
305
|
<Link href="/queue" style={{
|
|
@@ -418,13 +312,13 @@ function HomeInner() {
|
|
|
418
312
|
{pendingCount} Pending
|
|
419
313
|
</Link>
|
|
420
314
|
)}
|
|
421
|
-
</
|
|
315
|
+
</AppHeader>
|
|
422
316
|
|
|
423
317
|
<div style={{ display: 'flex', height: isMobile ? 'calc(100vh - 70px)' : 'calc(100vh - 130px)', position: 'relative' }}>
|
|
424
318
|
<FilterPanel
|
|
425
319
|
collapsed={filterPanelCollapsed}
|
|
426
320
|
onToggle={() => setFilterPanelCollapsed(!filterPanelCollapsed)}
|
|
427
|
-
mode={isDegreesMode ? 'degrees' : 'network'}
|
|
321
|
+
mode={isSeparation ? 'separation' : isDegreesMode ? 'degrees' : 'network'}
|
|
428
322
|
visualMode={view.key}
|
|
429
323
|
grid={grid}
|
|
430
324
|
gridCounts={panelCounts}
|
|
@@ -536,7 +430,8 @@ function networkShape(d1, d2) {
|
|
|
536
430
|
// Looks at the network again when a scan has changed it: once when any scan
|
|
537
431
|
// ends, and every 20 seconds while a circle is being scanned with Bridge Chains
|
|
538
432
|
// open, since the scanner saves every 10 pages and the circle fills in as it
|
|
539
|
-
// does. Its own component
|
|
433
|
+
// does. Its own component so the scanner's answer, which changes every second or
|
|
434
|
+
// two while a scan runs, re-renders it and not the whole map.
|
|
540
435
|
function NetworkRefresh({ onChange, live }) {
|
|
541
436
|
const scan = useScanner();
|
|
542
437
|
const ended = scan.finished.find(CHANGES_NETWORK)?.startedAt ?? null;
|
|
@@ -552,44 +447,3 @@ function NetworkRefresh({ onChange, live }) {
|
|
|
552
447
|
return null;
|
|
553
448
|
}
|
|
554
449
|
|
|
555
|
-
// Its own component so the scanner's answer, which changes every second or two
|
|
556
|
-
// while a scan runs, re-renders this button and not the whole map.
|
|
557
|
-
//
|
|
558
|
-
// It asks first, as a company scan does, and says what it will do and what it
|
|
559
|
-
// costs: one click on a small icon used to open a Chrome window on LinkedIn
|
|
560
|
-
// with no word of what it was about to do.
|
|
561
|
-
function RefreshButton({ isMobile }) {
|
|
562
|
-
const scan = useScanner();
|
|
563
|
-
const busy = busyReason(scan);
|
|
564
|
-
return (
|
|
565
|
-
<button
|
|
566
|
-
onClick={async () => {
|
|
567
|
-
try {
|
|
568
|
-
const blocked = notReadyMessage(await scraperStatus());
|
|
569
|
-
if (blocked) { alert(blocked); return; }
|
|
570
|
-
const ok = window.confirm(
|
|
571
|
-
'Check for new connections?\n\nThis opens a Chrome window on your LinkedIn connections ' +
|
|
572
|
-
'list and reads it from the newest, stopping once it reaches people already saved. It ' +
|
|
573
|
-
'usually takes under a minute. It reads your own list, not a search, so it doesn’t ' +
|
|
574
|
-
'use your search budget, but like any scan it is LinkedIn traffic from your account.',
|
|
575
|
-
);
|
|
576
|
-
if (!ok) return;
|
|
577
|
-
await beginScrape('refresh');
|
|
578
|
-
alert('Checking for new connections — watch it on the Scan page.');
|
|
579
|
-
} catch (e) {
|
|
580
|
-
alert(e.message);
|
|
581
|
-
}
|
|
582
|
-
}}
|
|
583
|
-
disabled={Boolean(busy)}
|
|
584
|
-
title={busy ? `${busy}. One scan at a time.` : 'Check for new connections'}
|
|
585
|
-
style={{
|
|
586
|
-
width: isMobile ? 28 : 32, height: isMobile ? 28 : 32, borderRadius: '50%', border: 'none',
|
|
587
|
-
cursor: busy ? 'not-allowed' : 'pointer', opacity: busy ? 0.4 : 1,
|
|
588
|
-
background: 'rgba(255,255,255,0.06)', color: '#888', fontSize: isMobile ? 12 : 14,
|
|
589
|
-
display: isMobile ? 'none' : 'flex', alignItems: 'center', justifyContent: 'center', marginLeft: 8,
|
|
590
|
-
}}
|
|
591
|
-
>
|
|
592
|
-
↻
|
|
593
|
-
</button>
|
|
594
|
-
);
|
|
595
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Suspense, useEffect, useState } from 'react';
|
|
4
|
-
import
|
|
4
|
+
import AppHeader from '../components/AppHeader';
|
|
5
5
|
import { setNotchTabs } from '../../lib/island';
|
|
6
6
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
7
7
|
import { runScrape, scraperStatus, notReadyMessage, busyReason } from '../../lib/scraper-client';
|
|
@@ -15,8 +15,8 @@ import useScanner from '../components/useScanner';
|
|
|
15
15
|
import Link from 'next/link';
|
|
16
16
|
import { companyOf, getSeniority } from '../../lib/companies';
|
|
17
17
|
import { localPhoto } from '../../lib/photos';
|
|
18
|
+
import { TIER_COLORS } from '../../lib/themes';
|
|
18
19
|
|
|
19
|
-
const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
|
|
20
20
|
// Map and Companies (Blake, 2026-10-02: companies are worth more than industries,
|
|
21
21
|
// and an industry's detail opens from a company's card). Whether the map's bubbles
|
|
22
22
|
// are companies or people is a switch in its Filters panel.
|
|
@@ -240,8 +240,8 @@ function PathsInner() {
|
|
|
240
240
|
return (
|
|
241
241
|
<div style={{
|
|
242
242
|
minHeight: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
|
|
243
|
-
gap: 12, background: '
|
|
244
|
-
fontFamily: '-
|
|
243
|
+
gap: 12, background: 'var(--sd-page)', color: 'rgba(255,255,255,0.7)',
|
|
244
|
+
fontFamily: 'var(--sd-font)',
|
|
245
245
|
}}>
|
|
246
246
|
<h1 style={{ fontSize: 20, fontWeight: 700, margin: 0, color: '#fff' }}>Not part of the demo</h1>
|
|
247
247
|
<p style={{ fontSize: 13, margin: 0 }}>The public demo includes the Network Circle and Degrees views only.</p>
|
|
@@ -251,31 +251,18 @@ function PathsInner() {
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
if (loading) {
|
|
254
|
-
return <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '
|
|
254
|
+
return <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--sd-page)', color: '#fff' }}>Loading...</div>;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
return (
|
|
258
258
|
<div style={{
|
|
259
|
-
height: '100vh', background: '
|
|
260
|
-
fontFamily: '-
|
|
259
|
+
height: '100vh', background: 'var(--sd-page)', color: '#fff',
|
|
260
|
+
fontFamily: 'var(--sd-font)',
|
|
261
261
|
display: 'flex', flexDirection: 'column', overflow: 'hidden',
|
|
262
262
|
}}>
|
|
263
263
|
{/* The same header as every page: the app's tabs, Paths lit; Map, People,
|
|
264
264
|
Industries and Companies sit in the notch under it. */}
|
|
265
|
-
<
|
|
266
|
-
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
|
|
267
|
-
<Link href="/" style={{ textDecoration: 'none' }}>
|
|
268
|
-
<h1 style={{ fontSize: 28, fontWeight: 700, margin: 0, background: 'linear-gradient(135deg, #FFD700, #9B59B6, #3498DB)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>
|
|
269
|
-
Six Degrees
|
|
270
|
-
</h1>
|
|
271
|
-
</Link>
|
|
272
|
-
<AppTabs active="paths" csvMode={localOnly} />
|
|
273
|
-
<Link href="/settings" title="Settings" aria-label="Settings" style={{
|
|
274
|
-
width: 32, height: 32, borderRadius: '50%', flexShrink: 0, background: 'rgba(255,255,255,0.06)', color: '#888',
|
|
275
|
-
fontSize: 16, textDecoration: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
276
|
-
}}>⚙</Link>
|
|
277
|
-
</div>
|
|
278
|
-
</header>
|
|
265
|
+
<AppHeader active="paths" csvMode={localOnly} />
|
|
279
266
|
{selectedCompany && (
|
|
280
267
|
<div style={{ padding: '10px 24px', borderBottom: '1px solid rgba(255,255,255,0.08)', flexShrink: 0 }}>
|
|
281
268
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
|
@@ -9,6 +9,8 @@ import OnboardingGate from '../components/OnboardingGate';
|
|
|
9
9
|
import { useUser } from '../components/UserProvider';
|
|
10
10
|
import { sectorByKey } from '../../lib/sector-labels';
|
|
11
11
|
import Link from 'next/link';
|
|
12
|
+
import { networkPower as powerOf, levelOf } from '../../lib/level';
|
|
13
|
+
import { TIER_COLORS } from '../../lib/themes';
|
|
12
14
|
import NetworkHealthSection from '../components/settings/NetworkHealthSection';
|
|
13
15
|
|
|
14
16
|
const LEVEL_NAMES = {
|
|
@@ -74,10 +76,9 @@ function ProfileInner() {
|
|
|
74
76
|
d1.forEach(c => { if (c.company) companies[c.company] = (companies[c.company] || 0) + 1; });
|
|
75
77
|
const topCompanies = Object.entries(companies).sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
76
78
|
|
|
77
|
-
// Network Power
|
|
78
|
-
const networkPower = (
|
|
79
|
-
|
|
80
|
-
const level = Math.floor(Math.sqrt(networkPower / 10));
|
|
79
|
+
// Network Power, and the level the header's round button shows (lib/level.js)
|
|
80
|
+
const networkPower = powerOf(d1, d2);
|
|
81
|
+
const level = levelOf(networkPower);
|
|
81
82
|
const currentLevelPower = level * level * 10;
|
|
82
83
|
const nextLevelPower = (level + 1) * (level + 1) * 10;
|
|
83
84
|
const xpProgress = ((networkPower - currentLevelPower) / (nextLevelPower - currentLevelPower)) * 100;
|
|
@@ -115,10 +116,10 @@ function ProfileInner() {
|
|
|
115
116
|
if (IS_DEMO) {
|
|
116
117
|
return (
|
|
117
118
|
<div style={{
|
|
118
|
-
minHeight: '100vh', background: '
|
|
119
|
+
minHeight: '100vh', background: 'var(--sd-page)', color: 'rgba(255,255,255,0.7)',
|
|
119
120
|
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
|
|
120
121
|
gap: 12, textAlign: 'center', padding: 24,
|
|
121
|
-
fontFamily: '-
|
|
122
|
+
fontFamily: 'var(--sd-font)',
|
|
122
123
|
}}>
|
|
123
124
|
<h2 style={{ margin: 0, fontSize: 20, fontWeight: 700, color: '#fff' }}>Not part of the demo</h2>
|
|
124
125
|
<p style={{ margin: 0, fontSize: 13 }}>The public demo includes the Network Circle and Degrees views only.</p>
|
|
@@ -129,13 +130,13 @@ function ProfileInner() {
|
|
|
129
130
|
|
|
130
131
|
if (loading) {
|
|
131
132
|
return (
|
|
132
|
-
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '
|
|
133
|
+
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--sd-page)', color: '#fff' }}>
|
|
133
134
|
Loading profile...
|
|
134
135
|
</div>
|
|
135
136
|
);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
const tierColors =
|
|
139
|
+
const tierColors = TIER_COLORS; // the theme's (lib/themes.js)
|
|
139
140
|
const s = stats;
|
|
140
141
|
|
|
141
142
|
// Milestones
|
|
@@ -154,8 +155,8 @@ function ProfileInner() {
|
|
|
154
155
|
|
|
155
156
|
return (
|
|
156
157
|
<div style={{
|
|
157
|
-
height: '100vh', background: '
|
|
158
|
-
fontFamily: '-
|
|
158
|
+
height: '100vh', background: 'var(--sd-page)', color: '#fff',
|
|
159
|
+
fontFamily: 'var(--sd-font)',
|
|
159
160
|
display: 'flex', flexDirection: 'column', overflow: 'hidden',
|
|
160
161
|
}}>
|
|
161
162
|
{/* Header */}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { Suspense, useEffect, useMemo, useState } from 'react';
|
|
4
4
|
import { useSearchParams } from 'next/navigation';
|
|
5
|
-
import
|
|
5
|
+
import AppHeader from '../components/AppHeader';
|
|
6
6
|
import SocialHub from '../social/SocialHub';
|
|
7
7
|
import { setNotchTabs } from '../../lib/island';
|
|
8
8
|
import { loadNetwork } from '../../lib/network';
|
|
@@ -18,8 +18,8 @@ import { keyFor } from '../../lib/separation';
|
|
|
18
18
|
import { localPhoto } from '../../lib/photos';
|
|
19
19
|
import { reachIndex } from '../../lib/reach';
|
|
20
20
|
import { loadScanNotes } from '../../lib/scraper-client';
|
|
21
|
+
import { TIER_COLORS } from '../../lib/themes';
|
|
21
22
|
|
|
22
|
-
const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
|
|
23
23
|
|
|
24
24
|
// Who to reach first: power, +1 when the company their score is built on is a
|
|
25
25
|
// top one by the model's own scores (TOP_COMPANY: the curated list's major
|
|
@@ -159,8 +159,8 @@ function QueueInner() {
|
|
|
159
159
|
if (IS_DEMO) {
|
|
160
160
|
return (
|
|
161
161
|
<div style={{
|
|
162
|
-
minHeight: '100vh', background: '
|
|
163
|
-
fontFamily: '-
|
|
162
|
+
minHeight: '100vh', background: 'var(--sd-page)', color: 'rgba(255,255,255,0.7)',
|
|
163
|
+
fontFamily: 'var(--sd-font)',
|
|
164
164
|
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 10,
|
|
165
165
|
textAlign: 'center', padding: 24,
|
|
166
166
|
}}>
|
|
@@ -254,31 +254,18 @@ function QueueInner() {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
if (loading) {
|
|
257
|
-
return <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '
|
|
257
|
+
return <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--sd-page)', color: '#fff' }}>Loading...</div>;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
return (
|
|
261
261
|
<div style={{
|
|
262
|
-
height: '100vh', background: '
|
|
263
|
-
fontFamily: '-
|
|
262
|
+
height: '100vh', background: 'var(--sd-page)', color: '#fff',
|
|
263
|
+
fontFamily: 'var(--sd-font)',
|
|
264
264
|
display: 'flex', flexDirection: 'column', overflow: 'hidden',
|
|
265
265
|
}}>
|
|
266
266
|
{/* The same header as every page: the app's tabs, Outlink lit. Circles, To add,
|
|
267
267
|
Pending and Messages & follow-ups sit in the notch under it. */}
|
|
268
|
-
<
|
|
269
|
-
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
|
|
270
|
-
<Link href="/" style={{ textDecoration: 'none' }}>
|
|
271
|
-
<h1 style={{ fontSize: 28, fontWeight: 700, margin: 0, background: 'linear-gradient(135deg, #FFD700, #9B59B6, #3498DB)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>
|
|
272
|
-
Six Degrees
|
|
273
|
-
</h1>
|
|
274
|
-
</Link>
|
|
275
|
-
<AppTabs active="outlink" />
|
|
276
|
-
<Link href="/settings" title="Settings" aria-label="Settings" style={{
|
|
277
|
-
width: 32, height: 32, borderRadius: '50%', flexShrink: 0, background: 'rgba(255,255,255,0.06)', color: '#888',
|
|
278
|
-
fontSize: 16, textDecoration: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
279
|
-
}}>⚙</Link>
|
|
280
|
-
</div>
|
|
281
|
-
</header>
|
|
268
|
+
<AppHeader active="outlink" />
|
|
282
269
|
{(view === 'recs' || view === 'pending') && (
|
|
283
270
|
<div style={{ padding: '10px 24px', borderBottom: '1px solid rgba(255,255,255,0.08)', flexShrink: 0 }}>
|
|
284
271
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 10 }}>
|
|
@@ -18,7 +18,7 @@ export default function ScoresMoved() {
|
|
|
18
18
|
router.replace(at === '#health' ? '/profile?view=insights' : `/settings${at || '#scoring'}`);
|
|
19
19
|
}, [router]);
|
|
20
20
|
return (
|
|
21
|
-
<div style={{ minHeight: '100vh', background: '
|
|
21
|
+
<div style={{ minHeight: '100vh', background: 'var(--sd-page)', color: '#aab', fontFamily: FONT, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 13 }}>
|
|
22
22
|
Scores are in <Link href="/settings#scoring" style={{ color: '#3498DB', marginLeft: 4 }}>Settings</Link> now.
|
|
23
23
|
</div>
|
|
24
24
|
);
|