127 lines
3.0 KiB
Vue
127 lines
3.0 KiB
Vue
<template>
|
|
<div class="file-selector">
|
|
<label for="file-select">Select File:</label>
|
|
<select
|
|
id="file-select"
|
|
v-model="selectedFile"
|
|
:disabled="isLoading || uniqueFiles.length === 0"
|
|
>
|
|
<option value="">-- Choose a file --</option>
|
|
<option
|
|
v-for="file in uniqueFiles"
|
|
:key="file.filename"
|
|
:value="getFileType(file.filename)"
|
|
>
|
|
{{ formatFileName(file.filename) }} ({{ formatSize(file.size) }})
|
|
</option>
|
|
</select>
|
|
|
|
<span v-if="fileContent" class="file-info">
|
|
{{ fileLines.length.toLocaleString() }} lines
|
|
<template v-if="selectedFileMeta">
|
|
• {{ formatSize(selectedFileMeta.size) }}
|
|
</template>
|
|
</span>
|
|
|
|
<span v-if="isLoading" class="file-status">Loading...</span>
|
|
<span v-if="fileError" class="file-error">{{ fileError }}</span>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted } from 'vue';
|
|
import { useGamemasterFiles } from '../../composables/useGamemasterFiles.js';
|
|
|
|
const props = defineProps({
|
|
client: {
|
|
type: Object,
|
|
default: null
|
|
},
|
|
filesState: {
|
|
type: Object,
|
|
default: null
|
|
}
|
|
});
|
|
|
|
const internalFilesState = props.client
|
|
? useGamemasterFiles(props.client)
|
|
: null;
|
|
const activeFilesState = computed(() => props.filesState || internalFilesState);
|
|
|
|
const selectedFile = computed({
|
|
get: () => activeFilesState.value?.selectedFile?.value,
|
|
set: val => {
|
|
if (activeFilesState.value?.selectedFile) {
|
|
activeFilesState.value.selectedFile.value = val;
|
|
}
|
|
}
|
|
});
|
|
const fileContent = computed(() => activeFilesState.value?.fileContent?.value);
|
|
const fileLines = computed(
|
|
() => activeFilesState.value?.fileLines?.value || []
|
|
);
|
|
const uniqueFiles = computed(
|
|
() => activeFilesState.value?.uniqueFiles?.value || []
|
|
);
|
|
const isLoading = computed(
|
|
() => activeFilesState.value?.isLoading?.value || false
|
|
);
|
|
const fileError = computed(() => activeFilesState.value?.fileError?.value);
|
|
|
|
const formatSize = (...args) => activeFilesState.value?.formatSize?.(...args);
|
|
const formatFileName = (...args) =>
|
|
activeFilesState.value?.formatFileName?.(...args);
|
|
const getFileType = (...args) => activeFilesState.value?.getFileType?.(...args);
|
|
|
|
const selectedFileMeta = computed(() => {
|
|
if (!selectedFile.value) return null;
|
|
return uniqueFiles.value.find(
|
|
file => getFileType(file.filename) === selectedFile.value
|
|
);
|
|
});
|
|
|
|
// Don't call loadStatus here - it's called by the parent component
|
|
</script>
|
|
|
|
<style scoped>
|
|
.file-selector {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.file-selector label {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.file-selector select {
|
|
padding: 6px 10px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
background: white;
|
|
}
|
|
|
|
.file-selector select:disabled {
|
|
background: #f5f5f5;
|
|
color: #999;
|
|
}
|
|
|
|
.file-info {
|
|
font-size: 13px;
|
|
color: #666;
|
|
}
|
|
|
|
.file-status {
|
|
font-size: 13px;
|
|
color: #666;
|
|
}
|
|
|
|
.file-error {
|
|
font-size: 13px;
|
|
color: #d9534f;
|
|
}
|
|
</style>
|