diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index ad3b41655..e9cd72fe2 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -31,11 +31,23 @@ class HomeController extends Controller $recentFactor = count($draftPages) > 0 ? 0.5 : 1; $recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 12*$recentFactor); $recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 12); - return view('home', [ + + // Custom homepage + $customHomepage = false; + $homepageSetting = setting('app-homepage'); + if ($homepageSetting) { + $id = intval(explode(':', $homepageSetting)[0]); + $customHomepage = $this->entityRepo->getById('page', $id); + $this->entityRepo->renderPage($customHomepage); + } + + $view = $customHomepage ? 'home-custom' : 'home'; + return view($view, [ 'activity' => $activity, 'recents' => $recents, 'recentlyUpdatedPages' => $recentlyUpdatedPages, - 'draftPages' => $draftPages + 'draftPages' => $draftPages, + 'customHomepage' => $customHomepage ]); } diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 573907e56..21572db29 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -167,7 +167,7 @@ class PageController extends Controller return view('pages/show', [ 'page' => $page,'book' => $page->book, 'current' => $page, 'sidebarTree' => $sidebarTree, - 'pageNav' => $pageNav, 'pageContent' => $pageContent]); + 'pageNav' => $pageNav]); } /** diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php index d87c40f9b..b2067ad7b 100644 --- a/app/Repos/EntityRepo.php +++ b/app/Repos/EntityRepo.php @@ -710,6 +710,7 @@ class EntityRepo $content = str_replace($matches[0][$index], trim($innerContent), $content); } + $page->renderedHTML = $content; return $content; } diff --git a/app/Services/ExportService.php b/app/Services/ExportService.php index 78cef41a4..40402dbce 100644 --- a/app/Services/ExportService.php +++ b/app/Services/ExportService.php @@ -27,9 +27,9 @@ class ExportService */ public function pageToContainedHtml(Page $page) { + $this->entityRepo->renderPage($page); $pageHtml = view('pages/export', [ - 'page' => $page, - 'pageContent' => $this->entityRepo->renderPage($page) + 'page' => $page ])->render(); return $this->containHtml($pageHtml); } @@ -74,9 +74,9 @@ class ExportService */ public function pageToPdf(Page $page) { + $this->entityRepo->renderPage($page); $html = view('pages/pdf', [ - 'page' => $page, - 'pageContent' => $this->entityRepo->renderPage($page) + 'page' => $page ])->render(); return $this->htmlToPdf($html); } diff --git a/app/Services/ViewService.php b/app/Services/ViewService.php index 3285745ce..770a9e39f 100644 --- a/app/Services/ViewService.php +++ b/app/Services/ViewService.php @@ -62,7 +62,7 @@ class ViewService $query->whereIn('viewable_type', $filterModel); } else if ($filterModel) { $query->where('viewable_type', '=', get_class($filterModel)); - }; + } return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable'); } diff --git a/resources/assets/js/components/entity-selector.js b/resources/assets/js/components/entity-selector.js index 57b2499cc..53358378a 100644 --- a/resources/assets/js/components/entity-selector.js +++ b/resources/assets/js/components/entity-selector.js @@ -68,8 +68,9 @@ class EntitySelector { onClick(event) { let t = event.target; + console.log('click', t); - if (t.matches('.entity-list a')) { + if (t.matches('.entity-list-item *')) { event.preventDefault(); event.stopPropagation(); let item = t.closest('[data-entity-type]'); @@ -84,12 +85,16 @@ class EntitySelector { let isDblClick = this.isDoubleClick(); let type = item.getAttribute('data-entity-type'); let id = item.getAttribute('data-entity-id'); - let isSelected = item.classList.contains('selected') || isDblClick; + let isSelected = !item.classList.contains('selected') || isDblClick; this.unselectAll(); this.input.value = isSelected ? `${type}:${id}` : ''; if (!isSelected) window.$events.emit('entity-select-change', null); + if (isSelected) { + item.classList.add('selected'); + item.classList.add('primary-background'); + } if (!isDblClick && !isSelected) return; let link = item.querySelector('.entity-list-item-link').getAttribute('href'); diff --git a/resources/assets/js/components/index.js b/resources/assets/js/components/index.js index f8025ac3d..988409fbc 100644 --- a/resources/assets/js/components/index.js +++ b/resources/assets/js/components/index.js @@ -9,6 +9,7 @@ let componentMapping = { 'entity-selector-popup': require('./entity-selector-popup'), 'entity-selector': require('./entity-selector'), 'sidebar': require('./sidebar'), + 'page-picker': require('./page-picker'), }; window.components = {}; diff --git a/resources/assets/js/components/page-picker.js b/resources/assets/js/components/page-picker.js new file mode 100644 index 000000000..e697d5f68 --- /dev/null +++ b/resources/assets/js/components/page-picker.js @@ -0,0 +1,60 @@ + +class PagePicker { + + constructor(elem) { + this.elem = elem; + this.input = elem.querySelector('input'); + this.resetButton = elem.querySelector('[page-picker-reset]'); + this.selectButton = elem.querySelector('[page-picker-select]'); + this.display = elem.querySelector('[page-picker-display]'); + this.defaultDisplay = elem.querySelector('[page-picker-default]'); + this.buttonSep = elem.querySelector('span.sep'); + + this.value = this.input.value; + this.setupListeners(); + } + + setupListeners() { + // Select click + this.selectButton.addEventListener('click', event => { + window.EntitySelectorPopup.show(entity => { + this.setValue(entity.id, entity.name); + }); + }); + + this.resetButton.addEventListener('click', event => { + this.setValue('', ''); + }); + } + + setValue(value, name) { + this.value = value; + this.input.value = value; + this.controlView(name); + } + + controlView(name) { + let hasValue = this.value && this.value !== 0; + toggleElem(this.resetButton, hasValue); + toggleElem(this.buttonSep, hasValue); + toggleElem(this.defaultDisplay, !hasValue); + toggleElem(this.display, hasValue); + if (hasValue) { + let id = this.getAssetIdFromVal(); + this.display.textContent = `#${id}, ${name}`; + this.display.href = window.baseUrl(`/link/${id}`); + } + } + + getAssetIdFromVal() { + return Number(this.value); + } + +} + +function toggleElem(elem, show) { + let display = (elem.tagName === 'BUTTON' || elem.tagName === 'SPAN') ? 'inline-block' : 'block'; + elem.style.display = show ? display : 'none'; +} + +module.exports = PagePicker; \ No newline at end of file diff --git a/resources/assets/sass/_forms.scss b/resources/assets/sass/_forms.scss index 657bbed17..700c15336 100644 --- a/resources/assets/sass/_forms.scss +++ b/resources/assets/sass/_forms.scss @@ -23,6 +23,11 @@ } } +.fake-input { + @extend .input-base; + overflow: auto; +} + #html-editor { display: none; } diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 3eec7737f..c4c8bfc78 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -31,6 +31,9 @@ return [ 'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.', 'app_primary_color' => 'Application primary color', 'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.', + 'app_homepage' => 'Application Homepage', + 'app_homepage_desc' => 'Select a page to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', + 'app_homepage_default' => 'Default homepage view chosen', /** * Registration settings diff --git a/resources/views/components/page-picker.blade.php b/resources/views/components/page-picker.blade.php new file mode 100644 index 000000000..91d8eb646 --- /dev/null +++ b/resources/views/components/page-picker.blade.php @@ -0,0 +1,13 @@ + +{{--Depends on entity selector popup--}} +<div page-picker> + <div class="input-base"> + <span @if($value) style="display: none" @endif page-picker-default class="text-muted italic">{{ $placeholder }}</span> + <a @if(!$value) style="display: none" @endif href="{{ baseUrl('/link/' . $value) }}" target="_blank" class="text-page" page-picker-display>#{{$value}}, {{$value ? \BookStack\Page::find($value)->name : '' }}</a> + </div> + <br> + <input type="hidden" value="{{$value}}" name="{{$name}}" id="{{$name}}"> + <button @if(!$value) style="display: none" @endif type="button" page-picker-reset class="text-button">{{ trans('common.reset') }}</button> + <span @if(!$value) style="display: none" @endif class="sep">|</span> + <button type="button" page-picker-select class="text-button">{{ trans('common.select') }}</button> +</div> \ No newline at end of file diff --git a/resources/views/home-custom.blade.php b/resources/views/home-custom.blade.php new file mode 100644 index 000000000..3d4616c4a --- /dev/null +++ b/resources/views/home-custom.blade.php @@ -0,0 +1,56 @@ +@extends('sidebar-layout') + +@section('toolbar') + <div class="col-sm-6 faded"> + <div class="action-buttons text-left"> + <a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button"><i class="zmdi zmdi-wrap-text"></i>{{ trans('common.toggle_details') }}</a> + </div> + </div> +@stop + +@section('sidebar') + @if(count($draftPages) > 0) + <div id="recent-drafts" class="card"> + <h3><i class="zmdi zmdi-edit"></i> {{ trans('entities.my_recent_drafts') }}</h3> + @include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact']) + </div> + @endif + + <div class="card"> + <h3><i class="zmdi zmdi-{{ $signedIn ? 'eye' : 'star-circle' }}"></i> {{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h3> + @include('partials/entity-list', [ + 'entities' => $recents, + 'style' => 'compact', + 'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty') + ]) + </div> + + <div class="card"> + <h3><i class="zmdi zmdi-file"></i> <a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h3> + <div id="recently-updated-pages"> + @include('partials/entity-list', [ + 'entities' => $recentlyUpdatedPages, + 'style' => 'compact', + 'emptyText' => trans('entities.no_pages_recently_updated') + ]) + </div> + </div> + + <div id="recent-activity" class="card"> + <h3><i class="zmdi zmdi-time"></i> {{ trans('entities.recent_activity') }}</h3> + @include('partials/activity-list', ['activity' => $activity]) + </div> +@stop + +@section('body') + <div class="page-content" ng-non-bindable> + @include('pages/page-display', ['page' => $customHomepage]) + </div> +@stop + +@section('scripts') + <script> + setupPageShow({{$customHomepage->id}}); + </script> +@stop + diff --git a/resources/views/pages/page-display.blade.php b/resources/views/pages/page-display.blade.php index cb7cae445..2f70c747d 100644 --- a/resources/views/pages/page-display.blade.php +++ b/resources/views/pages/page-display.blade.php @@ -7,6 +7,6 @@ @if (isset($diff) && $diff) {!! $diff !!} @else - {!! isset($pageContent) ? $pageContent : $page->html !!} + {!! isset($page->renderedHTML) ? $page->renderedHTML : $page->html !!} @endif </div> \ No newline at end of file diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index cd6a25493..09e480b43 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -71,6 +71,11 @@ <input type="text" value="{{ setting('app-color') }}" name="setting-app-color" id="setting-app-color" placeholder="#0288D1"> <input type="hidden" value="{{ setting('app-color-light') }}" name="setting-app-color-light" id="setting-app-color-light"> </div> + <div class="form-group" id="homepage-control"> + <label for="setting-app-homepage">{{ trans('settings.app_homepage') }}</label> + <p class="small">{{ trans('settings.app_homepage_desc') }}</p> + @include('components.page-picker', ['name' => 'setting-app-homepage', 'placeholder' => trans('settings.app_homepage_default'), 'value' => setting('app-homepage')]) + </div> </div> </div> @@ -140,6 +145,7 @@ </div> @include('components.image-manager', ['imageType' => 'system']) +@include('components.entity-selector-popup', ['entityTypes' => 'page']) @stop