From 26a3cb8b7e36a421c4491ad987e053d96ee84075 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 6 Aug 2026 15:32:17 +0100 Subject: [PATCH 01/21] Views: Started implementation of new sidebar back-end --- .../Providers/ViewTweaksServiceProvider.php | 2 + app/Entities/Controllers/BookController.php | 2 - app/View/SidebarSection.php | 16 ++++++ app/View/SidebarSectionInterface.php | 20 ++++++++ app/View/SidebarSectionManager.php | 51 +++++++++++++++++++ .../SidebarSections/BooksIndexRecents.php | 26 ++++++++++ resources/views/books/index.blade.php | 4 +- 7 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 app/View/SidebarSection.php create mode 100644 app/View/SidebarSectionInterface.php create mode 100644 app/View/SidebarSectionManager.php create mode 100644 app/View/SidebarSections/BooksIndexRecents.php diff --git a/app/App/Providers/ViewTweaksServiceProvider.php b/app/App/Providers/ViewTweaksServiceProvider.php index 6771e513f..d2d45abcc 100644 --- a/app/App/Providers/ViewTweaksServiceProvider.php +++ b/app/App/Providers/ViewTweaksServiceProvider.php @@ -4,6 +4,7 @@ namespace BookStack\App\Providers; use BookStack\Entities\BreadcrumbsViewComposer; use BookStack\Util\DateFormatter; +use BookStack\View\SidebarSectionManager; use Illuminate\Pagination\Paginator; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\View; @@ -33,6 +34,7 @@ class ViewTweaksServiceProvider extends ServiceProvider // View Globals View::share('dates', $this->app->make(DateFormatter::class)); + View::share('sidebar', $this->app->make(SidebarSectionManager::class)); // Custom blade view directives Blade::directive('icon', function ($expression) { diff --git a/app/Entities/Controllers/BookController.php b/app/Entities/Controllers/BookController.php index 98470d91c..9fa64d293 100644 --- a/app/Entities/Controllers/BookController.php +++ b/app/Entities/Controllers/BookController.php @@ -53,7 +53,6 @@ class BookController extends Controller $books = $this->queries->visibleForListWithCover() ->orderBy($listOptions->getSort(), $listOptions->getOrder()) ->paginate(setting()->getInteger('lists-page-count-books', 18, 1, 1000)); - $recents = $this->isSignedIn() ? $this->queries->recentlyViewedForCurrentUser()->take(4)->get() : false; $popular = $this->queries->popularForList()->take(4)->get(); $new = $this->queries->visibleForList()->orderBy('created_at', 'desc')->take(4)->get(); @@ -63,7 +62,6 @@ class BookController extends Controller return view('books.index', [ 'books' => $books, - 'recents' => $recents, 'popular' => $popular, 'new' => $new, 'view' => $view, diff --git a/app/View/SidebarSection.php b/app/View/SidebarSection.php new file mode 100644 index 000000000..68e1aa291 --- /dev/null +++ b/app/View/SidebarSection.php @@ -0,0 +1,16 @@ +view; + } +} diff --git a/app/View/SidebarSectionInterface.php b/app/View/SidebarSectionInterface.php new file mode 100644 index 000000000..84032ab61 --- /dev/null +++ b/app/View/SidebarSectionInterface.php @@ -0,0 +1,20 @@ + + */ + public function withData(array $viewData, Request $request): array; +} diff --git a/app/View/SidebarSectionManager.php b/app/View/SidebarSectionManager.php new file mode 100644 index 000000000..82af3721e --- /dev/null +++ b/app/View/SidebarSectionManager.php @@ -0,0 +1,51 @@ +[]>> + */ + protected array $sectionByLocation = [ + 'books-index' => [ + 'left' => [ + BooksIndexRecents::class, + ] + ], + ]; + + /** + * Register a sidebar section to be displayed at the given location and position. + * @param class-string $sectionClass + */ + public function register(string $location, string $position, string $sectionClass): void + { + if (!isset($this->sectionByLocation[$location])) { + $this->sectionByLocation[$location] = []; + } + + if (!isset($this->sectionByLocation[$location][$position])) { + $this->sectionByLocation[$location][$position] = []; + } + + $this->sectionByLocation[$location][$position][] = $sectionClass; + } + + /** + * Get all sidebar sections registered for a given location. + * + * @return SidebarSectionInterface[] + * @throws BindingResolutionException + */ + public function getSectionsForLocation(string $location, string $position): array + { + $sections = array_unique($this->sectionByLocation[$location][$position] ?? []); + return array_map(function (string $className) { + return app()->make($className); + }, $sections); + } +} diff --git a/app/View/SidebarSections/BooksIndexRecents.php b/app/View/SidebarSections/BooksIndexRecents.php new file mode 100644 index 000000000..485e6d431 --- /dev/null +++ b/app/View/SidebarSections/BooksIndexRecents.php @@ -0,0 +1,26 @@ +isGuest(); + $recents = $userSignedIn ? $this->queries->recentlyViewedForCurrentUser()->take(4)->get() : null; + return [ + 'recents' => $recents, + ]; + } +} diff --git a/resources/views/books/index.blade.php b/resources/views/books/index.blade.php index 660c008df..60152410c 100644 --- a/resources/views/books/index.blade.php +++ b/resources/views/books/index.blade.php @@ -5,7 +5,9 @@ @stop @section('left') - @include('books.parts.index-sidebar-section-recents', ['recents' => $recents]) + @foreach($sidebar->getSectionsForLocation('books-index', 'left') as $section) + @include($section->getView(), $section->withData(get_defined_vars(), request())) + @endforeach @include('books.parts.index-sidebar-section-popular', ['popular' => $popular]) @include('books.parts.index-sidebar-section-new', ['new' => $new]) @stop From dead0bfb5fd5b725230a5020973ddd4fa9560a95 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 7 Aug 2026 08:32:27 +0100 Subject: [PATCH 02/21] Views: Extracted books index/show sidebar sections --- app/Entities/Controllers/BookController.php | 15 +-------- app/View/SidebarSectionManager.php | 28 +++++++++++++++- .../SidebarSections/BooksIndexActions.php | 18 +++++++++++ app/View/SidebarSections/BooksIndexNew.php | 29 +++++++++++++++++ .../SidebarSections/BooksIndexPopular.php | 24 ++++++++++++++ app/View/SidebarSections/BooksShowActions.php | 24 ++++++++++++++ .../SidebarSections/BooksShowActivity.php | 28 ++++++++++++++++ app/View/SidebarSections/BooksShowDetails.php | 32 +++++++++++++++++++ .../SidebarSections/BooksShowSearchForm.php | 18 +++++++++++ app/View/SidebarSections/BooksShowShelves.php | 23 +++++++++++++ app/View/SidebarSections/BooksShowTags.php | 18 +++++++++++ resources/views/books/index.blade.php | 8 ++--- .../show-sidebar-section-details.blade.php | 2 +- .../show-sidebar-section-shelves.blade.php | 4 +-- resources/views/books/show.blade.php | 13 +++----- .../views/common/sidebar-sections.blade.php | 11 +++++++ 16 files changed, 262 insertions(+), 33 deletions(-) create mode 100644 app/View/SidebarSections/BooksIndexActions.php create mode 100644 app/View/SidebarSections/BooksIndexNew.php create mode 100644 app/View/SidebarSections/BooksIndexPopular.php create mode 100644 app/View/SidebarSections/BooksShowActions.php create mode 100644 app/View/SidebarSections/BooksShowActivity.php create mode 100644 app/View/SidebarSections/BooksShowDetails.php create mode 100644 app/View/SidebarSections/BooksShowSearchForm.php create mode 100644 app/View/SidebarSections/BooksShowShelves.php create mode 100644 app/View/SidebarSections/BooksShowTags.php create mode 100644 resources/views/common/sidebar-sections.blade.php diff --git a/app/Entities/Controllers/BookController.php b/app/Entities/Controllers/BookController.php index 9fa64d293..aa4f99daa 100644 --- a/app/Entities/Controllers/BookController.php +++ b/app/Entities/Controllers/BookController.php @@ -2,10 +2,8 @@ namespace BookStack\Entities\Controllers; -use BookStack\Activity\ActivityQueries; use BookStack\Activity\ActivityType; use BookStack\Activity\Models\View; -use BookStack\Activity\Tools\UserEntityWatchOptions; use BookStack\Entities\Queries\BookQueries; use BookStack\Entities\Queries\BookshelfQueries; use BookStack\Entities\Queries\EntityQueries; @@ -19,7 +17,6 @@ use BookStack\Exceptions\NotFoundException; use BookStack\Facades\Activity; use BookStack\Http\Controller; use BookStack\Permissions\Permission; -use BookStack\References\ReferenceFetcher; use BookStack\Util\DatabaseTransaction; use BookStack\Util\SimpleListOptions; use Illuminate\Http\Request; @@ -34,7 +31,6 @@ class BookController extends Controller protected BookQueries $queries, protected EntityQueries $entityQueries, protected BookshelfQueries $shelfQueries, - protected ReferenceFetcher $referenceFetcher, ) { } @@ -53,8 +49,6 @@ class BookController extends Controller $books = $this->queries->visibleForListWithCover() ->orderBy($listOptions->getSort(), $listOptions->getOrder()) ->paginate(setting()->getInteger('lists-page-count-books', 18, 1, 1000)); - $popular = $this->queries->popularForList()->take(4)->get(); - $new = $this->queries->visibleForList()->orderBy('created_at', 'desc')->take(4)->get(); $this->shelfContext->clearShelfContext(); @@ -62,8 +56,6 @@ class BookController extends Controller return view('books.index', [ 'books' => $books, - 'popular' => $popular, - 'new' => $new, 'view' => $view, 'listOptions' => $listOptions, ]); @@ -125,7 +117,7 @@ class BookController extends Controller /** * Display the specified book. */ - public function show(Request $request, ActivityQueries $activities, string $slug) + public function show(Request $request, string $slug) { try { $book = $this->queries->findVisibleBySlugOrFail($slug); @@ -138,7 +130,6 @@ class BookController extends Controller } $bookChildren = (new BookContents($book))->getTree(true); - $bookParentShelves = $book->shelves()->scopes('visible')->get(); View::incrementFor($book); if ($request->has('shelf')) { @@ -151,10 +142,6 @@ class BookController extends Controller 'book' => $book, 'current' => $book, 'bookChildren' => $bookChildren, - 'bookParentShelves' => $bookParentShelves, - 'watchOptions' => new UserEntityWatchOptions(user(), $book), - 'activity' => $activities->entityActivity($book, 20, 1), - 'referenceCount' => $this->referenceFetcher->getReferenceCountToEntity($book), ]); } diff --git a/app/View/SidebarSectionManager.php b/app/View/SidebarSectionManager.php index 82af3721e..d83b7afb0 100644 --- a/app/View/SidebarSectionManager.php +++ b/app/View/SidebarSectionManager.php @@ -2,7 +2,16 @@ namespace BookStack\View; +use BookStack\View\SidebarSections\BooksIndexActions; +use BookStack\View\SidebarSections\BooksIndexNew; +use BookStack\View\SidebarSections\BooksIndexPopular; use BookStack\View\SidebarSections\BooksIndexRecents; +use BookStack\View\SidebarSections\BooksShowActions; +use BookStack\View\SidebarSections\BooksShowActivity; +use BookStack\View\SidebarSections\BooksShowDetails; +use BookStack\View\SidebarSections\BooksShowSearchForm; +use BookStack\View\SidebarSections\BooksShowShelves; +use BookStack\View\SidebarSections\BooksShowTags; use Illuminate\Contracts\Container\BindingResolutionException; class SidebarSectionManager @@ -14,7 +23,24 @@ class SidebarSectionManager 'books-index' => [ 'left' => [ BooksIndexRecents::class, - ] + BooksIndexPopular::class, + BooksIndexNew::class, + ], + 'right' => [ + BooksIndexActions::class, + ], + ], + 'books-show' => [ + 'left' => [ + BooksShowSearchForm::class, + BooksShowTags::class, + BooksShowShelves::class, + BooksShowActivity::class, + ], + 'right' => [ + BooksShowDetails::class, + BooksShowActions::class, + ], ], ]; diff --git a/app/View/SidebarSections/BooksIndexActions.php b/app/View/SidebarSections/BooksIndexActions.php new file mode 100644 index 000000000..62f856a65 --- /dev/null +++ b/app/View/SidebarSections/BooksIndexActions.php @@ -0,0 +1,18 @@ + $viewData['view'], + ]; + } +} diff --git a/app/View/SidebarSections/BooksIndexNew.php b/app/View/SidebarSections/BooksIndexNew.php new file mode 100644 index 000000000..33a57f9d9 --- /dev/null +++ b/app/View/SidebarSections/BooksIndexNew.php @@ -0,0 +1,29 @@ +queries->visibleForList() + ->orderBy('created_at', 'desc') + ->take(4) + ->get(); + + return [ + 'new' => $new, + ]; + } +} diff --git a/app/View/SidebarSections/BooksIndexPopular.php b/app/View/SidebarSections/BooksIndexPopular.php new file mode 100644 index 000000000..9f5cc613f --- /dev/null +++ b/app/View/SidebarSections/BooksIndexPopular.php @@ -0,0 +1,24 @@ + $this->queries->popularForList()->take(4)->get(), + ]; + } +} diff --git a/app/View/SidebarSections/BooksShowActions.php b/app/View/SidebarSections/BooksShowActions.php new file mode 100644 index 000000000..0f97e625c --- /dev/null +++ b/app/View/SidebarSections/BooksShowActions.php @@ -0,0 +1,24 @@ + $book, + 'watchOptions' => new UserEntityWatchOptions(user(), $book), + ]; + } +} diff --git a/app/View/SidebarSections/BooksShowActivity.php b/app/View/SidebarSections/BooksShowActivity.php new file mode 100644 index 000000000..d892c5ea7 --- /dev/null +++ b/app/View/SidebarSections/BooksShowActivity.php @@ -0,0 +1,28 @@ + $this->activityQueries->entityActivity($book, 20, 1), + ]; + } +} diff --git a/app/View/SidebarSections/BooksShowDetails.php b/app/View/SidebarSections/BooksShowDetails.php new file mode 100644 index 000000000..bd91663b2 --- /dev/null +++ b/app/View/SidebarSections/BooksShowDetails.php @@ -0,0 +1,32 @@ +referenceFetcher->getReferenceCountToEntity($book); + + return [ + 'book' => $book, + 'watchOptions' => new UserEntityWatchOptions(user(), $book), + 'referenceCount' => $referenceCount, + ]; + } +} diff --git a/app/View/SidebarSections/BooksShowSearchForm.php b/app/View/SidebarSections/BooksShowSearchForm.php new file mode 100644 index 000000000..8fa24134b --- /dev/null +++ b/app/View/SidebarSections/BooksShowSearchForm.php @@ -0,0 +1,18 @@ + trans('entities.books_search_this'), + ]; + } +} diff --git a/app/View/SidebarSections/BooksShowShelves.php b/app/View/SidebarSections/BooksShowShelves.php new file mode 100644 index 000000000..28d2d8aa9 --- /dev/null +++ b/app/View/SidebarSections/BooksShowShelves.php @@ -0,0 +1,23 @@ +shelves()->scopes('visible')->get(); + + return [ + 'shelves' => $shelves, + ]; + } +} diff --git a/app/View/SidebarSections/BooksShowTags.php b/app/View/SidebarSections/BooksShowTags.php new file mode 100644 index 000000000..351686c7f --- /dev/null +++ b/app/View/SidebarSections/BooksShowTags.php @@ -0,0 +1,18 @@ + $viewData['book'], + ]; + } +} diff --git a/resources/views/books/index.blade.php b/resources/views/books/index.blade.php index 60152410c..020cb0966 100644 --- a/resources/views/books/index.blade.php +++ b/resources/views/books/index.blade.php @@ -5,13 +5,9 @@ @stop @section('left') - @foreach($sidebar->getSectionsForLocation('books-index', 'left') as $section) - @include($section->getView(), $section->withData(get_defined_vars(), request())) - @endforeach - @include('books.parts.index-sidebar-section-popular', ['popular' => $popular]) - @include('books.parts.index-sidebar-section-new', ['new' => $new]) + @include('common.sidebar-sections', ['location' => 'books-index', 'position' => 'left']) @stop @section('right') - @include('books.parts.index-sidebar-section-actions', ['view' => $view]) + @include('common.sidebar-sections', ['location' => 'books-index', 'position' => 'right']) @stop diff --git a/resources/views/books/parts/show-sidebar-section-details.blade.php b/resources/views/books/parts/show-sidebar-section-details.blade.php index 709d0ffd9..2c3d6d141 100644 --- a/resources/views/books/parts/show-sidebar-section-details.blade.php +++ b/resources/views/books/parts/show-sidebar-section-details.blade.php @@ -1,7 +1,7 @@
{{ trans('common.details') }}