corrad-af-2024/components/api-platform/ScalarConfigModal.vue

351 lines
13 KiB
Vue

<template>
<div class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-4xl max-h-[90vh] flex flex-col">
<!-- Header -->
<div class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
<div class="flex items-center gap-3">
<Icon name="ic:outline-settings" size="24" class="text-primary" />
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">
API Documentation Settings
</h2>
</div>
<rs-button variant="text" size="sm" @click="$emit('close')">
<Icon name="ic:outline-close" size="20" />
</rs-button>
</div>
<!-- Content -->
<div class="flex-1 overflow-hidden flex">
<!-- Sidebar Navigation -->
<div class="w-64 bg-gray-50 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 p-4">
<nav class="space-y-2">
<button
v-for="tab in configTabs"
:key="tab.id"
@click="activeTab = tab.id"
class="w-full text-left px-3 py-2 rounded-lg text-sm font-medium transition-colors"
:class="{
'bg-primary text-white': activeTab === tab.id,
'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800': activeTab !== tab.id
}"
>
<Icon :name="tab.icon" size="16" class="inline mr-2" />
{{ tab.label }}
</button>
</nav>
</div>
<!-- Main Content -->
<div class="flex-1 p-6 overflow-y-auto">
<!-- Basic Settings -->
<div v-if="activeTab === 'basic'" class="space-y-6">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Basic Information</h3>
<div class="grid grid-cols-1 gap-4">
<FormKit
type="text"
label="API Title"
help="The title shown in the documentation header"
v-model="localConfig.title"
/>
<FormKit
type="textarea"
label="Description"
help="Brief description of your API"
v-model="localConfig.description"
rows="3"
/>
<FormKit
type="text"
label="Version"
help="API version number"
v-model="localConfig.version"
/>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">OpenAPI Source</h3>
<FormKit
type="select"
label="Source Type"
help="Choose the source of your OpenAPI specification"
v-model="localConfig.sourceType"
:options="availableSourceTypes.map(t => ({ label: `${t.label} - ${t.description}`, value: t.value }))"
/>
</div>
</div>
<!-- Display Settings -->
<div v-if="activeTab === 'display'" class="space-y-6">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Theme</h3>
<FormKit
type="select"
label="Color Theme"
help="Choose the color theme for the documentation"
v-model="localConfig.theme"
:options="availableThemes.map(t => ({ label: `${t.label} - ${t.description}`, value: t.value }))"
/>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Layout Options</h3>
<div class="space-y-4">
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Show Sidebar</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Display the navigation sidebar</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.showSidebar"
outer-class="!mb-0"
/>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Show Search</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Enable search functionality</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.showSearch"
outer-class="!mb-0"
/>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Expand Tags by Default</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Show all endpoint groups expanded on load</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.defaultExpandedTags"
outer-class="!mb-0"
/>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Group by Tags</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Organize endpoints by their tags</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.groupByTags"
outer-class="!mb-0"
/>
</div>
</div>
</div>
</div>
<!-- Content Settings -->
<div v-if="activeTab === 'content'" class="space-y-6">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Content Display</h3>
<div class="space-y-4">
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Show Parameters</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Display endpoint parameters section</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.showParameters"
outer-class="!mb-0"
/>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Show Request Body</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Display request body schemas and examples</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.showRequestBody"
outer-class="!mb-0"
/>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Show Responses</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Display response schemas and examples</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.showResponses"
outer-class="!mb-0"
/>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">
<div>
<h5 class="font-medium text-gray-900 dark:text-white">Show Examples</h5>
<p class="text-sm text-gray-500 dark:text-gray-400">Display code examples and sample data</p>
</div>
<FormKit
type="checkbox"
v-model="localConfig.showExamples"
outer-class="!mb-0"
/>
</div>
</div>
</div>
</div>
<!-- Contact Settings -->
<div v-if="activeTab === 'contact'" class="space-y-6">
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Contact Information</h3>
<div class="grid grid-cols-1 gap-4">
<FormKit
type="text"
label="Contact Name"
help="Name or team responsible for the API"
v-model="localConfig.contact.name"
/>
<FormKit
type="email"
label="Contact Email"
help="Email address for API support"
v-model="localConfig.contact.email"
/>
<FormKit
type="url"
label="Contact URL"
help="Website or documentation URL"
v-model="localConfig.contact.url"
/>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Metadata</h3>
<div class="grid grid-cols-1 gap-4">
<FormKit
type="text"
label="Page Title"
help="Browser tab title"
v-model="localConfig.metaData.title"
/>
<FormKit
type="textarea"
label="Meta Description"
help="SEO description for the documentation page"
v-model="localConfig.metaData.description"
rows="2"
/>
<FormKit
type="text"
label="Favicon URL"
help="Path to favicon icon"
v-model="localConfig.metaData.favicon"
/>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<div class="flex items-center justify-between p-6 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
<div class="flex items-center space-x-3">
<rs-button
variant="secondary-outline"
size="sm"
@click="resetConfiguration"
>
<Icon name="ic:outline-refresh" size="16" class="mr-1" />
Reset to Defaults
</rs-button>
<rs-button
variant="secondary-outline"
size="sm"
@click="previewConfiguration"
>
<Icon name="ic:outline-visibility" size="16" class="mr-1" />
Preview
</rs-button>
</div>
<div class="flex items-center space-x-3">
<rs-button variant="secondary-outline" @click="$emit('close')">
Cancel
</rs-button>
<rs-button variant="primary" @click="saveConfiguration">
<Icon name="ic:outline-save" size="16" class="mr-1" />
Save Changes
</rs-button>
</div>
</div>
</div>
</div>
</template>
<script setup>
const emit = defineEmits(['close', 'saved']);
// Configuration management
const {
scalarConfig,
availableThemes,
availableSourceTypes,
updateScalarConfig,
resetScalarConfig
} = useScalarConfig();
// Local state
const activeTab = ref('basic');
const localConfig = ref({});
// Tab configuration
const configTabs = [
{ id: 'basic', label: 'Basic Info', icon: 'ic:outline-info' },
{ id: 'display', label: 'Display', icon: 'ic:outline-palette' },
{ id: 'content', label: 'Content', icon: 'ic:outline-article' },
{ id: 'contact', label: 'Contact', icon: 'ic:outline-contact-mail' }
];
// Initialize local config
onMounted(() => {
localConfig.value = JSON.parse(JSON.stringify(scalarConfig.value));
});
// Save configuration
const saveConfiguration = () => {
updateScalarConfig(localConfig.value);
emit('saved');
emit('close');
};
// Reset configuration
const resetConfiguration = () => {
if (confirm('Are you sure you want to reset all settings to their defaults?')) {
resetScalarConfig();
localConfig.value = JSON.parse(JSON.stringify(scalarConfig.value));
}
};
// Preview configuration
const previewConfiguration = () => {
// Save current config to preview storage
localStorage.setItem('api-docs-preview-config', JSON.stringify(localConfig.value));
// Open preview in new tab
const previewUrl = '/api-docs?preview=true';
window.open(previewUrl, '_blank');
};
</script>