EndpointSection.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <script setup>
  2. import { computed } from 'vue';
  3. import {
  4. DownOutlined,
  5. RightOutlined,
  6. } from '@ant-design/icons-vue';
  7. import EndpointRow from './EndpointRow.vue';
  8. import { safeInlineHtml } from './endpoints.js';
  9. const props = defineProps({
  10. section: { type: Object, required: true },
  11. icon: { type: Object, default: null },
  12. collapsed: { type: Boolean, default: false },
  13. });
  14. const emit = defineEmits(['toggle']);
  15. const endpointLabel = computed(() =>
  16. props.section.endpoints.length === 1
  17. ? '1 endpoint'
  18. : `${props.section.endpoints.length} endpoints`
  19. );
  20. </script>
  21. <template>
  22. <section :id="section.id" class="api-section">
  23. <div class="section-header" @click="emit('toggle')">
  24. <div class="section-header-left">
  25. <DownOutlined v-if="!collapsed" class="collapse-icon" />
  26. <RightOutlined v-else class="collapse-icon" />
  27. <component v-if="icon" :is="icon" class="section-icon" />
  28. <h2 class="section-title">{{ section.title }}</h2>
  29. </div>
  30. <span class="endpoint-count">{{ endpointLabel }}</span>
  31. </div>
  32. <p v-if="section.description && !collapsed" class="section-description" v-html="safeInlineHtml(section.description)"></p>
  33. <div v-if="section.subHeader && !collapsed" class="sub-header-block">
  34. <div class="block-label">Response headers</div>
  35. <a-table
  36. :columns="[{ title: 'Header', dataIndex: 'name', key: 'name', width: 240 }, { title: 'Description', dataIndex: 'desc', key: 'desc' }]"
  37. :data-source="section.subHeader"
  38. :pagination="false"
  39. size="small"
  40. row-key="name"
  41. >
  42. <template #bodyCell="{ column, text }">
  43. <span v-if="column.dataIndex === 'desc'" v-html="safeInlineHtml(text)"></span>
  44. <template v-else>{{ text }}</template>
  45. </template>
  46. </a-table>
  47. </div>
  48. <div v-show="!collapsed" class="endpoints">
  49. <EndpointRow v-for="(endpoint, idx) in section.endpoints" :key="idx" :endpoint="endpoint" />
  50. </div>
  51. </section>
  52. </template>
  53. <style scoped>
  54. .api-section {
  55. background: #fff;
  56. border: 1px solid rgba(128, 128, 128, 0.12);
  57. border-radius: 8px;
  58. padding: 20px 24px;
  59. margin-bottom: 16px;
  60. transition: box-shadow 0.2s, border-color 0.2s;
  61. }
  62. .api-section:hover {
  63. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
  64. }
  65. .section-header {
  66. display: flex;
  67. align-items: center;
  68. justify-content: space-between;
  69. cursor: pointer;
  70. user-select: none;
  71. }
  72. .section-header:hover .collapse-icon,
  73. .section-header:hover .section-icon {
  74. color: #1677ff;
  75. }
  76. .section-header-left {
  77. display: flex;
  78. align-items: center;
  79. gap: 10px;
  80. }
  81. .collapse-icon {
  82. font-size: 12px;
  83. color: rgba(0, 0, 0, 0.4);
  84. transition: color 0.2s;
  85. }
  86. .section-icon {
  87. font-size: 18px;
  88. color: rgba(0, 0, 0, 0.45);
  89. transition: color 0.2s;
  90. }
  91. .section-title {
  92. font-size: 20px;
  93. font-weight: 700;
  94. margin: 0;
  95. color: rgba(0, 0, 0, 0.88);
  96. }
  97. .endpoint-count {
  98. font-size: 11px;
  99. font-weight: 600;
  100. color: rgba(0, 0, 0, 0.45);
  101. white-space: nowrap;
  102. background: rgba(128, 128, 128, 0.08);
  103. padding: 3px 10px;
  104. border-radius: 12px;
  105. text-transform: uppercase;
  106. letter-spacing: 0.3px;
  107. }
  108. .section-description {
  109. margin: 12px 0 14px;
  110. color: rgba(0, 0, 0, 0.65);
  111. line-height: 1.6;
  112. }
  113. .sub-header-block {
  114. margin-bottom: 14px;
  115. }
  116. .block-label {
  117. font-size: 12px;
  118. font-weight: 600;
  119. text-transform: uppercase;
  120. letter-spacing: 0.5px;
  121. color: rgba(0, 0, 0, 0.5);
  122. margin-bottom: 6px;
  123. }
  124. .endpoints {
  125. padding-top: 8px;
  126. border-top: 1px solid rgba(128, 128, 128, 0.1);
  127. }
  128. .endpoints > :first-child {
  129. padding-top: 0;
  130. }
  131. </style>
  132. <style>
  133. body.dark .api-section {
  134. background: #252526;
  135. border-color: rgba(255, 255, 255, 0.08);
  136. }
  137. body.dark .api-section:hover {
  138. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
  139. }
  140. html[data-theme='ultra-dark'] .api-section {
  141. background: #0a0a0a;
  142. border-color: rgba(255, 255, 255, 0.06);
  143. }
  144. html[data-theme='ultra-dark'] .api-section:hover {
  145. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
  146. }
  147. body.dark .section-title {
  148. color: rgba(255, 255, 255, 0.92);
  149. }
  150. body.dark .section-icon {
  151. color: rgba(255, 255, 255, 0.5);
  152. }
  153. body.dark .section-description {
  154. color: rgba(255, 255, 255, 0.7);
  155. }
  156. body.dark .block-label {
  157. color: rgba(255, 255, 255, 0.55);
  158. }
  159. body.dark .endpoint-count {
  160. color: rgba(255, 255, 255, 0.55);
  161. background: rgba(255, 255, 255, 0.06);
  162. }
  163. </style>