mirror of
				https://github.com/Redocly/redoc.git
				synced 2025-11-04 01:37:32 +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