Merge remote-tracking branch 'origin/main' into fix/fri-8-may
This commit is contained in:
@@ -1,14 +1,12 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import {
|
import { Editor, ItemsPanel } from '@pascal-app/editor'
|
||||||
Editor,
|
|
||||||
ItemsPanel,
|
|
||||||
type SidebarTab,
|
|
||||||
ViewerToolbarLeft,
|
|
||||||
ViewerToolbarRight,
|
|
||||||
} from '@pascal-app/editor'
|
|
||||||
import { Layers, Package, Settings } from 'lucide-react'
|
import { Layers, Package, Settings } from 'lucide-react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import {
|
||||||
|
CommunityViewerToolbarLeft,
|
||||||
|
CommunityViewerToolbarRight,
|
||||||
|
} from '@/components/viewer-toolbar'
|
||||||
|
|
||||||
const SIDEBAR_TABS = [
|
const SIDEBAR_TABS = [
|
||||||
{
|
{
|
||||||
@@ -59,8 +57,8 @@ export default function Home() {
|
|||||||
layoutVersion="v2"
|
layoutVersion="v2"
|
||||||
projectId={PROJECT_ID}
|
projectId={PROJECT_ID}
|
||||||
sidebarTabs={SIDEBAR_TABS}
|
sidebarTabs={SIDEBAR_TABS}
|
||||||
viewerToolbarLeft={<ViewerToolbarLeft />}
|
viewerToolbarLeft={<CommunityViewerToolbarLeft />}
|
||||||
viewerToolbarRight={<ViewerToolbarRight />}
|
viewerToolbarRight={<CommunityViewerToolbarRight />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,12 +5,11 @@ import {
|
|||||||
Editor,
|
Editor,
|
||||||
type SceneGraph,
|
type SceneGraph,
|
||||||
type SidebarTab,
|
type SidebarTab,
|
||||||
ViewerToolbarLeft,
|
|
||||||
ViewerToolbarRight,
|
|
||||||
} from '@pascal-app/editor'
|
} from '@pascal-app/editor'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
import { CommunityViewerToolbarLeft, CommunityViewerToolbarRight } from './viewer-toolbar'
|
||||||
|
|
||||||
export interface SceneMeta {
|
export interface SceneMeta {
|
||||||
id: string
|
id: string
|
||||||
@@ -200,8 +199,8 @@ export function SceneLoader({ initialScene, meta }: SceneLoaderProps) {
|
|||||||
onThumbnailCapture={handleThumb}
|
onThumbnailCapture={handleThumb}
|
||||||
projectId={meta.projectId ?? 'default'}
|
projectId={meta.projectId ?? 'default'}
|
||||||
sidebarTabs={SIDEBAR_TABS}
|
sidebarTabs={SIDEBAR_TABS}
|
||||||
viewerToolbarLeft={<ViewerToolbarLeft />}
|
viewerToolbarLeft={<CommunityViewerToolbarLeft />}
|
||||||
viewerToolbarRight={<ViewerToolbarRight />}
|
viewerToolbarRight={<CommunityViewerToolbarRight />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
|
||||||
|
import type * as React from 'react'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
function TooltipProvider({
|
||||||
|
delayDuration = 0,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
||||||
|
return <TooltipPrimitive.Provider delayDuration={delayDuration} {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
||||||
|
return (
|
||||||
|
<TooltipProvider>
|
||||||
|
<TooltipPrimitive.Root {...props} />
|
||||||
|
</TooltipProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
||||||
|
return <TooltipPrimitive.Trigger {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function TooltipContent({
|
||||||
|
className,
|
||||||
|
sideOffset = 6,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
||||||
|
return (
|
||||||
|
<TooltipPrimitive.Portal>
|
||||||
|
<TooltipPrimitive.Content
|
||||||
|
className={cn(
|
||||||
|
'fade-in-0 zoom-in-95 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-background text-xs data-[state=closed]:animate-out',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
|
||||||
|
</TooltipPrimitive.Content>
|
||||||
|
</TooltipPrimitive.Portal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
|
||||||
@@ -0,0 +1,362 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Icon as IconifyIcon } from '@iconify/react'
|
||||||
|
import { useEditor, useSidebarStore, type ViewMode } from '@pascal-app/editor'
|
||||||
|
import { useViewer } from '@pascal-app/viewer'
|
||||||
|
import {
|
||||||
|
ChevronsLeft,
|
||||||
|
ChevronsRight,
|
||||||
|
Columns2,
|
||||||
|
Eye,
|
||||||
|
EyeOff,
|
||||||
|
Footprints,
|
||||||
|
Grid2X2,
|
||||||
|
Moon,
|
||||||
|
Sun,
|
||||||
|
} from 'lucide-react'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { type ReactNode, useCallback } from 'react'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from './toolbar-tooltip'
|
||||||
|
|
||||||
|
const TOOLBAR_CONTAINER =
|
||||||
|
'inline-flex h-8 items-stretch overflow-hidden rounded-xl border border-border bg-background/90 shadow-2xl backdrop-blur-md'
|
||||||
|
|
||||||
|
const TOOLBAR_BTN =
|
||||||
|
'flex w-8 items-center justify-center text-muted-foreground/80 transition-colors hover:bg-white/8 hover:text-foreground/90'
|
||||||
|
|
||||||
|
function ToolbarTooltip({ children, label }: { children: ReactNode; label: string }) {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>{children}</TooltipTrigger>
|
||||||
|
<TooltipContent side="bottom">{label}</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const VIEW_MODES: { id: ViewMode; label: string; icon: React.ReactNode }[] = [
|
||||||
|
{
|
||||||
|
id: '3d',
|
||||||
|
label: '3D',
|
||||||
|
icon: (
|
||||||
|
<Image
|
||||||
|
alt=""
|
||||||
|
className="h-3.5 w-3.5 object-contain"
|
||||||
|
height={14}
|
||||||
|
src="/icons/building.png"
|
||||||
|
width={14}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2d',
|
||||||
|
label: '2D',
|
||||||
|
icon: (
|
||||||
|
<Image
|
||||||
|
alt=""
|
||||||
|
className="h-3.5 w-3.5 object-contain"
|
||||||
|
height={14}
|
||||||
|
src="/icons/blueprint.png"
|
||||||
|
width={14}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'split',
|
||||||
|
label: 'Split',
|
||||||
|
icon: <Columns2 className="h-3 w-3" />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const levelModeOrder = ['stacked', 'exploded', 'solo'] as const
|
||||||
|
const levelModeLabels: Record<string, string> = {
|
||||||
|
manual: 'Stack',
|
||||||
|
stacked: 'Stack',
|
||||||
|
exploded: 'Exploded',
|
||||||
|
solo: 'Solo',
|
||||||
|
}
|
||||||
|
|
||||||
|
const wallModeOrder = ['cutaway', 'up', 'down'] as const
|
||||||
|
const wallModeConfig: Record<string, { icon: string; label: string }> = {
|
||||||
|
up: { icon: '/icons/room.png', label: 'Full height' },
|
||||||
|
cutaway: { icon: '/icons/wallcut.png', label: 'Cutaway' },
|
||||||
|
down: { icon: '/icons/walllow.png', label: 'Low' },
|
||||||
|
}
|
||||||
|
|
||||||
|
function ViewModeControl() {
|
||||||
|
const viewMode = useEditor((state) => state.viewMode)
|
||||||
|
const setViewMode = useEditor((state) => state.setViewMode)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={TOOLBAR_CONTAINER}>
|
||||||
|
{VIEW_MODES.map((mode) => {
|
||||||
|
const isActive = viewMode === mode.id
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip key={mode.id} label={mode.label}>
|
||||||
|
<button
|
||||||
|
aria-label={mode.label}
|
||||||
|
aria-pressed={isActive}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center justify-center gap-1.5 px-2.5 font-medium text-xs transition-colors',
|
||||||
|
isActive
|
||||||
|
? 'bg-white/10 text-foreground'
|
||||||
|
: 'text-muted-foreground/70 hover:bg-white/8 hover:text-muted-foreground',
|
||||||
|
)}
|
||||||
|
onClick={() => setViewMode(mode.id)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{mode.icon}
|
||||||
|
<span>{mode.label}</span>
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CollapseSidebarButton() {
|
||||||
|
const isCollapsed = useSidebarStore((state) => state.isCollapsed)
|
||||||
|
const setIsCollapsed = useSidebarStore((state) => state.setIsCollapsed)
|
||||||
|
|
||||||
|
const toggle = useCallback(() => {
|
||||||
|
setIsCollapsed(!isCollapsed)
|
||||||
|
}, [isCollapsed, setIsCollapsed])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={TOOLBAR_CONTAINER}>
|
||||||
|
<ToolbarTooltip label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}>
|
||||||
|
<button
|
||||||
|
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
||||||
|
className={TOOLBAR_BTN}
|
||||||
|
onClick={toggle}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{isCollapsed ? (
|
||||||
|
<ChevronsRight className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ChevronsLeft className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function LevelModeToggle() {
|
||||||
|
const levelMode = useViewer((state) => state.levelMode)
|
||||||
|
const setLevelMode = useViewer((state) => state.setLevelMode)
|
||||||
|
const isDefault = levelMode === 'stacked' || levelMode === 'manual'
|
||||||
|
|
||||||
|
const cycle = () => {
|
||||||
|
if (levelMode === 'manual') {
|
||||||
|
setLevelMode('stacked')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = levelModeOrder.indexOf(levelMode as (typeof levelModeOrder)[number])
|
||||||
|
const next = levelModeOrder[(index + 1) % levelModeOrder.length]
|
||||||
|
if (next) setLevelMode(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = `Levels: ${levelMode === 'manual' ? 'Manual' : (levelModeLabels[levelMode] ?? 'Stack')}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label={label}>
|
||||||
|
<button
|
||||||
|
className={cn(
|
||||||
|
TOOLBAR_BTN,
|
||||||
|
'w-auto gap-1.5 px-2.5',
|
||||||
|
!isDefault && 'bg-white/10 text-foreground/90',
|
||||||
|
)}
|
||||||
|
onClick={cycle}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{levelMode === 'solo' ? (
|
||||||
|
<IconifyIcon height={14} icon="lucide:diamond" width={14} />
|
||||||
|
) : levelMode === 'exploded' ? (
|
||||||
|
<IconifyIcon height={14} icon="charm:stack-pop" width={14} />
|
||||||
|
) : (
|
||||||
|
<IconifyIcon height={14} icon="charm:stack-push" width={14} />
|
||||||
|
)}
|
||||||
|
<span className="font-medium text-xs">{levelModeLabels[levelMode] ?? 'Stack'}</span>
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function WallModeToggle() {
|
||||||
|
const wallMode = useViewer((state) => state.wallMode)
|
||||||
|
const setWallMode = useViewer((state) => state.setWallMode)
|
||||||
|
const config = wallModeConfig[wallMode] ?? wallModeConfig.cutaway!
|
||||||
|
|
||||||
|
const cycle = () => {
|
||||||
|
const index = wallModeOrder.indexOf(wallMode as (typeof wallModeOrder)[number])
|
||||||
|
const next = wallModeOrder[(index + 1) % wallModeOrder.length]
|
||||||
|
if (next) setWallMode(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label={`Walls: ${config.label}`}>
|
||||||
|
<button
|
||||||
|
className={cn(
|
||||||
|
TOOLBAR_BTN,
|
||||||
|
'w-auto gap-1.5 px-2.5',
|
||||||
|
wallMode !== 'cutaway'
|
||||||
|
? 'bg-white/10'
|
||||||
|
: 'opacity-60 grayscale hover:opacity-100 hover:grayscale-0',
|
||||||
|
)}
|
||||||
|
onClick={cycle}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Image alt="" className="h-4 w-4 object-contain" height={16} src={config.icon} width={16} />
|
||||||
|
<span className="font-medium text-xs">{config.label}</span>
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function GridVisibilityToggle() {
|
||||||
|
const showGrid = useViewer((state) => state.showGrid)
|
||||||
|
const setShowGrid = useViewer((state) => state.setShowGrid)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label={`Grid: ${showGrid ? 'Visible' : 'Hidden'}`}>
|
||||||
|
<button
|
||||||
|
aria-label={`Grid: ${showGrid ? 'Visible' : 'Hidden'}`}
|
||||||
|
aria-pressed={showGrid}
|
||||||
|
className={cn(
|
||||||
|
TOOLBAR_BTN,
|
||||||
|
'w-auto gap-1.5 px-2.5',
|
||||||
|
showGrid
|
||||||
|
? 'bg-white/10 text-foreground/90'
|
||||||
|
: 'opacity-60 grayscale hover:opacity-100 hover:grayscale-0',
|
||||||
|
)}
|
||||||
|
onClick={() => setShowGrid(!showGrid)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Grid2X2 className="h-3.5 w-3.5" />
|
||||||
|
{showGrid ? <Eye className="h-3.5 w-3.5" /> : <EyeOff className="h-3.5 w-3.5" />}
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function UnitToggle() {
|
||||||
|
const unit = useViewer((state) => state.unit)
|
||||||
|
const setUnit = useViewer((state) => state.setUnit)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label={unit === 'metric' ? 'Metric (m)' : 'Imperial (ft)'}>
|
||||||
|
<button
|
||||||
|
className={TOOLBAR_BTN}
|
||||||
|
onClick={() => setUnit(unit === 'metric' ? 'imperial' : 'metric')}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span className="font-semibold text-[10px]">{unit === 'metric' ? 'm' : 'ft'}</span>
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ThemeToggle() {
|
||||||
|
const theme = useViewer((state) => state.theme)
|
||||||
|
const setTheme = useViewer((state) => state.setTheme)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label={theme === 'dark' ? 'Dark' : 'Light'}>
|
||||||
|
<button
|
||||||
|
className={cn(TOOLBAR_BTN, theme === 'dark' ? 'text-indigo-400/70' : 'text-amber-400/70')}
|
||||||
|
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{theme === 'dark' ? <Moon className="h-3.5 w-3.5" /> : <Sun className="h-3.5 w-3.5" />}
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CameraModeToggle() {
|
||||||
|
const cameraMode = useViewer((state) => state.cameraMode)
|
||||||
|
const setCameraMode = useViewer((state) => state.setCameraMode)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label={cameraMode === 'perspective' ? 'Perspective' : 'Orthographic'}>
|
||||||
|
<button
|
||||||
|
className={cn(
|
||||||
|
TOOLBAR_BTN,
|
||||||
|
cameraMode === 'orthographic' && 'bg-white/10 text-foreground/90',
|
||||||
|
)}
|
||||||
|
onClick={() => setCameraMode(cameraMode === 'perspective' ? 'orthographic' : 'perspective')}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{cameraMode === 'perspective' ? (
|
||||||
|
<IconifyIcon height={16} icon="icon-park-outline:perspective" width={16} />
|
||||||
|
) : (
|
||||||
|
<IconifyIcon height={16} icon="vaadin:grid" width={16} />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function WalkthroughButton() {
|
||||||
|
const isFirstPersonMode = useEditor((state) => state.isFirstPersonMode)
|
||||||
|
const setFirstPersonMode = useEditor((state) => state.setFirstPersonMode)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label="Walkthrough">
|
||||||
|
<button
|
||||||
|
className={cn(
|
||||||
|
TOOLBAR_BTN,
|
||||||
|
isFirstPersonMode && 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/20',
|
||||||
|
)}
|
||||||
|
onClick={() => setFirstPersonMode(!isFirstPersonMode)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Footprints className="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function PreviewButton() {
|
||||||
|
return (
|
||||||
|
<ToolbarTooltip label="Preview mode">
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-1.5 px-2.5 font-medium text-muted-foreground/80 text-xs transition-colors hover:bg-white/8 hover:text-foreground/90"
|
||||||
|
onClick={() => useEditor.getState().setPreviewMode(true)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Eye className="h-3.5 w-3.5 shrink-0" />
|
||||||
|
<span>Preview</span>
|
||||||
|
</button>
|
||||||
|
</ToolbarTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CommunityViewerToolbarLeft() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CollapseSidebarButton />
|
||||||
|
<ViewModeControl />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CommunityViewerToolbarRight() {
|
||||||
|
return (
|
||||||
|
<div className={TOOLBAR_CONTAINER}>
|
||||||
|
<LevelModeToggle />
|
||||||
|
<WallModeToggle />
|
||||||
|
<GridVisibilityToggle />
|
||||||
|
<div className="my-1.5 w-px bg-border/50" />
|
||||||
|
<UnitToggle />
|
||||||
|
<ThemeToggle />
|
||||||
|
<CameraModeToggle />
|
||||||
|
<div className="my-1.5 w-px bg-border/50" />
|
||||||
|
<WalkthroughButton />
|
||||||
|
<PreviewButton />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -11,11 +11,13 @@
|
|||||||
"check-types": "next typegen && tsc --noEmit"
|
"check-types": "next typegen && tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iconify/react": "^6.0.2",
|
||||||
"@number-flow/react": "^0.5.14",
|
"@number-flow/react": "^0.5.14",
|
||||||
"@pascal-app/core": "*",
|
"@pascal-app/core": "*",
|
||||||
"@pascal-app/editor": "*",
|
"@pascal-app/editor": "*",
|
||||||
"@pascal-app/mcp": "*",
|
"@pascal-app/mcp": "*",
|
||||||
"@pascal-app/viewer": "*",
|
"@pascal-app/viewer": "*",
|
||||||
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@react-three/drei": "^10.7.7",
|
"@react-three/drei": "^10.7.7",
|
||||||
"@react-three/fiber": "^9.5.0",
|
"@react-three/fiber": "^9.5.0",
|
||||||
"@tailwindcss/postcss": "^4.2.1",
|
"@tailwindcss/postcss": "^4.2.1",
|
||||||
|
|||||||
@@ -26,11 +26,13 @@
|
|||||||
"name": "editor",
|
"name": "editor",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iconify/react": "^6.0.2",
|
||||||
"@number-flow/react": "^0.5.14",
|
"@number-flow/react": "^0.5.14",
|
||||||
"@pascal-app/core": "*",
|
"@pascal-app/core": "*",
|
||||||
"@pascal-app/editor": "*",
|
"@pascal-app/editor": "*",
|
||||||
"@pascal-app/mcp": "*",
|
"@pascal-app/mcp": "*",
|
||||||
"@pascal-app/viewer": "*",
|
"@pascal-app/viewer": "*",
|
||||||
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@react-three/drei": "^10.7.7",
|
"@react-three/drei": "^10.7.7",
|
||||||
"@react-three/fiber": "^9.5.0",
|
"@react-three/fiber": "^9.5.0",
|
||||||
"@tailwindcss/postcss": "^4.2.1",
|
"@tailwindcss/postcss": "^4.2.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user