first commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1 @@
|
||||
import './bootstrap';
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
@@ -0,0 +1,3 @@
|
||||
@if($authenticated)@component('scribe::components.badges.base', ['colour' => "darkred", 'text' => 'requires authentication'])
|
||||
@endcomponent
|
||||
@endif
|
||||
@@ -0,0 +1 @@
|
||||
<small class="badge badge-{{ $colour }}">{{ $text }}</small>
|
||||
@@ -0,0 +1,5 @@
|
||||
@component('scribe::components.badges.base', [
|
||||
'colour' => \Knuckles\Scribe\Tools\WritingUtils::$httpMethodToCssColour[$method],
|
||||
'text' => $method,
|
||||
])
|
||||
@endcomponent
|
||||
@@ -0,0 +1,75 @@
|
||||
@php
|
||||
$html ??= []; $class = $html['class'] ?? null;
|
||||
@endphp
|
||||
<b style="line-height: 2;"><code>{{ $name }}</code></b>
|
||||
@if($type)<small>{{ $type }}</small>@endif
|
||||
@if($isInput && !$required)<i>optional</i>@endif
|
||||
@if($isInput && empty($hasChildren))
|
||||
@php
|
||||
$isList = Str::endsWith($type, '[]');
|
||||
$fullName = str_replace('[]', '.0', $fullName ?? $name);
|
||||
$baseType = $isList ? substr($type, 0, -2) : $type;
|
||||
// Ignore the first '[]': the frontend will take care of it
|
||||
while (\Str::endsWith($baseType, '[]')) {
|
||||
$fullName .= '.0';
|
||||
$baseType = substr($baseType, 0, -2);
|
||||
}
|
||||
// When the body is an array, the item names will be ".0.thing"
|
||||
$fullName = ltrim($fullName, '.');
|
||||
$inputType = match($baseType) {
|
||||
'number', 'integer' => 'number',
|
||||
'file' => 'file',
|
||||
default => 'text',
|
||||
};
|
||||
@endphp
|
||||
@if($type === 'boolean')
|
||||
<label data-endpoint="{{ $endpointId }}" style="display: none">
|
||||
<input type="radio" name="{{ $fullName }}"
|
||||
value="{{$component === 'body' ? 'true' : 1}}"
|
||||
data-endpoint="{{ $endpointId }}"
|
||||
data-component="{{ $component }}" @if($class)class="{{ $class }}"@endif
|
||||
>
|
||||
<code>true</code>
|
||||
</label>
|
||||
<label data-endpoint="{{ $endpointId }}" style="display: none">
|
||||
<input type="radio" name="{{ $fullName }}"
|
||||
value="{{$component === 'body' ? 'false' : 0}}"
|
||||
data-endpoint="{{ $endpointId }}"
|
||||
data-component="{{ $component }}" @if($class)class="{{ $class }}"@endif
|
||||
>
|
||||
<code>false</code>
|
||||
</label>
|
||||
@elseif($isList)
|
||||
<input type="{{ $inputType }}" style="display: none"
|
||||
@if($inputType === 'number')step="any"@endif
|
||||
name="{{ $fullName."[0]" }}" @if($class)class="{{ $class }}"@endif
|
||||
data-endpoint="{{ $endpointId }}"
|
||||
data-component="{{ $component }}">
|
||||
<input type="{{ $inputType }}" style="display: none"
|
||||
name="{{ $fullName."[1]" }}" @if($class)class="{{ $class }}"@endif
|
||||
data-endpoint="{{ $endpointId }}"
|
||||
data-component="{{ $component }}">
|
||||
@else
|
||||
<input type="{{ $inputType }}" style="display: none"
|
||||
@if($inputType === 'number')step="any"@endif
|
||||
name="{{ $fullName }}" @if($class)class="{{ $class }}"@endif
|
||||
data-endpoint="{{ $endpointId }}"
|
||||
value="{!! (isset($example) && (is_string($example) || is_numeric($example))) ? $example : '' !!}"
|
||||
data-component="{{ $component }}">
|
||||
@endif
|
||||
@endif
|
||||
<br>
|
||||
@php
|
||||
if($example !== null && $example !== '' && !is_array($example)) {
|
||||
$exampleAsString = $example;
|
||||
if (is_bool($example)) {
|
||||
$exampleAsString = $example ? "true" : "false";
|
||||
}
|
||||
$description .= " Example: `$exampleAsString`";
|
||||
}
|
||||
@endphp
|
||||
{!! Parsedown::instance()->text(trim($description)) !!}
|
||||
@if(!empty($enumValues))
|
||||
Must be one of:
|
||||
<ul style="list-style-type: square;">{!! implode(" ", array_map(fn($val) => "<li><code>$val</code></li>", $enumValues)) !!}</ul>
|
||||
@endif
|
||||
@@ -0,0 +1,101 @@
|
||||
@php
|
||||
$isInput ??= true;
|
||||
$level ??= 0;
|
||||
@endphp
|
||||
@foreach($fields as $name => $field)
|
||||
@if($name === '[]')
|
||||
@php
|
||||
$description = "The request body is an array (<code>{$field['type']}</code>`)";
|
||||
$description .= !empty($field['description']) ? ", representing ".lcfirst($field['description'])."." : '.';
|
||||
if(count($field['__fields'])) $description .= " Each item has the following properties:";
|
||||
@endphp
|
||||
{!! Parsedown::instance()->text($description) !!}
|
||||
|
||||
@foreach($field['__fields'] as $subfieldName => $subfield)
|
||||
@if(!empty($subfield['__fields']))
|
||||
<x-scribe::nested-fields
|
||||
:fields="[$subfieldName => $subfield]" :endpointId="$endpointId" :isInput="$isInput" :level="$level + 2"
|
||||
/>
|
||||
@else
|
||||
<div style="margin-left: {{ ($level + 2) * 14 }}px; clear: unset;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $subfieldName,
|
||||
'fullName' => $subfield['name'],
|
||||
'type' => $subfield['type'] ?? 'string',
|
||||
'required' => $subfield['required'] ?? false,
|
||||
'description' => $subfield['description'] ?? '',
|
||||
'example' => $subfield['example'] ?? '',
|
||||
'enumValues' => $subfield['enumValues'] ?? null,
|
||||
'endpointId' => $endpointId,
|
||||
'hasChildren' => false,
|
||||
'component' => 'body',
|
||||
'isInput' => $isInput,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@elseif(!empty($field['__fields']))
|
||||
<div style="@if($level) margin-left: {{ $level * 14 }}px;@else padding-left: 28px; @endif clear: unset;">
|
||||
<details>
|
||||
<summary style="padding-bottom: 10px;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $name,
|
||||
'fullName' => $field['name'],
|
||||
'type' => $field['type'] ?? 'string',
|
||||
'required' => $field['required'] ?? false,
|
||||
'description' => $field['description'] ?? '',
|
||||
'example' => $field['example'] ?? '',
|
||||
'enumValues' => $field['enumValues'] ?? null,
|
||||
'endpointId' => $endpointId,
|
||||
'hasChildren' => true,
|
||||
'component' => 'body',
|
||||
'isInput' => $isInput,
|
||||
])
|
||||
@endcomponent
|
||||
</summary>
|
||||
@foreach($field['__fields'] as $subfieldName => $subfield)
|
||||
@if(!empty($subfield['__fields']))
|
||||
<x-scribe::nested-fields
|
||||
:fields="[$subfieldName => $subfield]" :endpointId="$endpointId" :isInput="$isInput" :level="$level + 1"
|
||||
/>
|
||||
@else
|
||||
<div style="margin-left: {{ ($level + 1) * 14 }}px; clear: unset;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $subfieldName,
|
||||
'fullName' => $subfield['name'],
|
||||
'type' => $subfield['type'] ?? 'string',
|
||||
'required' => $subfield['required'] ?? false,
|
||||
'description' => $subfield['description'] ?? '',
|
||||
'example' => $subfield['example'] ?? '',
|
||||
'enumValues' => $subfield['enumValues'] ?? null,
|
||||
'endpointId' => $endpointId,
|
||||
'hasChildren' => false,
|
||||
'component' => 'body',
|
||||
'isInput' => $isInput,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</details>
|
||||
</div>
|
||||
@else
|
||||
<div style="@if($level) margin-left: {{ ($level + 1) * 14 }}px;@else padding-left: 28px; @endif clear: unset;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $name,
|
||||
'fullName' => $field['name'],
|
||||
'type' => $field['type'] ?? 'string',
|
||||
'required' => $field['required'] ?? false,
|
||||
'description' => $field['description'] ?? '',
|
||||
'example' => $field['example'] ?? '',
|
||||
'enumValues' => $field['enumValues'] ?? null,
|
||||
'endpointId' => $endpointId,
|
||||
'hasChildren' => false,
|
||||
'component' => 'body',
|
||||
'isInput' => $isInput,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@@ -0,0 +1,34 @@
|
||||
<!-- See https://github.com/stoplightio/elements/blob/main/docs/getting-started/elements/elements-options.md for config -->
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>{!! $metadata['title'] !!}</title>
|
||||
<!-- Embed elements Elements via Web Component -->
|
||||
<script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css">
|
||||
<style>
|
||||
body {
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<elements-api
|
||||
@foreach($htmlAttributes as $attribute => $value)
|
||||
{{-- Attributes specified first override later ones --}}
|
||||
{!! $attribute !!}="{!! $value !!}"
|
||||
@endforeach
|
||||
apiDescriptionUrl="{!! $metadata['openapi_spec_url'] !!}"
|
||||
router="hash"
|
||||
layout="sidebar"
|
||||
hideTryIt="{!! ($tryItOut['enabled'] ?? true) ? '' : 'true'!!}"
|
||||
@if(!empty($metadata['logo']))
|
||||
logo="{!! $metadata['logo'] !!}"
|
||||
@endif
|
||||
/>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!-- See https://rapidocweb.com/api.html for options -->
|
||||
<!doctype html> <!-- Important: must specify -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"> <!-- Important: rapi-doc uses utf8 characters -->
|
||||
<script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<rapi-doc
|
||||
@foreach($htmlAttributes as $attribute => $value)
|
||||
{{-- Attributes specified first override later ones --}}
|
||||
{!! $attribute !!}="{!! $value !!}"
|
||||
@endforeach
|
||||
spec-url="{!! $metadata['openapi_spec_url'] !!}"
|
||||
render-style="read"
|
||||
allow-try="{!! ($tryItOut['enabled'] ?? true) ? 'true' : 'false'!!}"
|
||||
>
|
||||
@if($metadata['logo'])
|
||||
<img slot="logo" src="{!! $metadata['logo'] !!}"/>
|
||||
@endif
|
||||
</rapi-doc>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{!! $metadata['title'] !!}</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1"/>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script
|
||||
id="api-reference"
|
||||
@foreach($htmlAttributes as $attribute => $value)
|
||||
{{-- Attributes specified first override later ones --}}
|
||||
{!! $attribute !!}="{!! $value !!}"
|
||||
@endforeach
|
||||
data-url="{!! $metadata['openapi_spec_url'] !!}">
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\Utils as u;
|
||||
@endphp
|
||||
# {{ u::trans("scribe::headings.auth") }}
|
||||
|
||||
@if(!$isAuthed)
|
||||
{!! u::trans("scribe::auth.none") !!}
|
||||
@else
|
||||
{!! $authDescription !!}
|
||||
|
||||
{!! $extraAuthInfo !!}
|
||||
@endif
|
||||
@@ -0,0 +1,13 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\Utils as u;
|
||||
@endphp
|
||||
# {{ u::trans("scribe::headings.introduction") }}
|
||||
|
||||
{!! $description !!}
|
||||
|
||||
<aside>
|
||||
<strong>{{ u::trans("scribe::labels.base_url") }}</strong>: <code>{!! $baseUrl !!}</code>
|
||||
</aside>
|
||||
|
||||
{!! $introText !!}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\WritingUtils as u;
|
||||
/** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
```bash
|
||||
curl --request {{$endpoint->httpMethods[0]}} \
|
||||
{{$endpoint->httpMethods[0] == 'GET' ? '--get ' : ''}}"{!! rtrim($baseUrl, '/') !!}/{{ ltrim($endpoint->boundUri, '/') }}@if(count($endpoint->cleanQueryParameters))?{!! u::printQueryParamsAsString($endpoint->cleanQueryParameters) !!}@endif"@if(count($endpoint->headers)) \
|
||||
@foreach($endpoint->headers as $header => $value)
|
||||
--header "{{$header}}: {{ addslashes($value) }}"@if(! ($loop->last) || ($loop->last && count($endpoint->bodyParameters))) \
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters)))
|
||||
@foreach($endpoint->cleanBodyParameters as $parameter => $value)
|
||||
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue)
|
||||
--form "{!! "$key=".$actualValue !!}"@if(!($loop->parent->last) || count($endpoint->fileParameters))\
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
@foreach($endpoint->fileParameters as $parameter => $value)
|
||||
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $file)
|
||||
--form "{!! "$key=@".$file->path() !!}" @if(!($loop->parent->last))\
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
@elseif(count($endpoint->cleanBodyParameters))
|
||||
@if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded')
|
||||
--data "{!! http_build_query($endpoint->cleanBodyParameters, '', '&') !!}"
|
||||
@else
|
||||
--data "{!! addslashes(json_encode($endpoint->cleanBodyParameters, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)) !!}"
|
||||
@endif
|
||||
@endif
|
||||
|
||||
```
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\WritingUtils as u;
|
||||
/** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
```javascript
|
||||
const url = new URL(
|
||||
"{!! rtrim($baseUrl, '/') !!}/{{ ltrim($endpoint->boundUri, '/') }}"
|
||||
);
|
||||
@if(count($endpoint->cleanQueryParameters))
|
||||
|
||||
const params = {!! u::printQueryParamsAsKeyValue($endpoint->cleanQueryParameters, "\"", ":", 4, "{}") !!};
|
||||
Object.keys(params)
|
||||
.forEach(key => url.searchParams.append(key, params[key]));
|
||||
@endif
|
||||
|
||||
@if(!empty($endpoint->headers))
|
||||
const headers = {
|
||||
@foreach($endpoint->headers as $header => $value)
|
||||
"{{$header}}": "{{$value}}",
|
||||
@endforeach
|
||||
@empty($endpoint->headers['Accept'])
|
||||
"Accept": "application/json",
|
||||
@endempty
|
||||
};
|
||||
@endif
|
||||
|
||||
@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters)))
|
||||
const body = new FormData();
|
||||
@foreach($endpoint->cleanBodyParameters as $parameter => $value)
|
||||
@foreach( u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue)
|
||||
body.append('{!! $key !!}', '{!! $actualValue !!}');
|
||||
@endforeach
|
||||
@endforeach
|
||||
@foreach($endpoint->fileParameters as $parameter => $value)
|
||||
@foreach( u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $file)
|
||||
body.append('{!! $key !!}', document.querySelector('input[name="{!! $key !!}"]').files[0]);
|
||||
@endforeach
|
||||
@endforeach
|
||||
@elseif(count($endpoint->cleanBodyParameters))
|
||||
@if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded')
|
||||
let body = "{!! http_build_query($endpoint->cleanBodyParameters, '', '&') !!}";
|
||||
@else
|
||||
let body = {!! json_encode($endpoint->cleanBodyParameters, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) !!};
|
||||
@endif
|
||||
@endif
|
||||
|
||||
fetch(url, {
|
||||
method: "{{$endpoint->httpMethods[0]}}",
|
||||
@if(count($endpoint->headers))
|
||||
headers,
|
||||
@endif
|
||||
@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters)))
|
||||
body,
|
||||
@elseif(count($endpoint->cleanBodyParameters))
|
||||
@if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded')
|
||||
body,
|
||||
@else
|
||||
body: JSON.stringify(body),
|
||||
@endif
|
||||
@endif
|
||||
}).then(response => response.json());
|
||||
```
|
||||
@@ -0,0 +1,51 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\WritingUtils as u;
|
||||
/** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
```php
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$url = '{!! rtrim($baseUrl, '/') . '/' . ltrim($endpoint->boundUri, '/') !!}';
|
||||
@if($endpoint->hasHeadersOrQueryOrBodyParams())
|
||||
$response = $client->{{ strtolower($endpoint->httpMethods[0]) }}(
|
||||
$url,
|
||||
[
|
||||
@if(!empty($endpoint->headers))
|
||||
'headers' => {!! u::printPhpValue($endpoint->headers, 8) !!},
|
||||
@endif
|
||||
@if(!empty($endpoint->cleanQueryParameters))
|
||||
'query' => {!! u::printQueryParamsAsKeyValue($endpoint->cleanQueryParameters, "'", " =>", 12, "[]", 8) !!},
|
||||
@endif
|
||||
@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && !empty($endpoint->cleanBodyParameters)))
|
||||
'multipart' => [
|
||||
@foreach($endpoint->cleanBodyParameters as $parameter => $value)
|
||||
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue)
|
||||
[
|
||||
'name' => '{!! $key !!}',
|
||||
'contents' => '{!! $actualValue !!}'
|
||||
],
|
||||
@endforeach
|
||||
@endforeach
|
||||
@foreach($endpoint->fileParameters as $parameter => $value)
|
||||
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $file)
|
||||
[
|
||||
'name' => '{!! $key !!}',
|
||||
'contents' => fopen('{!! $file->path() !!}', 'r')
|
||||
],
|
||||
@endforeach
|
||||
@endforeach
|
||||
],
|
||||
@elseif(count($endpoint->cleanBodyParameters))
|
||||
@if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded')
|
||||
'form_params' => {!! u::printPhpValue($endpoint->cleanBodyParameters, 8) !!},
|
||||
@else
|
||||
'json' => {!! u::printPhpValue($endpoint->cleanBodyParameters, 8) !!},
|
||||
@endif
|
||||
@endif
|
||||
]
|
||||
);
|
||||
@else
|
||||
$response = $client->{{ strtolower($endpoint->httpMethods[0]) }}($url);
|
||||
@endif
|
||||
$body = $response->getBody();
|
||||
print_r(json_decode((string) $body));
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\WritingUtils as u;
|
||||
/** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
```python
|
||||
import requests
|
||||
import json
|
||||
|
||||
url = '{!! rtrim($baseUrl, '/') !!}/{{ $endpoint->boundUri }}'
|
||||
@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters)))
|
||||
files = {
|
||||
@foreach($endpoint->cleanBodyParameters as $parameter => $value)
|
||||
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue)
|
||||
'{!! $key !!}': (None, '{!! $actualValue !!}')@if(!($loop->parent->last) || count($endpoint->fileParameters)),
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
@foreach($endpoint->fileParameters as $parameter => $value)
|
||||
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $file)
|
||||
'{!! $key !!}': open('{!! $file->path() !!}', 'rb')@if(!($loop->parent->last)),
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
}
|
||||
@endif
|
||||
@if(count($endpoint->cleanBodyParameters))
|
||||
payload = {!! json_encode($endpoint->cleanBodyParameters, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) !!}
|
||||
@endif
|
||||
@if(count($endpoint->cleanQueryParameters))
|
||||
params = {!! u::printQueryParamsAsKeyValue($endpoint->cleanQueryParameters, "'", ":", 2, "{}") !!}
|
||||
@endif
|
||||
@if(!empty($endpoint->headers))
|
||||
headers = {
|
||||
@foreach($endpoint->headers as $header => $value)
|
||||
'{{$header}}': '{{$value}}'@if(!($loop->last)),
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
}
|
||||
|
||||
@endif
|
||||
@php
|
||||
$optionalArguments = [];
|
||||
if (count($endpoint->headers)) $optionalArguments[] = "headers=headers";
|
||||
if (count($endpoint->fileParameters)) $optionalArguments[] = "files=files";
|
||||
if (count($endpoint->cleanBodyParameters) && $endpoint->headers['Content-Type'] != 'multipart/form-data') $optionalArguments[] = (count($endpoint->fileParameters) || $endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded' ? "data=payload" : "json=payload");
|
||||
if (count($endpoint->cleanQueryParameters)) $optionalArguments[] = "params=params";
|
||||
$optionalArguments = implode(', ',$optionalArguments);
|
||||
@endphp
|
||||
response = requests.request('{{$endpoint->httpMethods[0]}}', url, {{ $optionalArguments }})
|
||||
response.json()
|
||||
```
|
||||
@@ -0,0 +1,185 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\Utils as u;
|
||||
/** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
|
||||
<h2 id="{!! $endpoint->fullSlug() !!}">{{ $endpoint->name() }}</h2>
|
||||
|
||||
<p>
|
||||
@component('scribe::components.badges.auth', ['authenticated' => $endpoint->isAuthed()])
|
||||
@endcomponent
|
||||
</p>
|
||||
|
||||
{!! Parsedown::instance()->text($endpoint->metadata->description ?: '') !!}
|
||||
|
||||
<span id="example-requests-{!! $endpoint->endpointId() !!}">
|
||||
<blockquote>{{ u::trans("scribe::endpoint.example_request") }}:</blockquote>
|
||||
|
||||
@foreach($metadata['example_languages'] as $language)
|
||||
|
||||
<div class="{{ $language }}-example">
|
||||
@include("scribe::partials.example-requests.$language")
|
||||
</div>
|
||||
|
||||
@endforeach
|
||||
</span>
|
||||
|
||||
<span id="example-responses-{!! $endpoint->endpointId() !!}">
|
||||
@if($endpoint->isGet() || $endpoint->hasResponses())
|
||||
@foreach($endpoint->responses as $response)
|
||||
<blockquote>
|
||||
<p>{{ u::trans("scribe::endpoint.example_response") }} ({{ $response->fullDescription() }}):</p>
|
||||
</blockquote>
|
||||
@if(count($response->headers))
|
||||
<details class="annotation">
|
||||
<summary style="cursor: pointer;">
|
||||
<small onclick="textContent = parentElement.parentElement.open ? 'Show headers' : 'Hide headers'">Show headers</small>
|
||||
</summary>
|
||||
<pre><code class="language-http">@foreach($response->headers as $header => $value)
|
||||
{{ $header }}: {{ is_array($value) ? implode('; ', $value) : $value }}
|
||||
@endforeach </code></pre></details> @endif
|
||||
<pre>
|
||||
@if(is_string($response->content) && Str::startsWith($response->content, "<<binary>>"))
|
||||
<code>{!! u::trans("scribe::endpoint.responses.binary") !!} - {{ htmlentities(str_replace("<<binary>>", "", $response->content)) }}</code>
|
||||
@elseif($response->status == 204)
|
||||
<code>{!! u::trans("scribe::endpoint.responses.empty") !!}</code>
|
||||
@else
|
||||
@php($parsed = json_decode($response->content))
|
||||
{{-- If response is a JSON string, prettify it. Otherwise, just print it --}}
|
||||
<code class="language-json" style="max-height: 300px;">{!! htmlentities($parsed != null ? json_encode($parsed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : $response->content) !!}</code>
|
||||
@endif </pre>
|
||||
@endforeach
|
||||
@endif
|
||||
</span>
|
||||
<span id="execution-results-{{ $endpoint->endpointId() }}" hidden>
|
||||
<blockquote>{{ u::trans("scribe::try_it_out.received_response") }}<span
|
||||
id="execution-response-status-{{ $endpoint->endpointId() }}"></span>:
|
||||
</blockquote>
|
||||
<pre class="json"><code id="execution-response-content-{{ $endpoint->endpointId() }}"
|
||||
data-empty-response-text="<{{ u::trans("scribe::endpoint.responses.empty") }}>" style="max-height: 400px;"></code></pre>
|
||||
</span>
|
||||
<span id="execution-error-{{ $endpoint->endpointId() }}" hidden>
|
||||
<blockquote>{{ u::trans("scribe::try_it_out.request_failed") }}:</blockquote>
|
||||
<pre><code id="execution-error-message-{{ $endpoint->endpointId() }}">{{ "\n\n".u::trans("scribe::try_it_out.error_help") }}</code></pre>
|
||||
</span>
|
||||
<form id="form-{{ $endpoint->endpointId() }}" data-method="{{ $endpoint->httpMethods[0] }}"
|
||||
data-path="{{ $endpoint->uri }}"
|
||||
data-authed="{{ $endpoint->isAuthed() ? 1 : 0 }}"
|
||||
data-hasfiles="{{ $endpoint->hasFiles() ? 1 : 0 }}"
|
||||
data-isarraybody="{{ $endpoint->isArrayBody() ? 1 : 0 }}"
|
||||
autocomplete="off"
|
||||
onsubmit="event.preventDefault(); executeTryOut('{{ $endpoint->endpointId() }}', this);">
|
||||
<h3>
|
||||
{{ u::trans("scribe::endpoint.request") }}
|
||||
@if($metadata['try_it_out']['enabled'] ?? false)
|
||||
<button type="button"
|
||||
style="background-color: #8fbcd4; padding: 5px 10px; border-radius: 5px; border-width: thin;"
|
||||
id="btn-tryout-{{ $endpoint->endpointId() }}"
|
||||
onclick="tryItOut('{{ $endpoint->endpointId() }}');">{{ u::trans("scribe::try_it_out.open") }}
|
||||
</button>
|
||||
<button type="button"
|
||||
style="background-color: #c97a7e; padding: 5px 10px; border-radius: 5px; border-width: thin;"
|
||||
id="btn-canceltryout-{{ $endpoint->endpointId() }}"
|
||||
onclick="cancelTryOut('{{ $endpoint->endpointId() }}');" hidden>{{ u::trans("scribe::try_it_out.cancel") }}
|
||||
</button>
|
||||
<button type="submit"
|
||||
style="background-color: #6ac174; padding: 5px 10px; border-radius: 5px; border-width: thin;"
|
||||
id="btn-executetryout-{{ $endpoint->endpointId() }}"
|
||||
data-initial-text="{{ u::trans("scribe::try_it_out.send") }}"
|
||||
data-loading-text="{{ u::trans("scribe::try_it_out.loading") }}"
|
||||
hidden>{{ u::trans("scribe::try_it_out.send") }}
|
||||
</button>
|
||||
@endif
|
||||
</h3>
|
||||
@foreach($endpoint->httpMethods as $method)
|
||||
<p>
|
||||
@component('scribe::components.badges.http-method', ['method' => $method])@endcomponent
|
||||
<b><code>{{$endpoint->uri}}</code></b>
|
||||
</p>
|
||||
@endforeach
|
||||
@if(count($endpoint->headers))
|
||||
<h4 class="fancy-heading-panel"><b>{{ u::trans("scribe::endpoint.headers") }}</b></h4>
|
||||
@foreach($endpoint->headers as $name => $example)
|
||||
<?php
|
||||
$htmlOptions = [];
|
||||
if ($endpoint->isAuthed() && $metadata['auth']['location'] == 'header' && $metadata['auth']['name'] == $name) {
|
||||
$htmlOptions = [ 'class' => 'auth-value', ];
|
||||
}
|
||||
?>
|
||||
<div style="padding-left: 28px; clear: unset;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $name,
|
||||
'type' => null,
|
||||
'required' => true,
|
||||
'description' => null,
|
||||
'example' => $example,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'component' => 'header',
|
||||
'isInput' => true,
|
||||
'html' => $htmlOptions,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
@if(count($endpoint->urlParameters))
|
||||
<h4 class="fancy-heading-panel"><b>{{ u::trans("scribe::endpoint.url_parameters") }}</b></h4>
|
||||
@foreach($endpoint->urlParameters as $attribute => $parameter)
|
||||
<div style="padding-left: 28px; clear: unset;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $parameter->name,
|
||||
'type' => $parameter->type ?? 'string',
|
||||
'required' => $parameter->required,
|
||||
'description' => $parameter->description,
|
||||
'example' => $parameter->example ?? '',
|
||||
'enumValues' => $parameter->enumValues,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'component' => 'url',
|
||||
'isInput' => true,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
@if(count($endpoint->queryParameters))
|
||||
<h4 class="fancy-heading-panel"><b>{{ u::trans("scribe::endpoint.query_parameters") }}</b></h4>
|
||||
@foreach($endpoint->queryParameters as $attribute => $parameter)
|
||||
<?php
|
||||
$htmlOptions = [];
|
||||
if ($endpoint->isAuthed() && $metadata['auth']['location'] == 'query' && $metadata['auth']['name'] == $attribute) {
|
||||
$htmlOptions = [ 'class' => 'auth-value', ];
|
||||
}
|
||||
?>
|
||||
<div style="padding-left: 28px; clear: unset;">
|
||||
@component('scribe::components.field-details', [
|
||||
'name' => $parameter->name,
|
||||
'type' => $parameter->type,
|
||||
'required' => $parameter->required,
|
||||
'description' => $parameter->description,
|
||||
'example' => $parameter->example ?? '',
|
||||
'enumValues' => $parameter->enumValues,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'component' => 'query',
|
||||
'isInput' => true,
|
||||
'html' => $htmlOptions,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
@if(count($endpoint->nestedBodyParameters))
|
||||
<h4 class="fancy-heading-panel"><b>{{ u::trans("scribe::endpoint.body_parameters") }}</b></h4>
|
||||
<x-scribe::nested-fields
|
||||
:fields="$endpoint->nestedBodyParameters" :endpointId="$endpoint->endpointId()"
|
||||
/>
|
||||
@endif
|
||||
</form>
|
||||
|
||||
@if(count($endpoint->responseFields))
|
||||
<h3>{{ u::trans("scribe::endpoint.response") }}</h3>
|
||||
<h4 class="fancy-heading-panel"><b>{{ u::trans("scribe::endpoint.response_fields") }}</b></h4>
|
||||
<x-scribe::nested-fields
|
||||
:fields="$endpoint->nestedResponseFields" :endpointId="$endpoint->endpointId()"
|
||||
:isInput="false"
|
||||
/>
|
||||
@endif
|
||||
@@ -0,0 +1,21 @@
|
||||
@foreach($groupedEndpoints as $group)
|
||||
<h1 id="{!! Str::slug($group['name']) !!}">{!! $group['name'] !!}</h1>
|
||||
|
||||
{!! Parsedown::instance()->text($group['description']) !!}
|
||||
|
||||
@foreach($group['subgroups'] as $subgroupName => $subgroup)
|
||||
@if($subgroupName !== "")
|
||||
<h2 id="{!! Str::slug($group['name']) !!}-{!! Str::slug($subgroupName) !!}">{{ $subgroupName }}</h2>
|
||||
@php($subgroupDescription = collect($subgroup)->first(fn ($e) => $e->metadata->subgroupDescription)?->metadata?->subgroupDescription)
|
||||
@if($subgroupDescription)
|
||||
<p>
|
||||
{!! Parsedown::instance()->text($subgroupDescription) !!}
|
||||
</p>
|
||||
@endif
|
||||
@endif
|
||||
@foreach($subgroup as $endpoint)
|
||||
@include("scribe::themes.default.endpoint")
|
||||
@endforeach
|
||||
@endforeach
|
||||
@endforeach
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\WritingUtils as u;
|
||||
@endphp
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>{!! $metadata['title'] !!}</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="{!! $assetPathPrefix !!}css/theme-default.style.css" media="screen">
|
||||
<link rel="stylesheet" href="{!! $assetPathPrefix !!}css/theme-default.print.css" media="print">
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/@highlightjs/cdn-assets@11.6.0/styles/obsidian.min.css">
|
||||
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.6.0/highlight.min.js"></script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jets/0.14.1/jets.min.js"></script>
|
||||
|
||||
@if(isset($metadata['example_languages']))
|
||||
<style id="language-style">
|
||||
/* starts out as display none and is replaced with js later */
|
||||
@foreach($metadata['example_languages'] as $lang)
|
||||
body .content .{{ $lang }}-example code { display: none; }
|
||||
@endforeach
|
||||
</style>
|
||||
@endif
|
||||
|
||||
@if($tryItOut['enabled'] ?? true)
|
||||
<script>
|
||||
var tryItOutBaseUrl = "{!! $tryItOut['base_url'] ?? config('app.url') !!}";
|
||||
var useCsrf = Boolean({!! $tryItOut['use_csrf'] ?? null !!});
|
||||
var csrfUrl = "{!! $tryItOut['csrf_url'] ?? null !!}";
|
||||
</script>
|
||||
<script src="{{ u::getVersionedAsset($assetPathPrefix.'js/tryitout.js') }}"></script>
|
||||
@endif
|
||||
|
||||
<script src="{{ u::getVersionedAsset($assetPathPrefix.'js/theme-default.js') }}"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body data-languages="{{ json_encode($metadata['example_languages'] ?? []) }}">
|
||||
|
||||
@include("scribe::themes.default.sidebar")
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="dark-box"></div>
|
||||
<div class="content">
|
||||
{!! $intro !!}
|
||||
|
||||
{!! $auth !!}
|
||||
|
||||
@include("scribe::themes.default.groups")
|
||||
|
||||
{!! $append !!}
|
||||
</div>
|
||||
<div class="dark-box">
|
||||
@if(isset($metadata['example_languages']))
|
||||
<div class="lang-selector">
|
||||
@foreach($metadata['example_languages'] as $name => $lang)
|
||||
@php if (is_numeric($name)) $name = $lang; @endphp
|
||||
<button type="button" class="lang-button" data-language-name="{{$lang}}">{{$name}}</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,69 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\Utils as u;
|
||||
@endphp
|
||||
<a href="#" id="nav-button">
|
||||
<span>
|
||||
MENU
|
||||
<img src="{!! $assetPathPrefix !!}images/navbar.png" alt="navbar-image"/>
|
||||
</span>
|
||||
</a>
|
||||
<div class="tocify-wrapper">
|
||||
@if($metadata['logo'] != false)
|
||||
<img src="{{ $metadata['logo'] }}" alt="logo" class="logo" style="padding-top: 10px;" width="100%"/>
|
||||
@endif
|
||||
|
||||
@isset($metadata['example_languages'])
|
||||
<div class="lang-selector">
|
||||
@foreach($metadata['example_languages'] as $name => $lang)
|
||||
@php if (is_numeric($name)) $name = $lang; @endphp
|
||||
<button type="button" class="lang-button" data-language-name="{{ $lang }}">{{ $name }}</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endisset
|
||||
|
||||
<div class="search">
|
||||
<input type="text" class="search" id="input-search" placeholder="{{ u::trans("scribe::labels.search") }}">
|
||||
</div>
|
||||
|
||||
<div id="toc">
|
||||
@foreach($headings as $h1)
|
||||
<ul id="tocify-header-{{ $h1['slug'] }}" class="tocify-header">
|
||||
<li class="tocify-item level-1" data-unique="{!! $h1['slug'] !!}">
|
||||
<a href="#{!! $h1['slug'] !!}">{!! $h1['name'] !!}</a>
|
||||
</li>
|
||||
@if(count($h1['subheadings']) > 0)
|
||||
<ul id="tocify-subheader-{!! $h1['slug'] !!}" class="tocify-subheader">
|
||||
@foreach($h1['subheadings'] as $h2)
|
||||
<li class="tocify-item level-2" data-unique="{!! $h2['slug'] !!}">
|
||||
<a href="#{!! $h2['slug'] !!}">{!! $h2['name'] !!}</a>
|
||||
</li>
|
||||
@if(count($h2['subheadings']) > 0)
|
||||
<ul id="tocify-subheader-{!! $h2['slug'] !!}" class="tocify-subheader">
|
||||
@foreach($h2['subheadings'] as $h3)
|
||||
<li class="tocify-item level-3" data-unique="{!! $h3['slug'] !!}">
|
||||
<a href="#{!! $h3['slug'] !!}">{!! $h3['name'] !!}</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</ul>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<ul class="toc-footer" id="toc-footer">
|
||||
@if($metadata['postman_collection_url'])
|
||||
<li style="padding-bottom: 5px;"><a href="{!! $metadata['postman_collection_url'] !!}">{!! u::trans("scribe::links.postman") !!}</a></li>
|
||||
@endif
|
||||
@if($metadata['openapi_spec_url'])
|
||||
<li style="padding-bottom: 5px;"><a href="{!! $metadata['openapi_spec_url'] !!}">{!! u::trans("scribe::links.openapi") !!}</a></li>
|
||||
@endif
|
||||
<li><a href="http://github.com/knuckleswtf/scribe">Documentation powered by Scribe ✍</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="toc-footer" id="last-updated">
|
||||
<li>{{ $metadata['last_updated'] }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
@php
|
||||
$hasChildren ??= false;
|
||||
$isArrayBody = $name == "[]";
|
||||
$expandable = $hasChildren && !$isArrayBody;
|
||||
@endphp
|
||||
|
||||
<div class="sl-flex sl-relative sl-max-w-full sl-py-2 sl-pl-3">
|
||||
<div class="sl-w-1 sl-mt-2 sl-mr-3 sl--ml-3 sl-border-t"></div>
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--1 sl-flex sl-flex-1 sl-flex-col sl-items-stretch sl-max-w-full sl-ml-2 @if($expandable) sl-cursor-pointer @endif">
|
||||
<div class="sl-flex sl-items-center sl-max-w-full">
|
||||
@if($expandable)
|
||||
<div class="sl-flex sl-justify-center sl-w-8 sl--ml-8 sl-pl-3 sl-text-muted expansion-chevrons" role="button">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-right"
|
||||
class="svg-inline--fa fa-chevron-right fa-fw fa-sm sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
@endif
|
||||
@unless($isArrayBody)
|
||||
<div class="sl-flex sl-items-baseline sl-text-base">
|
||||
<div class="sl-font-mono sl-font-semibold sl-mr-2">{{ $name }}</div>
|
||||
@if($type)
|
||||
<span class="sl-truncate sl-text-muted">{{ $type }}</span>
|
||||
@endif
|
||||
</div>
|
||||
@if($required)
|
||||
<div class="sl-flex-1 sl-h-px sl-mx-3"></div>
|
||||
<span class="sl-ml-2 sl-text-warning">required</span>
|
||||
@endif
|
||||
@endunless
|
||||
</div>
|
||||
@if($description)
|
||||
<div class="sl-prose sl-markdown-viewer" style="font-size: 12px;">
|
||||
{!! Parsedown::instance()->text($description) !!}
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($enumValues))
|
||||
Must be one of:
|
||||
<ul style="list-style-position: inside; list-style-type: square;">{!! implode(" ", array_map(fn($val) => "<li><code>$val</code></li>", $enumValues)) !!}</ul>
|
||||
@endif
|
||||
@if($isArrayBody)
|
||||
<div class="sl-flex sl-items-baseline sl-text-base">
|
||||
<div class="sl-font-mono sl-font-semibold sl-mr-2">array of:</div>
|
||||
@if($required)
|
||||
<div class="sl-flex-1 sl-h-px sl-mx-3"></div>
|
||||
<span class="sl-ml-2 sl-text-warning">required</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@if(!$hasChildren && !is_null($example) && $example !== '')
|
||||
<div class="sl-stack sl-stack--horizontal sl-stack--2 sl-flex sl-flex-row sl-items-baseline sl-text-muted">
|
||||
<span>Example:</span> <!-- <span> important for spacing -->
|
||||
<div class="sl-flex sl-flex-1 sl-flex-wrap" style="gap: 4px;">
|
||||
<div class="sl-max-w-full sl-break-all sl-px-1 sl-bg-canvas-tint sl-text-muted sl-rounded sl-border">
|
||||
{{ is_array($example) || is_bool($example) ? json_encode($example) : $example }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
@php
|
||||
$level ??= 0;
|
||||
$levelNestingClass = match($level) {
|
||||
0 => "sl-ml-px",
|
||||
default => "sl-ml-7"
|
||||
};
|
||||
$expandable ??= !isset($fields["[]"]);
|
||||
@endphp
|
||||
|
||||
@foreach($fields as $name => $field)
|
||||
<div class="{{ $expandable ? 'expandable' : '' }} sl-text-sm sl-border-l {{ $levelNestingClass }}">
|
||||
@component('scribe::themes.elements.components.field-details', [
|
||||
'name' => $name,
|
||||
'type' => $field['type'] ?? 'string',
|
||||
'required' => $field['required'] ?? false,
|
||||
'description' => $field['description'] ?? '',
|
||||
'example' => $field['example'] ?? '',
|
||||
'enumValues' => $field['enumValues'] ?? null,
|
||||
'endpointId' => $endpointId,
|
||||
'hasChildren' => !empty($field['__fields']),
|
||||
'component' => 'body',
|
||||
])
|
||||
@endcomponent
|
||||
|
||||
@if(!empty($field['__fields']))
|
||||
<div class="children" style="{{ $expandable ? 'display: none;' : '' }}">
|
||||
@component('scribe::themes.elements.components.nested-fields', [
|
||||
'fields' => $field['__fields'],
|
||||
'endpointId' => $endpointId,
|
||||
'level' => $level + 1,
|
||||
'expandable'=> $expandable,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@@ -0,0 +1,263 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\Utils as u;
|
||||
/** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--8 HttpOperation sl-flex sl-flex-col sl-items-stretch sl-w-full">
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--5 sl-flex sl-flex-col sl-items-stretch">
|
||||
<div class="sl-relative">
|
||||
<div class="sl-stack sl-stack--horizontal sl-stack--5 sl-flex sl-flex-row sl-items-center">
|
||||
<h2 class="sl-text-3xl sl-leading-tight sl-font-prose sl-text-heading sl-mt-5 sl-mb-1"
|
||||
id="{!! $endpoint->fullSlug() !!}">
|
||||
{{ $endpoint->name() }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sl-relative">
|
||||
<div title="{{ rtrim($baseUrl, '/') . '/'. ltrim($endpoint->uri, '/') }}"
|
||||
class="sl-stack sl-stack--horizontal sl-stack--3 sl-inline-flex sl-flex-row sl-items-center sl-max-w-full sl-font-mono sl-py-2 sl-pr-4 sl-bg-canvas-50 sl-rounded-lg"
|
||||
>
|
||||
@foreach($endpoint->httpMethods as $method)
|
||||
<div class="sl-text-lg sl-font-semibold sl-px-2.5 sl-py-1 sl-text-on-primary sl-rounded-lg"
|
||||
style="background-color: {{ \Knuckles\Scribe\Tools\WritingUtils::$httpMethodToCssColour[$method] }};"
|
||||
>
|
||||
{{ $method }}
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="sl-flex sl-overflow-x-hidden sl-text-lg sl-select-all">
|
||||
<div dir="rtl"
|
||||
class="sl-overflow-x-hidden sl-truncate sl-text-muted">{{ rtrim($baseUrl, '/') }}</div>
|
||||
<div class="sl-flex-1 sl-font-semibold">/{{ ltrim($endpoint->uri, '/') }}</div>
|
||||
</div>
|
||||
|
||||
@if($endpoint->metadata->authenticated)
|
||||
<div class="sl-font-prose sl-font-semibold sl-px-1.5 sl-py-0.5 sl-text-on-primary sl-rounded-lg"
|
||||
style="background-color: darkred"
|
||||
>requires authentication
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Parsedown::instance()->text($endpoint->metadata->description ?: '') !!}
|
||||
</div>
|
||||
<div class="sl-flex">
|
||||
<div data-testid="two-column-left" class="sl-flex-1 sl-w-0">
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--10 sl-flex sl-flex-col sl-items-stretch">
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--8 sl-flex sl-flex-col sl-items-stretch">
|
||||
@if(count($endpoint->headers))
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--5 sl-flex sl-flex-col sl-items-stretch">
|
||||
<h3 class="sl-text-2xl sl-leading-snug sl-font-prose">
|
||||
{{ u::trans("scribe::endpoint.headers") }}
|
||||
</h3>
|
||||
<div class="sl-text-sm">
|
||||
@foreach($endpoint->headers as $header => $value)
|
||||
@component('scribe::themes.elements.components.field-details', [
|
||||
'name' => $header,
|
||||
'type' => null,
|
||||
'required' => false,
|
||||
'description' => null,
|
||||
'example' => $value,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'component' => 'header',
|
||||
'isInput' => true,
|
||||
])
|
||||
@endcomponent
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->urlParameters))
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
|
||||
<h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ u::trans("scribe::endpoint.url_parameters") }}</h3>
|
||||
|
||||
<div class="sl-text-sm">
|
||||
@foreach($endpoint->urlParameters as $attribute => $parameter)
|
||||
@component('scribe::themes.elements.components.field-details', [
|
||||
'name' => $parameter->name,
|
||||
'type' => $parameter->type ?? 'string',
|
||||
'required' => $parameter->required,
|
||||
'description' => $parameter->description,
|
||||
'example' => $parameter->example ?? '',
|
||||
'enumValues' => $parameter->enumValues,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'component' => 'url',
|
||||
'isInput' => true,
|
||||
])
|
||||
@endcomponent
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
@if(count($endpoint->queryParameters))
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
|
||||
<h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ u::trans("scribe::endpoint.query_parameters") }}</h3>
|
||||
|
||||
<div class="sl-text-sm">
|
||||
@foreach($endpoint->queryParameters as $attribute => $parameter)
|
||||
@component('scribe::themes.elements.components.field-details', [
|
||||
'name' => $parameter->name,
|
||||
'type' => $parameter->type,
|
||||
'required' => $parameter->required,
|
||||
'description' => $parameter->description,
|
||||
'example' => $parameter->example ?? '',
|
||||
'enumValues' => $parameter->enumValues,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'component' => 'query',
|
||||
'isInput' => true,
|
||||
])
|
||||
@endcomponent
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->nestedBodyParameters))
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
|
||||
<h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ u::trans("scribe::endpoint.body_parameters") }}</h3>
|
||||
|
||||
<div class="sl-text-sm">
|
||||
@component('scribe::themes.elements.components.nested-fields', [
|
||||
'fields' => $endpoint->nestedBodyParameters,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->responseFields))
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
|
||||
<h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ u::trans("scribe::endpoint.response_fields") }}</h3>
|
||||
|
||||
<div class="sl-text-sm">
|
||||
@component('scribe::themes.elements.components.nested-fields', [
|
||||
'fields' => $endpoint->nestedResponseFields,
|
||||
'endpointId' => $endpoint->endpointId(),
|
||||
'isInput' => false,
|
||||
])
|
||||
@endcomponent
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-testid="two-column-right" class="sl-relative sl-w-2/5 sl-ml-16" style="max-width: 500px;">
|
||||
<div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
|
||||
|
||||
@if($metadata['try_it_out']['enabled'] ?? false)
|
||||
@include("scribe::themes.elements.try_it_out")
|
||||
@endif
|
||||
|
||||
@if($metadata['example_languages'])
|
||||
<div class="sl-panel sl-outline-none sl-w-full sl-rounded-lg">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-3 sl-pl-4 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-select-none">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl--ml-2">
|
||||
{{ u::trans("scribe::endpoint.example_request") }}:
|
||||
<select class="example-request-lang-toggle sl-text-base"
|
||||
aria-label="Request Sample Language"
|
||||
onchange="switchExampleLanguage(event.target.value);">
|
||||
@foreach($metadata['example_languages'] as $language)
|
||||
<option>{{ $language }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@foreach($metadata['example_languages'] as $index => $language)
|
||||
<div class="sl-bg-canvas-100 example-request example-request-{{ $language }}"
|
||||
style="{{ $index == 0 ? '' : 'display: none;' }}">
|
||||
<div class="sl-px-0 sl-py-1">
|
||||
<div style="max-height: 400px;" class="sl-overflow-y-auto sl-rounded">
|
||||
@include("scribe::partials.example-requests.$language")
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($endpoint->isGet() || $endpoint->hasResponses())
|
||||
<div class="sl-panel sl-outline-none sl-w-full sl-rounded-lg">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-3 sl-pl-4 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-select-none">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-py-2">
|
||||
<div class="sl--ml-2">
|
||||
<div class="sl-h-sm sl-text-base sl-font-medium sl-px-1.5 sl-text-muted sl-rounded sl-border-transparent sl-border">
|
||||
<div class="sl-mb-2 sl-inline-block">{{ u::trans("scribe::endpoint.example_response") }}:</div>
|
||||
<div class="sl-mb-2 sl-inline-block">
|
||||
<select
|
||||
class="example-response-{{ $endpoint->endpointId() }}-toggle sl-text-base"
|
||||
aria-label="Response sample"
|
||||
onchange="switchExampleResponse('{{ $endpoint->endpointId() }}', event.target.value);">
|
||||
@foreach($endpoint->responses as $index => $response)
|
||||
<option value="{{ $index }}">{{ $response->fullDescription() }}</option>
|
||||
@endforeach
|
||||
</select></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="sl-button sl-h-sm sl-text-base sl-font-medium sl-px-1.5 hover:sl-bg-canvas-50 active:sl-bg-canvas-100 sl-text-muted hover:sl-text-body focus:sl-text-body sl-rounded sl-border-transparent sl-border disabled:sl-opacity-70">
|
||||
<div class="sl-mx-0">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="copy"
|
||||
class="svg-inline--fa fa-copy fa-fw fa-sm sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor"
|
||||
d="M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
@foreach($endpoint->responses as $index => $response)
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 example-response-{{ $endpoint->endpointId() }} example-response-{{ $endpoint->endpointId() }}-{{ $index }}"
|
||||
style=" {{ $index == 0 ? '' : 'display: none;' }}"
|
||||
>
|
||||
<div class="sl-panel__content sl-p-0">@if(count($response->headers))
|
||||
<details class="sl-pl-2">
|
||||
<summary style="cursor: pointer; list-style: none;">
|
||||
<small>
|
||||
<span class="expansion-chevrons">
|
||||
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="chevron-right"
|
||||
class="svg-inline--fa fa-chevron-right fa-fw sl-icon sl-text-muted"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
Headers
|
||||
</small>
|
||||
</summary>
|
||||
<pre><code class="language-http">@foreach($response->headers as $header => $value)
|
||||
{{ $header }}
|
||||
: {{ is_array($value) ? implode('; ', $value) : $value }}
|
||||
@endforeach </code></pre>
|
||||
</details>
|
||||
@endif
|
||||
@if(is_string($response->content) && Str::startsWith($response->content, "<<binary>>"))
|
||||
<pre><code>[{{ u::trans("scribe::endpoint.responses.binary") }}] - {{ htmlentities(str_replace("<<binary>>", "", $response->content)) }}</code></pre>
|
||||
@elseif($response->status == 204)
|
||||
<pre><code>[{{ u::trans("scribe::endpoint.responses.empty") }}]</code></pre>
|
||||
@else
|
||||
@php($parsed = json_decode($response->content))
|
||||
{{-- If response is a JSON string, prettify it. Otherwise, just print it --}}
|
||||
<pre><code style="max-height: 300px;"
|
||||
class="language-json sl-overflow-x-auto sl-overflow-y-auto">{!! htmlentities($parsed != null ? json_encode($parsed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : $response->content) !!}</code></pre>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
@foreach($groupedEndpoints as $group)
|
||||
<h1 id="{!! Str::slug($group['name']) !!}"
|
||||
class="sl-text-5xl sl-leading-tight sl-font-prose sl-text-heading"
|
||||
>
|
||||
{!! $group['name'] !!}
|
||||
</h1>
|
||||
|
||||
{!! Parsedown::instance()->text($group['description']) !!}
|
||||
|
||||
@foreach($group['subgroups'] as $subgroupName => $subgroup)
|
||||
@if($subgroupName !== "")
|
||||
<h2 id="{!! Str::slug($group['name']) !!}-{!! Str::slug($subgroupName) !!}"
|
||||
class="sl-text-3xl sl-leading-tight sl-font-prose sl-text-heading sl-mt-5 sl-mb-3"
|
||||
>
|
||||
{{ $subgroupName }}
|
||||
</h2>
|
||||
@php($subgroupDescription = collect($subgroup)->first(fn ($e) => $e->metadata->subgroupDescription)?->metadata?->subgroupDescription)
|
||||
@if($subgroupDescription)
|
||||
{!! Parsedown::instance()->text($subgroupDescription) !!}
|
||||
@endif
|
||||
<br>
|
||||
@endif
|
||||
@foreach($subgroup as $endpoint)
|
||||
@include("scribe::themes.elements.endpoint")
|
||||
@endforeach
|
||||
@endforeach
|
||||
@endforeach
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\WritingUtils as u;
|
||||
@endphp
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>{!! $metadata['title'] !!}</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=PT+Sans&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="{!! $assetPathPrefix !!}css/theme-elements.style.css" media="screen">
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/@highlightjs/cdn-assets@11.6.0/styles/docco.min.css">
|
||||
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.6.0/highlight.min.js"></script>
|
||||
<script>hljs.highlightAll();</script>
|
||||
<script type="module">
|
||||
import {CodeJar} from 'https://medv.io/codejar/codejar.js'
|
||||
window.CodeJar = CodeJar;
|
||||
</script>
|
||||
|
||||
@if($tryItOut['enabled'] ?? true)
|
||||
<script>
|
||||
var tryItOutBaseUrl = "{{ $tryItOut['base_url'] ?? config('app.url') }}";
|
||||
var useCsrf = Boolean({{ $tryItOut['use_csrf'] ?? null }});
|
||||
var csrfUrl = "{{ $tryItOut['csrf_url'] ?? null }}";
|
||||
</script>
|
||||
<script src="{{ u::getVersionedAsset($assetPathPrefix.'js/tryitout.js') }}"></script>
|
||||
<style>
|
||||
.code-editor, .response-content {
|
||||
color: whitesmoke;
|
||||
background-color: transparent;
|
||||
}
|
||||
/*
|
||||
Problem: we want syntax highlighting for the Try It Out JSON body code editor
|
||||
However, the Try It Out area uses a dark background, while request and response samples
|
||||
(which are already highlighted) use a light background. HighlightJS can only use one theme per document.
|
||||
Our options:
|
||||
1. Change the bg of one. => No, it looks out of place on the page.
|
||||
2. Use the same highlighting for both. => Nope, one would be unreadable.
|
||||
3. Copy styles for a dark-bg h1js theme and prefix them for the CodeEditor, which is what we're doing.
|
||||
Since it's only JSON, we only need a few styles anyway.
|
||||
Styles taken from the Nord theme: https://github.com/highlightjs/highlight.js/blob/3997c9b430a568d5ad46d96693b90a74fc01ea7f/src/styles/nord.css#L2
|
||||
*/
|
||||
.code-editor > .hljs-attr {
|
||||
color: #8FBCBB;
|
||||
}
|
||||
.code-editor > .hljs-string {
|
||||
color: #A3BE8C;
|
||||
}
|
||||
.code-editor > .hljs-number {
|
||||
color: #B48EAD;
|
||||
}
|
||||
.code-editor > .hljs-literal{
|
||||
color: #81A1C1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function tryItOut(btnElement) {
|
||||
btnElement.disabled = true;
|
||||
|
||||
let endpointId = btnElement.dataset.endpoint;
|
||||
|
||||
let errorPanel = document.querySelector(`.tryItOut-error[data-endpoint=${endpointId}]`);
|
||||
errorPanel.hidden = true;
|
||||
let responsePanel = document.querySelector(`.tryItOut-response[data-endpoint=${endpointId}]`);
|
||||
responsePanel.hidden = true;
|
||||
|
||||
let form = btnElement.form;
|
||||
let { method, path, hasjsonbody: hasJsonBody} = form.dataset;
|
||||
let body = {};
|
||||
if (hasJsonBody === "1") {
|
||||
body = form.querySelector('.code-editor').textContent;
|
||||
} else if (form.dataset.hasfiles === "1") {
|
||||
body = new FormData();
|
||||
form.querySelectorAll('input[data-component=body]')
|
||||
.forEach(el => {
|
||||
if (el.type === 'file') {
|
||||
if (el.files[0]) body.append(el.name, el.files[0])
|
||||
} else body.append(el.name, el.value);
|
||||
});
|
||||
} else {
|
||||
form.querySelectorAll('input[data-component=body]').forEach(el => {
|
||||
_.set(body, el.name, el.value);
|
||||
});
|
||||
}
|
||||
|
||||
const urlParameters = form.querySelectorAll('input[data-component=url]');
|
||||
urlParameters.forEach(el => (path = path.replace(new RegExp(`\\{${el.name}\\??}`), el.value)));
|
||||
|
||||
const headers = Object.fromEntries(Array.from(form.querySelectorAll('input[data-component=header]'))
|
||||
.map(el => [el.name, (el.dataset.prefix || '') + el.value]));
|
||||
|
||||
const query = {}
|
||||
form.querySelectorAll('input[data-component=query]').forEach(el => {
|
||||
_.set(query, el.name, el.value);
|
||||
});
|
||||
|
||||
let preflightPromise = Promise.resolve();
|
||||
if (window.useCsrf && window.csrfUrl) {
|
||||
preflightPromise = makeAPICall('GET', window.csrfUrl).then(() => {
|
||||
headers['X-XSRF-TOKEN'] = getCookie('XSRF-TOKEN');
|
||||
});
|
||||
}
|
||||
|
||||
// content type has to be unset otherwise file upload won't work
|
||||
if (form.dataset.hasfiles === "1") {
|
||||
delete headers['Content-Type'];
|
||||
}
|
||||
|
||||
return preflightPromise.then(() => makeAPICall(method, path, body, query, headers, endpointId))
|
||||
.then(([responseStatus, statusText, responseContent, responseHeaders]) => {
|
||||
responsePanel.hidden = false;
|
||||
responsePanel.querySelector(`.response-status`).textContent = responseStatus + " " + statusText ;
|
||||
|
||||
let contentEl = responsePanel.querySelector(`.response-content`);
|
||||
if (responseContent === '') {
|
||||
contentEl.textContent = contentEl.dataset.emptyResponseText;
|
||||
return;
|
||||
}
|
||||
|
||||
// Prettify it if it's JSON
|
||||
let isJson = false;
|
||||
try {
|
||||
const jsonParsed = JSON.parse(responseContent);
|
||||
if (jsonParsed !== null) {
|
||||
isJson = true;
|
||||
responseContent = JSON.stringify(jsonParsed, null, 4);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Replace HTML entities
|
||||
responseContent = responseContent.replace(/[<>&]/g, (i) => '&#' + i.charCodeAt(0) + ';');
|
||||
|
||||
contentEl.innerHTML = responseContent;
|
||||
isJson && window.hljs.highlightElement(contentEl);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
let errorMessage = err.message || err;
|
||||
errorPanel.hidden = false;
|
||||
errorPanel.querySelector(`.error-message`).textContent = errorMessage;
|
||||
})
|
||||
.finally(() => { btnElement.disabled = false } );
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('.tryItOut-btn').forEach(el => {
|
||||
el.addEventListener('click', () => tryItOut(el));
|
||||
});
|
||||
})
|
||||
</script>
|
||||
@endif
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@if($metadata['example_languages'])
|
||||
<script>
|
||||
function switchExampleLanguage(lang) {
|
||||
document.querySelectorAll(`.example-request`).forEach(el => el.style.display = 'none');
|
||||
document.querySelectorAll(`.example-request-${lang}`).forEach(el => el.style.display = 'initial');
|
||||
document.querySelectorAll(`.example-request-lang-toggle`).forEach(el => el.value = lang);
|
||||
}
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<script>
|
||||
function switchExampleResponse(endpointId, index) {
|
||||
document.querySelectorAll(`.example-response-${endpointId}`).forEach(el => el.style.display = 'none');
|
||||
document.querySelectorAll(`.example-response-${endpointId}-${index}`).forEach(el => el.style.display = 'initial');
|
||||
document.querySelectorAll(`.example-response-${endpointId}-toggle`).forEach(el => el.value = index);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Requirement: a div with class `expansion-chevrons`
|
||||
* (or `expansion-chevrons-solid` to use the solid version).
|
||||
* Also add the `expanded` class if your div is expanded by default.
|
||||
*/
|
||||
function toggleExpansionChevrons(evt) {
|
||||
let elem = evt.currentTarget;
|
||||
|
||||
let chevronsArea = elem.querySelector('.expansion-chevrons');
|
||||
const solid = chevronsArea.classList.contains('expansion-chevrons-solid');
|
||||
const newState = chevronsArea.classList.contains('expanded') ? 'expand' : 'expanded';
|
||||
if (newState === 'expanded') {
|
||||
const selector = solid ? '#expanded-chevron-solid' : '#expanded-chevron';
|
||||
const template = document.querySelector(selector);
|
||||
const chevron = template.content.cloneNode(true);
|
||||
chevronsArea.replaceChildren(chevron);
|
||||
chevronsArea.classList.add('expanded');
|
||||
} else {
|
||||
const selector = solid ? '#expand-chevron-solid' : '#expand-chevron';
|
||||
const template = document.querySelector(selector);
|
||||
const chevron = template.content.cloneNode(true);
|
||||
chevronsArea.replaceChildren(chevron);
|
||||
chevronsArea.classList.remove('expanded');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Make sure the children are inside the parent element
|
||||
* 2. Add `expandable` class to the parent
|
||||
* 3. Add `children` class to the children.
|
||||
* 4. Wrap the default chevron SVG in a div with class `expansion-chevrons`
|
||||
* (or `expansion-chevrons-solid` to use the solid version).
|
||||
* Also add the `expanded` class if your div is expanded by default.
|
||||
*/
|
||||
function toggleElementChildren(evt) {
|
||||
let elem = evt.currentTarget;
|
||||
let children = elem.querySelector(`.children`);
|
||||
if (!children) return;
|
||||
|
||||
if (children.contains(event.target)) return;
|
||||
|
||||
let oldState = children.style.display
|
||||
if (oldState === 'none') {
|
||||
children.style.removeProperty('display');
|
||||
toggleExpansionChevrons(evt);
|
||||
} else {
|
||||
children.style.display = 'none';
|
||||
toggleExpansionChevrons(evt);
|
||||
}
|
||||
|
||||
evt.stopPropagation();
|
||||
}
|
||||
|
||||
function highlightSidebarItem(evt = null) {
|
||||
if (evt && evt.oldURL) {
|
||||
let oldHash = new URL(evt.oldURL).hash.slice(1);
|
||||
if (oldHash) {
|
||||
let previousItem = window['sidebar'].querySelector(`#toc-item-${oldHash}`);
|
||||
previousItem.classList.remove('sl-bg-primary-tint');
|
||||
previousItem.classList.add('sl-bg-canvas-100');
|
||||
}
|
||||
}
|
||||
|
||||
let newHash = location.hash.slice(1);
|
||||
if (newHash) {
|
||||
let item = window['sidebar'].querySelector(`#toc-item-${newHash}`);
|
||||
item.classList.remove('sl-bg-canvas-100');
|
||||
item.classList.add('sl-bg-primary-tint');
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('DOMContentLoaded', () => {
|
||||
highlightSidebarItem();
|
||||
|
||||
document.querySelectorAll('.code-editor').forEach(elem => CodeJar(elem, (editor) => {
|
||||
// highlight.js does not trim old tags,
|
||||
// which means highlighting doesn't update on type (only on paste)
|
||||
// See https://github.com/antonmedv/codejar/issues/18
|
||||
editor.textContent = editor.textContent
|
||||
return hljs.highlightElement(editor)
|
||||
}));
|
||||
|
||||
document.querySelectorAll('.expandable').forEach(el => {
|
||||
el.addEventListener('click', toggleElementChildren);
|
||||
});
|
||||
|
||||
document.querySelectorAll('details').forEach(el => {
|
||||
el.addEventListener('toggle', toggleExpansionChevrons);
|
||||
});
|
||||
});
|
||||
|
||||
addEventListener('hashchange', highlightSidebarItem);
|
||||
</script>
|
||||
|
||||
<div class="sl-elements sl-antialiased sl-h-full sl-text-base sl-font-ui sl-text-body sl-flex sl-inset-0">
|
||||
|
||||
@include("scribe::themes.elements.sidebar")
|
||||
|
||||
<div class="sl-overflow-y-auto sl-flex-1 sl-w-full sl-px-16 sl-bg-canvas sl-py-16" style="max-width: 1500px;">
|
||||
|
||||
<div class="sl-mb-10">
|
||||
<div class="sl-mb-4">
|
||||
<h1 class="sl-text-5xl sl-leading-tight sl-font-prose sl-font-semibold sl-text-heading">
|
||||
{!! $metadata['title'] !!}
|
||||
</h1>
|
||||
@if($metadata['postman_collection_url'])
|
||||
<a title="Download Postman collection" class="sl-mx-1"
|
||||
href="{!! $metadata['postman_collection_url'] !!}" target="_blank">
|
||||
<small>Postman collection →</small>
|
||||
</a>
|
||||
@endif
|
||||
@if($metadata['openapi_spec_url'])
|
||||
<a title="Download OpenAPI spec" class="sl-mx-1"
|
||||
href="{!! $metadata['openapi_spec_url'] !!}" target="_blank">
|
||||
<small>OpenAPI spec →</small>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="sl-prose sl-markdown-viewer sl-my-4">
|
||||
{!! $intro !!}
|
||||
|
||||
{!! $auth !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include("scribe::themes.elements.groups")
|
||||
|
||||
<div class="sl-prose sl-markdown-viewer sl-my-5">
|
||||
{!! $append !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<template id="expand-chevron">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="chevron-right"
|
||||
class="svg-inline--fa fa-chevron-right fa-fw sl-icon sl-text-muted"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z"></path>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<template id="expanded-chevron">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="chevron-down"
|
||||
class="svg-inline--fa fa-chevron-down fa-fw sl-icon sl-text-muted"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor"
|
||||
d="M224 416c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L224 338.8l169.4-169.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-192 192C240.4 412.9 232.2 416 224 416z"></path>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<template id="expand-chevron-solid">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="caret-right"
|
||||
class="svg-inline--fa fa-caret-right fa-fw sl-icon" role="img" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 256 512">
|
||||
<path fill="currentColor"
|
||||
d="M118.6 105.4l128 127.1C252.9 239.6 256 247.8 256 255.1s-3.125 16.38-9.375 22.63l-128 127.1c-9.156 9.156-22.91 11.9-34.88 6.943S64 396.9 64 383.1V128c0-12.94 7.781-24.62 19.75-29.58S109.5 96.23 118.6 105.4z"></path>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<template id="expanded-chevron-solid">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</template>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,92 @@
|
||||
<div id="sidebar" class="sl-flex sl-overflow-y-auto sl-flex-col sl-sticky sl-inset-y-0 sl-pt-8 sl-bg-canvas-100 sl-border-r"
|
||||
style="width: calc((100% - 1800px) / 2 + 300px); padding-left: calc((100% - 1800px) / 2); min-width: 300px; max-height: 100vh">
|
||||
<div class="sl-flex sl-items-center sl-mb-5 sl-ml-4">
|
||||
@if($metadata['logo'] != false)
|
||||
<div class="sl-inline sl-overflow-x-hidden sl-overflow-y-hidden sl-mr-3 sl-rounded-lg"
|
||||
style="background-color: transparent;">
|
||||
<img src="{{ $metadata['logo'] }}" height="30px" width="30px" alt="logo">
|
||||
</div>
|
||||
@endif
|
||||
<h4 class="sl-text-paragraph sl-leading-snug sl-font-prose sl-font-semibold sl-text-heading">
|
||||
{{ $metadata['title'] }}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="sl-flex sl-overflow-y-auto sl-flex-col sl-flex-grow sl-flex-shrink">
|
||||
<div class="sl-overflow-y-auto sl-w-full sl-bg-canvas-100">
|
||||
<div class="sl-my-3">
|
||||
@foreach($headings as $h1)
|
||||
<div class="expandable">
|
||||
<div title="{!! $h1['name'] !!}" id="toc-item-{!! $h1['slug'] !!}"
|
||||
class="sl-flex sl-items-center sl-h-md sl-pr-4 sl-pl-4 sl-bg-canvas-100 hover:sl-bg-canvas-200 sl-cursor-pointer sl-select-none">
|
||||
<a href="#{!! $h1['slug'] !!}"
|
||||
class="sl-flex-1 sl-items-center sl-truncate sl-mr-1.5 sl-p-0">{!! $h1['name'] !!}</a>
|
||||
@if(count($h1['subheadings']) > 0)
|
||||
<div class="sl-flex sl-items-center sl-text-xs expansion-chevrons">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="chevron-right"
|
||||
class="svg-inline--fa fa-chevron-right fa-fw sl-icon sl-text-muted"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if(count($h1['subheadings']) > 0)
|
||||
<div class="children" style="display: none;">
|
||||
@foreach($h1['subheadings'] as $h2)
|
||||
<div class="expandable">
|
||||
<div class="sl-flex sl-items-center sl-h-md sl-pr-4 sl-pl-8 sl-bg-canvas-100 hover:sl-bg-canvas-200 sl-cursor-pointer sl-select-none"
|
||||
id="toc-item-{!! $h2['slug'] !!}">
|
||||
<div class="sl-flex-1 sl-items-center sl-truncate sl-mr-1.5 sl-p-0" title="{!! $h2['name'] !!}">
|
||||
<a class="ElementsTableOfContentsItem sl-block sl-no-underline"
|
||||
href="#{!! $h2['slug'] !!}">
|
||||
{!! $h2['name'] !!}
|
||||
</a>
|
||||
</div>
|
||||
@if(count($h2['subheadings']) > 0)
|
||||
<div class="sl-flex sl-items-center sl-text-xs expansion-chevrons">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="chevron-right"
|
||||
class="svg-inline--fa fa-chevron-right fa-fw sl-icon sl-text-muted"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if(count($h2['subheadings']) > 0)
|
||||
<div class="children" style="display: none;">
|
||||
@foreach($h2['subheadings'] as $h3)
|
||||
<a class="ElementsTableOfContentsItem sl-block sl-no-underline"
|
||||
href="#{!! $h3['slug'] !!}">
|
||||
<div title="{!! $h3['name'] !!}" id="toc-item-{!! $h3['slug'] !!}"
|
||||
class="sl-flex sl-items-center sl-h-md sl-pr-4 sl-pl-12 sl-bg-canvas-100 hover:sl-bg-canvas-200 sl-cursor-pointer sl-select-none">
|
||||
{!! $h3['name'] !!}
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="sl-flex sl-items-center sl-px-4 sl-py-3 sl-border-t">
|
||||
{{ $metadata['last_updated'] }}
|
||||
</div>
|
||||
|
||||
<div class="sl-flex sl-items-center sl-px-4 sl-py-3 sl-border-t">
|
||||
<a href="http://github.com/knuckleswtf/scribe">Documentation powered by Scribe ✍</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,322 @@
|
||||
@php
|
||||
use Knuckles\Scribe\Tools\Utils as u;
|
||||
/** @var \Knuckles\Camel\Output\OutputEndpointData $endpoint */
|
||||
@endphp
|
||||
|
||||
<div class="sl-inverted">
|
||||
<div class="sl-overflow-y-hidden sl-rounded-lg">
|
||||
<form class="TryItPanel sl-bg-canvas-100 sl-rounded-lg"
|
||||
data-method="{{ $endpoint->httpMethods[0] }}"
|
||||
data-path="{{ $endpoint->uri }}"
|
||||
data-hasfiles="{{ $endpoint->hasFiles() ? 1 : 0 }}"
|
||||
data-hasjsonbody="{{ $endpoint->hasJsonBody() ? 1 : 0 }}">
|
||||
@if($endpoint->isAuthed() && $metadata['auth']['location'] !== 'body')
|
||||
<div class="sl-panel sl-outline-none sl-w-full expandable">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Auth
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
<div class="ParameterGrid sl-p-4">
|
||||
<label aria-hidden="true"
|
||||
for="auth-{{ $endpoint->endpointId() }}">{{ $metadata['auth']['name'] }}</label>
|
||||
<span class="sl-mx-3">:</span>
|
||||
<div class="sl-flex sl-flex-1">
|
||||
<div class="sl-input sl-flex-1 sl-relative">
|
||||
<code>{{ $metadata['auth']['prefix'] }}</code>
|
||||
<input aria-label="{{ $metadata['auth']['name'] }}"
|
||||
id="auth-{{ $endpoint->endpointId() }}"
|
||||
data-component="{{ $metadata['auth']['location'] }}"
|
||||
data-prefix="{{ $metadata['auth']['prefix'] }}"
|
||||
name="{{ $metadata['auth']['name'] }}"
|
||||
placeholder="{{ $metadata['auth']['placeholder'] }}"
|
||||
class="auth-value sl-relative {{ $metadata['auth']['prefix'] ? 'sl-w-3/5' : 'sl-w-full sl-pr-2.5 sl-pl-2.5' }} sl-h-md sl-text-base sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->headers))
|
||||
<div class="sl-panel sl-outline-none sl-w-full expandable">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Headers
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
<div class="ParameterGrid sl-p-4">
|
||||
@foreach($endpoint->headers as $name => $example)
|
||||
@php
|
||||
if($endpoint->isAuthed() && $metadata['auth']['location'] === 'header' && $name === $metadata['auth']['name']) continue;
|
||||
@endphp
|
||||
<label aria-hidden="true"
|
||||
for="header-{{ $endpoint->endpointId() }}-{{ $name }}">{{ $name }}</label>
|
||||
<span class="sl-mx-3">:</span>
|
||||
<div class="sl-flex sl-flex-1">
|
||||
<div class="sl-input sl-flex-1 sl-relative">
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="header-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
value="{{ $example }}" data-component="header"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border">
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->urlParameters))
|
||||
<div class="sl-panel sl-outline-none sl-w-full expandable">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
URL Parameters
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
<div class="ParameterGrid sl-p-4">
|
||||
@foreach($endpoint->urlParameters as $name => $parameter)
|
||||
<label aria-hidden="true"
|
||||
for="urlparam-{{ $endpoint->endpointId() }}-{{ $name }}">{{ $name }}</label>
|
||||
<span class="sl-mx-3">:</span>
|
||||
<div class="sl-flex sl-flex-1">
|
||||
<div class="sl-input sl-flex-1 sl-relative">
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="urlparam-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
placeholder="{{ $parameter->description }}"
|
||||
value="{{ $parameter->example }}" data-component="url"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border">
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->queryParameters))
|
||||
<div class="sl-panel sl-outline-none sl-w-full expandable">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Query Parameters
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
<div class="ParameterGrid sl-p-4">
|
||||
@foreach($endpoint->queryParameters as $name => $parameter)
|
||||
@php
|
||||
/** @var \Knuckles\Camel\Output\Parameter $parameter */
|
||||
if ($parameter->type == 'object') // Skip; individual object children are listed
|
||||
continue;
|
||||
if (str_contains($name, "[]"))
|
||||
// This likely belongs to an obj-array (eg objs[].a); we only show the parent (objs[]), so skip
|
||||
continue;
|
||||
if($endpoint->isAuthed() && $metadata['auth']['location'] === 'query'
|
||||
&& $name === $metadata['auth']['name']) continue;
|
||||
@endphp
|
||||
<label aria-hidden="true"
|
||||
for="queryparam-{{ $endpoint->endpointId() }}-{{ $name }}">{{ $name }}</label>
|
||||
<span class="sl-mx-3">:</span>
|
||||
<div class="sl-flex sl-flex-1">
|
||||
<div class="sl-input sl-flex-1 sl-relative">
|
||||
@if(str_ends_with($parameter->type, '[]'))
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="queryparam-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
placeholder="{{ $parameter->description }}"
|
||||
value="{{ json_encode($parameter->example) }}" data-component="query"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border"
|
||||
>
|
||||
@else
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="queryparam-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
placeholder="{{ $parameter->description }}"
|
||||
value="{{ $parameter->example }}" data-component="query"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border"
|
||||
>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($endpoint->bodyParameters))
|
||||
<div class="sl-panel sl-outline-none sl-w-full expandable">
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Body
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
@if($endpoint->hasJsonBody())
|
||||
<div class="TextRequestBody sl-p-4">
|
||||
<div class="code-editor language-json"
|
||||
id="json-body-{{ $endpoint->endpointId() }}"
|
||||
style="font-family: var(--font-code); font-size: 12px; line-height: var(--lh-code);"
|
||||
>{!! json_encode($endpoint->getSampleBody(), JSON_PRETTY_PRINT) !!}</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="ParameterGrid sl-p-4">
|
||||
@foreach($endpoint->bodyParameters as $name => $parameter)
|
||||
@php
|
||||
/** @var \Knuckles\Camel\Output\Parameter $parameter */
|
||||
if ($parameter->type == 'object') // Skip; individual object children are listed
|
||||
continue;
|
||||
if (str_contains($name, "[]"))
|
||||
// This likely belongs to an obj-array (eg objs[].a); we only show the parent (objs[]), so skip
|
||||
continue;
|
||||
@endphp
|
||||
<label aria-hidden="true"
|
||||
for="bodyparam-{{ $endpoint->endpointId() }}-{{ $name }}">{{ $name }}</label>
|
||||
<span class="sl-mx-3">:</span>
|
||||
<div class="sl-flex sl-flex-1">
|
||||
<div class="sl-input sl-flex-1 sl-relative">
|
||||
@if($parameter->type == 'file')
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="bodyparam-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
type="file" data-component="body"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border"
|
||||
>
|
||||
@elseif(str_ends_with($parameter->type, '[]'))
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="bodyparam-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
placeholder="{{ $parameter->description }}"
|
||||
value="{{ json_encode($parameter->example) }}" data-component="body"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border"
|
||||
>
|
||||
@else
|
||||
<input aria-label="{{ $name }}" name="{{ $name }}"
|
||||
id="bodyparam-{{ $endpoint->endpointId() }}-{{ $name }}"
|
||||
placeholder="{{ $parameter->description }}"
|
||||
value="{{ $parameter->example }}" data-component="body"
|
||||
class="sl-relative sl-w-full sl-h-md sl-text-base sl-pr-2.5 sl-pl-2.5 sl-rounded sl-border-transparent hover:sl-border-input focus:sl-border-primary sl-border"
|
||||
>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="SendButtonHolder sl-mt-4 sl-p-4 sl-pt-0">
|
||||
<div class="sl-stack sl-stack--horizontal sl-stack--2 sl-flex sl-flex-row sl-items-center">
|
||||
<button type="button" data-endpoint="{{ $endpoint->endpointId() }}"
|
||||
class="tryItOut-btn sl-button sl-h-sm sl-text-base sl-font-medium sl-px-1.5 sl-bg-primary hover:sl-bg-primary-dark active:sl-bg-primary-darker disabled:sl-bg-canvas-100 sl-text-on-primary disabled:sl-text-body sl-rounded sl-border-transparent sl-border disabled:sl-opacity-70"
|
||||
>
|
||||
{{ u::trans("scribe::try_it_out.send") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-endpoint="{{ $endpoint->endpointId() }}"
|
||||
class="tryItOut-error expandable sl-panel sl-outline-none sl-w-full" hidden>
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ u::trans("scribe::try_it_out.request_failed") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
<div class="sl-panel__content sl-p-4">
|
||||
<p class="sl-pb-2"><strong class="error-message"></strong></p>
|
||||
<p class="sl-pb-2">{{ u::trans("scribe::try_it_out.error_help") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-endpoint="{{ $endpoint->endpointId() }}"
|
||||
class="tryItOut-response expandable sl-panel sl-outline-none sl-w-full" hidden>
|
||||
<div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-4 sl-pl-3 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-cursor-pointer sl-select-none"
|
||||
role="button">
|
||||
<div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
|
||||
<div class="sl-flex sl-items-center sl-mr-1.5 expansion-chevrons expansion-chevrons-solid expanded">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas"
|
||||
data-icon="caret-down"
|
||||
class="svg-inline--fa fa-caret-down fa-fw sl-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path fill="currentColor"
|
||||
d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ u::trans("scribe::try_it_out.received_response") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sl-panel__content-wrapper sl-bg-canvas-100 children" role="region">
|
||||
<div class="sl-panel__content sl-p-4">
|
||||
<p class="sl-pb-2 response-status"></p>
|
||||
<pre><code class="sl-pb-2 response-content language-json"
|
||||
data-empty-response-text="<{{ u::trans("scribe::endpoint.responses.empty") }}>"
|
||||
style="max-height: 300px;"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user