Added page navigation and tweaked header styles

Changed header selection in editor to be more descriptive and
to provide a wider range of styles.

Closes #68
This commit is contained in:
Dan Brown 2016-09-18 14:49:36 +01:00
parent e0235fda8b
commit 1d681e53e4
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
11 changed files with 147 additions and 90 deletions

View File

@ -42,7 +42,7 @@ class PageController extends Controller
/**
* Show the form for creating a new page.
* @param $bookSlug
* @param string $bookSlug
* @param bool $chapterSlug
* @return Response
* @internal param bool $pageSlug
@ -61,8 +61,8 @@ class PageController extends Controller
/**
* Show form to continue editing a draft page.
* @param $bookSlug
* @param $pageId
* @param string $bookSlug
* @param int $pageId
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function editDraft($bookSlug, $pageId)
@ -112,8 +112,8 @@ class PageController extends Controller
* Display the specified page.
* If the page is not found via the slug the
* revisions are searched for a match.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return Response
*/
public function show($bookSlug, $pageSlug)
@ -131,14 +131,17 @@ class PageController extends Controller
$this->checkOwnablePermission('page-view', $page);
$sidebarTree = $this->bookRepo->getChildren($book);
$pageNav = $this->pageRepo->getPageNav($page);
Views::add($page);
$this->setPageTitle($page->getShortName());
return view('pages/show', ['page' => $page, 'book' => $book, 'current' => $page, 'sidebarTree' => $sidebarTree]);
return view('pages/show', ['page' => $page, 'book' => $book,
'current' => $page, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav]);
}
/**
* Get page from an ajax request.
* @param $pageId
* @param int $pageId
* @return \Illuminate\Http\JsonResponse
*/
public function getPageAjax($pageId)
@ -149,8 +152,8 @@ class PageController extends Controller
/**
* Show the form for editing the specified page.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return Response
*/
public function edit($bookSlug, $pageSlug)
@ -185,8 +188,8 @@ class PageController extends Controller
/**
* Update the specified page in storage.
* @param Request $request
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return Response
*/
public function update(Request $request, $bookSlug, $pageSlug)
@ -205,7 +208,7 @@ class PageController extends Controller
/**
* Save a draft update as a revision.
* @param Request $request
* @param $pageId
* @param int $pageId
* @return \Illuminate\Http\JsonResponse
*/
public function saveDraft(Request $request, $pageId)
@ -230,7 +233,7 @@ class PageController extends Controller
/**
* Redirect from a special link url which
* uses the page id rather than the name.
* @param $pageId
* @param int $pageId
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function redirectFromLink($pageId)
@ -241,8 +244,8 @@ class PageController extends Controller
/**
* Show the deletion page for the specified page.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\View\View
*/
public function showDelete($bookSlug, $pageSlug)
@ -257,8 +260,8 @@ class PageController extends Controller
/**
* Show the deletion page for the specified page.
* @param $bookSlug
* @param $pageId
* @param string $bookSlug
* @param int $pageId
* @return \Illuminate\View\View
* @throws NotFoundException
*/
@ -273,8 +276,8 @@ class PageController extends Controller
/**
* Remove the specified page from storage.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return Response
* @internal param int $id
*/
@ -291,8 +294,8 @@ class PageController extends Controller
/**
* Remove the specified draft page from storage.
* @param $bookSlug
* @param $pageId
* @param string $bookSlug
* @param int $pageId
* @return Response
* @throws NotFoundException
*/
@ -308,8 +311,8 @@ class PageController extends Controller
/**
* Shows the last revisions for this page.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\View\View
*/
public function showRevisions($bookSlug, $pageSlug)
@ -322,9 +325,9 @@ class PageController extends Controller
/**
* Shows a preview of a single revision
* @param $bookSlug
* @param $pageSlug
* @param $revisionId
* @param string $bookSlug
* @param string $pageSlug
* @param int $revisionId
* @return \Illuminate\View\View
*/
public function showRevision($bookSlug, $pageSlug, $revisionId)
@ -339,9 +342,9 @@ class PageController extends Controller
/**
* Restores a page using the content of the specified revision.
* @param $bookSlug
* @param $pageSlug
* @param $revisionId
* @param string $bookSlug
* @param string $pageSlug
* @param int $revisionId
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function restoreRevision($bookSlug, $pageSlug, $revisionId)
@ -357,8 +360,8 @@ class PageController extends Controller
/**
* Exports a page to pdf format using barryvdh/laravel-dompdf wrapper.
* https://github.com/barryvdh/laravel-dompdf
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\Http\Response
*/
public function exportPdf($bookSlug, $pageSlug)
@ -374,8 +377,8 @@ class PageController extends Controller
/**
* Export a page to a self-contained HTML file.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\Http\Response
*/
public function exportHtml($bookSlug, $pageSlug)
@ -391,8 +394,8 @@ class PageController extends Controller
/**
* Export a page to a simple plaintext .txt file.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\Http\Response
*/
public function exportPlainText($bookSlug, $pageSlug)
@ -434,8 +437,8 @@ class PageController extends Controller
/**
* Show the Restrictions view.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showRestrict($bookSlug, $pageSlug)
@ -452,8 +455,8 @@ class PageController extends Controller
/**
* Show the view to choose a new parent to move a page into.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @return mixed
* @throws NotFoundException
*/
@ -470,8 +473,8 @@ class PageController extends Controller
/**
* Does the action of moving the location of a page
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @param Request $request
* @return mixed
* @throws NotFoundException
@ -513,8 +516,8 @@ class PageController extends Controller
/**
* Set the permissions for this page.
* @param $bookSlug
* @param $pageSlug
* @param string $bookSlug
* @param string $pageSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/

View File

@ -7,6 +7,7 @@ use BookStack\Entity;
use BookStack\Exceptions\NotFoundException;
use Carbon\Carbon;
use DOMDocument;
use DOMXPath;
use Illuminate\Support\Str;
use BookStack\Page;
use BookStack\PageRevision;
@ -158,6 +159,35 @@ class PageRepo extends EntityRepo
return $page;
}
/**
* Parse te headers on the page to get a navigation menu
* @param Page $page
* @return array
*/
public function getPageNav(Page $page)
{
if ($page->html == '') return null;
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($page->html, 'HTML-ENTITIES', 'UTF-8'));
$xPath = new DOMXPath($doc);
$headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
if (is_null($headers)) return null;
$tree = [];
foreach ($headers as $header) {
$text = $header->nodeValue;
$tree[] = [
'nodeName' => strtolower($header->nodeName),
'level' => intval(str_replace('h', '', $header->nodeName)),
'link' => '#' . $header->getAttribute('id'),
'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
];
}
return $tree;
}
/**
* Formats a page's html to be tagged correctly
* within the system.

View File

@ -81,9 +81,10 @@ var mceOptions = module.exports = {
toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen",
content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
style_formats: [
{title: "Header 1", format: "h1"},
{title: "Header 2", format: "h2"},
{title: "Header 3", format: "h3"},
{title: "Header Large", format: "h2"},
{title: "Header Medium", format: "h3"},
{title: "Header Small", format: "h4"},
{title: "Header Tiny", format: "h5"},
{title: "Paragraph", format: "p", exact: true, classes: ''},
{title: "Blockquote", format: "blockquote"},
{title: "Code Block", icon: "code", format: "pre"},

View File

@ -1,5 +1,5 @@
.page-list {
h3 {
h4 {
margin: $-l 0 $-xs 0;
font-size: 1.666em;
}
@ -11,11 +11,13 @@
overflow: hidden;
margin-bottom: $-l;
}
h4 {
h5 {
display: block;
margin: $-s 0 0 0;
border-left: 5px solid $color-page;
padding: $-xs 0 $-xs $-m;
font-size: 1.1em;
font-weight: normal;
&.draft {
border-left-color: $color-page-draft;
}
@ -67,44 +69,39 @@
}
}
.page-nav-list {
.sidebar-page-nav {
$nav-indent: $-s;
margin-left: 2px;
list-style: none;
margin: $-s 0 $-m 2px;
border-left: 2px dotted #BBB;
li {
//border-left: 1px solid rgba(0, 0, 0, 0.1);
padding-left: $-xs;
border-left: 2px solid #888;
padding-left: $-s;
margin-bottom: 4px;
}
li a {
color: #555;
}
.nav-H2 {
margin-left: $nav-indent;
font-size: 0.95em;
}
.nav-H3 {
.h1 {
margin-left: -2px;
}
.h2 {
margin-left: -2px;
}
.h3 {
margin-left: $nav-indent;
}
.h4 {
margin-left: $nav-indent*2;
font-size: 0.90em
}
.nav-H4 {
.h5 {
margin-left: $nav-indent*3;
font-size: 0.85em
}
.nav-H5 {
.h6 {
margin-left: $nav-indent*4;
font-size: 0.80em
}
.nav-H6 {
margin-left: $nav-indent*5;
font-size: 0.75em
}
}
// Sidebar list
.book-tree {
padding: $-l 0 0 0;
padding: $-xs 0 0 0;
position: relative;
right: 0;
top: 0;
@ -306,10 +303,10 @@ ul.pagination {
}
.entity-list {
>div {
> div {
padding: $-m 0;
}
h3 {
h4 {
margin: 0;
}
p {
@ -327,9 +324,10 @@ ul.pagination {
color: $color-page-draft;
}
}
.entity-list.compact {
font-size: 0.6em;
h3, a {
h4, a {
line-height: 1.2;
}
p {

View File

@ -15,31 +15,41 @@ h2 {
margin-bottom: 0.43137255em;
}
h3 {
font-size: 1.75em;
font-size: 2.333em;
line-height: 1.571428572em;
margin-top: 0.78571429em;
margin-bottom: 0.43137255em;
}
h4 {
font-size: 1em;
font-size: 1.666em;
line-height: 1.375em;
margin-top: 0.78571429em;
margin-bottom: 0.43137255em;
}
h1, h2, h3, h4 {
h1, h2, h3, h4, h5, h6 {
font-weight: 400;
position: relative;
display: block;
color: #555;
.subheader {
//display: block;
font-size: 0.5em;
line-height: 1em;
color: lighten($text-dark, 32%);
}
}
h5 {
font-size: 1.4em;
}
h5, h6 {
font-weight: 500;
line-height: 1.2em;
margin-top: 0.78571429em;
margin-bottom: 0.66em;
}
/*
* Link styling
*/

View File

@ -1,5 +1,5 @@
<div class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}">
<h3 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}"><i class="zmdi zmdi-book"></i><span class="entity-list-item-name">{{$book->name}}</span></a></h3>
<h4 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}"><i class="zmdi zmdi-book"></i><span class="entity-list-item-name">{{$book->name}}</span></a></h4>
@if(isset($book->searchSnippet))
<p class="text-muted">{!! $book->searchSnippet !!}</p>
@else

View File

@ -1,5 +1,5 @@
<div class="chapter entity-list-item" data-entity-type="chapter" data-entity-id="{{$chapter->id}}">
<h3>
<h4>
@if (isset($showPath) && $showPath)
<a href="{{ $chapter->book->getUrl() }}" class="text-book">
<i class="zmdi zmdi-book"></i>{{ $chapter->book->name }}
@ -9,7 +9,7 @@
<a href="{{ $chapter->getUrl() }}" class="text-chapter entity-list-item-link">
<i class="zmdi zmdi-collection-bookmark"></i><span class="entity-list-item-name">{{ $chapter->name }}</span>
</a>
</h3>
</h4>
@if(isset($chapter->searchSnippet))
<p class="text-muted">{!! $chapter->searchSnippet !!}</p>
@else
@ -20,7 +20,7 @@
<p class="text-muted chapter-toggle"><i class="zmdi zmdi-caret-right"></i> <i class="zmdi zmdi-file-text"></i> <span>{{ count($chapter->pages) }} Pages</span></p>
<div class="inset-list">
@foreach($chapter->pages as $page)
<h4 class="@if($page->draft) draft @endif"><a href="{{ $page->getUrl() }}" class="text-page @if($page->draft) draft @endif"><i class="zmdi zmdi-file-text"></i>{{$page->name}}</a></h4>
<h5 class="@if($page->draft) draft @endif"><a href="{{ $page->getUrl() }}" class="text-page @if($page->draft) draft @endif"><i class="zmdi zmdi-file-text"></i>{{$page->name}}</a></h5>
@endforeach
</div>
@endif

View File

@ -25,14 +25,14 @@
<div class="col-sm-4">
<div id="recent-drafts">
@if(count($draftPages) > 0)
<h3>My Recent Drafts</h3>
<h4>My Recent Drafts</h4>
@include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact'])
@endif
</div>
@if($signedIn)
<h3>My Recently Viewed</h3>
<h4>My Recently Viewed</h4>
@else
<h3>Recent Books</h3>
<h4>Recent Books</h4>
@endif
@include('partials/entity-list', [
'entities' => $recents,
@ -42,7 +42,7 @@
</div>
<div class="col-sm-4">
<h3><a class="no-color" href="{{ baseUrl("/pages/recently-created") }}">Recently Created Pages</a></h3>
<h4><a class="no-color" href="{{ baseUrl("/pages/recently-created") }}">Recently Created Pages</a></h4>
<div id="recently-created-pages">
@include('partials/entity-list', [
'entities' => $recentlyCreatedPages,
@ -51,7 +51,7 @@
])
</div>
<h3><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">Recently Updated Pages</a></h3>
<h4><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">Recently Updated Pages</a></h4>
<div id="recently-updated-pages">
@include('partials/entity-list', [
'entities' => $recentlyUpdatedPages,
@ -62,7 +62,7 @@
</div>
<div class="col-sm-4" id="recent-activity">
<h3>Recent Activity</h3>
<h4>Recent Activity</h4>
@include('partials/activity-list', ['activity' => $activity])
</div>

View File

@ -1,7 +1,7 @@
<div class="page {{$page->draft ? 'draft' : ''}} entity-list-item" data-entity-type="page" data-entity-id="{{$page->id}}">
<h3>
<h4>
<a href="{{ $page->getUrl() }}" class="text-page entity-list-item-link"><i class="zmdi zmdi-file-text"></i><span class="entity-list-item-name">{{ $page->name }}</span></a>
</h3>
</h4>
@if(isset($page->searchSnippet))
<p class="text-muted">{!! $page->searchSnippet !!}</p>

View File

@ -114,7 +114,8 @@
@endif
</div>
@endif
@include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
@include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav])
</div>
</div>

View File

@ -1,5 +1,19 @@
<div class="book-tree" ng-non-bindable>
@if (isset($pageNav) && $pageNav)
<h6 class="text-muted">Page Navigation</h6>
<div class="sidebar-page-nav menu">
@foreach($pageNav as $navItem)
<li class="page-nav-item {{ $navItem['nodeName'] }}">
<a href="{{ $navItem['link'] }}">{{ $navItem['text'] }}</a>
</li>
@endforeach
</div>
@endif
<h6 class="text-muted">Book Navigation</h6>
<ul class="sidebar-page-list menu">
<li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li>