Merge pull request 'ui/scene: add loading splash screen' (#4400) from scene-progress into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4400
This commit is contained in:
1
pkgs/clan-app/ui/logos/darknet-builder-logo.svg
Normal file
1
pkgs/clan-app/ui/logos/darknet-builder-logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
4
pkgs/clan-app/ui/src/routes/Clan/Clan.css
Normal file
4
pkgs/clan-app/ui/src/routes/Clan/Clan.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.fade-out {
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RouteSectionProps } from "@solidjs/router";
|
||||
import { Component, createEffect, JSX } from "solid-js";
|
||||
import { Component, JSX } from "solid-js";
|
||||
import { useClanURI } from "@/src/hooks/clan";
|
||||
import { CubeScene } from "@/src/scene/cubes";
|
||||
import { MachinesQueryResult, useMachinesQuery } from "@/src/queries/queries";
|
||||
@@ -7,6 +7,9 @@ import { callApi } from "@/src/hooks/api";
|
||||
import { store, setStore } from "@/src/stores/clan";
|
||||
import { produce } from "solid-js/store";
|
||||
import { Button } from "@/src/components/Button/Button";
|
||||
import { Splash } from "@/src/scene/splash";
|
||||
import cx from "classnames";
|
||||
import "./Clan.css";
|
||||
|
||||
export const Clan: Component<RouteSectionProps> = (props) => {
|
||||
return (
|
||||
@@ -49,10 +52,6 @@ const ClanSceneController = () => {
|
||||
return;
|
||||
};
|
||||
|
||||
createEffect(() => {
|
||||
console.log("sceneData changed:", store.sceneData);
|
||||
});
|
||||
|
||||
return (
|
||||
<SceneDataProvider clanURI={clanURI}>
|
||||
{({ query }) => {
|
||||
@@ -87,7 +86,12 @@ const ClanSceneController = () => {
|
||||
Refetch API
|
||||
</Button>
|
||||
</div>
|
||||
{/* TODO: Add minimal display time */}
|
||||
<div class={cx({ "fade-out": !query.isLoading })}>
|
||||
<Splash />
|
||||
</div>
|
||||
<CubeScene
|
||||
isLoading={query.isLoading}
|
||||
cubesQuery={query}
|
||||
onCreate={onCreate}
|
||||
sceneStore={() => {
|
||||
|
||||
@@ -69,6 +69,7 @@ export function CubeScene(props: {
|
||||
onCreate?: (id: string) => Promise<void>;
|
||||
sceneStore: Accessor<SceneData>;
|
||||
setMachinePos: (machineId: string, pos: [number, number]) => void;
|
||||
isLoading: boolean;
|
||||
}) {
|
||||
// sceneData.cubesQuer
|
||||
let container: HTMLDivElement;
|
||||
@@ -78,7 +79,7 @@ export function CubeScene(props: {
|
||||
let floor: THREE.Mesh;
|
||||
let controls: MapControls;
|
||||
// Raycaster for clicking
|
||||
let raycaster = new THREE.Raycaster();
|
||||
const raycaster = new THREE.Raycaster();
|
||||
|
||||
let needsRender = false; // Flag to control rendering
|
||||
|
||||
@@ -181,6 +182,7 @@ export function CubeScene(props: {
|
||||
requestAnimationFrame(renderScene);
|
||||
}
|
||||
}
|
||||
|
||||
function renderScene() {
|
||||
if (!isAnimating) return;
|
||||
needsRender = false;
|
||||
@@ -587,9 +589,6 @@ export function CubeScene(props: {
|
||||
BASE_SIZE,
|
||||
);
|
||||
|
||||
// Basic OrbitControls implementation (simplified)
|
||||
let isDragging = false;
|
||||
let previousMousePosition = { x: 0, y: 0 };
|
||||
// const spherical = new THREE.Spherical();
|
||||
// spherical.setFromVector3(camera.position);
|
||||
|
||||
|
||||
45
pkgs/clan-app/ui/src/scene/splash.css
Normal file
45
pkgs/clan-app/ui/src/scene/splash.css
Normal file
@@ -0,0 +1,45 @@
|
||||
#splash {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: linear-gradient(to top, #e3e7e7, #edf1f1);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#splash .content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply h-8 mb-8;
|
||||
}
|
||||
|
||||
.loader {
|
||||
@apply h-3 w-60 mb-3;
|
||||
width: 18rem;
|
||||
background: repeating-linear-gradient(
|
||||
-45deg,
|
||||
#bfd0d2 0px,
|
||||
#bfd0d2 10px,
|
||||
#f7f9fa 10px,
|
||||
#f7f9fa 20px
|
||||
);
|
||||
animation: stripe-move 1s linear infinite;
|
||||
background-size: 28px 28px; /* Sqrt(20^2 + 20^2) ~= 28 */
|
||||
|
||||
@apply border-2 border-solid rounded-[3px] border-bg-def-1;
|
||||
}
|
||||
|
||||
@keyframes stripe-move {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 28px 0;
|
||||
}
|
||||
}
|
||||
15
pkgs/clan-app/ui/src/scene/splash.stories.tsx
Normal file
15
pkgs/clan-app/ui/src/scene/splash.stories.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Meta, StoryObj } from "@kachurun/storybook-solid";
|
||||
import { Splash } from "./splash";
|
||||
|
||||
const meta: Meta = {
|
||||
title: "scene/splash",
|
||||
component: Splash,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
};
|
||||
18
pkgs/clan-app/ui/src/scene/splash.tsx
Normal file
18
pkgs/clan-app/ui/src/scene/splash.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import Logo from "@/logos/darknet-builder-logo.svg";
|
||||
import "./splash.css";
|
||||
import { Typography } from "../components/Typography/Typography";
|
||||
|
||||
export const Splash = () => (
|
||||
<div id="splash">
|
||||
<div class="content">
|
||||
<span class="title">
|
||||
<Logo />
|
||||
</span>
|
||||
<div class="loader"></div>
|
||||
|
||||
<Typography hierarchy="label" size="xs" weight="medium">
|
||||
Loading new Clan
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
Reference in New Issue
Block a user