Skip to content

Commit 2a5e166

Browse files
committed
Improve dashboard bundle size
1 parent 4b6d66d commit 2a5e166

10 files changed

Lines changed: 103 additions & 85 deletions

File tree

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(utils)/utils.tsx

Lines changed: 0 additions & 4 deletions
This file was deleted.

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(utils)/country-data.geo.json renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/country-data.geo.json

File renamed without changes.

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(utils)/country-data.original.geo.json renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/country-data.original.geo.json

File renamed without changes.

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(metrics)/globe.tsx renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/globe.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ import { Typography } from '@stackframe/stack-ui';
66
import dynamic from 'next/dynamic';
77
import { RefObject, use, useEffect, useId, useLayoutEffect, useRef, useState } from 'react';
88
import { GlobeMethods } from 'react-globe.gl';
9-
import { globeImages } from '../(utils)/utils';
9+
10+
export const globeImages = {
11+
light: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAAaADAAQAAAABAAAAAQAAAAD5Ip3+AAAADUlEQVQIHWO48vjffwAI+QO1AqIWWgAAAABJRU5ErkJggg==',
12+
dark: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAAaADAAQAAAABAAAAAQAAAAD5Ip3+AAAADUlEQVQIHWPgF9f8DwAB1wFPLWQXmAAAAABJRU5ErkJggg=='
13+
};
1014

1115
// https://github.com/vasturiano/react-globe.gl/issues/1#issuecomment-554459831
1216
const Globe = dynamic(() => import('react-globe.gl').then((mod) => mod.default), { ssr: false });
13-
const countriesPromise = import('../(utils)/country-data.geo.json');
17+
const countriesPromise = import('./country-data.geo.json');
1418

1519
function useSize(target: RefObject<HTMLDivElement | null>) {
1620
const [size, setSize] = useState<DOMRectReadOnly>();

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(metrics)/line-chart.tsx renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/line-chart.tsx

File renamed without changes.

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(metrics)/metrics-page.tsx renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/metrics-page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { ErrorBoundary } from '@sentry/nextjs';
55
import { UserAvatar } from '@stackframe/stack';
66
import { fromNow } from '@stackframe/stack-shared/dist/utils/dates';
77
import { Card, CardContent, CardHeader, CardTitle, Table, TableBody, TableCell, TableRow, Typography } from '@stackframe/stack-ui';
8-
import { PageLayout } from "../../page-layout";
9-
import { useAdminApp } from '../../use-admin-app';
8+
import { PageLayout } from "../page-layout";
9+
import { useAdminApp } from '../use-admin-app';
1010
import { GlobeSection } from './globe';
1111
import { DonutChartDisplay, LineChartDisplay, LineChartDisplayConfig } from './line-chart';
1212

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/page-client.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import { stackAppInternalsSymbol } from "@/app/(main)/integrations/transfer-confirm-page";
44
import { useState } from "react";
55
import { useAdminApp } from "../use-admin-app";
6-
import MetricsPage from "./(metrics)/metrics-page";
7-
import SetupPage from "./(setup)/setup-page";
6+
import MetricsPage from "./metrics-page";
7+
import SetupPage from "./setup-page";
88

99
export default function PageClient() {
1010
const adminApp = useAdminApp();

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(setup)/setup-page.module.css renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/setup-page.module.css

File renamed without changes.

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/(setup)/setup-page.tsx renamed to apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/setup-page.tsx

Lines changed: 84 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,21 @@ import { Button, Tabs, TabsContent, TabsList, TabsTrigger, Typography, cn } from
1010
import { Book, X } from "lucide-react";
1111
import dynamic from "next/dynamic";
1212
import 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';
1818
import styles from './setup-page.module.css';
19-
const countriesPromise = import('../(utils)/country-data.geo.json');
19+
20+
const countriesPromise = import('./country-data.geo.json');
2021
const Globe = dynamic(() => import('react-globe.gl').then((mod) => mod.default), { ssr: false });
2122

2223
const commandClasses = "text-red-600 dark:text-red-400";
2324
const nameClasses = "text-green-600 dark:text-green-500";
2425

2526
export 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+
597607
function StackAuthKeys(props: {
598608
keys: { projectId: string, publishableClientKey: string, secretServerKey: string } | null,
599609
onGenerateKeys: () => Promise<void>,

apps/dashboard/src/components/code-block.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,17 @@
33
import { useThemeWatcher } from '@/lib/theme';
44
import { CopyButton } from "@stackframe/stack-ui";
55
import { Code, Terminal } from "lucide-react";
6-
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
6+
import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
7+
import bash from 'react-syntax-highlighter/dist/esm/languages/prism/bash';
8+
import python from 'react-syntax-highlighter/dist/esm/languages/prism/python';
9+
import tsx from 'react-syntax-highlighter/dist/esm/languages/prism/tsx';
10+
import typescript from 'react-syntax-highlighter/dist/esm/languages/prism/typescript';
711
import { dark, prism } from 'react-syntax-highlighter/dist/esm/styles/prism';
812

13+
Object.entries({ tsx, bash, typescript, python }).forEach(([key, value]) => {
14+
SyntaxHighlighter.registerLanguage(key, value);
15+
});
16+
917
export function CodeBlock(props: {
1018
language: string,
1119
content: string,

0 commit comments

Comments
 (0)