This commit is contained in:
Халимов Рустам
2025-12-27 21:39:32 +03:00
parent 83cbe04c13
commit ff3c8e2156

View File

@@ -8,7 +8,7 @@ import { createBinGeometry, generateSTL, exportSTL } from '../services/geometryG
import { Download, Package, Info, Loader2, Share2, Check, Ruler } from 'lucide-react'; import { Download, Package, Info, Loader2, Share2, Check, Ruler } from 'lucide-react';
import { generateShareUrl } from '../utils/share'; import { generateShareUrl } from '../utils/share';
// --- DrawerFrame (Каркас ящика) --- // --- DrawerFrame (Каркас) ---
const DrawerFrame = ({ config }: { config: AppConfig }) => { const DrawerFrame = ({ config }: { config: AppConfig }) => {
const { width, depth, height } = config.drawer; const { width, depth, height } = config.drawer;
const offset = 0.5; const offset = 0.5;
@@ -26,37 +26,33 @@ const DrawerFrame = ({ config }: { config: AppConfig }) => {
interface BinMeshProps { interface BinMeshProps {
part: GeneratedPart; part: GeneratedPart;
thickness: number; thickness: number;
cornerRadius: number; // Важный проп для радиуса cornerRadius: number;
isSelected: boolean; isSelected: boolean;
onClick: () => void; onClick: () => void;
} }
const BinMesh: React.FC<BinMeshProps> = ({ part, thickness, cornerRadius, isSelected, onClick }) => { const BinMesh: React.FC<BinMeshProps> = ({ part, thickness, cornerRadius, isSelected, onClick }) => {
// 1. Создаем основную геометрию ячейки
const geometry = useMemo(() => { const geometry = useMemo(() => {
return createBinGeometry(part.width, part.depth, part.height, thickness, cornerRadius); return createBinGeometry(part.width, part.depth, part.height, thickness, cornerRadius);
}, [part, thickness, cornerRadius]); }, [part, thickness, cornerRadius]);
// 2. Создаем геометрию для рамки выделения
// Используем EdgesGeometry с порогом 20 градусов.
// Это скроет линии на плавных изгибах (где угол между полигонами ~5-6 градусов),
// но оставит четкие грани сверху, снизу и по углам.
const edgesGeometry = useMemo(() => { const edgesGeometry = useMemo(() => {
return new THREE.EdgesGeometry(geometry, 20); return new THREE.EdgesGeometry(geometry, 20);
}, [geometry]); }, [geometry]);
return ( return (
<group position={[part.x + part.width/2, 0, part.y + part.depth/2]}> <group position={[part.x + part.width/2, 0, part.y + part.depth/2]}>
{/* Сама модель */} {/* Модель */}
<mesh geometry={geometry} onClick={(e) => { e.stopPropagation(); onClick(); }}> <mesh geometry={geometry} onClick={(e) => { e.stopPropagation(); onClick(); }}>
<meshStandardMaterial <meshStandardMaterial
color={isSelected ? '#f59e0b' : part.color} color={isSelected ? '#f59e0b' : part.color}
roughness={0.5} roughness={0.5}
metalness={0.1} metalness={0.1}
side={THREE.DoubleSide} // <--- ИСПРАВЛЕНИЕ: Рисуем обе стороны стенки
/> />
</mesh> </mesh>
{/* Подсветка выделения (теперь повторяет форму скругления) */} {/* Белая обводка */}
{isSelected && ( {isSelected && (
<lineSegments geometry={edgesGeometry}> <lineSegments geometry={edgesGeometry}>
<lineBasicMaterial color="white" linewidth={2} /> <lineBasicMaterial color="white" linewidth={2} />
@@ -66,7 +62,7 @@ const BinMesh: React.FC<BinMeshProps> = ({ part, thickness, cornerRadius, isSele
); );
}; };
// --- PreviewStep (Основной компонент) --- // --- PreviewStep (Основной) ---
interface Props { interface Props {
parts: GeneratedPart[]; parts: GeneratedPart[];
config: AppConfig; config: AppConfig;
@@ -149,15 +145,12 @@ export const PreviewStep: React.FC<Props> = ({ parts, config, splits }) => {
return ( return (
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
{/* Верхняя панель: Размеры + Поделиться */}
<div className="flex flex-col xl:flex-row justify-between items-center bg-slate-800/80 p-4 rounded-xl border border-slate-700 mb-4 gap-4 backdrop-blur-sm shadow-lg"> <div className="flex flex-col xl:flex-row justify-between items-center bg-slate-800/80 p-4 rounded-xl border border-slate-700 mb-4 gap-4 backdrop-blur-sm shadow-lg">
<div className="flex flex-wrap items-center gap-6 justify-center md:justify-start"> <div className="flex flex-wrap items-center gap-6 justify-center md:justify-start">
<div className="hidden md:flex items-center gap-2 text-gray-300 mr-2"> <div className="hidden md:flex items-center gap-2 text-gray-300 mr-2">
<Ruler className="text-primary" size={20} /> <Ruler className="text-primary" size={20} />
<span className="font-medium text-sm uppercase tracking-wide opacity-70">Размеры ящика:</span> <span className="font-medium text-sm uppercase tracking-wide opacity-70">Размеры ящика:</span>
</div> </div>
<div className="flex flex-wrap gap-6 font-mono text-white items-baseline"> <div className="flex flex-wrap gap-6 font-mono text-white items-baseline">
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<span className="text-slate-500 text-sm font-bold uppercase tracking-wider">Ширина:</span> <span className="text-slate-500 text-sm font-bold uppercase tracking-wider">Ширина:</span>
@@ -174,7 +167,6 @@ export const PreviewStep: React.FC<Props> = ({ parts, config, splits }) => {
<span className="text-sm text-slate-500 font-bold self-baseline">мм</span> <span className="text-sm text-slate-500 font-bold self-baseline">мм</span>
</div> </div>
</div> </div>
<button <button
onClick={handleShare} onClick={handleShare}
className={` className={`
@@ -191,7 +183,6 @@ export const PreviewStep: React.FC<Props> = ({ parts, config, splits }) => {
</div> </div>
<div className="flex flex-col lg:flex-row h-full gap-6 relative flex-1 min-h-0"> <div className="flex flex-col lg:flex-row h-full gap-6 relative flex-1 min-h-0">
{/* 3D Viewer */}
<div className="flex-1 bg-slate-900 rounded-xl overflow-hidden shadow-2xl border border-slate-800 relative min-h-[400px]"> <div className="flex-1 bg-slate-900 rounded-xl overflow-hidden shadow-2xl border border-slate-800 relative min-h-[400px]">
<div className="absolute top-4 right-4 z-10 bg-black/60 p-3 rounded-lg text-xs text-gray-300 backdrop-blur pointer-events-none border border-slate-700"> <div className="absolute top-4 right-4 z-10 bg-black/60 p-3 rounded-lg text-xs text-gray-300 backdrop-blur pointer-events-none border border-slate-700">
<div className="flex items-center gap-2 mb-1 text-primary font-bold"> <div className="flex items-center gap-2 mb-1 text-primary font-bold">
@@ -227,7 +218,7 @@ export const PreviewStep: React.FC<Props> = ({ parts, config, splits }) => {
key={part.id} key={part.id}
part={part} part={part}
thickness={config.wallThickness} thickness={config.wallThickness}
cornerRadius={config.cornerRadius || 0} // <-- ИСПРАВЛЕНО: Передаем радиус cornerRadius={config.cornerRadius || 0}
isSelected={selectedId === part.id} isSelected={selectedId === part.id}
onClick={() => setSelectedId(part.id)} onClick={() => setSelectedId(part.id)}
/> />
@@ -239,7 +230,6 @@ export const PreviewStep: React.FC<Props> = ({ parts, config, splits }) => {
</Canvas> </Canvas>
</div> </div>
{/* Sidebar List */}
<div className="w-full lg:w-96 bg-slate-900 p-6 rounded-xl border border-slate-800 flex flex-col h-full shadow-xl"> <div className="w-full lg:w-96 bg-slate-900 p-6 rounded-xl border border-slate-800 flex flex-col h-full shadow-xl">
<div className="flex justify-between items-center mb-6 shrink-0"> <div className="flex justify-between items-center mb-6 shrink-0">
<h2 className="text-xl font-bold flex items-center gap-2 text-primary"> <h2 className="text-xl font-bold flex items-center gap-2 text-primary">