@scalar/api-reference 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/components/ApiReference.vue.d.ts +0 -24
- package/dist/components/ApiReference.vue.d.ts.map +1 -1
- package/dist/components/Content/Introduction/BaseUrl.vue.d.ts.map +1 -1
- package/dist/components/Content/MarkdownRenderer.vue.d.ts.map +1 -1
- package/dist/components/Content/ReferenceEndpoint/Copy.vue.d.ts.map +1 -1
- package/dist/components/Content/ReferenceEndpoint/ExampleRequest.vue.d.ts.map +1 -1
- package/dist/components/Content/ReferenceEndpoint/{ExampleResponses.vue.d.ts → ExampleResponses/ExampleResponses.vue.d.ts} +1 -1
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/ExampleResponses.vue.d.ts.map +1 -0
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/Headers.vue.d.ts +14 -0
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/Headers.vue.d.ts.map +1 -0
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/SelectExample.vue.d.ts +13 -0
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/SelectExample.vue.d.ts.map +1 -0
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/index.d.ts +2 -0
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses/index.d.ts.map +1 -0
- package/dist/components/Sidebar.vue.d.ts.map +1 -1
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/mapFromObject.d.ts +8 -0
- package/dist/helpers/mapFromObject.d.ts.map +1 -0
- package/dist/index.js +16657 -19388
- package/dist/types.d.ts +9 -11
- package/dist/types.d.ts.map +1 -1
- package/package.json +32 -11
- package/src/components/ApiReference.vue +0 -4
- package/src/components/Content/Introduction/BaseUrl.vue +22 -5
- package/src/components/Content/MarkdownRenderer.vue +5 -2
- package/src/components/Content/ReferenceEndpoint/Copy.vue +2 -1
- package/src/components/Content/ReferenceEndpoint/ExampleRequest.vue +21 -7
- package/src/components/Content/ReferenceEndpoint/{ExampleResponses.vue → ExampleResponses/ExampleResponses.vue} +57 -57
- package/src/components/Content/ReferenceEndpoint/ExampleResponses/Headers.vue +83 -0
- package/src/components/Content/ReferenceEndpoint/ExampleResponses/SelectExample.vue +129 -0
- package/src/components/Content/ReferenceEndpoint/ExampleResponses/index.ts +1 -0
- package/src/components/Content/ReferenceEndpoint/ReferenceEndpoint.vue +1 -1
- package/src/components/Sidebar.vue +6 -2
- package/src/components/SimpleTable/SimpleCell.vue +1 -0
- package/src/helpers/index.ts +1 -0
- package/src/helpers/mapFromObject.ts +11 -0
- package/src/types.ts +13 -14
- package/dist/components/Content/ReferenceEndpoint/ExampleResponses.vue.d.ts.map +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
export type ReferenceProps = {
|
|
2
|
-
documentName?: string;
|
|
3
|
-
token?: string;
|
|
4
|
-
username?: string;
|
|
5
|
-
hocusPocusUrl?: string;
|
|
6
2
|
isEditable?: boolean;
|
|
7
3
|
showSidebar?: boolean;
|
|
8
4
|
footerBelowSidebar?: boolean;
|
|
@@ -46,15 +42,17 @@ export type Operation = {
|
|
|
46
42
|
description: string;
|
|
47
43
|
information: Information;
|
|
48
44
|
};
|
|
45
|
+
export type ExampleResponseHeaders = Record<string, {
|
|
46
|
+
description: string;
|
|
47
|
+
schema: {
|
|
48
|
+
type: string;
|
|
49
|
+
format?: string;
|
|
50
|
+
example?: string;
|
|
51
|
+
};
|
|
52
|
+
}>;
|
|
49
53
|
export type TransformedOperation = Operation & {
|
|
50
54
|
responses: Record<string, Response & {
|
|
51
|
-
headers:
|
|
52
|
-
description: string;
|
|
53
|
-
schema: {
|
|
54
|
-
type: string;
|
|
55
|
-
format?: string;
|
|
56
|
-
};
|
|
57
|
-
}>;
|
|
55
|
+
headers: ExampleResponseHeaders;
|
|
58
56
|
}>;
|
|
59
57
|
};
|
|
60
58
|
export type Tag = {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalar/api-reference",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"description": "generate beautiful API references from OpenAPI specs",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"vue",
|
|
6
|
+
"vue3",
|
|
7
|
+
"swagger",
|
|
8
|
+
"openapi",
|
|
9
|
+
"spec",
|
|
10
|
+
"reference",
|
|
11
|
+
"documentation",
|
|
12
|
+
"component"
|
|
13
|
+
],
|
|
14
|
+
"version": "0.5.1",
|
|
15
|
+
"author": "Scalar (https://github.com/scalar)",
|
|
16
|
+
"homepage": "https://github.com/scalar/scalar",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/scalar/scalar.git",
|
|
20
|
+
"directory": "packages/api-reference"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/scalar/scalar/issues/new"
|
|
24
|
+
},
|
|
5
25
|
"license": "MIT",
|
|
6
26
|
"engines": {
|
|
7
27
|
"node": ">=18"
|
|
@@ -21,7 +41,6 @@
|
|
|
21
41
|
"dependencies": {
|
|
22
42
|
"@headlessui/vue": "1.7.14",
|
|
23
43
|
"@vueuse/core": "10.1.2",
|
|
24
|
-
"codemirror": "6.0.1",
|
|
25
44
|
"fuse.js": "^6.6.2",
|
|
26
45
|
"httpsnippet-lite": "3.0.5",
|
|
27
46
|
"js-yaml": "4.1.0",
|
|
@@ -32,6 +51,7 @@
|
|
|
32
51
|
"rehype-format": "4.0.1",
|
|
33
52
|
"rehype-sanitize": "5.0.1",
|
|
34
53
|
"rehype-stringify": "9.0.3",
|
|
54
|
+
"remark-breaks": "^3.0.3",
|
|
35
55
|
"remark-gfm": "3.0.1",
|
|
36
56
|
"remark-parse": "10.0.2",
|
|
37
57
|
"remark-rehype": "10.1.0",
|
|
@@ -39,14 +59,15 @@
|
|
|
39
59
|
"typographic-base": "1.0.4",
|
|
40
60
|
"unified": "10.1.2",
|
|
41
61
|
"xmldom": "0.6.0",
|
|
42
|
-
"@scalar/api-client": "0.
|
|
43
|
-
"@scalar/default-theme": "0.2.
|
|
44
|
-
"@scalar/swagger-editor": "0.
|
|
45
|
-
"@scalar/swagger-parser": "0.4.
|
|
46
|
-
"@scalar/use-clipboard": "0.4.
|
|
47
|
-
"@scalar/use-
|
|
48
|
-
"@scalar/use-
|
|
49
|
-
"@scalar/use-
|
|
62
|
+
"@scalar/api-client": "0.5.1",
|
|
63
|
+
"@scalar/default-theme": "0.2.1",
|
|
64
|
+
"@scalar/swagger-editor": "0.5.1",
|
|
65
|
+
"@scalar/swagger-parser": "0.4.2",
|
|
66
|
+
"@scalar/use-clipboard": "0.4.1",
|
|
67
|
+
"@scalar/use-codemirror": "0.5.0",
|
|
68
|
+
"@scalar/use-keyboard-event": "0.4.1",
|
|
69
|
+
"@scalar/use-toasts": "0.4.1",
|
|
70
|
+
"@scalar/use-tooltip": "0.4.1"
|
|
50
71
|
},
|
|
51
72
|
"devDependencies": {
|
|
52
73
|
"@vitejs/plugin-vue": "4.2.3",
|
|
@@ -180,10 +180,6 @@ const breadCrumbs = computed(() => {
|
|
|
180
180
|
v-show="showCodeEditor"
|
|
181
181
|
class="layout-content">
|
|
182
182
|
<LazyLoadedSwaggerEditor
|
|
183
|
-
:documentName="documentName"
|
|
184
|
-
:hocusPocusUrl="hocusPocusUrl"
|
|
185
|
-
:token="token"
|
|
186
|
-
:username="username"
|
|
187
183
|
:value="specRef"
|
|
188
184
|
@specUpdate="handleSpecUpdate" />
|
|
189
185
|
</div>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { useClipboard } from '@scalar/use-clipboard'
|
|
3
|
+
import { computed } from 'vue'
|
|
3
4
|
|
|
4
|
-
defineProps<{
|
|
5
|
+
const props = defineProps<{
|
|
5
6
|
server?: {
|
|
6
7
|
url: string
|
|
7
8
|
description?: string
|
|
@@ -9,23 +10,39 @@ defineProps<{
|
|
|
9
10
|
}>()
|
|
10
11
|
|
|
11
12
|
const { copyToClipboard } = useClipboard()
|
|
13
|
+
|
|
14
|
+
const formattedServerUrl = computed(() => {
|
|
15
|
+
const url = props.server?.url ?? ''
|
|
16
|
+
const urlWithoutHtml = url.replace(/(<([^>]+)>)/gi, '')
|
|
17
|
+
|
|
18
|
+
/* Replace all variables (example: {{ baseurl }} with an HTML tag) */
|
|
19
|
+
return urlWithoutHtml.replace(
|
|
20
|
+
/{{\s*([\w.-]+)\s*}}/g,
|
|
21
|
+
'<span class="base-url-variable">{{ $1 }}</span>',
|
|
22
|
+
)
|
|
23
|
+
})
|
|
12
24
|
</script>
|
|
13
25
|
<template>
|
|
14
26
|
<template v-if="server">
|
|
15
27
|
<a
|
|
16
28
|
class="base-url"
|
|
17
29
|
:title="server.description"
|
|
18
|
-
@click="copyToClipboard(server.url)"
|
|
19
|
-
|
|
20
|
-
</a>
|
|
30
|
+
@click="copyToClipboard(server.url)"
|
|
31
|
+
v-html="formattedServerUrl" />
|
|
21
32
|
</template>
|
|
22
33
|
</template>
|
|
34
|
+
|
|
35
|
+
<style>
|
|
36
|
+
.base-url-variable {
|
|
37
|
+
color: var(--theme-color-disabled);
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
40
|
+
|
|
23
41
|
<style scoped>
|
|
24
42
|
.base-url {
|
|
25
43
|
color: var(--theme-color-2);
|
|
26
44
|
font-size: var(--theme-mini);
|
|
27
45
|
cursor: pointer;
|
|
28
|
-
display: flex;
|
|
29
46
|
font-family: var(--theme-font-code);
|
|
30
47
|
flex-direction: column;
|
|
31
48
|
}
|
|
@@ -3,6 +3,7 @@ import rehypeDocument from 'rehype-document'
|
|
|
3
3
|
import rehypeFormat from 'rehype-format'
|
|
4
4
|
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'
|
|
5
5
|
import rehypeStringify from 'rehype-stringify'
|
|
6
|
+
import remarkBreaks from 'remark-breaks'
|
|
6
7
|
import remarkGfm from 'remark-gfm'
|
|
7
8
|
import remarkParse from 'remark-parse'
|
|
8
9
|
import remarkRehype from 'remark-rehype'
|
|
@@ -20,6 +21,7 @@ watch(
|
|
|
20
21
|
() => {
|
|
21
22
|
unified()
|
|
22
23
|
.use(remarkParse)
|
|
24
|
+
.use(remarkBreaks)
|
|
23
25
|
.use(remarkGfm)
|
|
24
26
|
.use(remarkRehype)
|
|
25
27
|
.use(remarkTextr, { plugins: [typographicBase] })
|
|
@@ -59,6 +61,7 @@ watch(
|
|
|
59
61
|
.markdown :deep(h6) {
|
|
60
62
|
font-size: var(--font-size);
|
|
61
63
|
margin: 12px 0 6px;
|
|
64
|
+
font-weight: var(--theme-bold);
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
.markdown :deep(p) {
|
|
@@ -123,7 +126,7 @@ watch(
|
|
|
123
126
|
border-collapse: collapse;
|
|
124
127
|
table-layout: fixed;
|
|
125
128
|
width: 100%;
|
|
126
|
-
margin: 0;
|
|
129
|
+
margin: 1em 0;
|
|
127
130
|
overflow: hidden;
|
|
128
131
|
box-shadow: 0 0 0 1px var(--theme-border-color);
|
|
129
132
|
border-radius: var(--theme-radius-lg);
|
|
@@ -149,7 +152,7 @@ watch(
|
|
|
149
152
|
margin-top: 4px;
|
|
150
153
|
font-size: var(--theme-small);
|
|
151
154
|
color: var(--theme-color-2);
|
|
152
|
-
line-height:
|
|
155
|
+
line-height: 1.4;
|
|
153
156
|
}
|
|
154
157
|
.markdown :deep(td:first-of-type),
|
|
155
158
|
.markdown :deep(th:first-of-type) {
|
|
@@ -9,6 +9,7 @@ import { computed, onMounted, ref } from 'vue'
|
|
|
9
9
|
|
|
10
10
|
import { useTemplateStore } from '../../../stores/template'
|
|
11
11
|
import type { Tag } from '../../../types'
|
|
12
|
+
import MarkdownRenderer from '../MarkdownRenderer.vue'
|
|
12
13
|
import Parameters from './Parameters.vue'
|
|
13
14
|
import RequestBody from './RequestBody.vue'
|
|
14
15
|
|
|
@@ -72,7 +73,7 @@ onMounted(() => {
|
|
|
72
73
|
</div>
|
|
73
74
|
<div>
|
|
74
75
|
<p class="tag-description">
|
|
75
|
-
|
|
76
|
+
<MarkdownRenderer :value="operation.description" />
|
|
76
77
|
</p>
|
|
77
78
|
</div>
|
|
78
79
|
<Parameters
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {
|
|
3
|
-
CodeMirror,
|
|
4
3
|
generateRequest,
|
|
5
4
|
useApiClientRequestStore,
|
|
6
5
|
useApiClientStore,
|
|
7
6
|
useOperation,
|
|
8
7
|
} from '@scalar/api-client'
|
|
9
8
|
import { useClipboard } from '@scalar/use-clipboard'
|
|
9
|
+
import { CodeMirror } from '@scalar/use-codemirror'
|
|
10
10
|
import {
|
|
11
11
|
HTTPSnippet,
|
|
12
12
|
type HarRequest,
|
|
@@ -55,26 +55,39 @@ async function generateSnippet() {
|
|
|
55
55
|
if (pathVariables) {
|
|
56
56
|
pathVariables.forEach((variable) => {
|
|
57
57
|
const variableName = variable.replace(/{|}/g, '')
|
|
58
|
-
path = path.replace(variable, variableName.toUpperCase())
|
|
58
|
+
path = path.replace(variable, `__${variableName.toUpperCase()}__`)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let url = props.server.url
|
|
63
|
+
|
|
64
|
+
// Replace all variables of the format {something} with the uppercase variable name without the brackets
|
|
65
|
+
const urlVariables = url.match(/{{(.*?)}}/g)
|
|
66
|
+
|
|
67
|
+
if (urlVariables) {
|
|
68
|
+
console.log(urlVariables)
|
|
69
|
+
urlVariables.forEach((variable) => {
|
|
70
|
+
const variableName = variable.replace(/{|}/g, '')
|
|
71
|
+
url = url.replace(variable, `__${variableName}__`)
|
|
59
72
|
})
|
|
60
73
|
}
|
|
61
74
|
|
|
62
75
|
if (templateState.preferredLanguage === 'axios') {
|
|
63
76
|
return generateAxiosCodeFromRequest({
|
|
64
77
|
method: props.operation.httpVerb.toUpperCase(),
|
|
65
|
-
url: `${
|
|
78
|
+
url: `${url}${path}`,
|
|
66
79
|
})
|
|
67
80
|
} else if (templateState.preferredLanguage === 'laravel') {
|
|
68
81
|
return generateLaravelCodeFromRequest({
|
|
69
82
|
method: props.operation.httpVerb.toUpperCase(),
|
|
70
|
-
url: `${
|
|
83
|
+
url: `${url}${path}`,
|
|
71
84
|
})
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
try {
|
|
75
88
|
const snippet = new HTTPSnippet({
|
|
76
89
|
method: props.operation.httpVerb.toUpperCase(),
|
|
77
|
-
url: `${
|
|
90
|
+
url: `${url}${path}`,
|
|
78
91
|
} as HarRequest)
|
|
79
92
|
const output = (await snippet.convert(
|
|
80
93
|
templateState.preferredLanguage as TargetId,
|
|
@@ -176,9 +189,10 @@ const availableLanguages = computed(() => {
|
|
|
176
189
|
<!-- @vue-ignore -->
|
|
177
190
|
<CodeMirror
|
|
178
191
|
:content="CodeMirrorValue"
|
|
192
|
+
:forceDarkMode="true"
|
|
179
193
|
:languages="CodeMirrorLanguages"
|
|
180
|
-
|
|
181
|
-
|
|
194
|
+
lineNumbers
|
|
195
|
+
readOnly />
|
|
182
196
|
</CardContent>
|
|
183
197
|
<CardFooter muted>
|
|
184
198
|
<button
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { CodeMirror, type HttpHeader, httpHeaders } from '@scalar/api-client'
|
|
3
2
|
import { useClipboard } from '@scalar/use-clipboard'
|
|
3
|
+
import { CodeMirror } from '@scalar/use-codemirror'
|
|
4
4
|
import { computed, ref } from 'vue'
|
|
5
5
|
|
|
6
|
-
import type { TransformedOperation } from '
|
|
6
|
+
import type { TransformedOperation } from '../../../../types'
|
|
7
7
|
import {
|
|
8
8
|
Card,
|
|
9
9
|
CardContent,
|
|
10
10
|
CardFooter,
|
|
11
11
|
CardTab,
|
|
12
12
|
CardTabHeader,
|
|
13
|
-
} from '
|
|
14
|
-
import { Icon } from '
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
SimpleHeader,
|
|
18
|
-
SimpleRow,
|
|
19
|
-
SimpleTable,
|
|
20
|
-
} from '../../SimpleTable'
|
|
13
|
+
} from '../../../Card'
|
|
14
|
+
import { Icon } from '../../../Icon'
|
|
15
|
+
import Headers from './Headers.vue'
|
|
16
|
+
import SelectExample from './SelectExample.vue'
|
|
21
17
|
|
|
22
18
|
const props = defineProps<{ operation: TransformedOperation }>()
|
|
23
19
|
|
|
@@ -45,29 +41,24 @@ const currentResponse = computed(() => {
|
|
|
45
41
|
return props.operation.responses?.[currentStatusCode]
|
|
46
42
|
})
|
|
47
43
|
|
|
48
|
-
const
|
|
49
|
-
|
|
44
|
+
const currentResponseExamples = computed(() => {
|
|
45
|
+
const examples =
|
|
46
|
+
currentResponse.value?.content?.['application/json']?.examples
|
|
47
|
+
|
|
48
|
+
if (examples) {
|
|
49
|
+
return JSON.parse(examples)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return false
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const currentResponseExample = computed(() => {
|
|
56
|
+
return currentResponse.value?.content?.['application/json']?.example
|
|
50
57
|
})
|
|
51
58
|
|
|
52
59
|
const changeTab = (index: number) => {
|
|
53
60
|
selectedResponseIndex.value = index
|
|
54
61
|
}
|
|
55
|
-
|
|
56
|
-
const getDocumentationUrlForHttpHeader = (headerName: string) => {
|
|
57
|
-
return httpHeaders.find((header: HttpHeader) => {
|
|
58
|
-
return header.name.toLowerCase() === headerName.toLowerCase()
|
|
59
|
-
})?.url
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Make the first letter and all letters after a - uppercase
|
|
63
|
-
const formatHeaderName = (headerName: string) => {
|
|
64
|
-
return headerName
|
|
65
|
-
.split('-')
|
|
66
|
-
.map((word) => {
|
|
67
|
-
return word.charAt(0).toUpperCase() + word.slice(1)
|
|
68
|
-
})
|
|
69
|
-
.join('-')
|
|
70
|
-
}
|
|
71
62
|
</script>
|
|
72
63
|
<template>
|
|
73
64
|
<Card v-if="orderedStatusCodes.length">
|
|
@@ -82,10 +73,10 @@ const formatHeaderName = (headerName: string) => {
|
|
|
82
73
|
|
|
83
74
|
<template #actions>
|
|
84
75
|
<button
|
|
85
|
-
v-if="
|
|
76
|
+
v-if="currentResponseExample"
|
|
86
77
|
class="code-copy"
|
|
87
78
|
type="button"
|
|
88
|
-
@click="() => copyToClipboard(
|
|
79
|
+
@click="() => copyToClipboard(currentResponseExample)">
|
|
89
80
|
<Icon
|
|
90
81
|
src="solid/interface-copy-clipboard"
|
|
91
82
|
width="10px" />
|
|
@@ -95,35 +86,24 @@ const formatHeaderName = (headerName: string) => {
|
|
|
95
86
|
<CardContent
|
|
96
87
|
v-if="currentResponse.headers"
|
|
97
88
|
muted>
|
|
98
|
-
<
|
|
99
|
-
<SimpleRow>
|
|
100
|
-
<SimpleHeader>Header</SimpleHeader>
|
|
101
|
-
<SimpleHeader>Description</SimpleHeader>
|
|
102
|
-
</SimpleRow>
|
|
103
|
-
<SimpleRow
|
|
104
|
-
v-for="(data, header) in currentResponse.headers"
|
|
105
|
-
:key="header">
|
|
106
|
-
<SimpleCell
|
|
107
|
-
:href="getDocumentationUrlForHttpHeader(header)"
|
|
108
|
-
:strong="true"
|
|
109
|
-
:wrap="false">
|
|
110
|
-
{{ formatHeaderName(header) }}
|
|
111
|
-
</SimpleCell>
|
|
112
|
-
<SimpleCell>{{ data.description }}</SimpleCell>
|
|
113
|
-
</SimpleRow>
|
|
114
|
-
</SimpleTable>
|
|
89
|
+
<Headers :headers="currentResponse.headers" />
|
|
115
90
|
</CardContent>
|
|
116
91
|
<CardContent muted>
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
92
|
+
<template v-if="currentResponseExamples">
|
|
93
|
+
<SelectExample :examples="currentResponseExamples" />
|
|
94
|
+
</template>
|
|
95
|
+
<template v-else>
|
|
96
|
+
<CodeMirror
|
|
97
|
+
v-show="currentResponseExample"
|
|
98
|
+
:content="currentResponseExample"
|
|
99
|
+
:languages="['json']"
|
|
100
|
+
readOnly />
|
|
101
|
+
<div
|
|
102
|
+
v-if="!currentResponseExample"
|
|
103
|
+
class="scalar-api-reference__empty-state">
|
|
104
|
+
No Body
|
|
105
|
+
</div>
|
|
106
|
+
</template>
|
|
127
107
|
</CardContent>
|
|
128
108
|
<CardFooter
|
|
129
109
|
v-if="currentResponse?.description"
|
|
@@ -165,4 +145,24 @@ const formatHeaderName = (headerName: string) => {
|
|
|
165
145
|
padding: 20px;
|
|
166
146
|
color: var(--theme-color-2);
|
|
167
147
|
}
|
|
148
|
+
|
|
149
|
+
.schema-type {
|
|
150
|
+
font-size: var(--theme-micro);
|
|
151
|
+
color: var(--theme-color-2);
|
|
152
|
+
font-weight: var(--theme-semibold);
|
|
153
|
+
background: var(--theme-background-3);
|
|
154
|
+
padding: 2px 4px;
|
|
155
|
+
border-radius: 4px;
|
|
156
|
+
margin-right: 4px;
|
|
157
|
+
}
|
|
158
|
+
.schema-example {
|
|
159
|
+
font-size: var(--theme-micro);
|
|
160
|
+
color: var(--theme-color-2);
|
|
161
|
+
font-weight: var(--theme-semibold);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.example-response-tab {
|
|
165
|
+
display: block;
|
|
166
|
+
margin: 6px;
|
|
167
|
+
}
|
|
168
168
|
</style>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { type HttpHeader, httpHeaders } from '@scalar/api-client'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
|
|
5
|
+
import { mapFromObject } from '../../../../helpers'
|
|
6
|
+
import type { ExampleResponseHeaders } from '../../../../types'
|
|
7
|
+
import {
|
|
8
|
+
SimpleCell,
|
|
9
|
+
SimpleHeader,
|
|
10
|
+
SimpleRow,
|
|
11
|
+
SimpleTable,
|
|
12
|
+
} from '../../../SimpleTable'
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
headers: ExampleResponseHeaders
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const getDocumentationUrlForHttpHeader = (headerName: string) => {
|
|
19
|
+
return httpHeaders.find((header: HttpHeader) => {
|
|
20
|
+
return header.name.toLowerCase() === headerName.toLowerCase()
|
|
21
|
+
})?.url
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Make the first letter and all letters after a - uppercase
|
|
25
|
+
const formatHeaderName = (headerName: string) => {
|
|
26
|
+
return headerName
|
|
27
|
+
.split('-')
|
|
28
|
+
.map((word) => {
|
|
29
|
+
return word.charAt(0).toUpperCase() + word.slice(1)
|
|
30
|
+
})
|
|
31
|
+
.join('-')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const headersHaveDescription = computed(() => {
|
|
35
|
+
const headers = mapFromObject(props.headers)
|
|
36
|
+
|
|
37
|
+
return headers.some((header: any) => {
|
|
38
|
+
return header.value.description
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const headersHaveSchema = computed(() => {
|
|
43
|
+
const headers = mapFromObject(props.headers)
|
|
44
|
+
|
|
45
|
+
return headers.some((header: any) => {
|
|
46
|
+
return header.value.schema
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<SimpleTable>
|
|
53
|
+
<SimpleRow>
|
|
54
|
+
<SimpleHeader>Header</SimpleHeader>
|
|
55
|
+
<SimpleHeader v-if="headersHaveDescription">Description</SimpleHeader>
|
|
56
|
+
<SimpleHeader v-if="headersHaveSchema">Value</SimpleHeader>
|
|
57
|
+
</SimpleRow>
|
|
58
|
+
<SimpleRow
|
|
59
|
+
v-for="(data, header) in headers"
|
|
60
|
+
:key="header">
|
|
61
|
+
<SimpleCell
|
|
62
|
+
:href="getDocumentationUrlForHttpHeader(header)"
|
|
63
|
+
:strong="true"
|
|
64
|
+
:wrap="false">
|
|
65
|
+
{{ formatHeaderName(header) }}
|
|
66
|
+
</SimpleCell>
|
|
67
|
+
<SimpleCell v-if="headersHaveDescription">{{ data }}</SimpleCell>
|
|
68
|
+
<SimpleCell v-if="headersHaveSchema">
|
|
69
|
+
<span v-if="data.schema.example">
|
|
70
|
+
<code class="schema-example">{{ data.schema.example }}</code>
|
|
71
|
+
</span>
|
|
72
|
+
<code
|
|
73
|
+
v-else-if="data.schema.type"
|
|
74
|
+
class="schema-type">
|
|
75
|
+
{{ data.schema.type }}
|
|
76
|
+
</code>
|
|
77
|
+
<code v-else>
|
|
78
|
+
{{ data.schema }}
|
|
79
|
+
</code>
|
|
80
|
+
</SimpleCell>
|
|
81
|
+
</SimpleRow>
|
|
82
|
+
</SimpleTable>
|
|
83
|
+
</template>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
Listbox,
|
|
4
|
+
ListboxButton,
|
|
5
|
+
ListboxOption,
|
|
6
|
+
ListboxOptions,
|
|
7
|
+
} from '@headlessui/vue'
|
|
8
|
+
import { CodeMirror } from '@scalar/use-codemirror'
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
import { mapFromObject } from '../../../../helpers'
|
|
12
|
+
import { Icon } from '../../../Icon'
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{ examples: Record<string, any> }>()
|
|
15
|
+
|
|
16
|
+
const examples = mapFromObject(props.examples)
|
|
17
|
+
const selectedExample = ref(examples[0])
|
|
18
|
+
</script>
|
|
19
|
+
<template>
|
|
20
|
+
<div class="example-switcher">
|
|
21
|
+
<label
|
|
22
|
+
class="listbox-label"
|
|
23
|
+
for="listbox-button">
|
|
24
|
+
Select Example
|
|
25
|
+
</label>
|
|
26
|
+
<Listbox v-model="selectedExample">
|
|
27
|
+
<ListboxButton
|
|
28
|
+
id="listbox-button"
|
|
29
|
+
class="listbox-button">
|
|
30
|
+
<div class="listbox-button-content">
|
|
31
|
+
<div class="listbox-button-label">
|
|
32
|
+
{{ selectedExample.value.summary ?? selectedExample.key }}
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
<Icon
|
|
36
|
+
class="icon"
|
|
37
|
+
src="line/arrow-chevron-down" />
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</ListboxButton>
|
|
41
|
+
|
|
42
|
+
<ListboxOptions class="listbox-options">
|
|
43
|
+
<ListboxOption
|
|
44
|
+
v-for="example in examples"
|
|
45
|
+
:key="example.key"
|
|
46
|
+
class="listbox-option"
|
|
47
|
+
:value="example">
|
|
48
|
+
{{ example.value.summary ?? example.key }}
|
|
49
|
+
</ListboxOption>
|
|
50
|
+
</ListboxOptions>
|
|
51
|
+
</Listbox>
|
|
52
|
+
<CodeMirror
|
|
53
|
+
:content="JSON.stringify(selectedExample.value.value, null, 2)"
|
|
54
|
+
:languages="['json']"
|
|
55
|
+
readOnly />
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<style scoped>
|
|
60
|
+
.example-switcher {
|
|
61
|
+
display: flex;
|
|
62
|
+
gap: 6px;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.listbox-label {
|
|
67
|
+
font-size: var(--theme-mini);
|
|
68
|
+
font-weight: var(--theme-semibold);
|
|
69
|
+
margin: 0 4px;
|
|
70
|
+
color: var(--theme-color-2);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.listbox-button {
|
|
74
|
+
border: 1px solid var(--theme-border-color);
|
|
75
|
+
background: var(--theme-background-1);
|
|
76
|
+
padding: 6px 12px;
|
|
77
|
+
border-radius: var(--theme-radius);
|
|
78
|
+
text-align: left;
|
|
79
|
+
display: block;
|
|
80
|
+
font-size: var(--theme-mini);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.listbox-button-content {
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
justify-content: space-between;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.listbox-button-label {
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
text-overflow: ellipsis;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.listbox-options {
|
|
96
|
+
background: var(--theme-background-1);
|
|
97
|
+
padding: 6px 6px;
|
|
98
|
+
border-radius: var(--theme-radius-lg);
|
|
99
|
+
margin-top: 4px;
|
|
100
|
+
box-shadow: var(--theme-shadow-2);
|
|
101
|
+
position: absolute;
|
|
102
|
+
margin: 0 1px;
|
|
103
|
+
transform: translateY(-50%);
|
|
104
|
+
z-index: 100;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.listbox-option {
|
|
108
|
+
padding: 6px 12px;
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
color: var(--theme-color-1);
|
|
111
|
+
border-radius: var(--theme-radius);
|
|
112
|
+
margin: 2px 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.listbox-option[data-headlessui-state='selected'] {
|
|
116
|
+
background: var(--theme-background-2);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.listbox-option:hover {
|
|
120
|
+
background: var(--theme-background-2);
|
|
121
|
+
color: var(--theme-color-2);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.icon {
|
|
125
|
+
width: 13px;
|
|
126
|
+
height: 13px;
|
|
127
|
+
color: var(--theme-color-3);
|
|
128
|
+
}
|
|
129
|
+
</style>
|