Added a view for the API docs

This commit is contained in:
Dan Brown 2020-01-15 20:18:02 +00:00
parent bed2498667
commit 45b5e631e2
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
9 changed files with 133 additions and 13 deletions

View File

@ -106,7 +106,7 @@ class ApiDocsGenerator
return strpos($route->uri, 'api/') === 0;
})->map(function ($route) {
[$controller, $controllerMethod] = explode('@', $route->action['uses']);
$baseModelName = explode('/', $route->uri)[1];
$baseModelName = explode('.', explode('/', $route->uri)[1])[0];
$shortName = $baseModelName . '-' . $controllerMethod;
return [
'name' => $shortName,

View File

@ -13,9 +13,9 @@ class ApiDocsController extends ApiController
public function display()
{
$docs = $this->getDocs();
dd($docs);
// TODO - Build view for API docs
return view('');
return view('api-docs.index', [
'docs' => $docs,
]);
}
/**

View File

@ -2,8 +2,11 @@
use BookStack\Entities\Book;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Exceptions\NotifyException;
use BookStack\Facades\Activity;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class BooksApiController extends ApiController
{
@ -41,8 +44,8 @@ class BooksApiController extends ApiController
}
/**
* Create a new book.
* @throws \Illuminate\Validation\ValidationException
* Create a new book in the system.
* @throws ValidationException
*/
public function create(Request $request)
{
@ -66,7 +69,7 @@ class BooksApiController extends ApiController
/**
* Update the details of a single book.
* @throws \Illuminate\Validation\ValidationException
* @throws ValidationException
*/
public function update(Request $request, string $id)
{
@ -81,9 +84,9 @@ class BooksApiController extends ApiController
}
/**
* Delete a book from the system.
* @throws \BookStack\Exceptions\NotifyException
* @throws \Illuminate\Contracts\Container\BindingResolutionException
* Delete a single book from the system.
* @throws NotifyException
* @throws BindingResolutionException
*/
public function delete(string $id)
{

View File

@ -0,0 +1,18 @@
import Code from "../services/code"
class DetailsHighlighter {
constructor(elem) {
this.elem = elem;
this.dealtWith = false;
elem.addEventListener('toggle', this.onToggle.bind(this));
}
onToggle() {
if (this.dealtWith) return;
Code.highlightWithin(this.elem);
this.dealtWith = true;
}
}
export default DetailsHighlighter;

View File

@ -30,6 +30,7 @@ import settingColorPicker from "./setting-color-picker";
import entityPermissionsEditor from "./entity-permissions-editor";
import templateManager from "./template-manager";
import newUserPassword from "./new-user-password";
import detailsHighlighter from "./details-highlighter";
const componentMapping = {
'dropdown': dropdown,
@ -64,6 +65,7 @@ const componentMapping = {
'entity-permissions-editor': entityPermissionsEditor,
'template-manager': templateManager,
'new-user-password': newUserPassword,
'details-highlighter': detailsHighlighter,
};
window.components = {};

View File

@ -87,9 +87,20 @@ const modeMap = {
* Highlight pre elements on a page
*/
function highlight() {
let codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre');
for (let i = 0; i < codeBlocks.length; i++) {
highlightElem(codeBlocks[i]);
const codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre');
for (const codeBlock of codeBlocks) {
highlightElem(codeBlock);
}
}
/**
* Highlight all code blocks within the given parent element
* @param {HTMLElement} parent
*/
function highlightWithin(parent) {
const codeBlocks = parent.querySelectorAll('pre');
for (const codeBlock of codeBlocks) {
highlightElem(codeBlock);
}
}
@ -308,6 +319,7 @@ function getMetaKey() {
export default {
highlight: highlight,
highlightWithin: highlightWithin,
wysiwygView: wysiwygView,
popupEditor: popupEditor,
setMode: setMode,

View File

@ -236,4 +236,26 @@
.tag-list div:last-child .tag-item {
margin-bottom: 0;
}
/**
* API Docs
*/
.api-method {
font-size: 0.75rem;
background-color: #888;
padding: $-xs;
line-height: 1.3;
opacity: 0.7;
vertical-align: top;
border-radius: 3px;
color: #FFF;
display: inline-block;
min-width: 60px;
text-align: center;
font-weight: bold;
&[data-method="GET"] { background-color: #077b70 }
&[data-method="POST"] { background-color: #cf4d03 }
&[data-method="PUT"] { background-color: #0288D1 }
&[data-method="DELETE"] { background-color: #ab0f0e }
}

View File

@ -213,6 +213,18 @@ blockquote {
}
}
.text-mono {
font-family: $mono;
}
.text-uppercase {
text-transform: uppercase;
}
.text-capitals {
text-transform: capitalize;
}
.code-base {
background-color: #F8F8F8;
font-size: 0.80em;

View File

@ -0,0 +1,51 @@
@extends('simple-layout')
@section('body')
<div class="container pt-xl">
<div class="grid right-focus reverse-collapse">
<div>
@foreach($docs as $model => $endpoints)
<p class="text-uppercase text-muted mb-xm mt-l"><strong>{{ $model }}</strong></p>
@foreach($endpoints as $endpoint)
<div class="mb-xs">
<a href="#{{ $endpoint['name'] }}" class="text-mono">
<span class="api-method" data-method="{{ $endpoint['method'] }}">{{ $endpoint['method'] }}</span>
/{{ $endpoint['uri'] }}
</a>
</div>
@endforeach
@endforeach
</div>
<div>
@foreach($docs as $model => $endpoints)
<section class="card content-wrap auto-height">
<h1 class="list-heading text-capitals">{{ $model }}</h1>
@foreach($endpoints as $endpoint)
<h5 id="{{ $endpoint['name'] }}" class="text-mono mb-m">
<span class="api-method" data-method="{{ $endpoint['method'] }}">{{ $endpoint['method'] }}</span>
{{ url($endpoint['uri']) }}
</h5>
<p class="mb-m">{{ $endpoint['description'] ?? '' }}</p>
@if($endpoint['example_response'] ?? false)
<details details-highlighter>
<summary class="text-muted">Example Response</summary>
<pre><code class="language-json">{{ $endpoint['example_response'] }}</code></pre>
</details>
<hr class="mt-m">
@endif
@endforeach
</section>
@endforeach
</div>
</div>
</div>
@stop