etape color
This commit is contained in:
parent
33bd462f87
commit
2e16353f5e
15 changed files with 325 additions and 31 deletions
|
|
@ -15,6 +15,7 @@ import {
|
|||
useTasksByTablo,
|
||||
useUpdateEtape,
|
||||
} from "../hooks/tasks";
|
||||
import { getEtapeColor } from "../utils/etapeColors";
|
||||
|
||||
interface TabloOverviewSectionProps {
|
||||
tablo: UserTablo;
|
||||
|
|
@ -163,10 +164,11 @@ export const TabloOverviewSection = ({ tablo, isAdmin }: TabloOverviewSectionPro
|
|||
<ul className="space-y-3">
|
||||
{sortedEtapes.map((etape, index) => {
|
||||
const isEditing = editingEtapeId === etape.id;
|
||||
const etapeColor = getEtapeColor(etape.position);
|
||||
return (
|
||||
<li
|
||||
key={etape.id}
|
||||
className="flex items-start gap-3 rounded-lg border border-border bg-card/40 px-4 py-3"
|
||||
className={`flex items-start gap-3 rounded-lg border px-4 py-3 ${etapeColor.bg} ${etapeColor.border}`}
|
||||
>
|
||||
{canManageEtapes && (
|
||||
<div className="flex flex-col gap-1 pt-1">
|
||||
|
|
@ -224,27 +226,27 @@ export const TabloOverviewSection = ({ tablo, isAdmin }: TabloOverviewSectionPro
|
|||
</div>
|
||||
) : (
|
||||
<>
|
||||
<TypographyP className="text-base font-medium text-foreground">
|
||||
<TypographyP className={`text-base font-medium ${etapeColor.text}`}>
|
||||
{etape.title}
|
||||
</TypographyP>
|
||||
<TypographyMuted className="text-xs text-muted-foreground">
|
||||
<TypographyMuted className={`text-xs ${etapeColor.text} opacity-70`}>
|
||||
Étape {etape.position + 1}
|
||||
</TypographyMuted>
|
||||
{(() => {
|
||||
const { total, done, ongoing } = getEtapeTaskCounts(etape.id);
|
||||
return (
|
||||
<div className="flex gap-3 mt-2 text-xs">
|
||||
<span className="text-muted-foreground">
|
||||
<span className="font-medium text-foreground">{total}</span>{" "}
|
||||
<div className={`flex gap-3 mt-2 text-xs ${etapeColor.text}`}>
|
||||
<span className="opacity-70">
|
||||
<span className="font-medium opacity-100">{total}</span>{" "}
|
||||
{pluralize("tâche", total)}
|
||||
</span>
|
||||
{ongoing > 0 && (
|
||||
<span className="text-blue-600 dark:text-blue-400">
|
||||
<span className="opacity-90">
|
||||
<span className="font-medium">{ongoing}</span> en cours
|
||||
</span>
|
||||
)}
|
||||
{done > 0 && (
|
||||
<span className="text-green-600 dark:text-green-400">
|
||||
<span className="opacity-90">
|
||||
<span className="font-medium">{done}</span>{" "}
|
||||
{pluralize("terminée", done)}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
useTasksByTablo,
|
||||
useUpdateTaskPositions,
|
||||
} from "../hooks/tasks";
|
||||
import { getEtapeColor } from "../utils/etapeColors";
|
||||
import { KanbanBoard } from "./kanban/KanbanBoard";
|
||||
import { TaskModal } from "./kanban/TaskModal";
|
||||
|
||||
|
|
@ -39,6 +40,15 @@ export const TabloTasksSection = ({ tablo }: TabloTasksSectionProps) => {
|
|||
[etapes]
|
||||
);
|
||||
|
||||
const etapeColorMap = useMemo(
|
||||
() =>
|
||||
etapes.reduce<Record<string, ReturnType<typeof getEtapeColor>>>((map, etape) => {
|
||||
map[etape.id] = getEtapeColor(etape.position);
|
||||
return map;
|
||||
}, {}),
|
||||
[etapes]
|
||||
);
|
||||
|
||||
// Check for tasks without parent (orphaned tasks)
|
||||
const orphanedTasks = useMemo(() => {
|
||||
return tasks?.filter((task) => !task.parent_task_id) || [];
|
||||
|
|
@ -196,6 +206,7 @@ export const TabloTasksSection = ({ tablo }: TabloTasksSectionProps) => {
|
|||
members={members}
|
||||
etapes={etapes}
|
||||
etapeTitles={etapeTitleMap}
|
||||
etapeColors={etapeColorMap}
|
||||
onTaskClick={handleTaskClick}
|
||||
onAddTask={handleAddTask}
|
||||
onAddTaskInline={handleCreateTask}
|
||||
|
|
|
|||
168
apps/main/src/components/ThreeLoginBackground.tsx
Normal file
168
apps/main/src/components/ThreeLoginBackground.tsx
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import { useEffect, useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
|
||||
const usePrefersReducedMotion = () => {
|
||||
if (typeof window === "undefined") return true;
|
||||
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
};
|
||||
|
||||
export const ThreeLoginBackground = () => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
if (usePrefersReducedMotion()) return;
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
antialias: true,
|
||||
alpha: true,
|
||||
});
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
containerRef.current.appendChild(renderer.domElement);
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.fog = new THREE.FogExp2(0x030014, 0.035);
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
45,
|
||||
window.innerWidth / window.innerHeight,
|
||||
0.1,
|
||||
100
|
||||
);
|
||||
camera.position.set(0, 0, 14);
|
||||
|
||||
const ambientLight = new THREE.AmbientLight(0x6d28d9, 0.6);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const pointLight = new THREE.PointLight(0x8b5cf6, 40, 40);
|
||||
pointLight.position.set(5, 5, 6);
|
||||
scene.add(pointLight);
|
||||
|
||||
const rimLight = new THREE.PointLight(0x38bdf8, 25, 30);
|
||||
rimLight.position.set(-4, -3, -6);
|
||||
scene.add(rimLight);
|
||||
|
||||
const coreGeometry = new THREE.IcosahedronGeometry(3, 1);
|
||||
const coreMaterial = new THREE.MeshStandardMaterial({
|
||||
color: new THREE.Color("#8b5cf6"),
|
||||
emissive: new THREE.Color("#6366f1"),
|
||||
metalness: 0.85,
|
||||
roughness: 0.2,
|
||||
transparent: true,
|
||||
opacity: 0.8,
|
||||
wireframe: true,
|
||||
});
|
||||
const core = new THREE.Mesh(coreGeometry, coreMaterial);
|
||||
scene.add(core);
|
||||
|
||||
const haloGeometry = new THREE.RingGeometry(4.2, 5.6, 128);
|
||||
const haloMaterial = new THREE.MeshBasicMaterial({
|
||||
color: 0x38bdf8,
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
opacity: 0.25,
|
||||
});
|
||||
const halo = new THREE.Mesh(haloGeometry, haloMaterial);
|
||||
halo.rotation.x = Math.PI / 2.4;
|
||||
scene.add(halo);
|
||||
|
||||
const orbitCount = 1200;
|
||||
const orbitPositions = new Float32Array(orbitCount * 3);
|
||||
for (let i = 0; i < orbitCount; i += 1) {
|
||||
const radius = 7 + Math.random() * 8;
|
||||
const angle = Math.random() * Math.PI * 2;
|
||||
orbitPositions[i * 3] = Math.cos(angle) * radius;
|
||||
orbitPositions[i * 3 + 1] = (Math.random() - 0.5) * 6;
|
||||
orbitPositions[i * 3 + 2] = Math.sin(angle) * radius;
|
||||
}
|
||||
const orbitGeometry = new THREE.BufferGeometry();
|
||||
orbitGeometry.setAttribute("position", new THREE.BufferAttribute(orbitPositions, 3));
|
||||
const orbitMaterial = new THREE.PointsMaterial({
|
||||
color: 0x818cf8,
|
||||
size: 0.07,
|
||||
transparent: true,
|
||||
opacity: 0.65,
|
||||
});
|
||||
const orbitField = new THREE.Points(orbitGeometry, orbitMaterial);
|
||||
scene.add(orbitField);
|
||||
|
||||
const floatingGeometry = new THREE.TetrahedronGeometry(0.35);
|
||||
const floatingMaterial = new THREE.MeshStandardMaterial({
|
||||
color: 0xffffff,
|
||||
emissive: 0x7c3aed,
|
||||
emissiveIntensity: 0.4,
|
||||
metalness: 0.4,
|
||||
roughness: 0.3,
|
||||
});
|
||||
const floatingMeshes: THREE.Mesh[] = [];
|
||||
for (let i = 0; i < 25; i += 1) {
|
||||
const mesh = new THREE.Mesh(floatingGeometry, floatingMaterial.clone());
|
||||
mesh.position.set(
|
||||
(Math.random() - 0.5) * 20,
|
||||
(Math.random() - 0.5) * 10,
|
||||
(Math.random() - 0.5) * 20
|
||||
);
|
||||
mesh.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI);
|
||||
mesh.scale.setScalar(0.6 + Math.random() * 0.9);
|
||||
floatingMeshes.push(mesh);
|
||||
scene.add(mesh);
|
||||
}
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
let frameId: number;
|
||||
|
||||
const animate = () => {
|
||||
const elapsed = clock.getElapsedTime();
|
||||
core.rotation.x = elapsed * 0.2;
|
||||
core.rotation.y = elapsed * 0.3;
|
||||
halo.rotation.z = elapsed * 0.1;
|
||||
|
||||
orbitField.rotation.y = elapsed * 0.05;
|
||||
orbitField.rotation.x = Math.sin(elapsed * 0.1) * 0.05;
|
||||
|
||||
floatingMeshes.forEach((mesh, index) => {
|
||||
mesh.position.y += Math.sin(elapsed + index) * 0.002;
|
||||
mesh.rotation.x += 0.005;
|
||||
mesh.rotation.y += 0.008;
|
||||
});
|
||||
|
||||
camera.position.x = Math.sin(elapsed * 0.2) * 1.5;
|
||||
camera.position.y = Math.cos(elapsed * 0.15) * 0.8;
|
||||
camera.lookAt(0, 0, 0);
|
||||
|
||||
renderer.render(scene, camera);
|
||||
frameId = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
const handleResize = () => {
|
||||
const { innerWidth, innerHeight } = window;
|
||||
camera.aspect = innerWidth / innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(innerWidth, innerHeight);
|
||||
};
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(frameId);
|
||||
window.removeEventListener("resize", handleResize);
|
||||
renderer.dispose();
|
||||
coreGeometry.dispose();
|
||||
haloGeometry.dispose();
|
||||
orbitGeometry.dispose();
|
||||
floatingGeometry.dispose();
|
||||
containerRef.current?.removeChild(renderer.domElement);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="absolute inset-0 -z-10 pointer-events-none"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -5,6 +5,7 @@ import type {
|
|||
TaskStatus,
|
||||
} from "@xtablo/shared-types";
|
||||
import { useState } from "react";
|
||||
import type { getEtapeColor } from "../../utils/etapeColors";
|
||||
import { KanbanColumn } from "./KanbanColumn";
|
||||
import type { TabloMember } from "./types";
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ interface KanbanBoardProps {
|
|||
members: TabloMember[];
|
||||
etapes: Etape[];
|
||||
etapeTitles: Record<string, string>;
|
||||
etapeColors: Record<string, ReturnType<typeof getEtapeColor>>;
|
||||
onTaskClick: (task: KanbanTask) => void;
|
||||
onAddTask: (status: TaskStatus) => void;
|
||||
onAddTaskInline: (task: {
|
||||
|
|
@ -29,6 +31,7 @@ export const KanbanBoard = ({
|
|||
columns,
|
||||
members,
|
||||
etapes,
|
||||
etapeColors,
|
||||
onTaskClick,
|
||||
onAddTask,
|
||||
onAddTaskInline,
|
||||
|
|
@ -62,6 +65,7 @@ export const KanbanBoard = ({
|
|||
column={column}
|
||||
members={members}
|
||||
etapes={etapes}
|
||||
etapeColors={etapeColors}
|
||||
onTaskClick={onTaskClick}
|
||||
onAddTask={onAddTask}
|
||||
onAddTaskInline={onAddTaskInline}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import type {
|
|||
} from "@xtablo/shared-types";
|
||||
import { Button } from "@xtablo/ui/components/button";
|
||||
import { Plus } from "lucide-react";
|
||||
import type { getEtapeColor } from "../../utils/etapeColors";
|
||||
import { InlineTaskCreate } from "./InlineTaskCreate";
|
||||
import { KanbanTaskCard } from "./KanbanTaskCard";
|
||||
import type { TabloMember } from "./types";
|
||||
|
|
@ -14,6 +15,7 @@ interface KanbanColumnProps {
|
|||
column: KanbanColumnType;
|
||||
members: TabloMember[];
|
||||
etapes: Etape[];
|
||||
etapeColors: Record<string, ReturnType<typeof getEtapeColor>>;
|
||||
onTaskClick: (task: KanbanTask) => void;
|
||||
onAddTask: (status: KanbanColumnType["status"]) => void;
|
||||
onAddTaskInline: (task: {
|
||||
|
|
@ -32,6 +34,7 @@ export const KanbanColumn = ({
|
|||
column,
|
||||
members,
|
||||
etapes,
|
||||
etapeColors,
|
||||
onTaskClick,
|
||||
onAddTask,
|
||||
onAddTaskInline,
|
||||
|
|
@ -71,22 +74,24 @@ export const KanbanColumn = ({
|
|||
Aucune tâche
|
||||
</div>
|
||||
) : (
|
||||
column.tasks.map((task: KanbanTask) => (
|
||||
<div
|
||||
key={task.id}
|
||||
draggable
|
||||
onDragStart={(e) => onDragStart(e, task)}
|
||||
className="cursor-move"
|
||||
>
|
||||
<KanbanTaskCard
|
||||
task={task}
|
||||
etapeTitle={
|
||||
etapes.find((etape) => etape.id === task.parent_task_id)?.title ?? undefined
|
||||
}
|
||||
onClick={() => onTaskClick(task)}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
column.tasks.map((task: KanbanTask) => {
|
||||
const etape = etapes.find((e) => e.id === task.parent_task_id);
|
||||
return (
|
||||
<div
|
||||
key={task.id}
|
||||
draggable
|
||||
onDragStart={(e) => onDragStart(e, task)}
|
||||
className="cursor-move"
|
||||
>
|
||||
<KanbanTaskCard
|
||||
task={task}
|
||||
etapeTitle={etape?.title}
|
||||
etapeColor={task.parent_task_id ? etapeColors[task.parent_task_id] : undefined}
|
||||
onClick={() => onTaskClick(task)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import type { KanbanTask } from "@xtablo/shared-types";
|
||||
import { TypographyH4, TypographyMuted } from "@xtablo/ui/components/typography";
|
||||
import { User } from "lucide-react";
|
||||
import type { getEtapeColor } from "../../utils/etapeColors";
|
||||
|
||||
interface KanbanTaskCardProps {
|
||||
task: KanbanTask;
|
||||
etapeTitle?: string;
|
||||
etapeColor?: ReturnType<typeof getEtapeColor>;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const KanbanTaskCard = ({ task, etapeTitle, onClick }: KanbanTaskCardProps) => {
|
||||
export const KanbanTaskCard = ({ task, etapeTitle, etapeColor, onClick }: KanbanTaskCardProps) => {
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
|
|
@ -24,11 +26,13 @@ export const KanbanTaskCard = ({ task, etapeTitle, onClick }: KanbanTaskCardProp
|
|||
</TypographyMuted>
|
||||
)}
|
||||
|
||||
{/* Status Pill */}
|
||||
{/* Status Pill with Etape Color */}
|
||||
<div className="mb-2">
|
||||
<span
|
||||
className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${
|
||||
etapeTitle ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"
|
||||
className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium border ${
|
||||
etapeColor
|
||||
? `${etapeColor.bg} ${etapeColor.text} ${etapeColor.border}`
|
||||
: "bg-muted text-muted-foreground border-muted"
|
||||
}`}
|
||||
>
|
||||
{etapeTitle ?? "Sans Étape"}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { AnimatedBackground } from "@ui/components/AnimatedBackground";
|
||||
import { LoginWithGoogle } from "@ui/components/BrandButtons/LoginWithGoogle";
|
||||
import { useTheme } from "@xtablo/shared/contexts/ThemeContext";
|
||||
import { Button } from "@xtablo/ui/components/button";
|
||||
|
|
@ -11,6 +10,7 @@ import { useTranslation } from "react-i18next";
|
|||
import { Link, useSearchParams } from "react-router-dom";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { useLoginEmail } from "../hooks/auth";
|
||||
import { ThreeLoginBackground } from "../components/ThreeLoginBackground";
|
||||
|
||||
export function LoginPage() {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
|
@ -96,7 +96,8 @@ export function LoginPage() {
|
|||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-linear-to-br from-primary/10 via-background to-secondary/5 animate-gradient-x bg-size-[400%_400%] relative overflow-hidden">
|
||||
<AnimatedBackground />
|
||||
<ThreeLoginBackground />
|
||||
{/* <AnimatedBackground /> */}
|
||||
<div
|
||||
ref={cardRef}
|
||||
className={twMerge(
|
||||
|
|
|
|||
40
apps/main/src/utils/etapeColors.ts
Normal file
40
apps/main/src/utils/etapeColors.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Get color classes for an etape based on its position
|
||||
* Colors cycle through: yellow (light), green, blue, gray
|
||||
*/
|
||||
export const getEtapeColor = (position: number) => {
|
||||
const colors = [
|
||||
{
|
||||
// Light/Yellow
|
||||
bg: "bg-yellow-100 dark:bg-yellow-950/30",
|
||||
text: "text-yellow-700 dark:text-yellow-400",
|
||||
border: "border-yellow-200 dark:border-yellow-900/50",
|
||||
indicator: "bg-yellow-400 dark:bg-yellow-500",
|
||||
},
|
||||
{
|
||||
// Green
|
||||
bg: "bg-green-100 dark:bg-green-950/30",
|
||||
text: "text-green-700 dark:text-green-400",
|
||||
border: "border-green-200 dark:border-green-900/50",
|
||||
indicator: "bg-green-400 dark:bg-green-500",
|
||||
},
|
||||
{
|
||||
// Blue
|
||||
bg: "bg-blue-100 dark:bg-blue-950/30",
|
||||
text: "text-blue-700 dark:text-blue-400",
|
||||
border: "border-blue-200 dark:border-blue-900/50",
|
||||
indicator: "bg-blue-400 dark:bg-blue-500",
|
||||
},
|
||||
{
|
||||
// Gray
|
||||
bg: "bg-gray-100 dark:bg-gray-800/30",
|
||||
text: "text-gray-700 dark:text-gray-400",
|
||||
border: "border-gray-200 dark:border-gray-700/50",
|
||||
indicator: "bg-gray-400 dark:bg-gray-500",
|
||||
},
|
||||
];
|
||||
|
||||
return colors[position % colors.length];
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -154,3 +154,4 @@ For a fresh setup:
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -324,3 +324,4 @@ All standard Stripe objects synced automatically:
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -211,3 +211,4 @@ However, this is not recommended as the old implementation had incorrect logic.
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -281,3 +281,4 @@ await stripeSync.syncSubscriptions();
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -203,3 +203,4 @@ All 142 tests are now passing with proper authentication logic being tested. The
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -350,6 +350,9 @@ importers:
|
|||
stream-chat-react:
|
||||
specifier: ^13.1.0
|
||||
version: 13.9.0(@emoji-mart/data@1.2.1)(@types/react@19.0.10)(emoji-mart@5.6.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(stream-chat@9.24.0)(typescript@5.9.3)
|
||||
three:
|
||||
specifier: ^0.172.0
|
||||
version: 0.172.0
|
||||
ts-pattern:
|
||||
specifier: ^5.6.2
|
||||
version: 5.8.0
|
||||
|
|
@ -414,6 +417,9 @@ importers:
|
|||
'@types/react-dom':
|
||||
specifier: 19.0.4
|
||||
version: 19.0.4(@types/react@19.0.10)
|
||||
'@types/three':
|
||||
specifier: ^0.181.0
|
||||
version: 0.181.0
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^7.0.2
|
||||
version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
|
|
@ -1292,6 +1298,9 @@ packages:
|
|||
'@date-fns/tz@1.4.1':
|
||||
resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==}
|
||||
|
||||
'@dimforge/rapier3d-compat@0.12.0':
|
||||
resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==}
|
||||
|
||||
'@emnapi/runtime@1.6.0':
|
||||
resolution: {integrity: sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==}
|
||||
|
||||
|
|
@ -3961,6 +3970,9 @@ packages:
|
|||
'@tsconfig/node16@1.0.4':
|
||||
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
||||
|
||||
'@tweenjs/tween.js@23.1.3':
|
||||
resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==}
|
||||
|
||||
'@types/aria-query@5.0.4':
|
||||
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
||||
|
||||
|
|
@ -4092,6 +4104,12 @@ packages:
|
|||
'@types/stack-utils@2.0.3':
|
||||
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
|
||||
|
||||
'@types/stats.js@0.17.4':
|
||||
resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==}
|
||||
|
||||
'@types/three@0.181.0':
|
||||
resolution: {integrity: sha512-MLF1ks8yRM2k71D7RprFpDb9DOX0p22DbdPqT/uAkc6AtQXjxWCVDjCy23G9t1o8HcQPk7woD2NIyiaWcWPYmA==}
|
||||
|
||||
'@types/tough-cookie@4.0.5':
|
||||
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
|
||||
|
||||
|
|
@ -4107,6 +4125,9 @@ packages:
|
|||
'@types/use-sync-external-store@0.0.6':
|
||||
resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
|
||||
|
||||
'@types/webxr@0.5.24':
|
||||
resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==}
|
||||
|
||||
'@types/whatwg-mimetype@3.0.2':
|
||||
resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==}
|
||||
|
||||
|
|
@ -4356,6 +4377,9 @@ packages:
|
|||
'@vitest/utils@4.0.8':
|
||||
resolution: {integrity: sha512-pdk2phO5NDvEFfUTxcTP8RFYjVj/kfLSPIN5ebP2Mu9kcIMeAQTbknqcFEyBcC4z2pJlJI9aS5UQjcYfhmKAow==}
|
||||
|
||||
'@webgpu/types@0.1.66':
|
||||
resolution: {integrity: sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA==}
|
||||
|
||||
abab@2.0.6:
|
||||
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
||||
deprecated: Use your platform's native atob() and btoa() methods instead
|
||||
|
|
@ -6517,6 +6541,9 @@ packages:
|
|||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
meshoptimizer@0.22.0:
|
||||
resolution: {integrity: sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==}
|
||||
|
||||
micromark-core-commonmark@2.0.3:
|
||||
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
|
||||
|
||||
|
|
@ -8005,6 +8032,9 @@ packages:
|
|||
thread-stream@3.1.0:
|
||||
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
|
||||
|
||||
three@0.172.0:
|
||||
resolution: {integrity: sha512-6HMgMlzU97MsV7D/tY8Va38b83kz8YJX+BefKjspMNAv0Vx6dxMogHOrnRl/sbMIs3BPUKijPqDqJ/+UwJbIow==}
|
||||
|
||||
through@2.3.8:
|
||||
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
||||
|
||||
|
|
@ -9739,6 +9769,8 @@ snapshots:
|
|||
|
||||
'@date-fns/tz@1.4.1': {}
|
||||
|
||||
'@dimforge/rapier3d-compat@0.12.0': {}
|
||||
|
||||
'@emnapi/runtime@1.6.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
|
@ -12919,6 +12951,8 @@ snapshots:
|
|||
|
||||
'@tsconfig/node16@1.0.4': {}
|
||||
|
||||
'@tweenjs/tween.js@23.1.3': {}
|
||||
|
||||
'@types/aria-query@5.0.4': {}
|
||||
|
||||
'@types/babel__core@7.20.5':
|
||||
|
|
@ -13076,6 +13110,18 @@ snapshots:
|
|||
|
||||
'@types/stack-utils@2.0.3': {}
|
||||
|
||||
'@types/stats.js@0.17.4': {}
|
||||
|
||||
'@types/three@0.181.0':
|
||||
dependencies:
|
||||
'@dimforge/rapier3d-compat': 0.12.0
|
||||
'@tweenjs/tween.js': 23.1.3
|
||||
'@types/stats.js': 0.17.4
|
||||
'@types/webxr': 0.5.24
|
||||
'@webgpu/types': 0.1.66
|
||||
fflate: 0.8.2
|
||||
meshoptimizer: 0.22.0
|
||||
|
||||
'@types/tough-cookie@4.0.5': {}
|
||||
|
||||
'@types/trusted-types@2.0.7':
|
||||
|
|
@ -13087,6 +13133,8 @@ snapshots:
|
|||
|
||||
'@types/use-sync-external-store@0.0.6': {}
|
||||
|
||||
'@types/webxr@0.5.24': {}
|
||||
|
||||
'@types/whatwg-mimetype@3.0.2': {}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
|
|
@ -13417,6 +13465,8 @@ snapshots:
|
|||
'@vitest/pretty-format': 4.0.8
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@webgpu/types@0.1.66': {}
|
||||
|
||||
abab@2.0.6: {}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
|
|
@ -16244,6 +16294,8 @@ snapshots:
|
|||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
meshoptimizer@0.22.0: {}
|
||||
|
||||
micromark-core-commonmark@2.0.3:
|
||||
dependencies:
|
||||
decode-named-character-reference: 1.2.0
|
||||
|
|
@ -18075,6 +18127,8 @@ snapshots:
|
|||
dependencies:
|
||||
real-require: 0.2.0
|
||||
|
||||
three@0.172.0: {}
|
||||
|
||||
through@2.3.8: {}
|
||||
|
||||
tiny-async-pool@2.1.0: {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue