diff --git a/site/src/pages/TemplateBuilder/BuildingTemplateLoader.stories.tsx b/site/src/pages/TemplateBuilder/BuildingTemplateLoader.stories.tsx new file mode 100644 index 0000000000..8387436840 --- /dev/null +++ b/site/src/pages/TemplateBuilder/BuildingTemplateLoader.stories.tsx @@ -0,0 +1,19 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { BuildingTemplateLoader } from "./BuildingTemplateLoader"; + +const meta: Meta = { + title: "pages/TemplateBuilder/BuildingTemplateLoader", + component: BuildingTemplateLoader, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/site/src/pages/TemplateBuilder/BuildingTemplateLoader.tsx b/site/src/pages/TemplateBuilder/BuildingTemplateLoader.tsx new file mode 100644 index 0000000000..8b6c434aef --- /dev/null +++ b/site/src/pages/TemplateBuilder/BuildingTemplateLoader.tsx @@ -0,0 +1,128 @@ +import { + CodeIcon, + DatabaseIcon, + KeyIcon, + LayoutTemplateIcon, + PackageIcon, + WrenchIcon, +} from "lucide-react"; +import { motion } from "motion/react"; +import type { FC } from "react"; + +type FloatingIcon = { + name: string; + icon: FC<{ className?: string }>; + // Position as percentage offsets from the container center. + x: number; + y: number; + delay: number; +}; + +const ICONS: FloatingIcon[] = [ + { name: "package", icon: PackageIcon, x: -18, y: 20, delay: 0 }, + { name: "key", icon: KeyIcon, x: -25, y: -10, delay: 0.4 }, + { name: "code", icon: CodeIcon, x: 15, y: 25, delay: 0.8 }, + { name: "database", icon: DatabaseIcon, x: 18, y: -30, delay: 1.2 }, + { name: "wrench", icon: WrenchIcon, x: 10, y: 0, delay: 1.6 }, + { name: "template", icon: LayoutTemplateIcon, x: 28, y: -8, delay: 2.0 }, +]; + +/** + * Full-area animated loader displayed while the template builder compose + * API call is in flight. Shows floating icon boxes, a progress bar, and + * an animated "Building your template..." label. + */ +export const BuildingTemplateLoader: FC = () => { + return ( +
+ {/* Floating icon boxes; bottom-24 keeps them above the progress bar */} +
+ {ICONS.map(({ name, icon: Icon, x, y, delay }) => ( + + + + ))} +
+ + {/* Progress bar and label */} +
+ {/* Progress track */} +
+
+ +
+
+ + {/* Label */} +

+ Building your template + + + . + + + . + + + . + + +

+
+
+ ); +}; diff --git a/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx b/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx index 061918ba30..728a12094d 100644 --- a/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx +++ b/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx @@ -20,6 +20,7 @@ import { BaseTemplateParametersStep, baseParametersComplete, } from "./BaseTemplateParametersStep"; +import { BuildingTemplateLoader } from "./BuildingTemplateLoader"; import { ModuleSelectStep } from "./ModuleSelectStep"; import { ModuleSettingsStep, @@ -103,6 +104,10 @@ export const TemplateBuilderPageView: FC = ({ }); }; + if (isCreating) { + return ; + } + return ( @@ -143,12 +148,8 @@ export const TemplateBuilderPageView: FC = ({ Back )} -