mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-25 18:13:44 +03:00
Redoc search styling
This commit is contained in:
parent
18fe4bd748
commit
072ab15cae
|
@ -8,8 +8,10 @@
|
|||
<div class="background-actual"> </div>
|
||||
</div>
|
||||
<div class="menu-content" sticky-sidebar [scrollParent]="options.$scrollParent" [scrollYOffset]="options.scrollYOffset">
|
||||
<api-logo> </api-logo>
|
||||
<redoc-search> </redoc-search>
|
||||
<div class="menu-header">
|
||||
<api-logo> </api-logo>
|
||||
<redoc-search> </redoc-search>
|
||||
</div>
|
||||
<side-menu> </side-menu>
|
||||
</div>
|
||||
<div class="api-content">
|
||||
|
|
|
@ -40,12 +40,17 @@
|
|||
|
||||
.menu-content {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
side-menu {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
[sticky-sidebar] {
|
||||
width: $side-bar-width;
|
||||
background-color: $side-bar-bg-color;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
transform: translateZ(0);
|
||||
z-index: 75;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<input #search (keyup)="update(search.value)" placeholder="Search">
|
||||
<ul class="search-results">
|
||||
<li class="result" *ngFor="let item of items" (click)="clickSearch(item)">
|
||||
{{item?.menuItem?.name}}
|
||||
<div class="search-input-wrap">
|
||||
<input #search (keyup)="update(search.value)" placeholder="Search">
|
||||
</div>
|
||||
<ul class="search-results" [hidden]="!items.length">
|
||||
<li class="result" *ngFor="let item of items"
|
||||
ngClass="menu-item-depth-{{item.menuItem.depth}} {{item.menuItem.ready ? '' : 'disabled'}}"
|
||||
(click)="clickSearch(item)">
|
||||
{{item.menuItem.name}}
|
||||
<li>
|
||||
</ul>
|
||||
|
|
|
@ -1,22 +1,61 @@
|
|||
@import '../../shared/styles/variables';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
padding: 20px;
|
||||
background: silver;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.search-input-wrap {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
|
||||
border: 0;
|
||||
border-bottom: 1px solid darken($side-bar-bg-color, 10%);
|
||||
font-weight: bold;
|
||||
|
||||
font-size: 13px;
|
||||
color: $text-color;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
margin: 10px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
padding: 10px 0;
|
||||
background-color: darken($side-bar-bg-color, 5%);
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
border-bottom: 1px solid darken($side-bar-bg-color, 10%);
|
||||
border-top: 1px solid darken($side-bar-bg-color, 10%);
|
||||
|
||||
min-height: 150px;
|
||||
max-height: 250px;
|
||||
|
||||
> li {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
font-family: Montserrat, sans-serif;
|
||||
font-size: 13px;
|
||||
padding: 5px 20px;
|
||||
|
||||
&:hover {
|
||||
background-color: darken($side-bar-bg-color, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
li.menu-item-depth-1 {
|
||||
color: #0033a0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
> li.disabled {
|
||||
cursor: default;
|
||||
color: lighten($text-color, 60%);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, HostBinding } from '@angular/core';
|
||||
import { Marker, SearchService, MenuService } from '../../services/';
|
||||
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, HostBinding } from '@angular/core';
|
||||
import { Marker, SearchService, MenuService, MenuItem } from '../../services/';
|
||||
|
||||
@Component({
|
||||
selector: 'redoc-search',
|
||||
|
@ -10,9 +10,16 @@ import { Marker, SearchService, MenuService } from '../../services/';
|
|||
})
|
||||
export class RedocSearch implements OnInit {
|
||||
logo:any = {};
|
||||
items: any[] = [];
|
||||
items: { menuItem: MenuItem, pointers: string[] }[] = [];
|
||||
|
||||
constructor(private marker: Marker, public search: SearchService, public menu: MenuService) {
|
||||
_subscription;
|
||||
|
||||
constructor(
|
||||
cdr: ChangeDetectorRef,
|
||||
private marker: Marker,
|
||||
public search: SearchService,
|
||||
public menu: MenuService) {
|
||||
this._subscription = menu.changed.subscribe(() => cdr.detectChanges());
|
||||
}
|
||||
|
||||
init() {
|
||||
|
@ -25,6 +32,11 @@ export class RedocSearch implements OnInit {
|
|||
menuItem: this.menu.getItemById(id),
|
||||
pointers: searchRes[id].map(el => el.pointer)
|
||||
}));
|
||||
this.items.sort((a, b) => {
|
||||
if (a.menuItem.depth > b.menuItem.depth) return 1;
|
||||
else if (a.menuItem.depth < b.menuItem.depth) return -1;
|
||||
else return 0;
|
||||
});
|
||||
this.marker.mark(val);
|
||||
}
|
||||
|
||||
|
@ -40,4 +52,8 @@ export class RedocSearch implements OnInit {
|
|||
ngOnInit() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
<div #mobile class="mobile-nav" (click)="toggleMobileNav()">
|
||||
<span class="menu-header"> API Reference: </span>
|
||||
<span class="selected-item-info">
|
||||
<span class="selected-tag"> {{activeCatCaption}} </span>
|
||||
<span class="selected-endpoint">{{activeItemCaption}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div #desktop id="resources-nav">
|
||||
<h5 class="menu-header"> API reference </h5>
|
||||
<ul class="menu-root">
|
||||
<side-menu-items [items]="menuItems" (activate)="activateAndScroll($event)"></side-menu-items>
|
||||
</ul>
|
||||
|
|
|
@ -11,13 +11,6 @@ ul.menu-root {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.menu-header {
|
||||
text-transform: uppercase;
|
||||
color: $headers-color;
|
||||
padding: 0 $side-menu-item-hpadding;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.mobile-nav {
|
||||
display: none;
|
||||
height: 3em;
|
||||
|
@ -39,15 +32,6 @@ ul.menu-root {
|
|||
float: right;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.menu-header {
|
||||
padding: 0 10px 0 20px;
|
||||
font-size: 0.95em;
|
||||
|
||||
@media (max-width: $mobile-menu-compact-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $side-menu-mobile-breakpoint) {
|
||||
|
@ -61,10 +45,6 @@ ul.menu-root {
|
|||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#resources-nav .menu-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-subitems {
|
||||
height: auto;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ export abstract class BaseSearchableComponent extends BaseComponent implements O
|
|||
subscribeForSearch() {
|
||||
this.searchSubscription = this.app.searchContainingPointers.subscribe(ptrs => {
|
||||
for (let i = 0; i < ptrs.length; ++i) {
|
||||
this.ensureSearchIsShown(ptrs[i]);
|
||||
if (ptrs[i]) this.ensureSearchIsShown(ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export class AppStateService {
|
|||
loading = new Subject<boolean>();
|
||||
initialized = new BehaviorSubject<any>(false);
|
||||
|
||||
searchContainingPointers = new BehaviorSubject<string[]>([]);
|
||||
searchContainingPointers = new BehaviorSubject<string|null[]>([]);
|
||||
|
||||
startLoading() {
|
||||
this.loading.next(true);
|
||||
|
|
|
@ -34,7 +34,7 @@ export interface MenuItem {
|
|||
active?: boolean;
|
||||
ready?: boolean;
|
||||
|
||||
level?: number;
|
||||
depth?: number;
|
||||
flatIdx?: number;
|
||||
|
||||
metadata?: any;
|
||||
|
|
|
@ -2,6 +2,14 @@ import { Injectable } from '@angular/core';
|
|||
import { AppStateService } from './app-state.service';
|
||||
import { SchemaNormalizer } from './schema-normalizer.service';
|
||||
import { JsonPointer, groupBy, SpecManager, StringMap, snapshot } from '../utils/';
|
||||
import * as slugify from 'slugify';
|
||||
|
||||
import {
|
||||
Spec as SwaggerSpec,
|
||||
Operation as SwaggerOperation,
|
||||
Schema as SwaggerSchema,
|
||||
BodyParameter
|
||||
} from '@types/swagger-schema-official';
|
||||
|
||||
import * as lunr from 'lunr';
|
||||
|
||||
|
@ -12,6 +20,10 @@ interface IndexElement {
|
|||
pointer: string;
|
||||
}
|
||||
|
||||
interface SwaggerSchemaExt extends SwaggerSchema {
|
||||
_pointer?: string;
|
||||
}
|
||||
|
||||
const index = lunr(function () {
|
||||
//this.field('menuId', {boost: 0});
|
||||
this.field('title', {boost: 1.5});
|
||||
|
@ -28,12 +40,13 @@ export class SearchService {
|
|||
this.normalizer = new SchemaNormalizer(spec);
|
||||
}
|
||||
|
||||
ensureSearchVisible(containingPointers: string[]) {
|
||||
ensureSearchVisible(containingPointers: string|null[]) {
|
||||
this.app.searchContainingPointers.next(containingPointers);
|
||||
}
|
||||
|
||||
indexAll() {
|
||||
this.indexPaths(this.spec.schema);
|
||||
this.indexTags(this.spec.schema);
|
||||
}
|
||||
|
||||
search(q):StringMap<IndexElement[]> {
|
||||
|
@ -53,7 +66,21 @@ export class SearchService {
|
|||
store[element.pointer] = element;
|
||||
}
|
||||
|
||||
indexPaths(swagger:any) {
|
||||
indexTags(swagger:SwaggerSpec) {
|
||||
let tags = swagger.tags;
|
||||
for (let tag of tags) {
|
||||
if (tag['x-traitTag']) continue;
|
||||
let id = `tag/${slugify(tag.name)}`;
|
||||
this.index({
|
||||
menuId: id,
|
||||
title: tag.name,
|
||||
body: tag.description,
|
||||
pointer: id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
indexPaths(swagger:SwaggerSpec) {
|
||||
const paths = swagger.paths;
|
||||
const basePtr = '#/paths';
|
||||
Object.keys(paths).forEach(path => {
|
||||
|
@ -66,7 +93,7 @@ export class SearchService {
|
|||
});
|
||||
}
|
||||
|
||||
indexOperation(operation:any, operationPointer:string) {
|
||||
indexOperation(operation:SwaggerOperation, operationPointer:string) {
|
||||
this.index({
|
||||
pointer: operationPointer,
|
||||
menuId: operationPointer,
|
||||
|
@ -77,7 +104,7 @@ export class SearchService {
|
|||
this.indexOperationParameters(operation, operationPointer);
|
||||
}
|
||||
|
||||
indexOperationParameters(operation: any, operationPointer: string) {
|
||||
indexOperationParameters(operation: SwaggerOperation, operationPointer: string) {
|
||||
const parameters = operation.parameters;
|
||||
if (!parameters) return;
|
||||
for (let i=0; i<parameters.length; ++i) {
|
||||
|
@ -92,12 +119,13 @@ export class SearchService {
|
|||
|
||||
if (param.in === 'body') {
|
||||
this.normalizer.reset();
|
||||
this.indexSchema(param.schema, '', JsonPointer.join(paramPointer, ['schema']), operationPointer);
|
||||
this.indexSchema((<BodyParameter>param).schema,
|
||||
'', JsonPointer.join(paramPointer, ['schema']), operationPointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
indexOperationResponses(operation:any, operationPtr:string) {
|
||||
indexOperationResponses(operation:SwaggerOperation, operationPtr:string) {
|
||||
const responses = operation.responses;
|
||||
if (!responses) return;
|
||||
Object.keys(responses).forEach(code => {
|
||||
|
@ -117,7 +145,8 @@ export class SearchService {
|
|||
});
|
||||
}
|
||||
|
||||
indexSchema(_schema:any, name: string, absolutePointer: string, menuPointer: string, parent?: string) {
|
||||
indexSchema(_schema:SwaggerSchemaExt, name: string, absolutePointer: string,
|
||||
menuPointer: string, parent?: string) {
|
||||
if (!_schema) return;
|
||||
let schema = _schema;
|
||||
let title = name;
|
||||
|
|
Loading…
Reference in New Issue
Block a user