@@ -10,24 +10,21 @@ import { Button, Tabs, TabsContent, TabsList, TabsTrigger, Typography, cn } from
1010import { Book , X } from "lucide-react" ;
1111import dynamic from "next/dynamic" ;
1212import Image from 'next/image' ;
13- import { use , useEffect , useRef , useState } from "react" ;
14- import { GlobeMethods } from " react-globe.gl" ;
15- import { globeImages } from ' ../(utils)/utils' ;
16- import { PageLayout } from " ../../page-layout" ;
17- import { useAdminApp } from '../../use-admin-app ' ;
13+ import { Suspense , use , useRef , useState } from "react" ;
14+ import type { GlobeMethods } from ' react-globe.gl' ;
15+ import { PageLayout } from " ../page-layout" ;
16+ import { useAdminApp } from ' ../use-admin-app' ;
17+ import { globeImages } from './globe ' ;
1818import styles from './setup-page.module.css' ;
19- const countriesPromise = import ( '../(utils)/country-data.geo.json' ) ;
19+
20+ const countriesPromise = import ( './country-data.geo.json' ) ;
2021const Globe = dynamic ( ( ) => import ( 'react-globe.gl' ) . then ( ( mod ) => mod . default ) , { ssr : false } ) ;
2122
2223const commandClasses = "text-red-600 dark:text-red-400" ;
2324const nameClasses = "text-green-600 dark:text-green-500" ;
2425
2526export default function SetupPage ( props : { toMetrics : ( ) => void } ) {
2627 const adminApp = useAdminApp ( ) ;
27- const countries = use ( countriesPromise ) ;
28- const globeEl = useRef < GlobeMethods | undefined > ( undefined ) ;
29- const { theme, mounted } = useThemeWatcher ( ) ;
30- const [ showPulse , setShowPulse ] = useState ( false ) ;
3128 const [ selectedFramework , setSelectedFramework ] = useState < 'nextjs' | 'react' | 'javascript' | 'python' > ( 'nextjs' ) ;
3229 const [ keys , setKeys ] = useState < { projectId : string , publishableClientKey : string , secretServerKey : string } | null > ( null ) ;
3330
@@ -47,15 +44,6 @@ export default function SetupPage(props: { toMetrics: () => void }) {
4744 } ) ;
4845 } ;
4946
50- useEffect ( ( ) => {
51- // Add delay before showing pulse circles in order to allow the globe to animate in
52- const timer = setTimeout ( ( ) => {
53- setShowPulse ( true ) ;
54- } , 1000 ) ;
55-
56- return ( ) => clearTimeout ( timer ) ;
57- } , [ ] ) ;
58-
5947 const nextJsSteps = [
6048 {
6149 step : 2 ,
@@ -178,7 +166,7 @@ export default function SetupPage(props: { toMetrics: () => void }) {
178166
179167 export default function App() {
180168 return (
181- <Suspense fallback={null }>
169+ <Suspense fallback={"Loading..." }>
182170 <BrowserRouter>
183171 <StackProvider app={stackClientApp}>
184172 <StackTheme>
@@ -440,60 +428,7 @@ export default function SetupPage(props: { toMetrics: () => void }) {
440428 </ Button >
441429 </ div >
442430 < div className = "flex gap-4 justify-center items-center border rounded-2xl py-4 px-8 backdrop-blur-md bg-white/20 dark:bg-black/20" >
443- < div className = "w-[200px] h-[200px] relative hidden md:block" >
444- { showPulse && (
445- < div className = "absolute inset-0 pointer-events-none w-[200px] h-[200px] flex items-center justify-center" >
446- { [ ...Array ( 3 ) ] . map ( ( _ , i ) => (
447- < div
448- key = { i }
449- className = { `${ styles [ 'pulse-circle' ] } rounded-full bg-blue-200 dark:bg-blue-800` }
450- style = { {
451- width : "50px" ,
452- height : "50px" ,
453- animationDelay : `${ i * 2.5 } s` ,
454- } }
455- />
456- ) ) }
457- </ div >
458- ) }
459-
460- < div className = "relative z-10 items-center justify-center w-full h-full hidden md:flex" >
461- { mounted && (
462- < Globe
463- ref = { globeEl }
464- onGlobeReady = { ( ) => {
465- const setupControls = ( ) => {
466- if ( globeEl . current ) {
467- const controls = globeEl . current . controls ( ) ;
468- controls . autoRotate = true ;
469- controls . enableZoom = false ;
470- controls . enablePan = false ;
471- controls . enableRotate = false ;
472- return true ;
473- }
474- return false ;
475- } ;
476-
477- setupControls ( ) ;
478- // Sometimes the controls don't get set up in time, so we try again
479- setTimeout ( setupControls , 100 ) ;
480- } }
481- globeImageUrl = { globeImages [ theme ] }
482- backgroundColor = "#00000000"
483- polygonsData = { countries . features }
484- polygonCapColor = { ( ) => "transparent" }
485- polygonSideColor = { ( ) => "transparent" }
486- hexPolygonsData = { countries . features }
487- hexPolygonResolution = { 1 }
488- hexPolygonMargin = { 0.2 }
489- hexPolygonAltitude = { 0.003 }
490- hexPolygonColor = { ( ) => "rgb(107, 93, 247)" }
491- width = { 160 }
492- height = { 160 }
493- />
494- ) }
495- </ div >
496- </ div >
431+ < GlobeIllustration />
497432
498433 < div className = "flex flex-col gap-4" >
499434 < div className = "flex flex-col gap-1" >
@@ -594,6 +529,81 @@ export default function SetupPage(props: { toMetrics: () => void }) {
594529 ) ;
595530}
596531
532+ function GlobeIllustration ( ) {
533+ return (
534+ < div className = "w-[200px] h-[200px] relative hidden md:block" >
535+ < Suspense fallback = { "LOADING" } >
536+ < GlobeIllustrationInner />
537+ </ Suspense >
538+ </ div >
539+ ) ;
540+ }
541+
542+ function GlobeIllustrationInner ( ) {
543+ const { theme, mounted } = useThemeWatcher ( ) ;
544+ const [ showPulse , setShowPulse ] = useState ( false ) ;
545+ const globeEl = useRef < GlobeMethods | undefined > ( undefined ) ;
546+ const countries = use ( countriesPromise ) ;
547+
548+ return (
549+ < >
550+ { showPulse && (
551+ < div className = "absolute inset-0 pointer-events-none w-[200px] h-[200px] flex items-center justify-center" >
552+ { [ ...Array ( 3 ) ] . map ( ( _ , i ) => (
553+ < div
554+ key = { i }
555+ className = { `${ styles [ 'pulse-circle' ] } rounded-full bg-blue-200 dark:bg-blue-800` }
556+ style = { {
557+ width : "50px" ,
558+ height : "50px" ,
559+ animationDelay : `${ i * 2.5 } s` ,
560+ } }
561+ />
562+ ) ) }
563+ </ div >
564+ ) }
565+
566+ < div className = "relative z-10 items-center justify-center w-full h-full hidden md:flex" >
567+ { mounted && (
568+ < Globe
569+ ref = { globeEl }
570+ onGlobeReady = { ( ) => {
571+ const setupControls = ( ) => {
572+ if ( globeEl . current ) {
573+ const controls = globeEl . current . controls ( ) ;
574+ controls . autoRotate = true ;
575+ controls . enableZoom = false ;
576+ controls . enablePan = false ;
577+ controls . enableRotate = false ;
578+ return true ;
579+ }
580+ return false ;
581+ } ;
582+
583+ setupControls ( ) ;
584+ // Sometimes the controls don't get set up in time, so we try again
585+ setTimeout ( setupControls , 100 ) ;
586+ setTimeout ( ( ) => setShowPulse ( true ) , 200 ) ;
587+ } }
588+ globeImageUrl = { globeImages [ theme ] }
589+ backgroundColor = "#00000000"
590+ polygonsData = { countries . features }
591+ polygonCapColor = { ( ) => "transparent" }
592+ polygonSideColor = { ( ) => "transparent" }
593+ hexPolygonsData = { countries . features }
594+ hexPolygonResolution = { 1 }
595+ hexPolygonMargin = { 0.2 }
596+ hexPolygonAltitude = { 0.003 }
597+ hexPolygonColor = { ( ) => "rgb(107, 93, 247)" }
598+ width = { 160 }
599+ height = { 160 }
600+ />
601+ ) }
602+ </ div >
603+ </ >
604+ ) ;
605+ }
606+
597607function StackAuthKeys ( props : {
598608 keys : { projectId : string , publishableClientKey : string , secretServerKey : string } | null ,
599609 onGenerateKeys : ( ) => Promise < void > ,
0 commit comments