Redoc search styling

This commit is contained in:
Roman Hotsiy 2017-01-28 18:47:12 +02:00
parent 18fe4bd748
commit 072ab15cae
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
11 changed files with 119 additions and 46 deletions

View File

@ -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">

View File

@ -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;

View File

@ -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>

View File

@ -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%);
}
}

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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;
}

View File

@ -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]);
}
});
}

View File

@ -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);

View File

@ -34,7 +34,7 @@ export interface MenuItem {
active?: boolean;
ready?: boolean;
level?: number;
depth?: number;
flatIdx?: number;
metadata?: any;

View File

@ -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;