mirror of
https://github.com/Redocly/redoc.git
synced 2025-06-05 05:23:07 +03:00
Refactor menu
This commit is contained in:
parent
08a46846bc
commit
a5959bdf55
|
@ -19,5 +19,6 @@ a.openapi-button {
|
||||||
}
|
}
|
||||||
|
|
||||||
:host [section] {
|
:host [section] {
|
||||||
padding-top: 80px;
|
padding-top: 60px;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $secondary-color;
|
||||||
|
}
|
||||||
|
|
||||||
responses-list, params-list {
|
responses-list, params-list {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export class Method extends BaseComponent {
|
||||||
if (this.componentSchema.operationId) {
|
if (this.componentSchema.operationId) {
|
||||||
this.method.anchor = 'operation/' + encodeURIComponent(this.componentSchema.operationId);
|
this.method.anchor = 'operation/' + encodeURIComponent(this.componentSchema.operationId);
|
||||||
} else {
|
} else {
|
||||||
this.method.anchor = 'tag/' + encodeURIComponent(this.tag + this.pointer);
|
this.method.anchor = this.tag + encodeURIComponent(this.pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="methods">
|
<div class="methods">
|
||||||
<div class="tag" *ngFor="let tag of tags;trackBy:trackByTagName">
|
<div class="tag" *ngFor="let tag of tags;trackBy:trackByTagName">
|
||||||
<div class="tag-info" [attr.section]="tag.name" *ngIf="!tag.virtual">
|
<div class="tag-info" [attr.section]="tag.id" *ngIf="!tag.virtual">
|
||||||
<h1 class="sharable-header"> <a class="share-link" href="#section/{{tag.name | encodeURIComponent}}"></a>{{tag.name}} </h1>
|
<h1 class="sharable-header"> <a class="share-link" href="#tag/{{tag.name | encodeURIComponent}}"></a>{{tag.name}} </h1>
|
||||||
<p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p>
|
<p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p>
|
||||||
</div>
|
</div>
|
||||||
<method *ngFor="let method of tag.methods;trackBy:trackByPointer" [pointer]="method.pointer" [attr.pointer]="method.pointer"
|
<method *ngFor="let method of tag.methods;trackBy:trackByPointer" [pointer]="method.pointer" [attr.pointer]="method.pointer"
|
||||||
|
|
|
@ -27,7 +27,7 @@ export class MethodsList extends BaseComponent {
|
||||||
// inject tag name into method info
|
// inject tag name into method info
|
||||||
tagInfo.methods = tagInfo.methods || [];
|
tagInfo.methods = tagInfo.methods || [];
|
||||||
tagInfo.methods.forEach(method => {
|
tagInfo.methods.forEach(method => {
|
||||||
method.tag = tagInfo.name;
|
method.tag = tagInfo.id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div #desktop id="resources-nav">
|
<div #desktop id="resources-nav">
|
||||||
<h5 class="menu-header" (click)="onclk()"> API reference </h5>
|
<h5 class="menu-header"> API reference </h5>
|
||||||
<div *ngFor="let cat of categories; let idx = index" class="menu-cat">
|
<div *ngFor="let cat of categories; let idx = index" class="menu-cat">
|
||||||
|
|
||||||
<label class="menu-cat-header" (click)="activateAndScroll(idx, -1)" [hidden]="cat.headless"
|
<label class="menu-cat-header" (click)="activateAndScroll(idx, -1)" [hidden]="cat.headless"
|
||||||
|
|
|
@ -79,7 +79,7 @@ export function RedocComponent(options) {
|
||||||
*/
|
*/
|
||||||
export class BaseComponent implements OnInit, OnDestroy {
|
export class BaseComponent implements OnInit, OnDestroy {
|
||||||
componentSchema: any = null;
|
componentSchema: any = null;
|
||||||
pointer: String;
|
pointer: string;
|
||||||
dereferencedCache = {};
|
dereferencedCache = {};
|
||||||
|
|
||||||
constructor(public specMgr: SpecManager) {
|
constructor(public specMgr: SpecManager) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ describe('Menu service', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should scroll to method when location hash is present [jp]', (done) => {
|
it('should scroll to method when location hash is present [jp]', (done) => {
|
||||||
let hash = '#section/pet/paths/~1pet~1findByStatus/get';
|
let hash = '#tag/pet/paths/~1pet~1findByStatus/get';
|
||||||
spyOn(menu, 'hashScroll').and.callThrough();
|
spyOn(menu, 'hashScroll').and.callThrough();
|
||||||
spyOn(window, 'scrollTo').and.stub();
|
spyOn(window, 'scrollTo').and.stub();
|
||||||
hashService.changed.subscribe(() => {
|
hashService.changed.subscribe(() => {
|
||||||
|
|
|
@ -55,7 +55,7 @@ export class MenuService {
|
||||||
|
|
||||||
getCurrentMethodEl() {
|
getCurrentMethodEl() {
|
||||||
return this.getMethodElByPtr(this.activeMethodPtr,
|
return this.getMethodElByPtr(this.activeMethodPtr,
|
||||||
this.categories[this.activeCatIdx].name);
|
this.categories[this.activeCatIdx].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMethodElByPtr(ptr, section) {
|
getMethodElByPtr(ptr, section) {
|
||||||
|
@ -141,10 +141,11 @@ export class MenuService {
|
||||||
let ptr = decodeURIComponent(hash.substr(namespace.length + 1));
|
let ptr = decodeURIComponent(hash.substr(namespace.length + 1));
|
||||||
if (namespace === 'operation') {
|
if (namespace === 'operation') {
|
||||||
$el = this.getMethodElByOperId(ptr);
|
$el = this.getMethodElByOperId(ptr);
|
||||||
} else if (namespace === 'section') {
|
} else {
|
||||||
let tag = ptr.split('/')[0];
|
let sectionId = ptr.split('/')[0];
|
||||||
ptr = ptr.substr(tag.length);
|
ptr = ptr.substr(sectionId.length) || null;
|
||||||
$el = this.getMethodElByPtr(ptr, tag);
|
sectionId = namespace + (sectionId ? '/' + sectionId : '');
|
||||||
|
$el = this.getMethodElByPtr(ptr, sectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($el) this.scrollService.scrollTo($el);
|
if ($el) this.scrollService.scrollTo($el);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { JsonPointer } from '../utils/JsonPointer';
|
import { JsonPointer } from '../utils/JsonPointer';
|
||||||
import { SpecManager } from '../utils/SpecManager';
|
import { SpecManager } from '../utils/SpecManager';
|
||||||
import {methods as swaggerMethods} from '../utils/swagger-defs';
|
import {methods as swaggerMethods} from '../utils/swagger-defs';
|
||||||
|
import slugify from 'slugify';
|
||||||
|
|
||||||
interface PropertyPreprocessOptions {
|
interface PropertyPreprocessOptions {
|
||||||
childFor: string;
|
childFor: string;
|
||||||
|
@ -16,6 +17,7 @@ export interface MenuMethod {
|
||||||
|
|
||||||
export interface MenuCategory {
|
export interface MenuCategory {
|
||||||
name: string;
|
name: string;
|
||||||
|
id: string;
|
||||||
|
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
methods?: Array<MenuMethod>;
|
methods?: Array<MenuMethod>;
|
||||||
|
@ -245,14 +247,17 @@ export class SchemaHelper {
|
||||||
let tag2MethodMapping = {};
|
let tag2MethodMapping = {};
|
||||||
|
|
||||||
for (let header of (<Array<string>>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) {
|
for (let header of (<Array<string>>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) {
|
||||||
tag2MethodMapping[header] = {
|
let id = 'section/' + slugify(header);
|
||||||
name: header, virtual: true, methods: []
|
tag2MethodMapping[id] = {
|
||||||
|
name: header, id: id, virtual: true, methods: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let tag of schema.tags || []) {
|
for (let tag of schema.tags || []) {
|
||||||
tag2MethodMapping[tag.name] = {
|
let id = 'tag/' + slugify(tag.name);
|
||||||
|
tag2MethodMapping[id] = {
|
||||||
name: tag.name,
|
name: tag.name,
|
||||||
|
id: id,
|
||||||
description: tag.description,
|
description: tag.description,
|
||||||
headless: tag.name === '',
|
headless: tag.name === '',
|
||||||
empty: !!tag['x-traitTag'],
|
empty: !!tag['x-traitTag'],
|
||||||
|
@ -273,13 +278,15 @@ export class SchemaHelper {
|
||||||
let methodPointer = JsonPointer.compile(['paths', path, method]);
|
let methodPointer = JsonPointer.compile(['paths', path, method]);
|
||||||
let methodSummary = SchemaHelper.methodSummary(methodInfo);
|
let methodSummary = SchemaHelper.methodSummary(methodInfo);
|
||||||
for (let tag of tags) {
|
for (let tag of tags) {
|
||||||
let tagDetails = tag2MethodMapping[tag];
|
let id = 'tag/' + slugify(tag);
|
||||||
if (!tag2MethodMapping[tag]) {
|
let tagDetails = tag2MethodMapping[id];
|
||||||
|
if (!tagDetails) {
|
||||||
tagDetails = {
|
tagDetails = {
|
||||||
name: tag,
|
name: tag,
|
||||||
|
id: id,
|
||||||
headless: tag === ''
|
headless: tag === ''
|
||||||
};
|
};
|
||||||
tag2MethodMapping[tag] = tagDetails;
|
tag2MethodMapping[id] = tagDetails;
|
||||||
}
|
}
|
||||||
if (tagDetails.empty) continue;
|
if (tagDetails.empty) continue;
|
||||||
if (!tagDetails.methods) tagDetails.methods = [];
|
if (!tagDetails.methods) tagDetails.methods = [];
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sharable-header {
|
|
||||||
color: $secondary-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sharable-header:hover .share-link:before, .share-link:hover:before {
|
.sharable-header:hover .share-link:before, .share-link:hover:before {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import JsonSchemaRefParser from 'json-schema-ref-parser';
|
import JsonSchemaRefParser from 'json-schema-ref-parser';
|
||||||
import JsonPointer from './JsonPointer';
|
import JsonPointer from './JsonPointer';
|
||||||
import { renderMd, safePush } from './helpers';
|
import { renderMd, safePush } from './helpers';
|
||||||
|
import slugify from 'slugify';
|
||||||
|
|
||||||
export class SpecManager {
|
export class SpecManager {
|
||||||
public _schema:any = {};
|
public _schema:any = {};
|
||||||
|
@ -52,7 +53,8 @@ export class SpecManager {
|
||||||
open: (tokens, idx) => {
|
open: (tokens, idx) => {
|
||||||
let content = tokens[idx + 1].content;
|
let content = tokens[idx + 1].content;
|
||||||
safePush(this._schema.info, 'x-redoc-markdown-headers', content);
|
safePush(this._schema.info, 'x-redoc-markdown-headers', content);
|
||||||
return `<h${tokens[idx].hLevel} section="${content}">` +
|
content = slugify(content);
|
||||||
|
return `<h${tokens[idx].hLevel} section="section/${content}">` +
|
||||||
`<a class="share-link" href="#section/${content}"></a>`;
|
`<a class="share-link" href="#section/${content}"></a>`;
|
||||||
},
|
},
|
||||||
close: (tokens, idx) => {
|
close: (tokens, idx) => {
|
||||||
|
|
|
@ -43,7 +43,7 @@ describe('Scroll sync', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update active menu entries on page scroll forwards', () => {
|
it('should update active menu entries on page scroll forwards', () => {
|
||||||
scrollToEl('[tag="store"]').then(() => {
|
scrollToEl('[section="tag/store"]').then(() => {
|
||||||
expect($('.menu-cat-header.active').getInnerHtml()).toContain('store');
|
expect($('.menu-cat-header.active').getInnerHtml()).toContain('store');
|
||||||
expect($('.selected-tag').getInnerHtml()).toContain('store');
|
expect($('.selected-tag').getInnerHtml()).toContain('store');
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user