fix: arreglar errores menores y ajustes visuales
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import CriterionInput from '../components/CriterionInput';
|
||||
import CardEditor from '../components/CardEditor';
|
||||
import BlankCardsCounter from '../components/BlankCardsCounter';
|
||||
@@ -22,6 +22,28 @@ export default function AdvancedMode() {
|
||||
// Estado para controlar la lupa (Zoom)
|
||||
const [isZoomActive, setIsZoomActive] = useState(true);
|
||||
|
||||
// Medición exacta con Refs
|
||||
const containerRef = useRef(null);
|
||||
const tableRef = useRef(null);
|
||||
const [dimensions, setDimensions] = useState({ container: 1000, table: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
const updateMeasurements = () => {
|
||||
if (containerRef.current && tableRef.current) {
|
||||
setDimensions({
|
||||
container: containerRef.current.offsetWidth,
|
||||
table: tableRef.current.scrollWidth
|
||||
});
|
||||
}
|
||||
};
|
||||
const timeoutId = setTimeout(updateMeasurements, 50);
|
||||
window.addEventListener('resize', updateMeasurements);
|
||||
return () => {
|
||||
clearTimeout(timeoutId);
|
||||
window.removeEventListener('resize', updateMeasurements);
|
||||
};
|
||||
}, [levels, blankCards, step]);
|
||||
|
||||
// Estados Fase 2 (Franjas)
|
||||
const [baseScale, setBaseScale] = useState({});
|
||||
const [selectedTerm, setSelectedTerm] = useState(null);
|
||||
@@ -56,7 +78,6 @@ export default function AdvancedMode() {
|
||||
} catch (error) { alert("Error: " + error); } finally { setIsLoading(false); }
|
||||
};
|
||||
|
||||
// Manejadores de Franjas
|
||||
const updateCurrentMf = (field, value) => {
|
||||
if (!selectedTerm) return;
|
||||
let numValue = parseFloat(value);
|
||||
@@ -64,7 +85,6 @@ export default function AdvancedMode() {
|
||||
setMfDefinitions(prev => {
|
||||
const scaleKeys = Object.keys(baseScale);
|
||||
const selectedIndex = scaleKeys.indexOf(selectedTerm);
|
||||
|
||||
let prevCoreEnd = 0, prevSupportEnd = 0, nextCoreStart = 1, nextSupportStart = 1;
|
||||
|
||||
if (selectedIndex > 0) {
|
||||
@@ -100,66 +120,62 @@ export default function AdvancedMode() {
|
||||
const scaleKeys = Object.keys(baseScale);
|
||||
const selectedColor = COLORS[scaleKeys.indexOf(selectedTerm) % COLORS.length] || '#2563eb';
|
||||
|
||||
const totalElements = levels.length;
|
||||
const dynamicScale = totalElements > 6 ? 6.2 / totalElements : 1;
|
||||
const currentScale = isZoomActive ? Math.max(0.4, dynamicScale) : 1;
|
||||
const needsZoom = dimensions.table > dimensions.container;
|
||||
const dynamicScale = needsZoom ? (dimensions.container / dimensions.table) * 0.95 : 1;
|
||||
const currentScale = isZoomActive && needsZoom ? dynamicScale : 1;
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-col items-center">
|
||||
|
||||
{/* PASO 1 */}
|
||||
{step === 1 && (
|
||||
<div className="w-full bg-white p-8 rounded-3xl shadow-sm border border-slate-200 mb-12 flex flex-col items-center animate-fade-in overflow-hidden">
|
||||
<div className="w-full bg-white p-6 rounded-2xl shadow-sm border border-slate-200 mb-6 flex flex-col items-center animate-fade-in relative overflow-visible">
|
||||
|
||||
<div className="flex justify-between items-center w-full mb-8 border-b pb-4">
|
||||
<h2 className="text-2xl font-bold text-slate-800">
|
||||
<div className="flex justify-between items-center w-full mb-4 border-b pb-3 relative z-30">
|
||||
<h2 className="text-xl font-bold text-slate-800">
|
||||
Paso 1: Escala de Referencia (Mesa)
|
||||
</h2>
|
||||
|
||||
{totalElements > 6 && (
|
||||
<button
|
||||
onClick={() => setIsZoomActive(!isZoomActive)}
|
||||
className={`flex items-center gap-2 px-4 py-2 rounded-xl font-bold transition-all shadow-sm border-2 ${
|
||||
isZoomActive
|
||||
? 'bg-blue-50 border-blue-200 text-blue-700 hover:bg-blue-100'
|
||||
: 'bg-white border-slate-200 text-slate-600 hover:bg-slate-50'
|
||||
}`}
|
||||
>
|
||||
<span className="text-xl">{isZoomActive ? '🔍' : '🖼️'}</span>
|
||||
{isZoomActive ? 'Ver de cerca' : 'Ajustar mesa a la pantalla'}
|
||||
{needsZoom && (
|
||||
<button onClick={() => setIsZoomActive(!isZoomActive)} className={`flex items-center gap-2 px-3 py-1.5 rounded-lg font-bold transition-all shadow-sm border text-sm ${isZoomActive ? 'bg-blue-50 border-blue-200 text-blue-700' : 'bg-white border-slate-200 text-slate-600'}`}>
|
||||
<span>{isZoomActive ? '🔍' : '🖼️'}</span>
|
||||
{isZoomActive ? 'Ver de cerca (Scroll)' : 'Ajustar mesa'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<CriterionInput criterionName={criterionName} setCriterionName={handleCriterionChange} error={errors.criterion} />
|
||||
|
||||
<div className={`w-full mt-6 flex ${!isZoomActive ? 'overflow-x-auto pb-12 justify-start px-4' : 'overflow-hidden justify-center'}`}>
|
||||
|
||||
<div
|
||||
className={`flex flex-row items-center min-w-max px-2 transition-transform duration-500 ease-out ${isZoomActive ? 'origin-top' : 'origin-top-left'}`}
|
||||
style={{
|
||||
transform: `scale(${currentScale})`,
|
||||
marginBottom: isZoomActive && currentScale < 1 ? `-${(1 - currentScale) * 350}px` : '0px'
|
||||
}}
|
||||
>
|
||||
{levels.map((level, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<CardEditor index={index} level={level} handleLevelChange={handleLevelChange} handleRemoveLevel={handleRemoveLevel} totalLevels={levels.length} error={errors.levels[index]} canRemove={levels.length > 3} />
|
||||
|
||||
{index < levels.length - 1 && (
|
||||
<BlankCardsCounter index={index} blankCardsCount={blankCards[index]} handleBlankCardChange={handleBlankCardChange} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div ref={containerRef} className={`w-full mt-6 transition-all relative ${!isZoomActive && needsZoom ? 'overflow-x-auto flex justify-start pb-8 pt-8 px-4' : 'overflow-hidden flex justify-center pb-8 pt-8'}`}>
|
||||
<div className={`flex flex-row items-start min-w-max transition-transform duration-500 ease-out px-4 origin-top`} style={{ transform: `scale(${currentScale})`, marginBottom: isZoomActive && currentScale < 1 ? `-${(1 - currentScale) * 300}px` : '0px' }}>
|
||||
|
||||
<div className="w-6 h-1 bg-slate-200 mx-1 top-[40%]"></div>
|
||||
<AddLevelButton handleAddLevel={handleAddLevel} />
|
||||
</div>
|
||||
<div ref={tableRef} className="flex flex-row items-start relative px-10 overflow-visible">
|
||||
|
||||
{levels.map((level, index) => (
|
||||
<React.Fragment key={index}>
|
||||
|
||||
<div className="flex flex-col items-center mx-2 my-2 relative z-20">
|
||||
<CardEditor index={index} level={level} handleLevelChange={handleLevelChange} handleRemoveLevel={handleRemoveLevel} totalLevels={levels.length} error={errors.levels[index]} canRemove={levels.length > 3} />
|
||||
</div>
|
||||
|
||||
{index < levels.length - 1 && (
|
||||
<BlankCardsCounter index={index} blankCardsCount={blankCards[index]} handleBlankCardChange={handleBlankCardChange} />
|
||||
)}
|
||||
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
<div className="mx-1 my-2 h-52 flex items-center justify-center">
|
||||
<div className="w-10 h-1 bg-slate-200 rounded"></div>
|
||||
</div>
|
||||
|
||||
<AddLevelButton handleAddLevel={handleAddLevel} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full max-w-lg mt-12 pt-8 border-t-2 border-slate-200 flex flex-col items-center z-20 relative bg-white">
|
||||
<button onClick={handleGenerateBaseScale} disabled={isLoading} className={`w-full py-4 text-white text-xl font-bold rounded-xl shadow-lg transition-all active:scale-[0.98] ${isLoading ? 'bg-slate-400 cursor-not-allowed' : 'bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700'}`}>
|
||||
<div className="w-full max-w-lg mt-2 pt-6 border-t border-slate-200 flex flex-col items-center z-20 relative bg-white">
|
||||
<button onClick={handleGenerateBaseScale} disabled={isLoading} className={`w-full py-3 text-white text-lg font-bold rounded-xl shadow-md transition-all active:scale-[0.98] ${isLoading ? 'bg-slate-400 cursor-not-allowed' : 'bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700'}`}>
|
||||
{isLoading ? 'Calculando...' : 'Generar Gráfica Continua'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -168,19 +184,19 @@ export default function AdvancedMode() {
|
||||
|
||||
{/* PASO 2 */}
|
||||
{step === 2 && (
|
||||
<div className="w-full max-w-6xl bg-white p-10 rounded-3xl shadow-sm border border-slate-200 animate-fade-in">
|
||||
<div className="flex justify-between items-center mb-8 border-b pb-4">
|
||||
<h2 className="text-2xl font-bold text-slate-800">Paso 2: Modelar Conceptos Difusos</h2>
|
||||
<button onClick={() => setStep(1)} className="text-slate-500 hover:text-blue-600 font-semibold underline">← Volver a las cartas</button>
|
||||
<div className="w-full max-w-6xl bg-white p-6 rounded-2xl shadow-sm border border-slate-200 animate-fade-in relative overflow-visible">
|
||||
<div className="flex justify-between items-center mb-6 border-b pb-3">
|
||||
<h2 className="text-xl font-bold text-slate-800">Paso 2: Modelar Conceptos Difusos</h2>
|
||||
<button onClick={() => setStep(1)} className="text-slate-500 hover:text-blue-600 text-sm font-semibold underline">← Volver a las cartas</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap justify-center gap-4 mb-8">
|
||||
<div className="flex flex-wrap justify-center gap-3 mb-6">
|
||||
{scaleKeys.map((name, index) => {
|
||||
const color = COLORS[index % COLORS.length];
|
||||
const isSelected = selectedTerm === name;
|
||||
return (
|
||||
<button key={name} onClick={() => setSelectedTerm(name)} style={isSelected ? { backgroundColor: color, borderColor: color, color: '#fff' } : { borderColor: color, color: '#475569' }} className={`px-6 py-3 rounded-xl font-bold border-2 transition-all duration-300 flex flex-col items-center shadow-sm hover:shadow-md ${isSelected ? 'transform scale-105' : 'bg-white opacity-80 hover:opacity-100'}`}>
|
||||
<span>{name}</span><span className="text-xs font-normal opacity-80">(X: {baseScale[name].toFixed(2)})</span>
|
||||
<button key={name} onClick={() => setSelectedTerm(name)} style={isSelected ? { backgroundColor: color, borderColor: color, color: '#fff' } : { borderColor: color, color: '#475569' }} className={`px-5 py-2 rounded-lg font-bold border-2 transition-all duration-300 flex flex-col items-center shadow-sm hover:shadow-md ${isSelected ? 'transform scale-105' : 'bg-white opacity-80 hover:opacity-100'}`}>
|
||||
<span>{name}</span><span className="text-[10px] font-normal opacity-80">(X: {baseScale[name].toFixed(2)})</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -188,16 +204,10 @@ export default function AdvancedMode() {
|
||||
|
||||
<Chart baseScale={baseScale} mfDefinitions={mfDefinitions} selectedTerm={selectedTerm} colors={COLORS} />
|
||||
|
||||
<Controls
|
||||
selectedTerm={selectedTerm}
|
||||
currentMf={mfDefinitions[selectedTerm]}
|
||||
selectedColor={selectedColor}
|
||||
baseScale={baseScale}
|
||||
mfDefinitions={mfDefinitions}
|
||||
updateCurrentMf={updateCurrentMf}
|
||||
/>
|
||||
<div className="w-full mt-12 flex justify-center">
|
||||
<button onClick={handleFinalSubmit} className="px-12 py-4 bg-slate-900 text-white text-xl font-bold rounded-xl shadow-lg hover:bg-black hover:shadow-xl transition-all">
|
||||
<Controls selectedTerm={selectedTerm} currentMf={mfDefinitions[selectedTerm]} selectedColor={selectedColor} baseScale={baseScale} mfDefinitions={mfDefinitions} updateCurrentMf={updateCurrentMf} />
|
||||
|
||||
<div className="w-full mt-8 flex justify-center">
|
||||
<button onClick={handleFinalSubmit} className="px-10 py-3 bg-slate-900 text-white text-lg font-bold rounded-xl shadow-md hover:bg-black hover:shadow-lg transition-all">
|
||||
Guardar Todo el Espectro Difuso
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user