Files
house-plan-maker/apps/client/src/components/editor/projection/ProjectionFurniture.tsx
T
alexei.dolgolyov af8b9fe00f feat: complete house plan maker application
Full-featured house/apartment floor plan editor with:

- Turborepo monorepo (React/Vite client, Fastify/Prisma server, shared Zod schemas)
- 2D room editor with walls, doors, windows, furniture, electrical elements
- 3D room preview with Three.js (auto-hide nearest walls, bird's eye default)
- Wall projection views with interactive drag (elevation, position)
- Apartment floor plan view with room positioning
- Copy/paste, alignment tools, measurement tool, annotations
- Item-attached annotations with leader lines (visible on projections)
- Door open direction (LEFT/RIGHT/INWARD/OUTWARD) with swing arc
- Floor type textures (wood, tile, concrete, laminate, herringbone)
- Wall color picker for 3D view
- Furniture: bed, desk, wardrobe, sofa, table, chair, shelf, nightstand, dresser, bookcase, TV (with stand toggle), AC unit
- Furniture elevation support (wall-mounted items)
- Auto-save with dirty state tracking, batch save API
- Rotation-aware collision detection (SAT/OBB) with 3D elevation check
- Rotation-aware hit testing
- i18n (English/Russian) with locale-aware number formatting
- Dark mode with system preference detection
- Undo/redo, keyboard shortcuts, scale bar
- PDF/PNG/JSON export and JSON import
- Focus trap modal, toast notifications, tooltips
- Responsive layout with overlay palettes
2026-04-05 22:34:03 +03:00

66 lines
1.6 KiB
TypeScript

import { Group, Rect, Text } from 'react-konva';
import type { ProjectedFurniture } from '../utils/projectionMapping';
import { projectionToPixel } from '../utils/projectionMapping';
interface ProjectionFurnitureProps {
readonly projected: ProjectedFurniture;
readonly wallHeight: number;
readonly scale: number;
readonly padding: number;
readonly isSelected: boolean;
readonly onClick: () => void;
}
const TYPE_COLORS: Record<string, string> = {
SHELF: '#d4a574',
BOOKCASE: '#b8860b',
WARDROBE: '#8b7355',
DRESSER: '#a0845c',
DESK: '#c9a96e',
TABLE: '#deb887',
};
/** Render a furniture item in wall elevation view. */
export function ProjectionFurniture({
projected,
wallHeight,
scale,
padding,
isSelected,
onClick,
}: ProjectionFurnitureProps) {
const { rect, item } = projected;
const topLeft = projectionToPixel(rect.x, rect.y + rect.height, wallHeight, scale, padding);
const pxWidth = rect.width * scale;
const pxHeight = rect.height * scale;
const color = TYPE_COLORS[item.type] ?? '#a0845c';
return (
<Group onClick={onClick}>
<Rect
x={topLeft.x}
y={topLeft.y}
width={pxWidth}
height={pxHeight}
fill={isSelected ? '#dbeafe' : color}
stroke={isSelected ? '#2563eb' : '#6b5b3a'}
strokeWidth={isSelected ? 2 : 1}
opacity={0.7}
/>
{/* Furniture label */}
<Text
x={topLeft.x}
y={topLeft.y + pxHeight / 2 - 5}
width={pxWidth}
text={item.label ?? item.type}
align="center"
fontSize={9}
fill={isSelected ? '#1e40af' : '#3b2f1e'}
ellipsis
/>
</Group>
);
}