FitMop/frontend/src/components/WorkoutCompareView.vue

156 lines
4.6 KiB
Vue

<script setup>
import { ref, computed } from 'vue'
import { Eye, Edit2, Columns, Smartphone } from 'lucide-vue-next'
import WorkoutVisualEditor from './WorkoutVisualEditor.vue'
import WorkoutJsonEditor from './WorkoutJsonEditor.vue'
const props = defineProps({
original: {
type: Object,
required: true
},
modelValue: {
type: Object,
required: true
},
editorTab: {
type: String,
default: 'visual'
}
})
const emit = defineEmits(['update:modelValue'])
// Tab state for mobile or constrained views
const activeTab = ref('modified') // 'original' | 'modified' | 'split'
// Helper to determine if we can show split view (simple width check or just controlled by user preference)
const canSplit = ref(true)
const setTab = (tab) => {
activeTab.value = tab
}
const updateTabBasedOnWidth = () => {
if (window.innerWidth >= 768) {
if (activeTab.value !== 'split') activeTab.value = 'split'
}
}
import { onMounted, onUnmounted } from 'vue'
onMounted(() => {
updateTabBasedOnWidth()
window.addEventListener('resize', updateTabBasedOnWidth)
})
onUnmounted(() => {
window.removeEventListener('resize', updateTabBasedOnWidth)
})
</script>
<template>
<div class="compare-view h-full flex flex-col">
<!-- View Controls (only visible on small screens or if needed) -->
<div class="mobile-tabs md:hidden flex bg-gray-900 border-b border-gray-800 p-1">
<button
class="flex-1 py-2 text-sm font-medium rounded-md transition-colors flex items-center justify-center gap-2"
:class="
activeTab === 'original'
? 'bg-gray-800 text-white shadow'
: 'text-gray-400 hover:text-white'
"
@click="setTab('original')"
>
<Eye class="w-4 h-4" /> Original
</button>
<button
class="flex-1 py-2 text-sm font-medium rounded-md transition-colors flex items-center justify-center gap-2"
:class="
activeTab === 'modified'
? 'bg-blue-900/40 text-blue-100 shadow'
: 'text-gray-400 hover:text-white'
"
@click="setTab('modified')"
>
<Edit2 class="w-4 h-4" /> Modified
</button>
</div>
<!-- MAIN CONTENT AREA -->
<div class="compare-container flex-1 overflow-hidden relative">
<!-- LEFT PANEL: ORIGINAL (READONLY) -->
<div
class="panel original-panel border-r border-gray-800 bg-gray-900/50 flex-1 min-w-0"
:class="{ hidden: activeTab === 'modified' }"
>
<div
class="panel-header text-xs font-bold text-gray-500 uppercase tracking-wider p-3 border-b border-gray-800 flex justify-between"
>
<span>Original Version</span>
<span class="bg-gray-800 px-2 py-0.5 rounded text-gray-400">Read-only</span>
</div>
<div class="panel-content overflow-y-auto h-full p-4 relative">
<!-- Blocking Overlay for Interaction -->
<div class="absolute inset-0 z-10 cursor-not-allowed"></div>
<WorkoutVisualEditor
v-if="editorTab === 'visual'"
:modelValue="original"
:steps="original.workoutSegments[0].workoutSteps"
readonly
/>
<WorkoutJsonEditor v-else :modelValue="original" readonly />
</div>
</div>
<!-- RIGHT PANEL: MODIFIED (EDITABLE) -->
<div
class="panel modified-panel flex-1 min-w-0"
:class="{ hidden: activeTab === 'original' }"
>
<div
class="panel-header text-xs font-bold text-blue-400 uppercase tracking-wider p-3 border-b border-gray-800 bg-blue-900/10 flex justify-between"
>
<span>Working Copy</span>
<span class="bg-blue-900/30 px-2 py-0.5 rounded text-blue-200">Editable</span>
</div>
<div class="panel-content overflow-y-auto h-full p-4">
<WorkoutVisualEditor
v-if="editorTab === 'visual'"
:modelValue="modelValue"
:steps="modelValue.workoutSegments[0].workoutSteps"
@update:modelValue="(val) => emit('update:modelValue', val)"
/>
<WorkoutJsonEditor
v-else
:modelValue="modelValue"
@update:modelValue="(val) => emit('update:modelValue', val)"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.compare-container {
display: flex !important; /* Force flex to override any potential blocking */
flex-direction: row;
flex-wrap: nowrap;
}
.panel {
display: flex;
flex-direction: column;
}
/* Ensure Desktop defaults to split */
/* Ensure Desktop defaults to split */
@media (min-width: 768px) {
.md\:hidden {
display: none !important;
}
}
</style>