351 lines
13 KiB
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> |