feat: filter empty projects from public gallery (#125)
* feat(community): filter empty projects from public gallery Add is_empty column to projects table so the public gallery only shows projects with actual content. Scene graph emptiness is computed on save and on creation, and a backfill migration marks existing non-empty projects. Also cleans up import ordering, fixes README migration path, and removes stale feedback table migration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Use ESNext modules and bundler resolution Update packages/db tsconfig to emit ESNext modules and use 'bundler' moduleResolution. This enables modern ESM output and bundler-style resolution for the db package (keeps outDir and rootDir unchanged). * feat(editor): add dark mode theme and grid visibility toggle Add theme state to viewer store with light/dark modes, dark-aware lighting and background colors, grid show/hide toggle in settings, and theme toggle buttons in the sidebar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add ground occluder, animated lighting & UI tweaks Introduce a ground occluder and smoother animated lighting while adjusting editor UI and icons. Viewer: add GroundOccluder (uses polygon-clipping to union slab/zone polygons) and AnimatedBackground, integrate both into the Canvas; improve Lights to interpolate intensities/colors/ambient for smooth theme transitions. Editor: refactor sidebar header to support inline project title editing and move the theme toggle; replace some lucide icons with image assets and add a settings icon (apps/editor/public/icons/settings.png). Also add polygon-clipping to the viewer package dependencies. * Update dark mode background color and clean up imports Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
5077011c26
commit
98c1d5247e
@@ -1,22 +1,57 @@
|
||||
'use client'
|
||||
|
||||
import { CeilingSystem, DoorSystem, ItemSystem, RoofSystem, SlabSystem, WallSystem, WindowSystem } from '@pascal-app/core'
|
||||
import {
|
||||
CeilingSystem,
|
||||
DoorSystem,
|
||||
ItemSystem,
|
||||
RoofSystem,
|
||||
SlabSystem,
|
||||
WallSystem,
|
||||
WindowSystem,
|
||||
} from '@pascal-app/core'
|
||||
import { Bvh } from '@react-three/drei'
|
||||
import { Canvas, extend, type ThreeToJSXElements } from '@react-three/fiber'
|
||||
import { Canvas, extend, type ThreeToJSXElements, useFrame } from '@react-three/fiber'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import * as THREE from 'three/webgpu'
|
||||
import useViewer from '../../store/use-viewer'
|
||||
import { GuideSystem } from '../../systems/guide/guide-system'
|
||||
import { LevelSystem } from '../../systems/level/level-system'
|
||||
import { ScanSystem } from '../../systems/scan/scan-system'
|
||||
import { WallCutout } from '../../systems/wall/wall-cutout'
|
||||
import { ZoneSystem } from '../../systems/zone/zone-system'
|
||||
import { SceneRenderer } from '../renderers/scene-renderer'
|
||||
import { GroundOccluder } from './ground-occluder'
|
||||
import { Lights } from './lights'
|
||||
import PostProcessing from './post-processing'
|
||||
import { SelectionManager } from './selection-manager'
|
||||
import { ViewerCamera } from './viewer-camera'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import useViewer from '../../store/use-viewer'
|
||||
function AnimatedBackground({ isDark }: { isDark: boolean }) {
|
||||
const targetColor = useMemo(() => new THREE.Color(), [])
|
||||
const initialized = useRef(false)
|
||||
|
||||
useFrame(({ scene }, delta) => {
|
||||
const dt = Math.min(delta, 0.1) * 4
|
||||
const targetHex = isDark ? '#1f2433' : '#ffffff'
|
||||
|
||||
if (!scene.background || !(scene.background instanceof THREE.Color)) {
|
||||
scene.background = new THREE.Color(targetHex)
|
||||
initialized.current = true
|
||||
return
|
||||
}
|
||||
|
||||
if (!initialized.current) {
|
||||
scene.background.set(targetHex)
|
||||
initialized.current = true
|
||||
return
|
||||
}
|
||||
|
||||
targetColor.set(targetHex)
|
||||
scene.background.lerp(targetColor, dt)
|
||||
})
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
declare module '@react-three/fiber' {
|
||||
interface ThreeElements extends ThreeToJSXElements<typeof THREE> {}
|
||||
@@ -30,8 +65,15 @@ interface ViewerProps {
|
||||
isEditor?: boolean
|
||||
}
|
||||
|
||||
const Viewer: React.FC<ViewerProps> = ({ children, selectionManager = 'default', isEditor = false }) => {
|
||||
const Viewer: React.FC<ViewerProps> = ({
|
||||
children,
|
||||
selectionManager = 'default',
|
||||
isEditor = false,
|
||||
}) => {
|
||||
const setIsEditor = useViewer((state) => state.setIsEditor)
|
||||
const theme = useViewer((state) => state.theme)
|
||||
|
||||
const bgColor = theme === 'dark' ? '#1f2433' : '#fafafa'
|
||||
|
||||
useEffect(() => {
|
||||
setIsEditor(isEditor)
|
||||
@@ -40,7 +82,7 @@ const Viewer: React.FC<ViewerProps> = ({ children, selectionManager = 'default',
|
||||
return (
|
||||
<Canvas
|
||||
dpr={[1, 1.5]}
|
||||
className={'bg-[#fafafa]'}
|
||||
className={`transition-colors duration-700 ${theme === 'dark' ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`}
|
||||
gl={(props) => {
|
||||
const renderer = new THREE.WebGPURenderer(props as any)
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping
|
||||
@@ -53,7 +95,8 @@ const Viewer: React.FC<ViewerProps> = ({ children, selectionManager = 'default',
|
||||
}}
|
||||
camera={{ position: [50, 50, 50], fov: 50 }}
|
||||
>
|
||||
<color attach="background" args={['#fafafa']} />
|
||||
<AnimatedBackground isDark={theme === 'dark'} />
|
||||
<GroundOccluder />
|
||||
<ViewerCamera />
|
||||
|
||||
{/* <directionalLight position={[10, 10, 5]} intensity={0.5} castShadow
|
||||
|
||||
Reference in New Issue
Block a user