mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Updated tags list to new responsive format
This commit is contained in:
parent
9e8516c2df
commit
80d2889217
@ -4,6 +4,7 @@ namespace BookStack\Actions;
|
||||
|
||||
use BookStack\Auth\Permissions\PermissionApplicator;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Util\SimpleListOptions;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -20,8 +21,14 @@ class TagRepo
|
||||
/**
|
||||
* Start a query against all tags in the system.
|
||||
*/
|
||||
public function queryWithTotals(string $searchTerm, string $nameFilter): Builder
|
||||
public function queryWithTotals(SimpleListOptions $listOptions, string $nameFilter): Builder
|
||||
{
|
||||
$searchTerm = $listOptions->getSearch();
|
||||
$sort = $listOptions->getSort();
|
||||
if ($sort === 'name' && $nameFilter) {
|
||||
$sort = 'value';
|
||||
}
|
||||
|
||||
$query = Tag::query()
|
||||
->select([
|
||||
'name',
|
||||
@ -32,7 +39,7 @@ class TagRepo
|
||||
DB::raw('SUM(IF(entity_type = \'book\', 1, 0)) as book_count'),
|
||||
DB::raw('SUM(IF(entity_type = \'bookshelf\', 1, 0)) as shelf_count'),
|
||||
])
|
||||
->orderBy($nameFilter ? 'value' : 'name');
|
||||
->orderBy($sort, $listOptions->getOrder());
|
||||
|
||||
if ($nameFilter) {
|
||||
$query->where('name', '=', $nameFilter);
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Actions\TagRepo;
|
||||
use BookStack\Util\SimpleListOptions;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TagController extends Controller
|
||||
@ -19,22 +20,26 @@ class TagController extends Controller
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$search = $request->get('search', '');
|
||||
$listOptions = SimpleListOptions::fromRequest($request, 'tags')->withSortOptions([
|
||||
'name' => trans('common.sort_name'),
|
||||
'usages' => trans('entities.tags_usages'),
|
||||
]);
|
||||
|
||||
$nameFilter = $request->get('name', '');
|
||||
$tags = $this->tagRepo
|
||||
->queryWithTotals($search, $nameFilter)
|
||||
->queryWithTotals($listOptions, $nameFilter)
|
||||
->paginate(50)
|
||||
->appends(array_filter([
|
||||
'search' => $search,
|
||||
...$listOptions->getPaginationAppends(),
|
||||
'name' => $nameFilter,
|
||||
]));
|
||||
|
||||
$this->setPageTitle(trans('entities.tags'));
|
||||
|
||||
return view('tags.index', [
|
||||
'tags' => $tags,
|
||||
'search' => $search,
|
||||
'nameFilter' => $nameFilter,
|
||||
'tags' => $tags,
|
||||
'nameFilter' => $nameFilter,
|
||||
'listOptions' => $listOptions,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ class UserPreferencesController extends Controller
|
||||
*/
|
||||
public function changeSort(Request $request, string $id, string $type)
|
||||
{
|
||||
$validSortTypes = ['books', 'bookshelves', 'shelf_books', 'users', 'roles', 'webhooks'];
|
||||
$validSortTypes = ['books', 'bookshelves', 'shelf_books', 'users', 'roles', 'webhooks', 'tags'];
|
||||
if (!in_array($type, $validSortTypes)) {
|
||||
return redirect()->back(500);
|
||||
}
|
||||
|
@ -275,6 +275,7 @@ return [
|
||||
'shelf_tags' => 'Shelf Tags',
|
||||
'tag' => 'Tag',
|
||||
'tags' => 'Tags',
|
||||
'tags_index_desc' => 'Tags can be applied to content within the system to apply a flexible form of categorization. Tags can have both a key and value, with the value being optional. Once applied, content can then be queried using the tag name and value.',
|
||||
'tag_name' => 'Tag Name',
|
||||
'tag_value' => 'Tag Value (Optional)',
|
||||
'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.",
|
||||
|
@ -286,35 +286,10 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
td .tag-item {
|
||||
.item-list-row .tag-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pill boxes
|
||||
*/
|
||||
|
||||
.pill {
|
||||
display: inline-block;
|
||||
border: 1px solid currentColor;
|
||||
padding: .2em .8em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 1rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
line-height: 1.4;
|
||||
&:before {
|
||||
content: '';
|
||||
background-color: currentColor;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* API Docs
|
||||
*/
|
||||
|
@ -160,6 +160,11 @@ body.flexbox {
|
||||
flex-basis: auto;
|
||||
flex-grow: 0;
|
||||
}
|
||||
&.fill-area {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
min-width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-2 {
|
||||
|
28
resources/sass/_opacity.scss
Normal file
28
resources/sass/_opacity.scss
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
.opacity-10 {
|
||||
opacity: 0.1;
|
||||
}
|
||||
.opacity-20 {
|
||||
opacity: 0.2;
|
||||
}
|
||||
.opacity-30 {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.opacity-40 {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.opacity-50 {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.opacity-60 {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.opacity-70 {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.opacity-80 {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.opacity-90 {
|
||||
opacity: 0.9;
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
@import "variables";
|
||||
@import "mixins";
|
||||
@import "spacing";
|
||||
@import "opacity";
|
||||
@import "html";
|
||||
@import "text";
|
||||
@import "colors";
|
||||
|
@ -5,25 +5,28 @@
|
||||
|
||||
<main class="card content-wrap mt-xxl">
|
||||
|
||||
<div class="flex-container-row wrap justify-space-between items-center mb-s">
|
||||
<h1 class="list-heading">{{ trans('entities.tags') }}</h1>
|
||||
<h1 class="list-heading">{{ trans('entities.tags') }}</h1>
|
||||
|
||||
<div>
|
||||
<div class="block inline mr-xs">
|
||||
<form method="get" action="{{ url("/tags") }}">
|
||||
@include('form.request-query-inputs', ['params' => ['name']])
|
||||
<input type="text"
|
||||
name="search"
|
||||
placeholder="{{ trans('common.search') }}"
|
||||
value="{{ $search }}">
|
||||
</form>
|
||||
</div>
|
||||
<p class="text-muted">{{ trans('entities.tags_index_desc') }}</p>
|
||||
|
||||
<div class="flex-container-row wrap justify-space-between items-center mb-s gap-m">
|
||||
<div class="block inline mr-xs">
|
||||
<form method="get" action="{{ url("/tags") }}">
|
||||
@include('form.request-query-inputs', ['params' => ['name']])
|
||||
<input type="text"
|
||||
name="search"
|
||||
placeholder="{{ trans('common.search') }}"
|
||||
value="{{ $listOptions->getSearch() }}">
|
||||
</form>
|
||||
</div>
|
||||
<div class="block inline">
|
||||
@include('common.sort', $listOptions->getSortControlData())
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($nameFilter)
|
||||
<div class="mb-m">
|
||||
<span class="mr-xs">{{ trans('common.filter_active') }}</span>
|
||||
<div class="my-m">
|
||||
<strong class="mr-xs">{{ trans('common.filter_active') }}</strong>
|
||||
@include('entities.tag', ['tag' => new \BookStack\Actions\Tag(['name' => $nameFilter])])
|
||||
<form method="get" action="{{ url("/tags") }}" class="inline block">
|
||||
@include('form.request-query-inputs', ['params' => ['search']])
|
||||
@ -33,13 +36,13 @@
|
||||
@endif
|
||||
|
||||
@if(count($tags) > 0)
|
||||
<table class="table expand-to-padding mt-m">
|
||||
<div class="item-list mt-m">
|
||||
@foreach($tags as $tag)
|
||||
@include('tags.parts.table-row', ['tag' => $tag, 'nameFilter' => $nameFilter])
|
||||
@include('tags.parts.tags-list-item', ['tag' => $tag, 'nameFilter' => $nameFilter])
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="my-m">
|
||||
{{ $tags->links() }}
|
||||
</div>
|
||||
@else
|
||||
|
@ -1,37 +0,0 @@
|
||||
<tr>
|
||||
<td>
|
||||
<span class="text-bigger mr-xl">@include('entities.tag', ['tag' => $tag])</span>
|
||||
</td>
|
||||
<td width="70" class="px-xs">
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() }}"
|
||||
title="{{ trans('entities.tags_usages') }}"
|
||||
class="pill text-muted">@icon('leaderboard'){{ $tag->usages }}</a>
|
||||
</td>
|
||||
<td width="70" class="px-xs">
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:page}' }}"
|
||||
title="{{ trans('entities.tags_assigned_pages') }}"
|
||||
class="pill text-page">@icon('page'){{ $tag->page_count }}</a>
|
||||
</td>
|
||||
<td width="70" class="px-xs">
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:chapter}' }}"
|
||||
title="{{ trans('entities.tags_assigned_chapters') }}"
|
||||
class="pill text-chapter">@icon('chapter'){{ $tag->chapter_count }}</a>
|
||||
</td>
|
||||
<td width="70" class="px-xs">
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:book}' }}"
|
||||
title="{{ trans('entities.tags_assigned_books') }}"
|
||||
class="pill text-book">@icon('book'){{ $tag->book_count }}</a>
|
||||
</td>
|
||||
<td width="70" class="px-xs">
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:bookshelf}' }}"
|
||||
title="{{ trans('entities.tags_assigned_shelves') }}"
|
||||
class="pill text-bookshelf">@icon('bookshelf'){{ $tag->shelf_count }}</a>
|
||||
</td>
|
||||
<td class="text-right text-muted">
|
||||
@if($tag->values ?? false)
|
||||
<a href="{{ url('/tags?name=' . urlencode($tag->name)) }}">{{ trans('entities.tags_x_unique_values', ['count' => $tag->values]) }}</a>
|
||||
@elseif(empty($nameFilter))
|
||||
<a href="{{ url('/tags?name=' . urlencode($tag->name)) }}">{{ trans('entities.tags_all_values') }}</a>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
31
resources/views/tags/parts/tags-list-item.blade.php
Normal file
31
resources/views/tags/parts/tags-list-item.blade.php
Normal file
@ -0,0 +1,31 @@
|
||||
<div class="item-list-row flex-container-row items-center wrap">
|
||||
<div class="{{ isset($nameFilter) && $tag->value ? 'flex-2' : 'flex' }} py-s px-m min-width-m">
|
||||
<span class="text-bigger mr-xl">@include('entities.tag', ['tag' => $tag])</span>
|
||||
</div>
|
||||
<div class="flex-2 flex-container-row justify-center items-center gap-m py-s px-m min-width-l wrap">
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() }}"
|
||||
title="{{ trans('entities.tags_usages') }}"
|
||||
class="flex fill-area min-width-xxs bold text-right text-muted"><span class="opacity-60">@icon('leaderboard')</span>{{ $tag->usages }}</a>
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:page}' }}"
|
||||
title="{{ trans('entities.tags_assigned_pages') }}"
|
||||
class="flex fill-area min-width-xxs bold text-right text-page"><span class="opacity-60">@icon('page')</span>{{ $tag->page_count }}</a>
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:chapter}' }}"
|
||||
title="{{ trans('entities.tags_assigned_chapters') }}"
|
||||
class="flex fill-area min-width-xxs bold text-right text-chapter"><span class="opacity-60">@icon('chapter')</span>{{ $tag->chapter_count }}</a>
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:book}' }}"
|
||||
title="{{ trans('entities.tags_assigned_books') }}"
|
||||
class="flex fill-area min-width-xxs bold text-right text-book"><span class="opacity-60">@icon('book')</span>{{ $tag->book_count }}</a>
|
||||
<a href="{{ isset($tag->value) ? $tag->valueUrl() : $tag->nameUrl() . '+{type:bookshelf}' }}"
|
||||
title="{{ trans('entities.tags_assigned_shelves') }}"
|
||||
class="flex fill-area min-width-xxs bold text-right text-bookshelf"><span class="opacity-60">@icon('bookshelf')</span>{{ $tag->shelf_count }}</a>
|
||||
</div>
|
||||
@if($tag->values ?? false)
|
||||
<div class="flex text-s-right text-muted py-s px-m min-width-s">
|
||||
<a href="{{ url('/tags?name=' . urlencode($tag->name)) }}">{{ trans('entities.tags_x_unique_values', ['count' => $tag->values]) }}</a>
|
||||
</div>
|
||||
@elseif(empty($nameFilter))
|
||||
<div class="flex text-s-right text-muted py-s px-m min-width-s">
|
||||
<a href="{{ url('/tags?name=' . urlencode($tag->name)) }}">{{ trans('entities.tags_all_values') }}</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user